PageSourceSearch

https://www.martinwoods.me.uk/app/themes/salt-blog/assets/js/header.js?ver=1.0

js martinwoods.me.uk collected 2026-10-04 16:03:04 UTC 90,860 bytes, 3,065 lines download raw bytes

1/*!
2 * modernizr v3.3.1
3 * Build http://modernizr.com/download?-canvas-cssanimations-csscolumns-cssgradients-csstransforms-csstransitions-cssvhunit-cssvwunit-flexbox-inlinesvg-localstorage-placeholder-shapes-target-domprefixes-mq-prefixed-prefixes-setclasses-testallprops-testprop-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 tests = [];
27  
28
29  /**
30   *
31   * ModernizrProto is the constructor for Modernizr
32   *
33   * @class
34   * @access public
35   */
36
37  var ModernizrProto = {
38    // The current version, dummy
39    _version: '3.3.1',
40
41    // Any settings that don't work as separate modules
42    // can go in here as configuration.
43    _config: {
44      'classPrefix': '',
45      'enableClasses': true,
46      'enableJSClass': true,
47      'usePrefixes': true
48    },
49
50    // Queue of tests
51    _q: [],
52
53    // Stub these for people who are listening
54    on: function(test, cb) {
55      // I don't really think people should do this, but we can
56      // safe guard it a bit.
57      // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
58      // This is in case people listen to synchronous tests. I would leave it out,
59      // but the code to *disallow* sync tests in the real version of this
60      // function is actually larger than this.
61      var self = this;
62      setTimeout(function() {
63        cb(self[test]);
64      }, 0);
65    },
66
67    addTest: function(name, fn, options) {
68      tests.push({name: name, fn: fn, options: options});
69    },
70
71    addAsyncTest: function(fn) {
72      tests.push({name: null, fn: fn});
73    }
74  };
75
76  
77
78  // Fake some of Object.create so we can force non test results to be non "own" properties.
79  var Modernizr = function() {};
80  Modernizr.prototype = ModernizrProto;
81
82  // Leak modernizr globally when you `require` it rather than force it here.
83  // Overwrite name so constructor name is nicer :D
84  Modernizr = new Modernizr();
85
86  
87
88  var classes = [];
89  
90
91  /**
92   * is returns a boolean if the typeof an obj is exactly type.
93   *
94   * @access private
95   * @function is
96   * @param {*} obj - A thing we want to check the type of
97   * @param {string} type - A string to compare the typeof against
98   * @returns {boolean}
99   */
100
101  function is(obj, type) {
102    return typeof obj === type;
103  }
104  ;
105
106  /**
107   * Run through all tests and detect their support in the current UA.
108   *
109   * @access private
110   */
111
112  function testRunner() {
113    var featureNames;
114    var feature;
115    var aliasIdx;
116    var result;
117    var nameIdx;
118    var featureName;
119    var featureNameSplit;
120
121    for (var featureIdx in tests) {
122      if (tests.hasOwnProperty(featureIdx)) {
123        featureNames = [];
124        feature = tests[featureIdx];
125        // run the test, throw the return value into the Modernizr,
126        // then based on that boolean, define an appropriate className
127        // and push it into an array of classes we'll join later.
128        //
129        // If there is no name, it's an 'async' test that is run,
130        // but not directly added to the object. That should
131        // be done with a post-run addTest call.
132        if (feature.name) {
133          featureNames.push(feature.name.toLowerCase());
134
135          if (feature.options && feature.options.aliases && feature.options.aliases.length) {
136            // Add all the aliases into the names list
137            for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
138              featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
139            }
140          }
141        }
142
143        // Run the test, or use the raw value if it's not a function
144        result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
145
146
147        // Set each of the names on the Modernizr object
148        for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
149          featureName = featureNames[nameIdx];
150          // Support dot properties as sub tests. We don't do checking to make sure
151          // that the implied parent tests have been added. You must call them in
152          // order (either in the test, or make the parent test a dependency).
153          //
154          // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
155          // hashtag famous last words
156          featureNameSplit = featureName.split('.');
157
158          if (featureNameSplit.length === 1) {
159            Modernizr[featureNameSplit[0]] = result;
160          } else {
161            // cast to a Boolean, if not one already
162            /* jshint -W053 */
163            if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
164              Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
165            }
166
167            Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
168          }
169
170          classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
171        }
172      }
173    }
174  }
175  ;
176
177  /**
178   * docElement is a convenience wrapper to grab the root element of the document
179   *
180   * @access private
181   * @returns {HTMLElement|SVGElement} The root element of the document
182   */
183
184  var docElement = document.documentElement;
185  
186
187  /**
188   * A convenience helper to check if the document we are running in is an SVG document
189   *
190   * @access private
191   * @returns {boolean}
192   */
193
194  var isSVG = docElement.nodeName.toLowerCase() === 'svg';
195  
196
197  /**
198   * setClasses takes an array of class names and adds them to the root element
199   *
200   * @access private
201   * @function setClasses
202   * @param {string[]} classes - Array of class names
203   */
204
205  // Pass in an and array of class names, e.g.:
206  //  ['no-webp', 'borderradius', ...]
207  function setClasses(classes) {
208    var className = docElement.className;
209    var classPrefix = Modernizr._config.classPrefix || '';
210
211    if (isSVG) {
212      className = className.baseVal;
213    }
214
215    // Change `no-js` to `js` (independently of the `enableClasses` option)
216    // Handle classPrefix on this too
217    if (Modernizr._config.enableJSClass) {
218      var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
219      className = className.replace(reJS, '$1' + classPrefix + 'js$2');
220    }
221
222    if (Modernizr._config.enableClasses) {
223      // Add the new classes
224      className += ' ' + classPrefix + classes.join(' ' + classPrefix);
225      isSVG ? docElement.className.baseVal = className : docElement.className = className;
226    }
227
228  }
229
230  ;
231
232  /**
233   * If the browsers follow the spec, then they would expose vendor-specific style as:
234   *   elem.style.WebkitBorderRadius
235   * instead of something like the following, which would be technically incorrect:
236   *   elem.style.webkitBorderRadius
237
238   * Webkit ghosts their properties in lowercase but Opera & Moz do not.
239   * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
240   *   erik.eae.net/archives/2008/03/10/21.48.10/
241
242   * More here: github.com/Modernizr/Modernizr/issues/issue/21
243   *
244   * @access private
245   * @returns {string} The string representing the vendor-specific style properties
246   */
247
248  var omPrefixes = 'Moz O ms Webkit';
249  
250
251  /**
252   * List of JavaScript DOM values used for tests
253   *
254   * @memberof Modernizr
255   * @name Modernizr._domPrefixes
256   * @optionName Modernizr._domPrefixes
257   * @optionProp domPrefixes
258   * @access public
259   * @example
260   *
261   * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
262   * than kebab-case properties, all properties are their Capitalized variant
263   *
264   * ```js
265   * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
266   * ```
267   */
268
269  var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
270  ModernizrProto._domPrefixes = domPrefixes;
271  
272
273  /**
274   * List of property values to set for css tests. See ticket #21
275   * http://git.io/vUGl4
276   *
277   * @memberof Modernizr
278   * @name Modernizr._prefixes
279   * @optionName Modernizr._prefixes
280   * @optionProp prefixes
281   * @access public
282   * @example
283   *
284   * Modernizr._prefixes is the internal list of prefixes that we test against
285   * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
286   * an array of kebab-case vendor prefixes you can use within your code.
287   *
288   * Some common use cases include
289   *
290   * Generating all possible prefixed version of a CSS property
291   * ```js
292   * var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
293   *
294   * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
295   * ```
296   *
297   * Generating all possible prefixed version of a CSS value
298   * ```js
299   * rule = 'display:' +  Modernizr._prefixes.join('flex; display:') + 'flex';
300   *
301   * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
302   * ```
303   */
304
305  var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : []);
306
307  // expose these for the plugin API. Look in the source for how to join() them against your input
308  ModernizrProto._prefixes = prefixes;
309
310  
311
312  /**
313   * createElement is a convenience wrapper around document.createElement. Since we
314   * use createElement all over the place, this allows for (slightly) smaller code
315   * as well as abstracting away issues with creating elements in contexts other than
316   * HTML documents (e.g. SVG documents).
317   *
318   * @access private
319   * @function createElement
320   * @returns {HTMLElement|SVGElement} An HTML or SVG element
321   */
322
323  function createElement() {
324    if (typeof document.createElement !== 'function') {
325      // This is the case in IE7, where the type of createElement is "object".
326      // For this reason, we cannot call apply() as Object is not a Function.
327      return document.createElement(arguments[0]);
328    } else if (isSVG) {
329      return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
330    } else {
331      return document.createElement.apply(document, arguments);
332    }
333  }
334
335  ;
336
337  /**
338   * getBody returns the body of a document, or an element that can stand in for
339   * the body if a real body does not exist
340   *
341   * @access private
342   * @function getBody
343   * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
344   * artificially created element that stands in for the body
345   */
346
347  function getBody() {
348    // After page load injecting a fake body doesn't work so check if body exists
349    var body = document.body;
350
351    if (!body) {
352      // Can't use the real body create a fake one.
353      body = createElement(isSVG ? 'svg' : 'body');
354      body.fake = true;
355    }
356
357    return body;
358  }
359
360  ;
361
362  /**
363   * injectElementWithStyles injects an element with style element and some CSS rules
364   *
365   * @access private
366   * @function injectElementWithStyles
367   * @param {string} rule - String representing a css rule
368   * @param {function} callback - A function that is used to test the injected element
369   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
370   * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
371   * @returns {boolean}
372   */
373
374  function injectElementWithStyles(rule, callback, nodes, testnames) {
375    var mod = 'modernizr';
376    var style;
377    var ret;
378    var node;
379    var docOverflow;
380    var div = createElement('div');
381    var body = getBody();
382
383    if (parseInt(nodes, 10)) {
384      // In order not to give false positives we create a node for each test
385      // This also allows the method to scale for unspecified uses
386      while (nodes--) {
387        node = createElement('div');
388        node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
389        div.appendChild(node);
390      }
391    }
392
393    style = createElement('style');
394    style.type = 'text/css';
395    style.id = 's' + mod;
396
397    // 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.
398    // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
399    (!body.fake ? div : body).appendChild(style);
400    body.appendChild(div);
401
402    if (style.styleSheet) {
403      style.styleSheet.cssText = rule;
404    } else {
405      style.appendChild(document.createTextNode(rule));
406    }
407    div.id = mod;
408
409    if (body.fake) {
410      //avoid crashing IE8, if background image is used
411      body.style.background = '';
412      //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
413      body.style.overflow = 'hidden';
414      docOverflow = docElement.style.overflow;
415      docElement.style.overflow = 'hidden';
416      docElement.appendChild(body);
417    }
418
419    ret = callback(div, rule);
420    // If this is done after page load we don't want to remove the body so check if body exists
421    if (body.fake) {
422      body.parentNode.removeChild(body);
423      docElement.style.overflow = docOverflow;
424      // Trigger layout so kinetic scrolling isn't disabled in iOS6+
425      docElement.offsetHeight;
426    } else {
427      div.parentNode.removeChild(div);
428    }
429
430    return !!ret;
431
432  }
433
434  ;
435
436  /**
437   * Modernizr.mq tests a given media query, live against the current state of the window
438   * adapted from matchMedia polyfill by Scott Jehl and Paul Irish
439   * gist.github.com/786768
440   *
441   * @memberof Modernizr
442   * @name Modernizr.mq
443   * @optionName Modernizr.mq()
444   * @optionProp mq
445   * @access public
446   * @function mq
447   * @param {string} mq - String of the media query we want to test
448   * @returns {boolean}
449   * @example
450   * Modernizr.mq allows for you to programmatically check if the current browser
451   * window state matches a media query.
452   *
453   * ```js
454   *  var query = Modernizr.mq('(min-width: 900px)');
455   *
456   *  if (query) {
457   *    // the browser window is larger than 900px
458   *  }
459   * ```
460   *
461   * Only valid media queries are supported, therefore you must always include values
462   * with your media query
463   *
464   * ```js
465   * // good
466   *  Modernizr.mq('(min-width: 900px)');
467   *
468   * // bad
469   *  Modernizr.mq('min-width');
470   * ```
471   *
472   * If you would just like to test that media queries are supported in general, use
473   *
474   * ```js
475   *  Modernizr.mq('only all'); // true if MQ are supported, false if not
476   * ```
477   *
478   *
479   * Note that if the browser does not support media queries (e.g. old IE) mq will
480   * always return false.
481   */
482
483  var mq = (function() {
484    var matchMedia = window.matchMedia || window.msMatchMedia;
485    if (matchMedia) {
486      return function(mq) {
487        var mql = matchMedia(mq);
488        return mql && mql.matches || false;
489      };
490    }
491
492    return function(mq) {
493      var bool = false;
494
495      injectElementWithStyles('@media ' + mq + ' { #modernizr { position: absolute; } }', function(node) {
496        bool = (window.getComputedStyle ?
497                window.getComputedStyle(node, null) :
498                node.currentStyle).position == 'absolute';
499      });
500
501      return bool;
502    };
503  })();
504
505
506  ModernizrProto.mq = mq;
507
508  
509
510  var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
511  ModernizrProto._cssomPrefixes = cssomPrefixes;
512  
513
514
515  /**
516   * contains checks to see if a string contains another string
517   *
518   * @access private
519   * @function contains
520   * @param {string} str - The string we want to check for substrings
521   * @param {string} substr - The substring we want to search the first string for
522   * @returns {boolean}
523   */
524
525  function contains(str, substr) {
526    return !!~('' + str).indexOf(substr);
527  }
528
529  ;
530
531  /**
532   * Create our "modernizr" element that we do most feature tests on.
533   *
534   * @access private
535   */
536
537  var modElem = {
538    elem: createElement('modernizr')
539  };
540
541  // Clean up this element
542  Modernizr._q.push(function() {
543    delete modElem.elem;
544  });
545
546  
547
548  var mStyle = {
549    style: modElem.elem.style
550  };
551
552  // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
553  // the front of the queue.
554  Modernizr._q.unshift(function() {
555    delete mStyle.style;
556  });
557
558  
559
560  /**
561   * domToCSS takes a camelCase string and converts it to kebab-case
562   * e.g. boxSizing -> box-sizing
563   *
564   * @access private
565   * @function domToCSS
566   * @param {string} name - String name of camelCase prop we want to convert
567   * @returns {string} The kebab-case version of the supplied name
568   */
569
570  function domToCSS(name) {
571    return name.replace(/([A-Z])/g, function(str, m1) {
572      return '-' + m1.toLowerCase();
573    }).replace(/^ms-/, '-ms-');
574  }
575  ;
576
577  /**
578   * nativeTestProps allows for us to use native feature detection functionality if available.
579   * some prefixed form, or false, in the case of an unsupported rule
580   *
581   * @access private
582   * @function nativeTestProps
583   * @param {array} props - An array of property names
584   * @param {string} value - A string representing the value we want to check via @supports
585   * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
586   */
587
588  // Accepts a list of property names and a single value
589  // Returns `undefined` if native detection not available
590  function nativeTestProps(props, value) {
591    var i = props.length;
592    // Start with the JS API: http://www.w3.org/TR/css3-conditional/#the-css-interface
593    if ('CSS' in window && 'supports' in window.CSS) {
594      // Try every prefixed variant of the property
595      while (i--) {
596        if (window.CSS.supports(domToCSS(props[i]), value)) {
597          return true;
598        }
599      }
600      return false;
601    }
602    // Otherwise fall back to at-rule (for Opera 12.x)
603    else if ('CSSSupportsRule' in window) {
604      // Build a condition string for every prefixed variant
605      var conditionText = [];
606      while (i--) {
607        conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
608      }
609      conditionText = conditionText.join(' or ');
610      return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
611        return getComputedStyle(node, null).position == 'absolute';
612      });
613    }
614    return undefined;
615  }
616  ;
617
618  /**
619   * cssToDOM takes a kebab-case string and converts it to camelCase
620   * e.g. box-sizing -> boxSizing
621   *
622   * @access private
623   * @function cssToDOM
624   * @param {string} name - String name of kebab-case prop we want to convert
625   * @returns {string} The camelCase version of the supplied name
626   */
627
628  function cssToDOM(name) {
629    return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
630      return m1 + m2.toUpperCase();
631    }).replace(/^-/, '');
632  }
633  ;
634
635  // testProps is a generic CSS / DOM property test.
636
637  // In testing support for a given CSS property, it's legit to test:
638  //    `elem.style[styleName] !== undefined`
639  // If the property is supported it will return an empty string,
640  // if unsupported it will return undefined.
641
642  // We'll take advantage of this quick test and skip setting a style
643  // on our modernizr element, but instead just testing undefined vs
644  // empty string.
645
646  // Property names can be provided in either camelCase or kebab-case.
647
648  function testProps(props, prefixed, value, skipValueTest) {
649    skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
650
651    // Try native detect first
652    if (!is(value, 'undefined')) {
653      var result = nativeTestProps(props, value);
654      if (!is(result, 'undefined')) {
655        return result;
656      }
657    }
658
659    // Otherwise do it properly
660    var afterInit, i, propsLength, prop, before;
661
662    // If we don't have a style element, that means we're running async or after
663    // the core tests, so we'll need to create our own elements to use
664
665    // inside of an SVG element, in certain browsers, the `style` element is only
666    // defined for valid tags. Therefore, if `modernizr` does not have one, we
667    // fall back to a less used element and hope for the best.
668    var elems = ['modernizr', 'tspan'];
669    while (!mStyle.style) {
670      afterInit = true;
671      mStyle.modElem = createElement(elems.shift());
672      mStyle.style = mStyle.modElem.style;
673    }
674
675    // Delete the objects if we created them.
676    function cleanElems() {
677      if (afterInit) {
678        delete mStyle.style;
679        delete mStyle.modElem;
680      }
681    }
682
683    propsLength = props.length;
684    for (i = 0; i < propsLength; i++) {
685      prop = props[i];
686      before = mStyle.style[prop];
687
688      if (contains(prop, '-')) {
689        prop = cssToDOM(prop);
690      }
691
692      if (mStyle.style[prop] !== undefined) {
693
694        // If value to test has been passed in, do a set-and-check test.
695        // 0 (integer) is a valid property value, so check that `value` isn't
696        // undefined, rather than just checking it's truthy.
697        if (!skipValueTest && !is(value, 'undefined')) {
698
699          // Needs a try catch block because of old IE. This is slow, but will
700          // be avoided in most cases because `skipValueTest` will be used.
701          try {
702            mStyle.style[prop] = value;
703          } catch (e) {}
704
705          // If the property value has changed, we assume the value used is
706          // supported. If `value` is empty string, it'll fail here (because
707          // it hasn't changed), which matches how browsers have implemented
708          // CSS.supports()
709          if (mStyle.style[prop] != before) {
710            cleanElems();
711            return prefixed == 'pfx' ? prop : true;
712          }
713        }
714        // Otherwise just return true, or the property name if this is a
715        // `prefixed()` call
716        else {
717          cleanElems();
718          return prefixed == 'pfx' ? prop : true;
719        }
720      }
721    }
722    cleanElems();
723    return false;
724  }
725
726  ;
727
728  /**
729   * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
730   *
731   * @access private
732   * @function fnBind
733   * @param {function} fn - a function you want to change `this` reference to
734   * @param {object} that - the `this` you want to call the function with
735   * @returns {function} The wrapped version of the supplied function
736   */
737
738  function fnBind(fn, that) {
739    return function() {
740      return fn.apply(that, arguments);
741    };
742  }
743
744  ;
745
746  /**
747   * testDOMProps is a generic DOM property test; if a browser supports
748   *   a certain property, it won't return undefined for it.
749   *
750   * @access private
751   * @function testDOMProps
752   * @param {array.<string>} props - An array of properties to test for
753   * @param {object} obj - An object or Element you want to use to test the parameters again
754   * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
755   */
756  function testDOMProps(props, obj, elem) {
757    var item;
758
759    for (var i in props) {
760      if (props[i] in obj) {
761
762        // return the property name as a string
763        if (elem === false) {
764          return props[i];
765        }
766
767        item = obj[props[i]];
768
769        // let's bind a function
770        if (is(item, 'function')) {
771          // bind to obj unless overriden
772          return fnBind(item, elem || obj);
773        }
774
775        // return the unbound function or obj or value
776        return item;
777      }
778    }
779    return false;
780  }
781
782  ;
783
784  /**
785   * testPropsAll tests a list of DOM properties we want to check against.
786   * We specify literally ALL possible (known and/or likely) properties on
787   * the element including the non-vendor prefixed one, for forward-
788   * compatibility.
789   *
790   * @access private
791   * @function testPropsAll
792   * @param {string} prop - A string of the property to test for
793   * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
794   * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
795   * @param {string} [value] - A string of a css value
796   * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
797   */
798  function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
799
800    var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
801    props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
802
803    // did they call .prefixed('boxSizing') or are we just testing a prop?
804    if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
805      return testProps(props, prefixed, value, skipValueTest);
806
807      // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
808    } else {
809      props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
810      return testDOMProps(props, prefixed, elem);
811    }
812  }
813
814  // Modernizr.testAllProps() investigates whether a given style property,
815  // or any of its vendor-prefixed variants, is recognized
816  //
817  // Note that the property names must be provided in the camelCase variant.
818  // Modernizr.testAllProps('boxSizing')
819  ModernizrProto.testAllProps = testPropsAll;
820
821  
822
823  /**
824   * atRule returns a given CSS property at-rule (eg @keyframes), possibly in
825   * some prefixed form, or false, in the case of an unsupported rule
826   *
827   * @memberof Modernizr
828   * @name Modernizr.atRule
829   * @optionName Modernizr.atRule()
830   * @optionProp atRule
831   * @access public
832   * @function atRule
833   * @param {string} prop - String name of the @-rule to test for
834   * @returns {string|boolean} The string representing the (possibly prefixed)
835   * valid version of the @-rule, or `false` when it is unsupported.
836   * @example
837   * ```js
838   *  var keyframes = Modernizr.atRule('@keyframes');
839   *
840   *  if (keyframes) {
841   *    // keyframes are supported
842   *    // could be `@-webkit-keyframes` or `@keyframes`
843   *  } else {
844   *    // keyframes === `false`
845   *  }
846   * ```
847   *
848   */
849
850  var atRule = function(prop) {
851    var length = prefixes.length;
852    var cssrule = window.CSSRule;
853    var rule;
854
855    if (typeof cssrule === 'undefined') {
856      return undefined;
857    }
858
859    if (!prop) {
860      return false;
861    }
862
863    // remove literal @ from beginning of provided property
864    prop = prop.replace(/^@/, '');
865
866    // CSSRules use underscores instead of dashes
867    rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE';
868
869    if (rule in cssrule) {
870      return '@' + prop;
871    }
872
873    for (var i = 0; i < length; i++) {
874      // prefixes gives us something like -o-, and we want O_
875      var prefix = prefixes[i];
876      var thisRule = prefix.toUpperCase() + '_' + rule;
877
878      if (thisRule in cssrule) {
879        return '@-' + prefix.toLowerCase() + '-' + prop;
880      }
881    }
882
883    return false;
884  };
885
886  ModernizrProto.atRule = atRule;
887
888  
889
890  /**
891   * prefixed returns the prefixed or nonprefixed property name variant of your input
892   *
893   * @memberof Modernizr
894   * @name Modernizr.prefixed
895   * @optionName Modernizr.prefixed()
896   * @optionProp prefixed
897   * @access public
898   * @function prefixed
899   * @param {string} prop - String name of the property to test for
900   * @param {object} [obj] - An object to test for the prefixed properties on
901   * @param {HTMLElement} [elem] - An element used to test specific properties against
902   * @returns {string|false} The string representing the (possibly prefixed) valid
903   * version of the property, or `false` when it is unsupported.
904   * @example
905   *
906   * Modernizr.prefixed takes a string css value in the DOM style camelCase (as
907   * opposed to the css style kebab-case) form and returns the (possibly prefixed)
908   * version of that property that the browser actually supports.
909   *
910   * For example, in older Firefox...
911   * ```js
912   * prefixed('boxSizing')
913   * ```
914   * returns 'MozBoxSizing'
915   *
916   * In newer Firefox, as well as any other browser that support the unprefixed
917   * version would simply return `boxSizing`. Any browser that does not support
918   * the property at all, it will return `false`.
919   *
920   * By default, prefixed is checked against a DOM element. If you want to check
921   * for a property on another object, just pass it as a second argument
922   *
923   * ```js
924   * var rAF = prefixed('requestAnimationFrame', window);
925   *
926   * raf(function() {
927   *  renderFunction();
928   * })
929   * ```
930   *
931   * Note that this will return _the actual function_ - not the name of the function.
932   * If you need the actual name of the property, pass in `false` as a third argument
933   *
934   * ```js
935   * var rAFProp = prefixed('requestAnimationFrame', window, false);
936   *
937   * rafProp === 'WebkitRequestAnimationFrame' // in older webkit
938   * ```
939   *
940   * One common use case for prefixed is if you're trying to determine which transition
941   * end event to bind to, you might do something like...
942   * ```js
943   * var transEndEventNames = {
944   *     'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser
945   *     'MozTransition'    : 'transitionend',       * only for FF < 15
946   *     'transition'       : 'transitionend'        * IE10, Opera, Chrome, FF 15+, Saf 7+
947   * };
948   *
949   * var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
950   * ```
951   *
952   * If you want a similar lookup, but in kebab-case, you can use [prefixedCSS](#modernizr-prefixedcss).
953   */
954
955  var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
956    if (prop.indexOf('@') === 0) {
957      return atRule(prop);
958    }
959
960    if (prop.indexOf('-') != -1) {
961      // Convert kebab-case to camelCase
962      prop = cssToDOM(prop);
963    }
964    if (!obj) {
965      return testPropsAll(prop, 'pfx');
966    } else {
967      // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
968      return testPropsAll(prop, obj, elem);
969    }
970  };
971
972  
973
974  /**
975   * testAllProps determines whether a given CSS property is supported in the browser
976   *
977   * @memberof Modernizr
978   * @name Modernizr.testAllProps
979   * @optionName Modernizr.testAllProps()
980   * @optionProp testAllProps
981   * @access public
982   * @function testAllProps
983   * @param {string} prop - String naming the property to test (either camelCase or kebab-case)
984   * @param {string} [value] - String of the value to test
985   * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
986   * @example
987   *
988   * testAllProps determines whether a given CSS property, in some prefixed form,
989   * is supported by the browser.
990   *
991   * ```js
992   * testAllProps('boxSizing')  // true
993   * ```
994   *
995   * It can optionally be given a CSS value in string form to test if a property
996   * value is valid
997   *
998   * ```js
999   * testAllProps('display', 'block') // true
1000   * testAllProps('display', 'penguin') // false
1001   * ```
1002   *
1003   * A boolean can be passed as a third parameter to skip the value check when
1004   * native detection (@supports) isn't available.
1005   *
1006   * ```js
1007   * testAllProps('shapeOutside', 'content-box', true);
1008   * ```
1009   */
1010
1011  function testAllProps(prop, value, skipValueTest) {
1012    return testPropsAll(prop, undefined, undefined, value, skipValueTest);
1013  }
1014  ModernizrProto.testAllProps = testAllProps;
1015  
1016
1017  /**
1018   * testProp() investigates whether a given style property is recognized
1019   * Property names can be provided in either camelCase or kebab-case.
1020   *
1021   * @memberof Modernizr
1022   * @name Modernizr.testProp
1023   * @access public
1024   * @optionName Modernizr.testProp()
1025   * @optionProp testProp
1026   * @function testProp
1027   * @param {string} prop - Name of the CSS property to check
1028   * @param {string} [value] - Name of the CSS value to check
1029   * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
1030   * @returns {boolean}
1031   * @example
1032   *
1033   * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
1034   * version of the string.
1035   *
1036   * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
1037   *
1038   * ```js
1039   * Modernizr.testProp('pointerEvents')  // true
1040   * ```
1041   *
1042   * You can also provide a value as an optional second argument to check if a
1043   * specific value is supported
1044   *
1045   * ```js
1046   * Modernizr.testProp('pointerEvents', 'none') // true
1047   * Modernizr.testProp('pointerEvents', 'penguin') // false
1048   * ```
1049   */
1050
1051  var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
1052    return testProps([prop], undefined, value, useValue);
1053  };
1054  
1055/*!
1056{
1057  "name": "Flexbox",
1058  "property": "flexbox",
1059  "caniuse": "flexbox",
1060  "tags": ["css"],
1061  "notes": [{
1062    "name": "The _new_ flexbox",
1063    "href": "http://dev.w3.org/csswg/css3-flexbox"
1064  }],
1065  "warnings": [
1066    "A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect."
1067  ]
1068}
1069!*/
1070/* DOC
1071Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows easy manipulation of layout order and sizing within a container.
1072*/
1073
1074  Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true));
1075
1076/*!
1077{
1078  "name": "CSS Animations",
1079  "property": "cssanimations",
1080  "caniuse": "css-animation",
1081  "polyfills": ["transformie", "csssandpaper"],
1082  "tags": ["css"],
1083  "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
1084  "notes": [{
1085    "name" : "Article: 'Dispelling the Android CSS animation myths'",
1086    "href": "https://goo.gl/OGw5Gm"
1087  }]
1088}
1089!*/
1090/* DOC
1091Detects whether or not elements can be animated using CSS
1092*/
1093
1094  Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
1095
1096/*!
1097{
1098  "name": "CSS Gradients",
1099  "caniuse": "css-gradients",
1100  "property": "cssgradients",
1101  "tags": ["css"],
1102  "knownBugs": ["False-positives on webOS (https://github.com/Modernizr/Modernizr/issues/202)"],
1103  "notes": [{
1104    "name": "Webkit Gradient Syntax",
1105    "href": "https://webkit.org/blog/175/introducing-css-gradients/"
1106  },{
1107    "name": "Linear Gradient Syntax",
1108    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient"
1109  },{
1110    "name": "W3C Gradient Spec",
1111    "href": "https://drafts.csswg.org/css-images-3/#gradients"
1112  }]
1113}
1114!*/
1115
1116
1117  Modernizr.addTest('cssgradients', function() {
1118
1119    var str1 = 'background-image:';
1120    var str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));';
1121    var css = '';
1122    var angle;
1123
1124    for (var i = 0, len = prefixes.length - 1; i < len; i++) {
1125      angle = (i === 0 ? 'to ' : '');
1126      css += str1 + prefixes[i] + 'linear-gradient(' + angle + 'left top, #9f9, white);';
1127    }
1128
1129    if (Modernizr._config.usePrefixes) {
1130    // legacy webkit syntax (FIXME: remove when syntax not in use anymore)
1131      css += str1 + '-webkit-' + str2;
1132    }
1133
1134    var elem = createElement('a');
1135    var style = elem.style;
1136    style.cssText = css;
1137
1138    // IE6 returns undefined so cast to string
1139    return ('' + style.backgroundImage).indexOf('gradient') > -1;
1140  });
1141
1142/*!
1143{
1144  "name": "CSS Transforms",
1145  "property": "csstransforms",
1146  "caniuse": "transforms2d",
1147  "tags": ["css"]
1148}
1149!*/
1150
1151  Modernizr.addTest('csstransforms', function() {
1152    // Android < 3.0 is buggy, so we sniff and blacklist
1153    // http://git.io/hHzL7w
1154    return navigator.userAgent.indexOf('Android 2.') === -1 &&
1155           testAllProps('transform', 'scale(1)', true);
1156  });
1157
1158/*!
1159{
1160  "name": "CSS Transitions",
1161  "property": "csstransitions",
1162  "caniuse": "css-transitions",
1163  "tags": ["css"]
1164}
1165!*/
1166
1167  Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
1168
1169/*!
1170{
1171  "name": "CSS Columns",
1172  "property": "csscolumns",
1173  "caniuse": "multicolumn",
1174  "polyfills": ["css3multicolumnjs"],
1175  "tags": ["css"]
1176}
1177!*/
1178
1179
1180  (function() {
1181
1182    /* jshint -W053 */
1183    Modernizr.addTest('csscolumns', function() {
1184      var bool = false;
1185      var test = testAllProps('columnCount');
1186      try {
1187        if (bool = !!test) {
1188          bool = new Boolean(bool);
1189        }
1190      } catch (e) {}
1191
1192      return bool;
1193    });
1194
1195    var props = ['Width', 'Span', 'Fill', 'Gap', 'Rule', 'RuleColor', 'RuleStyle', 'RuleWidth', 'BreakBefore', 'BreakAfter', 'BreakInside'];
1196    var name, test;
1197
1198    for (var i = 0; i < props.length; i++) {
1199      name = props[i].toLowerCase();
1200      test = testAllProps('column' + props[i]);
1201
1202      // break-before, break-after & break-inside are not "column"-prefixed in spec
1203      if (name === 'breakbefore' || name === 'breakafter' || name == 'breakinside') {
1204        test = test || testAllProps(props[i]);
1205      }
1206
1207      Modernizr.addTest('csscolumns.' + name, test);
1208    }
1209
1210
1211  })();
1212
1213
1214
1215  /**
1216   * testStyles injects an element with style element and some CSS rules
1217   *
1218   * @memberof Modernizr
1219   * @name Modernizr.testStyles
1220   * @optionName Modernizr.testStyles()
1221   * @optionProp testStyles
1222   * @access public
1223   * @function testStyles
1224   * @param {string} rule - String representing a css rule
1225   * @param {function} callback - A function that is used to test the injected element
1226   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
1227   * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
1228   * @returns {boolean}
1229   * @example
1230   *
1231   * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
1232   * along with (possibly multiple) DOM elements. This lets you check for features
1233   * 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).
1234   *
1235   * ```js
1236   * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
1237   *   // elem is the first DOM node in the page (by default #modernizr)
1238   *   // rule is the first argument you supplied - the CSS rule in string form
1239   *
1240   *   addTest('widthworks', elem.style.width === '9px')
1241   * });
1242   * ```
1243   *
1244   * If your test requires multiple nodes, you can include a third argument
1245   * indicating how many additional div elements to include on the page. The
1246   * additional nodes are injected as children of the `elem` that is returned as
1247   * the first argument to the callback.
1248   *
1249   * ```js
1250   * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
1251   *   document.getElementById('modernizr').style.width === '1px'; // true
1252   *   document.getElementById('modernizr2').style.width === '2px'; // true
1253   *   elem.firstChild === document.getElementById('modernizr2'); // true
1254   * }, 1);
1255   * ```
1256   *
1257   * By default, all of the additional elements have an ID of `modernizr[n]`, where
1258   * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
1259   * the second additional is `#modernizr3`, etc.).
1260   * If you want to have more meaningful IDs for your function, you can provide
1261   * them as the fourth argument, as an array of strings
1262   *
1263   * ```js
1264   * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
1265   *   elem.firstChild === document.getElementById('foo'); // true
1266   *   elem.lastChild === document.getElementById('bar'); // true
1267   * }, 2, ['foo', 'bar']);
1268   * ```
1269   *
1270   */
1271
1272  var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
1273  
1274/*!
1275{
1276  "name": "CSS vh unit",
1277  "property": "cssvhunit",
1278  "caniuse": "viewport-units",
1279  "tags": ["css"],
1280  "builderAliases": ["css_vhunit"],
1281  "notes": [{
1282    "name": "Related Modernizr Issue",
1283    "href": "https://github.com/Modernizr/Modernizr/issues/572"
1284  },{
1285    "name": "Similar JSFiddle",
1286    "href": "https://jsfiddle.net/FWeinb/etnYC/"
1287  }]
1288}
1289!*/
1290
1291  testStyles('#modernizr { height: 50vh; }', function(elem) {
1292    var height = parseInt(window.innerHeight / 2, 10);
1293    var compStyle = parseInt((window.getComputedStyle ?
1294                              getComputedStyle(elem, null) :
1295                              elem.currentStyle).height, 10);
1296    Modernizr.addTest('cssvhunit', compStyle == height);
1297  });
1298
1299/*!
1300{
1301  "name": "CSS vw unit",
1302  "property": "cssvwunit",
1303  "caniuse": "viewport-units",
1304  "tags": ["css"],
1305  "builderAliases": ["css_vwunit"],
1306  "notes": [{
1307    "name": "Related Modernizr Issue",
1308    "href": "https://github.com/Modernizr/Modernizr/issues/572"
1309  },{
1310    "name": "JSFiddle Example",
1311    "href": "https://jsfiddle.net/FWeinb/etnYC/"
1312  }]
1313}
1314!*/
1315
1316  testStyles('#modernizr { width: 50vw; }', function(elem) {
1317    var width = parseInt(window.innerWidth / 2, 10);
1318    var compStyle = parseInt((window.getComputedStyle ?
1319                              getComputedStyle(elem, null) :
1320                              elem.currentStyle).width, 10);
1321
1322    Modernizr.addTest('cssvwunit', compStyle == width);
1323  });
1324
1325/*!
1326{
1327  "name": "placeholder attribute",
1328  "property": "placeholder",
1329  "tags": ["forms", "attribute"],
1330  "builderAliases": ["forms_placeholder"]
1331}
1332!*/
1333/* DOC
1334Tests for placeholder attribute in inputs and textareas
1335*/
1336
1337  Modernizr.addTest('placeholder', ('placeholder' in createElement('input') && 'placeholder' in createElement('textarea')));
1338
1339/*!
1340{
1341  "name": "Local Storage",
1342  "property": "localstorage",
1343  "caniuse": "namevalue-storage",
1344  "tags": ["storage"],
1345  "knownBugs": [],
1346  "notes": [],
1347  "warnings": [],
1348  "polyfills": [
1349    "joshuabell-polyfill",
1350    "cupcake",
1351    "storagepolyfill",
1352    "amplifyjs",
1353    "yui-cacheoffline"
1354  ]
1355}
1356!*/
1357
1358  // In FF4, if disabled, window.localStorage should === null.
1359
1360  // Normally, we could not test that directly and need to do a
1361  //   `('localStorage' in window) && ` test first because otherwise Firefox will
1362  //   throw bugzil.la/365772 if cookies are disabled
1363
1364  // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
1365  // will throw the exception:
1366  //   QUOTA_EXCEEDED_ERROR DOM Exception 22.
1367  // Peculiarly, getItem and removeItem calls do not throw.
1368
1369  // Because we are forced to try/catch this, we'll go aggressive.
1370
1371  // Just FWIW: IE8 Compat mode supports these features completely:
1372  //   www.quirksmode.org/dom/html5.html
1373  // But IE8 doesn't support either with local files
1374
1375  Modernizr.addTest('localstorage', function() {
1376    var mod = 'modernizr';
1377    try {
1378      localStorage.setItem(mod, mod);
1379      localStorage.removeItem(mod);
1380      return true;
1381    } catch (e) {
1382      return false;
1383    }
1384  });
1385
1386/*!
1387{
1388  "name": "Inline SVG",
1389  "property": "inlinesvg",
1390  "caniuse": "svg-html5",
1391  "tags": ["svg"],
1392  "notes": [{
1393    "name": "Test page",
1394    "href": "https://paulirish.com/demo/inline-svg"
1395  }, {
1396    "name": "Test page and results",
1397    "href": "https://codepen.io/eltonmesquita/full/GgXbvo/"
1398  }],
1399  "polyfills": ["inline-svg-polyfill"],
1400  "knownBugs": ["False negative on some Chromia browsers."]
1401}
1402!*/
1403/* DOC
1404Detects support for inline SVG in HTML (not within XHTML).
1405*/
1406
1407  Modernizr.addTest('inlinesvg', function() {
1408    var div = createElement('div');
1409    div.innerHTML = '<svg/>';
1410    return (typeof SVGRect != 'undefined' && div.firstChild && div.firstChild.namespaceURI) == 'http://www.w3.org/2000/svg';
1411  });
1412
1413/*!
1414{
1415  "name": "Canvas",
1416  "property": "canvas",
1417  "caniuse": "canvas",
1418  "tags": ["canvas", "graphics"],
1419  "polyfills": ["flashcanvas", "excanvas", "slcanvas", "fxcanvas"]
1420}
1421!*/
1422/* DOC
1423Detects support for the `<canvas>` element for 2D drawing.
1424*/
1425
1426  // On the S60 and BB Storm, getContext exists, but always returns undefined
1427  // so we actually have to call getContext() to verify
1428  // github.com/Modernizr/Modernizr/issues/issue/97/
1429  Modernizr.addTest('canvas', function() {
1430    var elem = createElement('canvas');
1431    return !!(elem.getContext && elem.getContext('2d'));
1432  });
1433
1434/*!
1435{
1436  "name": "CSS Shapes",
1437  "property": "shapes",
1438  "tags": ["css"],
1439  "notes": [{
1440    "name": "CSS Shapes W3C specification",
1441    "href": "https://www.w3.org/TR/css-shapes"
1442  },{
1443    "name": "Examples from Adobe",
1444    "href": "http://webplatform.adobe.com/shapes/"
1445  }, {
1446    "name": "Samples showcasing uses of Shapes",
1447    "href": "http://codepen.io/collection/qFesk"
1448  }]
1449}
1450!*/
1451
1452  Modernizr.addTest('shapes', testAllProps('shapeOutside', 'content-box', true));
1453
1454/*!
1455{
1456  "name": "CSS :target pseudo-class",
1457  "caniuse": "css-sel3",
1458  "property": "target",
1459  "tags": ["css"],
1460  "notes": [{
1461    "name": "MDN documentation",
1462    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/:target"
1463  }],
1464  "authors": ["@zachleat"],
1465  "warnings": ["Opera Mini supports :target but doesn't update the hash for anchor links."]
1466}
1467!*/
1468/* DOC
1469Detects support for the ':target' CSS pseudo-class.
1470*/
1471
1472  // querySelector
1473  Modernizr.addTest('target', function() {
1474    var doc = window.document;
1475    if (!('querySelectorAll' in doc)) {
1476      return false;
1477    }
1478
1479    try {
1480      doc.querySelectorAll(':target');
1481      return true;
1482    } catch (e) {
1483      return false;
1484    }
1485  });
1486
1487
1488  // Run each test
1489  testRunner();
1490
1491  // Remove the "no-js" class if it exists
1492  setClasses(classes);
1493
1494  delete ModernizrProto.addTest;
1495  delete ModernizrProto.addAsyncTest;
1496
1497  // Run the things that are supposed to run after the tests
1498  for (var i = 0; i < Modernizr._q.length; i++) {
1499    Modernizr._q[i]();
1500  }
1501
1502  // Leak Modernizr namespace
1503  window.Modernizr = Modernizr;
1504
1505
1506;
1507
1508})(window, document);
1509
vendor: 44,683 bytes, lines 1510-3053
1510/*! picturefill - v3.0.2 - 2016-02-12
1511 * https://scottjehl.github.io/picturefill/
1512 * Copyright (c) 2016 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT
1513 */
1514/*! Gecko-Picture - v1.0
1515 * https://github.com/scottjehl/picturefill/tree/3.0/src/plugins/gecko-picture
1516 * Firefox's early picture implementation (prior to FF41) is static and does
1517 * not react to viewport changes. This tiny module fixes this.
1518 */
1519(function(window) {
1520	/*jshint eqnull:true */
1521	var ua = navigator.userAgent;
1522
1523	if ( window.HTMLPictureElement && ((/ecko/).test(ua) && ua.match(/rv\:(\d+)/) && RegExp.$1 < 45) ) {
1524		addEventListener("resize", (function() {
1525			var timer;
1526
1527			var dummySrc = document.createElement("source");
1528
1529			var fixRespimg = function(img) {
1530				var source, sizes;
1531				var picture = img.parentNode;
1532
1533				if (picture.nodeName.toUpperCase() === "PICTURE") {
1534					source = dummySrc.cloneNode();
1535
1536					picture.insertBefore(source, picture.firstElementChild);
1537					setTimeout(function() {
1538						picture.removeChild(source);
1539					});
1540				} else if (!img._pfLastSize || img.offsetWidth > img._pfLastSize) {
1541					img._pfLastSize = img.offsetWidth;
1542					sizes = img.sizes;
1543					img.sizes += ",100vw";
1544					setTimeout(function() {
1545						img.sizes = sizes;
1546					});
1547				}
1548			};
1549
1550			var findPictureImgs = function() {
1551				var i;
1552				var imgs = document.querySelectorAll("picture > img, img[srcset][sizes]");
1553				for (i = 0; i < imgs.length; i++) {
1554					fixRespimg(imgs[i]);
1555				}
1556			};
1557			var onResize = function() {
1558				clearTimeout(timer);
1559				timer = setTimeout(findPictureImgs, 99);
1560			};
1561			var mq = window.matchMedia && matchMedia("(orientation: landscape)");
1562			var init = function() {
1563				onResize();
1564
1565				if (mq && mq.addListener) {
1566					mq.addListener(onResize);
1567				}
1568			};
1569
1570			dummySrc.srcset = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
1571
1572			if (/^[c|i]|d$/.test(document.readyState || "")) {
1573				init();
1574			} else {
1575				document.addEventListener("DOMContentLoaded", init);
1576			}
1577
1578			return onResize;
1579		})());
1580	}
1581})(window);
1582
1583/*! Picturefill - v3.0.2
1584 * http://scottjehl.github.io/picturefill
1585 * Copyright (c) 2015 https://github.com/scottjehl/picturefill/blob/master/Authors.txt;
1586 *  License: MIT
1587 */
1588
1589(function( window, document, undefined ) {
1590	// Enable strict mode
1591	"use strict";
1592
1593	// HTML shim|v it for old IE (IE9 will still need the HTML video tag workaround)
1594	document.createElement( "picture" );
1595
1596	var warn, eminpx, alwaysCheckWDescriptor, evalId;
1597	// local object for method references and testing exposure
1598	var pf = {};
1599	var isSupportTestReady = false;
1600	var noop = function() {};
1601	var image = document.createElement( "img" );
1602	var getImgAttr = image.getAttribute;
1603	var setImgAttr = image.setAttribute;
1604	var removeImgAttr = image.removeAttribute;
1605	var docElem = document.documentElement;
1606	var types = {};
1607	var cfg = {
1608		//resource selection:
1609		algorithm: ""
1610	};
1611	var srcAttr = "data-pfsrc";
1612	var srcsetAttr = srcAttr + "set";
1613	// ua sniffing is done for undetectable img loading features,
1614	// to do some non crucial perf optimizations
1615	var ua = navigator.userAgent;
1616	var supportAbort = (/rident/).test(ua) || ((/ecko/).test(ua) && ua.match(/rv\:(\d+)/) && RegExp.$1 > 35 );
1617	var curSrcProp = "currentSrc";
1618	var regWDesc = /\s+\+?\d+(e\d+)?w/;
1619	var regSize = /(\([^)]+\))?\s*(.+)/;
1620	var setOptions = window.picturefillCFG;
1621	/**
1622	 * Shortcut property for https://w3c.github.io/webappsec/specs/mixedcontent/#restricts-mixed-content ( for easy overriding in tests )
1623	 */
1624	// baseStyle also used by getEmValue (i.e.: width: 1em is important)
1625	var baseStyle = "position:absolute;left:0;visibility:hidden;display:block;padding:0;border:none;font-size:1em;width:1em;overflow:hidden;clip:rect(0px, 0px, 0px, 0px)";
1626	var fsCss = "font-size:100%!important;";
1627	var isVwDirty = true;
1628
1629	var cssCache = {};
1630	var sizeLengthCache = {};
1631	var DPR = window.devicePixelRatio;
1632	var units = {
1633		px: 1,
1634		"in": 96
1635	};
1636	var anchor = document.createElement( "a" );
1637	/**
1638	 * alreadyRun flag used for setOptions. is it true setOptions will reevaluate
1639	 * @type {boolean}
1640	 */
1641	var alreadyRun = false;
1642
1643	// Reusable, non-"g" Regexes
1644
1645	// (Don't use \s, to avoid matching non-breaking space.)
1646	var regexLeadingSpaces = /^[ \t\n\r\u000c]+/,
1647	    regexLeadingCommasOrSpaces = /^[, \t\n\r\u000c]+/,
1648	    regexLeadingNotSpaces = /^[^ \t\n\r\u000c]+/,
1649	    regexTrailingCommas = /[,]+$/,
1650	    regexNonNegativeInteger = /^\d+$/,
1651
1652	    // ( Positive or negative or unsigned integers or decimals, without or without exponents.
1653	    // Must include at least one digit.
1654	    // According to spec tests any decimal point must be followed by a digit.
1655	    // No leading plus sign is allowed.)
1656	    // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-floating-point-number
1657	    regexFloatingPoint = /^-?(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/;
1658
1659	var on = function(obj, evt, fn, capture) {
1660		if ( obj.addEventListener ) {
1661			obj.addEventListener(evt, fn, capture || false);
1662		} else if ( obj.attachEvent ) {
1663			obj.attachEvent( "on" + evt, fn);
1664		}
1665	};
1666
1667	/**
1668	 * simple memoize function:
1669	 */
1670
1671	var memoize = function(fn) {
1672		var cache = {};
1673		return function(input) {
1674			if ( !(input in cache) ) {
1675				cache[ input ] = fn(input);
1676			}
1677			return cache[ input ];
1678		};
1679	};
1680
1681	// UTILITY FUNCTIONS
1682
1683	// Manual is faster than RegEx
1684	// http://jsperf.com/whitespace-character/5
1685	function isSpace(c) {
1686		return (c === "\u0020" || // space
1687		        c === "\u0009" || // horizontal tab
1688		        c === "\u000A" || // new line
1689		        c === "\u000C" || // form feed
1690		        c === "\u000D");  // carriage return
1691	}
1692
1693	/**
1694	 * gets a mediaquery and returns a boolean or gets a css length and returns a number
1695	 * @param css mediaqueries or css length
1696	 * @returns {boolean|number}
1697	 *
1698	 * based on: https://gist.github.com/jonathantneal/db4f77009b155f083738
1699	 */
1700	var evalCSS = (function() {
1701
1702		var regLength = /^([\d\.]+)(em|vw|px)$/;
1703		var replace = function() {
1704			var args = arguments, index = 0, string = args[0];
1705			while (++index in args) {
1706				string = string.replace(args[index], args[++index]);
1707			}
1708			return string;
1709		};
1710
1711		var buildStr = memoize(function(css) {
1712
1713			return "return " + replace((css || "").toLowerCase(),
1714				// interpret `and`
1715				/\band\b/g, "&&",
1716
1717				// interpret `,`
1718				/,/g, "||",
1719
1720				// interpret `min-` as >=
1721				/min-([a-z-\s]+):/g, "e.$1>=",
1722
1723				// interpret `max-` as <=
1724				/max-([a-z-\s]+):/g, "e.$1<=",
1725
1726				//calc value
1727				/calc([^)]+)/g, "($1)",
1728
1729				// interpret css values
1730				/(\d+[\.]*[\d]*)([a-z]+)/g, "($1 * e.$2)",
1731				//make eval less evil
1732				/^(?!(e.[a-z]|[0-9\.&=|><\+\-\*\(\)\/])).*/ig, ""
1733			) + ";";
1734		});
1735
1736		return function(css, length) {
1737			var parsedLength;
1738			if (!(css in cssCache)) {
1739				cssCache[css] = false;
1740				if (length && (parsedLength = css.match( regLength ))) {
1741					cssCache[css] = parsedLength[ 1 ] * units[parsedLength[ 2 ]];
1742				} else {
1743					/*jshint evil:true */
1744					try{
1745						cssCache[css] = new Function("e", buildStr(css))(units);
1746					} catch(e) {}
1747					/*jshint evil:false */
1748				}
1749			}
1750			return cssCache[css];
1751		};
1752	})();
1753
1754	var setResolution = function( candidate, sizesattr ) {
1755		if ( candidate.w ) { // h = means height: || descriptor.type === 'h' do not handle yet...
1756			candidate.cWidth = pf.calcListLength( sizesattr || "100vw" );
1757			candidate.res = candidate.w / candidate.cWidth ;
1758		} else {
1759			candidate.res = candidate.d;
1760		}
1761		return candidate;
1762	};
1763
1764	/**
1765	 *
1766	 * @param opt
1767	 */
1768	var picturefill = function( opt ) {
1769
1770		if (!isSupportTestReady) {return;}
1771
1772		var elements, i, plen;
1773
1774		var options = opt || {};
1775
1776		if ( options.elements && options.elements.nodeType === 1 ) {
1777			if ( options.elements.nodeName.toUpperCase() === "IMG" ) {
1778				options.elements =  [ options.elements ];
1779			} else {
1780				options.context = options.elements;
1781				options.elements =  null;
1782			}
1783		}
1784
1785		elements = options.elements || pf.qsa( (options.context || document), ( options.reevaluate || options.reselect ) ? pf.sel : pf.selShort );
1786
1787		if ( (plen = elements.length) ) {
1788
1789			pf.setupRun( options );
1790			alreadyRun = true;
1791
1792			// Loop through all elements
1793			for ( i = 0; i < plen; i++ ) {
1794				pf.fillImg(elements[ i ], options);
1795			}
1796
1797			pf.teardownRun( options );
1798		}
1799	};
1800
1801	/**
1802	 * outputs a warning for the developer
1803	 * @param {message}
1804	 * @type {Function}
1805	 */
1806	warn = ( window.console && console.warn ) ?
1807		function( message ) {
1808			console.warn( message );
1809		} :
1810		noop
1811	;
1812
1813	if ( !(curSrcProp in image) ) {
1814		curSrcProp = "src";
1815	}
1816
1817	// Add support for standard mime types.
1818	types[ "image/jpeg" ] = true;
1819	types[ "image/gif" ] = true;
1820	types[ "image/png" ] = true;
1821
1822	function detectTypeSupport( type, typeUri ) {
1823		// based on Modernizr's lossless img-webp test
1824		// note: asynchronous
1825		var image = new window.Image();
1826		image.onerror = function() {
1827			types[ type ] = false;
1828			picturefill();
1829		};
1830		image.onload = function() {
1831			types[ type ] = image.width === 1;
1832			picturefill();
1833		};
1834		image.src = typeUri;
1835		return "pending";
1836	}
1837
1838	// test svg support
1839	types[ "image/svg+xml" ] = document.implementation.hasFeature( "http://www.w3.org/TR/SVG11/feature#Image", "1.1" );
1840
1841	/**
1842	 * updates the internal vW property with the current viewport width in px
1843	 */
1844	function updateMetrics() {
1845
1846		isVwDirty = false;
1847		DPR = window.devicePixelRatio;
1848		cssCache = {};
1849		sizeLengthCache = {};
1850
1851		pf.DPR = DPR || 1;
1852
1853		units.width = Math.max(window.innerWidth || 0, docElem.clientWidth);
1854		units.height = Math.max(window.innerHeight || 0, docElem.clientHeight);
1855
1856		units.vw = units.width / 100;
1857		units.vh = units.height / 100;
1858
1859		evalId = [ units.height, units.width, DPR ].join("-");
1860
1861		units.em = pf.getEmValue();
1862		units.rem = units.em;
1863	}
1864
1865	function chooseLowRes( lowerValue, higherValue, dprValue, isCached ) {
1866		var bonusFactor, tooMuch, bonus, meanDensity;
1867
1868		//experimental
1869		if (cfg.algorithm === "saveData" ){
1870			if ( lowerValue > 2.7 ) {
1871				meanDensity = dprValue + 1;
1872			} else {
1873				tooMuch = higherValue - dprValue;
1874				bonusFactor = Math.pow(lowerValue - 0.6, 1.5);
1875
1876				bonus = tooMuch * bonusFactor;
1877
1878				if (isCached) {
1879					bonus += 0.1 * bonusFactor;
1880				}
1881
1882				meanDensity = lowerValue + bonus;
1883			}
1884		} else {
1885			meanDensity = (dprValue > 1) ?
1886				Math.sqrt(lowerValue * higherValue) :
1887				lowerValue;
1888		}
1889
1890		return meanDensity > dprValue;
1891	}
1892
1893	function applyBestCandidate( img ) {
1894		var srcSetCandidates;
1895		var matchingSet = pf.getSet( img );
1896		var evaluated = false;
1897		if ( matchingSet !== "pending" ) {
1898			evaluated = evalId;
1899			if ( matchingSet ) {
1900				srcSetCandidates = pf.setRes( matchingSet );
1901				pf.applySetCandidate( srcSetCandidates, img );
1902			}
1903		}
1904		img[ pf.ns ].evaled = evaluated;
1905	}
1906
1907	function ascendingSort( a, b ) {
1908		return a.res - b.res;
1909	}
1910
1911	function setSrcToCur( img, src, set ) {
1912		var candidate;
1913		if ( !set && src ) {
1914			set = img[ pf.ns ].sets;
1915			set = set && set[set.length - 1];
1916		}
1917
1918		candidate = getCandidateForSrc(src, set);
1919
1920		if ( candidate ) {
1921			src = pf.makeUrl(src);
1922			img[ pf.ns ].curSrc = src;
1923			img[ pf.ns ].curCan = candidate;
1924
1925			if ( !candidate.res ) {
1926				setResolution( candidate, candidate.set.sizes );
1927			}
1928		}
1929		return candidate;
1930	}
1931
1932	function getCandidateForSrc( src, set ) {
1933		var i, candidate, candidates;
1934		if ( src && set ) {
1935			candidates = pf.parseSet( set );
1936			src = pf.makeUrl(src);
1937			for ( i = 0; i < candidates.length; i++ ) {
1938				if ( src === pf.makeUrl(candidates[ i ].url) ) {
1939					candidate = candidates[ i ];
1940					break;
1941				}
1942			}
1943		}
1944		return candidate;
1945	}
1946
1947	function getAllSourceElements( picture, candidates ) {
1948		var i, len, source, srcset;
1949
1950		// SPEC mismatch intended for size and perf:
1951		// actually only source elements preceding the img should be used
1952		// also note: don't use qsa here, because IE8 sometimes doesn't like source as the key part in a selector
1953		var sources = picture.getElementsByTagName( "source" );
1954
1955		for ( i = 0, len = sources.length; i < len; i++ ) {
1956			source = sources[ i ];
1957			source[ pf.ns ] = true;
1958			srcset = source.getAttribute( "srcset" );
1959
1960			// if source does not have a srcset attribute, skip
1961			if ( srcset ) {
1962				candidates.push( {
1963					srcset: srcset,
1964					media: source.getAttribute( "media" ),
1965					type: source.getAttribute( "type" ),
1966					sizes: source.getAttribute( "sizes" )
1967				} );
1968			}
1969		}
1970	}
1971
1972	/**
1973	 * Srcset Parser
1974	 * By Alex Bell |  MIT License
1975	 *
1976	 * @returns Array [{url: _, d: _, w: _, h:_, set:_(????)}, ...]
1977	 *
1978	 * Based super duper closely on the reference algorithm at:
1979	 * https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-srcset-attribute
1980	 */
1981
1982	// 1. Let input be the value passed to this algorithm.
1983	// (TO-DO : Explain what "set" argument is here. Maybe choose a more
1984	// descriptive & more searchable name.  Since passing the "set" in really has
1985	// nothing to do with parsing proper, I would prefer this assignment eventually
1986	// go in an external fn.)
1987	function parseSrcset(input, set) {
1988
1989		function collectCharacters(regEx) {
1990			var chars,
1991			    match = regEx.exec(input.substring(pos));
1992			if (match) {
1993				chars = match[ 0 ];
1994				pos += chars.length;
1995				return chars;
1996			}
1997		}
1998
1999		var inputLength = input.length,
2000		    url,
2001		    descriptors,
2002		    currentDescriptor,
2003		    state,
2004		    c,
2005
2006		    // 2. Let position be a pointer into input, initially pointing at the start
2007		    //    of the string.
2008		    pos = 0,
2009
2010		    // 3. Let candidates be an initially empty source set.
2011		    candidates = [];
2012
2013		/**
2014		* Adds descriptor properties to a candidate, pushes to the candidates array
2015		* @return undefined
2016		*/
2017		// (Declared outside of the while loop so that it's only created once.
2018		// (This fn is defined before it is used, in order to pass JSHINT.
2019		// Unfortunately this breaks the sequencing of the spec comments. :/ )
2020		function parseDescriptors() {
2021
2022			// 9. Descriptor parser: Let error be no.
2023			var pError = false,
2024
2025			// 10. Let width be absent.
2026			// 11. Let density be absent.
2027			// 12. Let future-compat-h be absent. (We're implementing it now as h)
2028			    w, d, h, i,
2029			    candidate = {},
2030			    desc, lastChar, value, intVal, floatVal;
2031
2032			// 13. For each descriptor in descriptors, run the appropriate set of steps
2033			// from the following list:
2034			for (i = 0 ; i < descriptors.length; i++) {
2035				desc = descriptors[ i ];
2036
2037				lastChar = desc[ desc.length - 1 ];
2038				value = desc.substring(0, desc.length - 1);
2039				intVal = parseInt(value, 10);
2040				floatVal = parseFloat(value);
2041
2042				// If the descriptor consists of a valid non-negative integer followed by
2043				// a U+0077 LATIN SMALL LETTER W character
2044				if (regexNonNegativeInteger.test(value) && (lastChar === "w")) {
2045
2046					// If width and density are not both absent, then let error be yes.
2047					if (w || d) {pError = true;}
2048
2049					// Apply the rules for parsing non-negative integers to the descriptor.
2050					// If the result is zero, let error be yes.
2051					// Otherwise, let width be the result.
2052					if (intVal === 0) {pError = true;} else {w = intVal;}
2053
2054				// If the descriptor consists of a valid floating-point number followed by
2055				// a U+0078 LATIN SMALL LETTER X character
2056				} else if (regexFloatingPoint.test(value) && (lastChar === "x")) {
2057
2058					// If width, density and future-compat-h are not all absent, then let error
2059					// be yes.
2060					if (w || d || h) {pError = true;}
2061
2062					// Apply the rules for parsing floating-point number values to the descriptor.
2063					// If the result is less than zero, let error be yes. Otherwise, let density
2064					// be the result.
2065					if (floatVal < 0) {pError = true;} else {d = floatVal;}
2066
2067				// If the descriptor consists of a valid non-negative integer followed by
2068				// a U+0068 LATIN SMALL LETTER H character
2069				} else if (regexNonNegativeInteger.test(value) && (lastChar === "h")) {
2070
2071					// If height and density are not both absent, then let error be yes.
2072					if (h || d) {pError = true;}
2073
2074					// Apply the rules for parsing non-negative integers to the descriptor.
2075					// If the result is zero, let error be yes. Otherwise, let future-compat-h
2076					// be the result.
2077					if (intVal === 0) {pError = true;} else {h = intVal;}
2078
2079				// Anything else, Let error be yes.
2080				} else {pError = true;}
2081			} // (close step 13 for loop)
2082
2083			// 15. If error is still no, then append a new image source to candidates whose
2084			// URL is url, associated with a width width if not absent and a pixel
2085			// density density if not absent. Otherwise, there is a parse error.
2086			if (!pError) {
2087				candidate.url = url;
2088
2089				if (w) { candidate.w = w;}
2090				if (d) { candidate.d = d;}
2091				if (h) { candidate.h = h;}
2092				if (!h && !d && !w) {candidate.d = 1;}
2093				if (candidate.d === 1) {set.has1x = true;}
2094				candidate.set = set;
2095
2096				candidates.push(candidate);
2097			}
2098		} // (close parseDescriptors fn)
2099
2100		/**
2101		* Tokenizes descriptor properties prior to parsing
2102		* Returns undefined.
2103		* (Again, this fn is defined before it is used, in order to pass JSHINT.
2104		* Unfortunately this breaks the logical sequencing of the spec comments. :/ )
2105		*/
2106		function tokenize() {
2107
2108			// 8.1. Descriptor tokeniser: Skip whitespace
2109			collectCharacters(regexLeadingSpaces);
2110
2111			// 8.2. Let current descriptor be the empty string.
2112			currentDescriptor = "";
2113
2114			// 8.3. Let state be in descriptor.
2115			state = "in descriptor";
2116
2117			while (true) {
2118
2119				// 8.4. Let c be the character at position.
2120				c = input.charAt(pos);
2121
2122				//  Do the following depending on the value of state.
2123				//  For the purpose of this step, "EOF" is a special character representing
2124				//  that position is past the end of input.
2125
2126				// In descriptor
2127				if (state === "in descriptor") {
2128					// Do the following, depending on the value of c:
2129
2130				  // Space character
2131				  // If current descriptor is not empty, append current descriptor to
2132				  // descriptors and let current descriptor be the empty string.
2133				  // Set state to after descriptor.
2134					if (isSpace(c)) {
2135						if (currentDescriptor) {
2136							descriptors.push(currentDescriptor);
2137							currentDescriptor = "";
2138							state = "after descriptor";
2139						}
2140
2141					// U+002C COMMA (,)
2142					// Advance position to the next character in input. If current descriptor
2143					// is not empty, append current descriptor to descriptors. Jump to the step
2144					// labeled descriptor parser.
2145					} else if (c === ",") {
2146						pos += 1;
2147						if (currentDescriptor) {
2148							descriptors.push(currentDescriptor);
2149						}
2150						parseDescriptors();
2151						return;
2152
2153					// U+0028 LEFT PARENTHESIS (()
2154					// Append c to current descriptor. Set state to in parens.
2155					} else if (c === "\u0028") {
2156						currentDescriptor = currentDescriptor + c;
2157						state = "in parens";
2158
2159					// EOF
2160					// If current descriptor is not empty, append current descriptor to
2161					// descriptors. Jump to the step labeled descriptor parser.
2162					} else if (c === "") {
2163						if (currentDescriptor) {
2164							descriptors.push(currentDescriptor);
2165						}
2166						parseDescriptors();
2167						return;
2168
2169					// Anything else
2170					// Append c to current descriptor.
2171					} else {
2172						currentDescriptor = currentDescriptor + c;
2173					}
2174				// (end "in descriptor"
2175
2176				// In parens
2177				} else if (state === "in parens") {
2178
2179					// U+0029 RIGHT PARENTHESIS ())
2180					// Append c to current descriptor. Set state to in descriptor.
2181					if (c === ")") {
2182						currentDescriptor = currentDescriptor + c;
2183						state = "in descriptor";
2184
2185					// EOF
2186					// Append current descriptor to descriptors. Jump to the step labeled
2187					// descriptor parser.
2188					} else if (c === "") {
2189						descriptors.push(currentDescriptor);
2190						parseDescriptors();
2191						return;
2192
2193					// Anything else
2194					// Append c to current descriptor.
2195					} else {
2196						currentDescriptor = currentDescriptor + c;
2197					}
2198
2199				// After descriptor
2200				} else if (state === "after descriptor") {
2201
2202					// Do the following, depending on the value of c:
2203					// Space character: Stay in this state.
2204					if (isSpace(c)) {
2205
2206					// EOF: Jump to the step labeled descriptor parser.
2207					} else if (c === "") {
2208						parseDescriptors();
2209						return;
2210
2211					// Anything else
2212					// Set state to in descriptor. Set position to the previous character in input.
2213					} else {
2214						state = "in descriptor";
2215						pos -= 1;
2216
2217					}
2218				}
2219
2220				// Advance position to the next character in input.
2221				pos += 1;
2222
2223			// Repeat this step.
2224			} // (close while true loop)
2225		}
2226
2227		// 4. Splitting loop: Collect a sequence of characters that are space
2228		//    characters or U+002C COMMA characters. If any U+002C COMMA characters
2229		//    were collected, that is a parse error.
2230		while (true) {
2231			collectCharacters(regexLeadingCommasOrSpaces);
2232
2233			// 5. If position is past the end of input, return candidates and abort these steps.
2234			if (pos >= inputLength) {
2235				return candidates; // (we're done, this is the sole return path)
2236			}
2237
2238			// 6. Collect a sequence of characters that are not space characters,
2239			//    and let that be url.
2240			url = collectCharacters(regexLeadingNotSpaces);
2241
2242			// 7. Let descriptors be a new empty list.
2243			descriptors = [];
2244
2245			// 8. If url ends with a U+002C COMMA character (,), follow these substeps:
2246			//		(1). Remove all trailing U+002C COMMA characters from url. If this removed
2247			//         more than one character, that is a parse error.
2248			if (url.slice(-1) === ",") {
2249				url = url.replace(regexTrailingCommas, "");
2250				// (Jump ahead to step 9 to skip tokenization and just push the candidate).
2251				parseDescriptors();
2252
2253			//	Otherwise, follow these substeps:
2254			} else {
2255				tokenize();
2256			} // (close else of step 8)
2257
2258		// 16. Return to the step labeled splitting loop.
2259		} // (Close of big while loop.)
2260	}
2261
2262	/*
2263	 * Sizes Parser
2264	 *
2265	 * By Alex Bell |  MIT License
2266	 *
2267	 * Non-strict but accurate and lightweight JS Parser for the string value <img sizes="here">
2268	 *
2269	 * Reference algorithm at:
2270	 * https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-sizes-attribute
2271	 *
2272	 * Most comments are copied in directly from the spec
2273	 * (except for comments in parens).
2274	 *
2275	 * Grammar is:
2276	 * <source-size-list> = <source-size># [ , <source-size-value> ]? | <source-size-value>
2277	 * <source-size> = <media-condition> <source-size-value>
2278	 * <source-size-value> = <length>
2279	 * http://www.w3.org/html/wg/drafts/html/master/embedded-content.html#attr-img-sizes
2280	 *
2281	 * E.g. "(max-width: 30em) 100vw, (max-width: 50em) 70vw, 100vw"
2282	 * or "(min-width: 30em), calc(30vw - 15px)" or just "30vw"
2283	 *
2284	 * Returns the first valid <css-length> with a media condition that evaluates to true,
2285	 * or "100vw" if all valid media conditions evaluate to false.
2286	 *
2287	 */
2288
2289	function parseSizes(strValue) {
2290
2291		// (Percentage CSS lengths are not allowed in this case, to avoid confusion:
2292		// https://html.spec.whatwg.org/multipage/embedded-content.html#valid-source-size-list
2293		// CSS allows a single optional plus or minus sign:
2294		// http://www.w3.org/TR/CSS2/syndata.html#numbers
2295		// CSS is ASCII case-insensitive:
2296		// http://www.w3.org/TR/CSS2/syndata.html#characters )
2297		// Spec allows exponential notation for <number> type:
2298		// http://dev.w3.org/csswg/css-values/#numbers
2299		var regexCssLengthWithUnits = /^(?:[+-]?[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?(?:ch|cm|em|ex|in|mm|pc|pt|px|rem|vh|vmin|vmax|vw)$/i;
2300
2301		// (This is a quick and lenient test. Because of optional unlimited-depth internal
2302		// grouping parens and strict spacing rules, this could get very complicated.)
2303		var regexCssCalc = /^calc\((?:[0-9a-z \.\+\-\*\/\(\)]+)\)$/i;
2304
2305		var i;
2306		var unparsedSizesList;
2307		var unparsedSizesListLength;
2308		var unparsedSize;
2309		var lastComponentValue;
2310		var size;
2311
2312		// UTILITY FUNCTIONS
2313
2314		//  (Toy CSS parser. The goals here are:
2315		//  1) expansive test coverage without the weight of a full CSS parser.
2316		//  2) Avoiding regex wherever convenient.
2317		//  Quick tests: http://jsfiddle.net/gtntL4gr/3/
2318		//  Returns an array of arrays.)
2319		function parseComponentValues(str) {
2320			var chrctr;
2321			var component = "";
2322			var componentArray = [];
2323			var listArray = [];
2324			var parenDepth = 0;
2325			var pos = 0;
2326			var inComment = false;
2327
2328			function pushComponent() {
2329				if (component) {
2330					componentArray.push(component);
2331					component = "";
2332				}
2333			}
2334
2335			function pushComponentArray() {
2336				if (componentArray[0]) {
2337					listArray.push(componentArray);
2338					componentArray = [];
2339				}
2340			}
2341
2342			// (Loop forwards from the beginning of the string.)
2343			while (true) {
2344				chrctr = str.charAt(pos);
2345
2346				if (chrctr === "") { // ( End of string reached.)
2347					pushComponent();
2348					pushComponentArray();
2349					return listArray;
2350				} else if (inComment) {
2351					if ((chrctr === "*") && (str[pos + 1] === "/")) { // (At end of a comment.)
2352						inComment = false;
2353						pos += 2;
2354						pushComponent();
2355						continue;
2356					} else {
2357						pos += 1; // (Skip all characters inside comments.)
2358						continue;
2359					}
2360				} else if (isSpace(chrctr)) {
2361					// (If previous character in loop was also a space, or if
2362					// at the beginning of the string, do not add space char to
2363					// component.)
2364					if ( (str.charAt(pos - 1) && isSpace( str.charAt(pos - 1) ) ) || !component ) {
2365						pos += 1;
2366						continue;
2367					} else if (parenDepth === 0) {
2368						pushComponent();
2369						pos +=1;
2370						continue;
2371					} else {
2372						// (Replace any space character with a plain space for legibility.)
2373						chrctr = " ";
2374					}
2375				} else if (chrctr === "(") {
2376					parenDepth += 1;
2377				} else if (chrctr === ")") {
2378					parenDepth -= 1;
2379				} else if (chrctr === ",") {
2380					pushComponent();
2381					pushComponentArray();
2382					pos += 1;
2383					continue;
2384				} else if ( (chrctr === "/") && (str.charAt(pos + 1) === "*") ) {
2385					inComment = true;
2386					pos += 2;
2387					continue;
2388				}
2389
2390				component = component + chrctr;
2391				pos += 1;
2392			}
2393		}
2394
2395		function isValidNonNegativeSourceSizeValue(s) {
2396			if (regexCssLengthWithUnits.test(s) && (parseFloat(s) >= 0)) {return true;}
2397			if (regexCssCalc.test(s)) {return true;}
2398			// ( http://www.w3.org/TR/CSS2/syndata.html#numbers says:
2399			// "-0 is equivalent to 0 and is not a negative number." which means that
2400			// unitless zero and unitless negative zero must be accepted as special cases.)
2401			if ((s === "0") || (s === "-0") || (s === "+0")) {return true;}
2402			return false;
2403		}
2404
2405		// When asked to parse a sizes attribute from an element, parse a
2406		// comma-separated list of component values from the value of the element's
2407		// sizes attribute (or the empty string, if the attribute is absent), and let
2408		// unparsed sizes list be the result.
2409		// http://dev.w3.org/csswg/css-syntax/#parse-comma-separated-list-of-component-values
2410
2411		unparsedSizesList = parseComponentValues(strValue);
2412		unparsedSizesListLength = unparsedSizesList.length;
2413
2414		// For each unparsed size in unparsed sizes list:
2415		for (i = 0; i < unparsedSizesListLength; i++) {
2416			unparsedSize = unparsedSizesList[i];
2417
2418			// 1. Remove all consecutive <whitespace-token>s from the end of unparsed size.
2419			// ( parseComponentValues() already omits spaces outside of parens. )
2420
2421			// If unparsed size is now empty, that is a parse error; continue to the next
2422			// iteration of this algorithm.
2423			// ( parseComponentValues() won't push an empty array. )
2424
2425			// 2. If the last component value in unparsed size is a valid non-negative
2426			// <source-size-value>, let size be its value and remove the component value
2427			// from unparsed size. Any CSS function other than the calc() function is
2428			// invalid. Otherwise, there is a parse error; continue to the next iteration
2429			// of this algorithm.
2430			// http://dev.w3.org/csswg/css-syntax/#parse-component-value
2431			lastComponentValue = unparsedSize[unparsedSize.length - 1];
2432
2433			if (isValidNonNegativeSourceSizeValue(lastComponentValue)) {
2434				size = lastComponentValue;
2435				unparsedSize.pop();
2436			} else {
2437				continue;
2438			}
2439
2440			// 3. Remove all consecutive <whitespace-token>s from the end of unparsed
2441			// size. If unparsed size is now empty, return size and exit this algorithm.
2442			// If this was not the last item in unparsed sizes list, that is a parse error.
2443			if (unparsedSize.length === 0) {
2444				return size;
2445			}
2446
2447			// 4. Parse the remaining component values in unparsed size as a
2448			// <media-condition>. If it does not parse correctly, or it does parse
2449			// correctly but the <media-condition> evaluates to false, continue to the
2450			// next iteration of this algorithm.
2451			// (Parsing all possible compound media conditions in JS is heavy, complicated,
2452			// and the payoff is unclear. Is there ever an situation where the
2453			// media condition parses incorrectly but still somehow evaluates to true?
2454			// Can we just rely on the browser/polyfill to do it?)
2455			unparsedSize = unparsedSize.join(" ");
2456			if (!(pf.matchesMedia( unparsedSize ) ) ) {
2457				continue;
2458			}
2459
2460			// 5. Return size and exit this algorithm.
2461			return size;
2462		}
2463
2464		// If the above algorithm exhausts unparsed sizes list without returning a
2465		// size value, return 100vw.
2466		return "100vw";
2467	}
2468
2469	// namespace
2470	pf.ns = ("pf" + new Date().getTime()).substr(0, 9);
2471
2472	// srcset support test
2473	pf.supSrcset = "srcset" in image;
2474	pf.supSizes = "sizes" in image;
2475	pf.supPicture = !!window.HTMLPictureElement;
2476
2477	// UC browser does claim to support srcset and picture, but not sizes,
2478	// this extended test reveals the browser does support nothing
2479	if (pf.supSrcset && pf.supPicture && !pf.supSizes) {
2480		(function(image2) {
2481			image.srcset = "data:,a";
2482			image2.src = "data:,a";
2483			pf.supSrcset = image.complete === image2.complete;
2484			pf.supPicture = pf.supSrcset && pf.supPicture;
2485		})(document.createElement("img"));
2486	}
2487
2488	// Safari9 has basic support for sizes, but does't expose the `sizes` idl attribute
2489	if (pf.supSrcset && !pf.supSizes) {
2490
2491		(function() {
2492			var width2 = "data:image/gif;base64,R0lGODlhAgABAPAAAP///wAAACH5BAAAAAAALAAAAAACAAEAAAICBAoAOw==";
2493			var width1 = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
2494			var img = document.createElement("img");
2495			var test = function() {
2496				var width = img.width;
2497
2498				if (width === 2) {
2499					pf.supSizes = true;
2500				}
2501
2502				alwaysCheckWDescriptor = pf.supSrcset && !pf.supSizes;
2503
2504				isSupportTestReady = true;
2505				// force async
2506				setTimeout(picturefill);
2507			};
2508
2509			img.onload = test;
2510			img.onerror = test;
2511			img.setAttribute("sizes", "9px");
2512
2513			img.srcset = width1 + " 1w," + width2 + " 9w";
2514			img.src = width1;
2515		})();
2516
2517	} else {
2518		isSupportTestReady = true;
2519	}
2520
2521	// using pf.qsa instead of dom traversing does scale much better,
2522	// especially on sites mixing responsive and non-responsive images
2523	pf.selShort = "picture>img,img[srcset]";
2524	pf.sel = pf.selShort;
2525	pf.cfg = cfg;
2526
2527	/**
2528	 * Shortcut property for `devicePixelRatio` ( for easy overriding in tests )
2529	 */
2530	pf.DPR = (DPR  || 1 );
2531	pf.u = units;
2532
2533	// container of supported mime types that one might need to qualify before using
2534	pf.types =  types;
2535
2536	pf.setSize = noop;
2537
2538	/**
2539	 * Gets a string and returns the absolute URL
2540	 * @param src
2541	 * @returns {String} absolute URL
2542	 */
2543
2544	pf.makeUrl = memoize(function(src) {
2545		anchor.href = src;
2546		return anchor.href;
2547	});
2548
2549	/**
2550	 * Gets a DOM element or document and a selctor and returns the found matches
2551	 * Can be extended with jQuery/Sizzle for IE7 support
2552	 * @param context
2553	 * @param sel
2554	 * @returns {NodeList|Array}
2555	 */
2556	pf.qsa = function(context, sel) {
2557		return ( "querySelector" in context ) ? context.querySelectorAll(sel) : [];
2558	};
2559
2560	/**
2561	 * Shortcut method for matchMedia ( for easy overriding in tests )
2562	 * wether native or pf.mMQ is used will be decided lazy on first call
2563	 * @returns {boolean}
2564	 */
2565	pf.matchesMedia = function() {
2566		if ( window.matchMedia && (matchMedia( "(min-width: 0.1em)" ) || {}).matches ) {
2567			pf.matchesMedia = function( media ) {
2568				return !media || ( matchMedia( media ).matches );
2569			};
2570		} else {
2571			pf.matchesMedia = pf.mMQ;
2572		}
2573
2574		return pf.matchesMedia.apply( this, arguments );
2575	};
2576
2577	/**
2578	 * A simplified matchMedia implementation for IE8 and IE9
2579	 * handles only min-width/max-width with px or em values
2580	 * @param media
2581	 * @returns {boolean}
2582	 */
2583	pf.mMQ = function( media ) {
2584		return media ? evalCSS(media) : true;
2585	};
2586
2587	/**
2588	 * Returns the calculated length in css pixel from the given sourceSizeValue
2589	 * http://dev.w3.org/csswg/css-values-3/#length-value
2590	 * intended Spec mismatches:
2591	 * * Does not check for invalid use of CSS functions
2592	 * * Does handle a computed length of 0 the same as a negative and therefore invalid value
2593	 * @param sourceSizeValue
2594	 * @returns {Number}
2595	 */
2596	pf.calcLength = function( sourceSizeValue ) {
2597
2598		var value = evalCSS(sourceSizeValue, true) || false;
2599		if (value < 0) {
2600			value = false;
2601		}
2602
2603		return value;
2604	};
2605
2606	/**
2607	 * Takes a type string and checks if its supported
2608	 */
2609
2610	pf.supportsType = function( type ) {
2611		return ( type ) ? types[ type ] : true;
2612	};
2613
2614	/**
2615	 * Parses a sourceSize into mediaCondition (media) and sourceSizeValue (length)
2616	 * @param sourceSizeStr
2617	 * @returns {*}
2618	 */
2619	pf.parseSize = memoize(function( sourceSizeStr ) {
2620		var match = ( sourceSizeStr || "" ).match(regSize);
2621		return {
2622			media: match && match[1],
2623			length: match && match[2]
2624		};
2625	});
2626
2627	pf.parseSet = function( set ) {
2628		if ( !set.cands ) {
2629			set.cands = parseSrcset(set.srcset, set);
2630		}
2631		return set.cands;
2632	};
2633
2634	/**
2635	 * returns 1em in css px for html/body default size
2636	 * function taken from respondjs
2637	 * @returns {*|number}
2638	 */
2639	pf.getEmValue = function() {
2640		var body;
2641		if ( !eminpx && (body = document.body) ) {
2642			var div = document.createElement( "div" ),
2643				originalHTMLCSS = docElem.style.cssText,
2644				originalBodyCSS = body.style.cssText;
2645
2646			div.style.cssText = baseStyle;
2647
2648			// 1em in a media query is the value of the default font size of the browser
2649			// reset docElem and body to ensure the correct value is returned
2650			docElem.style.cssText = fsCss;
2651			body.style.cssText = fsCss;
2652
2653			body.appendChild( div );
2654			eminpx = div.offsetWidth;
2655			body.removeChild( div );
2656
2657			//also update eminpx before returning
2658			eminpx = parseFloat( eminpx, 10 );
2659
2660			// restore the original values
2661			docElem.style.cssText = originalHTMLCSS;
2662			body.style.cssText = originalBodyCSS;
2663
2664		}
2665		return eminpx || 16;
2666	};
2667
2668	/**
2669	 * Takes a string of sizes and returns the width in pixels as a number
2670	 */
2671	pf.calcListLength = function( sourceSizeListStr ) {
2672		// Split up source size list, ie ( max-width: 30em ) 100%, ( max-width: 50em ) 50%, 33%
2673		//
2674		//                           or (min-width:30em) calc(30% - 15px)
2675		if ( !(sourceSizeListStr in sizeLengthCache) || cfg.uT ) {
2676			var winningLength = pf.calcLength( parseSizes( sourceSizeListStr ) );
2677
2678			sizeLengthCache[ sourceSizeListStr ] = !winningLength ? units.width : winningLength;
2679		}
2680
2681		return sizeLengthCache[ sourceSizeListStr ];
2682	};
2683
2684	/**
2685	 * Takes a candidate object with a srcset property in the form of url/
2686	 * ex. "images/pic-medium.png 1x, images/pic-medium-2x.png 2x" or
2687	 *     "images/pic-medium.png 400w, images/pic-medium-2x.png 800w" or
2688	 *     "images/pic-small.png"
2689	 * Get an array of image candidates in the form of
2690	 *      {url: "/foo/bar.png", resolution: 1}
2691	 * where resolution is http://dev.w3.org/csswg/css-values-3/#resolution-value
2692	 * If sizes is specified, res is calculated
2693	 */
2694	pf.setRes = function( set ) {
2695		var candidates;
2696		if ( set ) {
2697
2698			candidates = pf.parseSet( set );
2699
2700			for ( var i = 0, len = candidates.length; i < len; i++ ) {
2701				setResolution( candidates[ i ], set.sizes );
2702			}
2703		}
2704		return candidates;
2705	};
2706
2707	pf.setRes.res = setResolution;
2708
2709	pf.applySetCandidate = function( candidates, img ) {
2710		if ( !candidates.length ) {return;}
2711		var candidate,
2712			i,
2713			j,
2714			length,
2715			bestCandidate,
2716			curSrc,
2717			curCan,
2718			candidateSrc,
2719			abortCurSrc;
2720
2721		var imageData = img[ pf.ns ];
2722		var dpr = pf.DPR;
2723
2724		curSrc = imageData.curSrc || img[curSrcProp];
2725
2726		curCan = imageData.curCan || setSrcToCur(img, curSrc, candidates[0].set);
2727
2728		// if we have a current source, we might either become lazy or give this source some advantage
2729		if ( curCan && curCan.set === candidates[ 0 ].set ) {
2730
2731			// if browser can abort image request and the image has a higher pixel density than needed
2732			// and this image isn't downloaded yet, we skip next part and try to save bandwidth
2733			abortCurSrc = (supportAbort && !img.complete && curCan.res - 0.1 > dpr);
2734
2735			if ( !abortCurSrc ) {
2736				curCan.cached = true;
2737
2738				// if current candidate is "best", "better" or "okay",
2739				// set it to bestCandidate
2740				if ( curCan.res >= dpr ) {
2741					bestCandidate = curCan;
2742				}
2743			}
2744		}
2745
2746		if ( !bestCandidate ) {
2747
2748			candidates.sort( ascendingSort );
2749
2750			length = candidates.length;
2751			bestCandidate = candidates[ length - 1 ];
2752
2753			for ( i = 0; i < length; i++ ) {
2754				candidate = candidates[ i ];
2755				if ( candidate.res >= dpr ) {
2756					j = i - 1;
2757
2758					// we have found the perfect candidate,
2759					// but let's improve this a little bit with some assumptions ;-)
2760					if (candidates[ j ] &&
2761						(abortCurSrc || curSrc !== pf.makeUrl( candidate.url )) &&
2762						chooseLowRes(candidates[ j ].res, candidate.res, dpr, candidates[ j ].cached)) {
2763
2764						bestCandidate = candidates[ j ];
2765
2766					} else {
2767						bestCandidate = candidate;
2768					}
2769					break;
2770				}
2771			}
2772		}
2773
2774		if ( bestCandidate ) {
2775
2776			candidateSrc = pf.makeUrl( bestCandidate.url );
2777
2778			imageData.curSrc = candidateSrc;
2779			imageData.curCan = bestCandidate;
2780
2781			if ( candidateSrc !== curSrc ) {
2782				pf.setSrc( img, bestCandidate );
2783			}
2784			pf.setSize( img );
2785		}
2786	};
2787
2788	pf.setSrc = function( img, bestCandidate ) {
2789		var origWidth;
2790		img.src = bestCandidate.url;
2791
2792		// although this is a specific Safari issue, we don't want to take too much different code paths
2793		if ( bestCandidate.set.type === "image/svg+xml" ) {
2794			origWidth = img.style.width;
2795			img.style.width = (img.offsetWidth + 1) + "px";
2796
2797			// next line only should trigger a repaint
2798			// if... is only done to trick dead code removal
2799			if ( img.offsetWidth + 1 ) {
2800				img.style.width = origWidth;
2801			}
2802		}
2803	};
2804
2805	pf.getSet = function( img ) {
2806		var i, set, supportsType;
2807		var match = false;
2808		var sets = img [ pf.ns ].sets;
2809
2810		for ( i = 0; i < sets.length && !match; i++ ) {
2811			set = sets[i];
2812
2813			if ( !set.srcset || !pf.matchesMedia( set.media ) || !(supportsType = pf.supportsType( set.type )) ) {
2814				continue;
2815			}
2816
2817			if ( supportsType === "pending" ) {
2818				set = supportsType;
2819			}
2820
2821			match = set;
2822			break;
2823		}
2824
2825		return match;
2826	};
2827
2828	pf.parseSets = function( element, parent, options ) {
2829		var srcsetAttribute, imageSet, isWDescripor, srcsetParsed;
2830
2831		var hasPicture = parent && parent.nodeName.toUpperCase() === "PICTURE";
2832		var imageData = element[ pf.ns ];
2833
2834		if ( imageData.src === undefined || options.src ) {
2835			imageData.src = getImgAttr.call( element, "src" );
2836			if ( imageData.src ) {
2837				setImgAttr.call( element, srcAttr, imageData.src );
2838			} else {
2839				removeImgAttr.call( element, srcAttr );
2840			}
2841		}
2842
2843		if ( imageData.srcset === undefined || options.srcset || !pf.supSrcset || element.srcset ) {
2844			srcsetAttribute = getImgAttr.call( element, "srcset" );
2845			imageData.srcset = srcsetAttribute;
2846			srcsetParsed = true;
2847		}
2848
2849		imageData.sets = [];
2850
2851		if ( hasPicture ) {
2852			imageData.pic = true;
2853			getAllSourceElements( parent, imageData.sets );
2854		}
2855
2856		if ( imageData.srcset ) {
2857			imageSet = {
2858				srcset: imageData.srcset,
2859				sizes: getImgAttr.call( element, "sizes" )
2860			};
2861
2862			imageData.sets.push( imageSet );
2863
2864			isWDescripor = (alwaysCheckWDescriptor || imageData.src) && regWDesc.test(imageData.srcset || "");
2865
2866			// add normal src as candidate, if source has no w descriptor
2867			if ( !isWDescripor && imageData.src && !getCandidateForSrc(imageData.src, imageSet) && !imageSet.has1x ) {
2868				imageSet.srcset += ", " + imageData.src;
2869				imageSet.cands.push({
2870					url: imageData.src,
2871					d: 1,
2872					set: imageSet
2873				});
2874			}
2875
2876		} else if ( imageData.src ) {
2877			imageData.sets.push( {
2878				srcset: imageData.src,
2879				sizes: null
2880			} );
2881		}
2882
2883		imageData.curCan = null;
2884		imageData.curSrc = undefined;
2885
2886		// if img has picture or the srcset was removed or has a srcset and does not support srcset at all
2887		// or has a w descriptor (and does not support sizes) set support to false to evaluate
2888		imageData.supported = !( hasPicture || ( imageSet && !pf.supSrcset ) || (isWDescripor && !pf.supSizes) );
2889
2890		if ( srcsetParsed && pf.supSrcset && !imageData.supported ) {
2891			if ( srcsetAttribute ) {
2892				setImgAttr.call( element, srcsetAttr, srcsetAttribute );
2893				element.srcset = "";
2894			} else {
2895				removeImgAttr.call( element, srcsetAttr );
2896			}
2897		}
2898
2899		if (imageData.supported && !imageData.srcset && ((!imageData.src && element.src) ||  element.src !== pf.makeUrl(imageData.src))) {
2900			if (imageData.src === null) {
2901				element.removeAttribute("src");
2902			} else {
2903				element.src = imageData.src;
2904			}
2905		}
2906
2907		imageData.parsed = true;
2908	};
2909
2910	pf.fillImg = function(element, options) {
2911		var imageData;
2912		var extreme = options.reselect || options.reevaluate;
2913
2914		// expando for caching data on the img
2915		if ( !element[ pf.ns ] ) {
2916			element[ pf.ns ] = {};
2917		}
2918
2919		imageData = element[ pf.ns ];
2920
2921		// if the element has already been evaluated, skip it
2922		// unless `options.reevaluate` is set to true ( this, for example,
2923		// is set to true when running `picturefill` on `resize` ).
2924		if ( !extreme && imageData.evaled === evalId ) {
2925			return;
2926		}
2927
2928		if ( !imageData.parsed || options.reevaluate ) {
2929			pf.parseSets( element, element.parentNode, options );
2930		}
2931
2932		if ( !imageData.supported ) {
2933			applyBestCandidate( element );
2934		} else {
2935			imageData.evaled = evalId;
2936		}
2937	};
2938
2939	pf.setupRun = function() {
2940		if ( !alreadyRun || isVwDirty || (DPR !== window.devicePixelRatio) ) {
2941			updateMetrics();
2942		}
2943	};
2944
2945	// If picture is supported, well, that's awesome.
2946	if ( pf.supPicture ) {
2947		picturefill = noop;
2948		pf.fillImg = noop;
2949	} else {
2950
2951		 // Set up picture polyfill by polling the document
2952		(function() {
2953			var isDomReady;
2954			var regReady = window.attachEvent ? /d$|^c/ : /d$|^c|^i/;
2955
2956			var run = function() {
2957				var readyState = document.readyState || "";
2958
2959				timerId = setTimeout(run, readyState === "loading" ? 200 :  999);
2960				if ( document.body ) {
2961					pf.fillImgs();
2962					isDomReady = isDomReady || regReady.test(readyState);
2963					if ( isDomReady ) {
2964						clearTimeout( timerId );
2965					}
2966
2967				}
2968			};
2969
2970			var timerId = setTimeout(run, document.body ? 9 : 99);
2971
2972			// Also attach picturefill on resize and readystatechange
2973			// http://modernjavascript.blogspot.com/2013/08/building-better-debounce.html
2974			var debounce = function(func, wait) {
2975				var timeout, timestamp;
2976				var later = function() {
2977					var last = (new Date()) - timestamp;
2978
2979					if (last < wait) {
2980						timeout = setTimeout(later, wait - last);
2981					} else {
2982						timeout = null;
2983						func();
2984					}
2985				};
2986
2987				return function() {
2988					timestamp = new Date();
2989
2990					if (!timeout) {
2991						timeout = setTimeout(later, wait);
2992					}
2993				};
2994			};
2995			var lastClientWidth = docElem.clientHeight;
2996			var onResize = function() {
2997				isVwDirty = Math.max(window.innerWidth || 0, docElem.clientWidth) !== units.width || docElem.clientHeight !== lastClientWidth;
2998				lastClientWidth = docElem.clientHeight;
2999				if ( isVwDirty ) {
3000					pf.fillImgs();
3001				}
3002			};
3003
3004			on( window, "resize", debounce(onResize, 99 ) );
3005			on( document, "readystatechange", run );
3006		})();
3007	}
3008
3009	pf.picturefill = picturefill;
3010	//use this internally for easy monkey patching/performance testing
3011	pf.fillImgs = picturefill;
3012	pf.teardownRun = noop;
3013
3014	/* expose methods for testing */
3015	picturefill._ = pf;
3016
3017	window.picturefillCFG = {
3018		pf: pf,
3019		push: function(args) {
3020			var name = args.shift();
3021			if (typeof pf[name] === "function") {
3022				pf[name].apply(pf, args);
3023			} else {
3024				cfg[name] = args[0];
3025				if (alreadyRun) {
3026					pf.fillImgs( { reselect: true } );
3027				}
3028			}
3029		}
3030	};
3031
3032	while (setOptions && setOptions.length) {
3033		window.picturefillCFG.push(setOptions.shift());
3034	}
3035
3036	/* expose picturefill */
3037	window.picturefill = picturefill;
3038
3039	/* expose picturefill */
3040	if ( typeof module === "object" && typeof module.exports === "object" ) {
3041		// CommonJS, just export
3042		module.exports = picturefill;
3043	} else if ( typeof define === "function" && define.amd ) {
3044		// AMD support
3045		define( "picturefill", function() { return picturefill; } );
3046	}
3047
3048	// IE8 evals this sync, so it must be the last thing we do
3049	if ( !pf.supPicture ) {
3050		types[ "image/webp" ] = detectTypeSupport("image/webp", "data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==" );
3051	}
3052
3053} )( window, document );
3054
3055
3056// Custom JS for the Header.
3057// ----------------------------------------------------------------------------
3058
3059// Adds User Agent and Operating System
3060// details to the <html> tag.
3061// -------------------------------------
3062var b = document.documentElement;
3063    b.setAttribute('data-useragent',  navigator.userAgent);
3064    b.setAttribute('data-platform', navigator.platform );
3065    b.className += ((!!('ontouchstart' in window) || !!('onmsgesturechange' in window))?' touch':'');

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.