New Upstream Snapshot - modernizr

Ready changes

Summary

Merged new upstream version: 3.11.0+git20221020.1.86ebb04+ds1 (was: 2.6.2+ds1).

Diff

diff --git a/.editorconfig b/.editorconfig
deleted file mode 100644
index 0f09989..0000000
--- a/.editorconfig
+++ /dev/null
@@ -1,10 +0,0 @@
-# editorconfig.org
-root = true
-
-[*]
-indent_style = space
-indent_size = 2
-end_of_line = lf
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
diff --git a/.gitignore b/.gitignore
deleted file mode 100644
index 9c4d3b4..0000000
--- a/.gitignore
+++ /dev/null
@@ -1,2 +0,0 @@
-modernizr.min.js
-.DS_Store
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 1a0d9c0..0000000
--- a/.travis.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-language: node_js
-node_js:
-  - 0.8
-before_script:
-  - npm install grunt
-script: grunt travis --verbose
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..bfb12d0
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2021 The Modernizr Team | Modernizr 4.0.0-alpha
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/README.id.md b/README.id.md
new file mode 100644
index 0000000..3abcb20
--- /dev/null
+++ b/README.id.md
@@ -0,0 +1,149 @@
+<p align="center">
+   <a href="https://www.npmjs.com/package/modernizr" rel="noopener" target="_blank"><img alt="Modernizr" src="./media/Modernizr-2-Logo-vertical-medium.png" width="250" /></a>
+</p>
+
+<div align="center">
+  
+##### Modernizr adalah library JavaScript yang mendeteksi fitur HTML5 dan CSS3 di browser pengguna.
+  
+[![npm version](https://badge.fury.io/js/modernizr.svg)](https://badge.fury.io/js/modernizr)
+[![Build Status](https://github.com/Modernizr/Modernizr/workflows/Testing/badge.svg)](https://github.com/Modernizr/Modernizr/actions)
+[![codecov](https://codecov.io/gh/Modernizr/Modernizr/branch/master/graph/badge.svg)](https://codecov.io/gh/Modernizr/Modernizr)
+[![Inline docs](https://inch-ci.org/github/Modernizr/Modernizr.svg?branch=master)](https://inch-ci.org/github/Modernizr/Modernizr)
+
+</div>
+
+- Baca file ini dengan bahasa Portuguese-BR [disini](/README.pt_br.md)
+- Baca file ini dengan bahasa Indonesia [disini](/README.id.md)
+
+- Situs web kami sudah lama dan rusak, mohon JANGAN menggunakannya (https://modernizr.com) melainkan buat versi modernizr dari npm.
+- [Dokumentasi](https://modernizr.com/docs/)
+- [Tes integrasi](https://modernizr.github.io/Modernizr/test/integration.html)
+- [Tes unit](https://modernizr.github.io/Modernizr/test/unit.html)
+
+Modernizr menguji fitur CSS3 dan HTML5 asli mana yang tersedia di UA saat ini dan membuat hasilnya tersedia untuk Anda dalam dua cara: sebagai properti pada objek `Modernizr` global, dan sebagai kelas pada elemen `<html>`. Informasi ini memungkinkan anda untuk meningkatkan halaman Anda secara bertahap dengan tingkat kontrol yang terperinci.
+
+## Melanggar Perubahan Dengan v4
+
+- Menjatuhkan dukungan untuk versi node <= 10, harap tingkatkan ke setidaknya versi 12
+
+- Tes berikut diganti namanya:
+  
+  - `class` ke `es6class` agar tetap sejalan dengan es-test lainnya
+
+- Tes berikut dipindahkan di subdirektori:
+
+  - `cookies`, `indexeddb`, `indexedblob`, `quota-management-api`, `userdata` pindahkan ke subdirektori penyimpanan 
+  - `audio` 
+  - `battery` pindahkan ke subdirektori audio
+  - `canvas`, `canvastext` pindahkan ke subdirektori canvas
+  - `customevent`, `eventlistener`, `forcetouch`, `hashchange`, `pointerevents`, `proximity` pindahkan ke subdirektori event
+  - `exiforientation` pindahkan ke subdirektori gambar
+  - `capture`, `fileinput`, `fileinputdirectory`, `formatattribute`, `input`, `inputnumber-l10n`, `inputsearchevent`, `inputtypes`, `placeholder`, `requestautocomplete`, `validation` pindahkan ke subdirektori input
+  - `svg` pindahkan ke subdirektori svg
+  - `webgl` pindahkan ke subdirektori webgl
+     
+- Tes berikut yang telah dihapus:
+  
+  - `touchevents`: [diskusi](https://github.com/Modernizr/Modernizr/pull/2432)
+  - `unicode`: [diskusi](https://github.com/Modernizr/Modernizr/issues/2468)
+  - `templatestrings`: duplikat dari deteksi es6 `stringtemplate`
+  - `contains`: duplikat dari deteksi es6 `es6string`
+  - `datalistelem`: memanipulasi dari Modernizr.input.list
+
+## New Asynchronous Event Listeners
+
+Sering kali orang ingin tahu kapan pengujian asynchronous dilakukan sehingga mereka dapat mengizinkan aplikasi mereka untuk bereaksi terhadapnya. Di masa lalu, Anda harus mengandalkan properti menonton atau kelas `<html>`. Hanya peristiwa pada pengujian **asynchronous** yang didukung. Tes sinkron harus ditangani secara sinkron untuk meningkatkan kecepatan dan menjaga konsistensi.
+
+API baru terlihat seperti ini:
+
+```js
+// Listen to a test, give it a callback
+Modernizr.on('testname', function( result ) {
+  if (result) {
+    console.log('The test passed!');
+  }
+  else {
+    console.log('The test failed!');
+  }
+});
+```
+
+Kami menjamin bahwa kami hanya akan memanggil fungsi Anda sekali (per kali Anda memanggil `on`). Kami saat ini tidak mengekspos
+metode untuk mengekspos fungsionalitas `trigger`. Sebagai gantinya, jika Anda ingin memiliki kontrol atas pengujian async, gunakan fitur `src/addTest`, dan pengujian apa pun yang Anda setel akan secara otomatis mengekspos dan memicu fungsionalitas `on`.
+
+## Getting Started
+
+- Kloning atau unduh repository
+- Install dependensi proyek dengan `npm install`
+
+## Membangun Modernizr 
+
+### Dari javascript
+
+Modernizr dapat digunakan secara terprogram melalui npm:
+
+```js
+var modernizr = require("modernizr");
+```
+
+Metode `build` diekspos untuk menghasilkan build Modernizr kustom. Contoh:
+
+```javascript
+var modernizr = require("modernizr");
+
+modernizr.build({}, function (result) {
+  console.log(result); // the build
+});
+```
+
+Parameter pertama mengambil objek opsi JSON dan deteksi fitur untuk disertakan. Lihat [`lib/config-all.json`](lib/config-all.json) untuk semua opsi yang tersedia.
+
+Parameter kedua adalah fungsi yang dipanggil pada penyelesaian tugas.
+
+### Dari command-line
+
+Kami juga menyediakan antarmuka baris perintah untuk membangun modernizr.
+Untuk melihat semua opsi yang tersedia, jalankan:
+
+```shell
+./bin/modernizr
+```
+
+Atau untuk menghasilkan semua yang ada di 'config-all.json', jalankan ini dengan npm:
+
+```shell
+npm start
+//outputs to ./dist/modernizr-build.js
+```
+
+## Testing Modernizr
+
+Untuk menjalankan tes menggunakan mocha-headless-chrome di konsol, jalankan:
+
+```shell
+npm test
+```
+
+Anda juga dapat menjalankan tes di browser pilihan Anda dengan perintah ini:
+
+```shell
+npm run serve-gh-pages
+```
+
+dan menavigasi ke dua URL ini:
+
+```shell
+http://localhost:8080/test/unit.html
+http://localhost:8080/test/integration.html
+```
+
+## Code of Conduct
+
+Proyek ini mematuhi [Open Code of Conduct](https://github.com/Modernizr/Modernizr/blob/master/.github/CODE_OF_CONDUCT.md). 
+Dengan berpertisipasi, anda diharapkan untuk menghormati code ini.
+
+
+## License
+
+[Lisensi MIT](https://opensource.org/licenses/MIT)
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..ad6cc14
--- /dev/null
+++ b/README.md
@@ -0,0 +1,155 @@
+<p align="center">
+   <a href="https://www.npmjs.com/package/modernizr" rel="noopener" target="_blank"><img alt="Modernizr" src="./media/Modernizr-2-Logo-vertical-medium.png" width="250" /></a>
+</p>
+
+<div align="center">
+  
+##### Modernizr is a JavaScript library that detects HTML5 and CSS3 features in the user’s browser.
+  
+[![npm version](https://badge.fury.io/js/modernizr.svg)](https://badge.fury.io/js/modernizr)
+[![Build Status](https://github.com/Modernizr/Modernizr/workflows/Testing/badge.svg)](https://github.com/Modernizr/Modernizr/actions)
+[![codecov](https://codecov.io/gh/Modernizr/Modernizr/branch/master/graph/badge.svg)](https://codecov.io/gh/Modernizr/Modernizr)
+[![Inline docs](https://inch-ci.org/github/Modernizr/Modernizr.svg?branch=master)](https://inch-ci.org/github/Modernizr/Modernizr)
+
+</div>
+
+- Read this file in Portuguese-BR [here](/README.pt_br.md)
+- Read this file in Indonesian [here](/README.id.md)
+- Read this file in Spanish [here](/README.sp.md)
+- Read this file in Swedish [here](/README.sv.md)
+- Read this file in Tamil [here](/README.ta.md)
+
+- Our Website is outdated and broken, please DO NOT use it (https://modernizr.com) but rather build your modernizr version from npm.
+- [Documentation](https://modernizr.com/docs/)
+- [Integration tests](https://modernizr.github.io/Modernizr/test/integration.html)
+- [Unit tests](https://modernizr.github.io/Modernizr/test/unit.html)
+
+Modernizr tests which native CSS3 and HTML5 features are available in the current UA and makes the results available to you in two ways: as properties on a global `Modernizr` object, and as classes on the `<html>` element. This information allows you to progressively enhance your pages with a granular level of control over the experience.
+
+## Breaking changes with v4
+
+- Dropped support for node versions <= 10, please upgrade to at least version 12
+
+- Following tests got renamed:
+  
+  - `class` to `es6class` to keep in line with the rest of the es-tests
+
+- Following tests got moved in subdirectories:
+
+  - `cookies`, `indexeddb`, `indexedblob`, `quota-management-api`, `userdata` moved into the storage subdirectory
+  - `audio` moved into the audio subdirectory
+  - `battery` moved into the battery subdirectory
+  - `canvas`, `canvastext` moved into the canvas subdirectory
+  - `customevent`, `eventlistener`, `forcetouch`, `hashchange`, `pointerevents`, `proximity` moved into the event subdirectory
+  - `exiforientation` moved into the image subdirectory
+  - `capture`, `fileinput`, `fileinputdirectory`, `formatattribute`, `input`, `inputnumber-l10n`, `inputsearchevent`, `inputtypes`, `placeholder`, `requestautocomplete`, `validation` moved into the input subdirectory
+  - `svg` moved into the svg subdirectory
+  - `webgl` moved into the webgl subdirectory
+     
+- Following tests got removed:
+  
+  - `touchevents`: [discussion](https://github.com/Modernizr/Modernizr/pull/2432)
+  - `unicode`: [discussion](https://github.com/Modernizr/Modernizr/issues/2468)
+  - `templatestrings`: duplicate of the es6 detect `stringtemplate`
+  - `contains`: duplicate of the es6 detect `es6string`
+  - `datalistelem`: A dupe of Modernizr.input.list
+
+## New Asynchronous Event Listeners
+
+Often times people want to know when an asynchronous test is done so they can allow their application to react to it.
+In the past, you've had to rely on watching properties or `<html>` classes. Only events on **asynchronous** tests are
+supported. Synchronous tests should be handled synchronously to improve speed and to maintain consistency.
+
+The new API looks like this:
+
+```js
+// Listen to a test, give it a callback
+Modernizr.on('testname', function( result ) {
+  if (result) {
+    console.log('The test passed!');
+  }
+  else {
+    console.log('The test failed!');
+  }
+});
+```
+
+We guarantee that we'll only invoke your function once (per time that you call `on`). We are currently not exposing
+a method for exposing the `trigger` functionality. Instead, if you'd like to have control over async tests, use the
+`src/addTest` feature, and any test that you set will automatically expose and trigger the `on` functionality.
+
+## Getting Started
+
+- Clone or download the repository
+- Install project dependencies with `npm install`
+
+## Building Modernizr 
+
+### From javascript
+
+Modernizr can be used programmatically via npm:
+
+```js
+var modernizr = require("modernizr");
+```
+
+A `build` method is exposed for generating custom Modernizr builds. Example:
+
+```javascript
+var modernizr = require("modernizr");
+
+modernizr.build({}, function (result) {
+  console.log(result); // the build
+});
+```
+
+The first parameter takes a JSON object of options and feature-detects to include. See [`lib/config-all.json`](lib/config-all.json) for all available options.
+
+The second parameter is a function invoked on task completion.
+
+### From the command-line
+
+We also provide a command line interface for building modernizr. 
+To see all available options run:
+
+```shell
+./bin/modernizr
+```
+
+Or to generate everything in 'config-all.json' run this with npm:
+
+```shell
+npm start
+//outputs to ./dist/modernizr-build.js
+```
+
+## Testing Modernizr
+
+To execute the tests using mocha-headless-chrome on the console run:
+
+```shell
+npm test
+```
+
+You can also run tests in the browser of your choice with this command:
+
+```shell
+npm run serve-gh-pages
+```
+
+and navigating to these two URLs:
+
+```shell
+http://localhost:8080/test/unit.html
+http://localhost:8080/test/integration.html
+```
+
+## Code of Conduct
+
+This project adheres to the [Open Code of Conduct](https://github.com/Modernizr/Modernizr/blob/master/.github/CODE_OF_CONDUCT.md). 
+By participating, you are expected to honor this code.
+
+
+## License
+
+[MIT License](https://opensource.org/licenses/MIT)
diff --git a/README.pt_br.md b/README.pt_br.md
new file mode 100644
index 0000000..ad2105e
--- /dev/null
+++ b/README.pt_br.md
@@ -0,0 +1,117 @@
+# Português-BR
+
+##### Modernizr é uma biblioteca de JavaScript que detecta recursos HTML5 e CSS3 no navegador do usuário.
+
+- [Website](https://modernizr.com)
+- [Documentação](https://modernizr.com/docs/)
+- [Teste de integração](https://modernizr.github.io/Modernizr/test/integration.html)
+- [Teste de unit](https://modernizr.github.io/Modernizr/test/unit.html)
+
+Modernizr testa quais recursos nativos de HTML5 e CSS3 estão disponíveis na UA atual, e deixa os recursos disponíveis para você em duas maneiras: como propriedades num objeto global `Modernizr`, e como classes no elemento `<html>`. Essa informação permite que você melhore progressivamente suas páginas com um nível granular de controle sobre a experiência.
+
+## Mudanças com a v4
+
+- Fechou o suporte para Node 8, por favor atualize para Node v10
+
+- Esses testes foram removidos:
+
+    - `touchevents`: [discussion](https://github.com/Modernizr/Modernizr/pull/2432) 
+    - `unicode`: [discussion](https://github.com/Modernizr/Modernizr/issues/2468) 
+    - `templatestrings`: duplicate of the es6 detect `stringtemplate`
+    - `contains`: duplicate of the es6 detect `es6string`
+    - `datalistelem`: A dupe of Modernizr.input.list
+
+## Novos Event Listeners Assíncronos
+
+Várias vezes as pessoas querem saber quando um teste assíncrono é feito pra que eles possam autorizar suas aplicações a reagir com ele. No passado, tinha que confiar em ficar monitorando propriedades ou em classes `<html>`. Apenas eventos em testes **asynchronous** possuem suporte. Testes síncronos devem ser manipulados sincronamente para aumentar velocidade e manter consistência.
+
+A API nova está assim:
+
+```js
+// Listen to a test, give it a callback
+Modernizr.on('testname', function( result ) {
+  if (result) {
+    console.log('O teste passou!');
+  }
+  else {
+    console.log('O teste falhou!');
+  }
+});
+```
+
+Nós garantimos que só vamos invocar sua função uma vez (por vezes que você chame `on`). Atualmente não estamos expondo um método para expôr a funcionalidade `trigger`. Em vez disso, se você gostaria de ter controle sobre testes assíncronos, use o recurso `src/addTest`, e qualquer teste que você faça vai automaticamente expôr e ativar a funcionalidade `on`.
+
+## Começando
+
+- Clone ou baixe o repositório
+- Instale as dependências do projeto com `npm install`
+
+## Construindo Modernizr 
+
+### Pelo JavaScript
+
+Modernizr pode ser usado programaticamente via npm:
+
+```js
+var modernizr = require("modernizr");
+```
+
+Um método `build` é exposto para gerar builds customizadas do Modernizr. Exemplo: 
+
+```javascript
+var modernizr = require("modernizr");
+
+modernizr.build({}, function (result) {
+  console.log(result); // a build
+});
+```
+
+O primeiro parâmetro pega um objeto JSON de opções e detector de recursos para incluir. Veja [`lib/config-all.json`](lib/config-all.json) para todas opções disponíveis.
+
+O segundo parâmetro é uma função invocada pela conclusão de tarefa.
+
+### Pela linha de comando
+
+Nós também disponibilizamos uma interface na linha de comando para a construção do Modernizr. Para ver todas opções disponíveis digite:
+
+```shell
+./bin/modernizr
+```
+
+Ou para gerar tudo no 'config-all.json' digite isso com o npm:
+
+```shell
+npm start
+//outputs to ./dist/modernizr-build.js
+```
+
+## Testando Modernizr
+
+Para executar os testes usando mocha-headless-chrome no console, use:
+
+```shell
+npm test
+```
+
+Também tem como fazer testes no navegador de sua escolha com esse comando:
+
+```shell
+npm run serve-gh-pages
+```
+
+e navegando para essas duas URLs:
+
+```shell
+http://localhost:8080/test/unit.html
+http://localhost:8080/test/integration.html
+```
+
+## Código de Conduta
+
+Este projeto adere ao [Código Aberto de Conduta](https://github.com/Modernizr/Modernizr/blob/master/.github/CODE_OF_CONDUCT.md). 
+Participando deste projeto, é esperado que você honre esse código.
+
+
+## Licensa
+
+[Licensa MIT](https://opensource.org/licenses/MIT)
\ No newline at end of file
diff --git a/README.sp.md b/README.sp.md
new file mode 100644
index 0000000..ce728f7
--- /dev/null
+++ b/README.sp.md
@@ -0,0 +1,149 @@
+<p align="center">
+   <a href="https://www.npmjs.com/package/modernizr" rel="noopener" target="_blank"><img alt="Modernizr" src="./media/Modernizr-2-Logo-vertical-medium.png" width="250" /></a>
+</p>
+
+<div align="center">
+  
+##### Modernizr es una libreria de JavaScript la cual detecta características de HTML5 y CSS3 en el navegador del usuario.
+  
+[![npm version](https://badge.fury.io/js/modernizr.svg)](https://badge.fury.io/js/modernizr)
+[![Build Status](https://github.com/Modernizr/Modernizr/workflows/Testing/badge.svg)](https://github.com/Modernizr/Modernizr/actions)
+[![codecov](https://codecov.io/gh/Modernizr/Modernizr/branch/master/graph/badge.svg)](https://codecov.io/gh/Modernizr/Modernizr)
+[![Inline docs](https://inch-ci.org/github/Modernizr/Modernizr.svg?branch=master)](https://inch-ci.org/github/Modernizr/Modernizr)
+
+</div>
+
+- Nuestro Website está desactualizado y dañado, por favor NO usarlo (https://modernizr.com) en su lugar cree su versión de modernizr a partir de npm.
+- [Documentation](https://modernizr.com/docs/)
+- [Integration tests](https://modernizr.github.io/Modernizr/test/integration.html)
+- [Unit tests](https://modernizr.github.io/Modernizr/test/unit.html)
+
+Modernizr testea cuales características nativas de CSS3 y HTML5 están disponibles en el actual UA y le devuelve los resultados de dos formas: como propiedades de un objeto global `Modernizr`, y como clases en el elemento `<html>`. Esta información le permite mejorar progresivamente sus páginas con un nivel de control granular sobre las experiencias.
+
+## Breaking changes with v4
+
+- Sin soporte para versiones de Node <= 10, por favor actualizar por lo menos a la versión 12
+
+- Los siguientes tests fueron renombrados:
+  
+  - `class` a `es6class` para mantenerse en linea con el resto de los es-tests
+
+- Los siguientes tests fueron movidos a subdirectorios:
+
+  - `cookies`, `indexeddb`, `indexedblob`, `quota-management-api`, `userdata` movidos al subdirectorio storage
+  - `audio` movido al subdirectorio audio
+  - `battery` movido al subdirectorio battery
+  - `canvas`, `canvastext` movidos al subdirectorio canvas
+  - `customevent`, `eventlistener`, `forcetouch`, `hashchange`, `pointerevents`, `proximity` movidos al subdirectorio event
+  - `exiforientation` movidos al subdirectorio image
+  - `capture`, `fileinput`, `fileinputdirectory`, `formatattribute`, `input`, `inputnumber-l10n`, `inputsearchevent`, `inputtypes`, `placeholder`, `requestautocomplete`, `validation` movidos al subdirectorio input
+  - `svg` movido al subdirectorio svg
+  - `webgl` movido al subdirectorio webgl
+    
+- Los siguientes tests fueron removidos:
+  
+  - `touchevents`: [discusión](https://github.com/Modernizr/Modernizr/pull/2432)
+  - `unicode`: [discusión](https://github.com/Modernizr/Modernizr/issues/2468)
+  - `templatestrings`: duplicado de la detección es6 `stringtemplate`
+  - `contains`: duplicado de la detección es6 `es6string`
+  - `datalistelem`: Una replica de Modernizr.input.list
+
+## New Asynchronous Event Listeners
+
+A menudo las personas quieren saber cuando un test asíncrono se ha realizado y de esta forma permitir que la aplicación reaccione a esto.
+En el pasado, usted ha tenido que verificar las propiedades o clases de `<html>`. Solo los enventos en los tests **asynchronous** están soportados.
+Tests síncronos deberían ser manejados sincrónicamente para mejorar la velocidad y mantener la consistencia.
+
+La nueva API se ve así:
+
+```js
+// Escuchando un test, dar un callback
+Modernizr.on('testname', function( result ) {
+  if (result) {
+    console.log('Test exitoso!');
+  }
+  else {
+    console.log('El test ha fallado!');
+  }
+});
+```
+
+Garantizamos que solo invocaremos tu función una vez (por cada vez que llames a `on`). Actualmente no estamos exponiendo
+un metodo para exponer la funcionalidad de `trigger`. En cambio, si quisiera tener el control sobre los tests asíncronos, use la
+característica `src/addTest`, y cualquier test que establezca automáticamente expondrá y encenderá la funcionalidad `on`.
+
+## Getting Started
+
+- Clone o descargue el repositorio
+- Instale las dependencias del proyecto con `npm install`
+
+## Building Modernizr 
+
+### From javascript
+
+Modernizr puede ser usado programáticamente via npm:
+
+```js
+var modernizr = require("modernizr");
+```
+
+Un método `build` está expuesto para generar builds personalizadas. Ejemplo:
+
+```javascript
+var modernizr = require("modernizr");
+
+modernizr.build({}, function (result) {
+  console.log(result); // la build
+});
+```
+
+El primer parámetro toma un objeto JSON de opciones y feature-detects a incluir. Ver [`lib/config-all.json`](lib/config-all.json) para todas las opciones disponibles.
+
+El segundo parámetro es una función invocada cuando la tarea se ha completado.
+
+### From the command-line
+
+También proveemos una CLI para building modernizr. 
+Para ver todas las opciones disponibles, ejecutar:
+
+```shell
+./bin/modernizr
+```
+
+O generar todo en 'config-all.json' ejecutar esto con npm:
+
+```shell
+npm start
+//outputs to ./dist/modernizr-build.js
+```
+
+## Testing Modernizr
+
+Para ejecutar los tests usando mocha-headless-chrome en la consola, ejecutar:
+
+```shell
+npm test
+```
+
+También se pueden correr en el navegador de su elección usando:
+
+```shell
+npm run serve-gh-pages
+```
+
+y navegando a estas dos URLs:
+
+```shell
+http://localhost:8080/test/unit.html
+http://localhost:8080/test/integration.html
+```
+
+## Code of Conduct
+
+Este proyecto se adhiere al [Open Code of Conduct](https://github.com/Modernizr/Modernizr/blob/master/.github/CODE_OF_CONDUCT.md). 
+Al participar, se espera que honre este código.
+
+
+## License
+
+[MIT License](https://opensource.org/licenses/MIT)
diff --git a/README.sv.md b/README.sv.md
new file mode 100644
index 0000000..3b7dc1a
--- /dev/null
+++ b/README.sv.md
@@ -0,0 +1,153 @@
+<p align="center">
+   <a href="https://www.npmjs.com/package/modernizr" rel="noopener" target="_blank"><img alt="Modernizr" src="./media/Modernizr-2-Logo-vertical-medium.png" width="250" /></a>
+</p>
+
+<div align="center">
+  
+##### Modernizr är ett JavaScript-bibliotek som upptäcker HTML5- och CSS3-funktioner i användarens webbläsare.
+  
+[![npm version](https://badge.fury.io/js/modernizr.svg)](https://badge.fury.io/js/modernizr)
+[![Build Status](https://github.com/Modernizr/Modernizr/workflows/Testing/badge.svg)](https://github.com/Modernizr/Modernizr/actions)
+[![codecov](https://codecov.io/gh/Modernizr/Modernizr/branch/master/graph/badge.svg)](https://codecov.io/gh/Modernizr/Modernizr)
+[![Inline docs](https://inch-ci.org/github/Modernizr/Modernizr.svg?branch=master)](https://inch-ci.org/github/Modernizr/Modernizr)
+
+</div>
+
+- Läs filen på Portugugisiska-BR [här](/README.pt_br.md)
+- Läs filen på indonesiska [här](/README.id.md)
+- Läs filen på spanska [här](/README.sp.md)
+
+- Vår webbplats är föråldrad och trasig, använd rekommenderas inte (https://modernizr.com) utan ladda ned och bygg din modernizr-version med npm.
+- [Documentation](https://modernizr.com/docs/)
+- [Integration tests](https://modernizr.github.io/Modernizr/test/integration.html)
+- [Unit tests](https://modernizr.github.io/Modernizr/test/unit.html)
+
+Modernizr testar vilka inbyggda CSS3- och HTML5-funktioner som är tillgängliga i den aktuella UA och gör resultaten tillgängliga för dig på två sätt: som egenskaper på ett globalt `Modernizr`-objekt och som klasser på `<html>`-elementet. Denna information gör att du gradvis kan förbättra dina sidor med detaljerad information över upplevelsen.
+
+## Förändringar med v4
+
+- Avbrutet stöd för node versioner <= 10, uppgradera till minst version 12
+
+- Följande tester har bytt namn:
+  
+  - `class` till `es6class` för att vara närmare resten av es-testen
+
+- Följande tester har flyttats till underkataloger:
+
+  - `cookies`, `indexeddb`, `indexedblob`, `quota-management-api`, `userdata` flyttade till storage underkatalogen
+  - `audio` flyttade till audio underkatalogen
+  - `battery` flyttade till battery underkatalogen
+  - `canvas`, `canvastext` flyttade till canvas underkatalogen
+  - `customevent`, `eventlistener`, `forcetouch`, `hashchange`, `pointerevents`, `proximity` flyttade till event underkatalogen
+  - `exiforientation` flyttade till image underkatalogen
+  - `capture`, `fileinput`, `fileinputdirectory`, `formatattribute`, `input`, `inputnumber-l10n`, `inputsearchevent`, `inputtypes`, `placeholder`, `requestautocomplete`, `validation` flyttade till input underkatalogen
+  - `svg` flyttade till svg underkatalogen
+  - `webgl` flyttade till webgl underkatalogen
+     
+- Följande tester har tagits bort:
+  
+  - `touchevents`: [diskussion](https://github.com/Modernizr/Modernizr/pull/2432)
+  - `unicode`: [diskussion](https://github.com/Modernizr/Modernizr/issues/2468)
+  - `templatestrings`: dubblett av es6 detect `stringtemplate`
+  - `contains`: dublett av es6 detect `es6string`
+  - `datalistelem`: En dublett av Modernizr.input.list
+
+## Nya asynkrona händelselyssnare
+
+Folk vill ofta veta när ett asynkront test görs så att de kan låta deras applikation reagera på det.
+Tidigare har du varit tvungen att lita på att titta på egenskaper eller `<html>`-klasser. Tester stöder ändast **asynkrona** händelser.
+Synkrona tester bör hanteras synkront för att förbättra hastigheten och bibehålla konsekvenser.
+
+Det nya API:n ser ut så här:
+
+```js
+// Listen to a test, give it a callback
+Modernizr.on('testname', function( result ) {
+  if (result) {
+    console.log('The test passed!');
+  }
+  else {
+    console.log('The test failed!');
+  }
+});
+```
+
+Vi garanterar att vi bara kommer att anropa din funktion en gång (per gång du aktiverar `on` funktionen). Vi förser för närvarande inte
+en metod för att exponera "trigger"-funktionen. Istället, om du vill ha kontroll över dina asynkronatester, använd
+`src/addTest`-funktionen, och varje test som du ställer in kommer automatiskt att exponera och trigga `on`-funktionen.
+
+## Kom igång
+
+- Klona eller ladda ned arkivet.
+- Installera projektberoenden med `npm install`
+
+## Att bygga Modernizr 
+
+### Från javascript
+
+Modernizr kan användas via npm:
+
+```js
+var modernizr = require("modernizr");
+```
+
+En `build` metod är exponerad för att generera anpassade Modernizr-builds. Exempel:
+
+```javascript
+var modernizr = require("modernizr");
+
+modernizr.build({}, function (result) {
+  console.log(result); // the build
+});
+```
+
+Den första parametern tar med ett JSON-objekt med alternativ och funktioner. Se [`lib/config-all.json`](lib/config-all.json) för alla alternativ.
+
+Den andra parametern är en funktion som anropas när uppgiften är klar.
+
+### Från kommandocentralen
+
+Vi tillhandahåller också ett kommando för att bygga modernizr.
+För att se alla tillgängliga alternativ körs:
+
+```shell
+./bin/modernizr
+```
+
+Eller för att generera allt i 'config-all.json' kör detta med npm:
+
+```shell
+npm start
+//outputs to ./dist/modernizr-build.js
+```
+
+## Testa Modernizr
+
+Så här kör du testerna med mocha-headless-chrome på konsolen:
+
+```shell
+npm test
+```
+
+Du kan också köra tester i den webbläsare du väljer med detta kommando:
+
+```shell
+npm run serve-gh-pages
+```
+
+och navigera till dessa två webbadresser:
+
+```shell
+http://localhost:8080/test/unit.html
+http://localhost:8080/test/integration.html
+```
+
+## Uppförandekod
+
+Detta projekt följer [Open Code of Conduct](https://github.com/Modernizr/Modernizr/blob/master/.github/CODE_OF_CONDUCT.md). 
+Genom att delta förväntas du respektera detta.
+
+
+## License
+
+[MIT License](https://opensource.org/licenses/MIT)
diff --git a/README.ta.md b/README.ta.md
new file mode 100644
index 0000000..c6740bd
--- /dev/null
+++ b/README.ta.md
@@ -0,0 +1,155 @@
+<p align="center">
+   <a href="https://www.npmjs.com/package/modernizr" rel="noopener" target="_blank"><img alt="Modernizr" src="./media/Modernizr-2-Logo-vertical-medium.png" width="250" /></a>
+</p>
+
+<div align="center">
+  
+##### மாடர்னிசர் என்பது ஜாவாஸ்கிரிப்ட் நூலகமாகும், இது பயனரின் உலாவியில் எச்டிஎம்எல்5 மற்றும் சிஎஸ்எஸ்3 அம்சங்களைக் கண்டறியும்.
+  
+[![npm version](https://badge.fury.io/js/modernizr.svg)](https://badge.fury.io/js/modernizr)
+[![Build Status](https://github.com/Modernizr/Modernizr/workflows/Testing/badge.svg)](https://github.com/Modernizr/Modernizr/actions)
+[![codecov](https://codecov.io/gh/Modernizr/Modernizr/branch/master/graph/badge.svg)](https://codecov.io/gh/Modernizr/Modernizr)
+[![Inline docs](https://inch-ci.org/github/Modernizr/Modernizr.svg?branch=master)](https://inch-ci.org/github/Modernizr/Modernizr)
+
+</div>
+
+- இந்த கோப்பை போர்ச்சுகீஸ் மொழியில் படிக்கவும்-பி.ஆர் [இங்கே](/README.pt_br.md)
+- இந்தக் கோப்பை இந்தோனேசிய மொழியில் படிக்கவும் [இங்கே](/README.id.md)
+- இந்த கோப்பை ஸ்பானிஷ் மொழியில் [இங்கே](/README.sp.md)
+- இந்த கோப்பை ஸ்வீடிஷ் மொழியில் படிக்கவும் [இங்கே](/README.sv.md)
+- இந்த கோப்பை தமிழில் படிக்கவும் [இங்கே](/README.ta.md)
+
+- எங்கள் இணையதளம் காலாவதியானது மற்றும் உடைந்துவிட்டது, தயவுசெய்து அதைப் பயன்படுத்த வேண்டாம் (https://modernizr.com) மாறாக உங்கள் நவீனமயமாக்கல் பதிப்பை npm இலிருந்து உருவாக்கவும்.
+- [ஆவணப்படுத்தல்](https://modernizr.com/docs/)
+- [இடையீடு சோதனைகள்](https://modernizr.github.io/Modernizr/test/integration.html)
+- [அலகு சோதனைகள்](https://modernizr.github.io/Modernizr/test/unit.html)
+
+மாடர்னிசர் தற்போதைய யுஏ இல் எந்த சொந்த சிஎஸ்எஸ்3 மற்றும் எச்டிஎம்எல்5 அம்சங்கள் உள்ளன என்பதைச் சோதித்து, முடிவுகளை இரண்டு வழிகளில் உங்களுக்குக் கிடைக்கச் செய்கிறது: உலகளாவிய `Modernizr` பொருளின் பண்புகளாகவும், `<html>` உறுப்புக்கான வகுப்புகளாகவும். இந்தத் தகவல், அனுபவத்தின் மீதான சிறு அளவிலான கட்டுப்பாட்டுடன் உங்கள் பக்கங்களை படிப்படியாக மேம்படுத்த அனுமதிக்கிறது.
+
+## v4 உடன் மாற்றங்களை உடைக்கிறது
+
+- முனை பதிப்புகளுக்கான ஆதரவு கைவிடப்பட்டது <= 10, தயவுசெய்து குறைந்தபட்சம் பதிப்பு 12 க்கு மேம்படுத்தவும்
+
+- பின்வரும் சோதனைகள் மறுபெயரிடப்பட்டன:
+  
+  - `வகுப்பு` முதல் `es6class` வரை மீதமுள்ள es-சோதனைகளுக்கு ஏற்ப இருக்க வேண்டும்
+
+- பின்வரும் சோதனைகள் துணை அடைவுகளில் நகர்த்தப்பட்டன:  
+
+  - `cookies`, `indexeddb`, `indexedblob`, `quota-management-api`, `userdata` சேமிப்பக துணை அடைவுக்கு நகர்த்தப்பட்டது   
+  - `audio` ஆடியோ துணை அடைவுக்கு நகர்த்தப்பட்டது
+  - `battery` பேட்டரி துணை அடைவுக்கு நகர்த்தப்பட்டது
+  - `canvas`, `canvastext` கேன்வாஸ் துணை அடைவுக்கு நகர்த்தப்பட்டது
+  - `customevent`, `eventlistener`, `forcetouch`, `hashchange`, `pointerevents`, `proximity` நிகழ்வு துணை அடைவுக்கு நகர்த்தப்பட்டது
+  - `exiforientation` படத்தின் துணை அடைவுக்கு நகர்த்தப்பட்டது
+  - `capture`, `fileinput`, `fileinputdirectory`, `formatattribute`, `input`, `inputnumber-l10n`, `inputsearchevent`, `inputtypes`, `placeholder`, `requestautocomplete`, `validation` உள்ளீட்டிற்கு நகர்த்தப்பட்டது துணை அடைவு
+  - `svg` எஸ்.வி.ஜி துணை அடைவுக்கு நகர்த்தப்பட்டது
+  - `webgl` wவலைஜிஎல் துணை அடைவுக்கு நகர்த்தப்பட்டது
+       
+- பின்வரும் சோதனைகள் நீக்கப்பட்டன:
+  
+  - `தொடுதல் நிகழ்வுகள்`: [விவாதம்](https://github.com/Modernizr/Modernizr/pull/2432)
+  - `யூனிகோட்`: [விவாதம்](https://github.com/Modernizr/Modernizr/issues/2468)
+  - `வார்ப்புருக்கள்`: ஈஎஸ்6 கண்டறிதலின் நகல் `stringtemplate`
+  - `கொண்டுள்ளது`: ஈஎஸ்6 கண்டறிதலின் நகல் `es6string`
+  - `தரவு பட்டியல்`: Modernizr.input.list இன் போலி
+
+
+## புதிய ஒத்திசைவற்ற நிகழ்வு கேட்போர்
+
+ஒரு ஒத்திசைவற்ற சோதனை எப்போது செய்யப்படுகிறது என்பதை மக்கள் அடிக்கடி அறிய விரும்புகிறார்கள், அதனால் அவர்கள் தங்கள் விண்ணப்பத்தை அதற்கு எதிர்வினையாற்ற அனுமதிக்கலாம்.
+கடந்த காலத்தில், பண்புகள் அல்லது `<html>` வகுப்புகளைப் பார்ப்பதில் நீங்கள் தங்கியிருக்க வேண்டியிருந்தது. **ஒத்திசைவற்ற** சோதனைகளில் நிகழ்வுகள் மட்டுமே
+ஆதரித்தது. வேகத்தை மேம்படுத்தவும், நிலைத்தன்மையை பராமரிக்கவும் ஒத்திசைவான சோதனைகள் ஒத்திசைவாக கையாப்பட வேண்டும்.
+
+புதிய ஏபிஈ API இது போல் தெரிகிறது
+
+```js
+// ஒரு சோதனையைக் கேளுங்கள், அதை மீண்டும் அழைக்கவும்  
+Modernizr.on('testname', function( result ) {
+  if (result) {
+    console.log('The test passed!');
+  }
+  else {
+    console.log('The test failed!');
+  }
+});
+```
+உங்கள் செயல்பாட்டை ஒருமுறை மட்டுமே செயல்படுத்துவோம் என்று நாங்கள் உத்தரவாதம் அளிக்கிறோம் (ஒரு முறை நீங்கள் `ஆன்` என்று அழைக்கும் போது). நாங்கள் தற்போது வெளிப்படுத்தவில்லை
+`தூண்டுதல்` செயல்பாட்டை வெளிப்படுத்துவதற்கான ஒரு முறை. அதற்குப் பதிலாக, ஒத்திசைவு சோதனைகளின் மீது நீங்கள் கட்டுப்பாட்டைப் பெற விரும்பினால், இதைப் பயன்படுத்தவும்
+`src/addTest` அம்சம் மற்றும் நீங்கள் அமைக்கும் எந்த சோதனையும் தானாகவே `ஆன்` செயல்பாட்டை வெளிப்படுத்தும் மற்றும் தூண்டும்.
+
+## தொடங்குதல்
+
+- களஞ்சியத்தை குளோன் செய்யவும் அல்லது பதிவிறக்கவும்
+- `npm install` மூலம் திட்ட சார்புகளை நிறுவவும்
+
+## கட்டிடம் நவீனமயமாக்கல்
+
+
+### ஜாவாஸ்கிரிப்டில் இருந்து
+
+மாடர்னிசர் ஐ npm வழியாக நிரல் ரீதியாகப் பயன்படுத்தலாம்:
+
+```js
+var modernizr = require("modernizr");
+```
+
+தனிப்பயன் மாடர்னிசர் பில்ட்களை உருவாக்குவதற்கான ஒரு `build` முறை வெளிப்படுகிறது. உதாரணமாக:
+
+```javascript
+var modernizr = require("modernizr");
+
+modernizr.build({}, function (result) {
+  console.log(result); // the build
+});
+```
+
+முதல் அளவுருவானது JSON ஆப்ஜெக்ட் ஆப்ஜெக்ட் மற்றும் அம்சத்தைக் கண்டறிகிறது. கிடைக்கக்கூடிய அனைத்து விருப்பங்களுக்கும் [`lib/config-all.json`](lib/config-all.json) ஐப் பார்க்கவும்.
+
+இரண்டாவது அளவுரு என்பது பணியை முடிக்கும் போது செயல்படுத்தப்படும் ஒரு செயல்பாடாகும்.
+
+### கட்டளை வரியிலிருந்து
+
+நவீனமயமாக்கலை உருவாக்குவதற்கான கட்டளை வரி இடைமுகத்தையும் நாங்கள் வழங்குகிறோம்.
+கிடைக்கக்கூடிய அனைத்து விருப்பங்களையும் பார்க்க, இயக்கவும்:
+
+```shell
+./bin/modernizr
+```
+
+அல்லது 'config-all.json' இல் அனைத்தையும் உருவாக்க, இதை npm உடன் இயக்கவும்:
+
+```shell
+npm start
+//outputs to ./dist/modernizr-build.js
+```
+
+## மாடர்னிசர் சோதனை
+
+கன்சோல் இயக்கத்தில் mocha-headless-chrome ஐப் பயன்படுத்தி சோதனைகளைச் செயல்படுத்த:
+
+```shell
+npm test
+```
+
+இந்தக் கட்டளையைப் பயன்படுத்தி உங்களுக்கு விருப்பமான உலாவியில் சோதனைகளையும் இயக்கலாம்:
+
+```shell
+npm run serve-gh-pages
+```
+
+மற்றும் இந்த இரண்டு URLகளுக்கு செல்லவும்:
+
+```shell
+http://localhost:8080/test/unit.html
+http://localhost:8080/test/integration.html
+```
+
+## நடத்தை விதிகள்
+
+இந்த திட்டம் [ஓப்பன் கான்டக்ட் கோட்](https://github.com/Modernizr/Modernizr/blob/master/.github/CODE_OF_CONDUCT.md) இணங்குகிறது.
+பங்கேற்பதன் மூலம், இந்த குறியீட்டை நீங்கள் மதிக்க வேண்டும் என்று எதிர்பார்க்கப்படுகிறது.
+
+## உரிமம்
+
+[எம்ஐடி உரிமம்](https://opensource.org/licenses/MIT)
diff --git a/bin/modernizr b/bin/modernizr
new file mode 100755
index 0000000..05066fb
--- /dev/null
+++ b/bin/modernizr
@@ -0,0 +1,193 @@
+#!/usr/bin/env node
+'use strict';
+
+var fs = require('fs');
+var _ = require('lodash');
+var path = require('path');
+var mkdirp = require('mkdirp');
+var Modernizr = require(path.resolve(__dirname + '/../lib/cli.js'));
+var yargs = require('yargs')
+  .options('h', {
+    alias: 'help',
+    describe: 'Print Help'
+  })
+  .options('V', {
+    alias: ['v', 'version'],
+    describe: 'Print the version and exit'
+  })
+  .options('f', {
+    alias: 'features',
+    describe: 'comma separated list of feature detects'
+  })
+  .options('o', {
+    alias: 'options',
+    describe: 'comma separated list of extensibility options'
+  })
+  .options('c', {
+    alias: 'config',
+    describe: 'Path to a JSON file containing Modernizr configuration. See lib/config-all.json for an example'
+  })
+  .options('d', {
+    alias: 'dest',
+    describe: 'Path to write the Modernizr build file to. Defaults to ./modernizr.js'
+  })
+  .options('m', {
+    alias: 'metadata',
+    describe: 'Path to where the Modernizr feature-detect metadata should be saved. Defaults to ./metadata.json'
+  })
+  .options('u', {
+    alias: 'uglify',
+    describe: 'uglify/minify the output'
+  })
+  .options('s', {
+    alias: 'scriptGlobalName',
+    describe: 'Script global variable where Modernizr is attached. Defaults to window'
+  })
+  .options('q', {
+    alias: 'quiet',
+    describe: 'Silence all output'
+  });
+var argv = yargs.argv;
+var cwd = process.cwd();
+var dest = cwd + '/modernizr.js';
+var configPath;
+var config;
+
+function log() {
+  if (!argv.q) {
+    console.log.apply(console, arguments);
+  }
+}
+function stringify(obj, minified) {
+  var replacer = function(key, value) {
+    return value;
+  };
+  var args = minified ? [replacer,2] : [];
+  args.unshift(obj);
+  return JSON.stringify.apply(JSON, args);
+}
+
+if (argv.h) {
+  yargs.showHelp();
+  process.exit();
+}
+
+if (argv.V) {
+  var pkg = require('../package.json');
+  console.log('Modernizr v' + pkg.version);
+  process.exit();
+}
+
+if (argv.d) {
+  dest = path.normalize(argv.d);
+  var exists = fs.existsSync(dest);
+  var isDir = exists && fs.statSync(dest).isDirectory();
+  var fileRequested = _.endsWith(dest, '.js');
+
+  if ((exists && isDir) || (!exists && !fileRequested)) {
+    dest = path.join(dest, 'modernizr.js');
+  }
+
+  mkdirp.sync(path.dirname(dest));
+}
+
+if (argv.m) {
+  // path.normalize is used instead of normalize in order to support ~
+  // we get an absolute path on the fallback from cwd, and any user supplied
+  // argument will be relative to their current directory.
+  var metaDest = path.normalize(argv.m === true ? cwd + '/metadata.json' : argv.m);
+  Modernizr.metadata(function(metadata) {
+    mkdirp.sync(path.dirname(metaDest));
+    fs.writeFileSync(metaDest, stringify(metadata, !argv.u));
+    log('metadata saved to ' + metaDest);
+  });
+  if (!argv.d) {
+    // return early unless we explicitly request Modernizr to be built
+    return;
+  }
+}
+
+if (argv.o || argv.f) {
+  var metadata = Modernizr.metadata();
+  var options = Modernizr.options();
+
+  var find = function(config, source) {
+    if (!config) {
+      return;
+    }
+
+    return config
+      .replace(/-/g, ',')
+      .split(',')
+      .map(function(prop) {
+        var obj = _.find(source, function(o) {
+          if (o.property instanceof Array) {
+            return o.property.includes(prop);
+          } else {
+            return o.property === prop;
+          }
+        });
+
+        // setClasses is technically a flag, not an option. But it is passed
+        // in as an option. Since it doesn't exist as an option we have to
+        // special case around it :[
+        if (prop === 'setClasses') {
+          return 'setClasses';
+        } else if (_.isUndefined(obj)) {
+          throw new Error('invalid key value name - ' + prop);
+        } else {
+          return obj.amdPath || obj.property;
+        }
+      });
+  };
+
+  config = {
+    'feature-detects': find(argv.f, metadata),
+    'options': find(argv.o, options)
+  };
+}
+
+if (argv.c) {
+  try {
+    configPath = fs.realpathSync(argv.c);
+  } catch (e) {
+    console.error(argv.c + ' does not exist.');
+    process.exit(1);
+  }
+  if (!configPath) {
+    configPath = path.resolve(__dirname, '../lib/config-all.json');
+  }
+}
+
+try {
+  if (!config && !configPath) {
+    console.error('config file, inline features, or options required.');
+    yargs.showHelp();
+    process.exit(1);
+  } else {
+    config = config || {};
+    if (configPath) {
+      config = _.extend(config, require(configPath));
+    }
+    if (config && config.dest) {
+      dest = path.join(cwd, config.dest, 'modernizr.js');
+    }
+  }
+} catch (e) {
+  console.error(configPath + ' is not valid JSON.');
+  console.error(e);
+  process.exit(1);
+}
+
+if (argv.u) {
+  config.minify = true;
+}
+
+if (argv.scriptGlobalName) {
+  config.scriptGlobalName = argv.scriptGlobalName;
+}
+
+Modernizr.build(config, function(output) {
+  fs.writeFileSync(dest, output);
+  log('Modernizr build saved to ' + dest);
+});
diff --git a/bin/modernizr.bat b/bin/modernizr.bat
new file mode 100644
index 0000000..05711dc
--- /dev/null
+++ b/bin/modernizr.bat
@@ -0,0 +1,2 @@
+@echo off
+node .\bin\modernizr %*
diff --git a/debian/changelog b/debian/changelog
index 84b9d0a..2ea63c6 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,9 @@
+modernizr (3.11.0+git20221020.1.86ebb04+ds1-1) UNRELEASED; urgency=low
+
+  * New upstream snapshot.
+
+ -- Debian Janitor <janitor@jelmer.uk>  Thu, 09 Feb 2023 19:20:18 -0000
+
 modernizr (2.6.2+ds1-5) unstable; urgency=medium
 
   [ Debian Janitor ]
diff --git a/feature-detects/a-download.js b/feature-detects/a-download.js
deleted file mode 100644
index 559fadd..0000000
--- a/feature-detects/a-download.js
+++ /dev/null
@@ -1,8 +0,0 @@
-
-// a[download] attribute
-// When used on an <a>, this attribute signifies that the resource it
-// points to should be downloaded by the browser rather than navigating to it.
-// http://developers.whatwg.org/links.html#downloading-resources
-// By Addy Osmani
-
-Modernizr.addTest('adownload', 'download' in document.createElement('a'));
diff --git a/feature-detects/a/aping.js b/feature-detects/a/aping.js
new file mode 100644
index 0000000..70a887a
--- /dev/null
+++ b/feature-detects/a/aping.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "a[ping] Attribute",
+  "property": "aping",
+  "caniuse": "ping",
+  "tags": ["media", "attribute"],
+  "builderAliases": ["a_ping"],
+  "authors": ["Hélio Correia (@heliocorreia)"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/dev/links.html#ping"
+  }]
+}
+!*/
+/* DOC
+The ping attribute, if present, gives the URLs of the resources that are interested in being notified if the user follows the hyperlink.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('aping', !window.externalHost && 'ping' in createElement('a'));
+});
diff --git a/feature-detects/a/areaping.js b/feature-detects/a/areaping.js
new file mode 100644
index 0000000..1a84d5e
--- /dev/null
+++ b/feature-detects/a/areaping.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "area[ping] Attribute",
+  "property": "areaping",
+  "caniuse": "ping",
+  "tags": ["media", "attribute"],
+  "builderAliases": ["area_ping"],
+  "authors": ["Hélio Correia (@heliocorreia)"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/dev/links.html#ping"
+  }]
+}
+!*/
+/* DOC
+The ping attribute, if present, gives the URLs of the resources that are interested in being notified if the user follows the hyperlink.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('areaping', !window.externalHost && 'ping' in createElement('area'));
+});
diff --git a/feature-detects/a/download.js b/feature-detects/a/download.js
new file mode 100644
index 0000000..a2be946
--- /dev/null
+++ b/feature-detects/a/download.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "a[download] Attribute",
+  "property": "adownload",
+  "caniuse": "download",
+  "tags": ["media", "attribute"],
+  "builderAliases": ["a_download"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://developers.whatwg.org/links.html#downloading-resources"
+  }]
+}
+!*/
+/* DOC
+When used on an `<a>`, this attribute signifies that the resource it points to should be downloaded by the browser rather than navigating to it.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('adownload', !window.externalHost && 'download' in createElement('a'));
+});
diff --git a/feature-detects/ambientlight.js b/feature-detects/ambientlight.js
new file mode 100644
index 0000000..04ab629
--- /dev/null
+++ b/feature-detects/ambientlight.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "Ambient Light Events",
+  "property": "ambientlight",
+  "caniuse": "ambient-light",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/ambient-light/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the API that provides information about the ambient light levels, as detected by the device's light detector, in terms of lux units.
+*/
+define(['Modernizr', 'hasEvent'], function(Modernizr, hasEvent) {
+  Modernizr.addTest('ambientlight', hasEvent('devicelight', window));
+});
diff --git a/feature-detects/applicationcache.js b/feature-detects/applicationcache.js
new file mode 100644
index 0000000..54fb35e
--- /dev/null
+++ b/feature-detects/applicationcache.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "Application Cache",
+  "property": "applicationcache",
+  "caniuse": "offline-apps",
+  "tags": ["storage", "offline"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/docs/HTML/Using_the_application_cache"
+  }],
+  "polyfills": ["html5gears"]
+}
+!*/
+/* DOC
+Detects support for the Application Cache, for storing data to enable web-based applications run offline.
+
+The API has been [heavily criticized](https://alistapart.com/article/application-cache-is-a-douchebag) and discussions are underway to address this.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('applicationcache', 'applicationCache' in window);
+});
diff --git a/feature-detects/audio-audiodata-api.js b/feature-detects/audio-audiodata-api.js
deleted file mode 100644
index bfcd9fe..0000000
--- a/feature-detects/audio-audiodata-api.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// Mozilla Audio Data API
-// https://wiki.mozilla.org/Audio_Data_API
-// by Addy Osmani
-Modernizr.addTest('audiodata', !!(window.Audio));
diff --git a/feature-detects/audio-webaudio-api.js b/feature-detects/audio-webaudio-api.js
deleted file mode 100644
index 46d3c63..0000000
--- a/feature-detects/audio-webaudio-api.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// Web Audio API
-// https://dvcs.w3.org/hg/audio/raw-file/tip/webaudio/specification.html
-// By Addy Osmani
-Modernizr.addTest('webaudio', !!(window.webkitAudioContext || window.AudioContext));
diff --git a/feature-detects/audio/audio.js b/feature-detects/audio/audio.js
new file mode 100644
index 0000000..b2eabe0
--- /dev/null
+++ b/feature-detects/audio/audio.js
@@ -0,0 +1,58 @@
+/*!
+{
+  "name": "HTML5 Audio Element",
+  "property": "audio",
+  "caniuse": "audio",
+  "tags": ["html5", "audio", "media"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements"
+  }]
+}
+!*/
+/* DOC
+Detects support of the audio element, as well as testing what types of content it supports.
+
+Subproperties are provided to describe support for `ogg`, `mp3`,`opus`, `wav` and `m4a` formats, e.g.:
+
+```javascript
+Modernizr.audio         // true
+Modernizr.audio.ogg     // 'probably'
+```
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
+  //                     thx to NielsLeenheer and zcorpan
+
+  // Note: in some older browsers, "no" was a return value instead of empty string.
+  //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
+  //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
+  (function() {
+    var elem = createElement('audio');
+
+    Modernizr.addTest('audio', function() {
+      var bool = false;
+      try {
+        bool = !!elem.canPlayType;
+        if (bool) {
+          bool = new Boolean(bool);
+        }
+      } catch (e) {}
+
+      return bool;
+    });
+
+    // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
+    try {
+      if (!!elem.canPlayType) {
+        Modernizr.addTest('audio.ogg', elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/, ''));
+        Modernizr.addTest('audio.mp3', elem.canPlayType('audio/mpeg; codecs="mp3"').replace(/^no$/, ''));
+        Modernizr.addTest('audio.opus', elem.canPlayType('audio/ogg; codecs="opus"') ||
+          elem.canPlayType('audio/webm; codecs="opus"').replace(/^no$/, ''));
+        Modernizr.addTest('audio.wav', elem.canPlayType('audio/wav; codecs="1"').replace(/^no$/, ''));
+        Modernizr.addTest('audio.m4a', (elem.canPlayType('audio/x-m4a;') ||
+          elem.canPlayType('audio/aac;')).replace(/^no$/, ''));
+      }
+    } catch (e) {}
+  })();
+});
diff --git a/feature-detects/audio/autoplay.js b/feature-detects/audio/autoplay.js
new file mode 100644
index 0000000..4015506
--- /dev/null
+++ b/feature-detects/audio/autoplay.js
@@ -0,0 +1,83 @@
+/*!
+{
+  "name": "Audio Autoplay",
+  "property": "audioautoplay",
+  "authors": ["Jordy van Dortmont"],
+  "tags": ["audio"],
+  "async": true
+}
+!*/
+/* DOC
+Checks for support of the autoplay attribute of the audio element.
+*/
+define(['Modernizr', 'addTest', 'docElement', 'createElement', 'test/audio/audio'], function(Modernizr, addTest, docElement, createElement) {
+
+  Modernizr.addAsyncTest(function() {
+    var timeout;
+    var waitTime = 200;
+    var retries = 5;
+    var currentTry = 0;
+    var elem = createElement('audio');
+    var elemStyle = elem.style;
+
+    function testAutoplay(arg) {
+      currentTry++;
+      clearTimeout(timeout);
+
+      var result = arg && arg.type === 'playing' || elem.currentTime !== 0;
+
+      if (!result && currentTry < retries) {
+        // Detection can be flaky if the browser is slow, so lets retry in a little bit
+        timeout = setTimeout(testAutoplay, waitTime);
+        return;
+      }
+
+      elem.removeEventListener('playing', testAutoplay, false);
+      addTest('audioautoplay', result);
+
+      // Cleanup, but don't assume elem is still in the page -
+      // an extension may already have removed it.
+      if (elem.parentNode) {
+        elem.parentNode.removeChild(elem);
+      }
+    }
+
+    // Skip the test if audio itself, or the autoplay element on it isn't supported
+    if (!Modernizr.audio || !('autoplay' in elem)) {
+      addTest('audioautoplay', false);
+      return;
+    }
+
+    elemStyle.position = 'absolute';
+    elemStyle.height = 0;
+    elemStyle.width = 0;
+
+    try {
+      if (Modernizr.audio.mp3) {
+        elem.src = 'data:audio/mpeg;base64,/+MYxAAAAANIAUAAAASEEB/jwOFM/0MM/90b/+RhST//w4NFwOjf///PZu////9lns5GFDv//l9GlUIEEIAAAgIg8Ir/JGq3/+MYxDsLIj5QMYcoAP0dv9HIjUcH//yYSg+CIbkGP//8w0bLVjUP///3Z0x5QCAv/yLjwtGKTEFNRTMuOTeqqqqqqqqqqqqq/+MYxEkNmdJkUYc4AKqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq';
+      }
+      else if (Modernizr.audio.wav) {
+        elem.src = 'data:audio/wav;base64,UklGRjQAAABXQVZFZm10IBAAAAABAAEAEAAAABAAAAABAAgAZGF0YRAAAAB/f39/f39/f39/f39/f39/';
+      }
+      else {
+        addTest('audioautoplay', false);
+        return;
+      }
+    }
+
+    catch (e) {
+      addTest('audioautoplay', false);
+      return;
+    }
+
+    elem.setAttribute('autoplay', '');
+    elemStyle.cssText = 'display:none';
+    docElement.appendChild(elem);
+    // Wait for the next tick to add the listener, otherwise the element may
+    // not have time to play in high load situations (e.g. the test suite)
+    setTimeout(function() {
+      elem.addEventListener('playing', testAutoplay, false);
+      timeout = setTimeout(testAutoplay, waitTime);
+    }, 0);
+  });
+});
diff --git a/feature-detects/audio/loop.js b/feature-detects/audio/loop.js
new file mode 100644
index 0000000..96a2d77
--- /dev/null
+++ b/feature-detects/audio/loop.js
@@ -0,0 +1,13 @@
+/*!
+{
+  "name": "Audio Loop Attribute",
+  "property": "audioloop",
+  "tags": ["audio", "media"]
+}
+!*/
+/* DOC
+Detects if an audio element can automatically restart, once it has finished
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('audioloop', 'loop' in createElement('audio'));
+});
diff --git a/feature-detects/audio/preload.js b/feature-detects/audio/preload.js
new file mode 100644
index 0000000..9c279bb
--- /dev/null
+++ b/feature-detects/audio/preload.js
@@ -0,0 +1,79 @@
+/*!
+{
+  "name": "Audio Preload",
+  "property": "audiopreload",
+  "tags": ["audio", "media"],
+  "async": true,
+  "warnings": ["This test is very large – only include it if you absolutely need it"]
+}
+!*/
+/* DOC
+Detects if audio can be downloaded in the background before it starts playing in the `<audio>` element
+*/
+define(['Modernizr', 'addTest', 'docElement', 'createElement', 'test/audio/audio'], function(Modernizr, addTest, docElement, createElement) {
+
+  Modernizr.addAsyncTest(function() {
+    var timeout;
+    var waitTime = 300;
+    var elem = createElement('audio');
+    var elemStyle = elem.style;
+
+    function testpreload(event) {
+      clearTimeout(timeout);
+      var result = event !== undefined && event.type === 'loadeddata' ? true : false; //need to check if event is not undefined here in case function is evoked from timeout (no parameters)
+      elem.removeEventListener('loadeddata', testpreload, false);
+      addTest('audiopreload', result);
+      // Cleanup, but don't assume elem is still in the page -
+      // an extension (eg Flashblock) may already have removed it.
+      if (elem.parentNode) {
+        elem.parentNode.removeChild(elem);
+      }
+    }
+
+    //skip the test if audio itself, or the preload
+    //element on it isn't supported
+    if (!Modernizr.audio || !('preload' in elem)) {
+      addTest('audiopreload', false);
+      return;
+    }
+
+    elemStyle.position = 'absolute';
+    elemStyle.height = 0;
+    elemStyle.width = 0;
+
+    try {
+      if (Modernizr.audio.mp3) {
+        //75ms of silence (minimum Mp3 duration loaded by Safari, not tested other formats thoroughly: may be possible to shrink base64 URI)
+        elem.src = 'data:audio/mpeg;base64,//MUxAAB6AXgAAAAAPP+c6nf//yi/6f3//MUxAMAAAIAAAjEcH//0fTX6C9Lf//0//MUxA4BeAIAAAAAAKX2/6zv//+IlR4f//MUxBMCMAH8AAAAABYWalVMQU1FMy45//MUxBUB0AH0AAAAADkuM1VVVVVVVVVV//MUxBgBUATowAAAAFVVVVVVVVVVVVVV';
+      }
+      else if (Modernizr.audio.m4a) {
+        elem.src = 'data:audio/x-m4a;base64,AAAAGGZ0eXBNNEEgAAACAGlzb21pc28yAAAACGZyZWUAAAAfbWRhdN4EAABsaWJmYWFjIDEuMjgAAAFoAQBHAAACiG1vb3YAAABsbXZoZAAAAAB8JbCAfCWwgAAAA+gAAAAYAAEAAAEAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAIAAAG0dHJhawAAAFx0a2hkAAAAD3wlsIB8JbCAAAAAAQAAAAAAAAAYAAAAAAAAAAAAAAAAAQAAAAABAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAABUG1kaWEAAAAgbWRoZAAAAAB8JbCAfCWwgAAArEQAAAQAVcQAAAAAAC1oZGxyAAAAAAAAAABzb3VuAAAAAAAAAAAAAAAAU291bmRIYW5kbGVyAAAAAPttaW5mAAAAEHNtaGQAAAAAAAAAAAAAACRkaW5mAAAAHGRyZWYAAAAAAAAAAQAAAAx1cmwgAAAAAQAAAL9zdGJsAAAAW3N0c2QAAAAAAAAAAQAAAEttcDRhAAAAAAAAAAEAAAAAAAAAAAACABAAAAAArEQAAAAAACdlc2RzAAAAAAMZAAEABBFAFQAAAAABftAAAAAABQISCAYBAgAAABhzdHRzAAAAAAAAAAEAAAABAAAEAAAAABxzdHNjAAAAAAAAAAEAAAABAAAAAQAAAAEAAAAUc3RzegAAAAAAAAAXAAAAAQAAABRzdGNvAAAAAAAAAAEAAAAoAAAAYHVkdGEAAABYbWV0YQAAAAAAAAAhaGRscgAAAAAAAAAAbWRpcmFwcGwAAAAAAAAAAAAAAAAraWxzdAAAACOpdG9vAAAAG2RhdGEAAAABAAAAAExhdmY1Mi42NC4y';
+      }
+      else if (Modernizr.audio.ogg) {
+        elem.src = 'data:audio/ogg;base64,T2dnUwACAAAAAAAAAAD/QwAAAAAAAM2LVKsBHgF2b3JiaXMAAAAAAUSsAAAAAAAAgLsAAAAAAAC4AU9nZ1MAAAAAAAAAAAAA/0MAAAEAAADmvOe6Dy3/////////////////MgN2b3JiaXMdAAAAWGlwaC5PcmcgbGliVm9yYmlzIEkgMjAwNzA2MjIAAAAAAQV2b3JiaXMfQkNWAQAAAQAYY1QpRplS0kqJGXOUMUaZYpJKiaWEFkJInXMUU6k515xrrLm1IIQQGlNQKQWZUo5SaRljkCkFmVIQS0kldBI6J51jEFtJwdaYa4tBthyEDZpSTCnElFKKQggZU4wpxZRSSkIHJXQOOuYcU45KKEG4nHOrtZaWY4updJJK5yRkTEJIKYWSSgelU05CSDWW1lIpHXNSUmpB6CCEEEK2IIQNgtCQVQAAAQDAQBAasgoAUAAAEIqhGIoChIasAgAyAAAEoCiO4iiOIzmSY0kWEBqyCgAAAgAQAADAcBRJkRTJsSRL0ixL00RRVX3VNlVV9nVd13Vd13UgNGQVAAABAEBIp5mlGiDCDGQYCA1ZBQAgAAAARijCEANCQ1YBAAABAABiKDmIJrTmfHOOg2Y5aCrF5nRwItXmSW4q5uacc845J5tzxjjnnHOKcmYxaCa05pxzEoNmKWgmtOacc57E5kFrqrTmnHPGOaeDcUYY55xzmrTmQWo21uaccxa0pjlqLsXmnHMi5eZJbS7V5pxzzjnnnHPOOeecc6oXp3NwTjjnnHOi9uZabkIX55xzPhmne3NCOOecc84555xzzjnnnHOC0JBVAAAQAABBGDaGcacgSJ+jgRhFiGnIpAfdo8MkaAxyCqlHo6ORUuoglFTGSSmdIDRkFQAACAAAIYQUUkghhRRSSCGFFFKIIYYYYsgpp5yCCiqppKKKMsoss8wyyyyzzDLrsLPOOuwwxBBDDK20EktNtdVYY62555xrDtJaaa211koppZRSSikIDVkFAIAAABAIGWSQQUYhhRRSiCGmnHLKKaigAkJDVgEAgAAAAgAAADzJc0RHdERHdERHdERHdETHczxHlERJlERJtEzL1ExPFVXVlV1b1mXd9m1hF3bd93Xf93Xj14VhWZZlWZZlWZZlWZZlWZZlWYLQkFUAAAgAAIAQQgghhRRSSCGlGGPMMeegk1BCIDRkFQAACAAgAAAAwFEcxXEkR3IkyZIsSZM0S7M8zdM8TfREURRN01RFV3RF3bRF2ZRN13RN2XRVWbVdWbZt2dZtX5Zt3/d93/d93/d93/d93/d1HQgNWQUASAAA6EiOpEiKpEiO4ziSJAGhIasAABkAAAEAKIqjOI7jSJIkSZakSZ7lWaJmaqZneqqoAqEhqwAAQAAAAQAAAAAAKJriKabiKaLiOaIjSqJlWqKmaq4om7Lruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7ruq7rui4QGrIKAJAAANCRHMmRHEmRFEmRHMkBQkNWAQAyAAACAHAMx5AUybEsS9M8zdM8TfRET/RMTxVd0QVCQ1YBAIAAAAIAAAAAADAkw1IsR3M0SZRUS7VUTbVUSxVVT1VVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVVTVN0zRNIDRkJQAABADAYo3B5SAhJSXl3hDCEJOeMSYhtV4hBJGS3jEGFYOeMqIMct5C4xCDHggNWREARAEAAMYgxxBzyDlHqZMSOeeodJQa5xyljlJnKcWYYs0oldhSrI1zjlJHraOUYiwtdpRSjanGAgAAAhwAAAIshEJDVgQAUQAAhDFIKaQUYow5p5xDjCnnmHOGMeYcc44556B0UirnnHROSsQYc445p5xzUjonlXNOSiehAACAAAcAgAALodCQFQFAnACAQZI8T/I0UZQ0TxRFU3RdUTRd1/I81fRMU1U90VRVU1Vt2VRVWZY8zzQ901RVzzRV1VRVWTZVVZZFVdVt03V123RV3ZZt2/ddWxZ2UVVt3VRd2zdV1/Zd2fZ9WdZ1Y/I8VfVM03U903Rl1XVtW3VdXfdMU5ZN15Vl03Vt25VlXXdl2fc103Rd01Vl2XRd2XZlV7ddWfZ903WF35VlX1dlWRh2XfeFW9eV5XRd3VdlVzdWWfZ9W9eF4dZ1YZk8T1U903RdzzRdV3VdX1dd19Y105Rl03Vt2VRdWXZl2fddV9Z1zzRl2XRd2zZdV5ZdWfZ9V5Z13XRdX1dlWfhVV/Z1WdeV4dZt4Tdd1/dVWfaFV5Z14dZ1Ybl1XRg+VfV9U3aF4XRl39eF31luXTiW0XV9YZVt4VhlWTl+4ViW3feVZXRdX1ht2RhWWRaGX/id5fZ943h1XRlu3efMuu8Mx++k+8rT1W1jmX3dWWZfd47hGDq/8OOpqq+brisMpywLv+3rxrP7vrKMruv7qiwLvyrbwrHrvvP8vrAso+z6wmrLwrDatjHcvm4sv3Acy2vryjHrvlG2dXxfeArD83R1XXlmXcf2dXTjRzh+ygAAgAEHAIAAE8pAoSErAoA4AQCPJImiZFmiKFmWKIqm6LqiaLqupGmmqWmeaVqaZ5qmaaqyKZquLGmaaVqeZpqap5mmaJqua5qmrIqmKcumasqyaZqy7LqybbuubNuiacqyaZqybJqmLLuyq9uu7Oq6pFmmqXmeaWqeZ5qmasqyaZquq3meanqeaKqeKKqqaqqqraqqLFueZ5qa6KmmJ4qqaqqmrZqqKsumqtqyaaq2bKqqbbuq7Pqybeu6aaqybaqmLZuqatuu7OqyLNu6L2maaWqeZ5qa55mmaZqybJqqK1uep5qeKKqq5ommaqqqLJumqsqW55mqJ4qq6omea5qqKsumatqqaZq2bKqqLZumKsuubfu+68qybqqqbJuqauumasqybMu+78qq7oqmKcumqtqyaaqyLduy78uyrPuiacqyaaqybaqqLsuybRuzbPu6aJqybaqmLZuqKtuyLfu6LNu678qub6uqrOuyLfu67vqucOu6MLyybPuqrPq6K9u6b+sy2/Z9RNOUZVM1bdtUVVl2Zdn2Zdv2fdE0bVtVVVs2TdW2ZVn2fVm2bWE0Tdk2VVXWTdW0bVmWbWG2ZeF2Zdm3ZVv2ddeVdV/XfePXZd3murLty7Kt+6qr+rbu+8Jw667wCgAAGHAAAAgwoQwUGrISAIgCAACMYYwxCI1SzjkHoVHKOecgZM5BCCGVzDkIIZSSOQehlJQy5yCUklIIoZSUWgshlJRSawUAABQ4AAAE2KApsThAoSErAYBUAACD41iW55miatqyY0meJ4qqqaq27UiW54miaaqqbVueJ4qmqaqu6+ua54miaaqq6+q6aJqmqaqu67q6Lpqiqaqq67qyrpumqqquK7uy7Oumqqqq68quLPvCqrquK8uybevCsKqu68qybNu2b9y6ruu+7/vCka3rui78wjEMRwEA4AkOAEAFNqyOcFI0FlhoyEoAIAMAgDAGIYMQQgYhhJBSSiGllBIAADDgAAAQYEIZKDRkRQAQJwAAGEMppJRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkgppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkqppJRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoplVJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSCgCQinAAkHowoQwUGrISAEgFAACMUUopxpyDEDHmGGPQSSgpYsw5xhyUklLlHIQQUmktt8o5CCGk1FJtmXNSWosx5hgz56SkFFvNOYdSUoux5ppr7qS0VmuuNedaWqs115xzzbm0FmuuOdecc8sx15xzzjnnGHPOOeecc84FAOA0OACAHtiwOsJJ0VhgoSErAYBUAAACGaUYc8456BBSjDnnHIQQIoUYc845CCFUjDnnHHQQQqgYc8w5CCGEkDnnHIQQQgghcw466CCEEEIHHYQQQgihlM5BCCGEEEooIYQQQgghhBA6CCGEEEIIIYQQQgghhFJKCCGEEEIJoZRQAABggQMAQIANqyOcFI0FFhqyEgAAAgCAHJagUs6EQY5Bjw1BylEzDUJMOdGZYk5qMxVTkDkQnXQSGWpB2V4yCwAAgCAAIMAEEBggKPhCCIgxAABBiMwQCYVVsMCgDBoc5gHAA0SERACQmKBIu7iALgNc0MVdB0IIQhCCWBxAAQk4OOGGJ97whBucoFNU6iAAAAAAAAwA4AEA4KAAIiKaq7C4wMjQ2ODo8AgAAAAAABYA+AAAOD6AiIjmKiwuMDI0Njg6PAIAAAAAAAAAAICAgAAAAAAAQAAAAICAT2dnUwAE7AwAAAAAAAD/QwAAAgAAADuydfsFAQEBAQEACg4ODg==';
+      }
+      else if (Modernizr.audio.wav) {
+        elem.src = 'data:audio/wav;base64,UklGRvwZAABXQVZFZm10IBAAAAABAAEARKwAAIhYAQACABAAZGF0YdgZAAAAAAEA/v8CAP//AAABAP////8DAPz/BAD9/wEAAAAAAAAAAAABAP7/AgD//wAAAQD//wAAAQD//wAAAQD+/wIA//8AAAAAAAD//wIA/v8BAAAA//8BAAAA//8BAP//AQAAAP//AQD//wEAAAD//wEA//8BAP//AQD//wEA//8BAP//AQD+/wMA/f8DAP3/AgD+/wIA/////wMA/f8CAP7/AgD+/wMA/f8CAP7/AgD//wAAAAAAAAAAAQD+/wIA/v8CAP7/AwD9/wIA/v8BAAEA/v8CAP7/AQAAAAAAAAD//wEAAAD//wIA/f8DAP7/AQD//wEAAAD//wEA//8CAP7/AQD//wIA/v8CAP7/AQAAAAAAAAD//wEAAAAAAAAA//8BAP//AgD9/wQA+/8FAPz/AgAAAP//AgD+/wEAAAD//wIA/v8CAP3/BAD8/wQA/P8DAP7/AwD8/wQA/P8DAP7/AQAAAAAA//8BAP//AgD+/wEAAAD//wIA/v8BAP//AQD//wEAAAD//wEA//8BAAAAAAAAAP//AgD+/wEAAAAAAAAAAAD//wEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAP//AgD+/wIA/v8BAP//AQABAP7/AQD//wIA/v8CAP3/AwD/////AgD9/wMA/v8BAP//AQAAAP//AQD//wEA//8BAP//AAABAP//AAABAP//AQD//wAAAAACAP3/AwD9/wIA//8BAP//AQD//wEA//8BAP//AgD9/wMA/v8AAAIA/f8CAAAA/v8EAPv/BAD9/wIAAAD+/wQA+v8HAPr/BAD+/wEAAAD//wIA/f8EAPz/BAD7/wUA/P8EAPz/AwD+/wEAAAD//wEAAAAAAP//AgD8/wUA+/8FAPz/AwD9/wIA//8AAAEA/v8CAP//AQD//wAAAAABAP//AgD9/wMA/f8EAPz/AwD+/wAAAwD7/wUA/P8DAP7/AQAAAP//AgD+/wEAAQD+/wIA/v8BAAEA/v8CAP7/AQAAAP//AgD9/wMA/f8DAP7/AgD+/wEAAAAAAAEA//8AAAEA/v8DAP3/AgD//wEA//8BAP7/AwD9/wMA/v8BAP//AQAAAP//AgD9/wMA/v8BAP//AQAAAP//AgD+/wEAAQD+/wIA/////wIA//8AAAEA/f8DAP//AAABAP////8DAP3/AwD+/wEA//8BAP//AQAAAAAA//8BAP//AQD//wEA//8BAP//AAAAAAEA//8BAP7/AgD//wEA//8AAAAAAAAAAAAAAAD//wIA/v8BAAAA//8BAAEA/v8BAAAA//8DAPz/AwD+/wIA/v8CAP3/AwD+/wEAAAD//wEA//8BAAAA//8BAAAA/v8EAPv/BAD+/wAAAAABAP7/AgD//wAAAAABAP7/AgD//wAAAAAAAAAAAAABAP3/BAD8/wQA/f8BAAAAAAABAP7/AgD+/wIA/v8CAP7/AgD+/wIA/v8BAAAAAAD//wIA/f8DAP7/AAABAP//AAACAPz/BAD9/wIA//8AAP//AwD9/wMA/P8EAP3/AwD9/wIA//8BAP//AQD+/wMA/f8DAP7/AAABAP//AQAAAP//AQD//wIA/f8DAP7/AQAAAP//AQAAAAAA//8CAP7/AQABAP7/AgD+/wEAAQD+/wIA/v8CAP////8CAP7/AgD//wAAAAABAP7/AwD9/wIAAAD+/wMA/f8CAP//AQD+/wMA/f8CAP//AAACAPz/BQD6/wUA/v///wIA/v8CAP3/BAD7/wYA+v8FAPz/AwD/////AgD+/wEAAAD//wEAAAD//wIA/f8DAP7/AQAAAP//AgD//wAA//8BAAAAAAAAAP//AQD//wEA//8AAAIA/f8DAP3/AgAAAP//AQD//wEA//8AAAEA//8BAP////8CAP//AAABAP3/BAD9/wIA/v8BAAEA//8BAP7/AgD//wEA//8AAAEA//8BAP//AAAAAAEA//8BAP7/AgD//wEA//8AAAAAAQD+/wIA/v8BAAAAAAD//wIA/v8BAAAAAAAAAAAAAQD+/wMA/f8CAP//AQD//wIA/f8DAP7/AQD//wEA//8CAP7/AAABAP7/AwD9/wMA/v8AAAEA//8BAAAAAAD//wIA/v8BAAAA//8CAP7/AgD+/wEA//8CAP7/AgD//wAAAAAAAAAAAQD//wEA/v8DAPz/BQD8/wIA//8AAAEAAAD//wEA//8BAP//AQAAAAAA//8BAP//AgD+/wEAAAAAAP//AQD+/wMA/////wEA/v8CAP//AQD//wEA//8AAAEA//8BAAAA/v8EAPz/AwD+/wEAAAAAAAAA//8CAP7/AQD//wEA//8BAP//AAABAP7/AwD9/wIA//8BAP//AQD//wEA//8AAAEA/v8EAPv/BAD9/wIA//8BAP7/AwD9/wIA//8AAAEA//8BAP//AQD//wAAAQD//wEAAAD+/wMA/v8AAAIA/f8DAP7/AQD//wAAAQD+/wMA/f8CAP//AAABAP7/AgD+/wMA/f8CAP7/AQABAP7/AgD+/wIA/v8CAP7/AwD8/wMA//8AAAEA//8AAAAAAAABAP//AQD//wAAAQD//wIA/f8DAP3/AwD+/wAAAgD9/wIA//8AAAEAAAD+/wMA/P8FAPv/BAD9/wIA//8AAP//AgD+/wIA/v8BAAAAAAD//wEAAAAAAP//AQD//wEA//8BAP//AAABAP7/AwD9/wIA//8BAP//AAABAP//AQD//wAAAQD//wEA//8BAP//AAABAAAA//8BAP7/AwD9/wMA/f8DAP3/AgD//wEA//8BAP7/AgD//wAAAgD8/wQA/f8CAP//AQD+/wMA/f8CAP7/AgD//wAAAAAAAAAAAAABAP7/AwD9/wIA/v8DAP3/AwD9/wIA/v8DAPz/BQD7/wQA/f8CAP7/AwD9/wMA/f8CAP//AQAAAP7/AwD+/wEA//8AAAEAAAAAAP//AAABAP//AQAAAP7/AwD9/wMA/f8CAP//AQD//wEA//8AAAIA/f8CAAAA//8BAAAA//8BAAAA/v8EAPv/BAD9/wIA//8AAAEA/v8CAP//AAABAP//AAABAP//AAABAP7/AwD8/wQA/f8CAAAA/v8DAP3/AwD9/wMA/v8BAAAA//8BAAAA//8CAP7/AQAAAAAAAAAAAAAA//8CAP7/AgD+/wIA/v8CAP7/AgD//wAAAQD//wAAAQD//wAAAQD//wAAAQD+/wIA//8AAAAAAQD+/wMA/f8CAP//AQD//wEA//8AAAEA/v8DAP3/AgD//wAAAAABAP7/AwD9/wIA//8AAAEA/v8DAP3/AgD//wAAAAABAP7/AwD8/wMA/v8CAP//AAD//wIA/v8CAP7/AQABAP7/AQAAAP//AgD/////AQD//wEAAAD//wEA/v8EAPv/BAD9/wMA/v8BAAAA//8BAAEA/P8GAPr/BQD8/wMA/v8BAAAA//8CAP7/AQABAP3/BAD7/wYA+/8EAPz/AwD//wEA//8BAP7/BAD8/wMA/v8AAAIA/v8BAAAA//8BAAAA//8BAAAA//8CAP3/AwD+/wAAAgD8/wUA/P8DAP7/AAABAAAAAAD//wEAAAD//wIA/f8DAP7/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA/f8EAPz/AwD/////AgD+/wIA/f8DAP7/AgD+/wEA//8CAP7/AQD//wEAAAAAAP//AQAAAP//AgD9/wMA/v8BAAAA//8BAP//AQAAAP//AAACAP3/BAD7/wQA/v8BAAAA//8BAP//AQAAAP//AQAAAP7/BAD7/wUA+/8EAP3/AgD//wAAAQD+/wIA//8AAAEA/v8CAP//AQD+/wEAAAAAAAAAAAD//wEA//8CAP3/AwD9/wIA//8AAAAAAAAAAAAA//8BAP//AgD+/wEA//8CAP7/AQAAAP//AgD/////AgD/////AgD+/wIA//8AAP//AQABAP7/AgD9/wMA/v8CAP////8BAAAAAAAAAAAA//8CAP////8DAPz/AwD+/wEAAAAAAP//AQD//wEAAAD//wEAAAD+/wQA+/8FAPz/AgAAAP//AgD9/wMA/v8BAAAAAAD//wEAAAD//wIA/v8BAAAAAAD//wIA/v8BAAAA//8BAAAA//8CAP7/AQD//wEA//8BAAAA//8BAP//AAABAP//AQAAAP7/AgD//wEA//8AAAAAAQD+/wMA/P8EAP7///8DAPz/BQD8/wEAAQD+/wMA/v8AAAEA//8BAP//AQD//wEA/v8CAP//AQD//wAAAAABAAAA//8BAP//AQAAAAAA//8BAP//AgD+/wAAAQD//wIA/f8CAP//AQAAAP7/AwD9/wMA/v8BAP//AAABAP//AgD9/wIA//8BAAAA//8BAAAA//8CAP3/AwD+/wEAAAD+/wQA/P8DAP7/AAACAP7/AQAAAP//AQAAAP//AQAAAP//AgD9/wIAAAD//wIA/f8DAP7/AQD//wEA//8CAP7/AQD//wAAAQD//wEA//8AAAAAAQD//wEAAAD9/wUA+/8FAPz/AgD//wAAAQD//wAAAQD+/wMA/f8BAAEA/v8CAP7/AgD+/wIA/v8BAAAAAAAAAAAAAAD//wIA/v8CAP////8CAP7/AgD+/wIA/v8CAP7/AQAAAP//AQAAAP//AQD//wAAAQD//wAAAQD+/wMA/f8CAAAA/v8DAP3/AgAAAP//AQAAAP7/AwD9/wMA/v8BAP//AQD//wEAAAD+/wMA/f8CAAAA/v8CAP//AAAAAAEA//8AAAEA/v8DAP3/AwD9/wIA//8BAP//AgD8/wQA/v8BAAAA/v8CAP//AQD//wAAAAAAAAEA/f8EAPz/BAD9/wIA//8AAAAAAAABAP//AAAAAAAAAAABAP3/BAD9/wIA/v8BAAEA//8AAAAA//8CAP7/AgD9/wQA+/8FAPv/BQD8/wMA/f8DAP3/AwD+/wAAAgD9/wMA/f8CAAAA/v8EAPv/BQD7/wUA/P8DAP///v8DAP3/BAD8/wMA/f8DAP7/AQD//wEAAAD//wEA/v8CAAAA/v8CAP7/AgD//wAAAAAAAAAAAQD+/wIA//8AAAEA/v8DAPz/BAD9/wIA//8AAP//AgD//wEA/v8BAAAAAQD//wAAAAAAAAEA//8AAAEA//8BAP//AAABAP//AQD+/wIA/v8DAPz/BAD8/wQA/f8BAAAAAQD+/wMA/P8DAP//AAAAAAAAAAD//wMA+/8FAP3/AQABAP3/BAD8/wMA/v8BAAAA//8CAP3/AwD+/wEAAQD9/wMA/f8EAPz/BAD7/wQA/v8BAAEA/f8DAP7/AQAAAP//AgD+/wEAAAD//wIA/v8CAP7/AgD+/wEAAQD//wEA/v8CAP7/BAD7/wQA/f8CAAAA//8AAAAAAAABAP//AQD+/wEAAQD+/wMA/f8BAAEA/v8DAPz/AwD/////AwD8/wQA/P8DAP7/AgD//wAA//8BAAAAAAAAAP//AgD+/wEAAAD//wIA/v8BAAAA//8CAP3/AgD//wAAAQD+/wIA/v8BAAAA//8CAP7/AgD+/wEA//8CAP3/BAD7/wQA/v8BAAAA//8AAAEAAAD//wIA/f8DAP7/AgD+/wIA/v8CAP7/AgD+/wEAAAAAAP//AgD9/wMA/v8BAP//AgD9/wMA/v8AAAEA//8BAP//AQD//wEA//8AAAEA/v8EAPz/AgD//wAAAQAAAP//AAABAP//AQD//wEAAAD//wEA//8BAAEA/f8DAP7/AQABAP3/AwD+/wIA/////wEAAAAAAAAAAAD//wIA/v8CAP////8CAP7/AgD//wAA//8CAP3/BAD9/wAAAgD9/wMA/v8BAP//AQAAAP//AQAAAP//AgD9/wMA/f8EAPz/AwD+/wEAAAAAAAAAAAD//wIA/f8EAP3/AAABAAAA//8CAP7/AQAAAP//AQAAAAAA//8BAP//AQAAAP//AQAAAP//AQAAAP//AgD9/wMA/v8BAP//AQAAAP//AQD//wIA/v8CAP3/BAD9/wEAAAD//wEAAQD9/wMA/f8CAAAA/v8DAP3/AgD//wAAAQD+/wIA/v8CAP7/AQAAAP//AgD+/wEAAAAAAP//AwD7/wUA/f8BAAEA/v8BAAEA/v8DAP3/AgD//wEA//8BAP//AQD//wEA//8CAP3/BAD7/wQA/////wIA/v8AAAIA/v8CAP3/BAD7/wUA/P8DAP3/AwD9/wMA/v8AAAIA/v8CAP7/AgD+/wIA//8AAAEA/v8CAP7/AgD//wAAAAD//wEAAAAAAAAA//8BAP7/BAD7/wUA/P8CAAAA//8BAP//AQAAAP//AgD9/wMA/v8BAAAA//8BAAAA//8CAP3/AwD+/wEA//8CAP3/AwD+/wAAAwD8/wIAAAD//wIA/////wIA/v8CAP7/AgD+/wEAAAAAAAAAAAAAAP//AgD+/wIA//8AAAAA//8CAP7/AgD+/wEA//8CAP3/AwD9/wMA/v8BAP7/AwD9/wMA/f8CAP//AQD+/wIA//8BAP//AQD+/wMA/v8BAAAA//8BAAAA//8CAP7/AQAAAP//AgD+/wIA/v8CAP//AAAAAAEA//8BAP//AAABAAAA//8BAP//AQD//wEA//8BAP//AQAAAP//AQD//wEAAAD//wIA/f8CAAAA//8BAAAA//8BAP//AAABAP//AQD//wAAAAAAAAEA/v8CAP//AQD//wAAAAABAP7/AwD9/wIAAAD+/wIA//8BAP//AgD9/wMA/f8DAP7/AgD+/wEAAAAAAAEA/v8CAP7/AgD//wAAAAAAAAAAAAAAAP//AgD/////AgD9/wQA/f8BAAAAAAAAAAEA/f8DAP////8DAP3/AQABAP7/AgD//wAAAQD+/wMA/f8CAP7/AQABAP7/AwD7/wYA+v8FAP3/AQABAP7/AgD+/wMA/f8CAP7/AwD+/wEA//8BAP//AQAAAP7/BQD5/wcA+v8FAPz/AwD+/wIA/v8BAAAA//8DAPv/BQD8/wMA/////wEAAAAAAAAAAAD//wIA/f8DAP7/AQAAAP//AQAAAP//AgD+/wIA/v8BAAEA/f8EAPz/AwD+/wEA//8CAP7/AQD//wEA//8CAP7/AQAAAP//AgD+/wEAAAAAAAAAAAAAAAAAAAD//wIA/f8EAPz/AwD+/wEA//8CAP7/AgD+/wEAAQD+/wEAAQD+/wIA/////wIA//8AAAAAAAAAAAAAAAD//wEAAAAAAP//AgD9/wMA/v8BAP//AQAAAP//AQD//wEA//8BAP//AQD//wEA//8BAP//AQAAAP7/AwD9/wMA/v8BAP7/AwD9/wMA/v8BAP//AAABAP//AQD//wAAAAABAP//AAAAAAAAAQD//wEA/v8CAAAA/v8EAPv/BAD9/wIAAAD+/wMA/P8DAP//AAAAAP//AQD//wIA/f8DAP3/AwD9/wMA/v8BAAAA//8BAAAA//8CAP3/AwD9/wQA+/8FAPv/BQD8/wMA/v8BAAAA//8BAP//AgD+/wEAAAD//wIA/v8BAAEA/f8DAP3/AgAAAP//AQD//wAAAQD//wEA//8BAP//AQD//wEA/v8DAP3/AgAAAP7/AwD9/wIAAAD//wEAAAD//wIA/f8DAP7/AgD9/wQA+/8FAPz/AgAAAP//AgD9/wIA//8BAP//AQD//wEA//8BAP//AQD//wIA/f8DAP3/AgD//wAAAQD+/wIA/v8BAAEA/v8CAP7/AgD+/wMA/P8DAP//AAABAP7/AQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEA/v8CAP3/BAD8/wMA/v8BAAAAAAD//wEAAAAAAAAAAAD//wEAAAAAAAAA//8BAP//AgD+/wEA//8CAP3/AwD9/wMA/f8EAPv/BAD+/wAAAQD//wEA//8BAP//AAABAP//AQD//wEAAAD//wEA//8BAP//AgD9/wMA/v8AAAIA/f8DAP7/AAACAP3/AwD+/wEA//8BAP//AQAAAP//AQAAAP7/AwD9/wMA/v8AAAEA//8BAP//AAAAAAEA//8AAAEA/v8CAP//AAAAAAEA/v8DAPz/BAD9/wEAAQD+/wEAAQD9/wQA/P8DAP7/AQAAAAAAAAAAAAAAAAAAAAAAAQD+/wIA/////wIA/v8BAAAA//8BAP//AQD//wEA//8BAAAA/v8EAPz/AwD///7/BAD8/wMA/////wIA/v8CAP////8CAP7/AgD+/wIA/v8CAP////8CAP7/AwD9/wIA/v8CAP//AAABAP7/AwD9/wEAAQD+/wMA/f8CAP//AAAAAAEA/v8DAPz/BAD9/wIA/v8CAP7/AgD//wAAAAD//wIA/v8CAP7/AQAAAAAA//8CAP7/AgD+/wIA/v8CAP7/AwD8/wUA+v8GAPv/AwD//wAAAAAAAAAA//8DAPv/BQD9/wAAAgD9/wMA/v8BAP//AQAAAP//AgD9/wMA/v8BAAAA//8BAAAAAAAAAP//AQAAAAAAAAD//wEA//8CAP3/AwD+/wAAAgD+/wEAAAD//wIA/v8CAP7/AgD/////AwD8/wUA/P8CAP//AQD//wIA/f8DAP3/AwD+/wAAAQD+/wMA/f8DAP3/AgD//wAAAQD//wEA//8BAP7/AwD+/wEA//8AAAEA//8CAPz/BAD9/wIA//8AAAEA/v8DAPz/BAD9/wIA//8AAAEA/v8CAP7/AgD//wEA/f8EAPz/BAD+////AgD//wAAAQD//wAAAQD//wEA//8BAP7/AwD+/wEA';
+      }
+      else {
+        addTest('audiopreload', false);
+        return;
+      }
+    }
+
+    catch (e) {
+      addTest('audiopreload', false);
+      return;
+    }
+
+    elem.setAttribute('preload', 'auto');
+    elem.style.cssText = 'display:none';
+    docElement.appendChild(elem);
+    // wait for the next tick to add the listener, otherwise the element may
+    // not have time to play in high load situations (e.g. the test suite)
+    setTimeout(function() {
+      elem.addEventListener('loadeddata', testpreload, false);
+      timeout = setTimeout(testpreload, waitTime);
+    }, 0);
+  });
+});
diff --git a/feature-detects/audio/webaudio.js b/feature-detects/audio/webaudio.js
new file mode 100644
index 0000000..8947f6d
--- /dev/null
+++ b/feature-detects/audio/webaudio.js
@@ -0,0 +1,29 @@
+/*!
+{
+  "name": "Web Audio API",
+  "property": "webaudio",
+  "caniuse": "audio-api",
+  "polyfills": ["dynamicaudiojs", "audiolibjs"],
+  "tags": ["audio", "media"],
+  "builderAliases": ["audio_webaudio_api"],
+  "authors": ["Addy Osmani"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://webaudio.github.io/web-audio-api/"
+  }]
+}
+!*/
+/* DOC
+Check for the Web Audio API
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('webaudio', function() {
+    var prefixed = 'webkitAudioContext' in window;
+    var unprefixed = 'AudioContext' in window;
+
+    if (Modernizr._config.usePrefixes) {
+      return prefixed || unprefixed;
+    }
+    return unprefixed;
+  });
+});
diff --git a/feature-detects/battery-api.js b/feature-detects/battery-api.js
deleted file mode 100644
index 4177e8f..0000000
--- a/feature-detects/battery-api.js
+++ /dev/null
@@ -1,8 +0,0 @@
-
-// Battery API
-// https://developer.mozilla.org/en/DOM/window.navigator.mozBattery
-// By: Paul Sayre
-
-Modernizr.addTest('battery',
-	!!Modernizr.prefixed('battery', navigator)
-);
\ No newline at end of file
diff --git a/feature-detects/battery-level.js b/feature-detects/battery-level.js
deleted file mode 100644
index 07f9575..0000000
--- a/feature-detects/battery-level.js
+++ /dev/null
@@ -1,11 +0,0 @@
-
-// Low Battery Level
-// Enable a developer to remove CPU intensive CSS/JS when battery is low
-// developer.mozilla.org/en/DOM/window.navigator.mozBattery
-// By: Paul Sayre
-
-Modernizr.addTest('lowbattery', function () {
-	var minLevel = 0.20,
-		battery = Modernizr.prefixed('battery', navigator);
-	return !!(battery && !battery.charging && battery.level <= minLevel);
-});
diff --git a/feature-detects/battery/battery.js b/feature-detects/battery/battery.js
new file mode 100644
index 0000000..2b83ca3
--- /dev/null
+++ b/feature-detects/battery/battery.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "Battery API",
+  "property": "batteryapi",
+  "aliases": ["battery-api"],
+  "builderAliases": ["battery_api"],
+  "tags": ["battery", "device", "media"],
+  "authors": ["Paul Sayre", "Alex Bradley (@abrad1212)"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/DOM/window.navigator.mozBattery"
+  }]
+}
+!*/
+/* DOC
+Detect support for the Battery API, for accessing information about the system's battery charge level.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('batteryapi', !!prefixed('battery', navigator) || !!prefixed('getBattery', navigator), {aliases: ['battery-api']});
+});
diff --git a/feature-detects/battery/lowbattery.js b/feature-detects/battery/lowbattery.js
new file mode 100644
index 0000000..a39f374
--- /dev/null
+++ b/feature-detects/battery/lowbattery.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "Low Battery Level",
+  "property": "lowbattery",
+  "tags": ["battery", "hardware", "mobile"],
+  "builderAliases": ["battery_level"],
+  "authors": ["Paul Sayre"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Navigator/battery"
+  }]
+}
+!*/
+/* DOC
+Enable a developer to remove CPU intensive CSS/JS when battery is low
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('lowbattery', function() {
+    var minLevel = 0.20;
+    var battery = prefixed('battery', navigator);
+    return !!(battery && !battery.charging && battery.level <= minLevel);
+  });
+});
diff --git a/feature-detects/blob-constructor.js b/feature-detects/blob-constructor.js
deleted file mode 100644
index f10bd7b..0000000
--- a/feature-detects/blob-constructor.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// Blob constructor
-// http://dev.w3.org/2006/webapi/FileAPI/#constructorBlob
-
-Modernizr.addTest('blobconstructor', function () {
-    try {
-        return !!new Blob();
-    } catch (e) {
-        return false;
-    }
-});
diff --git a/feature-detects/blob.js b/feature-detects/blob.js
new file mode 100644
index 0000000..7af699a
--- /dev/null
+++ b/feature-detects/blob.js
@@ -0,0 +1,28 @@
+/*!
+{
+  "name": "Blob constructor",
+  "property": "blobconstructor",
+  "aliases": ["blob-constructor"],
+  "builderAliases": ["blob_constructor"],
+  "caniuse": "blobbuilder",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://w3c.github.io/FileAPI/#constructorBlob"
+  }],
+  "polyfills": ["blobjs"]
+}
+!*/
+/* DOC
+Detects support for the Blob constructor, for creating file-like objects of immutable, raw data.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('blobconstructor', function() {
+    try {
+      return !!new Blob();
+    } catch (e) {
+      return false;
+    }
+  }, {
+    aliases: ['blob-constructor']
+  });
+});
diff --git a/feature-detects/canvas-todataurl-type.js b/feature-detects/canvas-todataurl-type.js
deleted file mode 100644
index bf8f2e3..0000000
--- a/feature-detects/canvas-todataurl-type.js
+++ /dev/null
@@ -1,28 +0,0 @@
-// canvas.toDataURL type support
-// http://www.w3.org/TR/html5/the-canvas-element.html#dom-canvas-todataurl
-
-// This test is asynchronous. Watch out.
-
-(function () {
-
-    if (!Modernizr.canvas) {
-        return false;
-    }
-
-    var image = new Image(),
-        canvas = document.createElement('canvas'),
-        ctx = canvas.getContext('2d');
-
-    image.onload = function() {
-        ctx.drawImage(image, 0, 0);
-
-        Modernizr.addTest('todataurljpeg', function() {
-            return canvas.toDataURL('image/jpeg').indexOf('data:image/jpeg') === 0;
-        });
-        Modernizr.addTest('todataurlwebp', function() {
-            return canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
-        });
-    };
-
-    image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==';
-}());
diff --git a/feature-detects/canvas/blending.js b/feature-detects/canvas/blending.js
new file mode 100644
index 0000000..6a95550
--- /dev/null
+++ b/feature-detects/canvas/blending.js
@@ -0,0 +1,32 @@
+/*!
+{
+  "name": "canvas blending support",
+  "property": "canvasblending",
+  "caniuse": "canvas-blending",
+  "tags": ["canvas"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://drafts.fxtf.org/compositing-1/"
+  }, {
+    "name": "Article",
+    "href": "https://web.archive.org/web/20171003232921/http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/"
+  }]
+}
+!*/
+/* DOC
+Detects if Photoshop style blending modes are available in canvas.
+*/
+define(['Modernizr', 'createElement', 'test/canvas/canvas'], function(Modernizr, createElement) {
+  Modernizr.addTest('canvasblending', function() {
+    if (Modernizr.canvas === false) {
+      return false;
+    }
+    var ctx = createElement('canvas').getContext('2d');
+    // firefox 3 throws an error when setting an invalid `globalCompositeOperation`
+    try {
+      ctx.globalCompositeOperation = 'screen';
+    } catch (e) {}
+
+    return ctx.globalCompositeOperation === 'screen';
+  });
+});
diff --git a/feature-detects/canvas/canvas.js b/feature-detects/canvas/canvas.js
new file mode 100644
index 0000000..859a87c
--- /dev/null
+++ b/feature-detects/canvas/canvas.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "Canvas",
+  "property": "canvas",
+  "caniuse": "canvas",
+  "tags": ["canvas", "graphics"],
+  "polyfills": ["excanvas", "slcanvas"]
+}
+!*/
+/* DOC
+Detects support for the `<canvas>` element for 2D drawing.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  // On the S60 and BB Storm, getContext exists, but always returns undefined
+  // so we actually have to call getContext() to verify
+  // github.com/Modernizr/Modernizr/issues/issue/97/
+  Modernizr.addTest('canvas', function() {
+    var elem = createElement('canvas');
+    return !!(elem.getContext && elem.getContext('2d'));
+  });
+});
diff --git a/feature-detects/canvas/text.js b/feature-detects/canvas/text.js
new file mode 100644
index 0000000..6e6cb72
--- /dev/null
+++ b/feature-detects/canvas/text.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "Canvas text",
+  "property": "canvastext",
+  "caniuse": "canvas-text",
+  "tags": ["canvas", "graphics"],
+  "polyfills": ["canvastext"]
+}
+!*/
+/* DOC
+Detects support for the text APIs for `<canvas>` elements.
+*/
+define(['Modernizr', 'createElement', 'test/canvas/canvas'], function(Modernizr, createElement) {
+  Modernizr.addTest('canvastext', function() {
+    if (Modernizr.canvas === false) {
+      return false;
+    }
+    return typeof createElement('canvas').getContext('2d').fillText === 'function';
+  });
+});
diff --git a/feature-detects/canvas/todataurl.js b/feature-detects/canvas/todataurl.js
new file mode 100644
index 0000000..ca72efd
--- /dev/null
+++ b/feature-detects/canvas/todataurl.js
@@ -0,0 +1,48 @@
+/*!
+{
+  "name": "canvas.toDataURL type support",
+  "property": ["todataurljpeg", "todataurlpng", "todataurlwebp"],
+  "tags": ["canvas"],
+  "builderAliases": ["canvas_todataurl_type"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement.toDataURL"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement', 'test/canvas/canvas'], function(Modernizr, createElement) {
+
+  var canvas = createElement('canvas');
+
+  Modernizr.addTest('todataurljpeg', function() {
+    var supports = false;
+
+    // AVG secure browser with 'Anti-Fingerprinting' turned on throws an exception when using an "invalid" toDataUrl
+    try {
+      supports = !!Modernizr.canvas && canvas.toDataURL('image/jpeg').indexOf('data:image/jpeg') === 0;
+    } catch (e) {}
+
+    return supports;
+  });
+  Modernizr.addTest('todataurlpng', function() {
+    var supports = false;
+
+    // AVG secure browser with 'Anti-Fingerprinting' turned on throws an exception when using an "invalid" toDataUrl
+    try {
+      supports = !!Modernizr.canvas && canvas.toDataURL('image/png').indexOf('data:image/png') === 0;
+    } catch (e) {}
+
+    return supports;
+  });
+  Modernizr.addTest('todataurlwebp', function() {
+    var supports = false;
+
+    // firefox 3 throws an error when you use an "invalid" toDataUrl
+    try {
+      supports = !!Modernizr.canvas && canvas.toDataURL('image/webp').indexOf('data:image/webp') === 0;
+    } catch (e) {}
+
+    return supports;
+  });
+
+});
diff --git a/feature-detects/canvas/winding.js b/feature-detects/canvas/winding.js
new file mode 100644
index 0000000..88c9522
--- /dev/null
+++ b/feature-detects/canvas/winding.js
@@ -0,0 +1,28 @@
+/*!
+{
+  "name": "canvas winding support",
+  "property": "canvaswinding",
+  "tags": ["canvas"],
+  "notes": [{
+    "name": "Article",
+    "href": "https://web.archive.org/web/20170825024655/http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/"
+  }]
+}
+!*/
+/* DOC
+Determines if winding rules, which controls if a path can go clockwise or counterclockwise
+*/
+define(['Modernizr', 'createElement', 'test/canvas/canvas'], function(Modernizr, createElement) {
+
+  Modernizr.addTest('canvaswinding', function() {
+    if (Modernizr.canvas === false) {
+      return false;
+    }
+    var ctx = createElement('canvas').getContext('2d');
+
+    ctx.rect(0, 0, 10, 10);
+    ctx.rect(2, 2, 6, 6);
+    return ctx.isPointInPath(5, 5, 'evenodd') === false;
+  });
+
+});
diff --git a/feature-detects/clipboard.js b/feature-detects/clipboard.js
new file mode 100644
index 0000000..d163bb9
--- /dev/null
+++ b/feature-detects/clipboard.js
@@ -0,0 +1,46 @@
+/*!
+{
+  "name": "Clipboard API",
+  "property": "clipboard",
+  "tags": ["clipboard"],
+  "authors": ["Markel Ferro (@MarkelFe)"],
+  "async": true,
+  "warnings": ["It may return false in non-HTTPS connections as the API is only available in secure contexts"],
+  "notes": [{
+    "name": "MDN Docs Clipboard Object",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Clipboard"
+  }, {
+    "name": "MDN Docs Clipboard API",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Clipboard_API"
+  }]
+}
+!*/
+/* DOC
+It tests for the whole clipboard API. The sub-properties `read`, `readText`, `write` and `writeText` are supported. Note: This test does not detect the [clipboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/ClipboardEvent).
+
+```javascript
+Modernizr.clipboard         // Supports the clipboard API
+Modernizr.clipboard.read    // Supports the read sub-property
+```
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+  Modernizr.addAsyncTest(function() {
+    var result;
+    var props = ['read', 'readText', 'write', 'writeText'];
+    if (navigator.clipboard) {
+      addTest('clipboard', true);
+      // The sub-modules checked only if API is available to avoid Edge crashes
+      for (var i = 0; i < props.length; i++) {
+        if (navigator.clipboard[props[i]]) {
+          result = true;
+        } else {
+          result = false;
+        }
+        addTest('clipboard.' + props[i].toLowerCase(), result);
+      }
+    }
+    else {
+      addTest('clipboard', false);
+    }
+  });
+});
\ No newline at end of file
diff --git a/feature-detects/contenteditable.js b/feature-detects/contenteditable.js
index 6543666..a2676d0 100644
--- a/feature-detects/contenteditable.js
+++ b/feature-detects/contenteditable.js
@@ -1,9 +1,30 @@
-// contentEditable
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/editing.html#contenteditable
+/*!
+{
+  "name": "Content Editable",
+  "property": "contenteditable",
+  "caniuse": "contenteditable",
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/interaction.html#contenteditable"
+  }]
+}
+!*/
+/* DOC
+Detects support for the `contenteditable` attribute of elements, allowing their DOM text contents to be edited directly by the user.
+*/
+define(['Modernizr', 'createElement', 'docElement'], function(Modernizr, createElement, docElement) {
+  Modernizr.addTest('contenteditable', function() {
+    // early bail out
+    if (!('contentEditable' in docElement)) {
+      return;
+    }
 
-// this is known to false positive in some mobile browsers
-// here is a whitelist of verified working browsers:
-// https://github.com/NielsLeenheer/html5test/blob/549f6eac866aa861d9649a0707ff2c0157895706/scripts/engine.js#L2083
+    // some mobile browsers (android < 3.0, iOS < 5) claim to support
+    // contentEditable, but but don't really. This test checks to see
+    // confirms whether or not it actually supports it.
 
-Modernizr.addTest('contenteditable',
-        'contentEditable' in document.documentElement);
+    var div = createElement('div');
+    div.contentEditable = true;
+    return div.contentEditable === 'true';
+  });
+});
diff --git a/feature-detects/contentsecuritypolicy.js b/feature-detects/contentsecuritypolicy.js
deleted file mode 100644
index ee1ddb8..0000000
--- a/feature-detects/contentsecuritypolicy.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// Test for (experimental) Content Security Policy 1.1 support.
-//
-// This feature is still quite experimental, but is available now in Chrome 22.
-// If the `SecurityPolicy` property is available, you can be sure the browser
-// supports CSP. If it's not available, the browser still might support an
-// earlier version of the CSP spec.
-//
-// Editor's Draft: https://dvcs.w3.org/hg/content-security-policy/raw-file/tip/csp-specification.dev.html
-
-Modernizr.addTest('contentsecuritypolicy', 'SecurityPolicy' in document);
diff --git a/feature-detects/contextmenu.js b/feature-detects/contextmenu.js
index dd8182f..ac533f2 100644
--- a/feature-detects/contextmenu.js
+++ b/feature-detects/contextmenu.js
@@ -1,11 +1,24 @@
-// http://www.w3.org/TR/html5/interactive-elements.html#context-menus
-// Demo at http://thewebrocks.com/demos/context-menu/
-Modernizr.addTest(
-  'contextmenu', 
-  ('contextMenu' in document.documentElement && 'HTMLMenuItemElement' in window) 
-);
-
-
-
-
-
+/*!
+{
+  "name": "Context menus",
+  "property": "contextmenu",
+  "caniuse": "menu",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/html5/interactive-elements.html#context-menus"
+  }, {
+    "name": "thewebrocks.com Demo",
+    "href": "http://thewebrocks.com/demos/context-menu/"
+  }],
+  "polyfills": ["jquery-contextmenu"]
+}
+!*/
+/* DOC
+Detects support for custom context menus.
+*/
+define(['Modernizr', 'docElement'], function(Modernizr, docElement) {
+  Modernizr.addTest(
+    'contextmenu',
+    ('contextMenu' in docElement && 'HTMLMenuItemElement' in window)
+  );
+});
diff --git a/feature-detects/cookies.js b/feature-detects/cookies.js
deleted file mode 100644
index 6a2f9d4..0000000
--- a/feature-detects/cookies.js
+++ /dev/null
@@ -1,15 +0,0 @@
-
-// by tauren
-// https://github.com/Modernizr/Modernizr/issues/191
-
-Modernizr.addTest('cookies', function () {
-  // Quick test if browser has cookieEnabled host property
-  if (navigator.cookieEnabled) return true;
-  // Create cookie
-  document.cookie = "cookietest=1";
-  var ret = document.cookie.indexOf("cookietest=") != -1;
-  // Delete cookie
-  document.cookie = "cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT";
-  return ret;
-});
-
diff --git a/feature-detects/cors.js b/feature-detects/cors.js
index 286d717..3f74ce9 100644
--- a/feature-detects/cors.js
+++ b/feature-detects/cors.js
@@ -1,3 +1,19 @@
-// cors
-// By Theodoor van Donge
-Modernizr.addTest('cors', !!(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()));
\ No newline at end of file
+/*!
+{
+  "name": "Cross-Origin Resource Sharing",
+  "property": "cors",
+  "caniuse": "cors",
+  "authors": ["Theodoor van Donge"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS"
+  }],
+  "polyfills": ["pmxdr", "ppx", "flxhr"]
+}
+!*/
+/* DOC
+Detects support for Cross-Origin Resource Sharing: method of performing XMLHttpRequests across domains.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('cors', 'XMLHttpRequest' in window && 'withCredentials' in new XMLHttpRequest());
+});
diff --git a/feature-detects/crypto.js b/feature-detects/crypto.js
new file mode 100644
index 0000000..93a65d4
--- /dev/null
+++ b/feature-detects/crypto.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "Web Cryptography",
+  "property": "cryptography",
+  "caniuse": "cryptography",
+  "tags": ["crypto"],
+  "authors": ["roblarsen"],
+  "notes": [{
+    "name": "W3C Editor's Draft Spec",
+    "href": "https://www.w3.org/TR/WebCryptoAPI/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the cryptographic functionality available under window.crypto.subtle
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  var crypto = prefixed('crypto', window);
+  Modernizr.addTest('crypto', !!prefixed('subtle', crypto));
+});
diff --git a/feature-detects/crypto/getrandomvalues.js b/feature-detects/crypto/getrandomvalues.js
new file mode 100644
index 0000000..2bb398f
--- /dev/null
+++ b/feature-detects/crypto/getrandomvalues.js
@@ -0,0 +1,32 @@
+/*!
+{
+  "name": "getRandomValues",
+  "property": "getrandomvalues",
+  "caniuse": "getrandomvalues",
+  "tags": ["crypto"],
+  "authors": ["komachi"],
+  "notes": [{
+    "name": "W3C Editor’s Draft Spec",
+    "href": "https://w3c.github.io/webcrypto/#Crypto-interface-methods"
+  }]
+}
+!*/
+/* DOC
+Detects support for the window.crypto.getRandomValues method for generating cryptographically secure random numbers
+*/
+define(['Modernizr', 'prefixed', 'is'], function(Modernizr, prefixed, is) {
+  // In Safari <=5.0 `window.crypto` exists (for some reason) but is `undefined`, so we have to check
+  // it’s truthy before checking for existence of `getRandomValues`
+  var crypto = prefixed('crypto', window);
+  var supportsGetRandomValues;
+
+  // Safari 6.0 supports crypto.getRandomValues, but does not return the array,
+  // which is required by the spec, so we need to actually check.
+  if (crypto && 'getRandomValues' in crypto && 'Uint32Array' in window) {
+    var array = new Uint32Array(10);
+    var values = crypto.getRandomValues(array);
+    supportsGetRandomValues = values && is(values[0], 'number');
+  }
+
+  Modernizr.addTest('getrandomvalues', !!supportsGetRandomValues);
+});
diff --git a/feature-detects/css-backgroundposition-shorthand.js b/feature-detects/css-backgroundposition-shorthand.js
deleted file mode 100644
index ce016e1..0000000
--- a/feature-detects/css-backgroundposition-shorthand.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
-    https://developer.mozilla.org/en/CSS/background-position
-    http://www.w3.org/TR/css3-background/#background-position
-
-    Example: http://jsfiddle.net/Blink/bBXvt/
-*/
-
-(function() {
-
-    var elem = document.createElement('a'),
-        eStyle = elem.style,
-        val = "right 10px bottom 10px";
-
-    Modernizr.addTest('bgpositionshorthand', function(){
-        eStyle.cssText = "background-position: " + val + ";";
-        return (eStyle.backgroundPosition === val);
-    });
-
-}());
diff --git a/feature-detects/css-backgroundposition-xy.js b/feature-detects/css-backgroundposition-xy.js
deleted file mode 100644
index d52d600..0000000
--- a/feature-detects/css-backgroundposition-xy.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
-	Allan Lei https://github.com/allanlei
-	
-	Check adapted from https://github.com/brandonaaron/jquery-cssHooks/blob/master/bgpos.js
-	
-	Test: http://jsfiddle.net/allanlei/R8AYS/
-*/
-Modernizr.addTest('bgpositionxy', function() {
-    return Modernizr.testStyles('#modernizr {background-position: 3px 5px;}', function(elem) {
-        var cssStyleDeclaration = window.getComputedStyle ? getComputedStyle(elem, null) : elem.currentStyle;
-        var xSupport = (cssStyleDeclaration.backgroundPositionX == '3px') || (cssStyleDeclaration['background-position-x'] == '3px');
-        var ySupport = (cssStyleDeclaration.backgroundPositionY == '5px') || (cssStyleDeclaration['background-position-y'] == '5px');
-        return xSupport && ySupport;
-    });
-});
\ No newline at end of file
diff --git a/feature-detects/css-backgroundrepeat.js b/feature-detects/css-backgroundrepeat.js
deleted file mode 100644
index 365447c..0000000
--- a/feature-detects/css-backgroundrepeat.js
+++ /dev/null
@@ -1,31 +0,0 @@
-// developer.mozilla.org/en/CSS/background-repeat
-
-// test page: jsbin.com/uzesun/
-// http://jsfiddle.net/ryanseddon/yMLTQ/6/    
-
-(function(){
-
-
-function getBgRepeatValue(elem){
-    return (window.getComputedStyle ?
-             getComputedStyle(elem, null).getPropertyValue('background') :
-             elem.currentStyle['background']);
-}
-  
-
-Modernizr.testStyles(' #modernizr { background-repeat: round; } ', function(elem, rule){ 
-
-  Modernizr.addTest('bgrepeatround', getBgRepeatValue(elem) == 'round');
-
-});
-
-
-
-Modernizr.testStyles(' #modernizr { background-repeat: space; } ', function(elem, rule){ 
-
-  Modernizr.addTest('bgrepeatspace', getBgRepeatValue(elem) == 'space');
-
-});
-
-
-})();
diff --git a/feature-detects/css-backgroundsizecover.js b/feature-detects/css-backgroundsizecover.js
deleted file mode 100644
index dd7e51b..0000000
--- a/feature-detects/css-backgroundsizecover.js
+++ /dev/null
@@ -1,10 +0,0 @@
-
-// developer.mozilla.org/en/CSS/background-size
-
-Modernizr.testStyles( '#modernizr{background-size:cover}', function( elem ) {
-	var style = window.getComputedStyle ?
-		window.getComputedStyle( elem, null )
-		: elem.currentStyle;
-		
-	Modernizr.addTest( 'bgsizecover', style.backgroundSize == 'cover' );
-});
\ No newline at end of file
diff --git a/feature-detects/css-boxsizing.js b/feature-detects/css-boxsizing.js
deleted file mode 100644
index ab90913..0000000
--- a/feature-detects/css-boxsizing.js
+++ /dev/null
@@ -1,9 +0,0 @@
-
-// developer.mozilla.org/en/CSS/box-sizing
-// github.com/Modernizr/Modernizr/issues/248
-
-Modernizr.addTest("boxsizing",function(){
-    return Modernizr.testAllProps("boxSizing") && (document.documentMode === undefined || document.documentMode > 7);
-});
-
-
diff --git a/feature-detects/css-calc.js b/feature-detects/css-calc.js
deleted file mode 100644
index bb5b7e9..0000000
--- a/feature-detects/css-calc.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Method of allowing calculated values for length units, i.e. width: calc(100%-3em) http://caniuse.com/#search=calc
-// By @calvein
-
-Modernizr.addTest('csscalc', function() {
-    var prop = 'width:';
-    var value = 'calc(10px);';
-    var el = document.createElement('div');
-
-    el.style.cssText = prop + Modernizr._prefixes.join(value + prop);
-
-    return !!el.style.length;
-});
diff --git a/feature-detects/css-cubicbezierrange.js b/feature-detects/css-cubicbezierrange.js
deleted file mode 100644
index 28e72aa..0000000
--- a/feature-detects/css-cubicbezierrange.js
+++ /dev/null
@@ -1,8 +0,0 @@
-// cubic-bezier values can't be > 1 for Webkit until bug #45761 (https://bugs.webkit.org/show_bug.cgi?id=45761) is fixed
-// By @calvein
-
-Modernizr.addTest('cubicbezierrange', function() {
-    var el = document.createElement('div');
-    el.style.cssText = Modernizr._prefixes.join('transition-timing-function' + ':cubic-bezier(1,0,0,1.1); ');
-    return !!el.style.length;
-});
diff --git a/feature-detects/css-displayrunin.js b/feature-detects/css-displayrunin.js
deleted file mode 100644
index 01eddb7..0000000
--- a/feature-detects/css-displayrunin.js
+++ /dev/null
@@ -1,18 +0,0 @@
-
-// by alanhogan
-
-// https://github.com/Modernizr/Modernizr/issues/198
-// http://css-tricks.com/596-run-in/
-
-
-
-Modernizr.testStyles(' #modernizr { display: run-in; } ', function(elem, rule){ 
-
-  var ret = (window.getComputedStyle ?
-         getComputedStyle(elem, null).getPropertyValue('display') :
-         elem.currentStyle['display']);
-
-  Modernizr.addTest('display-runin', ret == 'run-in');
-
-});
-
diff --git a/feature-detects/css-displaytable.js b/feature-detects/css-displaytable.js
deleted file mode 100644
index bc0a67c..0000000
--- a/feature-detects/css-displaytable.js
+++ /dev/null
@@ -1,27 +0,0 @@
-// display: table and table-cell test. (both are tested under one name "table-cell" )
-// By @scottjehl
-
-// all additional table display values are here: http://pastebin.com/Gk9PeVaQ though Scott has seen some IE false positives with that sort of weak detection.
-// more testing neccessary perhaps.
-
-Modernizr.addTest( "display-table",function(){
-  
-  var doc   = window.document,
-      docElem = doc.documentElement,   
-      parent  = doc.createElement( "div" ),
-      child = doc.createElement( "div" ),
-      childb  = doc.createElement( "div" ),
-      ret;
-  
-  parent.style.cssText = "display: table";
-  child.style.cssText = childb.style.cssText = "display: table-cell; padding: 10px";    
-          
-  parent.appendChild( child );
-  parent.appendChild( childb );
-  docElem.insertBefore( parent, docElem.firstChild );
-  
-  ret = child.offsetLeft < childb.offsetLeft;
-  docElem.removeChild(parent);
-  return ret; 
-});
-
diff --git a/feature-detects/css-filters.js b/feature-detects/css-filters.js
deleted file mode 100644
index aec4fad..0000000
--- a/feature-detects/css-filters.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// https://github.com/Modernizr/Modernizr/issues/615
-// documentMode is needed for false positives in oldIE, please see issue above
-Modernizr.addTest('cssfilters', function() {
-    var el = document.createElement('div');
-    el.style.cssText = Modernizr._prefixes.join('filter' + ':blur(2px); ');
-    return !!el.style.length && ((document.documentMode === undefined || document.documentMode > 9));
-});
\ No newline at end of file
diff --git a/feature-detects/css-hyphens.js b/feature-detects/css-hyphens.js
deleted file mode 100644
index 8215dd5..0000000
--- a/feature-detects/css-hyphens.js
+++ /dev/null
@@ -1,205 +0,0 @@
-/* see http://davidnewton.ca/the-current-state-of-hyphenation-on-the-web
-   http://davidnewton.ca/demos/hyphenation/test.html
-
-
-There are three tests:
-   1. csshyphens      - tests hyphens:auto actually adds hyphens to text
-   2. softhyphens     - tests that &shy; does its job
-   3. softhyphensfind - tests that in-browser Find functionality still works correctly with &shy;
-
-These tests currently require document.body to be present
-
-Hyphenation is language specific, sometimes.
-  See for more details: http://code.google.com/p/hyphenator/source/diff?spec=svn975&r=975&format=side&path=/trunk/Hyphenator.js#sc_svn975_313
-
-If loading Hyphenator.js via Modernizr.load, be cautious of issue 158: http://code.google.com/p/hyphenator/issues/detail?id=158
-
-More details at https://github.com/Modernizr/Modernizr/issues/312
-
-*/
-
-(function() {
-
-	if (!document.body){
-		window.console && console.warn('document.body doesn\'t exist. Modernizr hyphens test needs it.');
-		return;
-	}
-
-	// functional test of adding hyphens:auto
-	function test_hyphens_css() {
-		try {
-			/* create a div container and a span within that
-			 * these have to be appended to document.body, otherwise some browsers can give false negative */
-			var div = document.createElement('div'),
-				span = document.createElement('span'),
-				divStyle = div.style,
-				spanHeight = 0,
-				spanWidth = 0,
-				result = false,
-				firstChild = document.body.firstElementChild || document.body.firstChild;
-
-			div.appendChild(span);
-			span.innerHTML = 'Bacon ipsum dolor sit amet jerky velit in culpa hamburger et. Laborum dolor proident, enim dolore duis commodo et strip steak. Salami anim et, veniam consectetur dolore qui tenderloin jowl velit sirloin. Et ad culpa, fatback cillum jowl ball tip ham hock nulla short ribs pariatur aute. Pig pancetta ham bresaola, ut boudin nostrud commodo flank esse cow tongue culpa. Pork belly bresaola enim pig, ea consectetur nisi. Fugiat officia turkey, ea cow jowl pariatur ullamco proident do laborum velit sausage. Magna biltong sint tri-tip commodo sed bacon, esse proident aliquip. Ullamco ham sint fugiat, velit in enim sed mollit nulla cow ut adipisicing nostrud consectetur. Proident dolore beef ribs, laborum nostrud meatball ea laboris rump cupidatat labore culpa. Shankle minim beef, velit sint cupidatat fugiat tenderloin pig et ball tip. Ut cow fatback salami, bacon ball tip et in shank strip steak bresaola. In ut pork belly sed mollit tri-tip magna culpa veniam, short ribs qui in andouille ham consequat. Dolore bacon t-bone, velit short ribs enim strip steak nulla. Voluptate labore ut, biltong swine irure jerky. Cupidatat excepteur aliquip salami dolore. Ball tip strip steak in pork dolor. Ad in esse biltong. Dolore tenderloin exercitation ad pork loin t-bone, dolore in chicken ball tip qui pig. Ut culpa tongue, sint ribeye dolore ex shank voluptate hamburger. Jowl et tempor, boudin pork chop labore ham hock drumstick consectetur tri-tip elit swine meatball chicken ground round. Proident shankle mollit dolore. Shoulder ut duis t-bone quis reprehenderit. Meatloaf dolore minim strip steak, laboris ea aute bacon beef ribs elit shank in veniam drumstick qui. Ex laboris meatball cow tongue pork belly. Ea ball tip reprehenderit pig, sed fatback boudin dolore flank aliquip laboris eu quis. Beef ribs duis beef, cow corned beef adipisicing commodo nisi deserunt exercitation. Cillum dolor t-bone spare ribs, ham hock est sirloin. Brisket irure meatloaf in, boudin pork belly sirloin ball tip. Sirloin sint irure nisi nostrud aliqua. Nostrud nulla aute, enim officia culpa ham hock. Aliqua reprehenderit dolore sunt nostrud sausage, ea boudin pork loin ut t-bone ham tempor. Tri-tip et pancetta drumstick laborum. Ham hock magna do nostrud in proident. Ex ground round fatback, venison non ribeye in.';
-
-			document.body.insertBefore(div, firstChild);
-
-			/* get size of unhyphenated text */
-			divStyle.cssText = 'position:absolute;top:0;left:0;width:5em;text-align:justify;text-justification:newspaper;';
-			spanHeight = span.offsetHeight;
-			spanWidth = span.offsetWidth;
-
-			/* compare size with hyphenated text */
-			divStyle.cssText = 'position:absolute;top:0;left:0;width:5em;text-align:justify;'+
-												 'text-justification:newspaper;'+
-												 Modernizr._prefixes.join('hyphens:auto; ');
-
-			result = (span.offsetHeight != spanHeight || span.offsetWidth != spanWidth);
-
-			/* results and cleanup */
-			document.body.removeChild(div);
-			div.removeChild(span);
-
-			return result;
-		} catch(e) {
-			return false;
-		}
-	}
-
-	// for the softhyphens test
-	function test_hyphens(delimiter, testWidth) {
-		try {
-			/* create a div container and a span within that
-			 * these have to be appended to document.body, otherwise some browsers can give false negative */
-			var div = document.createElement('div'),
-				span = document.createElement('span'),
-				divStyle = div.style,
-				spanSize = 0,
-				result = false,
-				result1 = false,
-				result2 = false,
-				firstChild = document.body.firstElementChild || document.body.firstChild;
-
-			divStyle.cssText = 'position:absolute;top:0;left:0;overflow:visible;width:1.25em;';
-			div.appendChild(span);
-			document.body.insertBefore(div, firstChild);
-
-
-			/* get height of unwrapped text */
-			span.innerHTML = 'mm';
-			spanSize = span.offsetHeight;
-
-			/* compare height w/ delimiter, to see if it wraps to new line */
-			span.innerHTML = 'm' + delimiter + 'm';
-			result1 = (span.offsetHeight > spanSize);
-
-			/* if we're testing the width too (i.e. for soft-hyphen, not zws),
-			 * this is because tested Blackberry devices will wrap the text but not display the hyphen */
-			if (testWidth) {
-				/* get width of wrapped, non-hyphenated text */
-				span.innerHTML = 'm<br />m';
-				spanSize = span.offsetWidth;
-
-				/* compare width w/ wrapped w/ delimiter to see if hyphen is present */
-				span.innerHTML = 'm' + delimiter + 'm';
-				result2 = (span.offsetWidth > spanSize);
-			} else {
-				result2 = true;
-			}
-
-			/* results and cleanup */
-			if (result1 === true && result2 === true) { result = true; }
-			document.body.removeChild(div);
-			div.removeChild(span);
-
-			return result;
-		} catch(e) {
-			return false;
-		}
-	}
-
-	// testing if in-browser Find functionality will work on hyphenated text
-	function test_hyphens_find(delimiter) {
-		try {
-			/* create a dummy input for resetting selection location, and a div container
-			 * these have to be appended to document.body, otherwise some browsers can give false negative
-			 * div container gets the doubled testword, separated by the delimiter
-			 * Note: giving a width to div gives false positive in iOS Safari */
-			var dummy = document.createElement('input'),
-				div = document.createElement('div'),
-				testword = 'lebowski',
-				result = false,
-				textrange,
-				firstChild = document.body.firstElementChild || document.body.firstChild;
-
-			div.innerHTML = testword + delimiter + testword;
-
-			document.body.insertBefore(div, firstChild);
-			document.body.insertBefore(dummy, div);
-
-
-			/* reset the selection to the dummy input element, i.e. BEFORE the div container
-			 *   stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area */
-			if (dummy.setSelectionRange) {
-				dummy.focus();
-				dummy.setSelectionRange(0,0);
-			} else if (dummy.createTextRange) {
-				textrange = dummy.createTextRange();
-				textrange.collapse(true);
-				textrange.moveEnd('character', 0);
-				textrange.moveStart('character', 0);
-				textrange.select();
-			}
-
-			/* try to find the doubled testword, without the delimiter */
-			if (window.find) {
-				result = window.find(testword + testword);
-			} else {
-				try {
-					textrange = window.self.document.body.createTextRange();
-					result = textrange.findText(testword + testword);
-				} catch(e) {
-					result = false;
-				}
-			}
-
-			document.body.removeChild(div);
-			document.body.removeChild(dummy);
-
-			return result;
-		} catch(e) {
-			return false;
-		}
-	}
-
-	Modernizr.addTest("csshyphens", function() {
-
-		if (!Modernizr.testAllProps('hyphens')) return false;
-
-		/* Chrome lies about its hyphens support so we need a more robust test
-				crbug.com/107111
-		*/
-		try {
-			return test_hyphens_css();
-		} catch(e) {
-			return false;
-		}
-	});
-
-	Modernizr.addTest("softhyphens", function() {
-		try {
-			// use numeric entity instead of &shy; in case it's XHTML
-			return test_hyphens('&#173;', true) && test_hyphens('&#8203;', false);
-		} catch(e) {
-			return false;
-		}
-	});
-
-	Modernizr.addTest("softhyphensfind", function() {
-		try {
-			return test_hyphens_find('&#173;') && test_hyphens_find('&#8203;');
-		} catch(e) {
-			return false;
-		}
-	});
-
-})();
diff --git a/feature-detects/css-lastchild.js b/feature-detects/css-lastchild.js
deleted file mode 100644
index 3e51516..0000000
--- a/feature-detects/css-lastchild.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// last-child pseudo selector
-// https://github.com/Modernizr/Modernizr/pull/304
-
-
-Modernizr.addTest('lastchild', function(){
-
-  return Modernizr.testStyles("#modernizr div {width:100px} #modernizr :last-child{width:200px;display:block}", function (elem) {
-    return elem.lastChild.offsetWidth > elem.firstChild.offsetWidth;
-  }, 2);
-
-});
diff --git a/feature-detects/css-mask.js b/feature-detects/css-mask.js
deleted file mode 100644
index 1afeab4..0000000
--- a/feature-detects/css-mask.js
+++ /dev/null
@@ -1,13 +0,0 @@
-
-// this tests passes for webkit's proprietary `-webkit-mask` feature
-//   www.webkit.org/blog/181/css-masks/
-//   developer.apple.com/library/safari/#documentation/InternetWeb/Conceptual/SafariVisualEffectsProgGuide/Masks/Masks.html
-
-// it does not pass mozilla's implementation of `mask` for SVG
-
-//   developer.mozilla.org/en/CSS/mask
-//   developer.mozilla.org/En/Applying_SVG_effects_to_HTML_content
-
-// Can combine with clippaths for awesomeness: http://generic.cx/for/webkit/test.html
-
-Modernizr.addTest('cssmask', Modernizr.testAllProps('mask-repeat'));
diff --git a/feature-detects/css-mediaqueries.js b/feature-detects/css-mediaqueries.js
deleted file mode 100644
index e0e2c50..0000000
--- a/feature-detects/css-mediaqueries.js
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-Modernizr.addTest('mediaqueries', Modernizr.mq('only all'));
\ No newline at end of file
diff --git a/feature-detects/css-objectfit.js b/feature-detects/css-objectfit.js
deleted file mode 100644
index 3daecde..0000000
--- a/feature-detects/css-objectfit.js
+++ /dev/null
@@ -1,6 +0,0 @@
-
-// dev.opera.com/articles/view/css3-object-fit-object-position/
-
-Modernizr.addTest('object-fit',
-	!!Modernizr.prefixed('objectFit')
-);
\ No newline at end of file
diff --git a/feature-detects/css-overflow-scrolling.js b/feature-detects/css-overflow-scrolling.js
deleted file mode 100644
index 364e71d..0000000
--- a/feature-detects/css-overflow-scrolling.js
+++ /dev/null
@@ -1,9 +0,0 @@
-
-// johanbrook.com/browsers/native-momentum-scrolling-ios-5/
-// introduced in iOS5b2. Possible API may change...
-
-Modernizr.addTest("overflowscrolling",function(){
-    return Modernizr.testAllProps("overflowScrolling");
-});
-
-
diff --git a/feature-detects/css-pointerevents.js b/feature-detects/css-pointerevents.js
deleted file mode 100644
index f18a5c1..0000000
--- a/feature-detects/css-pointerevents.js
+++ /dev/null
@@ -1,25 +0,0 @@
-
-// developer.mozilla.org/en/CSS/pointer-events
-
-// Test and project pages:
-// ausi.github.com/Feature-detection-technique-for-pointer-events/
-// github.com/ausi/Feature-detection-technique-for-pointer-events/wiki
-// github.com/Modernizr/Modernizr/issues/80
-
-
-Modernizr.addTest('pointerevents', function(){
-    var element = document.createElement('x'),
-        documentElement = document.documentElement,
-        getComputedStyle = window.getComputedStyle,
-        supports;
-    if(!('pointerEvents' in element.style)){
-        return false;
-    }
-    element.style.pointerEvents = 'auto';
-    element.style.pointerEvents = 'x';
-    documentElement.appendChild(element);
-    supports = getComputedStyle &&
-        getComputedStyle(element, '').pointerEvents === 'auto';
-    documentElement.removeChild(element);
-    return !!supports;
-});
diff --git a/feature-detects/css-positionsticky.js b/feature-detects/css-positionsticky.js
deleted file mode 100644
index 43a19ec..0000000
--- a/feature-detects/css-positionsticky.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Sticky positioning - constrains an element to be positioned inside the
-// intersection of its container box, and the viewport.
-Modernizr.addTest('csspositionsticky', function () {
-
-    var prop = 'position:';
-    var value = 'sticky';
-    var el = document.createElement('modernizr');
-    var mStyle = el.style;
-
-    mStyle.cssText = prop + Modernizr._prefixes.join(value + ';' + prop).slice(0, -prop.length);
-
-    return mStyle.position.indexOf(value) !== -1;
-});
diff --git a/feature-detects/css-regions.js b/feature-detects/css-regions.js
deleted file mode 100644
index c8995c3..0000000
--- a/feature-detects/css-regions.js
+++ /dev/null
@@ -1,55 +0,0 @@
-// CSS Regions
-// http://www.w3.org/TR/css3-regions/
-// By: Mihai Balan
-
-// We start with a CSS parser test then we check page geometry to see if it's affected by regions
-// Later we might be able to retire the second part, as WebKit builds with the false positives die out
-
-Modernizr.addTest('regions', function() {
-
-	/* Get the 'flowFrom' property name available in the browser. Either default or vendor prefixed.
-	If the property name can't be found we'll get Boolean 'false' and fail quickly */
-	var flowFromProperty = Modernizr.prefixed("flowFrom"),
-		flowIntoProperty = Modernizr.prefixed("flowInto");
-
-	if (!flowFromProperty || !flowIntoProperty){
-		return false;
-	}
-
-	/* If CSS parsing is there, try to determine if regions actually work. */
-	var container		= document.createElement('div'),
-		content			= document.createElement('div'),
-		region			= document.createElement('div'),
-
-	/* we create a random, unlikely to be generated flow number to make sure we don't
-	clash with anything more vanilla, like 'flow', or 'article', or 'f1' */
-	flowName = 'modernizr_flow_for_regions_check';
-
-	/* First create a div with two adjacent divs inside it. The first will be the
-	content, the second will be the region. To be able to distinguish between the two,
-	we'll give the region a particular padding */
-	content.innerText		= 'M';
-	container.style.cssText	= 'top: 150px; left: 150px; padding: 0px;';
-	region.style.cssText	= 'width: 50px; height: 50px; padding: 42px;';
-
-	region.style[flowFromProperty] = flowName;
-	container.appendChild(content);
-	container.appendChild(region);
-	document.documentElement.appendChild(container);
-
-	/* Now compute the bounding client rect, before and after attempting to flow the
-	content div in the region div. If regions are enabled, the after bounding rect
-	should reflect the padding of the region div.*/
-	var flowedRect, delta,
-		plainRect = content.getBoundingClientRect();
-
-
-	content.style[flowIntoProperty] = flowName;
-	flowedRect = content.getBoundingClientRect();
-
-	delta = flowedRect.left - plainRect.left;
-	document.documentElement.removeChild(container);
-	content = region = container = undefined;
-
-	return (delta == 42);
-});
diff --git a/feature-detects/css-remunit.js b/feature-detects/css-remunit.js
deleted file mode 100644
index 38e15b8..0000000
--- a/feature-detects/css-remunit.js
+++ /dev/null
@@ -1,19 +0,0 @@
-
-// test by github.com/nsfmc
-
-// "The 'rem' unit ('root em') is relative to the computed
-// value of the 'font-size' value of the root element."
-// http://www.w3.org/TR/css3-values/#relative0
-// you can test by checking if the prop was ditched
-
-// http://snook.ca/archives/html_and_css/font-size-with-rem
-
-Modernizr.addTest('cssremunit', function(){
-
-  var div = document.createElement('div');
-  try {
-    div.style.fontSize = '3rem';
-  } catch(er){}
-  return (/rem/).test(div.style.fontSize);
-
-});
diff --git a/feature-detects/css-resize.js b/feature-detects/css-resize.js
deleted file mode 100644
index fff99ba..0000000
--- a/feature-detects/css-resize.js
+++ /dev/null
@@ -1,8 +0,0 @@
-
-// Test for CSS 3 UI "resize" property
-// http://www.w3.org/TR/css3-ui/#resize
-// https://developer.mozilla.org/en/CSS/resize
-
-Modernizr.addTest('cssresize', Modernizr.testAllProps('resize'));
-
-
diff --git a/feature-detects/css-scrollbars.js b/feature-detects/css-scrollbars.js
deleted file mode 100644
index f26de9f..0000000
--- a/feature-detects/css-scrollbars.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// Stylable scrollbars detection
-Modernizr.addTest('cssscrollbar', function() {
-
-	var bool,
-
-		styles = "#modernizr{overflow: scroll; width: 40px }#" +
-			Modernizr._prefixes
-				.join("scrollbar{width:0px}"+' #modernizr::')
-				.split('#')
-				.slice(1)
-				.join('#') + "scrollbar{width:0px}";
-
-	Modernizr.testStyles(styles, function(node) {
-		bool = 'scrollWidth' in node && node.scrollWidth == 40;
-	});
-
-	return bool;
-
-});
diff --git a/feature-detects/css-subpixelfont.js b/feature-detects/css-subpixelfont.js
deleted file mode 100644
index 57a11b0..0000000
--- a/feature-detects/css-subpixelfont.js
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Test for SubPixel Font Rendering
- * (to infer if GDI or DirectWrite is used on Windows)
- * Authors: @derSchepp, @gerritvanaaken, @rodneyrehm, @yatil, @ryanseddon
- * Web: https://github.com/gerritvanaaken/subpixeldetect
- */
-Modernizr.addTest('subpixelfont', function() {
-    var bool,
-        styles = "#modernizr{position: absolute; top: -10em; visibility:hidden; font: normal 10px arial;}#subpixel{float: left; font-size: 33.3333%;}";
-    
-    // see https://github.com/Modernizr/Modernizr/blob/master/modernizr.js#L97
-    Modernizr.testStyles(styles, function(elem) {
-        var subpixel = elem.firstChild;
-
-        subpixel.innerHTML = 'This is a text written in Arial';
-
-        bool = window.getComputedStyle ?
-            window.getComputedStyle(subpixel, null).getPropertyValue("width") !== '44px'
-            : false;
-    }, 1, ['subpixel']);
-
-    return bool;
-});
diff --git a/feature-detects/css-supports.js b/feature-detects/css-supports.js
deleted file mode 100644
index 24d26d4..0000000
--- a/feature-detects/css-supports.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// http://dev.w3.org/csswg/css3-conditional/#at-supports
-// github.com/Modernizr/Modernizr/issues/648
-// Relies on the fact that a browser vendor should expose the CSSSupportsRule interface
-// http://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface
-
-Modernizr.addTest("supports","CSSSupportsRule" in window);
\ No newline at end of file
diff --git a/feature-detects/css-userselect.js b/feature-detects/css-userselect.js
deleted file mode 100644
index 062ee90..0000000
--- a/feature-detects/css-userselect.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// -moz-user-select:none test.
-
-// by ryan seddon
-//https://github.com/Modernizr/Modernizr/issues/250
-
-
-Modernizr.addTest("userselect",function(){
-    return Modernizr.testAllProps("user-select");
-});
-
diff --git a/feature-detects/css-vhunit.js b/feature-detects/css-vhunit.js
deleted file mode 100644
index 9de2b64..0000000
--- a/feature-detects/css-vhunit.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// https://github.com/Modernizr/Modernizr/issues/572
-// Similar to http://jsfiddle.net/FWeinb/etnYC/
-Modernizr.addTest('cssvhunit', function() {
-    var bool;
-    Modernizr.testStyles("#modernizr { height: 50vh; }", function(elem, rule) {   
-        var height = parseInt(window.innerHeight/2,10),
-            compStyle = parseInt((window.getComputedStyle ?
-                      getComputedStyle(elem, null) :
-                      elem.currentStyle)["height"],10);
-        
-        bool= (compStyle == height);
-    });
-    return bool;
-});
\ No newline at end of file
diff --git a/feature-detects/css-vmaxunit.js b/feature-detects/css-vmaxunit.js
deleted file mode 100644
index 142346b..0000000
--- a/feature-detects/css-vmaxunit.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// https://github.com/Modernizr/Modernizr/issues/572
-// http://jsfiddle.net/glsee/JDsWQ/4/
-Modernizr.addTest('cssvmaxunit', function(){
-    var bool;
-    Modernizr.testStyles("#modernizr { width: 50vmax; }", function(elem, rule) {
-        var one_vw = window.innerWidth/100,
-            one_vh = window.innerHeight/100,
-            compWidth = parseInt((window.getComputedStyle ?
-                                  getComputedStyle(elem, null) :
-                                  elem.currentStyle)['width'],10);
-        bool = ( parseInt(Math.max(one_vw, one_vh)*50,10) == compWidth );
-    });
-    return bool;
-});
\ No newline at end of file
diff --git a/feature-detects/css-vminunit.js b/feature-detects/css-vminunit.js
deleted file mode 100644
index e6b9881..0000000
--- a/feature-detects/css-vminunit.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// https://github.com/Modernizr/Modernizr/issues/572
-// http://jsfiddle.net/glsee/JRmdq/8/
-Modernizr.addTest('cssvminunit', function(){
-    var bool;
-    Modernizr.testStyles("#modernizr { width: 50vmin; }", function(elem, rule) {
-        var one_vw = window.innerWidth/100,
-            one_vh = window.innerHeight/100,
-            compWidth = parseInt((window.getComputedStyle ?
-                                  getComputedStyle(elem, null) :
-                                  elem.currentStyle)['width'],10);
-        bool = ( parseInt(Math.min(one_vw, one_vh)*50,10) == compWidth );
-    });
-    return bool;
-});
diff --git a/feature-detects/css-vwunit.js b/feature-detects/css-vwunit.js
deleted file mode 100644
index 28f8ca2..0000000
--- a/feature-detects/css-vwunit.js
+++ /dev/null
@@ -1,14 +0,0 @@
-// https://github.com/Modernizr/Modernizr/issues/572
-// http://jsfiddle.net/FWeinb/etnYC/
-Modernizr.addTest('cssvwunit', function(){
-    var bool;
-    Modernizr.testStyles("#modernizr { width: 50vw; }", function(elem, rule) {
-        var width = parseInt(window.innerWidth/2,10),
-            compStyle = parseInt((window.getComputedStyle ?
-                      getComputedStyle(elem, null) :
-                      elem.currentStyle)["width"],10);
-        
-        bool= (compStyle == width);
-    });
-    return bool;
-});
diff --git a/feature-detects/css/all.js b/feature-detects/css/all.js
new file mode 100644
index 0000000..8b0c1a4
--- /dev/null
+++ b/feature-detects/css/all.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "cssall",
+  "property": "cssall",
+  "notes": [{
+    "name": "Spec",
+    "href": "https://drafts.csswg.org/css-cascade/#all-shorthand"
+  }]
+}
+!*/
+/* DOC
+Detects support for the `all` css property, which is a shorthand to reset all css properties (except direction and unicode-bidi) to their original value
+*/
+
+define(['Modernizr', 'docElement'], function(Modernizr, docElement) {
+  Modernizr.addTest('cssall', 'all' in docElement.style);
+});
diff --git a/feature-detects/css/animations.js b/feature-detects/css/animations.js
new file mode 100644
index 0000000..19088f2
--- /dev/null
+++ b/feature-detects/css/animations.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "CSS Animations",
+  "property": "cssanimations",
+  "caniuse": "css-animation",
+  "polyfills": ["transformie", "csssandpaper"],
+  "tags": ["css"],
+  "warnings": ["Android < 4 will pass this test, but can only animate a single property at a time"],
+  "notes": [{
+    "name": "Article: 'Dispelling the Android CSS animation myths'",
+    "href": "https://web.archive.org/web/20180602074607/https://daneden.me/2011/12/14/putting-up-with-androids-bullshit/"
+  }]
+}
+!*/
+/* DOC
+Detects whether or not elements can be animated using CSS
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('cssanimations', testAllProps('animationName', 'a', true));
+});
diff --git a/feature-detects/css/appearance.js b/feature-detects/css/appearance.js
new file mode 100644
index 0000000..33c1c75
--- /dev/null
+++ b/feature-detects/css/appearance.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "Appearance",
+  "property": "appearance",
+  "caniuse": "css-appearance",
+  "tags": ["css"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-appearance"
+  }, {
+    "name": "CSS-Tricks CSS Almanac: appearance",
+    "href": "https://css-tricks.com/almanac/properties/a/appearance/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the `appearance` css property, which is used to make an
+element inherit the style of a standard user interface element. It can also be
+used to remove the default styles of an element, such as input and buttons.
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('appearance', testAllProps('appearance'));
+});
diff --git a/feature-detects/css/aspectratio.js b/feature-detects/css/aspectratio.js
new file mode 100644
index 0000000..5a8a6f1
--- /dev/null
+++ b/feature-detects/css/aspectratio.js
@@ -0,0 +1,36 @@
+/*!
+{
+  "name": "aspectratio css property",
+  "property": "aspectratio",
+  "tags": ["css aspectratio", "aspect-ratio"],
+  "builderAliases": ["aspectratio"],
+  "caniuse":"mdn-css_properties_aspect-ratio",
+  "authors": ["Debadutta Panda"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio"
+  }]
+}
+!*/
+/* DOC
+Detect working status of all aspectratio css property
+https://developer.mozilla.org/en-US/docs/Web/CSS/aspect-ratio
+*/
+define(['Modernizr', 'createElement'], function (Modernizr, createElement) {
+  Modernizr.addTest("aspectratio", function () {
+    if (typeof CSS !== "object" && typeof CSS.supports === "function") {
+      return CSS.supports('aspect-ratio', '1 / 1')
+    } else {
+      var element = createElement('p'),
+            elStyle = element.style
+      if ('aspectRatio' in elStyle) {
+        elStyle.cssText = 'aspect-ratio:1 / 1'
+        element.remove()
+        return (elStyle['aspectRatio'] === '1 / 1');
+      } else {
+        element.remove();
+        return false;
+      }
+    }
+  });
+});
\ No newline at end of file
diff --git a/feature-detects/css/backdropfilter.js b/feature-detects/css/backdropfilter.js
new file mode 100644
index 0000000..52c7831
--- /dev/null
+++ b/feature-detects/css/backdropfilter.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "Backdrop Filter",
+  "property": "backdropfilter",
+  "authors": ["Brian Seward"],
+  "tags": ["css"],
+  "caniuse": "css-backdrop-filter",
+  "notes": [{
+    "name": "W3C Editor’s Draft Spec",
+    "href": "https://drafts.fxtf.org/filters-2/#BackdropFilterProperty"
+  }, {
+    "name": "WebKit Blog introduction + Demo",
+    "href": "https://www.webkit.org/blog/3632/introducing-backdrop-filters/"
+  }]
+}
+!*/
+/* DOC
+Detects support for CSS Backdrop Filters, allowing for background blur effects like those introduced in iOS 7. Support for this was added to iOS Safari/WebKit in iOS 9.
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('backdropfilter', testAllProps('backdropFilter'));
+});
diff --git a/feature-detects/css/backgroundblendmode.js b/feature-detects/css/backgroundblendmode.js
new file mode 100644
index 0000000..6075fb2
--- /dev/null
+++ b/feature-detects/css/backgroundblendmode.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "CSS Background Blend Mode",
+  "property": "backgroundblendmode",
+  "caniuse": "css-backgroundblendmode",
+  "tags": ["css"],
+  "notes": [{
+    "name": "CSS Blend Modes could be the next big thing in Web Design",
+    "href": "https://medium.com/@bennettfeely/css-blend-modes-could-be-the-next-big-thing-in-web-design-6b51bf53743a"
+  }, {
+    "name": "Demo",
+    "href": "https://bennettfeely.com/gradients/"
+  }]
+}
+!*/
+/* DOC
+Detects the ability for the browser to composite backgrounds using blending modes similar to ones found in Photoshop or Illustrator.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('backgroundblendmode', prefixed('backgroundBlendMode', 'text'));
+});
diff --git a/feature-detects/css/backgroundcliptext.js b/feature-detects/css/backgroundcliptext.js
new file mode 100644
index 0000000..adb83b0
--- /dev/null
+++ b/feature-detects/css/backgroundcliptext.js
@@ -0,0 +1,27 @@
+/*!
+{
+  "name": "CSS Background Clip Text",
+  "property": "backgroundcliptext",
+  "authors": ["ausi"],
+  "tags": ["css"],
+  "notes": [{
+    "name": "CSS Tricks Article",
+    "href": "https://css-tricks.com/image-under-text/"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/background-clip"
+  }, {
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/199"
+  }]
+}
+!*/
+/* DOC
+Detects the ability to control specifies whether or not an element's background
+extends beyond its border in CSS
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('backgroundcliptext', function() {
+    return testAllProps('backgroundClip', 'text');
+  });
+});
diff --git a/feature-detects/css/backgroundposition-shorthand.js b/feature-detects/css/backgroundposition-shorthand.js
new file mode 100644
index 0000000..98709d1
--- /dev/null
+++ b/feature-detects/css/backgroundposition-shorthand.js
@@ -0,0 +1,34 @@
+/*!
+{
+  "name": "Background Position Shorthand",
+  "property": "bgpositionshorthand",
+  "caniuse": "css-background-offsets",
+  "tags": ["css"],
+  "builderAliases": ["css_backgroundposition_shorthand"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/CSS/background-position"
+  }, {
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css3-background/#background-position"
+  }, {
+    "name": "Demo",
+    "href": "https://jsfiddle.net/Blink/bBXvt/"
+  }]
+}
+!*/
+/* DOC
+Detects if you can use the shorthand method to define multiple parts of an
+element's background-position simultaneously.
+
+eg `background-position: right 10px bottom 10px`
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('bgpositionshorthand', function() {
+    var elem = createElement('a');
+    var eStyle = elem.style;
+    var val = 'right 10px bottom 10px';
+    eStyle.cssText = 'background-position: ' + val + ';';
+    return (eStyle.backgroundPosition === val);
+  });
+});
diff --git a/feature-detects/css/backgroundposition-xy.js b/feature-detects/css/backgroundposition-xy.js
new file mode 100644
index 0000000..02de261
--- /dev/null
+++ b/feature-detects/css/backgroundposition-xy.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "Background Position XY",
+  "property": "bgpositionxy",
+  "tags": ["css"],
+  "builderAliases": ["css_backgroundposition_xy"],
+  "authors": ["Allan Lei", "Brandom Aaron"],
+  "notes": [{
+    "name": "Demo",
+    "href": "https://jsfiddle.net/allanlei/R8AYS/"
+  }, {
+    "name": "Adapted From",
+    "href": "https://github.com/brandonaaron/jquery-cssHooks/blob/master/bgpos.js"
+  }]
+}
+!*/
+/* DOC
+Detects the ability to control an element's background position using css
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('bgpositionxy', function() {
+    return testAllProps('backgroundPositionX', '3px', true) && testAllProps('backgroundPositionY', '5px', true);
+  });
+});
diff --git a/feature-detects/css/backgroundrepeat.js b/feature-detects/css/backgroundrepeat.js
new file mode 100644
index 0000000..2665393
--- /dev/null
+++ b/feature-detects/css/backgroundrepeat.js
@@ -0,0 +1,27 @@
+/*!
+{
+  "name": "Background Repeat",
+  "property": ["bgrepeatspace", "bgrepeatround"],
+  "tags": ["css"],
+  "builderAliases": ["css_backgroundrepeat"],
+  "authors": ["Ryan Seddon"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/background-repeat"
+  }, {
+    "name": "Test Page",
+    "href": "https://jsbin.com/uzesun/"
+  }, {
+    "name": "Demo",
+    "href": "https://jsfiddle.net/ryanseddon/yMLTQ/6/"
+  }]
+}
+!*/
+/* DOC
+Detects the ability to use round and space as properties for background-repeat
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  // Must value-test these
+  Modernizr.addTest('bgrepeatround', testAllProps('backgroundRepeat', 'round'));
+  Modernizr.addTest('bgrepeatspace', testAllProps('backgroundRepeat', 'space'));
+});
diff --git a/feature-detects/css/backgroundsize.js b/feature-detects/css/backgroundsize.js
new file mode 100644
index 0000000..d18baf0
--- /dev/null
+++ b/feature-detects/css/backgroundsize.js
@@ -0,0 +1,15 @@
+/*!
+{
+  "name": "Background Size",
+  "property": "backgroundsize",
+  "tags": ["css"],
+  "knownBugs": ["This will false positive in Opera Mini - https://github.com/Modernizr/Modernizr/issues/396"],
+  "notes": [{
+    "name": "Related Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/396"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('backgroundsize', testAllProps('backgroundSize', '100%', true));
+});
diff --git a/feature-detects/css/backgroundsizecover.js b/feature-detects/css/backgroundsizecover.js
new file mode 100644
index 0000000..ac8f677
--- /dev/null
+++ b/feature-detects/css/backgroundsizecover.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "Background Size Cover",
+  "property": "bgsizecover",
+  "tags": ["css"],
+  "builderAliases": ["css_backgroundsizecover"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/CSS/background-size"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  // Must test value, as this specifically tests the `cover` value
+  Modernizr.addTest('bgsizecover', testAllProps('backgroundSize', 'cover'));
+});
diff --git a/feature-detects/css/borderimage.js b/feature-detects/css/borderimage.js
new file mode 100644
index 0000000..c68f380
--- /dev/null
+++ b/feature-detects/css/borderimage.js
@@ -0,0 +1,13 @@
+/*!
+{
+  "name": "Border Image",
+  "property": "borderimage",
+  "caniuse": "border-image",
+  "polyfills": ["css3pie"],
+  "knownBugs": ["Android < 2.0 is true, but has a broken implementation"],
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('borderimage', testAllProps('borderImage', 'url() 1', true));
+});
diff --git a/feature-detects/css/borderradius.js b/feature-detects/css/borderradius.js
new file mode 100644
index 0000000..281f19f
--- /dev/null
+++ b/feature-detects/css/borderradius.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "Border Radius",
+  "property": "borderradius",
+  "caniuse": "border-radius",
+  "polyfills": ["css3pie"],
+  "tags": ["css"],
+  "notes": [{
+    "name": "Comprehensive Compat Chart",
+    "href": "https://muddledramblings.com/table-of-css3-border-radius-compliance"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('borderradius', testAllProps('borderRadius', '0px', true));
+});
diff --git a/feature-detects/css/boxdecorationbreak.js b/feature-detects/css/boxdecorationbreak.js
new file mode 100644
index 0000000..e1dc8f0
--- /dev/null
+++ b/feature-detects/css/boxdecorationbreak.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "Box Decoration Break",
+  "property": "boxdecorationbreak",
+  "caniuse": "css-boxdecorationbreak",
+  "tags": ["css"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/box-decoration-break"
+  }, {
+    "name": "Demo",
+    "href": "https://jsbin.com/xojoro/edit?css,output"
+  }]
+}
+!*/
+/* DOC
+Specifies how an element's fragments should be rendered when broken across multiple lines, columns, or pages.
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('boxdecorationbreak', testAllProps('boxDecorationBreak', 'slice'));
+});
diff --git a/feature-detects/css/boxshadow.js b/feature-detects/css/boxshadow.js
new file mode 100644
index 0000000..d342ea2
--- /dev/null
+++ b/feature-detects/css/boxshadow.js
@@ -0,0 +1,15 @@
+/*!
+{
+  "name": "Box Shadow",
+  "property": "boxshadow",
+  "caniuse": "css-boxshadow",
+  "tags": ["css"],
+  "knownBugs": [
+    "WebOS false positives on this test.",
+    "The Kindle Silk browser false positives"
+  ]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('boxshadow', testAllProps('boxShadow', '1px 1px', true));
+});
diff --git a/feature-detects/css/boxsizing.js b/feature-detects/css/boxsizing.js
new file mode 100644
index 0000000..7d92893
--- /dev/null
+++ b/feature-detects/css/boxsizing.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "Box Sizing",
+  "property": "boxsizing",
+  "caniuse": "css3-boxsizing",
+  "polyfills": ["borderboxmodel", "boxsizingpolyfill", "borderbox"],
+  "tags": ["css"],
+  "builderAliases": ["css_boxsizing"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/box-sizing"
+  }, {
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/248"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('boxsizing', testAllProps('boxSizing', 'border-box', true) && (document.documentMode === undefined || document.documentMode > 7));
+});
diff --git a/feature-detects/css/calc.js b/feature-detects/css/calc.js
new file mode 100644
index 0000000..2cf2d10
--- /dev/null
+++ b/feature-detects/css/calc.js
@@ -0,0 +1,30 @@
+/*!
+{
+  "name": "CSS Calc",
+  "property": "csscalc",
+  "caniuse": "calc",
+  "tags": ["css"],
+  "builderAliases": ["css_calc"],
+  "authors": ["@calvein"]
+}
+!*/
+/* DOC
+Method of allowing calculated values for length units. For example:
+
+```css
+//lem {
+  width: calc(100% - 3em);
+}
+```
+*/
+define(['Modernizr', 'createElement', 'prefixes'], function(Modernizr, createElement, prefixes) {
+  Modernizr.addTest('csscalc', function() {
+    var prop = 'width:';
+    var value = 'calc(10px);';
+    var el = createElement('a');
+
+    el.style.cssText = prop + prefixes.join(value + prop);
+
+    return !!el.style.length;
+  });
+});
diff --git a/feature-detects/css/checked.js b/feature-detects/css/checked.js
new file mode 100644
index 0000000..4541364
--- /dev/null
+++ b/feature-detects/css/checked.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "CSS :checked pseudo-selector",
+  "caniuse": "css-sel3",
+  "property": "checked",
+  "tags": ["css"],
+  "notes": [{
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/pull/879"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement', 'testStyles'], function(Modernizr, createElement, testStyles) {
+  Modernizr.addTest('checked', function() {
+    return testStyles('#modernizr {position:absolute} #modernizr input {margin-left:10px} #modernizr :checked {margin-left:20px;display:block}', function(elem) {
+      var cb = createElement('input');
+      cb.setAttribute('type', 'checkbox');
+      cb.setAttribute('checked', 'checked');
+      elem.appendChild(cb);
+      return cb.offsetLeft === 20;
+    });
+  });
+});
diff --git a/feature-detects/css/chunit.js b/feature-detects/css/chunit.js
new file mode 100644
index 0000000..b562315
--- /dev/null
+++ b/feature-detects/css/chunit.js
@@ -0,0 +1,26 @@
+/*!
+{
+  "name": "CSS Font ch Units",
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "property": "csschunit",
+  "caniuse": "ch-unit",
+  "tags": ["css"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css3-values/#font-relative-lengths"
+  }]
+}
+!*/
+define(['Modernizr', 'modElem'], function(Modernizr, modElem) {
+  Modernizr.addTest('csschunit', function() {
+    var elemStyle = modElem.elem.style;
+    var supports;
+    try {
+      elemStyle.fontSize = '3ch';
+      supports = elemStyle.fontSize.indexOf('ch') !== -1;
+    } catch (e) {
+      supports = false;
+    }
+    return supports;
+  });
+});
diff --git a/feature-detects/css/columns.js b/feature-detects/css/columns.js
new file mode 100644
index 0000000..ca73fdb
--- /dev/null
+++ b/feature-detects/css/columns.js
@@ -0,0 +1,41 @@
+/*!
+{
+  "name": "CSS Columns",
+  "property": "csscolumns",
+  "caniuse": "multicolumn",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+
+  (function() {
+
+    Modernizr.addTest('csscolumns', function() {
+      var bool = false;
+      var test = testAllProps('columnCount');
+      try {
+        bool = !!test;
+        if (bool) {
+          bool = new Boolean(bool);
+        }
+      } catch (e) {}
+
+      return bool;
+    });
+
+    var props = ['Width', 'Span', 'Fill', 'Gap', 'Rule', 'RuleColor', 'RuleStyle', 'RuleWidth', 'BreakBefore', 'BreakAfter', 'BreakInside'];
+    var name, test;
+
+    for (var i = 0; i < props.length; i++) {
+      name = props[i].toLowerCase();
+      test = testAllProps('column' + props[i]);
+
+      // break-before, break-after & break-inside are not "column"-prefixed in spec
+      if (name === 'breakbefore' || name === 'breakafter' || name === 'breakinside') {
+        test = test || testAllProps(props[i]);
+      }
+
+      Modernizr.addTest('csscolumns.' + name, test);
+    }
+  })();
+});
diff --git a/feature-detects/css/cssgrid.js b/feature-detects/css/cssgrid.js
new file mode 100644
index 0000000..28a7ffa
--- /dev/null
+++ b/feature-detects/css/cssgrid.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "CSS Grid (old & new)",
+  "property": ["cssgrid", "cssgridlegacy"],
+  "authors": ["Faruk Ates"],
+  "tags": ["css"],
+  "notes": [{
+    "name": "The new, standardized CSS Grid",
+    "href": "https://www.w3.org/TR/css3-grid-layout/"
+  }, {
+    "name": "The _old_ CSS Grid (legacy)",
+    "href": "https://www.w3.org/TR/2011/WD-css3-grid-layout-20110407/"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  // `grid-columns` is only in the old syntax, `grid-column` exists in both and so `grid-template-rows` is used for the new syntax.
+  Modernizr.addTest('cssgridlegacy', testAllProps('grid-columns', '10px', true));
+  Modernizr.addTest('cssgrid', testAllProps('grid-template-rows', 'none', true));
+});
diff --git a/feature-detects/css/cubicbezierrange.js b/feature-detects/css/cubicbezierrange.js
new file mode 100644
index 0000000..8f94508
--- /dev/null
+++ b/feature-detects/css/cubicbezierrange.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "CSS Cubic Bezier Range",
+  "property": "cubicbezierrange",
+  "tags": ["css"],
+  "builderAliases": ["css_cubicbezierrange"],
+  "authors": ["@calvein"],
+  "warnings": ["In old versions (pre-2013) cubic-bezier values can't be > 1 due to Webkit [bug #45761](https://bugs.webkit.org/show_bug.cgi?id=45761)"],
+  "notes": [{
+    "name": "Comprehensive Compat Chart",
+    "href": "https://muddledramblings.com/table-of-css3-border-radius-compliance/"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement', 'prefixes'], function(Modernizr, createElement, prefixes) {
+  Modernizr.addTest('cubicbezierrange', function() {
+    var el = createElement('a');
+    el.style.cssText = prefixes.join('transition-timing-function:cubic-bezier(1,0,0,1.1); ');
+    return !!el.style.length;
+  });
+});
diff --git a/feature-detects/css/customproperties.js b/feature-detects/css/customproperties.js
new file mode 100644
index 0000000..78e035f
--- /dev/null
+++ b/feature-detects/css/customproperties.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "CSS Custom Properties",
+  "property": "customproperties",
+  "caniuse": "css-variables",
+  "tags": ["css"],
+  "builderAliases": ["css_customproperties"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/--*"
+  }, {
+    "name": "W3C Spec",
+    "href": "https://drafts.csswg.org/css-variables/"
+  }]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  var supportsFn = (window.CSS && window.CSS.supports.bind(window.CSS)) || (window.supportsCSS);
+  Modernizr.addTest('customproperties', !!supportsFn && (supportsFn('--f:0') || supportsFn('--f', 0)));
+});
diff --git a/feature-detects/css/displayrunin.js b/feature-detects/css/displayrunin.js
new file mode 100644
index 0000000..d07fa01
--- /dev/null
+++ b/feature-detects/css/displayrunin.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "CSS Display run-in",
+  "property": "display-runin",
+  "authors": ["alanhogan"],
+  "tags": ["css"],
+  "builderAliases": ["css_displayrunin"],
+  "notes": [{
+    "name": "CSS Tricks Article",
+    "href": "https://web.archive.org/web/20111204150927/http://css-tricks.com:80/596-run-in/"
+  }, {
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/198"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('displayrunin', testAllProps('display', 'run-in'),
+    {aliases: ['display-runin']});
+});
diff --git a/feature-detects/css/displaytable.js b/feature-detects/css/displaytable.js
new file mode 100644
index 0000000..c991432
--- /dev/null
+++ b/feature-detects/css/displaytable.js
@@ -0,0 +1,27 @@
+/*!
+{
+  "name": "CSS Display table",
+  "property": "displaytable",
+  "caniuse": "css-table",
+  "authors": ["scottjehl"],
+  "tags": ["css"],
+  "builderAliases": ["css_displaytable"],
+  "notes": [{
+    "name": "Detects for all additional table display values",
+    "href": "https://pastebin.com/Gk9PeVaQ"
+  }]
+}
+!*/
+/* DOC
+`display: table` and `table-cell` test. (both are tested under one name `table-cell` )
+*/
+define(['Modernizr', 'testStyles'], function(Modernizr, testStyles) {
+  // If a document is in rtl mode this test will fail so we force ltr mode on the injected
+  // element https://github.com/Modernizr/Modernizr/issues/716
+  testStyles('#modernizr{display: table; direction: ltr}#modernizr div{display: table-cell; padding: 10px}', function(elem) {
+    var ret;
+    var child = elem.childNodes;
+    ret = child[0].offsetLeft < child[1].offsetLeft;
+    Modernizr.addTest('displaytable', ret, {aliases: ['display-table']});
+  }, 2);
+});
diff --git a/feature-detects/css/ellipsis.js b/feature-detects/css/ellipsis.js
new file mode 100644
index 0000000..cf120e7
--- /dev/null
+++ b/feature-detects/css/ellipsis.js
@@ -0,0 +1,11 @@
+/*!
+{
+  "name": "CSS text-overflow ellipsis",
+  "property": "ellipsis",
+  "caniuse": "text-overflow",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('ellipsis', testAllProps('textOverflow', 'ellipsis'));
+});
diff --git a/feature-detects/css/escape.js b/feature-detects/css/escape.js
new file mode 100644
index 0000000..b3a26f6
--- /dev/null
+++ b/feature-detects/css/escape.js
@@ -0,0 +1,15 @@
+/*!
+{
+  "name": "CSS.escape()",
+  "property": "cssescape",
+  "polyfills": ["css-escape"],
+  "tags": ["css", "cssom"]
+}
+!*/
+/* DOC
+Tests for `CSS.escape()` support.
+*/
+define(['Modernizr'], function(Modernizr) {
+  var CSS = window.CSS;
+  Modernizr.addTest('cssescape', CSS ? typeof CSS.escape === 'function' : false);
+});
diff --git a/feature-detects/css/exunit.js b/feature-detects/css/exunit.js
new file mode 100644
index 0000000..38a51f3
--- /dev/null
+++ b/feature-detects/css/exunit.js
@@ -0,0 +1,26 @@
+/*!
+{
+  "name": "CSS Font ex Units",
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "property": "cssexunit",
+  "caniuse": "mdn-css_types_length_ex",
+  "tags": ["css"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css3-values/#font-relative-lengths"
+  }]
+}
+!*/
+define(['Modernizr', 'modElem'], function(Modernizr, modElem) {
+  Modernizr.addTest('cssexunit', function() {
+    var elemStyle = modElem.elem.style;
+    var supports;
+    try {
+      elemStyle.fontSize = '3ex';
+      supports = elemStyle.fontSize.indexOf('ex') !== -1;
+    } catch (e) {
+      supports = false;
+    }
+    return supports;
+  });
+});
diff --git a/feature-detects/css/filters.js b/feature-detects/css/filters.js
new file mode 100644
index 0000000..481e040
--- /dev/null
+++ b/feature-detects/css/filters.js
@@ -0,0 +1,28 @@
+/*!
+{
+  "name": "CSS Filters",
+  "property": "cssfilters",
+  "caniuse": "css-filters",
+  "polyfills": ["polyfilter"],
+  "tags": ["css"],
+  "builderAliases": ["css_filters"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/filter"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement', 'prefixes', 'testAllProps', 'test/css/supports'], function(Modernizr, createElement, prefixes, testAllProps) {
+  Modernizr.addTest('cssfilters', function() {
+    if (Modernizr.supports) {
+      return testAllProps('filter', 'blur(2px)');
+    } else {
+      var el = createElement('a');
+      el.style.cssText = prefixes.join('filter:blur(2px); ');
+      // https://github.com/Modernizr/Modernizr/issues/615
+      // documentMode is needed for false positives in oldIE, please see issue above
+      return !!el.style.length && ((document.documentMode === undefined || document.documentMode > 9));
+    }
+  });
+
+});
diff --git a/feature-detects/css/flexbox.js b/feature-detects/css/flexbox.js
new file mode 100644
index 0000000..4dc36fa
--- /dev/null
+++ b/feature-detects/css/flexbox.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "Flexbox",
+  "property": "flexbox",
+  "caniuse": "flexbox",
+  "tags": ["css"],
+  "notes": [{
+    "name": "The _new_ flexbox",
+    "href": "https://www.w3.org/TR/css-flexbox-1/"
+  }],
+  "warnings": [
+    "A `true` result for this detect does not imply that the `flex-wrap` property is supported; see the `flexwrap` detect."
+  ]
+}
+!*/
+/* DOC
+Detects support for the Flexible Box Layout model, a.k.a. Flexbox, which allows easy manipulation of layout order and sizing within a container.
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('flexbox', testAllProps('flexBasis', '1px', true));
+});
diff --git a/feature-detects/css/flexboxlegacy.js b/feature-detects/css/flexboxlegacy.js
new file mode 100644
index 0000000..4adfa8d
--- /dev/null
+++ b/feature-detects/css/flexboxlegacy.js
@@ -0,0 +1,15 @@
+/*!
+{
+  "name": "Flexbox (legacy)",
+  "property": "flexboxlegacy",
+  "tags": ["css"],
+  "polyfills": ["flexie"],
+  "notes": [{
+    "name": "The _old_ flexbox",
+    "href": "https://www.w3.org/TR/2009/WD-css3-flexbox-20090723/"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('flexboxlegacy', testAllProps('boxDirection', 'reverse', true));
+});
diff --git a/feature-detects/css/flexboxtweener.js b/feature-detects/css/flexboxtweener.js
new file mode 100644
index 0000000..e683adb
--- /dev/null
+++ b/feature-detects/css/flexboxtweener.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "Flexbox (tweener)",
+  "property": "flexboxtweener",
+  "tags": ["css"],
+  "polyfills": ["flexie"],
+  "notes": [{
+    "name": "The _inbetween_ flexbox",
+    "href": "https://www.w3.org/TR/2011/WD-css3-flexbox-20111129/"
+  }],
+  "warnings": ["This represents an old syntax, not the latest standard syntax."]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('flexboxtweener', testAllProps('flexAlign', 'end', true));
+});
diff --git a/feature-detects/css/flexgap.js b/feature-detects/css/flexgap.js
new file mode 100644
index 0000000..ebb87bb
--- /dev/null
+++ b/feature-detects/css/flexgap.js
@@ -0,0 +1,33 @@
+/*!
+{
+  "name": "Flex Gap",
+  "property": "flexgap",
+  "caniuse": "flexbox-gap",
+  "tags": ["css", "flexbox"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css-align-3/#gaps"
+  }],
+  "authors": ["Chris Smith (@chris13524)"]
+}
+!*/
+define(['Modernizr', 'createElement', 'docElement'], function(Modernizr, createElement, docElement) {
+  Modernizr.addTest('flexgap', function() {
+    // create flex container with row-gap set
+    var flex = createElement('div');
+    flex.style.display = 'flex';
+    flex.style.flexDirection = 'column';
+    flex.style.rowGap = '1px';
+
+    // create two elements inside it
+    flex.appendChild(createElement('div'));
+    flex.appendChild(createElement('div'));
+
+    // append to the DOM (needed to obtain scrollHeight)
+    docElement.appendChild(flex);
+    var isSupported = flex.scrollHeight === 1; // flex container should be 1px high from the row-gap
+    flex.parentNode.removeChild(flex);
+
+    return isSupported;
+  });
+});
diff --git a/feature-detects/css/flexwrap.js b/feature-detects/css/flexwrap.js
new file mode 100644
index 0000000..2b30fd9
--- /dev/null
+++ b/feature-detects/css/flexwrap.js
@@ -0,0 +1,31 @@
+/*!
+{
+  "name": "Flex Line Wrapping",
+  "property": "flexwrap",
+  "tags": ["css", "flexbox"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css-flexbox-1/"
+  }],
+  "warnings": [
+    "Does not imply a modern implementation – see documentation."
+  ]
+}
+!*/
+/* DOC
+Detects support for the `flex-wrap` CSS property, part of Flexbox, which isn’t present in all Flexbox implementations (notably Firefox).
+
+This featured in both the 'tweener' syntax (implemented by IE10) and the 'modern' syntax (implemented by others). This detect will return `true` for either of these implementations, as long as the `flex-wrap` property is supported. So to ensure the modern syntax is supported, use together with `Modernizr.flexbox`:
+
+```javascript
+if (Modernizr.flexbox && Modernizr.flexwrap) {
+  // Modern Flexbox with `flex-wrap` supported
+}
+else {
+  // Either old Flexbox syntax, or `flex-wrap` not supported
+}
+```
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('flexwrap', testAllProps('flexWrap', 'wrap', true));
+});
diff --git a/feature-detects/css/focusvisible.js b/feature-detects/css/focusvisible.js
new file mode 100644
index 0000000..a7b50c3
--- /dev/null
+++ b/feature-detects/css/focusvisible.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "CSS :focus-visible pseudo-selector",
+  "caniuse": "css-focus-visible",
+  "property": "focusvisible",  
+  "authors": ["@esaborit4code"],
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('focusvisible', function() {
+    try {
+      document.querySelector(':focus-visible');
+    } catch (error) {
+      return false;
+    }
+    return true;
+  });
+});
diff --git a/feature-detects/css/focuswithin.js b/feature-detects/css/focuswithin.js
new file mode 100644
index 0000000..2677297
--- /dev/null
+++ b/feature-detects/css/focuswithin.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "CSS :focus-within pseudo-selector",
+  "caniuse": "css-focus-within",
+  "property": "focuswithin",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('focuswithin', function() {
+    try {
+      document.querySelector(':focus-within');
+    } catch (error) {
+      return false;
+    }
+    return true;
+  });
+});
diff --git a/feature-detects/css/fontdisplay.js b/feature-detects/css/fontdisplay.js
new file mode 100644
index 0000000..01e1188
--- /dev/null
+++ b/feature-detects/css/fontdisplay.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "Font Display",
+  "property": "fontdisplay",
+  "authors": ["Patrick Kettner"],
+  "caniuse": "css-font-rendering-controls",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://drafts.csswg.org/css-fonts-4/#font-display-desc"
+  }, {
+    "name": "`font-display` for the masses",
+    "href": "https://css-tricks.com/font-display-masses/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the `font-display` descriptor, which defines how font files are loaded and displayed by the browser.
+*/
+define(['Modernizr', 'testProp'], function(Modernizr, testProp) {
+  Modernizr.addTest('fontDisplay', testProp('font-display'));
+});
diff --git a/feature-detects/css/fontface.js b/feature-detects/css/fontface.js
new file mode 100644
index 0000000..9e1eeda
--- /dev/null
+++ b/feature-detects/css/fontface.js
@@ -0,0 +1,47 @@
+/*!
+{
+  "name": "@font-face",
+  "property": "fontface",
+  "authors": ["Diego Perini", "Mat Marquis"],
+  "tags": ["css"],
+  "knownBugs": [
+    "False Positive: WebOS https://github.com/Modernizr/Modernizr/issues/342",
+    "False Positive: WP7 https://github.com/Modernizr/Modernizr/issues/538"
+  ],
+  "notes": [{
+    "name": "@font-face detection routine by Diego Perini",
+    "href": "http://javascript.nwbox.com/CSSSupport/"
+  }, {
+    "name": "Filament Group @font-face compatibility research",
+    "href": "https://docs.google.com/presentation/d/1n4NyG4uPRjAA8zn_pSQ_Ket0RhcWC6QlZ6LMjKeECo0/edit#slide=id.p"
+  }, {
+    "name": "Filament Grunticon/@font-face device testing results",
+    "href": "https://docs.google.com/spreadsheet/ccc?key=0Ag5_yGvxpINRdHFYeUJPNnZMWUZKR2ItMEpRTXZPdUE#gid=0"
+  }, {
+    "name": "CSS fonts on Android",
+    "href": "https://stackoverflow.com/questions/3200069/css-fonts-on-android"
+  }, {
+    "name": "@font-face and Android",
+    "href": "http://archivist.incutio.com/viewlist/css-discuss/115960"
+  }]
+}
+!*/
+define(['Modernizr', 'testStyles'], function(Modernizr, testStyles) {
+  var unsupportedUserAgent = (function() {
+    var ua = navigator.userAgent;
+    var webos = ua.match(/w(eb)?osbrowser/gi);
+    var wppre8 = ua.match(/windows phone/gi) && ua.match(/iemobile\/([0-9])+/gi) && parseFloat(RegExp.$1) >= 9;
+    return webos || wppre8;
+  }());
+  if (unsupportedUserAgent) {
+    Modernizr.addTest('fontface', false);
+  } else {
+    testStyles('@font-face {font-family:"font";src:url("https://")}', function(node, rule) {
+      var style = document.getElementById('smodernizr');
+      var sheet = style.sheet || style.styleSheet;
+      var cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
+      var bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
+      Modernizr.addTest('fontface', bool);
+    });
+  }
+});
diff --git a/feature-detects/css/generatedcontent.js b/feature-detects/css/generatedcontent.js
new file mode 100644
index 0000000..4ed0912
--- /dev/null
+++ b/feature-detects/css/generatedcontent.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "CSS Generated Content",
+  "property": "generatedcontent",
+  "tags": ["css"],
+  "warnings": ["Android may not return correct height for anything below 7px in old versions #738"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css3-selectors/#gen-content"
+  }, {
+    "name": "MDN Docs on :before",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::before"
+  }, {
+    "name": "MDN Docs on :after",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/::after"
+  }]
+}
+!*/
+define(['Modernizr', 'testStyles'], function(Modernizr, testStyles) {
+  testStyles('#modernizr{font:0/0 a}#modernizr:after{content:":)";visibility:hidden;font:7px/1 a}', function(node) {
+    // See bug report on why this value is 6 crbug.com/608142
+    Modernizr.addTest('generatedcontent', node.offsetHeight >= 6);
+  });
+});
diff --git a/feature-detects/css/gradients.js b/feature-detects/css/gradients.js
new file mode 100644
index 0000000..dc9869d
--- /dev/null
+++ b/feature-detects/css/gradients.js
@@ -0,0 +1,46 @@
+/*!
+{
+  "name": "CSS Gradients",
+  "caniuse": "css-gradients",
+  "property": "cssgradients",
+  "tags": ["css"],
+  "knownBugs": ["False-positives on webOS (https://github.com/Modernizr/Modernizr/issues/202)"],
+  "notes": [{
+    "name": "Webkit Gradient Syntax",
+    "href": "https://webkit.org/blog/175/introducing-css-gradients/"
+  }, {
+    "name": "Linear Gradient Syntax",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/linear-gradient"
+  }, {
+    "name": "W3C Spec",
+    "href": "https://drafts.csswg.org/css-images-3/#gradients"
+  }]
+}
+!*/
+define(['Modernizr', 'prefixes', 'createElement'], function(Modernizr, prefixes, createElement) {
+
+  Modernizr.addTest('cssgradients', function() {
+
+    var str1 = 'background-image:';
+    var str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));';
+    var css = '';
+    var angle;
+
+    for (var i = 0, len = prefixes.length - 1; i < len; i++) {
+      angle = (i === 0 ? 'to ' : '');
+      css += str1 + prefixes[i] + 'linear-gradient(' + angle + 'left top, #9f9, white);';
+    }
+
+    if (Modernizr._config.usePrefixes) {
+    // legacy webkit syntax (TODO:: remove when syntax not in use anymore)
+      css += str1 + '-webkit-' + str2;
+    }
+
+    var elem = createElement('a');
+    var style = elem.style;
+    style.cssText = css;
+
+    // IE6 returns undefined so cast to string
+    return ('' + style.backgroundImage).indexOf('gradient') > -1;
+  });
+});
diff --git a/feature-detects/css/hairline.js b/feature-detects/css/hairline.js
new file mode 100644
index 0000000..9b0c300
--- /dev/null
+++ b/feature-detects/css/hairline.js
@@ -0,0 +1,24 @@
+/*! {
+  "name": "CSS Hairline",
+  "property": "hairline",
+  "tags": ["css"],
+  "authors": ["strarsis"],
+  "notes": [{
+    "name": "Blog post about CSS retina hairlines",
+    "href": "http://dieulot.net/css-retina-hairline"
+  }, {
+    "name": "Derived from",
+    "href": "https://gist.github.com/dieulot/520a49463f6058fbc8d1"
+  }]
+}
+!*/
+/* DOC
+Detects support for hidpi/retina hairlines, which are CSS borders with less than 1px in width, for being physically 1px on hidpi screens.
+*/
+define(['Modernizr', 'testStyles'], function(Modernizr, testStyles) {
+  Modernizr.addTest('hairline', function() {
+    return testStyles('#modernizr {border:.5px solid transparent}', function(elem) {
+      return elem.offsetHeight === 1;
+    });
+  });
+});
diff --git a/feature-detects/css/hsla.js b/feature-detects/css/hsla.js
new file mode 100644
index 0000000..75cf0b7
--- /dev/null
+++ b/feature-detects/css/hsla.js
@@ -0,0 +1,15 @@
+/*!
+{
+  "name": "CSS HSLA Colors",
+  "caniuse": "css3-colors",
+  "property": "hsla",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'createElement', 'contains'], function(Modernizr, createElement, contains) {
+  Modernizr.addTest('hsla', function() {
+    var style = createElement('a').style;
+    style.cssText = 'background-color:hsla(120,40%,100%,.5)';
+    return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
+  });
+});
diff --git a/feature-detects/css/hyphens.js b/feature-detects/css/hyphens.js
new file mode 100644
index 0000000..4f8289f
--- /dev/null
+++ b/feature-detects/css/hyphens.js
@@ -0,0 +1,228 @@
+/*!
+{
+  "name": "CSS Hyphens",
+  "caniuse": "css-hyphens",
+  "property": ["csshyphens", "softhyphens", "softhyphensfind"],
+  "tags": ["css"],
+  "builderAliases": ["css_hyphens"],
+  "async": true,
+  "authors": ["David Newton"],
+  "warnings": [
+    "These tests currently require document.body to be present",
+    "If loading Hyphenator.js via yepnope, be cautious of issue 158: https://github.com/mnater/hyphenator/issues/158",
+    "This is very large – only include it if you absolutely need it"
+  ],
+  "notes": [{
+    "name": "The Current State of Hyphenation on the Web.",
+    "href": "https://davidnewton.ca/the-current-state-of-hyphenation-on-the-web"
+  }, {
+    "name": "Hyphenation Test Page",
+    "href": "https://web.archive.org/web/20150319125549/http://davidnewton.ca/demos/hyphenation/test.html"
+  }, {
+    "name": "Hyphenation is Language Specific",
+    "href": "https://code.google.com/p/hyphenator/source/diff?spec=svn975&r=975&format=side&path=/trunk/Hyphenator.js#sc_svn975_313"
+  }, {
+    "name": "Related Modernizr Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/312"
+  }]
+}
+!*/
+define(['Modernizr', 'prefixes', 'createElement', 'testAllProps', 'addTest'], function(Modernizr, prefixes, createElement, testAllProps, addTest) {
+
+  Modernizr.addAsyncTest(function() {
+    var waitTime = 300;
+    setTimeout(runHyphenTest, waitTime);
+    // Wait 1000ms so we can hope for document.body
+    function runHyphenTest() {
+      if (!document.body && !document.getElementsByTagName('body')[0]) {
+        setTimeout(runHyphenTest, waitTime);
+        return;
+      }
+
+      // functional test of adding hyphens:auto
+      function test_hyphens_css() {
+        try {
+          /* create a div container and a span within that
+           * these have to be appended to document.body, otherwise some browsers can give false negative */
+          var div = createElement('div');
+          var span = createElement('span');
+          var divStyle = div.style;
+          var spanHeight = 0;
+          var spanWidth = 0;
+          var result = false;
+          var firstChild = document.body.firstElementChild || document.body.firstChild;
+
+          /* Hyphenation is only applied when language is explicitly set and when respective dictionary
+           * is available. See https://developer.mozilla.org/en-US/docs/Web/CSS/hyphens for details. */
+          div.lang = 'en';
+          div.appendChild(span);
+          span.innerHTML = 'Bacon ipsum dolor sit amet jerky velit in culpa hamburger et. Laborum dolor proident, enim dolore duis commodo et strip steak. Salami anim et, veniam consectetur dolore qui tenderloin jowl velit sirloin. Et ad culpa, fatback cillum jowl ball tip ham hock nulla short ribs pariatur aute. Pig pancetta ham bresaola, ut boudin nostrud commodo flank esse cow tongue culpa. Pork belly bresaola enim pig, ea consectetur nisi. Fugiat officia turkey, ea cow jowl pariatur ullamco proident do laborum velit sausage. Magna biltong sint tri-tip commodo sed bacon, esse proident aliquip. Ullamco ham sint fugiat, velit in enim sed mollit nulla cow ut adipisicing nostrud consectetur. Proident dolore beef ribs, laborum nostrud meatball ea laboris rump cupidatat labore culpa. Shankle minim beef, velit sint cupidatat fugiat tenderloin pig et ball tip. Ut cow fatback salami, bacon ball tip et in shank strip steak bresaola. In ut pork belly sed mollit tri-tip magna culpa veniam, short ribs qui in andouille ham consequat. Dolore bacon t-bone, velit short ribs enim strip steak nulla. Voluptate labore ut, biltong swine irure jerky. Cupidatat excepteur aliquip salami dolore. Ball tip strip steak in pork dolor. Ad in esse biltong. Dolore tenderloin exercitation ad pork loin t-bone, dolore in chicken ball tip qui pig. Ut culpa tongue, sint ribeye dolore ex shank voluptate hamburger. Jowl et tempor, boudin pork chop labore ham hock drumstick consectetur tri-tip elit swine meatball chicken ground round. Proident shankle mollit dolore. Shoulder ut duis t-bone quis reprehenderit. Meatloaf dolore minim strip steak, laboris ea aute bacon beef ribs elit shank in veniam drumstick qui. Ex laboris meatball cow tongue pork belly. Ea ball tip reprehenderit pig, sed fatback boudin dolore flank aliquip laboris eu quis. Beef ribs duis beef, cow corned beef adipisicing commodo nisi deserunt exercitation. Cillum dolor t-bone spare ribs, ham hock est sirloin. Brisket irure meatloaf in, boudin pork belly sirloin ball tip. Sirloin sint irure nisi nostrud aliqua. Nostrud nulla aute, enim officia culpa ham hock. Aliqua reprehenderit dolore sunt nostrud sausage, ea boudin pork loin ut t-bone ham tempor. Tri-tip et pancetta drumstick laborum. Ham hock magna do nostrud in proident. Ex ground round fatback, venison non ribeye in.';
+
+          document.body.insertBefore(div, firstChild);
+
+          /* get size of unhyphenated text */
+          divStyle.cssText = 'position:absolute;top:0;left:0;width:5em;text-align:justify;text-justify:newspaper;';
+          spanHeight = span.offsetHeight;
+          spanWidth = span.offsetWidth;
+
+          /* compare size with hyphenated text */
+          divStyle.cssText = 'position:absolute;top:0;left:0;width:5em;text-align:justify;text-justify:newspaper;' +
+            prefixes.join('hyphens:auto; ');
+
+          /* results */
+          result = (span.offsetHeight !== spanHeight || span.offsetWidth !== spanWidth);
+
+          /* cleanup */
+          document.body.removeChild(div);
+          div.removeChild(span);
+
+          return result;
+        } catch (e) {
+          return false;
+        }
+      }
+
+      // for the softhyphens test
+      function test_hyphens(delimiter, testWidth) {
+        try {
+          /* create a div container and a span within that
+           * these have to be appended to document.body, otherwise some browsers can give false negative */
+          var div = createElement('div');
+          var span = createElement('span');
+          var divStyle = div.style;
+          var spanSize = 0;
+          var result = false;
+          var result1 = false;
+          var result2 = false;
+          var firstChild = document.body.firstElementChild || document.body.firstChild;
+
+          divStyle.cssText = 'position:absolute;top:0;left:0;overflow:visible;width:1.25em;';
+          div.appendChild(span);
+          document.body.insertBefore(div, firstChild);
+
+          /* get height of unwrapped text */
+          span.innerHTML = 'mm';
+          spanSize = span.offsetHeight;
+
+          /* compare height w/ delimiter, to see if it wraps to new line */
+          span.innerHTML = 'm' + delimiter + 'm';
+          result1 = (span.offsetHeight > spanSize);
+
+          /* if we're testing the width too (i.e. for soft-hyphen, not zws),
+           * this is because tested Blackberry devices will wrap the text but not display the hyphen */
+          if (testWidth) {
+            /* get width of wrapped, non-hyphenated text */
+            span.innerHTML = 'm<br />m';
+            spanSize = span.offsetWidth;
+
+            /* compare width w/ wrapped w/ delimiter to see if hyphen is present */
+            span.innerHTML = 'm' + delimiter + 'm';
+            result2 = (span.offsetWidth > spanSize);
+          } else {
+            result2 = true;
+          }
+
+          /* results and cleanup */
+          if (result1 === true && result2 === true) { result = true; }
+          document.body.removeChild(div);
+          div.removeChild(span);
+
+          return result;
+        } catch (e) {
+          return false;
+        }
+      }
+
+      // testing if in-browser Find functionality will work on hyphenated text
+      function test_hyphens_find(delimiter) {
+        try {
+          /* create a sample input for resetting selection location, and a div container
+           * these have to be appended to document.body, otherwise some browsers can give false negative
+           * div container gets the doubled testword, separated by the delimiter
+           * Note: giving a width to div gives false positive in iOS Safari */
+          var sampleInput = createElement('input');
+          var div = createElement('div');
+          var testword = 'lebowski';
+          var result = false;
+          var textrange;
+          var firstChild = document.body.firstElementChild || document.body.firstChild;
+
+          /* Make the elements fixed to prevent that the browser's viewport will jump to the top  */
+          sampleInput.style.cssText = 'position:fixed;top:0;';
+          div.style.cssText = 'position:fixed;top:0;';
+
+          div.innerHTML = testword + delimiter + testword;
+
+          document.body.insertBefore(div, firstChild);
+          document.body.insertBefore(sampleInput, div);
+
+          /* reset the selection to the sample input element, i.e. BEFORE the div container
+           *   stackoverflow.com/questions/499126/jquery-set-cursor-position-in-text-area */
+          if (sampleInput.setSelectionRange) {
+            sampleInput.focus();
+            sampleInput.setSelectionRange(0, 0);
+          } else if (sampleInput.createTextRange) {
+            textrange = sampleInput.createTextRange();
+            textrange.collapse(true);
+            textrange.moveEnd('character', 0);
+            textrange.moveStart('character', 0);
+            textrange.select();
+          }
+
+          /* try to find the doubled testword, without the delimiter */
+          try {
+            if (window.find) {
+              result = window.find(testword + testword);
+            } else {
+              textrange = window.self.document.body.createTextRange();
+              result = textrange.findText(testword + testword);
+            }
+          } catch (e) {
+            result = false;
+          }
+
+          document.body.removeChild(div);
+          document.body.removeChild(sampleInput);
+
+          return result;
+        } catch (e) {
+          return false;
+        }
+      }
+
+      addTest('csshyphens', function() {
+
+        if (!testAllProps('hyphens', 'auto', true)) {
+          return false;
+        }
+
+        /* Chrome lies about its hyphens support so we need a more robust test
+           crbug.com/107111
+           */
+        try {
+          return test_hyphens_css();
+        } catch (e) {
+          return false;
+        }
+      });
+
+      addTest('softhyphens', function() {
+        try {
+          // use numeric entity instead of &shy; in case it's XHTML
+          return test_hyphens('&#173;', true) && test_hyphens('&#8203;', false);
+        } catch (e) {
+          return false;
+        }
+      });
+
+      addTest('softhyphensfind', function() {
+        try {
+          return test_hyphens_find('&#173;') && test_hyphens_find('&#8203;');
+        } catch (e) {
+          return false;
+        }
+      });
+
+    }
+  });
+});
diff --git a/feature-detects/css/invalid.js b/feature-detects/css/invalid.js
new file mode 100644
index 0000000..87bc0d3
--- /dev/null
+++ b/feature-detects/css/invalid.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "CSS :invalid pseudo-class",
+  "property": "cssinvalid",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/:invalid"
+  }]
+}
+!*/
+/* DOC
+  Detects support for the ':invalid' CSS pseudo-class.
+*/
+define(['Modernizr', 'testStyles', 'createElement'], function(Modernizr, testStyles, createElement) {
+  Modernizr.addTest('cssinvalid', function() {
+    return testStyles('#modernizr input{height:0;border:0;padding:0;margin:0;width:10px} #modernizr input:invalid{width:50px}', function(elem) {
+      var input = createElement('input');
+      input.required = true;
+      elem.appendChild(input);
+      return input.clientWidth > 10;
+    });
+  });
+});
diff --git a/feature-detects/css/lastchild.js b/feature-detects/css/lastchild.js
new file mode 100644
index 0000000..2d4f449
--- /dev/null
+++ b/feature-detects/css/lastchild.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "CSS :last-child pseudo-selector",
+  "caniuse": "css-sel3",
+  "property": "lastchild",
+  "tags": ["css"],
+  "builderAliases": ["css_lastchild"],
+  "notes": [{
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/pull/304"
+  }]
+}
+!*/
+define(['Modernizr', 'testStyles'], function(Modernizr, testStyles) {
+  testStyles('#modernizr div {width:100px} #modernizr :last-child{width:200px;display:block}', function(elem) {
+    Modernizr.addTest('lastchild', elem.lastChild.offsetWidth > elem.firstChild.offsetWidth);
+  }, 2);
+});
diff --git a/feature-detects/css/mask.js b/feature-detects/css/mask.js
new file mode 100644
index 0000000..f7a38ad
--- /dev/null
+++ b/feature-detects/css/mask.js
@@ -0,0 +1,25 @@
+/*!
+{
+  "name": "CSS Mask",
+  "caniuse": "css-masks",
+  "property": "cssmask",
+  "tags": ["css"],
+  "builderAliases": ["css_mask"],
+  "notes": [{
+    "name": "Webkit blog on CSS Masks",
+    "href": "https://webkit.org/blog/181/css-masks/"
+  }, {
+    "name": "Safari Docs",
+    "href": "https://developer.apple.com/library/archive/documentation/InternetWeb/Conceptual/SafariVisualEffectsProgGuide/Masks/Masks.html"
+  }, {
+    "name": "CSS SVG mask",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/mask"
+  }, {
+    "name": "Combine with clippaths for awesomeness",
+    "href": "https://web.archive.org/web/20150508193041/http://generic.cx:80/for/webkit/test.html"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('cssmask', testAllProps('maskRepeat', 'repeat-x', true));
+});
diff --git a/feature-detects/css/mediaqueries.js b/feature-detects/css/mediaqueries.js
new file mode 100644
index 0000000..7ddd823
--- /dev/null
+++ b/feature-detects/css/mediaqueries.js
@@ -0,0 +1,12 @@
+/*!
+{
+  "name": "CSS Media Queries",
+  "caniuse": "css-mediaqueries",
+  "property": "mediaqueries",
+  "tags": ["css"],
+  "builderAliases": ["css_mediaqueries"]
+}
+!*/
+define(['Modernizr', 'mq'], function(Modernizr, mq) {
+  Modernizr.addTest('mediaqueries', mq('only all'));
+});
diff --git a/feature-detects/css/multiplebgs.js b/feature-detects/css/multiplebgs.js
new file mode 100644
index 0000000..0f756df
--- /dev/null
+++ b/feature-detects/css/multiplebgs.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "CSS Multiple Backgrounds",
+  "caniuse": "multibackgrounds",
+  "property": "multiplebgs",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  // Setting multiple images AND a color on the background shorthand property
+  // and then querying the style.background property value for the number of
+  // occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
+
+  Modernizr.addTest('multiplebgs', function() {
+    var style = createElement('a').style;
+    style.cssText = 'background:url(https://),url(https://),red url(https://)';
+
+    // If the UA supports multiple backgrounds, there should be three occurrences
+    // of the string "url(" in the return value for elemStyle.background
+    return (/(url\s*\(.*?){3}/).test(style.background);
+  });
+});
diff --git a/feature-detects/css/nthchild.js b/feature-detects/css/nthchild.js
new file mode 100644
index 0000000..1e2cc81
--- /dev/null
+++ b/feature-detects/css/nthchild.js
@@ -0,0 +1,34 @@
+/*!
+{
+  "name": "CSS :nth-child pseudo-selector",
+  "caniuse": "css-sel3",
+  "property": "nthchild",
+  "tags": ["css"],
+  "notes": [{
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/pull/685"
+  }, {
+    "name": "Sitepoint :nth-child documentation",
+    "href": "https://www.sitepoint.com/atoz-css-screencast-nth-child/"
+  }],
+  "authors": ["@emilchristensen"],
+  "knownBugs": ["Known false negative in Safari 3.1 and Safari 3.2.2"]
+}
+!*/
+/* DOC
+Detects support for the ':nth-child()' CSS pseudo-selector.
+*/
+define(['Modernizr', 'testStyles'], function(Modernizr, testStyles) {
+  // 4 `<div>` elements with `1px` width are created. Then every other element has its `width` set to `2px`.
+  // Then we check if the width of the even elements is different then the width of the odd elements
+  // while the two even elements have the same width (and the two odd elements too).
+  // Earlier versions of the tests tried to check for the actual width which didnt work on chrome when the
+  // browser was zoomed in our out in specific ways.
+  testStyles('#modernizr div {width:1px} #modernizr div:nth-child(2n) {width:2px;}', function(elem) {
+    var elems = elem.getElementsByTagName('div');
+    var correctWidths = elems[0].offsetWidth === elems[2].offsetWidth &&
+      elems[1].offsetWidth === elems[3].offsetWidth &&
+      elems[0].offsetWidth !== elems[1].offsetWidth;
+    Modernizr.addTest('nthchild', correctWidths);
+  }, 4);
+});
diff --git a/feature-detects/css/objectfit.js b/feature-detects/css/objectfit.js
new file mode 100644
index 0000000..3f2aae9
--- /dev/null
+++ b/feature-detects/css/objectfit.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "CSS Object Fit",
+  "caniuse": "object-fit",
+  "property": "objectfit",
+  "tags": ["css"],
+  "builderAliases": ["css_objectfit"],
+  "notes": [{
+    "name": "Opera Article on Object Fit",
+    "href": "https://dev.opera.com/articles/css3-object-fit-object-position/"
+  }]
+}
+!*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('objectfit', !!prefixed('objectFit'), {aliases: ['object-fit']});
+});
diff --git a/feature-detects/css/opacity.js b/feature-detects/css/opacity.js
new file mode 100644
index 0000000..3aa97c0
--- /dev/null
+++ b/feature-detects/css/opacity.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "CSS Opacity",
+  "caniuse": "css-opacity",
+  "property": "opacity",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'createElement', 'prefixes'], function(Modernizr, createElement, prefixes) {
+  // Browsers that actually have CSS Opacity implemented have done so
+  // according to spec, which means their return values are within the
+  // range of [0.0,1.0] - including the leading zero.
+
+  Modernizr.addTest('opacity', function() {
+    var style = createElement('a').style;
+    style.cssText = prefixes.join('opacity:.55;');
+
+    // The non-literal . in this regex is intentional:
+    // German Chrome returns this value as 0,55
+    // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
+    return (/^0.55$/).test(style.opacity);
+  });
+});
diff --git a/feature-detects/css/overflow-scrolling.js b/feature-detects/css/overflow-scrolling.js
new file mode 100644
index 0000000..5e3668d
--- /dev/null
+++ b/feature-detects/css/overflow-scrolling.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "CSS Overflow Scrolling",
+  "property": "overflowscrolling",
+  "tags": ["css"],
+  "builderAliases": ["css_overflow_scrolling"],
+  "notes": [{
+    "name": "Article on iOS overflow scrolling",
+    "href": "https://css-tricks.com/snippets/css/momentum-scrolling-on-ios-overflow-elements/"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-overflow-scrolling"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('overflowscrolling', testAllProps('overflowScrolling', 'touch', true));
+});
diff --git a/feature-detects/css/pointerevents.js b/feature-detects/css/pointerevents.js
new file mode 100644
index 0000000..43f49c5
--- /dev/null
+++ b/feature-detects/css/pointerevents.js
@@ -0,0 +1,30 @@
+/*!
+{
+  "name": "CSS Pointer Events",
+  "caniuse": "pointer-events",
+  "property": "csspointerevents",
+  "authors": ["ausi"],
+  "tags": ["css"],
+  "builderAliases": ["css_pointerevents"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/pointer-events"
+  }, {
+    "name": "Test Project Page",
+    "href": "https://ausi.github.com/Feature-detection-technique-for-pointer-events/"
+  }, {
+    "name": "Test Project Wiki",
+    "href": "https://github.com/ausi/Feature-detection-technique-for-pointer-events/wiki"
+  }, {
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/80"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('csspointerevents', function() {
+    var style = createElement('a').style;
+    style.cssText = 'pointer-events:auto';
+    return style.pointerEvents === 'auto';
+  });
+});
diff --git a/feature-detects/css/positionsticky.js b/feature-detects/css/positionsticky.js
new file mode 100644
index 0000000..5e67c0e
--- /dev/null
+++ b/feature-detects/css/positionsticky.js
@@ -0,0 +1,27 @@
+/*!
+{
+  "name": "CSS position: sticky",
+  "property": "csspositionsticky",
+  "tags": ["css"],
+  "builderAliases": ["css_positionsticky"],
+  "notes": [{
+    "name": "Chrome bug report",
+    "href": "https://bugs.chromium.org/p/chromium/issues/detail?id=322972"
+  }],
+  "warnings": ["using position:sticky on anything but top aligned elements is buggy in Chrome < 37 and iOS <=7+"]
+}
+!*/
+define(['Modernizr', 'createElement', 'prefixes'], function(Modernizr, createElement, prefixes) {
+  // Sticky positioning - constrains an element to be positioned inside the
+  // intersection of its container box, and the viewport.
+  Modernizr.addTest('csspositionsticky', function() {
+    var prop = 'position:';
+    var value = 'sticky';
+    var el = createElement('a');
+    var mStyle = el.style;
+
+    mStyle.cssText = prop + prefixes.join(value + ';' + prop).slice(0, -prop.length);
+
+    return mStyle.position.indexOf(value) !== -1;
+  });
+});
diff --git a/feature-detects/css/pseudoanimations.js b/feature-detects/css/pseudoanimations.js
new file mode 100644
index 0000000..43de4f8
--- /dev/null
+++ b/feature-detects/css/pseudoanimations.js
@@ -0,0 +1,29 @@
+/*!
+{
+  "name": "CSS Generated Content Animations",
+  "property": "csspseudoanimations",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'testStyles', 'prefixes', 'test/css/animations', 'computedStyle'], function(Modernizr, testStyles, prefixes, computedStyle) {
+  Modernizr.addTest('csspseudoanimations', function() {
+    var result = false;
+
+    if (!Modernizr.cssanimations) {
+      return result;
+    }
+
+    var styles = [
+      '@', prefixes.join('keyframes csspseudoanimations { from { font-size: 10px; } }@').replace(/\@$/, ''),
+      '#modernizr:before { content:" "; font-size:5px;',
+      prefixes.join('animation:csspseudoanimations 1ms infinite;'),
+      '}'
+    ].join('');
+
+    testStyles(styles, function(elem) {
+      result = computedStyle(elem, ':before', 'font-size') === '10px';
+    });
+
+    return result;
+  });
+});
diff --git a/feature-detects/css/pseudotransitions.js b/feature-detects/css/pseudotransitions.js
new file mode 100644
index 0000000..6f17a17
--- /dev/null
+++ b/feature-detects/css/pseudotransitions.js
@@ -0,0 +1,29 @@
+/*!
+{
+  "name": "CSS Generated Content Transitions",
+  "property": "csspseudotransitions",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'testStyles', 'prefixes', 'test/css/transitions', 'computedStyle'], function(Modernizr, testStyles, prefixes, computedStyle) {
+  Modernizr.addTest('csspseudotransitions', function() {
+    var result = false;
+
+    if (!Modernizr.csstransitions) {
+      return result;
+    }
+
+    var styles =
+      '#modernizr:before { content:" "; font-size:5px;' + prefixes.join('transition:0s 100s;') + '}' +
+      '#modernizr.trigger:before { font-size:10px; }';
+
+    testStyles(styles, function(elem) {
+      // Force rendering of the element's styles so that the transition will trigger
+      computedStyle(elem, ':before', 'font-size');
+      elem.className += 'trigger';
+      result = computedStyle(elem, ':before', 'font-size') === '5px';
+    });
+
+    return result;
+  });
+});
diff --git a/feature-detects/css/reflections.js b/feature-detects/css/reflections.js
new file mode 100644
index 0000000..fb947a3
--- /dev/null
+++ b/feature-detects/css/reflections.js
@@ -0,0 +1,11 @@
+/*!
+{
+  "name": "CSS Reflections",
+  "caniuse": "css-reflections",
+  "property": "cssreflections",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('cssreflections', testAllProps('boxReflect', 'above', true));
+});
diff --git a/feature-detects/css/regions.js b/feature-detects/css/regions.js
new file mode 100644
index 0000000..1546618
--- /dev/null
+++ b/feature-detects/css/regions.js
@@ -0,0 +1,93 @@
+/*!
+{
+  "name": "CSS Regions",
+  "caniuse": "css-regions",
+  "authors": ["Mihai Balan"],
+  "property": "regions",
+  "tags": ["css"],
+  "builderAliases": ["css_regions"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css3-regions/"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement', 'docElement', 'isSVG', 'prefixed'], function(Modernizr, createElement, docElement, isSVG, prefixed) {
+  // We start with a CSS parser test then we check page geometry to see if it's affected by regions
+  // Later we might be able to retire the second part, as WebKit builds with the false positives die out
+
+  Modernizr.addTest('regions', function() {
+
+    if (isSVG) {
+      // css regions don't work inside of SVG elements. Rather than update the
+      // below test to work in an SVG context, just exit early to save bytes
+      return false;
+    }
+
+    /* Get the 'flowFrom' property name available in the browser. Either default or vendor prefixed.
+       If the property name can't be found we'll get Boolean 'false' and fail quickly */
+    var flowFromProperty = prefixed('flowFrom');
+    var flowIntoProperty = prefixed('flowInto');
+    var result = false;
+
+    if (!flowFromProperty || !flowIntoProperty) {
+      return result;
+    }
+
+    /* If CSS parsing is there, try to determine if regions actually work. */
+    var iframeContainer = createElement('iframe');
+    var container = createElement('div');
+    var content = createElement('div');
+    var region = createElement('div');
+
+    /* we create a random, unlikely to be generated flow number to make sure we don't
+       clash with anything more vanilla, like 'flow', or 'article', or 'f1' */
+    var flowName = 'modernizr_flow_for_regions_check';
+
+    /* First create a div with two adjacent divs inside it. The first will be the
+       content, the second will be the region. To be able to distinguish between the two,
+       we'll give the region a particular padding */
+    content.innerText = 'M';
+    container.style.cssText = 'top: 150px; left: 150px; padding: 0px;';
+    region.style.cssText = 'width: 50px; height: 50px; padding: 42px;';
+
+    region.style[flowFromProperty] = flowName;
+    container.appendChild(content);
+    container.appendChild(region);
+    docElement.appendChild(container);
+
+    /* Now compute the bounding client rect, before and after attempting to flow the
+       content div in the region div. If regions are enabled, the after bounding rect
+       should reflect the padding of the region div.*/
+    var flowedRect, delta;
+    var plainRect = content.getBoundingClientRect();
+
+    content.style[flowIntoProperty] = flowName;
+    flowedRect = content.getBoundingClientRect();
+
+    delta = parseInt(flowedRect.left - plainRect.left, 10);
+    docElement.removeChild(container);
+
+    if (delta === 42) {
+      result = true;
+    } else {
+      /* IE only allows for the content to come from iframes. This has the
+       * side effect of automatic collapsing of iframes once they get the flow-into
+       * property set. checking for a change on the height allows us to detect this
+       * in a sync way, without having to wait for a frame to load */
+
+      docElement.appendChild(iframeContainer);
+      plainRect = iframeContainer.getBoundingClientRect();
+      iframeContainer.style[flowIntoProperty] = flowName;
+      flowedRect = iframeContainer.getBoundingClientRect();
+
+      if (plainRect.height > 0 && plainRect.height !== flowedRect.height && flowedRect.height === 0) {
+        result = true;
+      }
+    }
+
+    content = region = container = iframeContainer = undefined;
+
+    return result;
+  });
+});
diff --git a/feature-detects/css/remunit.js b/feature-detects/css/remunit.js
new file mode 100644
index 0000000..c0e3e32
--- /dev/null
+++ b/feature-detects/css/remunit.js
@@ -0,0 +1,31 @@
+/*!
+{
+  "name": "CSS Font rem Units",
+  "caniuse": "rem",
+  "authors": ["nsfmc"],
+  "property": "cssremunit",
+  "tags": ["css"],
+  "builderAliases": ["css_remunit"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css3-values/#relative0"
+  }, {
+    "name": "Font Size with rem by Jonathan Snook",
+    "href": "https://snook.ca/archives/html_and_css/font-size-with-rem"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  // "The 'rem' unit ('root em') is relative to the computed
+  // value of the 'font-size' value of the root element."
+  // you can test by checking if the prop was ditched
+
+  Modernizr.addTest('cssremunit', function() {
+    var style = createElement('a').style;
+    try {
+      style.fontSize = '3rem';
+    }
+    catch (e) {}
+    return (/rem/).test(style.fontSize);
+  });
+});
diff --git a/feature-detects/css/resize.js b/feature-detects/css/resize.js
new file mode 100644
index 0000000..50f6f84
--- /dev/null
+++ b/feature-detects/css/resize.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "CSS UI Resize",
+  "property": "cssresize",
+  "caniuse": "css-resize",
+  "tags": ["css"],
+  "builderAliases": ["css_resize"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css3-ui/#resize"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/CSS/resize"
+  }]
+}
+!*/
+/* DOC
+Test for CSS 3 UI "resize" property
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('cssresize', testAllProps('resize', 'both', true));
+});
diff --git a/feature-detects/css/rgba.js b/feature-detects/css/rgba.js
new file mode 100644
index 0000000..a468979
--- /dev/null
+++ b/feature-detects/css/rgba.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "CSS rgba",
+  "caniuse": "css3-colors",
+  "property": "rgba",
+  "tags": ["css"],
+  "notes": [{
+    "name": "CSSTricks Tutorial",
+    "href": "https://css-tricks.com/rgba-browser-support/"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('rgba', function() {
+    var style = createElement('a').style;
+    style.cssText = 'background-color:rgba(150,255,150,.5)';
+
+    return ('' + style.backgroundColor).indexOf('rgba') > -1;
+  });
+});
diff --git a/feature-detects/css/scrollbars.js b/feature-detects/css/scrollbars.js
new file mode 100644
index 0000000..be78b70
--- /dev/null
+++ b/feature-detects/css/scrollbars.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "CSS Stylable Scrollbars",
+  "property": "cssscrollbar",
+  "tags": ["css"],
+  "builderAliases": ["css_scrollbars"]
+}
+!*/
+define(['Modernizr', 'testStyles', 'prefixes'], function(Modernizr, testStyles, prefixes) {
+  testStyles('#modernizr{overflow: scroll; width: 40px; height: 40px; }#' + prefixes
+    .join('scrollbar{width:10px}' + ' #modernizr::')
+    .split('#')
+    .slice(1)
+    .join('#') + 'scrollbar{width:10px}',
+  function(node) {
+    Modernizr.addTest('cssscrollbar', 'scrollWidth' in node && node.scrollWidth === 30);
+  });
+});
diff --git a/feature-detects/css/scrollsnappoints.js b/feature-detects/css/scrollsnappoints.js
new file mode 100644
index 0000000..b43d8f8
--- /dev/null
+++ b/feature-detects/css/scrollsnappoints.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "Scroll Snap Points",
+  "property": "scrollsnappoints",
+  "caniuse": "css-snappoints",
+  "notes": [{
+    "name": "Setting native-like scrolling offsets in CSS with Scrolling Snap Points",
+    "href": "http://generatedcontent.org/post/66817675443/setting-native-like-scrolling-offsets-in-css-with"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Scroll_Snap_Points"
+  }],
+  "polyfills": ["scrollsnap"]
+}
+!*/
+/* DOC
+Detects support for CSS Snap Points
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('scrollsnappoints', testAllProps('scrollSnapType'));
+});
diff --git a/feature-detects/css/shapes.js b/feature-detects/css/shapes.js
new file mode 100644
index 0000000..e728d61
--- /dev/null
+++ b/feature-detects/css/shapes.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "CSS Shapes",
+  "property": "shapes",
+  "tags": ["css"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css-shapes"
+  }, {
+    "name": "Examples from Adobe",
+    "href": "https://web.archive.org/web/20171230010236/http://webplatform.adobe.com:80/shapes"
+  }, {
+    "name": "Examples from CSS-Tricks",
+    "href": "https://css-tricks.com/examples/ShapesOfCSS/"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('shapes', testAllProps('shapeOutside', 'content-box', true));
+});
diff --git a/feature-detects/css/siblinggeneral.js b/feature-detects/css/siblinggeneral.js
new file mode 100644
index 0000000..074b09d
--- /dev/null
+++ b/feature-detects/css/siblinggeneral.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "CSS general sibling selector",
+  "caniuse": "css-sel3",
+  "property": "siblinggeneral",
+  "tags": ["css"],
+  "notes": [{
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/pull/889"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement', 'testStyles'], function(Modernizr, createElement, testStyles) {
+  Modernizr.addTest('siblinggeneral', function() {
+    return testStyles('#modernizr div {width:100px} #modernizr div ~ div {width:200px;display:block}', function(elem) {
+      return elem.lastChild.offsetWidth === 200;
+    }, 2);
+  });
+});
diff --git a/feature-detects/css/subpixelfont.js b/feature-detects/css/subpixelfont.js
new file mode 100644
index 0000000..7aaec40
--- /dev/null
+++ b/feature-detects/css/subpixelfont.js
@@ -0,0 +1,25 @@
+/*!
+{
+  "name": "CSS Subpixel Fonts",
+  "property": "subpixelfont",
+  "tags": ["css"],
+  "builderAliases": ["css_subpixelfont"],
+  "authors": ["@derSchepp", "@gerritvanaaken", "@rodneyrehm", "@yatil", "@ryanseddon"],
+  "notes": [{
+    "name": "Origin Test",
+    "href": "https://github.com/gerritvanaaken/subpixeldetect"
+  }]
+}
+!*/
+define(['Modernizr', 'testStyles', 'computedStyle'], function(Modernizr, testStyles, computedStyle) {
+  /*
+   * (to infer if GDI or DirectWrite is used on Windows)
+   */
+  testStyles(
+    '#modernizr{position: absolute; top: -10em; visibility:hidden; font: normal 10px arial;}#subpixel{float: left; font-size: 33.3333%;}',
+    function(elem) {
+      var subpixel = elem.firstChild;
+      subpixel.innerHTML = 'This is a text written in Arial';
+      Modernizr.addTest('subpixelfont', computedStyle(subpixel, null, 'width') !== '44px');
+    }, 1, ['subpixel']);
+});
diff --git a/feature-detects/css/supports.js b/feature-detects/css/supports.js
new file mode 100644
index 0000000..a8b8620
--- /dev/null
+++ b/feature-detects/css/supports.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "CSS Supports",
+  "property": "supports",
+  "caniuse": "css-featurequeries",
+  "tags": ["css"],
+  "builderAliases": ["css_supports"],
+  "notes": [{
+    "name": "W3C Spec (The @supports rule)",
+    "href": "https://dev.w3.org/csswg/css3-conditional/#at-supports"
+  }, {
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/648"
+  }, {
+    "name": "W3C Spec (The CSSSupportsRule interface)",
+    "href": "https://dev.w3.org/csswg/css3-conditional/#the-csssupportsrule-interface"
+  }]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  var newSyntax = 'CSS' in window && 'supports' in window.CSS;
+  var oldSyntax = 'supportsCSS' in window;
+  Modernizr.addTest('supports', newSyntax || oldSyntax);
+});
diff --git a/feature-detects/css/target.js b/feature-detects/css/target.js
new file mode 100644
index 0000000..c7a100f
--- /dev/null
+++ b/feature-detects/css/target.js
@@ -0,0 +1,33 @@
+/*!
+{
+  "name": "CSS :target pseudo-class",
+  "caniuse": "css-sel3",
+  "property": "target",
+  "tags": ["css"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/:target"
+  }],
+  "authors": ["@zachleat"],
+  "warnings": ["Opera Mini supports :target but doesn't update the hash for anchor links."]
+}
+!*/
+/* DOC
+Detects support for the ':target' CSS pseudo-class.
+*/
+define(['Modernizr'], function(Modernizr) {
+  // querySelector
+  Modernizr.addTest('target', function() {
+    var doc = window.document;
+    if (!('querySelectorAll' in doc)) {
+      return false;
+    }
+
+    try {
+      doc.querySelectorAll(':target');
+      return true;
+    } catch (e) {
+      return false;
+    }
+  });
+});
diff --git a/feature-detects/css/textalignlast.js b/feature-detects/css/textalignlast.js
new file mode 100644
index 0000000..f15798e
--- /dev/null
+++ b/feature-detects/css/textalignlast.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "CSS text-align-last",
+  "property": "textalignlast",
+  "caniuse": "css-text-align-last",
+  "tags": ["css"],
+  "warnings": ["IE does not support the 'start' or 'end' values."],
+  "notes": [{
+    "name": "Quirksmode",
+    "href": "https://www.quirksmode.org/css/text/textalignlast.html"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/text-align-last"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('textalignlast', testAllProps('textAlignLast'));
+});
diff --git a/feature-detects/css/textdecoration.js b/feature-detects/css/textdecoration.js
new file mode 100644
index 0000000..6eca41e
--- /dev/null
+++ b/feature-detects/css/textdecoration.js
@@ -0,0 +1,41 @@
+/*!
+{
+  "name": "CSS textDecoration",
+  "property": "textdecoration",
+  "caniuse": "text-decoration",
+  "tags": ["css"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css-text-decor-3/#line-decoration"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+
+  (function() {
+
+    Modernizr.addTest('textdecoration', function() {
+      var bool = false;
+      var test = testAllProps('textDecoration');
+      try {
+        bool = !!test;
+        if (bool) {
+          bool = new Boolean(bool);
+        }
+      } catch (e) {}
+
+      return bool;
+    });
+
+    var props = ['Line', 'Style', 'Color', 'Skip', 'SkipInk'];
+    var name, test;
+
+    for (var i = 0; i < props.length; i++) {
+      name = props[i].toLowerCase();
+      test = testAllProps('textDecoration' + props[i]);
+
+      Modernizr.addTest('textdecoration.' + name, test);
+    }
+  })();
+
+});
diff --git a/feature-detects/css/textshadow.js b/feature-detects/css/textshadow.js
new file mode 100644
index 0000000..b5ac9b6
--- /dev/null
+++ b/feature-detects/css/textshadow.js
@@ -0,0 +1,12 @@
+/*!
+{
+  "name": "CSS textshadow",
+  "property": "textshadow",
+  "caniuse": "css-textshadow",
+  "tags": ["css"],
+  "knownBugs": ["FF3.0 will false positive on this test"]
+}
+!*/
+define(['Modernizr', 'testProp'], function(Modernizr, testProp) {
+  Modernizr.addTest('textshadow', testProp('textShadow', '1px 1px'));
+});
diff --git a/feature-detects/css/transforms.js b/feature-detects/css/transforms.js
new file mode 100644
index 0000000..2cb0008
--- /dev/null
+++ b/feature-detects/css/transforms.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "CSS Transforms",
+  "property": "csstransforms",
+  "caniuse": "transforms2d",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('csstransforms', function() {
+    // Android < 3.0 is buggy, so we sniff and reject it
+    // https://github.com/Modernizr/Modernizr/issues/903
+    return navigator.userAgent.indexOf('Android 2.') === -1 &&
+           testAllProps('transform', 'scale(1)', true);
+  });
+});
diff --git a/feature-detects/css/transforms3d.js b/feature-detects/css/transforms3d.js
new file mode 100644
index 0000000..ef87237
--- /dev/null
+++ b/feature-detects/css/transforms3d.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "CSS Transforms 3D",
+  "property": "csstransforms3d",
+  "caniuse": "transforms3d",
+  "tags": ["css"],
+  "knownBugs": [
+    "Chrome may occasionally fail this test on some systems; more info: https://bugs.chromium.org/p/chromium/issues/detail?id=129004, however, the issue has since been closed (marked as fixed)."
+  ]
+}
+!*/
+define(['Modernizr', 'testAllProps', 'test/css/supports'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('csstransforms3d', function() {
+    return !!testAllProps('perspective', '1px', true);
+  });
+});
diff --git a/feature-detects/css/transformslevel2.js b/feature-detects/css/transformslevel2.js
new file mode 100644
index 0000000..839f84e
--- /dev/null
+++ b/feature-detects/css/transformslevel2.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "CSS Transforms Level 2",
+  "property": "csstransformslevel2",
+  "authors": ["rupl"],
+  "tags": ["css"],
+  "notes": [{
+    "name": "CSSWG Draft Spec",
+    "href": "https://drafts.csswg.org/css-transforms-2/"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('csstransformslevel2', function() {
+    return testAllProps('translate', '45px', true);
+  });
+});
diff --git a/feature-detects/css/transformstylepreserve3d.js b/feature-detects/css/transformstylepreserve3d.js
new file mode 100755
index 0000000..139cd15
--- /dev/null
+++ b/feature-detects/css/transformstylepreserve3d.js
@@ -0,0 +1,44 @@
+/*!
+{
+  "name": "CSS Transform Style preserve-3d",
+  "property": "preserve3d",
+  "authors": ["denyskoch", "aFarkas"],
+  "tags": ["css"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/transform-style"
+  }, {
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/1748"
+  }]
+}
+!*/
+/* DOC
+Detects support for `transform-style: preserve-3d`, for getting a proper 3D perspective on elements.
+*/
+define(['Modernizr', 'createElement', 'docElement'], function(Modernizr, createElement, docElement) {
+  Modernizr.addTest('preserve3d', function() {
+    var outerAnchor, innerAnchor;
+    var CSS = window.CSS;
+    var result = false;
+
+    if (CSS && CSS.supports && CSS.supports('(transform-style: preserve-3d)')) {
+      return true;
+    }
+
+    outerAnchor = createElement('a');
+    innerAnchor = createElement('a');
+
+    outerAnchor.style.cssText = 'display: block; transform-style: preserve-3d; transform-origin: right; transform: rotateY(40deg);';
+    innerAnchor.style.cssText = 'display: block; width: 9px; height: 1px; background: #000; transform-origin: right; transform: rotateY(40deg);';
+
+    outerAnchor.appendChild(innerAnchor);
+    docElement.appendChild(outerAnchor);
+
+    result = innerAnchor.getBoundingClientRect();
+    docElement.removeChild(outerAnchor);
+
+    result = result.width && result.width < 4;
+    return result;
+  });
+});
diff --git a/feature-detects/css/transitions.js b/feature-detects/css/transitions.js
new file mode 100644
index 0000000..ed7d22a
--- /dev/null
+++ b/feature-detects/css/transitions.js
@@ -0,0 +1,11 @@
+/*!
+{
+  "name": "CSS Transitions",
+  "property": "csstransitions",
+  "caniuse": "css-transitions",
+  "tags": ["css"]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('csstransitions', testAllProps('transition', 'all', true));
+});
diff --git a/feature-detects/css/userselect.js b/feature-detects/css/userselect.js
new file mode 100644
index 0000000..258498b
--- /dev/null
+++ b/feature-detects/css/userselect.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "CSS user-select",
+  "property": "userselect",
+  "caniuse": "user-select-none",
+  "authors": ["ryan seddon"],
+  "tags": ["css"],
+  "builderAliases": ["css_userselect"],
+  "notes": [{
+    "name": "Related Modernizr Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/250"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  //https://github.com/Modernizr/Modernizr/issues/250
+  Modernizr.addTest('userselect', testAllProps('userSelect', 'none', true));
+});
diff --git a/feature-detects/css/valid.js b/feature-detects/css/valid.js
new file mode 100644
index 0000000..f7bfe12
--- /dev/null
+++ b/feature-detects/css/valid.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "CSS :valid pseudo-class",
+  "property": "cssvalid",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/CSS/:valid"
+  }]
+}
+!*/
+/* DOC
+  Detects support for the ':valid' CSS pseudo-class.
+*/
+define(['Modernizr', 'testStyles', 'createElement'], function(Modernizr, testStyles, createElement) {
+  Modernizr.addTest('cssvalid', function() {
+    return testStyles('#modernizr input{height:0;border:0;padding:0;margin:0;width:10px} #modernizr input:valid{width:50px}', function(elem) {
+      var input = createElement('input');
+      elem.appendChild(input);
+      return input.clientWidth > 10;
+    });
+  });
+});
diff --git a/feature-detects/css/variablefonts.js b/feature-detects/css/variablefonts.js
new file mode 100644
index 0000000..8acb89a
--- /dev/null
+++ b/feature-detects/css/variablefonts.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "Variable Open Type Fonts",
+  "property": "variablefonts",
+  "authors": ["Patrick Kettner"],
+  "tags": ["css"],
+  "notes": [{
+    "name": "Variable fonts on the web",
+    "href": "https://webkit.org/blog/7051/variable-fonts-on-the-web/"
+  }, {
+    "name": "Variable fonts for responsive design",
+    "href": "https://alistapart.com/blog/post/variable-fonts-for-responsive-design"
+  }]
+}
+!*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('variablefonts', testAllProps('fontVariationSettings'));
+});
diff --git a/feature-detects/css/vhunit.js b/feature-detects/css/vhunit.js
new file mode 100644
index 0000000..6183794
--- /dev/null
+++ b/feature-detects/css/vhunit.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "CSS vh unit",
+  "property": "cssvhunit",
+  "caniuse": "viewport-units",
+  "tags": ["css"],
+  "builderAliases": ["css_vhunit"],
+  "notes": [{
+    "name": "Related Modernizr Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/572"
+  }, {
+    "name": "Similar JSFiddle",
+    "href": "https://jsfiddle.net/FWeinb/etnYC/"
+  }]
+}
+!*/
+define(['Modernizr', 'testStyles', 'computedStyle'], function(Modernizr, testStyles, computedStyle) {
+  testStyles('#modernizr { height: 50vh; max-height: 10px; }', function(elem) {
+    var compStyle = parseInt(computedStyle(elem, null, 'height'), 10);
+    Modernizr.addTest('cssvhunit', compStyle === 10);
+  });
+});
diff --git a/feature-detects/css/vmaxunit.js b/feature-detects/css/vmaxunit.js
new file mode 100644
index 0000000..37cb128
--- /dev/null
+++ b/feature-detects/css/vmaxunit.js
@@ -0,0 +1,31 @@
+/*!
+{
+  "name": "CSS vmax unit",
+  "property": "cssvmaxunit",
+  "caniuse": "viewport-units",
+  "tags": ["css"],
+  "builderAliases": ["css_vmaxunit"],
+  "notes": [{
+    "name": "Related Modernizr Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/572"
+  }, {
+    "name": "JSFiddle Example",
+    "href": "https://jsfiddle.net/glsee/JDsWQ/4/"
+  }]
+}
+!*/
+define(['Modernizr', 'docElement', 'testStyles', 'roundedEquals', 'computedStyle'], function(Modernizr, docElement, testStyles, roundedEquals, computedStyle) {
+  testStyles('#modernizr1{width: 50vmax}#modernizr2{width:50px;height:50px;overflow:scroll}#modernizr3{position:fixed;top:0;left:0;bottom:0;right:0}', function(node) {
+    var elem = node.childNodes[2];
+    var scroller = node.childNodes[1];
+    var fullSizeElem = node.childNodes[0];
+    var scrollbarWidth = parseInt((scroller.offsetWidth - scroller.clientWidth) / 2, 10);
+
+    var one_vw = fullSizeElem.clientWidth / 100;
+    var one_vh = fullSizeElem.clientHeight / 100;
+    var expectedWidth = parseInt(Math.max(one_vw, one_vh) * 50, 10);
+    var compWidth = parseInt(computedStyle(elem, null, 'width'), 10);
+
+    Modernizr.addTest('cssvmaxunit', roundedEquals(expectedWidth, compWidth) || roundedEquals(expectedWidth, compWidth - scrollbarWidth));
+  }, 3);
+});
diff --git a/feature-detects/css/vminunit.js b/feature-detects/css/vminunit.js
new file mode 100644
index 0000000..01b67ba
--- /dev/null
+++ b/feature-detects/css/vminunit.js
@@ -0,0 +1,31 @@
+/*!
+{
+  "name": "CSS vmin unit",
+  "property": "cssvminunit",
+  "caniuse": "viewport-units",
+  "tags": ["css"],
+  "builderAliases": ["css_vminunit"],
+  "notes": [{
+    "name": "Related Modernizr Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/572"
+  }, {
+    "name": "JSFiddle Example",
+    "href": "https://jsfiddle.net/glsee/JRmdq/8/"
+  }]
+}
+!*/
+define(['Modernizr', 'docElement', 'testStyles', 'roundedEquals', 'computedStyle'], function(Modernizr, docElement, testStyles, roundedEquals, computedStyle) {
+  testStyles('#modernizr1{width: 50vm;width:50vmin}#modernizr2{width:50px;height:50px;overflow:scroll}#modernizr3{position:fixed;top:0;left:0;bottom:0;right:0}', function(node) {
+    var elem = node.childNodes[2];
+    var scroller = node.childNodes[1];
+    var fullSizeElem = node.childNodes[0];
+    var scrollbarWidth = parseInt((scroller.offsetWidth - scroller.clientWidth) / 2, 10);
+
+    var one_vw = fullSizeElem.clientWidth / 100;
+    var one_vh = fullSizeElem.clientHeight / 100;
+    var expectedWidth = parseInt(Math.min(one_vw, one_vh) * 50, 10);
+    var compWidth = parseInt(computedStyle(elem, null, 'width'), 10);
+
+    Modernizr.addTest('cssvminunit', roundedEquals(expectedWidth, compWidth) || roundedEquals(expectedWidth, compWidth - scrollbarWidth));
+  }, 3);
+});
diff --git a/feature-detects/css/vwunit.js b/feature-detects/css/vwunit.js
new file mode 100644
index 0000000..279c4b8
--- /dev/null
+++ b/feature-detects/css/vwunit.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "CSS vw unit",
+  "property": "cssvwunit",
+  "caniuse": "viewport-units",
+  "tags": ["css"],
+  "builderAliases": ["css_vwunit"],
+  "notes": [{
+    "name": "Related Modernizr Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/572"
+  }, {
+    "name": "JSFiddle Example",
+    "href": "https://jsfiddle.net/FWeinb/etnYC/"
+  }]
+}
+!*/
+define(['Modernizr', 'testStyles', 'computedStyle', 'roundedEquals'], function(Modernizr, testStyles, computedStyle, roundedEquals) {
+  testStyles('#modernizr { width: 50vw; }', function(elem) {
+    var width = parseInt(window.innerWidth / 2, 10);
+    var compStyle = parseInt(computedStyle(elem, null, 'width'), 10);
+
+    Modernizr.addTest('cssvwunit', roundedEquals(compStyle, width));
+  });
+});
diff --git a/feature-detects/css/will-change.js b/feature-detects/css/will-change.js
new file mode 100644
index 0000000..c4f2175
--- /dev/null
+++ b/feature-detects/css/will-change.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "will-change",
+  "property": "willchange",
+  "caniuse": "will-change",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://drafts.csswg.org/css-will-change/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the `will-change` css property, which formally signals to the
+browser that an element will be animating.
+*/
+define(['Modernizr', 'docElement'], function(Modernizr, docElement) {
+  Modernizr.addTest('willchange', 'willChange' in docElement.style);
+});
diff --git a/feature-detects/css/wrapflow.js b/feature-detects/css/wrapflow.js
new file mode 100644
index 0000000..4c76f4b
--- /dev/null
+++ b/feature-detects/css/wrapflow.js
@@ -0,0 +1,48 @@
+/*!
+{
+  "name": "CSS wrap-flow",
+  "property": "wrapflow",
+  "tags": ["css"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/css3-exclusions"
+  }, {
+    "name": "Example by Louie Rootfield",
+    "href": "https://webdesign.tutsplus.com/tutorials/css-exclusions--cms-28087"
+  }]
+}
+!*/
+define(['Modernizr', 'prefixed', 'docElement', 'createElement', 'isSVG'], function(Modernizr, prefixed, docElement, createElement, isSVG) {
+  Modernizr.addTest('wrapflow', function() {
+    var prefixedProperty = prefixed('wrapFlow');
+    if (!prefixedProperty || isSVG) {
+      return false;
+    }
+
+    var wrapFlowProperty = prefixedProperty.replace(/([A-Z])/g, function(str, m1) { return '-' + m1.toLowerCase(); }).replace(/^ms-/, '-ms-');
+
+    /* If the CSS parsing is there we need to determine if wrap-flow actually works to avoid false positive cases, e.g. the browser parses
+       the property, but it hasn't got the implementation for the functionality yet. */
+    var container = createElement('div');
+    var exclusion = createElement('div');
+    var content = createElement('span');
+
+    /* First we create a div with two adjacent divs inside it. The first div will be the content, the second div will be the exclusion area.
+       We use the "wrap-flow: end" property to test the actual behavior. (https://drafts.csswg.org/css-exclusions-1/#wrap-flow-property)
+       The wrap-flow property is applied to the exclusion area what has a 50px left offset and a 100px width.
+       If the wrap-flow property is working correctly then the content should start after the exclusion area, so the content's left offset should be 150px. */
+    exclusion.style.cssText = 'position: absolute; left: 50px; width: 100px; height: 20px;' + wrapFlowProperty + ':end;';
+    content.innerText = 'X';
+
+    container.appendChild(exclusion);
+    container.appendChild(content);
+    docElement.appendChild(container);
+
+    var leftOffset = content.offsetLeft;
+
+    docElement.removeChild(container);
+    exclusion = content = container = undefined;
+
+    return (leftOffset === 150);
+  });
+});
diff --git a/feature-detects/custom-elements.js b/feature-detects/custom-elements.js
new file mode 100644
index 0000000..15bb886
--- /dev/null
+++ b/feature-detects/custom-elements.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "Custom Elements API",
+  "property": "customelements",
+  "caniuse": "custom-elementsv1",
+  "tags": ["customelements"],
+  "polyfills": ["customelements"],
+  "notes": [{
+    "name": "Specs for Custom Elements",
+    "href": "https://www.w3.org/TR/custom-elements/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the Custom Elements API, to create custom html elements via js
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('customelements', 'customElements' in window);
+});
diff --git a/feature-detects/custom-protocol-handler.js b/feature-detects/custom-protocol-handler.js
index 2534189..ced72f5 100644
--- a/feature-detects/custom-protocol-handler.js
+++ b/feature-detects/custom-protocol-handler.js
@@ -1,10 +1,38 @@
-/*
-	Custom protocol handler support
-	http://developers.whatwg.org/timers.html#custom-handlers
-	
-	Added by @benschwarz
+/*!
+{
+  "name": "Custom protocol handler",
+  "property": "customprotocolhandler",
+  "authors": ["Ben Schwarz"],
+  "builderAliases": ["custom_protocol_handler"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/dev/system-state.html#custom-handlers"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/navigator.registerProtocolHandler"
+  }]
+}
+!*/
+/* DOC
+Detects support for the `window.registerProtocolHandler()` API to allow websites to register themselves as possible handlers for particular protocols.
 */
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('customprotocolhandler', function() {
+    // early bailout where it doesn't exist at all
+    if (!navigator.registerProtocolHandler) {
+      return false;
+    }
 
-Modernizr.addTest('customprotocolhandler', function () {
-    return !!navigator.registerProtocolHandler;
+    // registerProtocolHandler was stubbed in webkit for a while, and didn't
+    // actually do anything. We intentionally set it improperly to test for
+    // the proper sort of failure
+    try {
+      navigator.registerProtocolHandler('thisShouldFail');
+    }
+    catch (e) {
+      return e instanceof TypeError;
+    }
+
+    return false;
+  });
 });
diff --git a/feature-detects/dart.js b/feature-detects/dart.js
index 9a8bc82..b7e2193 100644
--- a/feature-detects/dart.js
+++ b/feature-detects/dart.js
@@ -1,6 +1,17 @@
-// Dart
-// By Theodoor van Donge
-
-// https://chromiumcodereview.appspot.com/9232049/
-
-Modernizr.addTest('dart', !!Modernizr.prefixed('startDart', navigator));
+/*!
+{
+  "name": "Dart",
+  "property": "dart",
+  "authors": ["Theodoor van Donge"],
+  "notes": [{
+    "name": "Language website",
+    "href": "https://www.dartlang.org/"
+  }]
+}
+!*/
+/* DOC
+Detects native support for the Dart programming language.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('dart', !!prefixed('startDart', navigator));
+});
diff --git a/feature-detects/dataview-api.js b/feature-detects/dataview-api.js
index 249bfff..9699ba2 100644
--- a/feature-detects/dataview-api.js
+++ b/feature-detects/dataview-api.js
@@ -1,4 +1,19 @@
-// DataView 
-// https://developer.mozilla.org/en/JavaScript_typed_arrays/DataView
-// By Addy Osmani
-Modernizr.addTest('dataview', (typeof DataView !== 'undefined' && 'getFloat64' in DataView.prototype));
\ No newline at end of file
+/*!
+{
+  "name": "DataView",
+  "property": "dataview",
+  "authors": ["Addy Osmani"],
+  "builderAliases": ["dataview_api"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/JavaScript_typed_arrays/DataView"
+  }],
+  "polyfills": ["jdataview"]
+}
+!*/
+/* DOC
+Detects support for the DataView interface for reading data from an ArrayBuffer as part of the Typed Array spec.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('dataview', (typeof DataView !== 'undefined' && 'getFloat64' in DataView.prototype));
+});
diff --git a/feature-detects/dom-classlist.js b/feature-detects/dom-classlist.js
deleted file mode 100644
index c227057..0000000
--- a/feature-detects/dom-classlist.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// classList
-// https://developer.mozilla.org/en/DOM/element.classList
-// By Addy Osmani
-Modernizr.addTest('classlist', 'classList' in document.documentElement);
diff --git a/feature-detects/dom-createElement-attrs.js b/feature-detects/dom-createElement-attrs.js
deleted file mode 100644
index d9a3b11..0000000
--- a/feature-detects/dom-createElement-attrs.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// by james a rosen.
-// https://github.com/Modernizr/Modernizr/issues/258
-
-Modernizr.addTest('createelement-attrs', function() {
-  try {
-    return document.createElement("<input name='test' />").getAttribute('name') == 'test';
-  } catch(e) {
-    return false;
-  }
-});
-
diff --git a/feature-detects/dom-dataset.js b/feature-detects/dom-dataset.js
deleted file mode 100644
index 810ff50..0000000
--- a/feature-detects/dom-dataset.js
+++ /dev/null
@@ -1,9 +0,0 @@
-
-// dataset API for data-* attributes
-// test by @phiggins42
-
-Modernizr.addTest('dataset', function(){
-  var n = document.createElement("div");
-  n.setAttribute("data-a-b", "c");
-  return !!(n.dataset && n.dataset.aB === "c");
-});
diff --git a/feature-detects/dom-microdata.js b/feature-detects/dom-microdata.js
deleted file mode 100644
index ab0a5d6..0000000
--- a/feature-detects/dom-microdata.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// Microdata support
-// http://www.w3.org/TR/html5/microdata.html
-// By Addy Osmani
-Modernizr.addTest('microdata', !!(document['getItems']));
\ No newline at end of file
diff --git a/feature-detects/dom/classlist.js b/feature-detects/dom/classlist.js
new file mode 100644
index 0000000..dbbe483
--- /dev/null
+++ b/feature-detects/dom/classlist.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "classList",
+  "caniuse": "classlist",
+  "property": "classlist",
+  "tags": ["dom"],
+  "builderAliases": ["dataview_api"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/DOM/element.classList"
+  }]
+}
+!*/
+define(['Modernizr', 'docElement'], function(Modernizr, docElement) {
+  Modernizr.addTest('classlist', 'classList' in docElement);
+});
diff --git a/feature-detects/dom/createElement-attrs.js b/feature-detects/dom/createElement-attrs.js
new file mode 100644
index 0000000..12db6c6
--- /dev/null
+++ b/feature-detects/dom/createElement-attrs.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "createElement with Attributes",
+  "property": ["createelementattrs", "createelement-attrs"],
+  "tags": ["dom"],
+  "builderAliases": ["dom_createElement_attrs"],
+  "authors": ["James A. Rosen"],
+  "notes": [{
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/258"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('createelementattrs', function() {
+    try {
+      return createElement('<input name="test" />').getAttribute('name') === 'test';
+    } catch (e) {
+      return false;
+    }
+  }, {
+    aliases: ['createelement-attrs']
+  });
+});
diff --git a/feature-detects/dom/dataset.js b/feature-detects/dom/dataset.js
new file mode 100644
index 0000000..02a04d3
--- /dev/null
+++ b/feature-detects/dom/dataset.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "dataset API",
+  "caniuse": "dataset",
+  "property": "dataset",
+  "tags": ["dom"],
+  "builderAliases": ["dom_dataset"],
+  "authors": ["@phiggins42"]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  // dataset API for data-* attributes
+  Modernizr.addTest('dataset', function() {
+    var n = createElement('div');
+    n.setAttribute('data-a-b', 'c');
+    return !!(n.dataset && n.dataset.aB === 'c');
+  });
+});
diff --git a/feature-detects/dom/documentfragment.js b/feature-detects/dom/documentfragment.js
new file mode 100644
index 0000000..da3e5cf
--- /dev/null
+++ b/feature-detects/dom/documentfragment.js
@@ -0,0 +1,29 @@
+/*!
+{
+  "name": "Document Fragment",
+  "property": "documentfragment",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/REC-DOM-Level-1/level-one-core.html#ID-B63ED1A3"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment"
+  }, {
+    "name": "QuirksMode Compatibility Tables",
+    "href": "https://www.quirksmode.org/m/w3c_core.html#t112"
+  }],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "knownBugs": ["false-positive on Blackberry 9500, see QuirksMode note"],
+  "tags": ["dom"]
+}
+!*/
+/* DOC
+Append multiple elements to the DOM within a single insertion.
+*/
+define(['Modernizr', 'docElement'], function(Modernizr, docElement) {
+  Modernizr.addTest('documentfragment', function() {
+    return 'createDocumentFragment' in document &&
+      'appendChild' in docElement;
+  });
+});
+
diff --git a/feature-detects/dom/hidden.js b/feature-detects/dom/hidden.js
new file mode 100644
index 0000000..0e1b017
--- /dev/null
+++ b/feature-detects/dom/hidden.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "[hidden] Attribute",
+  "property": "hidden",
+  "tags": ["dom"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/dev/interaction.html#the-hidden-attribute"
+  }, {
+    "name": "original implementation of detect code",
+    "href": "https://github.com/aFarkas/html5shiv/blob/bf4fcc4/src/html5shiv.js#L38"
+  }],
+  "polyfills": ["html5shiv"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"]
+}
+!*/
+/* DOC
+Does the browser support the HTML5 [hidden] attribute?
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('hidden', 'hidden' in createElement('a'));
+});
diff --git a/feature-detects/dom/intersection-observer.js b/feature-detects/dom/intersection-observer.js
new file mode 100644
index 0000000..4538224
--- /dev/null
+++ b/feature-detects/dom/intersection-observer.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "Intersection Observer",
+  "property": "intersectionobserver",
+  "caniuse": "intersectionobserver",
+  "tags": ["dom"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://w3c.github.io/IntersectionObserver/"
+  }, {
+    "name": "IntersectionObserver polyfill",
+    "href": "https://github.com/w3c/IntersectionObserver/tree/master/polyfill"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/docs/Web/API/Intersection_Observer_API"
+  }]
+}
+!*/
+/* DOC
+ Determines if Intersection Observer API is available.
+ */
+define(['Modernizr'], function (Modernizr) {
+  Modernizr.addTest('intersectionobserver', 'IntersectionObserver' in window);
+});
diff --git a/feature-detects/dom/microdata.js b/feature-detects/dom/microdata.js
new file mode 100644
index 0000000..bc0377f
--- /dev/null
+++ b/feature-detects/dom/microdata.js
@@ -0,0 +1,15 @@
+/*!
+{
+  "name": "microdata",
+  "property": "microdata",
+  "tags": ["dom"],
+  "builderAliases": ["dom_microdata"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/microdata/"
+  }]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('microdata', 'getItems' in document);
+});
diff --git a/feature-detects/dom/mutationObserver.js b/feature-detects/dom/mutationObserver.js
new file mode 100644
index 0000000..888ca5a
--- /dev/null
+++ b/feature-detects/dom/mutationObserver.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "DOM4 MutationObserver",
+  "property": "mutationobserver",
+  "caniuse": "mutationobserver",
+  "tags": ["dom"],
+  "authors": ["Karel Sedláček (@ksdlck)"],
+  "polyfills": ["mutationobservers"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver"
+  }]
+}
+!*/
+/* DOC
+Determines if DOM4 MutationObserver support is available.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('mutationobserver',
+    !!window.MutationObserver || !!window.WebKitMutationObserver);
+});
diff --git a/feature-detects/dom/passiveeventlisteners.js b/feature-detects/dom/passiveeventlisteners.js
new file mode 100644
index 0000000..5e3bdc7
--- /dev/null
+++ b/feature-detects/dom/passiveeventlisteners.js
@@ -0,0 +1,36 @@
+/*!
+{
+  "property": "passiveeventlisteners",
+  "caniuse": "passive-event-listener",
+  "tags": ["dom"],
+  "authors": ["Rick Byers"],
+  "name": "Passive event listeners",
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://dom.spec.whatwg.org/#dom-addeventlisteneroptions-passive"
+  }, {
+    "name": "WICG explainer",
+    "href": "https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md"
+  }]
+}
+!*/
+/* DOC
+Detects support for the passive option to addEventListener.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('passiveeventlisteners', function() {
+    var supportsPassiveOption = false;
+    try {
+      var opts = Object.defineProperty({}, 'passive', {
+        get: function() {
+          supportsPassiveOption = true;
+          return;
+        }
+      });
+      var noop = function () {};
+      window.addEventListener('testPassiveEventSupport', noop, opts);
+      window.removeEventListener('testPassiveEventSupport', noop, opts);
+    } catch (e) {}
+    return supportsPassiveOption;
+  });
+});
diff --git a/feature-detects/dom/shadowroot.js b/feature-detects/dom/shadowroot.js
new file mode 100644
index 0000000..ca2354b
--- /dev/null
+++ b/feature-detects/dom/shadowroot.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "Shadow DOM API",
+  "property": "shadowroot",
+  "caniuse": "shadowdomv1",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot"
+  }],
+  "authors": ["Kevin Coyle (@kevin-coyle-unipro)", "Pascal Lim (@pascalim)"],
+  "tags": ["dom"]
+}
+!*/
+
+/* DOC
+Detects support for the Shadow DOM API.
+*/
+define(['Modernizr', 'createElement'], function (Modernizr, createElement) {
+  Modernizr.addTest('shadowroot', 'attachShadow' in createElement('div'));
+});
diff --git a/feature-detects/dom/shadowrootlegacy.js b/feature-detects/dom/shadowrootlegacy.js
new file mode 100644
index 0000000..9ad65b5
--- /dev/null
+++ b/feature-detects/dom/shadowrootlegacy.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "Shadow DOM API (Legacy)",
+  "property": "shadowrootlegacy",
+  "caniuse": "shadowdom",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Element/createShadowRoot"
+  }],
+  "authors": ["Kevin Coyle (@kevin-coyle-unipro)", "Pascal Lim (@pascalim)"],
+  "tags": ["dom"]
+}
+!*/
+
+/* DOC
+Detects support for the Shadow DOM API. (Legacy)
+*/
+define(['Modernizr', 'createElement'], function (Modernizr, createElement) {
+  Modernizr.addTest('shadowrootlegacy', 'createShadowRoot' in createElement('div'));
+});
diff --git a/feature-detects/elem-datalist.js b/feature-detects/elem-datalist.js
deleted file mode 100644
index 4bcdc1f..0000000
--- a/feature-detects/elem-datalist.js
+++ /dev/null
@@ -1,12 +0,0 @@
-
-
-// lol. we already have a test for datalist built in! silly you.
-
-
-// Helpful links while you're here, though..
-
-// http://css-tricks.com/15346-relevant-dropdowns-polyfill-for-datalist/
-// http://miketaylr.com/test/datalist.html
-// http://miketaylr.com/code/datalist.html
-
-Modernizr.addTest('datalistelem', Modernizr.input.list );
diff --git a/feature-detects/elem-details.js b/feature-detects/elem-details.js
deleted file mode 100644
index 90501f1..0000000
--- a/feature-detects/elem-details.js
+++ /dev/null
@@ -1,25 +0,0 @@
-// By @mathias, based on http://mths.be/axh
-Modernizr.addTest('details', function() {
-    var doc = document,
-        el = doc.createElement('details'),
-        fake,
-        root,
-        diff;
-    if (!('open' in el)) { // return early if possible; thanks @aFarkas!
-        return false;
-    }
-    root = doc.body || (function() {
-        var de = doc.documentElement;
-        fake = true;
-        return de.insertBefore(doc.createElement('body'), de.firstElementChild || de.firstChild);
-    }());
-    el.innerHTML = '<summary>a</summary>b';
-    el.style.display = 'block';
-    root.appendChild(el);
-    diff = el.offsetHeight;
-    el.open = true;
-    diff = diff != el.offsetHeight;
-    root.removeChild(el);
-    fake && root.parentNode.removeChild(root);
-    return diff;
-});
\ No newline at end of file
diff --git a/feature-detects/elem-output.js b/feature-detects/elem-output.js
deleted file mode 100644
index 54276b2..0000000
--- a/feature-detects/elem-output.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// <output>
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/the-button-element.html#the-output-element
-// by Addy Osmani
-Modernizr.addTest('outputelem', 'value' in document.createElement('output'));
diff --git a/feature-detects/elem-progress-meter.js b/feature-detects/elem-progress-meter.js
deleted file mode 100644
index cfa4bdf..0000000
--- a/feature-detects/elem-progress-meter.js
+++ /dev/null
@@ -1,11 +0,0 @@
-//By Stefan Wallin
-
-//tests for progressbar-support. All browsers that don't support progressbar returns undefined =)
-Modernizr.addTest("progressbar",function(){
-    return document.createElement('progress').max !== undefined;
-});
-
-//tests for meter-support. All browsers that don't support meters returns undefined =)
-Modernizr.addTest("meter",function(){
-    return document.createElement('meter').max !== undefined;
-});
diff --git a/feature-detects/elem-ruby.js b/feature-detects/elem-ruby.js
deleted file mode 100644
index dbb978f..0000000
--- a/feature-detects/elem-ruby.js
+++ /dev/null
@@ -1,53 +0,0 @@
-// Browser support test for the HTML5 <ruby>, <rt> and <rp> elements
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/text-level-semantics.html#the-ruby-element
-//
-// by @alrra
-
-Modernizr.addTest('ruby', function () {
-
-    var ruby = document.createElement('ruby'),
-        rt = document.createElement('rt'),
-        rp = document.createElement('rp'),
-        docElement = document.documentElement,
-        displayStyleProperty = 'display',
-        fontSizeStyleProperty = 'fontSize'; // 'fontSize' - because it`s only used for IE6 and IE7
-
-    ruby.appendChild(rp);
-    ruby.appendChild(rt);
-    docElement.appendChild(ruby);
-
-    // browsers that support <ruby> hide the <rp> via "display:none"
-    if ( getStyle(rp, displayStyleProperty) == 'none' ||                                                       // for non-IE browsers
-    // but in IE browsers <rp> has "display:inline" so, the test needs other conditions:
-        getStyle(ruby, displayStyleProperty) == 'ruby' && getStyle(rt, displayStyleProperty) == 'ruby-text' || // for IE8 & IE9
-        getStyle(rp, fontSizeStyleProperty) == '6pt' && getStyle(rt, fontSizeStyleProperty) == '6pt' ) {       // for IE6 & IE7
-
-        cleanUp();
-        return true;
-
-    } else {
-        cleanUp();
-        return false;
-    }
-
-    function getStyle( element, styleProperty ) {
-        var result;
-
-        if ( window.getComputedStyle ) {     // for non-IE browsers
-            result = document.defaultView.getComputedStyle(element,null).getPropertyValue(styleProperty);
-        } else if ( element.currentStyle ) { // for IE
-            result = element.currentStyle[styleProperty];
-        }
-
-        return result;
-    }
-
-    function cleanUp() {
-        docElement.removeChild(ruby);
-        // the removed child node still exists in memory, so ...
-        ruby = null;
-        rt = null;
-        rp = null;
-    }
-
-});
diff --git a/feature-detects/elem-time.js b/feature-detects/elem-time.js
deleted file mode 100644
index fc88606..0000000
--- a/feature-detects/elem-time.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// <time> element
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/rendering.html#the-time-element-0
-// by Addy Osmani
-Modernizr.addTest('time', 'valueAsDate' in document.createElement('time'));
diff --git a/feature-detects/elem-track.js b/feature-detects/elem-track.js
deleted file mode 100644
index 7d8e495..0000000
--- a/feature-detects/elem-track.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Track element + Timed Text Track API
-// http://www.w3.org/TR/html5/video.html#the-track-element
-// http://www.w3.org/TR/html5/media-elements.html#text-track-api
-//
-// While IE10 has implemented the track element, IE10 does not expose the underlying APIs to create timed text tracks by JS (really sad)
-// By Addy Osmani
-Modernizr.addTest({
-	texttrackapi: (typeof (document.createElement('video').addTextTrack) === 'function'),
-	// a more strict test for track including UI support: document.createElement('track').kind === 'subtitles'
-	track: ('kind' in document.createElement('track'))
-});
diff --git a/feature-detects/elem/bdi.js b/feature-detects/elem/bdi.js
new file mode 100644
index 0000000..45bc29e
--- /dev/null
+++ b/feature-detects/elem/bdi.js
@@ -0,0 +1,30 @@
+/*!
+{
+  "name": "bdi Element",
+  "property": "bdi",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/bdi"
+  }]
+}
+!*/
+/* DOC
+Detect support for the bdi element, a way to have text that is isolated from its possibly bidirectional surroundings
+*/
+define(['Modernizr', 'createElement', 'docElement', 'computedStyle'], function(Modernizr, createElement, docElement, computedStyle) {
+  Modernizr.addTest('bdi', function() {
+    var div = createElement('div');
+    var bdi = createElement('bdi');
+
+    bdi.innerHTML = '&#1573;';
+    div.appendChild(bdi);
+
+    docElement.appendChild(div);
+
+    var supports = computedStyle(bdi, null, 'direction') === 'rtl';
+
+    docElement.removeChild(div);
+
+    return supports;
+  });
+});
diff --git a/feature-detects/elem/details.js b/feature-detects/elem/details.js
new file mode 100644
index 0000000..862b263
--- /dev/null
+++ b/feature-detects/elem/details.js
@@ -0,0 +1,35 @@
+/*!
+{
+  "name": "details Element",
+  "caniuse": "details",
+  "property": "details",
+  "tags": ["elem"],
+  "builderAliases": ["elem_details"],
+  "authors": ["@mathias"],
+  "notes": [{
+    "name": "Mathias' Original",
+    "href": "https://mathiasbynens.be/notes/html5-details-jquery#comment-35"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement', 'docElement', 'testStyles'], function(Modernizr, createElement, docElement, testStyles) {
+  Modernizr.addTest('details', function() {
+    var el = createElement('details');
+    var diff;
+
+    // return early if possible; thanks @aFarkas!
+    if (!('open' in el)) {
+      return false;
+    }
+
+    testStyles('#modernizr details{display:block}', function(node) {
+      node.appendChild(el);
+      el.innerHTML = '<summary>a</summary>b';
+      diff = el.offsetHeight;
+      el.open = true;
+      diff = diff !== el.offsetHeight;
+    });
+
+    return diff;
+  });
+});
diff --git a/feature-detects/elem/output.js b/feature-detects/elem/output.js
new file mode 100644
index 0000000..9b73502
--- /dev/null
+++ b/feature-detects/elem/output.js
@@ -0,0 +1,15 @@
+/*!
+{
+  "name": "output Element",
+  "property": "outputelem",
+  "tags": ["elem"],
+  "builderAliases": ["elem_output"],
+  "notes": [{
+    "name": "WhatWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/form-elements.html#the-output-element"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('outputelem', 'value' in createElement('output'));
+});
diff --git a/feature-detects/elem/picture.js b/feature-detects/elem/picture.js
new file mode 100644
index 0000000..d9030ed
--- /dev/null
+++ b/feature-detects/elem/picture.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "picture Element",
+  "property": "picture",
+  "tags": ["elem"],
+  "authors": ["Scott Jehl", "Mat Marquis"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#embedded-content"
+  }, {
+    "name": "Relevant spec issue",
+    "href": "https://github.com/ResponsiveImagesCG/picture-element/issues/87"
+  }]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('picture', 'HTMLPictureElement' in window);
+});
diff --git a/feature-detects/elem/progress-meter.js b/feature-detects/elem/progress-meter.js
new file mode 100644
index 0000000..cea3f37
--- /dev/null
+++ b/feature-detects/elem/progress-meter.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "progress Element",
+  "caniuse": "progress",
+  "property": ["progressbar", "meter"],
+  "tags": ["elem"],
+  "builderAliases": ["elem_progress_meter"],
+  "authors": ["Stefan Wallin"]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  // Tests for progressbar-support. All browsers that don't support progressbar returns undefined =)
+  Modernizr.addTest('progressbar', createElement('progress').max !== undefined);
+
+  // Tests for meter-support. All browsers that don't support meters returns undefined =)
+  Modernizr.addTest('meter', createElement('meter').max !== undefined);
+});
diff --git a/feature-detects/elem/ruby.js b/feature-detects/elem/ruby.js
new file mode 100644
index 0000000..f9a50e2
--- /dev/null
+++ b/feature-detects/elem/ruby.js
@@ -0,0 +1,48 @@
+/*!
+{
+  "name": "ruby, rp, rt Elements",
+  "caniuse": "ruby",
+  "property": "ruby",
+  "tags": ["elem"],
+  "builderAliases": ["elem_ruby"],
+  "authors": ["Cătălin Mariș"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-ruby-element"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement', 'docElement', 'computedStyle'], function(Modernizr, createElement, docElement, computedStyle) {
+  Modernizr.addTest('ruby', function() {
+
+    var ruby = createElement('ruby');
+    var rt = createElement('rt');
+    var rp = createElement('rp');
+
+    ruby.appendChild(rp);
+    ruby.appendChild(rt);
+    docElement.appendChild(ruby);
+
+    // browsers that support <ruby> hide the <rp> via "display:none"
+    if (computedStyle(rp, null, 'display') === 'none' ||                                                       // for non-IE browsers
+         // but in IE browsers <rp> has "display:inline" so, the test needs other conditions:
+      computedStyle(ruby, null, 'display') === 'ruby' && computedStyle(rt, null, 'display') === 'ruby-text' || // for IE8+
+      computedStyle(rp, null, 'fontSize') === '6pt' && computedStyle(rt, null, 'fontSize') === '6pt') {        // for IE6 & IE7
+
+      cleanUp();
+      return true;
+
+    } else {
+      cleanUp();
+      return false;
+    }
+
+    function cleanUp() {
+      docElement.removeChild(ruby);
+      // the removed child node still exists in memory, so ...
+      ruby = null;
+      rt = null;
+      rp = null;
+    }
+  });
+});
diff --git a/feature-detects/elem/template.js b/feature-detects/elem/template.js
new file mode 100644
index 0000000..1a3d0bb
--- /dev/null
+++ b/feature-detects/elem/template.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "Template Tag",
+  "property": "template",
+  "caniuse": "template",
+  "tags": ["elem"],
+  "notes": [{
+    "name": "HTML5Rocks Article",
+    "href": "https://www.html5rocks.com/en/tutorials/webcomponents/template/"
+  }, {
+    "name": "W3C Spec",
+    "href": "https://web.archive.org/web/20171130222649/http://www.w3.org/TR/html5/scripting-1.html"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('template', 'content' in createElement('template'));
+});
diff --git a/feature-detects/elem/time.js b/feature-detects/elem/time.js
new file mode 100644
index 0000000..d7353c5
--- /dev/null
+++ b/feature-detects/elem/time.js
@@ -0,0 +1,15 @@
+/*!
+{
+  "name": "time Element",
+  "property": "time",
+  "tags": ["elem"],
+  "builderAliases": ["elem_time"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/text-level-semantics.html#the-time-element"
+  }]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('time', 'valueAsDate' in createElement('time'));
+});
diff --git a/feature-detects/elem/track.js b/feature-detects/elem/track.js
new file mode 100644
index 0000000..8ae2bdd
--- /dev/null
+++ b/feature-detects/elem/track.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "Track element and Timed Text Track",
+  "property": ["texttrackapi", "track"],
+  "tags": ["elem"],
+  "builderAliases": ["elem_track"],
+  "authors": ["Addy Osmani"],
+  "notes": [{
+    "name": "W3C Spec (Track Element)",
+    "href": "https://web.archive.org/web/20121119095019/http://www.w3.org/TR/html5/the-track-element.html#the-track-element"
+  }, {
+    "name": "W3C Spec (Track API)",
+    "href": "https://web.archive.org/web/20121119094620/http://www.w3.org/TR/html5/media-elements.html#text-track-api"
+  }],
+  "warnings": ["While IE10 has implemented the track element, IE10 does not expose the underlying APIs to create timed text tracks by JS (really sad)"]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('texttrackapi', typeof (createElement('video').addTextTrack) === 'function');
+
+  // a more strict test for track including UI support: document.createElement('track').kind === 'subtitles'
+  Modernizr.addTest('track', 'kind' in createElement('track'));
+});
diff --git a/feature-detects/elem/unknown.js b/feature-detects/elem/unknown.js
new file mode 100644
index 0000000..8aef9fe
--- /dev/null
+++ b/feature-detects/elem/unknown.js
@@ -0,0 +1,26 @@
+/*!
+{
+  "name": "Unknown Elements",
+  "property": "unknownelements",
+  "tags": ["elem"],
+  "notes": [{
+    "name": "The Story of the HTML5 Shiv",
+    "href": "https://www.paulirish.com/2011/the-history-of-the-html5-shiv/"
+  }, {
+    "name": "original implementation of detect code",
+    "href": "https://github.com/aFarkas/html5shiv/blob/bf4fcc4/src/html5shiv.js#L36"
+  }],
+  "polyfills": ["html5shiv"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"]
+}
+!*/
+/* DOC
+Does the browser support HTML with non-standard / new elements?
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('unknownelements', function() {
+    var a = createElement('a');
+    a.innerHTML = '<xyz></xyz>';
+    return a.childNodes.length === 1;
+  });
+});
diff --git a/feature-detects/emoji.js b/feature-detects/emoji.js
index 271db65..5eedb52 100644
--- a/feature-detects/emoji.js
+++ b/feature-detects/emoji.js
@@ -1,11 +1,31 @@
-// Requires a Modernizr build with `canvastext` included
-// http://www.modernizr.com/download/#-canvas-canvastext
-Modernizr.addTest('emoji', function() {
-  if (!Modernizr.canvastext) return false;
-  var node = document.createElement('canvas'),
-      ctx = node.getContext('2d');
-  ctx.textBaseline = 'top';
-  ctx.font = '32px Arial';
-  ctx.fillText('\ud83d\ude03', 0, 0); // "smiling face with open mouth" emoji
-  return ctx.getImageData(16, 16, 1, 1).data[0] !== 0;
-});
\ No newline at end of file
+/*!
+{
+  "name": "Emoji",
+  "property": "emoji"
+}
+!*/
+/* DOC
+Detects support for emoji character sets.
+*/
+define(['Modernizr', 'createElement', 'test/canvas/text'], function(Modernizr, createElement) {
+  Modernizr.addTest('emoji', function() {
+    if (!Modernizr.canvastext) {
+      return false;
+    }
+    var node = createElement('canvas');
+    var ctx = node.getContext('2d');
+    var backingStoreRatio =
+      ctx.webkitBackingStorePixelRatio ||
+      ctx.mozBackingStorePixelRatio ||
+      ctx.msBackingStorePixelRatio ||
+      ctx.oBackingStorePixelRatio ||
+      ctx.backingStorePixelRatio ||
+      1;
+    var offset = 12 * backingStoreRatio;
+    ctx.fillStyle = '#f00';
+    ctx.textBaseline = 'top';
+    ctx.font = '32px Arial';
+    ctx.fillText('\ud83d\udc28', 0, 0); // U+1F428 KOALA
+    return ctx.getImageData(offset, offset, 1, 1).data[0] !== 0;
+  });
+});
diff --git a/feature-detects/es5-strictmode.js b/feature-detects/es5-strictmode.js
deleted file mode 100644
index bffbe95..0000000
--- a/feature-detects/es5-strictmode.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// strict mode
-
-// test by @kangax
-
-Modernizr.addTest('strictmode', function(){
-	return (function(){ "use strict"; return !this; })(); 
-});
\ No newline at end of file
diff --git a/feature-detects/es5/array.js b/feature-detects/es5/array.js
new file mode 100644
index 0000000..e0bb067
--- /dev/null
+++ b/feature-detects/es5/array.js
@@ -0,0 +1,31 @@
+/*!
+{
+  "name": "ES5 Array",
+  "property": "es5array",
+  "notes": [{
+    "name": "ECMAScript 5.1 Language Specification",
+    "href": "https://www.ecma-international.org/ecma-262/5.1/"
+  }],
+  "polyfills": ["es5shim"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es5"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 5 Array per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es5array', function() {
+    return !!(Array.prototype &&
+      Array.prototype.every &&
+      Array.prototype.filter &&
+      Array.prototype.forEach &&
+      Array.prototype.indexOf &&
+      Array.prototype.lastIndexOf &&
+      Array.prototype.map &&
+      Array.prototype.some &&
+      Array.prototype.reduce &&
+      Array.prototype.reduceRight &&
+      Array.isArray);
+  });
+});
diff --git a/feature-detects/es5/date.js b/feature-detects/es5/date.js
new file mode 100644
index 0000000..b1ce7d0
--- /dev/null
+++ b/feature-detects/es5/date.js
@@ -0,0 +1,32 @@
+/*!
+{
+  "name": "ES5 Date",
+  "property": "es5date",
+  "notes": [{
+    "name": "ECMAScript 5.1 Language Specification",
+    "href": "https://www.ecma-international.org/ecma-262/5.1/"
+  }],
+  "polyfills": ["es5shim"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es5"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 5 Date per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es5date', function() {
+    var isoDate = '2013-04-12T06:06:37.307Z',
+      canParseISODate = false;
+    try {
+      canParseISODate = !!Date.parse(isoDate);
+    } catch (e) {
+      // no ISO date parsing yet
+    }
+    return !!(Date.now &&
+      Date.prototype &&
+      Date.prototype.toISOString &&
+      Date.prototype.toJSON &&
+      canParseISODate);
+  });
+});
diff --git a/feature-detects/es5/function.js b/feature-detects/es5/function.js
new file mode 100644
index 0000000..2c55124
--- /dev/null
+++ b/feature-detects/es5/function.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "ES5 Function",
+  "property": "es5function",
+  "notes": [{
+    "name": "ECMAScript 5.1 Language Specification",
+    "href": "https://www.ecma-international.org/ecma-262/5.1/"
+  }],
+  "polyfills": ["es5shim"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es5"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 5 Function per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es5function', function() {
+    return !!(Function.prototype && Function.prototype.bind);
+  });
+});
diff --git a/feature-detects/es5/object.js b/feature-detects/es5/object.js
new file mode 100644
index 0000000..aad575e
--- /dev/null
+++ b/feature-detects/es5/object.js
@@ -0,0 +1,33 @@
+/*!
+{
+  "name": "ES5 Object",
+  "property": "es5object",
+  "notes": [{
+    "name": "ECMAScript 5.1 Language Specification",
+    "href": "https://www.ecma-international.org/ecma-262/5.1/"
+  }],
+  "polyfills": ["es5shim", "es5sham"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es5"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 5 Object per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es5object', function() {
+    return !!(Object.keys &&
+      Object.create &&
+      Object.getPrototypeOf &&
+      Object.getOwnPropertyNames &&
+      Object.isSealed &&
+      Object.isFrozen &&
+      Object.isExtensible &&
+      Object.getOwnPropertyDescriptor &&
+      Object.defineProperty &&
+      Object.defineProperties &&
+      Object.seal &&
+      Object.freeze &&
+      Object.preventExtensions);
+  });
+});
diff --git a/feature-detects/es5/specification.js b/feature-detects/es5/specification.js
new file mode 100644
index 0000000..77c1767
--- /dev/null
+++ b/feature-detects/es5/specification.js
@@ -0,0 +1,32 @@
+/*!
+{
+  "name": "ES5",
+  "property": "es5",
+  "caniuse": "es5",
+  "notes": [{
+    "name": "ECMAScript 5.1 Language Specification",
+    "href": "https://www.ecma-international.org/ecma-262/5.1/"
+  }],
+  "polyfills": ["es5shim", "es5sham"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es5"]
+}
+!*/
+/* DOC
+Check if browser implements everything as specified in ECMAScript 5.
+*/
+define(['Modernizr', 'test/es5/array', 'test/es5/date', 'test/es5/function', 'test/es5/object', 'test/es5/strictmode', 'test/es5/string', 'test/json', 'test/es5/syntax', 'test/es5/undefined'], function(Modernizr) {
+  Modernizr.addTest('es5', function() {
+    return !!(
+      Modernizr.es5array &&
+      Modernizr.es5date &&
+      Modernizr.es5function &&
+      Modernizr.es5object &&
+      Modernizr.strictmode &&
+      Modernizr.es5string &&
+      Modernizr.json &&
+      Modernizr.es5syntax &&
+      Modernizr.es5undefined
+    );
+  });
+});
diff --git a/feature-detects/es5/strictmode.js b/feature-detects/es5/strictmode.js
new file mode 100644
index 0000000..f83955b
--- /dev/null
+++ b/feature-detects/es5/strictmode.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "ES5 Strict Mode",
+  "property": "strictmode",
+  "caniuse": "use-strict",
+  "notes": [{
+    "name": "ECMAScript 5.1 Language Specification",
+    "href": "https://www.ecma-international.org/ecma-262/5.1/"
+  }],
+  "authors": ["@kangax"],
+  "tags": ["es5"],
+  "builderAliases": ["es5_strictmode"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 5 Object strict mode.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('strictmode', (function() {'use strict'; return !this; })());
+});
diff --git a/feature-detects/es5/string.js b/feature-detects/es5/string.js
new file mode 100644
index 0000000..0ae3b13
--- /dev/null
+++ b/feature-detects/es5/string.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "ES5 String",
+  "property": "es5string",
+  "notes": [{
+    "name": "ECMAScript 5.1 Language Specification",
+    "href": "https://www.ecma-international.org/ecma-262/5.1/"
+  }],
+  "polyfills": ["es5shim"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es5"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 5 String per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es5string', function() {
+    return !!(String.prototype && String.prototype.trim);
+  });
+});
diff --git a/feature-detects/es5/syntax.js b/feature-detects/es5/syntax.js
new file mode 100644
index 0000000..d6af6a6
--- /dev/null
+++ b/feature-detects/es5/syntax.js
@@ -0,0 +1,43 @@
+/*!
+{
+  "name": "ES5 Syntax",
+  "property": "es5syntax",
+  "notes": [{
+    "name": "ECMAScript 5.1 Language Specification",
+    "href": "https://www.ecma-international.org/ecma-262/5.1/"
+  }, {
+    "name": "original implementation of detect code",
+    "href": "https://kangax.github.io/compat-table/es5/"
+  }],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "warnings": ["This detect uses `eval()`, so CSP may be a problem."],
+  "tags": ["es5"]
+}
+!*/
+/* DOC
+Check if browser accepts ECMAScript 5 syntax.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es5syntax', function() {
+    var value, obj, stringAccess, getter, setter, reservedWords, zeroWidthChars;
+    try {
+      /* eslint no-eval: "off" */
+      // Property access on strings
+      stringAccess = eval('"foobar"[3] === "b"');
+      // Getter in property initializer
+      getter = eval('({ get x(){ return 1 } }).x === 1');
+      eval('({ set x(v){ value = v; } }).x = 1');
+      // Setter in property initializer
+      setter = value === 1;
+      // Reserved words as property names
+      eval('obj = ({ if: 1 })');
+      reservedWords = obj['if'] === 1;
+      // Zero-width characters in identifiers
+      zeroWidthChars = eval('_\u200c\u200d = true');
+
+      return stringAccess && getter && setter && reservedWords && zeroWidthChars;
+    } catch (ignore) {
+      return false;
+    }
+  });
+});
diff --git a/feature-detects/es5/undefined.js b/feature-detects/es5/undefined.js
new file mode 100644
index 0000000..336e44f
--- /dev/null
+++ b/feature-detects/es5/undefined.js
@@ -0,0 +1,32 @@
+/*!
+{
+  "name": "ES5 Immutable Undefined",
+  "property": "es5undefined",
+  "notes": [{
+    "name": "ECMAScript 5.1 Language Specification",
+    "href": "https://www.ecma-international.org/ecma-262/5.1/"
+  }, {
+    "name": "original implementation of detect code",
+    "href": "https://kangax.github.io/compat-table/es5/"
+  }],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es5"]
+}
+!*/
+/* DOC
+Check if browser prevents assignment to global `undefined` per ECMAScript 5.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es5undefined', function() {
+    var result, originalUndefined;
+    try {
+      originalUndefined = window.undefined;
+      window.undefined = 12345;
+      result = typeof window.undefined === 'undefined';
+      window.undefined = originalUndefined;
+    } catch (e) {
+      return false;
+    }
+    return result;
+  });
+});
diff --git a/feature-detects/es6/array.js b/feature-detects/es6/array.js
new file mode 100644
index 0000000..2e16018
--- /dev/null
+++ b/feature-detects/es6/array.js
@@ -0,0 +1,31 @@
+/*!
+{
+  "name": "ES6 Array",
+  "property": "es6array",
+  "notes": [{
+    "name": "ECMAScript 6 specification",
+    "href": "https://www.ecma-international.org/ecma-262/6.0/index.html"
+  }, {
+    "name": "Last ECMAScript specification",
+    "href": "https://www.ecma-international.org/ecma-262/index.html"
+  }],
+  "polyfills": ["es6shim"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Array per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es6array', !!(Array.prototype &&
+    Array.prototype.copyWithin &&
+    Array.prototype.fill &&
+    Array.prototype.find &&
+    Array.prototype.findIndex &&
+    Array.prototype.keys &&
+    Array.prototype.entries &&
+    Array.prototype.values &&
+    Array.from &&
+    Array.of));
+});
diff --git a/feature-detects/es6/arrow.js b/feature-detects/es6/arrow.js
new file mode 100644
index 0000000..12645d7
--- /dev/null
+++ b/feature-detects/es6/arrow.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "ES6 Arrow Functions",
+  "property": "arrow",
+  "authors": ["Vincent Riemer"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Arrow Functions per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('arrow', function() {
+    try {
+      // eslint-disable-next-line
+      eval('()=>{}');
+    } catch (e) {
+      return false;
+    }
+    return true;
+  });
+});
diff --git a/feature-detects/es6/class.js b/feature-detects/es6/class.js
new file mode 100644
index 0000000..28d6175
--- /dev/null
+++ b/feature-detects/es6/class.js
@@ -0,0 +1,28 @@
+/*!
+{
+  "name": "ES6 Class",
+  "property": "es6class",
+  "notes": [{
+    "name": "ECMAScript 6 language specification",
+    "href": "https://www.ecma-international.org/ecma-262/6.0/#sec-class-definitions"
+  }],
+  "caniuse": "es6-class",
+  "authors": ["dabretin"],
+  "tags": ["es6"],
+  "builderAliases": ["class"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 class.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es6class', function() {
+    try {
+      // eslint-disable-next-line
+      eval('class A{}');
+    } catch (e) {
+      return false;
+    }
+    return true;
+  });
+});
diff --git a/feature-detects/es6/collections.js b/feature-detects/es6/collections.js
new file mode 100644
index 0000000..8f17819
--- /dev/null
+++ b/feature-detects/es6/collections.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "ES6 Collections",
+  "property": "es6collections",
+  "notes": [{
+    "name": "ECMAScript 6 specification",
+    "href": "https://www.ecma-international.org/ecma-262/6.0/index.html"
+  }, {
+    "name": "Last ECMAScript specification",
+    "href": "https://www.ecma-international.org/ecma-262/index.html"
+  }],
+  "polyfills": ["es6shim", "weakmap"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Map, Set, WeakMap and WeakSet
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es6collections', !!(
+    window.Map && window.Set && window.WeakMap && window.WeakSet
+  ));
+});
diff --git a/feature-detects/es6/generators.js b/feature-detects/es6/generators.js
new file mode 100644
index 0000000..0772005
--- /dev/null
+++ b/feature-detects/es6/generators.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "ES6 Generators",
+  "property": "generators",
+  "authors": ["Michael Kachanovskyi"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Generators per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('generators', function() {
+    try {
+      new Function('function* test() {}')();
+    } catch (e) {
+      return false;
+    }
+    return true;
+  });
+});
diff --git a/feature-detects/es6/math.js b/feature-detects/es6/math.js
new file mode 100644
index 0000000..3b5c13a
--- /dev/null
+++ b/feature-detects/es6/math.js
@@ -0,0 +1,39 @@
+/*!
+{
+  "name": "ES6 Math",
+  "property": "es6math",
+  "notes": [{
+    "name": "ECMAScript 6 specification",
+    "href": "https://www.ecma-international.org/ecma-262/6.0/index.html"
+  }, {
+    "name": "Last ECMAScript specification",
+    "href": "https://www.ecma-international.org/ecma-262/index.html"
+  }],
+  "polyfills": ["es6shim"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Math per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es6math', !!(Math &&
+    Math.clz32 &&
+    Math.cbrt &&
+    Math.imul &&
+    Math.sign &&
+    Math.log10 &&
+    Math.log2 &&
+    Math.log1p &&
+    Math.expm1 &&
+    Math.cosh &&
+    Math.sinh &&
+    Math.tanh &&
+    Math.acosh &&
+    Math.asinh &&
+    Math.atanh &&
+    Math.hypot &&
+    Math.trunc &&
+    Math.fround));
+});
diff --git a/feature-detects/es6/number.js b/feature-detects/es6/number.js
new file mode 100644
index 0000000..132ebf5
--- /dev/null
+++ b/feature-detects/es6/number.js
@@ -0,0 +1,30 @@
+/*!
+{
+  "name": "ES6 Number",
+  "property": "es6number",
+  "notes": [{
+    "name": "ECMAScript 6 specification",
+    "href": "https://www.ecma-international.org/ecma-262/6.0/index.html"
+  }, {
+    "name": "Last ECMAScript specification",
+    "href": "https://www.ecma-international.org/ecma-262/index.html"
+  }],
+  "polyfills": ["es6shim"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Number per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es6number', !!(Number.isFinite &&
+    Number.isInteger &&
+    Number.isSafeInteger &&
+    Number.isNaN &&
+    Number.parseInt &&
+    Number.parseFloat &&
+    Number.isInteger(Number.MAX_SAFE_INTEGER) &&
+    Number.isInteger(Number.MIN_SAFE_INTEGER) &&
+    Number.isFinite(Number.EPSILON)));
+});
diff --git a/feature-detects/es6/object.js b/feature-detects/es6/object.js
new file mode 100644
index 0000000..66c75f0
--- /dev/null
+++ b/feature-detects/es6/object.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "ES6 Object",
+  "property": "es6object",
+  "notes": [{
+    "name": "ECMAScript 6 specification",
+    "href": "https://www.ecma-international.org/ecma-262/6.0/index.html"
+  }, {
+    "name": "Last ECMAScript specification",
+    "href": "https://www.ecma-international.org/ecma-262/index.html"
+  }],
+  "polyfills": ["es6shim"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Object per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es6object', !!(Object.assign &&
+    Object.is &&
+    Object.setPrototypeOf));
+});
diff --git a/feature-detects/es6/promises.js b/feature-detects/es6/promises.js
new file mode 100644
index 0000000..86d9145
--- /dev/null
+++ b/feature-detects/es6/promises.js
@@ -0,0 +1,41 @@
+/*!
+{
+  "name": "ES6 Promises",
+  "property": "promises",
+  "caniuse": "promises",
+  "polyfills": ["es6promises"],
+  "authors": ["Krister Kari", "Jake Archibald"],
+  "tags": ["es6"],
+  "notes": [{
+    "name": "The ES6 promises spec",
+    "href": "https://github.com/domenic/promises-unwrapping"
+  }, {
+    "name": "Chromium dashboard - ES6 Promises",
+    "href": "https://www.chromestatus.com/features/5681726336532480"
+  }, {
+    "name": "JavaScript Promises: an Introduction",
+    "href": "https://developers.google.com/web/fundamentals/primers/promises/"
+  }]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Promises per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('promises', function() {
+    return 'Promise' in window &&
+    // Some of these methods are missing from
+    // Firefox/Chrome experimental implementations
+    'resolve' in window.Promise &&
+    'reject' in window.Promise &&
+    'all' in window.Promise &&
+    'race' in window.Promise &&
+    // Older version of the spec had a resolver object
+    // as the arg rather than a function
+    (function() {
+      var resolve;
+      new window.Promise(function(r) { resolve = r; });
+      return typeof resolve === 'function';
+    }());
+  });
+});
diff --git a/feature-detects/es6/rest-parameters.js b/feature-detects/es6/rest-parameters.js
new file mode 100644
index 0000000..2f9090e
--- /dev/null
+++ b/feature-detects/es6/rest-parameters.js
@@ -0,0 +1,27 @@
+/*!
+{
+  "name": "ES6 Rest parameters",
+  "property": "restparameters",
+  "notes": [{
+    "name": "ECMAScript 6 language specification",
+    "href": "https://www.ecma-international.org/ecma-262/6.0/#sec-function-definitions"
+  }],
+  "caniuse": "rest",
+  "authors": ["dabretin"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Rest parameters per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('restparameters', function() {
+    try {
+      // eslint-disable-next-line
+      eval('function f(...rest) {}');
+    } catch (e) {
+      return false;
+    }
+    return true;
+  });
+});
diff --git a/feature-detects/es6/spread-array.js b/feature-detects/es6/spread-array.js
new file mode 100644
index 0000000..49c1f9b
--- /dev/null
+++ b/feature-detects/es6/spread-array.js
@@ -0,0 +1,32 @@
+/*!
+{
+  "name": "ES6 Spread array",
+  "property": "spreadarray",
+  "notes": [{
+    "name": "ECMAScript Specification",
+    "href": "https://tc39.es/ecma262/#sec-array-initializer"
+  },
+  {
+    "name": "Article",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax"
+  }],
+  "caniuse": "mdn-javascript_operators_spread_spread_in_arrays",
+  "authors": ["dabretin"],
+  "warnings": ["not for object literals (implemented in ES7)"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 spread syntax (in array and function calls)
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('spreadarray', function() {
+    try {
+      // eslint-disable-next-line
+      eval('(function f(){})(...[1])');
+    } catch (e) {
+      return false;
+    }
+    return true;
+  });
+});
diff --git a/feature-detects/es6/string-template.js b/feature-detects/es6/string-template.js
new file mode 100644
index 0000000..afaa72f
--- /dev/null
+++ b/feature-detects/es6/string-template.js
@@ -0,0 +1,27 @@
+/*!
+{
+  "name": "ES6 Template Strings",
+  "property": "stringtemplate",
+  "caniuse": "template-literals",
+  "builderAliases": ["templatestrings"],
+  "notes": [{
+    "name": "ECMAScript 6 draft specification",
+    "href": "https://tc39wiki.calculist.org/es6/template-strings/"
+  }],
+  "authors": ["dabretin"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 String template.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('stringtemplate', function() {
+    try {
+      // eslint-disable-next-line
+      return eval('(function(){var a=1; return `-${a}-`;})()') === '-1-';
+    } catch (e) {
+      return false;
+    }
+  });
+});
diff --git a/feature-detects/es6/string.js b/feature-detects/es6/string.js
new file mode 100644
index 0000000..1f7e097
--- /dev/null
+++ b/feature-detects/es6/string.js
@@ -0,0 +1,28 @@
+/*!
+{
+  "name": "ES6 String",
+  "property": "es6string",
+  "notes": [{
+    "name": "ECMAScript 6 Specification",
+    "href": "https://www.ecma-international.org/ecma-262/6.0/index.html"
+  }, {
+    "name": "Last ECMAScript Specification",
+    "href": "https://www.ecma-international.org/ecma-262/index.html"
+  }],
+  "polyfills": ["es6shim"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["es6"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 String per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es6string', !!(String.fromCodePoint &&
+    String.raw &&
+    String.prototype.codePointAt &&
+    String.prototype.repeat &&
+    String.prototype.startsWith &&
+    String.prototype.endsWith &&
+    String.prototype.includes));
+});
diff --git a/feature-detects/es6/symbol.js b/feature-detects/es6/symbol.js
new file mode 100644
index 0000000..3027547
--- /dev/null
+++ b/feature-detects/es6/symbol.js
@@ -0,0 +1,37 @@
+/*!
+{
+  "name": "ES6 Symbol",
+  "property": "es6symbol",
+  "caniuse": "mdn-javascript_builtins_symbol",
+  "notes": [{
+    "name": "Official ECMAScript 6 specification",
+    "href": "https://www.ecma-international.org/ecma-262/6.0/#sec-symbol-constructor"
+  },{
+    "name": "MDN web docs",
+    "href": "https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Symbol"
+  }],
+  "polyfills": ["es6symbol"],
+  "authors": ["buhichan (@buhichan)"],
+  "tags": ["es6","symbol"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 6 Symbol per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es6symbol', !!(typeof(Symbol)==="function" &&
+    Symbol['for'] &&
+    Symbol.hasInstance &&
+    Symbol.isConcatSpreadable &&
+    Symbol.iterator &&
+    Symbol.keyFor &&
+    Symbol.match &&
+    Symbol.prototype &&
+    Symbol.replace &&
+    Symbol.search &&
+    Symbol.species &&
+    Symbol.split &&
+    Symbol.toPrimitive &&
+    Symbol.toStringTag &&
+    Symbol.unscopables));
+});
diff --git a/feature-detects/es7/array.js b/feature-detects/es7/array.js
new file mode 100644
index 0000000..56d85a2
--- /dev/null
+++ b/feature-detects/es7/array.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "ES7 Array",
+  "property": "es7array",
+  "notes": [{
+    "name": "ECMAScript array Specification",
+    "href": "https://tc39.es/ecma262/#sec-array.prototype.includes"
+  }],
+  "authors": ["dabretin"],
+  "tags": ["es7"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 7 Array per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es7array', !!(Array.prototype &&
+    Array.prototype.includes));
+});
diff --git a/feature-detects/es7/rest-destructuring.js b/feature-detects/es7/rest-destructuring.js
new file mode 100644
index 0000000..2ccb1cd
--- /dev/null
+++ b/feature-detects/es7/rest-destructuring.js
@@ -0,0 +1,36 @@
+/*!
+{
+  "name": "ES7 Rest destructuring",
+  "property": ["restdestructuringarray", "restdestructuringobject"],
+  "caniuse" : "destructuring%20assignment",
+  "notes": [{
+    "name": "ECMAScript Destructuring Assignment Specification",
+    "href": "https://tc39.es/ecma262/#sec-destructuring-assignment"
+  }],
+  "authors": ["dabretin"],
+  "tags": ["es7"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 7 Destructuring Assignment per specification.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('restdestructuringarray', function() {
+    try {
+      // eslint-disable-next-line
+      eval('var [...rest]=[1]');
+    } catch (e) {
+      return false;
+    }
+    return true;
+  });
+  Modernizr.addTest('restdestructuringobject', function() {
+    try {
+      // eslint-disable-next-line
+      eval('var {...rest}={a:1}');
+    } catch (e) {
+      return false;
+    }
+    return true;
+  });
+});
diff --git a/feature-detects/es7/spread-object.js b/feature-detects/es7/spread-object.js
new file mode 100644
index 0000000..25d6bb8
--- /dev/null
+++ b/feature-detects/es7/spread-object.js
@@ -0,0 +1,26 @@
+/*!
+{
+  "name": "ES7 Spread object",
+  "property": "spreadobject",
+  "notes": [{
+    "name": "ECMAScript array Specification",
+    "href": "http://www.ecma-international.org/ecma-262/#sec-object-initializer"
+  }],
+  "authors": ["dabretin"],
+  "tags": ["es7"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 7 object spread syntax 
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('spreadobject', function() {
+    try {
+      // eslint-disable-next-line
+      eval('var a={...{b:1}}');
+    } catch (e) {
+      return false;
+    }
+    return true;
+  });
+});
diff --git a/feature-detects/es8/object.js b/feature-detects/es8/object.js
new file mode 100644
index 0000000..fa54f6b
--- /dev/null
+++ b/feature-detects/es8/object.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "ES8 Object",
+  "property": "es8object",
+  "notes": [{
+    "name": "ECMAScript specification: Object.entries",
+    "href": "https://www.ecma-international.org/ecma-262/#sec-object.entries"
+  }, {
+    "name": "ECMAScript specification: Object.values",
+    "href": "https://www.ecma-international.org/ecma-262/#sec-object.values"
+  }],
+  "caniuse": "object-entries,object-values",
+  "authors": ["dabretin"],
+  "tags": ["es8"]
+}
+!*/
+/* DOC
+Check if browser implements ECMAScript 8 Object.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('es8object', !!(Object.entries &&
+    Object.values));
+});
diff --git a/feature-detects/event-deviceorientation-motion.js b/feature-detects/event-deviceorientation-motion.js
deleted file mode 100644
index 644e671..0000000
--- a/feature-detects/event-deviceorientation-motion.js
+++ /dev/null
@@ -1,11 +0,0 @@
-//By Shi Chuan
-//Part of Device Access aspect of HTML5, same category as geolocation
-//W3C Editor's Draft at http://dev.w3.org/geo/api/spec-source-orientation.html
-//Implementation by iOS Safari at http://goo.gl/fhce3 and http://goo.gl/rLKz8
-
-
-//test for Device Motion Event support, returns boolean value true/false
-Modernizr.addTest('devicemotion', ('DeviceMotionEvent' in window) );
-
-//test for Device Orientation Event support, returns boolean value true/false
-Modernizr.addTest('deviceorientation', ('DeviceOrientationEvent' in window) );
diff --git a/feature-detects/event/customevent.js b/feature-detects/event/customevent.js
new file mode 100644
index 0000000..6a19c5f
--- /dev/null
+++ b/feature-detects/event/customevent.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "CustomEvent",
+  "property": "customevent",
+  "tags": ["customevent"],
+  "authors": ["Alberto Elias"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/DOM-Level-3-Events/#interface-CustomEvent"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/docs/Web/API/CustomEvent"
+  }],
+  "polyfills": ["eventlistener"]
+}
+!*/
+/* DOC
+Detects support for CustomEvent.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('customevent', 'CustomEvent' in window && typeof window.CustomEvent === 'function');
+});
diff --git a/feature-detects/event/deviceorientation-motion.js b/feature-detects/event/deviceorientation-motion.js
new file mode 100644
index 0000000..042724b
--- /dev/null
+++ b/feature-detects/event/deviceorientation-motion.js
@@ -0,0 +1,28 @@
+/*!
+{
+  "name": "Orientation and Motion Events",
+  "property": ["devicemotion", "deviceorientation"],
+  "caniuse": "deviceorientation",
+  "notes": [{
+    "name": "W3C Editor's Draft Spec",
+    "href": "https://w3c.github.io/deviceorientation/"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Detecting_device_orientation"
+  }],
+  "authors": ["Shi Chuan"],
+  "tags": ["event"],
+  "builderAliases": ["event_deviceorientation_motion"]
+}
+!*/
+/* DOC
+Part of Device Access aspect of HTML5, same category as geolocation.
+
+`devicemotion` tests for Device Motion Event support, returns boolean value true/false.
+
+`deviceorientation` tests for Device Orientation Event support, returns boolean value true/false
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('devicemotion', 'DeviceMotionEvent' in window);
+  Modernizr.addTest('deviceorientation', 'DeviceOrientationEvent' in window);
+});
diff --git a/feature-detects/event/eventlistener.js b/feature-detects/event/eventlistener.js
new file mode 100644
index 0000000..c9a59ef
--- /dev/null
+++ b/feature-detects/event/eventlistener.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "Event Listener",
+  "property": "eventlistener",
+  "caniuse": "addeventlistener",
+  "authors": ["Andrew Betts (@triblondon)"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-Registration-interfaces"
+  }],
+  "polyfills": ["eventlistener"]
+}
+!*/
+/* DOC
+Detects native support for addEventListener
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('eventlistener', 'addEventListener' in window);
+});
diff --git a/feature-detects/event/forcetouch.js b/feature-detects/event/forcetouch.js
new file mode 100644
index 0000000..38807b6
--- /dev/null
+++ b/feature-detects/event/forcetouch.js
@@ -0,0 +1,29 @@
+/*!
+{
+  "name": "Force Touch Events",
+  "property": "forcetouch",
+  "authors": ["Kraig Walker"],
+  "notes": [{
+    "name": "Responding to Force Touch Events from JavaScript",
+    "href": "https://developer.apple.com/library/archive/documentation/AppleApplications/Conceptual/SafariJSProgTopics/RespondingtoForceTouchEventsfromJavaScript.html"
+  }]
+}
+!*/
+/* DOC
+Tests whether the browser supports the detection of Force Touch Events.
+Force Touch Events allow custom behaviours and interactions to take place based on the given pressure or change in pressure from a compatible trackpad.
+
+Force Touch events are available in OS X 10.11 and later on devices equipped with Force Touch trackpads.
+*/
+define(['Modernizr', 'hasEvent', 'prefixed'], function(Modernizr, hasEvent, prefixed) {
+  Modernizr.addTest('forcetouch', function() {
+    // github.com/Modernizr/Modernizr/issues/1613
+    // Test if the browser supports the force touch event progression (see notes link)
+    if (!hasEvent(prefixed('mouseforcewillbegin', window, false), window)) {
+      return false;
+    }
+
+    // Test if the browser provides thresholds defining a "force touch" from a normal touch/click event
+    return MouseEvent.WEBKIT_FORCE_AT_MOUSE_DOWN && MouseEvent.WEBKIT_FORCE_AT_FORCE_MOUSE_DOWN;
+  });
+});
diff --git a/feature-detects/event/hashchange.js b/feature-detects/event/hashchange.js
new file mode 100644
index 0000000..5b8f5db
--- /dev/null
+++ b/feature-detects/event/hashchange.js
@@ -0,0 +1,33 @@
+/*!
+{
+  "name": "Hashchange event",
+  "property": "hashchange",
+  "caniuse": "hashchange",
+  "tags": ["history"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onhashchange"
+  }],
+  "polyfills": [
+    "jquery-hashchange",
+    "moo-historymanager",
+    "jquery-ajaxy",
+    "hasher",
+    "shistory"
+  ]
+}
+!*/
+/* DOC
+Detects support for the `hashchange` event, fired when the current location fragment changes.
+*/
+define(['Modernizr', 'hasEvent'], function(Modernizr, hasEvent) {
+  Modernizr.addTest('hashchange', function() {
+    if (hasEvent('hashchange', window) === false) {
+      return false;
+    }
+
+    // documentMode logic from YUI to filter out IE8 Compat Mode
+    //   which false positives.
+    return (document.documentMode === undefined || document.documentMode > 7);
+  });
+});
diff --git a/feature-detects/event/oninput.js b/feature-detects/event/oninput.js
new file mode 100644
index 0000000..7b6e005
--- /dev/null
+++ b/feature-detects/event/oninput.js
@@ -0,0 +1,59 @@
+/*!
+{
+  "name": "onInput Event",
+  "property": "oninput",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/GlobalEventHandlers.oninput"
+  }, {
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/input.html#common-input-element-attributes"
+  }, {
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/210"
+  }],
+  "authors": ["Patrick Kettner"],
+  "tags": ["event"]
+}
+!*/
+/* DOC
+`oninput` tests if the browser is able to detect the input event
+*/
+define(['Modernizr', 'docElement', 'createElement', 'testStyles', 'hasEvent'], function(Modernizr, docElement, createElement, testStyles, hasEvent) {
+
+  Modernizr.addTest('oninput', function() {
+    var input = createElement('input');
+    var supportsOnInput;
+    input.setAttribute('oninput', 'return');
+    input.style.cssText = 'position:fixed;top:0;';
+
+    if (hasEvent('oninput', docElement) || typeof input.oninput === 'function') {
+      return true;
+    }
+
+    // IE doesn't support onInput, so we wrap up the non IE APIs
+    // (createEvent, addEventListener) in a try catch, rather than test for
+    // their trident equivalent.
+    try {
+      // Older Firefox didn't map oninput attribute to oninput property
+      var testEvent = document.createEvent('KeyboardEvent');
+      supportsOnInput = false;
+      var handler = function(e) {
+        supportsOnInput = true;
+        e.preventDefault();
+        e.stopPropagation();
+      };
+
+      testEvent.initKeyEvent('keypress', true, true, window, false, false, false, false, 0, 'e'.charCodeAt(0));
+      docElement.appendChild(input);
+      input.addEventListener('input', handler, false);
+      input.focus();
+      input.dispatchEvent(testEvent);
+      input.removeEventListener('input', handler, false);
+      docElement.removeChild(input);
+    } catch (e) {
+      supportsOnInput = false;
+    }
+    return supportsOnInput;
+  });
+});
diff --git a/feature-detects/event/pointerevents.js b/feature-detects/event/pointerevents.js
new file mode 100644
index 0000000..2d9b515
--- /dev/null
+++ b/feature-detects/event/pointerevents.js
@@ -0,0 +1,37 @@
+/*!
+{
+  "name": "DOM Pointer Events API",
+  "property": "pointerevents",
+  "caniuse": "pointer",
+  "tags": ["input"],
+  "authors": ["Stu Cox"],
+  "notes": [{
+    "name": "W3C Spec (Pointer Events)",
+    "href": "https://www.w3.org/TR/pointerevents/"
+  }, {
+    "name": "W3C Spec (Pointer Events Level 2)",
+    "href": "https://www.w3.org/TR/pointerevents2/"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent"
+  }],
+  "warnings": ["This property name now refers to W3C DOM PointerEvents: https://github.com/Modernizr/Modernizr/issues/548#issuecomment-12812099"],
+  "polyfills": ["pep"]
+}
+!*/
+/* DOC
+Detects support for the DOM Pointer Events API, which provides a unified event interface for pointing input devices, as implemented in IE10+, Edge and Blink.
+*/
+define(['Modernizr', 'domPrefixesAll', 'hasEvent'], function(Modernizr, domPrefixesAll, hasEvent) {
+  // **Test name hijacked!**
+  // Now refers to W3C DOM PointerEvents spec rather than the CSS pointer-events property.
+  Modernizr.addTest('pointerevents', function() {
+    // Cannot use `.prefixed()` for events, so test each prefix
+    for (var i = 0, len = domPrefixesAll.length; i < len; i++) {
+      if (hasEvent(domPrefixesAll[i] + 'pointerdown')) {
+        return true;
+      }
+    }
+    return false;
+  });
+});
diff --git a/feature-detects/event/proximity.js b/feature-detects/event/proximity.js
new file mode 100644
index 0000000..c097f35
--- /dev/null
+++ b/feature-detects/event/proximity.js
@@ -0,0 +1,61 @@
+/*!
+{
+  "name": "Proximity API",
+  "property": "proximity",
+  "authors": ["Cătălin Mariș"],
+  "tags": ["events", "proximity"],
+  "caniuse": "proximity",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Proximity_Events"
+  }, {
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/proximity/"
+  }]
+}
+!*/
+/* DOC
+Detects support for an API that allows users to get proximity related information from the device's proximity sensor.
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+
+  Modernizr.addAsyncTest(function() {
+
+    var timeout;
+    var timeoutTime = 300;
+
+    function advertiseSupport() {
+
+      // Clean up after ourselves
+      clearTimeout(timeout);
+      window.removeEventListener('deviceproximity', advertiseSupport);
+
+      // Advertise support as the browser supports
+      // the API and the device has a proximity sensor
+      addTest('proximity', true);
+
+    }
+
+    // Check if the browser has support for the API
+    if ('ondeviceproximity' in window && 'onuserproximity' in window) {
+
+      // Check if the device has a proximity sensor
+      // ( devices without such a sensor support the events but
+      //   will never fire them resulting in a false positive )
+      window.addEventListener('deviceproximity', advertiseSupport);
+
+      // If the event doesn't fire in a reasonable amount of time,
+      // it means that the device doesn't have a proximity sensor,
+      // thus, we can advertise the "lack" of support
+      timeout = setTimeout(function() {
+        window.removeEventListener('deviceproximity', advertiseSupport);
+        addTest('proximity', false);
+      }, timeoutTime);
+
+    } else {
+      addTest('proximity', false);
+    }
+
+  });
+
+});
diff --git a/feature-detects/exif-orientation.js b/feature-detects/exif-orientation.js
deleted file mode 100644
index 994c13d..0000000
--- a/feature-detects/exif-orientation.js
+++ /dev/null
@@ -1,32 +0,0 @@
-// EXIF Orientation test
-
-// iOS looks at the EXIF Orientation flag in jpgs and rotates the image
-// accordingly. Looks like most desktop browsers just ignore this data.
-
-// description: www.impulseadventure.com/photo/exif-orientation.html
-
-// Bug trackers:
-//    bugzil.la/298619 (unimplemented)
-//    crbug.com/56845 (looks incomplete)
-//    webk.it/19688 (available upstream but its up all ports to turn on individually)
-//
-
-// detect by Paul Sayre
-
-
-(function(){
-
-  var img = new Image();
-
-  img.onerror = function() {
-      Modernizr.addTest('exif-orientation', function () { return false; });
-  };
-
-  img.onload = function() {
-      Modernizr.addTest('exif-orientation', function () { return img.width !== 2; });
-  };
-
-  // There may be a way to shrink this more, it's a 1x2 white jpg with the orientation flag set to 6
-  img.src = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAASUkqAAgAAAABABIBAwABAAAABgASAAAAAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAABAAIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/iiiigD/2Q==";
-
-})();
diff --git a/feature-detects/file-api.js b/feature-detects/file-api.js
deleted file mode 100644
index 7c31e8c..0000000
--- a/feature-detects/file-api.js
+++ /dev/null
@@ -1,12 +0,0 @@
-/**
- * file tests for the File API specification
- *   Tests for objects specific to the File API W3C specification without
- *   being redundant (don't bother testing for Blob since it is assumed
- *   to be the File object's prototype.
- *
- *   Will fail in Safari 5 due to its lack of support for the standards
- *   defined FileReader object
- */
-Modernizr.addTest('filereader', function () {
-    return !!(window.File && window.FileList && window.FileReader);
-});
diff --git a/feature-detects/file-filesystem.js b/feature-detects/file-filesystem.js
deleted file mode 100644
index ced6761..0000000
--- a/feature-detects/file-filesystem.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// Filesystem API
-// dev.w3.org/2009/dap/file-system/file-dir-sys.html
-
-// The API will be present in Chrome incognito, but will throw an exception.
-// See crbug.com/93417
-//
-// By Eric Bidelman (@ebidel)
-
-Modernizr.addTest('filesystem', !!Modernizr.prefixed('requestFileSystem', window));
\ No newline at end of file
diff --git a/feature-detects/file/api.js b/feature-detects/file/api.js
new file mode 100644
index 0000000..b56330e
--- /dev/null
+++ b/feature-detects/file/api.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "File API",
+  "property": "filereader",
+  "caniuse": "fileapi",
+  "notes": [{
+    "name": "W3C Working Draft Spec",
+    "href": "https://www.w3.org/TR/FileAPI/"
+  }],
+  "tags": ["file"],
+  "builderAliases": ["file_api"],
+  "knownBugs": ["Will fail in Safari 5 due to its lack of support for the standards defined FileReader object"]
+}
+!*/
+/* DOC
+`filereader` tests for the File API specification
+
+Tests for objects specific to the File API W3C specification without
+being redundant (don't bother testing for Blob since it is assumed
+to be the File object's prototype.)
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('filereader', !!(window.File && window.FileList && window.FileReader));
+});
diff --git a/feature-detects/file/filesystem.js b/feature-detects/file/filesystem.js
new file mode 100644
index 0000000..dddc248
--- /dev/null
+++ b/feature-detects/file/filesystem.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "Filesystem API",
+  "property": "filesystem",
+  "caniuse": "filesystem",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/file-system-api/"
+  }],
+  "authors": ["Eric Bidelman (@ebidel)"],
+  "tags": ["file"],
+  "builderAliases": ["file_filesystem"],
+  "knownBugs": ["The API will be present in Chrome incognito, but will throw an exception. See crbug.com/93417"]
+}
+!*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('filesystem', !!prefixed('requestFileSystem', window));
+});
diff --git a/feature-detects/flash.js b/feature-detects/flash.js
new file mode 100644
index 0000000..d4801be
--- /dev/null
+++ b/feature-detects/flash.js
@@ -0,0 +1,119 @@
+/*!
+{
+  "name": "Flash",
+  "property": "flash",
+  "tags": ["flash"],
+  "polyfills": ["shumway"]
+}
+!*/
+/* DOC
+Detects Flash support as well as Flash-blocking plugins
+*/
+define(['Modernizr', 'createElement', 'docElement', 'addTest', 'getBody', 'isSVG'], function(Modernizr, createElement, docElement, addTest, getBody, isSVG) {
+  Modernizr.addAsyncTest(function() {
+
+    var attachBody = function(body) {
+      if (!docElement.contains(body)) {
+        docElement.appendChild(body);
+      }
+    };
+    var removeFakeBody = function(body) {
+      // If we’re rockin’ an attached fake body, clean it up
+      if (body.fake && body.parentNode) {
+        body.parentNode.removeChild(body);
+      }
+    };
+    var runTest = function(result, embed) {
+      var bool = !!result;
+      if (bool) {
+        bool = new Boolean(bool);
+        bool.blocked = (result === 'blocked');
+      }
+      addTest('flash', function() { return bool; });
+
+      if (embed && body.contains(embed)) {
+
+        // in case embed has been wrapped, as with ClickToPlugin
+        while (embed.parentNode !== body) {
+          embed = embed.parentNode;
+        }
+
+        body.removeChild(embed);
+      }
+
+    };
+    var easy_detect;
+    var activex;
+    // we wrap activex in a try/catch because when Flash is disabled through
+    // ActiveX controls, it throws an error.
+    try {
+      // Pan is an API that exists for Flash objects.
+      activex = 'ActiveXObject' in window && 'Pan' in new window.ActiveXObject('ShockwaveFlash.ShockwaveFlash');
+    } catch (e) {}
+
+    easy_detect = !(('plugins' in navigator && 'Shockwave Flash' in navigator.plugins) || activex);
+
+    if (easy_detect || isSVG) {
+      runTest(false);
+    }
+    else {
+      // Flash seems to be installed, but it might be blocked. We have to
+      // actually create an element to see what happens to it.
+      var embed = createElement('embed');
+      var body = getBody();
+      var blockedDetect;
+      var inline_style;
+
+      embed.type = 'application/x-shockwave-flash';
+
+      // Need to do this in the body (fake or otherwise) otherwise IE8 complains
+      body.appendChild(embed);
+
+      // Pan doesn't exist in the embed if its IE (its on the ActiveXObject)
+      // so this check is for all other browsers.
+      if (!('Pan' in embed) && !activex) {
+        attachBody(body);
+        runTest('blocked', embed);
+        removeFakeBody(body);
+        return;
+      }
+
+      blockedDetect = function() {
+        // if we used a fake body originally, we need to restart this test, since
+        // we haven't been attached to the DOM, and therefore none of the blockers
+        // have had time to work.
+        attachBody(body);
+        if (!docElement.contains(body)) {
+          body = document.body || body;
+          embed = createElement('embed');
+          embed.type = 'application/x-shockwave-flash';
+          body.appendChild(embed);
+          return setTimeout(blockedDetect, 1000);
+        }
+        if (!docElement.contains(embed)) {
+          runTest('blocked');
+        }
+        else {
+          inline_style = embed.style.cssText;
+          if (inline_style !== '') {
+            // the style of the element has changed automatically. This is a
+            // really poor heuristic, but for lower end Flash blocks, it the
+            // only change they can make.
+            runTest('blocked', embed);
+          }
+          else {
+            runTest(true, embed);
+          }
+        }
+        removeFakeBody(body);
+      };
+
+      // If we have got this far, there is still a chance a userland plugin
+      // is blocking us (either changing the styles, or automatically removing
+      // the element). Both of these require us to take a step back for a moment
+      // to allow for them to get time of the thread, hence a setTimeout.
+      //
+      setTimeout(blockedDetect, 10);
+    }
+  });
+});
diff --git a/feature-detects/forms-fileinput.js b/feature-detects/forms-fileinput.js
deleted file mode 100644
index b33eb97..0000000
--- a/feature-detects/forms-fileinput.js
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-// Detects whether input type="file" is available on the platform
-// E.g. iOS < 6 and some android version don't support this
-
-//  It's useful if you want to hide the upload feature of your app on devices that
-//  don't support it (iphone, ipad, etc).
-
-Modernizr.addTest('fileinput', function() {
-    var elem = document.createElement('input');
-    elem.type = 'file';
-    return !elem.disabled;
-});
diff --git a/feature-detects/forms-formattribute.js b/feature-detects/forms-formattribute.js
deleted file mode 100644
index 6b8e114..0000000
--- a/feature-detects/forms-formattribute.js
+++ /dev/null
@@ -1,29 +0,0 @@
-// Detects whether input form="form_id" is available on the platform
-// E.g. IE 10 (and below), don't support this
-Modernizr.addTest("formattribute", function() {
-	var form = document.createElement("form"),
-		input = document.createElement("input"),
-		div = document.createElement("div"),
-		id = "formtest"+(new Date().getTime()),
-		attr,
-		bool = false;
-
-		form.id = id;
-
-	//IE6/7 confuses the form idl attribute and the form content attribute
-	if(document.createAttribute){
-		attr = document.createAttribute("form");
-		attr.nodeValue = id;
-		input.setAttributeNode(attr);
-		div.appendChild(form);
-		div.appendChild(input);
-
-		document.documentElement.appendChild(div);
-
-		bool = form.elements.length === 1 && input.form == form;
-
-		div.parentNode.removeChild(div);
-	}
-
-	return bool;
-});
\ No newline at end of file
diff --git a/feature-detects/forms-inputnumber-l10n.js b/feature-detects/forms-inputnumber-l10n.js
deleted file mode 100644
index 8746b42..0000000
--- a/feature-detects/forms-inputnumber-l10n.js
+++ /dev/null
@@ -1,32 +0,0 @@
-// input[type="number"] localized input/output
-// // Detects whether input type="number" is capable of receiving and
-// // displaying localized numbers, e.g. with comma separator
-// // https://bugs.webkit.org/show_bug.cgi?id=42484
-// // Based on http://trac.webkit.org/browser/trunk/LayoutTests/fast/forms/script-tests/input-number-keyoperation.js?rev=80096#L9
-// // By Peter Janes
-
-Modernizr.addTest('localizedNumber', function() {
-    var doc = document,
-        el = document.createElement('div'),
-        fake,
-        root,
-        input,
-        diff;
-    root = doc.body || (function() {
-        var de = doc.documentElement;
-        fake = true;
-        return de.insertBefore(doc.createElement('body'), de.firstElementChild || de.firstChild);
-    }());
-    el.innerHTML = '<input type="number" value="1.0" step="0.1"/>';
-    input = el.childNodes[0];
-    root.appendChild(el);
-    input.focus();
-    try {
-        doc.execCommand('InsertText', false, '1,1');
-    } catch(e) { // prevent warnings in IE
-    }
-    diff = input.type === 'number' && input.valueAsNumber === 1.1 && input.checkValidity();
-    root.removeChild(el);
-    fake && root.parentNode.removeChild(root);
-    return diff;
-});
diff --git a/feature-detects/forms-placeholder.js b/feature-detects/forms-placeholder.js
deleted file mode 100644
index e68014b..0000000
--- a/feature-detects/forms-placeholder.js
+++ /dev/null
@@ -1,10 +0,0 @@
-// testing for placeholder attribute in inputs and textareas
-// re-using Modernizr.input if available
-
-Modernizr.addTest('placeholder', function(){
-
-  return !!( 'placeholder' in ( Modernizr.input    || document.createElement('input')    ) && 
-             'placeholder' in ( Modernizr.textarea || document.createElement('textarea') )
-           );
-
-});
diff --git a/feature-detects/forms-speechinput.js b/feature-detects/forms-speechinput.js
deleted file mode 100644
index 48c9021..0000000
--- a/feature-detects/forms-speechinput.js
+++ /dev/null
@@ -1,19 +0,0 @@
-// speech input for inputs
-// by @alrra
-
-
-// `webkitSpeech` in elem 
-// doesn`t work correctly in all versions of Chromium based browsers.
-//   It can return false even if they have support for speech i.imgur.com/2Y40n.png
-//  Testing with 'onwebkitspeechchange' seems to fix this problem
-
-// this detect only checks the webkit version because
-// the speech attribute is likely to be deprecated in favor of a JavaScript API.
-// http://lists.w3.org/Archives/Public/public-webapps/2011OctDec/att-1696/speechapi.html
-
-// FIXME: add support for detecting the new spec'd behavior
-
-Modernizr.addTest('speechinput', function(){
-    var elem = document.createElement('input'); 
-    return 'speech' in elem || 'onwebkitspeechchange' in elem; 
-});
\ No newline at end of file
diff --git a/feature-detects/forms-validation.js b/feature-detects/forms-validation.js
deleted file mode 100644
index 5e5cfa6..0000000
--- a/feature-detects/forms-validation.js
+++ /dev/null
@@ -1,83 +0,0 @@
-// This implementation only tests support for interactive form validation.
-// To check validation for a specific type or a specific other constraint,
-// the test can be combined: 
-//    - Modernizr.inputtypes.numer && Modernizr.formvalidation (browser supports rangeOverflow, typeMismatch etc. for type=number)
-//    - Modernizr.input.required && Modernizr.formvalidation (browser supports valueMissing)
-//
-(function(document, Modernizr){
-
-
-Modernizr.formvalidationapi = false;
-Modernizr.formvalidationmessage = false;
-
-Modernizr.addTest('formvalidation', function(){
-    var form = document.createElement('form');
-    if ( !('checkValidity' in form) ) {
-        return false;
-    }
-    var body = document.body,
-
-    html = document.documentElement,
-
-    bodyFaked = false,
-
-    invaildFired = false,
-
-    input;
-
-    Modernizr.formvalidationapi = true;
-
-    // Prevent form from being submitted
-    form.onsubmit = function(e) {
-        //Opera does not validate form, if submit is prevented
-        if ( !window.opera ) {
-            e.preventDefault();
-        }
-        e.stopPropagation();
-    };
-
-    // Calling form.submit() doesn't trigger interactive validation, 
-    // use a submit button instead
-    //older opera browsers need a name attribute
-    form.innerHTML = '<input name="modTest" required><button></button>';
-
-    // FF4 doesn't trigger "invalid" event if form is not in the DOM tree
-    // Chrome throws error if invalid input is not visible when submitting 
-    form.style.position = 'absolute';
-    form.style.top = '-99999em';
-
-    // We might in <head> in which case we need to create body manually
-    if ( !body ) {
-        bodyFaked = true;
-        body = document.createElement('body');
-        //avoid crashing IE8, if background image is used
-        body.style.background = "";
-        html.appendChild(body);
-    }
-
-    body.appendChild(form);
-
-    input = form.getElementsByTagName('input')[0];	
-
-    // Record whether "invalid" event is fired
-    input.oninvalid = function(e) {
-        invaildFired = true;
-        e.preventDefault();
-        e.stopPropagation();
-    };
-
-    //Opera does not fully support the validationMessage property
-    Modernizr.formvalidationmessage = !!input.validationMessage;
-
-    // Submit form by clicking submit button
-    form.getElementsByTagName('button')[0].click();
-
-    // Don't forget to clean up
-    body.removeChild(form);
-    bodyFaked && html.removeChild(body);
-
-    return invaildFired;
-});
-
-
-})(document, window.Modernizr);
\ No newline at end of file
diff --git a/feature-detects/fullscreen-api.js b/feature-detects/fullscreen-api.js
index 7432571..51a9ae7 100644
--- a/feature-detects/fullscreen-api.js
+++ b/feature-detects/fullscreen-api.js
@@ -1,10 +1,20 @@
-Modernizr.addTest('fullscreen',function(){
-     for(var i = 0; i < Modernizr._domPrefixes.length; i++) {
-        if( document[Modernizr._domPrefixes[i].toLowerCase() + 'CancelFullScreen'])
-            return true;
-     }
-     return !!document['cancelFullScreen'] || false;
+/*!
+{
+  "name": "Fullscreen API",
+  "property": "fullscreen",
+  "caniuse": "fullscreen",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/API/Fullscreen"
+  }],
+  "polyfills": ["screenfulljs"],
+  "builderAliases": ["fullscreen_api"]
+}
+!*/
+/* DOC
+Detects support for the ability to make the current website take over the user's entire screen
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  // github.com/Modernizr/Modernizr/issues/739
+  Modernizr.addTest('fullscreen', !!(prefixed('exitFullscreen', document, false) || prefixed('cancelFullScreen', document, false)));
 });
-
-// http://developer.apple.com/library/safari/documentation/AudioVideo/Conceptual/Using_HTML5_Audio_Video/ControllingMediaWithJavaScript/ControllingMediaWithJavaScript.html#//apple_ref/doc/uid/TP40009523-CH3-SW20
-// https://developer.mozilla.org/en/API/Fullscreen
diff --git a/feature-detects/gamepad.js b/feature-detects/gamepad.js
index 0756289..93427a8 100644
--- a/feature-detects/gamepad.js
+++ b/feature-detects/gamepad.js
@@ -1,12 +1,23 @@
-// GamePad API
-// https://dvcs.w3.org/hg/gamepad/raw-file/default/gamepad.html
-// By Eric Bidelman
-
-// FF has Gamepad API support only in special builds, but not in any release (even behind a flag)
-// Their current implementation has no way to feature detect, only events to bind to.
-//   http://www.html5rocks.com/en/tutorials/doodles/gamepad/#toc-featuredetect
-
-// but a patch will bring them up to date with the spec when it lands (and they'll pass this test)
-//   https://bugzilla.mozilla.org/show_bug.cgi?id=690935
-
-Modernizr.addTest('gamepads', !!Modernizr.prefixed('getGamepads', navigator));
+/*!
+{
+  "name": "GamePad API",
+  "property": "gamepads",
+  "caniuse": "gamepad",
+  "authors": ["Eric Bidelman"],
+  "tags": ["media"],
+  "warnings": ["In new browsers it may return false in non-HTTPS connections"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/gamepad/"
+  }, {
+    "name": "HTML5 Rocks Tutorial",
+    "href": "https://www.html5rocks.com/en/tutorials/doodles/gamepad/#toc-featuredetect"
+  }]
+}
+!*/
+/* DOC
+Detects support for the Gamepad API, for access to gamepads and controllers.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('gamepads', !!prefixed('getGamepads', navigator));
+});
diff --git a/feature-detects/geolocation.js b/feature-detects/geolocation.js
new file mode 100644
index 0000000..85e2657
--- /dev/null
+++ b/feature-detects/geolocation.js
@@ -0,0 +1,34 @@
+/*!
+{
+  "name": "Geolocation API",
+  "property": "geolocation",
+  "caniuse": "geolocation",
+  "tags": ["media"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/WebAPI/Using_geolocation"
+  }],
+  "polyfills": [
+    "joshuabell-polyfill",
+    "webshims",
+    "geo-location-javascript",
+    "geolocation-api-polyfill"
+  ]
+}
+!*/
+/* DOC
+Detects support for the Geolocation API for users to provide their location to web applications.
+*/
+define(['Modernizr'], function(Modernizr) {
+  // geolocation is often considered a trivial feature detect...
+  // Turns out, it's quite tricky to get right:
+  //
+  // Using !!navigator.geolocation does two things we don't want. It:
+  //   1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
+  //   2. Disables page caching in WebKit: webk.it/43956
+  //
+  // Meanwhile, in Firefox < 8, an about:config setting could expose
+  // a false positive that would throw an exception: bugzil.la/688158
+
+  Modernizr.addTest('geolocation', 'geolocation' in navigator);
+});
diff --git a/feature-detects/getusermedia.js b/feature-detects/getusermedia.js
deleted file mode 100644
index 4c38bec..0000000
--- a/feature-detects/getusermedia.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// getUserMedia
-// http://www.whatwg.org/specs/web-apps/current-work/multipage/video-conferencing-and-peer-to-peer-communication.html
-// By Eric Bidelman
-
-Modernizr.addTest('getusermedia', !!Modernizr.prefixed('getUserMedia', navigator));
\ No newline at end of file
diff --git a/feature-detects/hiddenscroll.js b/feature-detects/hiddenscroll.js
new file mode 100644
index 0000000..6b1be8d
--- /dev/null
+++ b/feature-detects/hiddenscroll.js
@@ -0,0 +1,25 @@
+/*!
+{
+  "name": "Hidden Scrollbar",
+  "property": "hiddenscroll",
+  "authors": ["Oleg Korsunsky"],
+  "tags": ["overlay"],
+  "notes": [{
+    "name": "Overlay Scrollbar description",
+    "href": "https://developer.apple.com/library/mac/releasenotes/MacOSX/WhatsNewInOSX/Articles/MacOSX10_7.html#//apple_ref/doc/uid/TP40010355-SW39"
+  }, {
+    "name": "Video example of overlay scrollbars",
+    "href": "https://gfycat.com/FoolishMeaslyAtlanticsharpnosepuffer"
+  }]
+}
+!*/
+/* DOC
+Detects overlay scrollbars (when scrollbars on overflowed blocks are visible). This is found most commonly on mobile and OS X.
+*/
+define(['Modernizr', 'testStyles'], function(Modernizr, testStyles) {
+  Modernizr.addTest('hiddenscroll', function() {
+    return testStyles('#modernizr {width:100px;height:100px;overflow:scroll}', function(elem) {
+      return elem.offsetWidth === elem.clientWidth;
+    });
+  });
+});
diff --git a/feature-detects/history.js b/feature-detects/history.js
new file mode 100644
index 0000000..6a266eb
--- /dev/null
+++ b/feature-detects/history.js
@@ -0,0 +1,52 @@
+/*!
+{
+  "name": "History API",
+  "property": "history",
+  "caniuse": "history",
+  "tags": ["history"],
+  "authors": ["Hay Kranen", "Alexander Farkas"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/html51/browsers.html#the-history-interface"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/window.history"
+  }],
+  "polyfills": ["historyjs", "html5historyapi"]
+}
+!*/
+/* DOC
+Detects support for the History API for manipulating the browser session history.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('history', function() {
+    // Issue #733
+    // The stock browser on Android 2.2 & 2.3, and 4.0.x returns positive on history support
+    // Unfortunately support is really buggy and there is no clean way to detect
+    // these bugs, so we fall back to a user agent sniff :(
+    var ua = navigator.userAgent;
+    
+    // Some browsers allow to have empty userAgent.
+    // Therefore, we need to check ua before using "indexOf" on it.
+    if(!ua) {
+      return false;
+    }
+
+    // We only want Android 2 and 4.0, stock browser, and not Chrome which identifies
+    // itself as 'Mobile Safari' as well, nor Windows Phone (issue #1471).
+    if ((ua.indexOf('Android 2.') !== -1 ||
+        (ua.indexOf('Android 4.0') !== -1)) &&
+        ua.indexOf('Mobile Safari') !== -1 &&
+        ua.indexOf('Chrome') === -1 &&
+        ua.indexOf('Windows Phone') === -1 &&
+    // Since all documents on file:// share an origin, the History apis are
+    // blocked there as well
+        location.protocol !== 'file:'
+    ) {
+      return false;
+    }
+
+    // Return the regular check
+    return (window.history && 'pushState' in window.history);
+  });
+});
diff --git a/feature-detects/htmlimports.js b/feature-detects/htmlimports.js
new file mode 100644
index 0000000..b62dfad
--- /dev/null
+++ b/feature-detects/htmlimports.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "HTML Imports",
+  "property": "htmlimports",
+  "tags": ["html", "import"],
+  "polyfills": ["polymer-htmlimports"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://w3c.github.io/webcomponents/spec/imports/"
+  }, {
+    "name": "HTML Imports - #include for the web",
+    "href": "https://www.html5rocks.com/en/tutorials/webcomponents/imports/"
+  }]
+}
+!*/
+/* DOC
+Detects support for HTML import, a feature that is used for loading in Web Components.
+ */
+define(['Modernizr', 'addTest', 'createElement'], function(Modernizr, addTest, createElement) {
+  Modernizr.addTest('htmlimports', 'import' in createElement('link'));
+});
diff --git a/feature-detects/ie8compat.js b/feature-detects/ie8compat.js
index c95e56a..6f6aa53 100644
--- a/feature-detects/ie8compat.js
+++ b/feature-detects/ie8compat.js
@@ -1,12 +1,18 @@
+/*!
+{
+  "name": "IE8 compat mode",
+  "property": "ie8compat",
+  "authors": ["Erich Ocean"]
+}
+!*/
+/* DOC
+Detects whether or not the current browser is IE8 in compatibility mode (i.e. acting as IE7).
+*/
+define(['Modernizr'], function(Modernizr) {
+  // In this case, IE8 will be acting as IE7. You may choose to remove features in this case.
 
-// IE8 compat mode aka Fake IE7
-// by Erich Ocean
+  // related:
+  // james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments/
 
-// In this case, IE8 will be acting as IE7. You may choose to remove features in this case.
-
-// related:
-// james.padolsey.com/javascript/detect-ie-in-js-using-conditional-comments/
-
-Modernizr.addTest('ie8compat',function(){
-    return (!window.addEventListener && document.documentMode && document.documentMode === 7);
+  Modernizr.addTest('ie8compat', (!window.addEventListener && !!document.documentMode && document.documentMode === 7));
 });
diff --git a/feature-detects/iframe-sandbox.js b/feature-detects/iframe-sandbox.js
deleted file mode 100644
index 869c94a..0000000
--- a/feature-detects/iframe-sandbox.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Test for `sandbox` attribute in iframes.
-//
-// Spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-sandbox
-
-Modernizr.addTest('sandbox', 'sandbox' in document.createElement('iframe'));
diff --git a/feature-detects/iframe-seamless.js b/feature-detects/iframe-seamless.js
deleted file mode 100644
index 247b9e6..0000000
--- a/feature-detects/iframe-seamless.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Test for `seamless` attribute in iframes.
-//
-// Spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-seamless
-
-Modernizr.addTest('seamless', 'seamless' in document.createElement('iframe'));
diff --git a/feature-detects/iframe-srcdoc.js b/feature-detects/iframe-srcdoc.js
deleted file mode 100644
index 1769858..0000000
--- a/feature-detects/iframe-srcdoc.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// Test for `srcdoc` attribute in iframes.
-//
-// Spec: http://www.whatwg.org/specs/web-apps/current-work/multipage/the-iframe-element.html#attr-iframe-srcdoc
-
-Modernizr.addTest('srcdoc', 'srcdoc' in document.createElement('iframe'));
diff --git a/feature-detects/iframe/sandbox.js b/feature-detects/iframe/sandbox.js
new file mode 100644
index 0000000..0d97b5c
--- /dev/null
+++ b/feature-detects/iframe/sandbox.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "iframe[sandbox] Attribute",
+  "property": "sandbox",
+  "caniuse": "iframe-sandbox",
+  "tags": ["iframe"],
+  "builderAliases": ["iframe_sandbox"],
+  "notes": [
+  {
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-sandbox"
+  }],
+  "knownBugs": ["False-positive on Firefox < 29"]
+}
+!*/
+/* DOC
+Test for `sandbox` attribute in iframes.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('sandbox', 'sandbox' in createElement('iframe'));
+});
diff --git a/feature-detects/iframe/seamless.js b/feature-detects/iframe/seamless.js
new file mode 100644
index 0000000..15a0b5b
--- /dev/null
+++ b/feature-detects/iframe/seamless.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "iframe[seamless] Attribute",
+  "property": "seamless",
+  "tags": ["iframe"],
+  "builderAliases": ["iframe_seamless"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-seamless"
+  }]
+}
+!*/
+/* DOC
+Test for `seamless` attribute in iframes.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('seamless', 'seamless' in createElement('iframe'));
+});
diff --git a/feature-detects/iframe/srcdoc.js b/feature-detects/iframe/srcdoc.js
new file mode 100644
index 0000000..1c25e23
--- /dev/null
+++ b/feature-detects/iframe/srcdoc.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "iframe[srcdoc] Attribute",
+  "property": "srcdoc",
+  "caniuse": "iframe-srcdoc",
+  "tags": ["iframe"],
+  "builderAliases": ["iframe_srcdoc"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#attr-iframe-srcdoc"
+  }]
+}
+!*/
+/* DOC
+Test for `srcdoc` attribute in iframes.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('srcdoc', 'srcdoc' in createElement('iframe'));
+});
diff --git a/feature-detects/img-apng.js b/feature-detects/img-apng.js
deleted file mode 100644
index 069ac93..0000000
--- a/feature-detects/img-apng.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// Animated PNG
-// http://en.wikipedia.org/wiki/APNG
-// By Addy Osmani
-(function () {
-
-    if (!Modernizr.canvas) return false;
-    
-    var image = new Image(),
-        canvas = document.createElement('canvas'),
-        ctx = canvas.getContext('2d');
-
-
-    image.onload = function () {
-        Modernizr.addTest('apng', function () {
-            if (typeof canvas.getContext == 'undefined') {
-                return false;
-            } else {
-                ctx.drawImage(image, 0, 0);
-                return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
-            }
-        });
-    };
-
-    image.src = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAAcMq2TYAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAGmZjVEwAAAAAAAAAAQAAAAEAAAAAAAAAAAD6A+gBAbNU+2sAAAARZmRBVAAAAAEImWNgYGBgAAAABQAB6MzFdgAAAABJRU5ErkJggg==";
-
-}());
diff --git a/feature-detects/img-webp.js b/feature-detects/img-webp.js
deleted file mode 100644
index 360cdf8..0000000
--- a/feature-detects/img-webp.js
+++ /dev/null
@@ -1,20 +0,0 @@
-// code.google.com/speed/webp/
-// by rich bradshaw, ryan seddon, and paul irish
-
-
-// This test is asynchronous. Watch out.
-
-(function(){
-
-  var image = new Image();
-
-  image.onerror = function() {
-      Modernizr.addTest('webp', false);
-  };  
-  image.onload = function() {
-      Modernizr.addTest('webp', function() { return image.width == 1; });
-  };
-
-  image.src = 'data:image/webp;base64,UklGRiwAAABXRUJQVlA4ICAAAAAUAgCdASoBAAEAL/3+/3+CAB/AAAFzrNsAAP5QAAAAAA==';
-
-}());
\ No newline at end of file
diff --git a/feature-detects/img/apng.js b/feature-detects/img/apng.js
new file mode 100644
index 0000000..bee1285
--- /dev/null
+++ b/feature-detects/img/apng.js
@@ -0,0 +1,42 @@
+/*!
+{
+  "name": "Animated PNG",
+  "async": true,
+  "property": "apng",
+  "caniuse": "apng",
+  "tags": ["image"],
+  "builderAliases": ["img_apng"],
+  "notes": [{
+    "name": "Wikipedia Article",
+    "href": "https://en.wikipedia.org/wiki/APNG"
+  }]
+}
+!*/
+/* DOC
+Test for animated png support.
+*/
+define(['Modernizr', 'createElement', 'addTest', 'test/canvas/canvas'], function(Modernizr, createElement, addTest) {
+  Modernizr.addAsyncTest(function() {
+    if (!Modernizr.canvas) {
+      return false;
+    }
+
+    var image = new Image();
+    var canvas = createElement('canvas');
+    var ctx = canvas.getContext('2d');
+
+    image.onload = function() {
+      addTest('apng', function() {
+        if (typeof canvas.getContext === 'undefined') {
+          return false;
+        }
+        else {
+          ctx.drawImage(image, 0, 0);
+          return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
+        }
+      });
+    };
+
+    image.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACGFjVEwAAAABAAAAAcMq2TYAAAANSURBVAiZY2BgYPgPAAEEAQB9ssjfAAAAGmZjVEwAAAAAAAAAAQAAAAEAAAAAAAAAAAD6A+gBAbNU+2sAAAARZmRBVAAAAAEImWNgYGBgAAAABQAB6MzFdgAAAABJRU5ErkJggg==';
+  });
+});
diff --git a/feature-detects/img/avif.js b/feature-detects/img/avif.js
new file mode 100644
index 0000000..9c14a9e
--- /dev/null
+++ b/feature-detects/img/avif.js
@@ -0,0 +1,30 @@
+/*!
+{
+  "name": "AVIF",
+  "async": true,
+  "property": "avif",
+  "caniuse": "avif",
+  "tags": ["image"],
+  "authors": ["Markel Ferro (@MarkelFe)"],
+  "polyfills": ["avifjs"],
+  "notes": [{
+    "name": "Avif Spec",
+    "href": "https://aomediacodec.github.io/av1-avif/"
+  }]
+}
+!*/
+/* DOC
+Test for AVIF support
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+
+    Modernizr.addAsyncTest(function() {
+      var image = new Image();
+  
+      image.onload = image.onerror = function() {
+        addTest('avif', image.width === 1);
+      };
+  
+      image.src = 'data:image/avif;base64,AAAAIGZ0eXBhdmlmAAAAAGF2aWZtaWYxbWlhZk1BMUIAAAEcbWV0YQAAAAAAAABIaGRscgAAAAAAAAAAcGljdAAAAAAAAAAAAAAAAGNhdmlmIC0gaHR0cHM6Ly9naXRodWIuY29tL2xpbmstdS9jYXZpZgAAAAAeaWxvYwAAAAAEQAABAAEAAAAAAUQAAQAAABcAAAAqaWluZgEAAAAAAAABAAAAGmluZmUCAAAAAAEAAGF2MDFJbWFnZQAAAAAOcGl0bQAAAAAAAQAAAHJpcHJwAAAAUmlwY28AAAAQcGFzcAAAAAEAAAABAAAAFGlzcGUAAAAAAAAAAQAAAAEAAAAQcGl4aQAAAAADCAgIAAAAFmF2MUOBAAwACggYAAYICGgIIAAAABhpcG1hAAAAAAAAAAEAAQUBAoMDhAAAAB9tZGF0CggYAAYICGgIIBoFHiAAAEQiBACwDoA=';
+    });
+  });
\ No newline at end of file
diff --git a/feature-detects/img/crossorigin.js b/feature-detects/img/crossorigin.js
new file mode 100644
index 0000000..018a8c5
--- /dev/null
+++ b/feature-detects/img/crossorigin.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "Image crossOrigin",
+  "property": "imgcrossorigin",
+  "tags": ["image"],
+  "notes": [{
+    "name": "Cross Domain Images and the Tainted Canvas",
+    "href": "https://blog.codepen.io/2013/10/08/cross-domain-images-tainted-canvas/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the crossOrigin attribute on images, which allow for cross domain images inside of a canvas without tainting it
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('imgcrossorigin', 'crossOrigin' in createElement('img'));
+});
diff --git a/feature-detects/img/exif-orientation.js b/feature-detects/img/exif-orientation.js
new file mode 100644
index 0000000..5ee321b
--- /dev/null
+++ b/feature-detects/img/exif-orientation.js
@@ -0,0 +1,42 @@
+/*!
+{
+  "name": "EXIF Orientation",
+  "property": "exiforientation",
+  "tags": ["image"],
+  "builderAliases": ["exif_orientation"],
+  "async": true,
+  "authors": ["Paul Sayre"],
+  "notes": [{
+    "name": "Article by Dave Perrett",
+    "href": "https://www.daveperrett.com/articles/2012/07/28/exif-orientation-handling-is-a-ghetto/"
+  }, {
+    "name": "Article by Calvin Hass",
+    "href": "https://www.impulseadventure.com/photo/exif-orientation.html"
+  }]
+}
+!*/
+/* DOC
+Detects support for EXIF Orientation in JPEG images.
+
+iOS looks at the EXIF Orientation flag in JPEGs and rotates the image accordingly. Most desktop browsers just ignore this data.
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+  // Bug trackers:
+  //    bugzil.la/298619 (unimplemented)
+  //    crbug.com/56845 (looks incomplete)
+  //    webk.it/19688 (available upstream but its up all ports to turn on individually)
+  Modernizr.addAsyncTest(function() {
+    var img = new Image();
+
+    img.onerror = function() {
+      addTest('exiforientation', false, {aliases: ['exif-orientation']});
+    };
+
+    img.onload = function() {
+      addTest('exiforientation', img.width !== 2, {aliases: ['exif-orientation']});
+    };
+
+    // There may be a way to shrink this more, it's a 1x2 white jpg with the orientation flag set to 6
+    img.src = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD/4QAiRXhpZgAASUkqAAgAAAABABIBAwABAAAABgASAAAAAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAABAAIDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+/iiiigD/2Q==';
+  });
+});
diff --git a/feature-detects/img/jpeg2000.js b/feature-detects/img/jpeg2000.js
new file mode 100644
index 0000000..0bf40ae
--- /dev/null
+++ b/feature-detects/img/jpeg2000.js
@@ -0,0 +1,30 @@
+/*!
+{
+  "name": "JPEG 2000",
+  "async": true,
+  "aliases": ["jpeg-2000", "jpg2"],
+  "property": "jpeg2000",
+  "caniuse": "jpeg2000",
+  "tags": ["image"],
+  "authors": ["@eric_wvgg"],
+  "notes": [{
+    "name": "Wikipedia Article",
+    "href": "https://en.wikipedia.org/wiki/JPEG_2000"
+  }]
+}
+!*/
+/* DOC
+Test for JPEG 2000 support
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+
+  Modernizr.addAsyncTest(function() {
+    var image = new Image();
+
+    image.onload = image.onerror = function() {
+      addTest('jpeg2000', image.width === 1);
+    };
+
+    image.src = 'data:image/jp2;base64,/0//UQAyAAAAAAABAAAAAgAAAAAAAAAAAAAABAAAAAQAAAAAAAAAAAAEBwEBBwEBBwEBBwEB/1IADAAAAAEAAAQEAAH/XAAEQED/ZAAlAAFDcmVhdGVkIGJ5IE9wZW5KUEVHIHZlcnNpb24gMi4wLjD/kAAKAAAAAABYAAH/UwAJAQAABAQAAf9dAAUBQED/UwAJAgAABAQAAf9dAAUCQED/UwAJAwAABAQAAf9dAAUDQED/k8+kEAGvz6QQAa/PpBABr994EAk//9k=';
+  });
+});
diff --git a/feature-detects/img/jpegxr.js b/feature-detects/img/jpegxr.js
new file mode 100644
index 0000000..98d23bf
--- /dev/null
+++ b/feature-detects/img/jpegxr.js
@@ -0,0 +1,28 @@
+/*!
+{
+  "name": "JPEG XR (extended range)",
+  "async": true,
+  "aliases": ["jpeg-xr"],
+  "property": "jpegxr",
+  "tags": ["image"],
+  "notes": [{
+    "name": "Wikipedia Article",
+    "href": "https://en.wikipedia.org/wiki/JPEG_XR"
+  }]
+}
+!*/
+/* DOC
+Test for JPEG XR support
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+
+  Modernizr.addAsyncTest(function() {
+    var image = new Image();
+
+    image.onload = image.onerror = function() {
+      addTest('jpegxr', image.width === 1, {aliases: ['jpeg-xr']});
+    };
+
+    image.src = 'data:image/vnd.ms-photo;base64,SUm8AQgAAAAFAAG8AQAQAAAASgAAAIC8BAABAAAAAQAAAIG8BAABAAAAAQAAAMC8BAABAAAAWgAAAMG8BAABAAAAHwAAAAAAAAAkw91vA07+S7GFPXd2jckNV01QSE9UTwAZAYBxAAAAABP/gAAEb/8AAQAAAQAAAA==';
+  });
+});
diff --git a/feature-detects/img/lazyloading.js b/feature-detects/img/lazyloading.js
new file mode 100644
index 0000000..9fbe962
--- /dev/null
+++ b/feature-detects/img/lazyloading.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "image and iframe native lazy loading",
+  "property": "lazyloading",
+  "caniuse": "loading-lazy-attr",
+  "tags": ["image", "lazy", "loading"],
+  "notes": [{
+    "name": "Native image lazy-loading for the web",
+    "href": "https://addyosmani.com/blog/lazy-loading/"
+  }]
+}
+!*/
+/* DOC
+Test for the loading attribute of images and iframes
+*/
+
+define(['Modernizr'], function (Modernizr) {
+  Modernizr.addTest('lazyloading', 'loading' in HTMLImageElement.prototype);
+});
diff --git a/feature-detects/img/sizes.js b/feature-detects/img/sizes.js
new file mode 100644
index 0000000..501c11e
--- /dev/null
+++ b/feature-detects/img/sizes.js
@@ -0,0 +1,46 @@
+/*!
+{
+  "name": "sizes attribute",
+  "async": true,
+  "property": "sizes",
+  "tags": ["image"],
+  "authors": ["Mat Marquis"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/embedded-content.html#the-img-element"
+  }, {
+    "name": "Srcset and sizes",
+    "href": "https://ericportis.com/posts/2014/srcset-sizes/"
+  }]
+}
+!*/
+/* DOC
+Test for the `sizes` attribute on images
+*/
+define(['Modernizr', 'createElement', 'addTest'], function(Modernizr, createElement, addTest) {
+  Modernizr.addAsyncTest(function() {
+    var width1, width2, test;
+    var image = createElement('img');
+    // in a perfect world this would be the test...
+    var isSizes = 'sizes' in image;
+
+    // ... but we need to deal with Safari 9...
+    if (!isSizes && ('srcset' in image)) {
+      width2 = 'data:image/gif;base64,R0lGODlhAgABAPAAAP///wAAACH5BAAAAAAALAAAAAACAAEAAAICBAoAOw==';
+      width1 = 'data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==';
+
+      test = function() {
+        addTest('sizes', image.width === 2);
+      };
+
+      image.onload = test;
+      image.onerror = test;
+      image.setAttribute('sizes', '9px');
+
+      image.srcset = width1 + ' 1w,' + width2 + ' 8w';
+      image.src = width1;
+    } else {
+      addTest('sizes', isSizes);
+    }
+  });
+});
diff --git a/feature-detects/img/srcset.js b/feature-detects/img/srcset.js
new file mode 100644
index 0000000..e9c49db
--- /dev/null
+++ b/feature-detects/img/srcset.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "srcset attribute",
+  "property": "srcset",
+  "caniuse": "srcset",
+  "tags": ["image"],
+  "notes": [{
+    "name": "Smashing Magazine Article",
+    "href": "https://www.smashingmagazine.com/2013/08/webkit-implements-srcset-and-why-its-a-good-thing/"
+  }, {
+    "name": "Generate multi-resolution images for srcset with Grunt",
+    "href": "https://addyosmani.com/blog/generate-multi-resolution-images-for-srcset-with-grunt/"
+  }]
+}
+!*/
+/* DOC
+Test for the srcset attribute of images
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('srcset', 'srcset' in createElement('img'));
+});
diff --git a/feature-detects/img/webp-alpha.js b/feature-detects/img/webp-alpha.js
new file mode 100644
index 0000000..dcc0eab
--- /dev/null
+++ b/feature-detects/img/webp-alpha.js
@@ -0,0 +1,38 @@
+/*!
+{
+  "name": "Webp Alpha",
+  "async": true,
+  "property": "webpalpha",
+  "aliases": ["webp-alpha"],
+  "tags": ["image"],
+  "authors": ["Krister Kari", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
+  "notes": [{
+    "name": "WebP Info",
+    "href": "https://developers.google.com/speed/webp/"
+  }, {
+    "name": "Article about WebP support",
+    "href": "https://optimus.keycdn.com/support/webp-support/"
+  }, {
+    "name": "Chromium WebP announcement",
+    "href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1"
+  }]
+}
+!*/
+/* DOC
+Tests for transparent webp support.
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+  Modernizr.addAsyncTest(function() {
+    var image = new Image();
+
+    image.onerror = function() {
+      addTest('webpalpha', false, {aliases: ['webp-alpha']});
+    };
+
+    image.onload = function() {
+      addTest('webpalpha', image.width === 1, {aliases: ['webp-alpha']});
+    };
+
+    image.src = 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==';
+  });
+});
diff --git a/feature-detects/img/webp-animation.js b/feature-detects/img/webp-animation.js
new file mode 100644
index 0000000..3162b80
--- /dev/null
+++ b/feature-detects/img/webp-animation.js
@@ -0,0 +1,35 @@
+/*!
+{
+  "name": "Webp Animation",
+  "async": true,
+  "property": "webpanimation",
+  "aliases": ["webp-animation"],
+  "tags": ["image"],
+  "authors": ["Krister Kari", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
+  "notes": [{
+    "name": "WebP Info",
+    "href": "https://developers.google.com/speed/webp/"
+  }, {
+    "name": "Chromium blog - Chrome 32 Beta: Animated WebP images and faster Chrome for Android touch input",
+    "href": "https://blog.chromium.org/2013/11/chrome-32-beta-animated-webp-images-and.html"
+  }]
+}
+!*/
+/* DOC
+Tests for animated webp support.
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+  Modernizr.addAsyncTest(function() {
+    var image = new Image();
+
+    image.onerror = function() {
+      addTest('webpanimation', false, {aliases: ['webp-animation']});
+    };
+
+    image.onload = function() {
+      addTest('webpanimation', image.width === 1, {aliases: ['webp-animation']});
+    };
+
+    image.src = 'data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA';
+  });
+});
diff --git a/feature-detects/img/webp-lossless.js b/feature-detects/img/webp-lossless.js
new file mode 100644
index 0000000..fb39972
--- /dev/null
+++ b/feature-detects/img/webp-lossless.js
@@ -0,0 +1,34 @@
+/*!
+{
+  "name": "Webp Lossless",
+  "async": true,
+  "property": ["webplossless", "webp-lossless"],
+  "tags": ["image"],
+  "authors": ["@amandeep", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
+  "notes": [{
+    "name": "Webp Info",
+    "href": "https://developers.google.com/speed/webp/"
+  }, {
+    "name": "Webp Lossless Spec",
+    "href": "https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification"
+  }]
+}
+!*/
+/* DOC
+Tests for non-alpha lossless webp support.
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+  Modernizr.addAsyncTest(function() {
+    var image = new Image();
+
+    image.onerror = function() {
+      addTest('webplossless', false, {aliases: ['webp-lossless']});
+    };
+
+    image.onload = function() {
+      addTest('webplossless', image.width === 1, {aliases: ['webp-lossless']});
+    };
+
+    image.src = 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=';
+  });
+});
diff --git a/feature-detects/img/webp.js b/feature-detects/img/webp.js
new file mode 100644
index 0000000..a509e00
--- /dev/null
+++ b/feature-detects/img/webp.js
@@ -0,0 +1,96 @@
+/*!
+{
+  "name": "Webp",
+  "async": true,
+  "property": "webp",
+  "caniuse": "webp",
+  "tags": ["image"],
+  "builderAliases": ["img_webp"],
+  "authors": ["Krister Kari", "@amandeep", "Rich Bradshaw", "Ryan Seddon", "Paul Irish"],
+  "notes": [{
+    "name": "Webp Info",
+    "href": "https://developers.google.com/speed/webp/"
+  }, {
+    "name": "Chromium blog - Chrome 32 Beta: Animated WebP images and faster Chrome for Android touch input",
+    "href": "https://blog.chromium.org/2013/11/chrome-32-beta-animated-webp-images-and.html"
+  }, {
+    "name": "Webp Lossless Spec",
+    "href": "https://developers.google.com/speed/webp/docs/webp_lossless_bitstream_specification"
+  }, {
+    "name": "Article about WebP support",
+    "href": "https://optimus.keycdn.com/support/webp-support/"
+  }, {
+    "name": "Chromium WebP announcement",
+    "href": "https://blog.chromium.org/2011/11/lossless-and-transparency-encoding-in.html?m=1"
+  }]
+}
+!*/
+/* DOC
+Tests for lossy, non-alpha webp support.
+
+Tests for all forms of webp support (lossless, lossy, alpha, and animated)..
+
+  Modernizr.webp              // Basic support (lossy)
+  Modernizr.webp.lossless     // Lossless
+  Modernizr.webp.alpha        // Alpha (both lossy and lossless)
+  Modernizr.webp.animation    // Animated WebP
+
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+
+  Modernizr.addAsyncTest(function() {
+
+    var webpTests = [{
+      'uri': 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=',
+      'name': 'webp'
+    }, {
+      'uri': 'data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==',
+      'name': 'webp.alpha'
+    }, {
+      'uri': 'data:image/webp;base64,UklGRlIAAABXRUJQVlA4WAoAAAASAAAAAAAAAAAAQU5JTQYAAAD/////AABBTk1GJgAAAAAAAAAAAAAAAAAAAGQAAABWUDhMDQAAAC8AAAAQBxAREYiI/gcA',
+      'name': 'webp.animation'
+    }, {
+      'uri': 'data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=',
+      'name': 'webp.lossless'
+    }];
+
+    var webp = webpTests.shift();
+    function test(name, uri, cb) {
+
+      var image = new Image();
+
+      function addResult(event) {
+        // if the event is from 'onload', check the see if the image's width is
+        // 1 pixel (which indicates support). otherwise, it fails
+
+        var result = event && event.type === 'load' ? image.width === 1 : false;
+        var baseTest = name === 'webp';
+
+        // if it is the base test, and the result is false, just set a literal false
+        // rather than use the Boolean constructor
+        addTest(name, (baseTest && result) ? new Boolean(result) : result);
+
+        if (cb) {
+          cb(event);
+        }
+      }
+
+      image.onerror = addResult;
+      image.onload = addResult;
+
+      image.src = uri;
+    }
+
+    // test for webp support in general
+    test(webp.name, webp.uri, function(e) {
+      // if the webp test loaded, test everything else.
+      if (e && e.type === 'load') {
+        for (var i = 0; i < webpTests.length; i++) {
+          test(webpTests[i].name, webpTests[i].uri);
+        }
+      }
+    });
+
+  });
+
+});
diff --git a/feature-detects/input/capture.js b/feature-detects/input/capture.js
new file mode 100644
index 0000000..a03bbe9
--- /dev/null
+++ b/feature-detects/input/capture.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "input[capture] Attribute",
+  "property": "capture",
+  "tags": ["video", "image", "audio", "media", "attribute"],
+  "notes": [{
+    "name": "W3C Draft Spec",
+    "href": "https://www.w3.org/TR/html-media-capture/"
+  }]
+}
+!*/
+/* DOC
+When used on an `<input>`, this attribute signifies that the resource it takes should be generated via device's camera, camcorder, sound recorder.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  // testing for capture attribute in inputs
+  Modernizr.addTest('capture', ('capture' in createElement('input')));
+});
diff --git a/feature-detects/input/fileinput.js b/feature-detects/input/fileinput.js
new file mode 100644
index 0000000..988af0f
--- /dev/null
+++ b/feature-detects/input/fileinput.js
@@ -0,0 +1,26 @@
+/*!
+{
+  "name": "input[file] Attribute",
+  "property": "fileinput",
+  "caniuse": "forms",
+  "tags": ["file", "forms", "input"],
+  "builderAliases": ["forms_fileinput"]
+}
+!*/
+/* DOC
+Detects whether input type="file" is available on the platform
+
+E.g. iOS < 6, some android versions and embedded Chrome WebViews don't support this
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('fileinput', function() {
+    var ua = navigator.userAgent;
+    if (ua.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/) ||
+        ua.match(/\swv\).+(chrome)\/([\w\.]+)/i)) {
+      return false;
+    }
+    var elem = createElement('input');
+    elem.type = 'file';
+    return !elem.disabled;
+  });
+});
diff --git a/feature-detects/input/fileinputdirectory.js b/feature-detects/input/fileinputdirectory.js
new file mode 100644
index 0000000..1df197d
--- /dev/null
+++ b/feature-detects/input/fileinputdirectory.js
@@ -0,0 +1,25 @@
+/*!
+{
+  "name": "input[directory] Attribute",
+  "property": "directory",
+  "authors": ["silverwind"],
+  "tags": ["file", "input", "attribute"]
+}
+!*/
+/* DOC
+When used on an `<input type="file">`, the `directory` attribute instructs
+the user agent to present a directory selection dialog instead of the usual
+file selection dialog.
+*/
+define(['Modernizr', 'createElement', 'domPrefixesAll'], function(Modernizr, createElement, domPrefixesAll) {
+  Modernizr.addTest('fileinputdirectory', function() {
+    var elem = createElement('input'), dir = 'directory';
+    elem.type = 'file';
+    for (var i = 0, len = domPrefixesAll.length; i < len; i++) {
+      if (domPrefixesAll[i] + dir in elem) {
+        return true;
+      }
+    }
+    return false;
+  });
+});
diff --git a/feature-detects/input/formaction.js b/feature-detects/input/formaction.js
new file mode 100644
index 0000000..d478f21
--- /dev/null
+++ b/feature-detects/input/formaction.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "input formaction",
+  "property": "inputformaction",
+  "aliases": ["input-formaction"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formaction"
+  }, {
+    "name": "Wufoo demo",
+    "href": "https://www.wufoo.com/html5/formaction-attribute/"
+  }],
+  "polyfills": ["webshims"]
+}
+!*/
+/* DOC
+Detect support for the formaction attribute on form inputs
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('inputformaction', !!('formAction' in createElement('input')), {aliases: ['input-formaction']});
+});
diff --git a/feature-detects/input/formattribute.js b/feature-detects/input/formattribute.js
new file mode 100644
index 0000000..38c187e
--- /dev/null
+++ b/feature-detects/input/formattribute.js
@@ -0,0 +1,47 @@
+/*!
+{
+  "name": "input[form] Attribute",
+  "property": "formattribute",
+  "tags": ["attribute", "forms", "input"],
+  "builderAliases": ["forms_formattribute"]
+}
+!*/
+/* DOC
+Detects whether input form="form_id" is available on the platform
+E.g. IE 10 (and below), don't support this
+*/
+define(['Modernizr', 'createElement', 'docElement'], function(Modernizr, createElement, docElement) {
+
+  Modernizr.addTest('formattribute', function() {
+    var form = createElement('form');
+    var input = createElement('input');
+    var div = createElement('div');
+    var id = 'formtest' + (new Date()).getTime();
+    var attr;
+    var bool = false;
+
+    form.id = id;
+
+    //IE6/7 confuses the form idl attribute and the form content attribute, so we use document.createAttribute
+    try {
+      input.setAttribute('form', id);
+    }
+    catch (e) {
+      if (document.createAttribute) {
+        attr = document.createAttribute('form');
+        attr.nodeValue = id;
+        input.setAttributeNode(attr);
+      }
+    }
+
+    div.appendChild(form);
+    div.appendChild(input);
+
+    docElement.appendChild(div);
+
+    bool = form.elements && form.elements.length === 1 && input.form === form;
+
+    div.parentNode.removeChild(div);
+    return bool;
+  });
+});
diff --git a/feature-detects/input/formenctype.js b/feature-detects/input/formenctype.js
new file mode 100644
index 0000000..c18da70
--- /dev/null
+++ b/feature-detects/input/formenctype.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "input formenctype",
+  "property": "inputformenctype",
+  "aliases": ["input-formenctype"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formenctype"
+  }, {
+    "name": "Wufoo demo",
+    "href": "https://www.wufoo.com/html5/formenctype-attribute/"
+  }],
+  "polyfills": ["html5formshim"]
+}
+!*/
+/* DOC
+Detect support for the formenctype attribute on form inputs, which overrides the form enctype attribute
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('inputformenctype', !!('formEnctype' in createElement('input')), {aliases: ['input-formenctype']});
+});
diff --git a/feature-detects/input/formmethod.js b/feature-detects/input/formmethod.js
new file mode 100644
index 0000000..65272c1
--- /dev/null
+++ b/feature-detects/input/formmethod.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "input formmethod",
+  "property": "inputformmethod",
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formmethod"
+  }, {
+    "name": "Wufoo demo",
+    "href": "https://www.wufoo.com/html5/formmethod-attribute/"
+  }],
+  "polyfills": ["webshims"]
+}
+!*/
+/* DOC
+Detect support for the formmethod attribute on form inputs
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('inputformmethod', !!('formMethod' in createElement('input')));
+});
diff --git a/feature-detects/input/formnovalidate.js b/feature-detects/input/formnovalidate.js
new file mode 100644
index 0000000..95f884d
--- /dev/null
+++ b/feature-detects/input/formnovalidate.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "input formnovalidate",
+  "property": "inputformnovalidate",
+  "aliases": ["input-formnovalidate"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formnovalidate"
+  }, {
+    "name": "Wufoo demo",
+    "href": "https://www.wufoo.com/html5/formnovalidate-attribute/"
+  }],
+  "polyfills": ["html5formshim"]
+}
+!*/
+/* DOC
+Detect support for the formnovalidate attribute on form inputs, which overrides the form novalidate attribute
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('inputformnovalidate', !!('formNoValidate' in createElement('input')), {aliases: ['input-formnovalidate']});
+});
diff --git a/feature-detects/input/formtarget.js b/feature-detects/input/formtarget.js
new file mode 100644
index 0000000..bee2a9d
--- /dev/null
+++ b/feature-detects/input/formtarget.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "input formtarget",
+  "property": "inputformtarget",
+  "aliases": ["input-formtarget"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-formtarget"
+  }, {
+    "name": "Wufoo demo",
+    "href": "https://www.wufoo.com/html5/formtarget-attribute/"
+  }],
+  "polyfills": ["html5formshim"]
+}
+!*/
+/* DOC
+Detect support for the formtarget attribute on form inputs, which overrides the form target attribute
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('inputformtarget', !!('formTarget' in createElement('input')), {aliases: ['input-formtarget']});
+});
diff --git a/feature-detects/input/input.js b/feature-detects/input/input.js
new file mode 100644
index 0000000..5c20a96
--- /dev/null
+++ b/feature-detects/input/input.js
@@ -0,0 +1,54 @@
+/*!
+{
+  "name": "Input attributes",
+  "property": "input",
+  "tags": ["forms"],
+  "authors": ["Mike Taylor"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/input.html#input-type-attr-summary"
+  }],
+  "knownBugs": ["Some blackberry devices report false positive for input.multiple"]
+}
+!*/
+/* DOC
+Detects support for HTML5 `<input>` element attributes and exposes Boolean subproperties with the results:
+
+```javascript
+Modernizr.input.autocomplete
+Modernizr.input.autofocus
+Modernizr.input.list
+Modernizr.input.max
+Modernizr.input.min
+Modernizr.input.multiple
+Modernizr.input.pattern
+Modernizr.input.placeholder
+Modernizr.input.required
+Modernizr.input.step
+```
+*/
+define(['Modernizr', 'createElement', 'inputElem'], function(Modernizr, createElement, inputElem) {
+  // Run through HTML5's new input attributes to see if the UA understands any.
+  // Mike Taylr has created a comprehensive resource for testing these attributes
+  //   when applied to all input types:
+  //   miketaylr.com/code/input-type-attr.html
+
+  // Only input placeholder is tested while textarea's placeholder is not.
+  // Currently Safari 4 and Opera 11 have support only for the input placeholder
+  // Both tests are available in feature-detects/forms-placeholder.js
+
+  var inputattrs = 'autocomplete autofocus list placeholder max min multiple pattern required step'.split(' ');
+  var attrs = {};
+
+  Modernizr.input = (function(props) {
+    for (var i = 0, len = props.length; i < len; i++) {
+      attrs[ props[i] ] = !!(props[i] in inputElem);
+    }
+    if (attrs.list) {
+      // safari false positive's on datalist: webk.it/74252
+      // see also github.com/Modernizr/Modernizr/issues/146
+      attrs.list = !!(createElement('datalist') && window.HTMLDataListElement);
+    }
+    return attrs;
+  })(inputattrs);
+});
diff --git a/feature-detects/input/inputnumber-l10n.js b/feature-detects/input/inputnumber-l10n.js
new file mode 100644
index 0000000..02526af
--- /dev/null
+++ b/feature-detects/input/inputnumber-l10n.js
@@ -0,0 +1,56 @@
+/*!
+{
+  "name": "input[type=\"number\"] Localization",
+  "property": "localizednumber",
+  "tags": ["forms", "localization", "attribute"],
+  "authors": ["Peter Janes"],
+  "notes": [{
+    "name": "Webkit Bug Tracker Listing",
+    "href": "https://bugs.webkit.org/show_bug.cgi?id=42484"
+  }, {
+    "name": "Based on This",
+    "href": "https://trac.webkit.org/browser/trunk/LayoutTests/fast/forms/script-tests/input-number-keyoperation.js?rev=80096#L9"
+  }],
+  "knownBugs": ["Only ever returns true if the browser/OS is configured to use comma as a decimal separator. This is probably fine for most use cases."]
+}
+!*/
+/* DOC
+Detects whether input type="number" is capable of receiving and displaying localized numbers, e.g. with comma separator.
+*/
+define(['Modernizr', 'createElement', 'getBody', 'test/input/inputtypes', 'test/input/validation'], function(Modernizr, createElement, getBody) {
+  Modernizr.addTest('localizednumber', function() {
+    /* this extends our testing of input[type=number], so bomb out if that's missing */
+    if (!Modernizr.inputtypes.number) { return false; }
+    /* we rely on checkValidity later, so bomb out early if we don't have it */
+    if (!Modernizr.formvalidation) { return false; }
+
+    var body = getBody();
+    var div = createElement('div');
+    var firstChild = body.firstElementChild || body.firstChild;
+    var result;
+
+    body.insertBefore(div, firstChild);
+
+    div.innerHTML = '<input type="number" value="1.0" step="0.1" style="position: fixed; top: 0;" />';
+    var input = div.childNodes[0];
+    body.appendChild(div);
+
+    input.focus();
+    try {
+      document.execCommand('SelectAll', false); // Overwrite current input value, rather than appending text
+      document.execCommand('InsertText', false, '1,1');
+    } catch (e) {} // prevent warnings in IE
+
+    /* results */
+    result = input.type === 'number' && input.valueAsNumber === 1.1 && input.checkValidity();
+
+    /* cleanup */
+    body.removeChild(div);
+    if (body.fake && body.parentNode) {
+      body.parentNode.removeChild(body);
+    }
+
+    return result;
+  });
+
+});
diff --git a/feature-detects/input/inputsearchevent.js b/feature-detects/input/inputsearchevent.js
new file mode 100644
index 0000000..9977bc0
--- /dev/null
+++ b/feature-detects/input/inputsearchevent.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "input[search] search event",
+  "property": "inputsearchevent",
+  "tags": ["input","search"],
+  "authors": ["Calvin Webster"],
+  "notes": [{
+    "name": "Wufoo demo",
+    "href": "https://www.wufoo.com/html5/search-type/"
+  }, {
+    "name": "CSS Tricks",
+    "href": "https://css-tricks.com/webkit-html5-search-inputs/"
+  }]
+}
+!*/
+/* DOC
+There is a custom `search` event implemented in webkit browsers when using an `input[search]` element.
+*/
+define(['Modernizr', 'hasEvent'], function(Modernizr, hasEvent) {
+  Modernizr.addTest('inputsearchevent', hasEvent('search'));
+});
diff --git a/feature-detects/input/inputtypes.js b/feature-detects/input/inputtypes.js
new file mode 100644
index 0000000..9508df8
--- /dev/null
+++ b/feature-detects/input/inputtypes.js
@@ -0,0 +1,103 @@
+/*!
+{
+  "name": "Form input types",
+  "property": "inputtypes",
+  "caniuse": "forms",
+  "tags": ["forms"],
+  "authors": ["Mike Taylor"],
+  "polyfills": [
+    "jquerytools",
+    "webshims",
+    "h5f",
+    "webforms2",
+    "nwxforms",
+    "fdslider",
+    "html5slider",
+    "galleryhtml5forms",
+    "jscolor",
+    "html5formshim",
+    "selectedoptionsjs",
+    "formvalidationjs"
+  ]
+}
+!*/
+/* DOC
+Detects support for HTML5 form input types and exposes Boolean subproperties with the results:
+
+```javascript
+Modernizr.inputtypes.color
+Modernizr.inputtypes.date
+Modernizr.inputtypes.datetime
+Modernizr.inputtypes['datetime-local']
+Modernizr.inputtypes.email
+Modernizr.inputtypes.month
+Modernizr.inputtypes.number
+Modernizr.inputtypes.range
+Modernizr.inputtypes.search
+Modernizr.inputtypes.tel
+Modernizr.inputtypes.time
+Modernizr.inputtypes.url
+Modernizr.inputtypes.week
+```
+*/
+define(['Modernizr', 'inputElem', 'docElement'], function(Modernizr, inputElem, docElement) {
+  // Run through HTML5's new input types to see if the UA understands any.
+  //   This is put behind the tests runloop because it doesn't return a
+  //   true/false like all the other tests; instead, it returns an object
+  //   containing each input type with its corresponding true/false value
+
+  // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
+  (function() {
+    var props = ['search', 'tel', 'url', 'email', 'datetime', 'date', 'month', 'week','time', 'datetime-local', 'number', 'range', 'color'];
+    var smile = '1)';
+    var inputElemType;
+    var defaultView;
+    var bool;
+
+    for (var i = 0; i < props.length; i++) {
+      inputElem.setAttribute('type', inputElemType = props[i]);
+      bool = inputElem.type !== 'text' && 'style' in inputElem;
+
+      // We first check to see if the type we give it sticks..
+      // If the type does, we feed it a textual value, which shouldn't be valid.
+      // If the value doesn't stick, we know there's input sanitization which infers a custom UI
+      if (bool) {
+
+        inputElem.value = smile;
+        inputElem.style.cssText = 'position:absolute;visibility:hidden;';
+
+        if (/^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined) {
+
+          docElement.appendChild(inputElem);
+          defaultView = document.defaultView;
+
+          // Safari 2-4 allows the smiley as a value, despite making a slider
+          bool = defaultView.getComputedStyle &&
+            defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
+            // Mobile android web browser has false positive, so must
+            // check the height to see if the widget is actually there.
+            (inputElem.offsetHeight !== 0);
+
+          docElement.removeChild(inputElem);
+
+        } else if (/^(search|tel)$/.test(inputElemType)) {
+          // Spec doesn't define any special parsing or detectable UI
+          //   behaviors so we pass these through as true
+
+          // Interestingly, opera fails the earlier test, so it doesn't
+          //  even make it here.
+
+        } else if (/^(url|email)$/.test(inputElemType)) {
+          // Real url and email support comes with prebaked validation.
+          bool = inputElem.checkValidity && inputElem.checkValidity() === false;
+
+        } else {
+          // If the upgraded input component rejects the :) text, we got a winner
+          bool = inputElem.value !== smile;
+        }
+      }
+
+      Modernizr.addTest('inputtypes.' + inputElemType, !!bool);
+    }
+  })();
+});
diff --git a/feature-detects/input/placeholder.js b/feature-detects/input/placeholder.js
new file mode 100644
index 0000000..c03bdac
--- /dev/null
+++ b/feature-detects/input/placeholder.js
@@ -0,0 +1,14 @@
+/*!
+{
+  "name": "placeholder attribute",
+  "property": "placeholder",
+  "tags": ["forms", "attribute"],
+  "builderAliases": ["forms_placeholder"]
+}
+!*/
+/* DOC
+Tests for placeholder attribute in inputs and textareas
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('placeholder', ('placeholder' in createElement('input') && 'placeholder' in createElement('textarea')));
+});
diff --git a/feature-detects/input/requestautocomplete.js b/feature-detects/input/requestautocomplete.js
new file mode 100644
index 0000000..bfa3ebc
--- /dev/null
+++ b/feature-detects/input/requestautocomplete.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "form#requestAutocomplete()",
+  "property": "requestautocomplete",
+  "tags": ["form", "forms", "requestAutocomplete", "payments"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://wiki.whatwg.org/wiki/RequestAutocomplete"
+  }]
+}
+!*/
+/* DOC
+When used with input[autocomplete] to annotate a form, form.requestAutocomplete() shows a dialog in Chrome that speeds up
+checkout flows (payments specific for now).
+*/
+define(['Modernizr', 'createElement', 'prefixed'], function(Modernizr, createElement, prefixed) {
+  Modernizr.addTest('requestautocomplete', !!prefixed('requestAutocomplete', createElement('form')));
+});
diff --git a/feature-detects/input/validation.js b/feature-detects/input/validation.js
new file mode 100644
index 0000000..0ab9da2
--- /dev/null
+++ b/feature-detects/input/validation.js
@@ -0,0 +1,67 @@
+/*!
+{
+  "name": "Form Validation",
+  "property": "formvalidation",
+  "tags": ["forms", "validation", "attribute"],
+  "builderAliases": ["forms_validation"]
+}
+!*/
+/* DOC
+This implementation only tests support for interactive form validation.
+To check validation for a specific type or a specific other constraint,
+the test can be combined:
+
+- `Modernizr.inputtypes.number && Modernizr.formvalidation` (browser supports rangeOverflow, typeMismatch etc. for type=number)
+- `Modernizr.input.required && Modernizr.formvalidation` (browser supports valueMissing)
+*/
+define(['Modernizr', 'createElement', 'docElement', 'testStyles'], function(Modernizr, createElement, docElement, testStyles) {
+  Modernizr.addTest('formvalidation', function() {
+    var form = createElement('form');
+    if (!('checkValidity' in form) || !('addEventListener' in form)) {
+      return false;
+    }
+    if ('reportValidity' in form) {
+      return true;
+    }
+    var invalidFired = false;
+    var input;
+
+    Modernizr.formvalidationapi = true;
+
+    // Prevent form from being submitted
+    form.addEventListener('submit', function(e) {
+      // Old Presto based Opera does not validate form, if submit is prevented
+      // although Opera Mini servers use newer Presto.
+      if (!window.opera || window.operamini) {
+        e.preventDefault();
+      }
+      e.stopPropagation();
+    }, false);
+
+    // Calling form.submit() doesn't trigger interactive validation,
+    // use a submit button instead
+    //older opera browsers need a name attribute
+    form.innerHTML = '<input name="modTest" required="required" /><button></button>';
+
+    testStyles('#modernizr form{position:absolute;top:-99999em}', function(node) {
+      node.appendChild(form);
+
+      input = form.getElementsByTagName('input')[0];
+
+      // Record whether "invalid" event is fired
+      input.addEventListener('invalid', function(e) {
+        invalidFired = true;
+        e.preventDefault();
+        e.stopPropagation();
+      }, false);
+
+      //Opera does not fully support the validationMessage property
+      Modernizr.formvalidationmessage = !!input.validationMessage;
+
+      // Submit form by clicking submit button
+      form.getElementsByTagName('button')[0].click();
+    });
+
+    return invalidFired;
+  });
+});
diff --git a/feature-detects/intl.js b/feature-detects/intl.js
new file mode 100644
index 0000000..acd7407
--- /dev/null
+++ b/feature-detects/intl.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "Internationalization API",
+  "property": "intl",
+  "caniuse": "internationalization",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl"
+  }, {
+    "name": "ECMAScript spec",
+    "href": "https://www.ecma-international.org/ecma-402/1.0/"
+  }]
+}
+ !*/
+/* DOC
+Detects support for the Internationalization API which allow easy formatting of number and dates and sorting string
+based on a locale
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('intl', !!prefixed('Intl', window));
+});
diff --git a/feature-detects/json.js b/feature-detects/json.js
index af58064..e7e89c7 100644
--- a/feature-detects/json.js
+++ b/feature-detects/json.js
@@ -1,7 +1,21 @@
-// native JSON support.
-// developer.mozilla.org/en/JSON
+/*!
+{
+  "name": "JSON",
+  "property": "json",
+  "caniuse": "json",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Glossary/JSON"
+  }],
+  "polyfills": ["json2"]
+}
+!*/
+/* DOC
+Detects native support for JSON handling functions.
+*/
+define(['Modernizr'], function(Modernizr) {
+  // this will also succeed if you've loaded the JSON2.js polyfill ahead of time
+  //   ... but that should be obvious. :)
 
-// this will also succeed if you've loaded the JSON2.js polyfill ahead of time
-//   ... but that should be obvious. :)
-
-Modernizr.addTest('json', !!window.JSON && !!JSON.parse);
+  Modernizr.addTest('json', 'JSON' in window && 'parse' in JSON && 'stringify' in JSON);
+});
diff --git a/feature-detects/ligatures.js b/feature-detects/ligatures.js
new file mode 100644
index 0000000..50d7858
--- /dev/null
+++ b/feature-detects/ligatures.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "Font Ligatures",
+  "property": "ligatures",
+  "caniuse": "font-feature",
+  "notes": [{
+    "name": "Cross-browser Web Fonts",
+    "href": "https://www.sitepoint.com/cross-browser-web-fonts-part-3/"
+  }]
+}
+!*/
+/* DOC
+Detects support for OpenType ligatures
+*/
+define(['Modernizr', 'testAllProps'], function(Modernizr, testAllProps) {
+  Modernizr.addTest('ligatures', testAllProps('fontFeatureSettings', '"liga" 1'));
+});
diff --git a/feature-detects/link/prefetch.js b/feature-detects/link/prefetch.js
new file mode 100644
index 0000000..66e0b4b
--- /dev/null
+++ b/feature-detects/link/prefetch.js
@@ -0,0 +1,33 @@
+/*!
+{
+  "name": "rel=prefetch",
+  "property": "prefetch",
+  "caniuse": "link-rel-prefetch",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/resource-hints/#prefetch"
+  }, {
+    "name": "Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/2536"
+  }]
+}
+!*/
+/* DOC
+Test for resource hints: prefetch.
+*/
+define(["Modernizr", "createElement"], function (Modernizr, createElement) {
+  Modernizr.addTest("prefetch", function() {
+    if (document.documentMode === 11) {
+      // Need to check specifically for IE11 as it supports prefetch, but not relList
+      // https://github.com/Modernizr/Modernizr/pull/2610#issuecomment-709717161
+      return true;
+    }
+
+    var relList = createElement("link").relList;
+    if (!relList || !relList.supports) {
+      return false;
+    }
+
+    return relList.supports("prefetch");
+  });
+});
diff --git a/feature-detects/lists-reversed.js b/feature-detects/lists-reversed.js
index 22fd92c..1d70bc7 100644
--- a/feature-detects/lists-reversed.js
+++ b/feature-detects/lists-reversed.js
@@ -1,6 +1,17 @@
-
-// impressivewebs.com/reverse-ordered-lists-html5
-// polyfill: github.com/impressivewebs/HTML5-Reverse-Ordered-Lists
-
-
-Modernizr.addTest('olreversed', 'reversed' in document.createElement('ol'));
+/*!
+{
+  "name": "Reverse Ordered Lists",
+  "property": "olreversed",
+  "notes": [{
+    "name": "Impressive Webs article",
+    "href": "https://www.impressivewebs.com/reverse-ordered-lists-html5/"
+  }],
+  "builderAliases": ["lists_reversed"]
+}
+!*/
+/* DOC
+Detects support for the `reversed` attribute on the `<ol>` element.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('olreversed', 'reversed' in createElement('ol'));
+});
diff --git a/feature-detects/mathml.js b/feature-detects/mathml.js
index e1c907a..749fc81 100644
--- a/feature-detects/mathml.js
+++ b/feature-detects/mathml.js
@@ -1,23 +1,33 @@
-// MathML
-// http://www.w3.org/Math/ 
-// By Addy Osmani
-// Based on work by Davide (@dpvc) and David (@davidcarlisle)
-// in https://github.com/mathjax/MathJax/issues/182
+/*!
+{
+  "name": "MathML",
+  "property": "mathml",
+  "caniuse": "mathml",
+  "authors": ["Addy Osmani", "Davide P. Cervone", "David Carlisle"],
+  "knownBugs": ["Firefox < 4 will likely return a false, however it does support MathML inside XHTML documents"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/Math/"
+  }],
+  "polyfills": ["mathjax"]
+}
+!*/
+/* DOC
+Detects support for MathML, for mathematic equations in web pages.
+*/
+define(['Modernizr', 'testStyles'], function(Modernizr, testStyles) {
+  // Based on work by Davide (@dpvc) and David (@davidcarlisle)
+  // in https://github.com/mathjax/MathJax/issues/182
 
-Modernizr.addTest('mathml', function(){
-	var hasMathML = false;
-	if ( document.createElementNS ) {
-	var ns = "http://www.w3.org/1998/Math/MathML",
-	    div = document.createElement("div");
-	    div.style.position = "absolute"; 
-	var mfrac = div.appendChild(document.createElementNS(ns,"math"))
-	               .appendChild(document.createElementNS(ns,"mfrac"));
-	mfrac.appendChild(document.createElementNS(ns,"mi"))
-	     .appendChild(document.createTextNode("xx"));
-	mfrac.appendChild(document.createElementNS(ns,"mi"))
-	     .appendChild(document.createTextNode("yy"));
-	document.body.appendChild(div);
-	hasMathML = div.offsetHeight > div.offsetWidth;
-	}
-	return hasMathML;
-});
\ No newline at end of file
+  Modernizr.addTest('mathml', function() {
+    var ret;
+
+    testStyles('#modernizr{position:absolute;display:inline-block}', function(node) {
+      node.innerHTML += '<math><mfrac><mi>xx</mi><mi>yy</mi></mfrac></math>';
+
+      ret = node.offsetHeight > node.offsetWidth;
+    });
+
+    return ret;
+  });
+});
diff --git a/feature-detects/media-source-extension-api.js b/feature-detects/media-source-extension-api.js
new file mode 100644
index 0000000..2578184
--- /dev/null
+++ b/feature-detects/media-source-extension-api.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "Media Source Extensions API",
+  "caniuse": "mediasource",
+  "property": "mediasource",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Media_Source_Extensions_API"
+  }],
+  "builderAliases": ["media_source_extension_api"]
+}
+!*/
+/* DOC
+Detects support the Media Source Extensions API, which allows JavaScript to send byte streams to media codecs within web browsers that support HTML5 video.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('mediasource', 'MediaSource' in window);
+});
diff --git a/feature-detects/mediaquery/hovermq.js b/feature-detects/mediaquery/hovermq.js
new file mode 100644
index 0000000..5a19bfd
--- /dev/null
+++ b/feature-detects/mediaquery/hovermq.js
@@ -0,0 +1,13 @@
+/*!
+{
+  "name": "Hover Media Query",
+  "property": "hovermq",
+  "tags": ["mediaquery"]
+}
+!*/
+/* DOC
+Detect support for Hover based media queries
+*/
+define(['Modernizr', 'addTest', 'mq'], function(Modernizr, addTest, mq) {
+  Modernizr.addTest('hovermq', mq('(hover)'));
+});
diff --git a/feature-detects/mediaquery/pointermq.js b/feature-detects/mediaquery/pointermq.js
new file mode 100644
index 0000000..32b0b94
--- /dev/null
+++ b/feature-detects/mediaquery/pointermq.js
@@ -0,0 +1,13 @@
+/*!
+{
+  "name": "Pointer Media Query",
+  "property": "pointermq",
+  "tags": ["mediaquery"]
+}
+!*/
+/* DOC
+Detect support for Pointer based media queries
+*/
+define(['Modernizr', 'addTest', 'mq'], function(Modernizr, addTest, mq) {
+  Modernizr.addTest('pointermq', mq(('(pointer:coarse),(pointer:fine),(pointer:none)')));
+});
diff --git a/feature-detects/messagechannel.js b/feature-detects/messagechannel.js
new file mode 100644
index 0000000..d2941e5
--- /dev/null
+++ b/feature-detects/messagechannel.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "Message Channel",
+  "property": "messagechannel",
+  "authors": ["Raju Konga (@kongaraju)"],
+  "caniuse": "channel-messaging",
+  "tags": ["performance", "messagechannel"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/2011/WD-webmessaging-20110317/#message-channels"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Channel_Messaging_API/Using_channel_messaging"
+  }]
+}
+!*/
+/* DOC
+Detects support for Message Channels, a way to communicate between different browsing contexts like iframes, workers, etc..
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('messagechannel', 'MessageChannel' in window);
+});
diff --git a/feature-detects/network-connection.js b/feature-detects/network-connection.js
deleted file mode 100644
index 242cdfe..0000000
--- a/feature-detects/network-connection.js
+++ /dev/null
@@ -1,22 +0,0 @@
-// determining low-bandwidth via navigator.connection
-
-// There are two iterations of the navigator.connection interface:
-
-// The first is present in Android 2.2+ and only in the Browser (not WebView)
-// : docs.phonegap.com/en/1.2.0/phonegap_connection_connection.md.html#connection.type
-// : davidbcalhoun.com/2010/using-navigator-connection-android
-
-// The second is specced at dev.w3.org/2009/dap/netinfo/ and perhaps landing in WebKit
-// : bugs.webkit.org/show_bug.cgi?id=73528
-
-// unknown devices are assumed as fast
-// for more rigorous network testing, consider boomerang.js: github.com/bluesmoon/boomerang/
-
-Modernizr.addTest('lowbandwidth', function() {
-
-  var connection = navigator.connection || { type: 0 }; // polyfill
-
-  return connection.type == 3 || // connection.CELL_2G
-      connection.type == 4 || // connection.CELL_3G
-      /^[23]g$/.test(connection.type); // string value in new spec
-});
diff --git a/feature-detects/network-eventsource.js b/feature-detects/network-eventsource.js
deleted file mode 100644
index ac94065..0000000
--- a/feature-detects/network-eventsource.js
+++ /dev/null
@@ -1,5 +0,0 @@
-
-// server sent events aka eventsource
-// dev.w3.org/html5/eventsource/
-
-Modernizr.addTest('eventsource', !!window.EventSource);
diff --git a/feature-detects/network-xhr2.js b/feature-detects/network-xhr2.js
deleted file mode 100644
index 8d3fb51..0000000
--- a/feature-detects/network-xhr2.js
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-// XML HTTP Request Level 2
-// www.w3.org/TR/XMLHttpRequest2/
-
-// Much more details at github.com/Modernizr/Modernizr/issues/385
-
-// all three of these details report consistently across all target browsers:
-//   !!(window.ProgressEvent);
-//   !!(window.FormData);
-//   window.XMLHttpRequest && "withCredentials" in new XMLHttpRequest;
-
-Modernizr.addTest('xhr2', 'FormData' in window);
diff --git a/feature-detects/network/beacon.js b/feature-detects/network/beacon.js
new file mode 100644
index 0000000..6c9d0d8
--- /dev/null
+++ b/feature-detects/network/beacon.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "Beacon API",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/navigator.sendBeacon"
+  }, {
+    "name": "W3C Spec",
+    "href": "https://w3c.github.io/beacon/"
+  }],
+  "property": "beacon",
+  "caniuse": "beacon",
+  "tags": ["beacon", "network"],
+  "authors": ["Cătălin Mariș"]
+}
+!*/
+/* DOC
+Detects support for an API that allows for asynchronous transfer of small HTTP data from the client to a server.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('beacon', 'sendBeacon' in navigator);
+});
diff --git a/feature-detects/network/connection-effectivetype.js b/feature-detects/network/connection-effectivetype.js
new file mode 100644
index 0000000..c3141cd
--- /dev/null
+++ b/feature-detects/network/connection-effectivetype.js
@@ -0,0 +1,27 @@
+/*!
+{
+  "name": "Connection Effective Type",
+  "notes": [{
+    "name": "MDN documentation",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/NetworkInformation/effectiveType"
+  }],
+  "property": "connectioneffectivetype",
+  "builderAliases": ["network_connection"],
+  "tags": ["network"]
+}
+!*/
+/* DOC
+Detects support for determining signal bandwidth via `navigator.connection.effectiveType`
+*/
+define(['Modernizr'], function (Modernizr) {
+  Modernizr.addTest('effectiveType', function () {
+    // polyfill
+    var connection = navigator.connection || { effectiveType: 0 };
+
+    if (connection.effectiveType !== 0) {
+      return true;
+    }
+
+    return false;
+  });
+});
diff --git a/feature-detects/network/connection.js b/feature-detects/network/connection.js
new file mode 100644
index 0000000..9cbc222
--- /dev/null
+++ b/feature-detects/network/connection.js
@@ -0,0 +1,40 @@
+/*!
+{
+  "name": "Low Bandwidth Connection",
+  "property": "lowbandwidth",
+  "tags": ["network"],
+  "builderAliases": ["network_connection"]
+}
+!*/
+/* DOC
+Tests for determining low-bandwidth via `navigator.connection`
+
+There are three iterations of the `navigator.connection` interface.
+
+The first is present in Android 2.2+ and only in the Browser (not WebView)
+
+- http://docs.phonegap.com/en/1.2.0/phonegap_connection_connection.md.html#connection.type
+- https://davidbcalhoun.com/2010/using-navigator-connection-android
+
+The second is speced at https://dvcs.w3.org/hg/dap/raw-file/tip/network-api/Overview.html and perhaps landing in WebKit
+
+- https://bugs.webkit.org/show_bug.cgi?id=73528
+
+Unknown devices are assumed as fast
+
+The third is placed at https://wicg.github.io/netinfo/
+
+- Support for the old type now only exists in Android 4 and below (https://caniuse.com/netinfo)
+
+For more rigorous network testing, consider boomerang.js: https://github.com/bluesmoon/boomerang/
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('lowbandwidth', function() {
+    // Polyfill the network info API to inculde both the old type and new effectiveType
+    var connection = navigator.connection || {type: 0, effectiveType: 0};
+
+    return connection.type === 3 || // connection.CELL_2G
+      connection.type === 4 || // connection.CELL_3G
+      /^[23]g$/.test(connection.effectiveType); // string value in new spec
+  });
+});
diff --git a/feature-detects/network/eventsource.js b/feature-detects/network/eventsource.js
new file mode 100644
index 0000000..55ff3ca
--- /dev/null
+++ b/feature-detects/network/eventsource.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "Server Sent Events",
+  "property": "eventsource",
+  "tags": ["network"],
+  "builderAliases": ["network_eventsource"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/server-sent-events.html#server-sent-events"
+  }]
+}
+!*/
+/* DOC
+Tests for server sent events aka eventsource.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('eventsource', 'EventSource' in window);
+});
diff --git a/feature-detects/network/fetch.js b/feature-detects/network/fetch.js
new file mode 100644
index 0000000..59de6a6
--- /dev/null
+++ b/feature-detects/network/fetch.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "Fetch API",
+  "property": "fetch",
+  "tags": ["network"],
+  "caniuse": "fetch",
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://fetch.spec.whatwg.org/"
+  }],
+  "polyfills": ["fetch"]
+}
+!*/
+/* DOC
+Detects support for the fetch API, a modern replacement for XMLHttpRequest.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('fetch', 'fetch' in window);
+});
diff --git a/feature-detects/network/xhr-responsetype-arraybuffer.js b/feature-detects/network/xhr-responsetype-arraybuffer.js
new file mode 100644
index 0000000..0af6700
--- /dev/null
+++ b/feature-detects/network/xhr-responsetype-arraybuffer.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "XHR responseType='arraybuffer'",
+  "property": "xhrresponsetypearraybuffer",
+  "tags": ["network"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
+  }]
+}
+!*/
+/* DOC
+Tests for XMLHttpRequest xhr.responseType='arraybuffer'.
+*/
+define(['Modernizr', 'testXhrType'], function(Modernizr, testXhrType) {
+  Modernizr.addTest('xhrresponsetypearraybuffer', testXhrType('arraybuffer'));
+});
diff --git a/feature-detects/network/xhr-responsetype-blob.js b/feature-detects/network/xhr-responsetype-blob.js
new file mode 100644
index 0000000..d4f3762
--- /dev/null
+++ b/feature-detects/network/xhr-responsetype-blob.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "XHR responseType='blob'",
+  "property": "xhrresponsetypeblob",
+  "tags": ["network"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
+  }]
+}
+!*/
+/* DOC
+Tests for XMLHttpRequest xhr.responseType='blob'.
+*/
+define(['Modernizr', 'testXhrType'], function(Modernizr, testXhrType) {
+  Modernizr.addTest('xhrresponsetypeblob', testXhrType('blob'));
+});
diff --git a/feature-detects/network/xhr-responsetype-document.js b/feature-detects/network/xhr-responsetype-document.js
new file mode 100644
index 0000000..de73a76
--- /dev/null
+++ b/feature-detects/network/xhr-responsetype-document.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "XHR responseType='document'",
+  "property": "xhrresponsetypedocument",
+  "tags": ["network"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
+  }]
+}
+!*/
+/* DOC
+Tests for XMLHttpRequest xhr.responseType='document'.
+*/
+define(['Modernizr', 'testXhrType'], function(Modernizr, testXhrType) {
+  Modernizr.addTest('xhrresponsetypedocument', testXhrType('document'));
+});
diff --git a/feature-detects/network/xhr-responsetype-json.js b/feature-detects/network/xhr-responsetype-json.js
new file mode 100644
index 0000000..40f61bc
--- /dev/null
+++ b/feature-detects/network/xhr-responsetype-json.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "XHR responseType='json'",
+  "property": "xhrresponsetypejson",
+  "tags": ["network"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
+  }, {
+    "name": "Explanation of xhr.responseType='json'",
+    "href": "https://mathiasbynens.be/notes/xhr-responsetype-json"
+  }]
+}
+!*/
+/* DOC
+Tests for XMLHttpRequest xhr.responseType='json'.
+*/
+define(['Modernizr', 'testXhrType'], function(Modernizr, testXhrType) {
+  Modernizr.addTest('xhrresponsetypejson', testXhrType('json'));
+});
diff --git a/feature-detects/network/xhr-responsetype-text.js b/feature-detects/network/xhr-responsetype-text.js
new file mode 100644
index 0000000..435f062
--- /dev/null
+++ b/feature-detects/network/xhr-responsetype-text.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "XHR responseType='text'",
+  "property": "xhrresponsetypetext",
+  "tags": ["network"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
+  }]
+}
+!*/
+/* DOC
+Tests for XMLHttpRequest xhr.responseType='text'.
+*/
+define(['Modernizr', 'testXhrType'], function(Modernizr, testXhrType) {
+  Modernizr.addTest('xhrresponsetypetext', testXhrType('text'));
+});
diff --git a/feature-detects/network/xhr-responsetype.js b/feature-detects/network/xhr-responsetype.js
new file mode 100644
index 0000000..fd7c87b
--- /dev/null
+++ b/feature-detects/network/xhr-responsetype.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "XHR responseType",
+  "property": "xhrresponsetype",
+  "tags": ["network"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://xhr.spec.whatwg.org/#the-responsetype-attribute"
+  }]
+}
+!*/
+/* DOC
+Tests for XMLHttpRequest xhr.responseType.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('xhrresponsetype', (function() {
+    if (typeof XMLHttpRequest === 'undefined') {
+      return false;
+    }
+    var xhr = new XMLHttpRequest();
+    xhr.open('get', '/', true);
+    return 'response' in xhr;
+  }()));
+});
diff --git a/feature-detects/network/xhr2.js b/feature-detects/network/xhr2.js
new file mode 100644
index 0000000..42e218a
--- /dev/null
+++ b/feature-detects/network/xhr2.js
@@ -0,0 +1,25 @@
+/*!
+{
+  "name": "XML HTTP Request Level 2 XHR2",
+  "property": "xhr2",
+  "caniuse": "xhr2",
+  "tags": ["network"],
+  "builderAliases": ["network_xhr2"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/XMLHttpRequest2/"
+  }, {
+    "name": "Details on Related Github Issue",
+    "href": "https://github.com/Modernizr/Modernizr/issues/385"
+  }]
+}
+!*/
+/* DOC
+Tests for XHR2.
+*/
+define(['Modernizr'], function(Modernizr) {
+  // all three of these details report consistently across all target browsers:
+  //   !!(window.ProgressEvent);
+  //   'XMLHttpRequest' in window && 'withCredentials' in new XMLHttpRequest
+  Modernizr.addTest('xhr2', 'XMLHttpRequest' in window && 'withCredentials' in new XMLHttpRequest());
+});
diff --git a/feature-detects/notification.js b/feature-detects/notification.js
index 4324222..1ff0ede 100644
--- a/feature-detects/notification.js
+++ b/feature-detects/notification.js
@@ -1,10 +1,44 @@
-// Notifications
-// By Theodoor van Donge
+/*!
+{
+  "name": "Notification",
+  "property": "notification",
+  "caniuse": "notifications",
+  "authors": ["Theodoor van Donge", "Hendrik Beskow"],
+  "notes": [{
+    "name": "HTML5 Rocks Tutorial",
+    "href": "https://www.html5rocks.com/en/tutorials/notifications/quick/"
+  }, {
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/notifications/"
+  }, {
+    "name": "Changes in Chrome to Notifications API due to Service Worker Push Notifications",
+    "href": "https://developers.google.com/web/updates/2015/05/Notifying-you-of-notificiation-changes"
+  }],
+  "knownBugs": ["Possibility of false-positive on Chrome for Android if permissions we're granted for a website prior to Chrome 44."],
+  "polyfills": ["desktop-notify", "html5-notifications"]
+}
+!*/
+/* DOC
+Detects support for the Notifications API
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('notification', function() {
+    if (!window.Notification || !window.Notification.requestPermission) {
+      return false;
+    }
+    // if permission is already granted, assume support
+    if (window.Notification.permission === 'granted') {
+      return true;
+    }
 
-// window.webkitNotifications is only used by Chrome 
-//	http://www.html5rocks.com/en/tutorials/notifications/quick/
+    try {
+      new window.Notification('');
+    } catch (e) {
+      if (e.name === 'TypeError') {
+        return false;
+      }
+    }
 
-// window.Notification only exist in the draft specs 
-//	http://dev.w3.org/2006/webapi/WebNotifications/publish/Notifications.html#idl-if-Notification
-
-Modernizr.addTest('notification', !!Modernizr.prefixed('Notifications', window));
\ No newline at end of file
+    return true;
+  });
+});
diff --git a/feature-detects/pagevisibility-api.js b/feature-detects/pagevisibility-api.js
new file mode 100644
index 0000000..0cf04b0
--- /dev/null
+++ b/feature-detects/pagevisibility-api.js
@@ -0,0 +1,25 @@
+/*!
+{
+  "name": "Page Visibility API",
+  "property": "pagevisibility",
+  "caniuse": "pagevisibility",
+  "tags": ["performance"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/DOM/Using_the_Page_Visibility_API"
+  }, {
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/2011/WD-page-visibility-20110602/"
+  }, {
+    "name": "HTML5 Rocks Tutorial",
+    "href": "https://www.html5rocks.com/en/tutorials/pagevisibility/intro/"
+  }],
+  "polyfills": ["visibilityjs", "visiblyjs", "jquery-visibility"]
+}
+!*/
+/* DOC
+Detects support for the Page Visibility API, which can be used to disable unnecessary actions and otherwise improve user experience.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('pagevisibility', !!prefixed('hidden', document, false));
+});
diff --git a/feature-detects/performance.js b/feature-detects/performance.js
index 903c5c9..d6b3c4a 100644
--- a/feature-detects/performance.js
+++ b/feature-detects/performance.js
@@ -1,5 +1,23 @@
-// Navigation Timing (Performance)
-// https://dvcs.w3.org/hg/webperf/raw-file/tip/specs/NavigationTiming/
-// http://www.html5rocks.com/en/tutorials/webperformance/basics/
-// By Scott Murphy (uxder)
-Modernizr.addTest('performance', !!Modernizr.prefixed('performance', window));
\ No newline at end of file
+/*!
+{
+  "name": "Navigation Timing API",
+  "property": "performance",
+  "caniuse": "nav-timing",
+  "tags": ["performance"],
+  "authors": ["Scott Murphy (@uxder)"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/navigation-timing/"
+  }, {
+    "name": "HTML5 Rocks Tutorial",
+    "href": "https://www.html5rocks.com/en/tutorials/webperformance/basics/"
+  }],
+  "polyfills": ["perfnow"]
+}
+!*/
+/* DOC
+Detects support for the Navigation Timing API, for measuring browser and connection performance.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('performance', !!prefixed('performance', window));
+});
diff --git a/feature-detects/pointerlock-api.js b/feature-detects/pointerlock-api.js
index 07eb07e..f6106f8 100644
--- a/feature-detects/pointerlock-api.js
+++ b/feature-detects/pointerlock-api.js
@@ -1,4 +1,18 @@
-// https://developer.mozilla.org/en-US/docs/API/Pointer_Lock_API
-
-Modernizr.addTest('pointerlock',!!Modernizr.prefixed('pointerLockElement', document));
-
+/*!
+{
+  "name": "Pointer Lock API",
+  "property": "pointerlock",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/API/Pointer_Lock_API"
+  }],
+  "builderAliases": ["pointerlock_api"]
+}
+!*/
+/* DOC
+Detects support the pointer lock API which allows you to lock the mouse cursor to the browser window.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  // https://developer.mozilla.org/en-US/docs/API/Pointer_Lock_API
+  Modernizr.addTest('pointerlock', !!prefixed('exitPointerLock', document));
+});
diff --git a/feature-detects/postmessage.js b/feature-detects/postmessage.js
new file mode 100644
index 0000000..c1d1379
--- /dev/null
+++ b/feature-detects/postmessage.js
@@ -0,0 +1,30 @@
+/*!
+{
+  "name": "postMessage",
+  "property": "postmessage",
+  "caniuse": "x-doc-messaging",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/webmessaging/#crossDocumentMessages"
+  }],
+  "polyfills": ["easyxdm", "postmessage-jquery"],
+  "knownBugs": [
+    "structuredclones - Android 2&3 can not send a structured clone of dates, filelists or regexps.",
+    "Some old WebKit versions have bugs."
+  ],
+  "warnings": ["To be safe you should stick with object, array, number and pixeldata."]
+}
+!*/
+/* DOC
+Detects support for the `window.postMessage` protocol for cross-document messaging.
+`Modernizr.postmessage.structuredclones` reports if `postMessage` can send objects.
+*/
+define(['Modernizr'], function( Modernizr ) {
+  var bool = true;
+  try {
+    window.postMessage({ toString: function () { bool = false; } }, '*');
+  } catch (e) {}
+
+  Modernizr.addTest('postmessage', new Boolean('postMessage' in window));
+  Modernizr.addTest('postmessage.structuredclones', bool);
+});
diff --git a/feature-detects/proxy.js b/feature-detects/proxy.js
new file mode 100644
index 0000000..6c1b4e4
--- /dev/null
+++ b/feature-detects/proxy.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "Proxy Object",
+  "property": "proxy",
+  "caniuse": "proxy",
+  "authors": ["Brock Beaudry"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy"
+  }],
+  "polyfills": [
+    "harmony-reflect"
+  ]
+}
+!*/
+/* DOC
+Detects support for the Proxy object which is used to create dynamic proxies.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('proxy', 'Proxy' in window);
+});
diff --git a/feature-detects/queryselector.js b/feature-detects/queryselector.js
new file mode 100644
index 0000000..5030f94
--- /dev/null
+++ b/feature-detects/queryselector.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "QuerySelector",
+  "property": "queryselector",
+  "caniuse": "queryselector",
+  "tags": ["queryselector"],
+  "authors": ["Andrew Betts (@triblondon)"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/selectors-api/#queryselectorall"
+  }],
+  "polyfills": ["css-selector-engine"]
+}
+!*/
+/* DOC
+Detects support for querySelector.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('queryselector', 'querySelector' in document && 'querySelectorAll' in document);
+});
diff --git a/feature-detects/quota-management-api.js b/feature-detects/quota-management-api.js
deleted file mode 100644
index 5ce2b02..0000000
--- a/feature-detects/quota-management-api.js
+++ /dev/null
@@ -1,11 +0,0 @@
-// Quota Storage Management API
-// This API can be used to check how much quota an origin is using and request more
-
-// Currently only implemented in Chrome.
-// https://developers.google.com/chrome/whitepapers/storage
-// By Addy Osmani
-
-Modernizr.addTest('quotamanagement', function(){
-  var storage = Modernizr.prefixed('StorageInfo', window);
-  return !!(storage && 'TEMPORARY' in storage && 'PERSISTENT' in storage);
-});
diff --git a/feature-detects/requestanimationframe.js b/feature-detects/requestanimationframe.js
index 5ac4bcf..3874298 100644
--- a/feature-detects/requestanimationframe.js
+++ b/feature-detects/requestanimationframe.js
@@ -1,7 +1,21 @@
-
-// requestAnimationFrame
-// Offload animation repainting to browser for optimized performance. 
-// http://dvcs.w3.org/hg/webperf/raw-file/tip/specs/RequestAnimationFrame/Overview.html
-// By Addy Osmani
-
-Modernizr.addTest('raf', !!Modernizr.prefixed('requestAnimationFrame', window));
\ No newline at end of file
+/*!
+{
+  "name": "requestAnimationFrame",
+  "property": "requestanimationframe",
+  "aliases": ["raf"],
+  "caniuse": "requestanimationframe",
+  "tags": ["animation"],
+  "authors": ["Addy Osmani"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/animation-timing/"
+  }],
+  "polyfills": ["raf"]
+}
+!*/
+/* DOC
+Detects support for the `window.requestAnimationFrame` API, for offloading animation repainting to the browser for optimized performance.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('requestanimationframe', !!prefixed('requestAnimationFrame', window), {aliases: ['raf']});
+});
diff --git a/feature-detects/script-async.js b/feature-detects/script-async.js
deleted file mode 100644
index d80d04b..0000000
--- a/feature-detects/script-async.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// async script
-// By Theodoor van Donge
-Modernizr.addTest('scriptasync', 'async' in document.createElement('script'));
\ No newline at end of file
diff --git a/feature-detects/script-defer.js b/feature-detects/script-defer.js
deleted file mode 100644
index 782f14a..0000000
--- a/feature-detects/script-defer.js
+++ /dev/null
@@ -1,3 +0,0 @@
-// defer script
-// By Theodoor van Donge
-Modernizr.addTest('scriptdefer', 'defer' in document.createElement('script'));
\ No newline at end of file
diff --git a/feature-detects/script/async.js b/feature-detects/script/async.js
new file mode 100644
index 0000000..fe9a4ac
--- /dev/null
+++ b/feature-detects/script/async.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "script[async]",
+  "property": "scriptasync",
+  "caniuse": "script-async",
+  "tags": ["script"],
+  "builderAliases": ["script_async"],
+  "authors": ["Theodoor van Donge"]
+}
+!*/
+/* DOC
+Detects support for the `async` attribute on the `<script>` element.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('scriptasync', 'async' in createElement('script'));
+});
diff --git a/feature-detects/script/defer.js b/feature-detects/script/defer.js
new file mode 100644
index 0000000..02e3b89
--- /dev/null
+++ b/feature-detects/script/defer.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "script[defer]",
+  "property": "scriptdefer",
+  "caniuse": "script-defer",
+  "tags": ["script"],
+  "builderAliases": ["script_defer"],
+  "authors": ["Theodoor van Donge"],
+  "warnings": ["Browser implementation of the `defer` attribute vary: https://stackoverflow.com/questions/3952009/defer-attribute-chrome#answer-3982619"],
+  "knownBugs": ["False positive in Opera 12"]
+}
+!*/
+/* DOC
+Detects support for the `defer` attribute on the `<script>` element.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('scriptdefer', 'defer' in createElement('script'));
+});
diff --git a/feature-detects/scrolltooptions.js b/feature-detects/scrolltooptions.js
new file mode 100644
index 0000000..20afb50
--- /dev/null
+++ b/feature-detects/scrolltooptions.js
@@ -0,0 +1,34 @@
+/*!
+{
+  "name": "scrollToOptions dictionary",
+  "property": "scrolltooptions",
+  "caniuse": "mdn-api_scrolltooptions",
+  "notes": [{
+    "name": "MDN docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Window/scrollTo"
+  }],
+  "authors": ["Oliver Tušla (@asmarcz)", "Chris Smith (@chris13524)"]
+}
+!*/
+define(['Modernizr', 'createElement', 'getBody'], function (Modernizr, createElement, getBody) {
+  Modernizr.addTest('scrolltooptions', function () {
+    var body = getBody();
+    var returnTo = window.pageYOffset;
+    var needsFill = body.clientHeight <= window.innerHeight;
+    if (needsFill) {
+      var div = createElement('div');
+      div.style.height = (window.innerHeight - body.clientHeight + 1) + 'px';
+      div.style.display = 'block';
+      body.appendChild(div);
+    }
+    window.scrollTo({
+      top: 1
+    });
+    var result = window.pageYOffset !== 0;
+    if (needsFill) {
+      body.removeChild(div);
+    }
+    window.scrollTo(0, returnTo);
+    return result;
+  });
+});
diff --git a/feature-detects/serviceworker.js b/feature-detects/serviceworker.js
new file mode 100644
index 0000000..4e21039
--- /dev/null
+++ b/feature-detects/serviceworker.js
@@ -0,0 +1,17 @@
+/*!
+{
+  "name": "ServiceWorker API",
+  "property": "serviceworker",
+  "caniuse": "serviceworkers",
+  "notes": [{
+    "name": "ServiceWorkers Explained",
+    "href": "https://github.com/slightlyoff/ServiceWorker/blob/master/explainer.md"
+  }]
+}
+!*/
+/* DOC
+ServiceWorkers (formerly Navigation Controllers) are a way to persistently cache resources to built apps that work better offline.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('serviceworker', 'serviceWorker' in navigator);
+});
diff --git a/feature-detects/speech/speech-recognition.js b/feature-detects/speech/speech-recognition.js
new file mode 100644
index 0000000..1cac9b6
--- /dev/null
+++ b/feature-detects/speech/speech-recognition.js
@@ -0,0 +1,25 @@
+/*!
+{
+  "property": "speechrecognition",
+  "caniuse": "speech-recognition",
+  "tags": ["input", "speech"],
+  "authors": ["Cătălin Mariș"],
+  "name": "Speech Recognition API",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://w3c.github.io/speech-api/speechapi.html#speechreco-section"
+  }, {
+    "name": "Introduction to the Web Speech API",
+    "href": "https://developers.google.com/web/updates/2013/01/Voice-Driven-Web-Apps-Introduction-to-the-Web-Speech-API"
+  }]
+}
+!*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('speechrecognition', function() {
+    try {
+      return !!prefixed('SpeechRecognition', window);
+    } catch (e) {
+      return false;
+    }
+  });
+});
diff --git a/feature-detects/speech/speech-synthesis.js b/feature-detects/speech/speech-synthesis.js
new file mode 100644
index 0000000..4e1fa09
--- /dev/null
+++ b/feature-detects/speech/speech-synthesis.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "property": "speechsynthesis",
+  "caniuse": "speech-synthesis",
+  "tags": ["input", "speech"],
+  "authors": ["Cătălin Mariș"],
+  "name": "Speech Synthesis API",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://w3c.github.io/speech-api/speechapi.html#tts-section"
+  }]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('speechsynthesis', function() {
+    try {
+      return 'SpeechSynthesisUtterance' in window;
+    } catch (e) {
+      return false;
+    }
+  });
+});
diff --git a/feature-detects/storage/cookies.js b/feature-detects/storage/cookies.js
new file mode 100644
index 0000000..992924f
--- /dev/null
+++ b/feature-detects/storage/cookies.js
@@ -0,0 +1,37 @@
+/*!
+{
+  "name": "Cookies",
+  "property": "cookies",
+  "tags": ["storage"],
+  "authors": ["tauren"]
+}
+!*/
+/* DOC
+Detects whether cookie support is enabled.
+*/
+define(['Modernizr'], function(Modernizr) {
+  // https://github.com/Modernizr/Modernizr/issues/191
+
+  Modernizr.addTest('cookies', function() {
+    // navigator.cookieEnabled cannot detect custom or nuanced cookie blocking
+    // configurations. For example, when blocking cookies via the Advanced
+    // Privacy Settings in IE9, it always returns true. And there have been
+    // issues in the past with site-specific exceptions.
+    // Don't rely on it.
+
+    // try..catch because some in situations `document.cookie` is exposed but throws a
+    // SecurityError if you try to access it; e.g. documents created from data URIs
+    // or in sandboxed iframes (depending on flags/context)
+    try {
+      // Create cookie
+      document.cookie = 'cookietest=1';
+      var ret = document.cookie.indexOf('cookietest=') !== -1;
+      // Delete cookie
+      document.cookie = 'cookietest=1; expires=Thu, 01-Jan-1970 00:00:01 GMT';
+      return ret;
+    }
+    catch (e) {
+      return false;
+    }
+  });
+});
diff --git a/feature-detects/storage/indexeddb.js b/feature-detects/storage/indexeddb.js
new file mode 100644
index 0000000..9042253
--- /dev/null
+++ b/feature-detects/storage/indexeddb.js
@@ -0,0 +1,69 @@
+/*!
+{
+  "name": "IndexedDB",
+  "property": "indexeddb",
+  "caniuse": "indexeddb",
+  "tags": ["storage"],
+  "polyfills": ["indexeddb"],
+  "async": true
+}
+!*/
+/* DOC
+Detects support for the IndexedDB client-side storage API (final spec).
+*/
+define(['Modernizr', 'prefixed', 'addTest'], function(Modernizr, prefixed, addTest) {
+  // Vendors had inconsistent prefixing with the experimental Indexed DB:
+  // - Webkit's implementation is accessible through webkitIndexedDB
+  // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
+  // For speed, we don't test the legacy (and beta-only) indexedDB
+
+  Modernizr.addAsyncTest(function() {
+
+    var indexeddb;
+
+    try {
+      // Firefox throws a Security Error when cookies are disabled
+      indexeddb = prefixed('indexedDB', window);
+    } catch (e) {
+    }
+
+    if (indexeddb) {
+      var testDBName = 'modernizr-' + Math.random();
+      var req;
+      try {
+        req = indexeddb.open(testDBName);
+      } catch (e) {
+        addTest('indexeddb', false);
+        return;
+      }
+
+      req.onerror = function(event) {
+        if (req.error && (req.error.name === 'InvalidStateError' || req.error.name === 'UnknownError')) {
+          addTest('indexeddb', false);
+          event.preventDefault();
+        } else {
+          addTest('indexeddb', true);
+          detectDeleteDatabase(indexeddb, testDBName);
+        }
+      };
+
+      req.onsuccess = function() {
+        addTest('indexeddb', true);
+        detectDeleteDatabase(indexeddb, testDBName);
+      };
+    } else {
+      addTest('indexeddb', false);
+    }
+  });
+
+  function detectDeleteDatabase(indexeddb, testDBName) {
+    var deleteReq = indexeddb.deleteDatabase(testDBName);
+    deleteReq.onsuccess = function() {
+      addTest('indexeddb.deletedatabase', true);
+    };
+    deleteReq.onerror = function() {
+      addTest('indexeddb.deletedatabase', false);
+    };
+  }
+
+});
diff --git a/feature-detects/storage/indexeddb2.js b/feature-detects/storage/indexeddb2.js
new file mode 100644
index 0000000..f3c6297
--- /dev/null
+++ b/feature-detects/storage/indexeddb2.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "IndexedDB 2.0",
+  "property": "indexeddb2",
+  "tags": ["storage"],
+  "caniuse": "indexeddb2",
+  "authors": ["Tan Zhen Yong (@Xenonym)"],
+  "polyfills": ["indexeddb"],
+  "async": true
+}
+!*/
+/* DOC
+Detects support for the IndexedDB 2.0 client-side storage API.
+*/
+define(['Modernizr', 'addTest', 'test/storage/indexeddb'], function(Modernizr, addTest) {
+  Modernizr.addAsyncTest(function() {
+    Modernizr.on('indexeddb', function(result) {
+      if (!result) return;
+      addTest('indexeddb2', 'getAll' in IDBIndex.prototype);
+    });
+  });
+});
diff --git a/feature-detects/storage/indexeddbblob.js b/feature-detects/storage/indexeddbblob.js
new file mode 100644
index 0000000..a39860a
--- /dev/null
+++ b/feature-detects/storage/indexeddbblob.js
@@ -0,0 +1,68 @@
+/*!
+{
+  "name": "IndexedDB Blob",
+  "property": "indexeddbblob",
+  "tags": ["storage"]
+}
+!*/
+/* DOC
+Detects if the browser can save File/Blob objects to IndexedDB
+*/
+define(['Modernizr', 'addTest', 'prefixed', 'test/storage/indexeddb'], function(Modernizr, addTest, prefixed) {
+  // Vendors had inconsistent prefixing with the experimental Indexed DB:
+  // - Webkit's implementation is accessible through webkitIndexedDB
+  // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
+  // For speed, we don't test the legacy (and beta-only) indexedDB
+
+  Modernizr.addAsyncTest(function() {
+    var indexeddb;
+    var dbname = 'detect-blob-support';
+    var supportsBlob = false;
+    var openRequest;
+    var db;
+    var putRequest;
+
+    try {
+      indexeddb = prefixed('indexedDB', window);
+    } catch (e) {
+    }
+
+    if (!(Modernizr.indexeddb && Modernizr.indexeddb.deletedatabase)) {
+      return false;
+    }
+
+    // Calling `deleteDatabase` in a try…catch because some contexts (e.g. data URIs)
+    // will throw a `SecurityError`
+    try {
+      indexeddb.deleteDatabase(dbname).onsuccess = function() {
+        openRequest = indexeddb.open(dbname, 1);
+        openRequest.onupgradeneeded = function() {
+          openRequest.result.createObjectStore('store');
+        };
+        openRequest.onsuccess = function() {
+          db = openRequest.result;
+          try {
+            putRequest = db.transaction('store', 'readwrite').objectStore('store').put(new Blob(), 'key');
+            putRequest.onsuccess = function() {
+              supportsBlob = true;
+            };
+            putRequest.onerror = function() {
+              supportsBlob = false;
+            };
+          }
+          catch (e) {
+            supportsBlob = false;
+          }
+          finally {
+            addTest('indexeddbblob', supportsBlob);
+            db.close();
+            indexeddb.deleteDatabase(dbname);
+          }
+        };
+      };
+    }
+    catch (e) {
+      addTest('indexeddbblob', false);
+    }
+  });
+});
diff --git a/feature-detects/storage/localstorage.js b/feature-detects/storage/localstorage.js
new file mode 100644
index 0000000..5564ecf
--- /dev/null
+++ b/feature-detects/storage/localstorage.js
@@ -0,0 +1,47 @@
+/*!
+{
+  "name": "Local Storage",
+  "property": "localstorage",
+  "caniuse": "namevalue-storage",
+  "tags": ["storage"],
+  "polyfills": [
+    "joshuabell-polyfill",
+    "cupcake",
+    "storagepolyfill",
+    "amplifyjs",
+    "yui-cacheoffline"
+  ]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  // In FF4, if disabled, window.localStorage should === null.
+
+  // Normally, we could not test that directly and need to do a
+  //   `('localStorage' in window)` test first because otherwise Firefox will
+  //   throw bugzil.la/365772 if cookies are disabled
+
+  // Similarly, in Chrome with "Block third-party cookies and site data" enabled,
+  // attempting to access `window.sessionStorage` will throw an exception. crbug.com/357625
+
+  // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
+  // will throw the exception:
+  //   QUOTA_EXCEEDED_ERROR DOM Exception 22.
+  // Peculiarly, getItem and removeItem calls do not throw.
+
+  // Because we are forced to try/catch this, we'll go aggressive.
+
+  // Just FWIW: IE8 Compat mode supports these features completely:
+  //   www.quirksmode.org/dom/html5.html
+  // But IE8 doesn't support either with local files
+
+  Modernizr.addTest('localstorage', function() {
+    var mod = 'modernizr';
+    try {
+      localStorage.setItem(mod, mod);
+      localStorage.removeItem(mod);
+      return true;
+    } catch (e) {
+      return false;
+    }
+  });
+});
diff --git a/feature-detects/storage/quota-management-api.js b/feature-detects/storage/quota-management-api.js
new file mode 100644
index 0000000..8c4f2cc
--- /dev/null
+++ b/feature-detects/storage/quota-management-api.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "Quota Storage Management API",
+  "property": "quotamanagement",
+  "tags": ["storage"],
+  "builderAliases": ["quota_management_api"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/quota-api/"
+  }]
+}
+!*/
+/* DOC
+Detects the ability to request a specific amount of space for filesystem access
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('quotamanagement', function() {
+    var tempStorage = prefixed('temporaryStorage', navigator);
+    var persStorage = prefixed('persistentStorage', navigator);
+
+    return !!(tempStorage && persStorage);
+  });
+});
diff --git a/feature-detects/storage/sessionstorage.js b/feature-detects/storage/sessionstorage.js
new file mode 100644
index 0000000..8af065c
--- /dev/null
+++ b/feature-detects/storage/sessionstorage.js
@@ -0,0 +1,25 @@
+/*!
+{
+  "name": "Session Storage",
+  "property": "sessionstorage",
+  "tags": ["storage"],
+  "polyfills": ["joshuabell-polyfill", "cupcake", "storagepolyfill"]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  // Because we are forced to try/catch this, we'll go aggressive.
+
+  // Just FWIW: IE8 Compat mode supports these features completely:
+  //   www.quirksmode.org/dom/html5.html
+  // But IE8 doesn't support either with local files
+  Modernizr.addTest('sessionstorage', function() {
+    var mod = 'modernizr';
+    try {
+      sessionStorage.setItem(mod, mod);
+      sessionStorage.removeItem(mod);
+      return true;
+    } catch (e) {
+      return false;
+    }
+  });
+});
diff --git a/feature-detects/storage/userdata.js b/feature-detects/storage/userdata.js
new file mode 100644
index 0000000..03f4b4d
--- /dev/null
+++ b/feature-detects/storage/userdata.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "IE User Data API",
+  "property": "userdata",
+  "tags": ["storage"],
+  "authors": ["@stereobooster"],
+  "notes": [{
+    "name": "MSDN Documentation",
+    "href": "https://msdn.microsoft.com/en-us/library/ms531424.aspx"
+  }]
+}
+!*/
+/* DOC
+Detects support for IE userData for persisting data, an API similar to localStorage but supported since IE5.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('userdata', !!createElement('div').addBehavior);
+});
diff --git a/feature-detects/storage/websqldatabase.js b/feature-detects/storage/websqldatabase.js
new file mode 100644
index 0000000..f50caf2
--- /dev/null
+++ b/feature-detects/storage/websqldatabase.js
@@ -0,0 +1,13 @@
+/*!
+{
+  "name": "Web SQL Database",
+  "property": "websqldatabase",
+  "caniuse": "sql-storage",
+  "tags": ["storage"]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  // Chrome incognito mode used to throw an exception when using openDatabase
+  // It doesn't anymore.
+  Modernizr.addTest('websqldatabase', 'openDatabase' in window);
+});
diff --git a/feature-detects/style-scoped.js b/feature-detects/style-scoped.js
deleted file mode 100644
index 3add1b0..0000000
--- a/feature-detects/style-scoped.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// Browser support test for <style scoped>
-// http://www.w3.org/TR/html5/the-style-element.html#attr-style-scoped
-//
-// by @alrra
-
-Modernizr.addTest( 'stylescoped', 'scoped' in document.createElement('style') );
diff --git a/feature-detects/style/scoped.js b/feature-detects/style/scoped.js
new file mode 100644
index 0000000..53833c9
--- /dev/null
+++ b/feature-detects/style/scoped.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "style[scoped]",
+  "property": "stylescoped",
+  "caniuse": "style-scoped",
+  "tags": ["dom"],
+  "builderAliases": ["style_scoped"],
+  "authors": ["Cătălin Mariș"],
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://html.spec.whatwg.org/multipage/semantics.html#attr-style-scoped"
+  }],
+  "polyfills": ["scoped-styles"]
+}
+!*/
+/* DOC
+Support for the `scoped` attribute of the `<style>` element.
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('stylescoped', 'scoped' in createElement('style'));
+});
diff --git a/feature-detects/svg-filters.js b/feature-detects/svg-filters.js
deleted file mode 100644
index d289b9d..0000000
--- a/feature-detects/svg-filters.js
+++ /dev/null
@@ -1,13 +0,0 @@
-// Detect support for svg filters - http://www.w3.org/TR/SVG11/filters.html.
-// Should fail in Safari: http://stackoverflow.com/questions/9739955/feature-detecting-support-for-svg-filters.
-// detect by erik dahlstrom
-
-Modernizr.addTest('svgfilters', function(){
-	var result = false;
-    try {
-      result = typeof SVGFEColorMatrixElement !== undefined &&
-               SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_SATURATE == 2;
-    }
-    catch(e) {}
-    return result;
-});
diff --git a/feature-detects/svg/asimg.js b/feature-detects/svg/asimg.js
new file mode 100644
index 0000000..6c2a8ff
--- /dev/null
+++ b/feature-detects/svg/asimg.js
@@ -0,0 +1,27 @@
+/*!
+{
+  "name": "SVG as an <img> tag source",
+  "property": "svgasimg",
+  "caniuse": "svg-img",
+  "tags": ["svg"],
+  "aliases": ["svgincss"],
+  "authors": ["Chris Coyier"],
+  "notes": [{
+    "name": "HTML5 Spec",
+    "href": "https://www.w3.org/TR/html5/embedded-content-0.html#the-img-element"
+  }]
+}
+!*/
+define(['Modernizr', 'addTest'], function(Modernizr) {
+
+  // Original Async test by Stu Cox
+  // https://gist.github.com/chriscoyier/8774501
+
+  // Now a Sync test based on good results here
+  // https://codepen.io/chriscoyier/pen/bADFx
+
+  // Note http://www.w3.org/TR/SVG11/feature#Image is *supposed* to represent
+  // support for the `<image>` tag in SVG, not an SVG file linked from an `<img>`
+  // tag in HTML – but it’s a heuristic which works
+  Modernizr.addTest('svgasimg', document.implementation.hasFeature('http://www.w3.org/TR/SVG11/feature#Image', '1.1'));
+});
diff --git a/feature-detects/svg/clippaths.js b/feature-detects/svg/clippaths.js
new file mode 100644
index 0000000..0c7231b
--- /dev/null
+++ b/feature-detects/svg/clippaths.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "name": "SVG clip paths",
+  "property": "svgclippaths",
+  "tags": ["svg"],
+  "notes": [{
+    "name": "Demo",
+    "href": "http://srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg"
+  }]
+}
+!*/
+/* DOC
+Detects support for clip paths in SVG (only, not on HTML content).
+
+See [this discussion](https://github.com/Modernizr/Modernizr/issues/213) regarding applying SVG clip paths to HTML content.
+*/
+define(['Modernizr', 'toStringFn'], function(Modernizr, toStringFn) {
+  Modernizr.addTest('svgclippaths', function() {
+    return !!document.createElementNS &&
+      /SVGClipPath/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'clipPath')));
+  });
+});
diff --git a/feature-detects/svg/filters.js b/feature-detects/svg/filters.js
new file mode 100644
index 0000000..b8f51f7
--- /dev/null
+++ b/feature-detects/svg/filters.js
@@ -0,0 +1,26 @@
+/*!
+{
+  "name": "SVG filters",
+  "property": "svgfilters",
+  "caniuse": "svg-filters",
+  "tags": ["svg"],
+  "builderAliases": ["svg_filters"],
+  "authors": ["Erik Dahlstrom"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/SVG11/filters.html"
+  }]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  // How it is made to fail in pre 6 versions of Safari: https://stackoverflow.com/questions/9739955/feature-detecting-support-for-svg-filters.
+  Modernizr.addTest('svgfilters', function() {
+    var result = false;
+    try {
+      result = 'SVGFEColorMatrixElement' in window &&
+        SVGFEColorMatrixElement.SVG_FECOLORMATRIX_TYPE_SATURATE === 2;
+    }
+    catch (e) {}
+    return result;
+  });
+});
diff --git a/feature-detects/svg/foreignobject.js b/feature-detects/svg/foreignobject.js
new file mode 100644
index 0000000..563d75d
--- /dev/null
+++ b/feature-detects/svg/foreignobject.js
@@ -0,0 +1,20 @@
+/*!
+{
+  "name": "SVG foreignObject",
+  "property": "svgforeignobject",
+  "tags": ["svg"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/SVG11/extend.html"
+  }]
+}
+!*/
+/* DOC
+Detects support for foreignObject tag in SVG.
+*/
+define(['Modernizr', 'toStringFn'], function(Modernizr, toStringFn) {
+  Modernizr.addTest('svgforeignobject', function() {
+    return !!document.createElementNS &&
+      /SVGForeignObject/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'foreignObject')));
+  });
+});
diff --git a/feature-detects/svg/inline.js b/feature-detects/svg/inline.js
new file mode 100644
index 0000000..7518bf1
--- /dev/null
+++ b/feature-detects/svg/inline.js
@@ -0,0 +1,27 @@
+/*!
+{
+  "name": "Inline SVG",
+  "property": "inlinesvg",
+  "caniuse": "svg-html5",
+  "tags": ["svg"],
+  "notes": [{
+    "name": "Test page",
+    "href": "https://paulirish.com/demo/inline-svg"
+  }, {
+    "name": "Test page and results",
+    "href": "https://codepen.io/eltonmesquita/full/GgXbvo/"
+  }],
+  "polyfills": ["inline-svg-polyfill"],
+  "knownBugs": ["False negative on some Chromia browsers."]
+}
+!*/
+/* DOC
+Detects support for inline SVG in HTML (not within XHTML).
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('inlinesvg', function() {
+    var div = createElement('div');
+    div.innerHTML = '<svg/>';
+    return (typeof SVGRect !== 'undefined' && div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg';
+  });
+});
diff --git a/feature-detects/svg/smil.js b/feature-detects/svg/smil.js
new file mode 100644
index 0000000..308e5df
--- /dev/null
+++ b/feature-detects/svg/smil.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "SVG SMIL animation",
+  "property": "smil",
+  "caniuse": "svg-smil",
+  "tags": ["svg"],
+  "notes": [{
+  "name": "W3C Spec",
+  "href": "https://www.w3.org/AudioVideo/"
+  }]
+}
+!*/
+define(['Modernizr', 'toStringFn'], function(Modernizr, toStringFn) {
+  // SVG SMIL animation
+  Modernizr.addTest('smil', function() {
+    return !!document.createElementNS &&
+      /SVGAnimate/.test(toStringFn.call(document.createElementNS('http://www.w3.org/2000/svg', 'animate')));
+  });
+});
diff --git a/feature-detects/svg/svg.js b/feature-detects/svg/svg.js
new file mode 100644
index 0000000..58bca67
--- /dev/null
+++ b/feature-detects/svg/svg.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "SVG",
+  "property": "svg",
+  "caniuse": "svg",
+  "tags": ["svg"],
+  "authors": ["Erik Dahlstrom"],
+  "polyfills": [
+    "svgweb",
+    "raphael",
+    "canvg",
+    "svg-boilerplate",
+    "sie",
+    "fabricjs"
+  ]
+}
+!*/
+/* DOC
+Detects support for SVG in `<embed>` or `<object>` elements.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('svg', !!document.createElementNS && !!document.createElementNS('http://www.w3.org/2000/svg', 'svg').createSVGRect);
+});
diff --git a/feature-detects/textarea/maxlength.js b/feature-detects/textarea/maxlength.js
new file mode 100644
index 0000000..6474ee6
--- /dev/null
+++ b/feature-detects/textarea/maxlength.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "textarea maxlength",
+  "property": "textareamaxlength",
+  "aliases": ["textarea-maxlength"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/HTML/Element/textarea"
+  }],
+  "polyfills": ["maxlength"]
+}
+!*/
+/* DOC
+Detect support for the maxlength attribute of a textarea element
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('textareamaxlength', !!('maxLength' in createElement('textarea')));
+});
diff --git a/feature-detects/textencoding.js b/feature-detects/textencoding.js
new file mode 100644
index 0000000..be2cee0
--- /dev/null
+++ b/feature-detects/textencoding.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "Text Encoding/Decoding",
+  "property": ["textencoder", "textdecoder"],
+  "caniuse" : "textencoder",
+  "notes": [{
+    "name": "MDN TextEncoder Doc",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/TextEncoder"
+  }, {
+    "name": "MDN TextDecoder Doc",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/TextDecoder"
+  }],
+  "authors": ["dabretin"]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('textencoder', !!(window.TextEncoder && window.TextEncoder.prototype.encode));
+  Modernizr.addTest('textdecoder', !!(window.TextDecoder && window.TextDecoder.prototype.decode));
+});
diff --git a/feature-detects/typed-arrays.js b/feature-detects/typed-arrays.js
new file mode 100644
index 0000000..416abdf
--- /dev/null
+++ b/feature-detects/typed-arrays.js
@@ -0,0 +1,36 @@
+/*!
+{
+  "name": "Typed arrays",
+  "property": "typedarrays",
+  "caniuse": "typedarrays",
+  "tags": ["js"],
+  "authors": ["Stanley Stuart (@fivetanley)"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays"
+  }, {
+    "name": "Kronos spec",
+    "href": "http://www.ecma-international.org/ecma-262/6.0/#sec-typedarray-objects"
+  }],
+  "polyfills": ["joshuabell-polyfill"]
+}
+!*/
+/* DOC
+Detects support for native binary data manipulation via Typed Arrays in JavaScript.
+
+Does not check for DataView support; use `Modernizr.dataview` for that.
+*/
+define(['Modernizr'], function(Modernizr) {
+  // Should fail in:
+  // Internet Explorer <= 9
+  // Firefox <= 3.6
+  // Chrome <= 6.0
+  // iOS Safari < 4.2
+  // Safari < 5.1
+  // Opera < 11.6
+  // Opera Mini, <= 7.0
+  // Android Browser < 4.0
+  // Blackberry Browser < 10.0
+
+  Modernizr.addTest('typedarrays', 'ArrayBuffer' in window);
+});
diff --git a/feature-detects/unicode-range.js b/feature-detects/unicode-range.js
new file mode 100644
index 0000000..dad322e
--- /dev/null
+++ b/feature-detects/unicode-range.js
@@ -0,0 +1,37 @@
+/*!
+{
+  "name": "Unicode Range",
+  "property": "unicoderange",
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/2013/CR-css-fonts-3-20131003/#descdef-unicode-range"
+  }, {
+    "name": "24 Way article",
+    "href": "https://24ways.org/2011/creating-custom-font-stacks-with-unicode-range"
+  }]
+}
+!*/
+define(['Modernizr', 'testStyles', 'createElement'], function(Modernizr, testStyles, createElement) {
+  Modernizr.addTest('unicoderange', function() {
+
+    return testStyles('@font-face{font-family:"unicodeRange";src:local("Arial");unicode-range:U+0020,U+002E}#modernizr span{font-size:20px;display:inline-block;font-family:"unicodeRange",monospace}#modernizr .mono{font-family:monospace}', function(elem) {
+
+      // we use specify a unicode-range of 002E (the `.` glyph,
+      // and a monospace font as the fallback. If the first of
+      // these test glyphs is a different width than the other
+      // the other three (which are all monospace), then we
+      // have a winner.
+      var testGlyphs = ['.', '.', 'm', 'm'];
+
+      for (var i = 0; i < testGlyphs.length; i++) {
+        var elm = createElement('span');
+        elm.innerHTML = testGlyphs[i];
+        elm.className = i % 2 ? 'mono' : '';
+        elem.appendChild(elm);
+        testGlyphs[i] = elm.clientWidth;
+      }
+
+      return (testGlyphs[0] !== testGlyphs[1] && testGlyphs[2] === testGlyphs[3]);
+    });
+  });
+});
diff --git a/feature-detects/unicode.js b/feature-detects/unicode.js
deleted file mode 100644
index 39908bf..0000000
--- a/feature-detects/unicode.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * Unicode special character support
- * 
- * Detection is made by testing missing glyph box rendering against star character
- * If widths are the same, this "probably" means the browser didn't support the star character and rendered a glyph box instead
- * Just need to ensure the font characters have different widths
- * 
- * Warning : positive Unicode support doesn't mean you can use it inside <title>, this seams more related to OS & Language packs
- */
-Modernizr.addTest('unicode', function() {
-	
-	
-	var bool,
-
-		missingGlyph = document.createElement('span'),
-		
-		star = document.createElement('span');
-
-	Modernizr.testStyles('#modernizr{font-family:Arial,sans;font-size:300em;}', function(node) {
-
-		missingGlyph.innerHTML = '&#5987';
-		star.innerHTML = '&#9734';		
-		
-		node.appendChild(missingGlyph);
-		node.appendChild(star);
-		
-		bool = 'offsetWidth' in missingGlyph && missingGlyph.offsetWidth !== star.offsetWidth;
-	});
-
-	return bool;
-
-});
\ No newline at end of file
diff --git a/feature-detects/url-data-uri.js b/feature-detects/url-data-uri.js
deleted file mode 100644
index e6479a2..0000000
--- a/feature-detects/url-data-uri.js
+++ /dev/null
@@ -1,26 +0,0 @@
-// data uri test.
-// https://github.com/Modernizr/Modernizr/issues/14
-
-// This test is asynchronous. Watch out.
-
-
-// in IE7 in HTTPS this can cause a Mixed Content security popup. 
-//  github.com/Modernizr/Modernizr/issues/362
-// To avoid that you can create a new iframe and inject this.. perhaps..
-
-
-(function(){
-
-  var datauri = new Image();
-
-
-  datauri.onerror = function() {
-      Modernizr.addTest('datauri', function () { return false; });
-  };  
-  datauri.onload = function() {
-      Modernizr.addTest('datauri', function () { return (datauri.width == 1 && datauri.height == 1); });
-  };
-
-  datauri.src = "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==";
-
-})();
diff --git a/feature-detects/url/bloburls.js b/feature-detects/url/bloburls.js
new file mode 100644
index 0000000..18abd60
--- /dev/null
+++ b/feature-detects/url/bloburls.js
@@ -0,0 +1,21 @@
+/*!
+{
+  "name": "Blob URLs",
+  "property": "bloburls",
+  "caniuse": "bloburls",
+  "notes": [{
+    "name": "W3C Working Draft Spec",
+    "href": "https://www.w3.org/TR/FileAPI/#creating-revoking"
+  }],
+  "tags": ["file", "url"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"]
+}
+!*/
+/* DOC
+Detects support for creating Blob URLs
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  var url = prefixed('URL', window, false);
+  url = url && window[url];
+  Modernizr.addTest('bloburls', url && 'revokeObjectURL' in url && 'createObjectURL' in url);
+});
diff --git a/feature-detects/url/data-uri.js b/feature-detects/url/data-uri.js
new file mode 100644
index 0000000..251eb11
--- /dev/null
+++ b/feature-detects/url/data-uri.js
@@ -0,0 +1,76 @@
+/*!
+{
+  "name": "Data URI",
+  "property": "datauri",
+  "caniuse": "datauri",
+  "tags": ["url"],
+  "builderAliases": ["url_data_uri"],
+  "async": true,
+  "notes": [{
+    "name": "Wikipedia article",
+    "href": "https://en.wikipedia.org/wiki/Data_URI_scheme"
+  }],
+  "warnings": ["Support in Internet Explorer 8 is limited to images and linked resources like CSS files, not HTML files"]
+}
+!*/
+/* DOC
+Detects support for data URIs. Provides a subproperty to report support for data URIs over 32kb in size:
+
+```javascript
+Modernizr.datauri           // true
+Modernizr.datauri.over32kb  // false in IE8
+```
+*/
+define(['Modernizr'], function(Modernizr) {
+  // https://github.com/Modernizr/Modernizr/issues/14
+  Modernizr.addAsyncTest(function() {
+
+    // IE7 throw a mixed content warning on HTTPS for this test, so we'll
+    // just reject it (we know it doesn't support data URIs anyway)
+    // https://github.com/Modernizr/Modernizr/issues/362
+    if (navigator.userAgent.indexOf('MSIE 7.') !== -1) {
+      // Keep the test async
+      setTimeout(function() {
+        Modernizr.addTest('datauri', new Boolean(false));
+      }, 10);
+    }
+
+    var datauri = new Image();
+
+    datauri.onerror = function() {
+      Modernizr.addTest('datauri', new Boolean(false));
+    };
+    datauri.onload = function() {
+      if (datauri.width === 1 && datauri.height === 1) {
+        testOver32kb();
+      }
+      else {
+        Modernizr.addTest('datauri', new Boolean(false));
+      }
+    };
+
+    datauri.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
+
+    // Once we have datauri, let's check to see if we can use data URIs over
+    // 32kb (IE8 can't). https://github.com/Modernizr/Modernizr/issues/321
+    function testOver32kb() {
+
+      var datauriBig = new Image();
+
+      datauriBig.onerror = function() {
+        Modernizr.addTest('datauri', new Boolean(true));
+        Modernizr.addTest('datauri.over32kb', false);
+      };
+      datauriBig.onload = function() {
+        Modernizr.addTest('datauri', new Boolean(true));
+        Modernizr.addTest('datauri.over32kb', datauriBig.width === 1 && datauriBig.height === 1);
+      };
+
+      var base64str = 'R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==';
+      while (base64str.length < 33000) {
+        base64str = '\r\n' + base64str;
+      }
+      datauriBig.src = 'data:image/gif;base64,' + base64str;
+    }
+  });
+});
diff --git a/feature-detects/url/parser.js b/feature-detects/url/parser.js
new file mode 100644
index 0000000..d265087
--- /dev/null
+++ b/feature-detects/url/parser.js
@@ -0,0 +1,28 @@
+/*!
+{
+  "name": "URL parser",
+  "property": "urlparser",
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://url.spec.whatwg.org/"
+  }],
+  "polyfills": ["urlparser"],
+  "authors": ["Ron Waldon (@jokeyrhyme)"],
+  "tags": ["url"]
+}
+!*/
+/* DOC
+Check if browser implements the URL constructor for parsing URLs.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('urlparser', function() {
+    var url;
+    try {
+      // have to actually try use it, because Safari defines a dud constructor
+      url = new URL('http://modernizr.com/');
+      return url.href === 'http://modernizr.com/';
+    } catch (e) {
+      return false;
+    }
+  });
+});
diff --git a/feature-detects/url/urlsearchparams.js b/feature-detects/url/urlsearchparams.js
new file mode 100644
index 0000000..b31a145
--- /dev/null
+++ b/feature-detects/url/urlsearchparams.js
@@ -0,0 +1,22 @@
+/*!
+{
+  "property": "urlsearchparams",
+  "caniuse": "urlsearchparams",
+  "tags": ["querystring", "url"],
+  "authors": ["Cătălin Mariș"],
+  "name": "URLSearchParams API",
+  "notes": [{
+    "name": "WHATWG Spec",
+    "href": "https://url.spec.whatwg.org/#interface-urlsearchparams"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams"
+  }]
+}
+!*/
+/* DOC
+Detects support for an API that provides utility methods for working with the query string of a URL.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('urlsearchparams', 'URLSearchParams' in window);
+});
diff --git a/feature-detects/userdata.js b/feature-detects/userdata.js
deleted file mode 100644
index 79d921e..0000000
--- a/feature-detects/userdata.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// test if IE userdata supported
-// msdn.microsoft.com/en-us/library/ms531424(v=vs.85).aspx
-// test by @stereobooster
-
-Modernizr.addTest('userdata', function(){
-  return !!document.createElement('div').addBehavior;
-});
diff --git a/feature-detects/vibration.js b/feature-detects/vibration.js
index 034c25d..81b2b81 100644
--- a/feature-detects/vibration.js
+++ b/feature-detects/vibration.js
@@ -1,4 +1,20 @@
-// Vibration API
-// http://www.w3.org/TR/vibration/
-// https://developer.mozilla.org/en/DOM/window.navigator.mozVibrate
-Modernizr.addTest('vibrate', !!Modernizr.prefixed('vibrate', navigator));
\ No newline at end of file
+/*!
+{
+  "name": "Vibration API",
+  "property": "vibrate",
+  "caniuse": "vibration",
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en/DOM/window.navigator.mozVibrate"
+  }, {
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/vibration/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the API that provides access to the vibration mechanism of the hosting device, to provide tactile feedback.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('vibrate', !!prefixed('vibrate', navigator));
+});
diff --git a/feature-detects/video/autoplay.js b/feature-detects/video/autoplay.js
new file mode 100644
index 0000000..ca213cd
--- /dev/null
+++ b/feature-detects/video/autoplay.js
@@ -0,0 +1,85 @@
+/*!
+{
+  "name": "Video Autoplay",
+  "property": "videoautoplay",
+  "tags": ["video"],
+  "async": true,
+  "warnings": ["This test is very large – only include it if you absolutely need it"],
+  "knownBugs": ["crashes with an alert on iOS7 when added to homescreen"]
+}
+!*/
+/* DOC
+Checks for support of the autoplay attribute of the video element.
+*/
+define(['Modernizr', 'addTest', 'docElement', 'createElement', 'test/video/video'], function(Modernizr, addTest, docElement, createElement) {
+
+  Modernizr.addAsyncTest(function() {
+    var timeout;
+    var waitTime = 200;
+    var retries = 5;
+    var currentTry = 0;
+    var elem = createElement('video');
+    var elemStyle = elem.style;
+
+    function testAutoplay(arg) {
+      currentTry++;
+      clearTimeout(timeout);
+
+      var result = arg && arg.type === 'playing' || elem.currentTime !== 0;
+
+      if (!result && currentTry < retries) {
+        //Detection can be flaky if the browser is slow, so lets retry in a little bit
+        timeout = setTimeout(testAutoplay, waitTime);
+        return;
+      }
+
+      elem.removeEventListener('playing', testAutoplay, false);
+      addTest('videoautoplay', result);
+
+      // Cleanup, but don't assume elem is still in the page -
+      // an extension (eg Flashblock) may already have removed it.
+      if (elem.parentNode) {
+        elem.parentNode.removeChild(elem);
+      }
+    }
+
+    //skip the test if video itself, or the autoplay
+    //element on it isn't supported
+    if (!Modernizr.video || !('autoplay' in elem)) {
+      addTest('videoautoplay', false);
+      return;
+    }
+
+    elemStyle.position = 'absolute';
+    elemStyle.height = 0;
+    elemStyle.width = 0;
+
+    try {
+      if (Modernizr.video.ogg) {
+        elem.src = 'data:video/ogg;base64,T2dnUwACAAAAAAAAAABmnCATAAAAAHDEixYBKoB0aGVvcmEDAgEAAQABAAAQAAAQAAAAAAAFAAAAAQAAAAAAAAAAAGIAYE9nZ1MAAAAAAAAAAAAAZpwgEwEAAAACrA7TDlj///////////////+QgXRoZW9yYSsAAABYaXBoLk9yZyBsaWJ0aGVvcmEgMS4xIDIwMDkwODIyIChUaHVzbmVsZGEpAQAAABoAAABFTkNPREVSPWZmbXBlZzJ0aGVvcmEtMC4yOYJ0aGVvcmG+zSj3uc1rGLWpSUoQc5zmMYxSlKQhCDGMYhCEIQhAAAAAAAAAAAAAEW2uU2eSyPxWEvx4OVts5ir1aKtUKBMpJFoQ/nk5m41mUwl4slUpk4kkghkIfDwdjgajQYC8VioUCQRiIQh8PBwMhgLBQIg4FRba5TZ5LI/FYS/Hg5W2zmKvVoq1QoEykkWhD+eTmbjWZTCXiyVSmTiSSCGQh8PB2OBqNBgLxWKhQJBGIhCHw8HAyGAsFAiDgUCw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDw8PDAwPEhQUFQ0NDhESFRUUDg4PEhQVFRUOEBETFBUVFRARFBUVFRUVEhMUFRUVFRUUFRUVFRUVFRUVFRUVFRUVEAwLEBQZGxwNDQ4SFRwcGw4NEBQZHBwcDhATFhsdHRwRExkcHB4eHRQYGxwdHh4dGxwdHR4eHh4dHR0dHh4eHRALChAYKDM9DAwOExo6PDcODRAYKDlFOA4RFh0zV1A+EhYlOkRtZ00YIzdAUWhxXDFATldneXhlSFxfYnBkZ2MTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExMTEhIVGRoaGhoSFBYaGhoaGhUWGRoaGhoaGRoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhoaGhESFh8kJCQkEhQYIiQkJCQWGCEkJCQkJB8iJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQkJCQREhgvY2NjYxIVGkJjY2NjGBo4Y2NjY2MvQmNjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRISEhUXGBkbEhIVFxgZGxwSFRcYGRscHRUXGBkbHB0dFxgZGxwdHR0YGRscHR0dHhkbHB0dHR4eGxwdHR0eHh4REREUFxocIBERFBcaHCAiERQXGhwgIiUUFxocICIlJRcaHCAiJSUlGhwgIiUlJSkcICIlJSUpKiAiJSUlKSoqEBAQFBgcICgQEBQYHCAoMBAUGBwgKDBAFBgcICgwQEAYHCAoMEBAQBwgKDBAQEBgICgwQEBAYIAoMEBAQGCAgAfF5cdH1e3Ow/L66wGmYnfIUbwdUTe3LMRbqON8B+5RJEvcGxkvrVUjTMrsXYhAnIwe0dTJfOYbWrDYyqUrz7dw/JO4hpmV2LsQQvkUeGq1BsZLx+cu5iV0e0eScJ91VIQYrmqfdVSK7GgjOU0oPaPOu5IcDK1mNvnD+K8LwS87f8Jx2mHtHnUkTGAurWZlNQa74ZLSFH9oF6FPGxzLsjQO5Qe0edcpttd7BXBSqMCL4k/4tFrHIPuEQ7m1/uIWkbDMWVoDdOSuRQ9286kvVUlQjzOE6VrNguN4oRXYGkgcnih7t13/9kxvLYKQezwLTrO44sVmMPgMqORo1E0sm1/9SludkcWHwfJwTSybR4LeAz6ugWVgRaY8mV/9SluQmtHrzsBtRF/wPY+X0JuYTs+ltgrXAmlk10xQHmTu9VSIAk1+vcvU4ml2oNzrNhEtQ3CysNP8UeR35wqpKUBdGdZMSjX4WVi8nJpdpHnbhzEIdx7mwf6W1FKAiucMXrWUWVjyRf23chNtR9mIzDoT/6ZLYailAjhFlZuvPtSeZ+2oREubDoWmT3TguY+JHPdRVSLKxfKH3vgNqJ/9emeEYikGXDFNzaLjvTeGAL61mogOoeG3y6oU4rW55ydoj0lUTSR/mmRhPmF86uwIfzp3FtiufQCmppaHDlGE0r2iTzXIw3zBq5hvaTldjG4CPb9wdxAme0SyedVKczJ9AtYbgPOzYKJvZZImsN7ecrxWZg5dR6ZLj/j4qpWsIA+vYwE+Tca9ounMIsrXMB4Stiib2SPQtZv+FVIpfEbzv8ncZoLBXc3YBqTG1HsskTTotZOYTG+oVUjLk6zhP8bg4RhMUNtfZdO7FdpBuXzhJ5Fh8IKlJG7wtD9ik8rWOJxy6iQ3NwzBpQ219mlyv+FLicYs2iJGSE0u2txzed++D61ZWCiHD/cZdQVCqkO2gJpdpNaObhnDfAPrT89RxdWFZ5hO3MseBSIlANppdZNIV/Rwe5eLTDvkfWKzFnH+QJ7m9QWV1KdwnuIwTNtZdJMoXBf74OhRnh2t+OTGL+AVUnIkyYY+QG7g9itHXyF3OIygG2s2kud679ZWKqSFa9n3IHD6MeLv1lZ0XyduRhiDRtrNnKoyiFVLcBm0ba5Yy3fQkDh4XsFE34isVpOzpa9nR8iCpS4HoxG2rJpnRhf3YboVa1PcRouh5LIJv/uQcPNd095ickTaiGBnWLKVWRc0OnYTSyex/n2FofEPnDG8y3PztHrzOLK1xo6RAml2k9owKajOC0Wr4D5x+3nA0UEhK2m198wuBHF3zlWWVKWLN1CHzLClUfuoYBcx4b1llpeBKmbayaR58njtE9onD66lUcsg0Spm2snsb+8HaJRn4dYcLbCuBuYwziB8/5U1C1DOOz2gZjSZtrLJk6vrLF3hwY4Io9xuT/ruUFRSBkNtUzTOWhjh26irLEPx4jPZL3Fo3QrReoGTTM21xYTT9oFdhTUIvjqTkfkvt0bzgVUjq/hOYY8j60IaO/0AzRBtqkTS6R5ellZd5uKdzzhb8BFlDdAcrwkE0rbXTOPB+7Y0FlZO96qFL4Ykg21StJs8qIW7h16H5hGiv8V2Cflau7QVDepTAHa6Lgt6feiEvJDM21StJsmOH/hynURrKxvUpQ8BH0JF7BiyG2qZpnL/7AOU66gt+reLEXY8pVOCQvSsBtqZTNM8bk9ohRcwD18o/WVkbvrceVKRb9I59IEKysjBeTMmmbA21xu/6iHadLRxuIzkLpi8wZYmmbbWi32RVAUjruxWlJ//iFxE38FI9hNKOoCdhwf5fDe4xZ81lgREhK2m1j78vW1CqkuMu/AjBNK210kzRUX/B+69cMMUG5bYrIeZxVSEZISmkzbXOi9yxwIfPgdsov7R71xuJ7rFcACjG/9PzApqFq7wEgzNJm2suWESPuwrQvejj7cbnQxMkxpm21lUYJL0fKmogPPqywn7e3FvB/FCNxPJ85iVUkCE9/tLKx31G4CgNtWTTPFhMvlu8G4/TrgaZttTChljfNJGgOT2X6EqpETy2tYd9cCBI4lIXJ1/3uVUllZEJz4baqGF64yxaZ+zPLYwde8Uqn1oKANtUrSaTOPHkhvuQP3bBlEJ/LFe4pqQOHUI8T8q7AXx3fLVBgSCVpMba55YxN3rv8U1Dv51bAPSOLlZWebkL8vSMGI21lJmmeVxPRwFlZF1CpqCN8uLwymaZyjbXHCRytogPN3o/n74CNykfT+qqRv5AQlHcRxYrC5KvGmbbUwmZY/29BvF6C1/93x4WVglXDLFpmbapmF89HKTogRwqqSlGbu+oiAkcWFbklC6Zhf+NtTLFpn8oWz+HsNRVSgIxZWON+yVyJlE5tq/+GWLTMutYX9ekTySEQPLVNQQ3OfycwJBM0zNtZcse7CvcKI0V/zh16Dr9OSA21MpmmcrHC+6pTAPHPwoit3LHHqs7jhFNRD6W8+EBGoSEoaZttTCZljfduH/fFisn+dRBGAZYtMzbVMwvul/T/crK1NQh8gN0SRRa9cOux6clC0/mDLFpmbarmF8/e6CopeOLCNW6S/IUUg3jJIYiAcDoMcGeRbOvuTPjXR/tyo79LK3kqqkbxkkMRAOB0GODPItnX3Jnxro/25Ud+llbyVVSN4ySGIgHA6DHBnkWzr7kz410f7cqO/Syt5KqpFVJwn6gBEvBM0zNtZcpGOEPiysW8vvRd2R0f7gtjhqUvXL+gWVwHm4XJDBiMpmmZtrLfPwd/IugP5+fKVSysH1EXreFAcEhelGmbbUmZY4Xdo1vQWVnK19P4RuEnbf0gQnR+lDCZlivNM22t1ESmopPIgfT0duOfQrsjgG4tPxli0zJmF5trdL1JDUIUT1ZXSqQDeR4B8mX3TrRro/2McGeUvLtwo6jIEKMkCUXWsLyZROd9P/rFYNtXPBli0z398iVUlVKAjFlY437JXImUTm2r/4ZYtMy61hf16RPJIU9nZ1MABAwAAAAAAAAAZpwgEwIAAABhp658BScAAAAAAADnUFBQXIDGXLhwtttNHDhw5OcpQRMETBEwRPduylKVB0HRdF0A';
+      }
+      else if (Modernizr.video.h264) {
+        elem.src = 'data:video/mp4;base64,AAAAIGZ0eXBpc29tAAACAGlzb21pc28yYXZjMW1wNDEAAAAIZnJlZQAAAs1tZGF0AAACrgYF//+q3EXpvebZSLeWLNgg2SPu73gyNjQgLSBjb3JlIDE0OCByMjYwMSBhMGNkN2QzIC0gSC4yNjQvTVBFRy00IEFWQyBjb2RlYyAtIENvcHlsZWZ0IDIwMDMtMjAxNSAtIGh0dHA6Ly93d3cudmlkZW9sYW4ub3JnL3gyNjQuaHRtbCAtIG9wdGlvbnM6IGNhYmFjPTEgcmVmPTMgZGVibG9jaz0xOjA6MCBhbmFseXNlPTB4MzoweDExMyBtZT1oZXggc3VibWU9NyBwc3k9MSBwc3lfcmQ9MS4wMDowLjAwIG1peGVkX3JlZj0xIG1lX3JhbmdlPTE2IGNocm9tYV9tZT0xIHRyZWxsaXM9MSA4eDhkY3Q9MSBjcW09MCBkZWFkem9uZT0yMSwxMSBmYXN0X3Bza2lwPTEgY2hyb21hX3FwX29mZnNldD0tMiB0aHJlYWRzPTEgbG9va2FoZWFkX3RocmVhZHM9MSBzbGljZWRfdGhyZWFkcz0wIG5yPTAgZGVjaW1hdGU9MSBpbnRlcmxhY2VkPTAgYmx1cmF5X2NvbXBhdD0wIGNvbnN0cmFpbmVkX2ludHJhPTAgYmZyYW1lcz0zIGJfcHlyYW1pZD0yIGJfYWRhcHQ9MSBiX2JpYXM9MCBkaXJlY3Q9MSB3ZWlnaHRiPTEgb3Blbl9nb3A9MCB3ZWlnaHRwPTIga2V5aW50PTI1MCBrZXlpbnRfbWluPTEwIHNjZW5lY3V0PTQwIGludHJhX3JlZnJlc2g9MCByY19sb29rYWhlYWQ9NDAgcmM9Y3JmIG1idHJlZT0xIGNyZj0yMy4wIHFjb21wPTAuNjAgcXBtaW49MCBxcG1heD02OSBxcHN0ZXA9NCBpcF9yYXRpbz0xLjQwIGFxPTE6MS4wMACAAAAAD2WIhAA3//728P4FNjuZQQAAAu5tb292AAAAbG12aGQAAAAAAAAAAAAAAAAAAAPoAAAAZAABAAABAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACAAACGHRyYWsAAABcdGtoZAAAAAMAAAAAAAAAAAAAAAEAAAAAAAAAZAAAAAAAAAAAAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAEAAAAAAAgAAAAIAAAAAACRlZHRzAAAAHGVsc3QAAAAAAAAAAQAAAGQAAAAAAAEAAAAAAZBtZGlhAAAAIG1kaGQAAAAAAAAAAAAAAAAAACgAAAAEAFXEAAAAAAAtaGRscgAAAAAAAAAAdmlkZQAAAAAAAAAAAAAAAFZpZGVvSGFuZGxlcgAAAAE7bWluZgAAABR2bWhkAAAAAQAAAAAAAAAAAAAAJGRpbmYAAAAcZHJlZgAAAAAAAAABAAAADHVybCAAAAABAAAA+3N0YmwAAACXc3RzZAAAAAAAAAABAAAAh2F2YzEAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAgACAEgAAABIAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY//8AAAAxYXZjQwFkAAr/4QAYZ2QACqzZX4iIhAAAAwAEAAADAFA8SJZYAQAGaOvjyyLAAAAAGHN0dHMAAAAAAAAAAQAAAAEAAAQAAAAAHHN0c2MAAAAAAAAAAQAAAAEAAAABAAAAAQAAABRzdHN6AAAAAAAAAsUAAAABAAAAFHN0Y28AAAAAAAAAAQAAADAAAABidWR0YQAAAFptZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAAC1pbHN0AAAAJal0b28AAAAdZGF0YQAAAAEAAAAATGF2ZjU2LjQwLjEwMQ==';
+      }
+      else {
+        addTest('videoautoplay', false);
+        return;
+      }
+    }
+
+    catch (e) {
+      addTest('videoautoplay', false);
+      return;
+    }
+
+    elem.setAttribute('autoplay', '');
+    elemStyle.cssText = 'display:none';
+    docElement.appendChild(elem);
+    // wait for the next tick to add the listener, otherwise the element may
+    // not have time to play in high load situations (e.g. the test suite)
+    setTimeout(function() {
+      elem.addEventListener('playing', testAutoplay, false);
+      timeout = setTimeout(testAutoplay, waitTime);
+    }, 0);
+  });
+});
diff --git a/feature-detects/video/crossorigin.js b/feature-detects/video/crossorigin.js
new file mode 100644
index 0000000..f7666ee
--- /dev/null
+++ b/feature-detects/video/crossorigin.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "Video crossOrigin",
+  "property": "videocrossorigin",
+  "caniuse": "cors",
+  "authors": ["Florian Mailliet"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_settings_attributes"
+  }]
+}
+!*/
+/* DOC
+Detects support for the crossOrigin attribute on video tag
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('videocrossorigin', 'crossOrigin' in createElement('video'));
+});
diff --git a/feature-detects/video/loop.js b/feature-detects/video/loop.js
new file mode 100644
index 0000000..9cfa5af
--- /dev/null
+++ b/feature-detects/video/loop.js
@@ -0,0 +1,10 @@
+/*!
+{
+  "name": "Video Loop Attribute",
+  "property": "videoloop",
+  "tags": ["video", "media"]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('videoloop', 'loop' in createElement('video'));
+});
diff --git a/feature-detects/video/preload.js b/feature-detects/video/preload.js
new file mode 100644
index 0000000..3ab95a8
--- /dev/null
+++ b/feature-detects/video/preload.js
@@ -0,0 +1,10 @@
+/*!
+{
+  "name": "Video Preload Attribute",
+  "property": "videopreload",
+  "tags": ["video", "media"]
+}
+!*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('videopreload', 'preload' in createElement('video'));
+});
diff --git a/feature-detects/video/video.js b/feature-detects/video/video.js
new file mode 100644
index 0000000..094dd4f
--- /dev/null
+++ b/feature-detects/video/video.js
@@ -0,0 +1,64 @@
+/*!
+{
+  "name": "HTML5 Video",
+  "property": "video",
+  "caniuse": "video",
+  "tags": ["html5", "video", "media"],
+  "knownBugs": ["Without QuickTime, `Modernizr.video.h264` will be `undefined`; https://github.com/Modernizr/Modernizr/issues/546"],
+  "polyfills": [
+    "html5media",
+    "mediaelementjs",
+    "videojs",
+    "leanbackplayer",
+    "videoforeverybody"
+  ]
+}
+!*/
+/* DOC
+Detects support for the video element, as well as testing what types of content it supports.
+
+Subproperties are provided to describe support for `ogg`, `h264`, `h265`, `webm`, `vp9`, `hls` and `av1` formats, e.g.:
+
+```javascript
+Modernizr.video         // true
+Modernizr.video.ogg     // 'probably'
+```
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
+  //                     thx to NielsLeenheer and zcorpan
+
+  // Note: in some older browsers, "no" was a return value instead of empty string.
+  //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
+  //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
+  (function() {
+    var elem = createElement('video');
+
+    Modernizr.addTest('video', function() {
+      var bool = false;
+      try {
+        bool = !!elem.canPlayType;
+        if (bool) {
+          bool = new Boolean(bool);
+        }
+      } catch (e) {}
+
+      return bool;
+    });
+
+    // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
+    try {
+      if (!!elem.canPlayType) {
+        Modernizr.addTest('video.ogg', elem.canPlayType('video/ogg; codecs="theora"').replace(/^no$/, ''));
+
+        // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
+        Modernizr.addTest('video.h264', elem.canPlayType('video/mp4; codecs="avc1.42E01E"').replace(/^no$/, ''));
+        Modernizr.addTest('video.h265', elem.canPlayType('video/mp4; codecs="hev1"').replace(/^no$/, ''));
+        Modernizr.addTest('video.webm', elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/, ''));
+        Modernizr.addTest('video.vp9', elem.canPlayType('video/webm; codecs="vp9"').replace(/^no$/, ''));
+        Modernizr.addTest('video.hls', elem.canPlayType('application/x-mpegURL; codecs="avc1.42E01E"').replace(/^no$/, ''));
+        Modernizr.addTest('video.av1', elem.canPlayType('video/mp4; codecs="av01"').replace(/^no$/, ''));
+      }
+    } catch (e) {}
+  })();
+});
diff --git a/feature-detects/vml.js b/feature-detects/vml.js
new file mode 100644
index 0000000..c4783db
--- /dev/null
+++ b/feature-detects/vml.js
@@ -0,0 +1,36 @@
+/*!
+{
+  "name": "VML",
+  "property": "vml",
+  "tags": ["vml"],
+  "authors": ["Craig Andrews (@candrews)"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/NOTE-VML"
+  }, {
+    "name": "MSDN Documentation",
+    "href": "https://docs.microsoft.com/en-us/windows/desktop/VML/msdn-online-vml-introduction"
+  }]
+}
+!*/
+/* DOC
+Detects support for VML.
+*/
+define(['Modernizr', 'createElement', 'isSVG'], function(Modernizr, createElement, isSVG) {
+  Modernizr.addTest('vml', function() {
+    var containerDiv = createElement('div');
+    var supports = false;
+    var shape;
+
+    if (!isSVG) {
+      containerDiv.innerHTML = '<v:shape id="vml_flag1" adj="1" />';
+      shape = containerDiv.firstChild;
+      if ('style' in shape) {
+        shape.style.behavior = 'url(#default#VML)';
+      }
+      supports = shape ? typeof shape.adj === 'object' : true;
+    }
+
+    return supports;
+  });
+});
diff --git a/feature-detects/web-intents.js b/feature-detects/web-intents.js
index d0557fe..10c79e6 100644
--- a/feature-detects/web-intents.js
+++ b/feature-detects/web-intents.js
@@ -1,6 +1,21 @@
-// Tests for the ability to use Web Intents (http://webintents.org).
-// By Eric Bidelman
+/*!
+{
+  "name": "Web Intents",
+  "property": "webintents",
+  "authors": ["Eric Bidelman"],
+  "notes": [{
+    "name": "Web Intents project site",
+    "href": "http://www.webintents.org/"
+  }],
+  "builderAliases": ["web_intents"]
+}
+!*/
+/* DOC
+Detects native support for the Web Intents APIs for service discovery and inter-application communication.
 
-Modernizr.addTest('webintents', function() {
-  return !!Modernizr.prefixed('startActivity', navigator);
+Chrome added support for this in v19, but [removed it again in v24](https://lists.w3.org/Archives/Public/public-web-intents/2012Nov/0000.html) because of "a number of areas for
+development in both the API and specific user experience in Chrome". No other browsers currently support it, however a [JavaScript shim](http://www.webintents.org/#javascriptshim) is available.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('webintents', !!prefixed('startActivity', navigator));
 });
diff --git a/feature-detects/webanimations.js b/feature-detects/webanimations.js
new file mode 100644
index 0000000..8420ea7
--- /dev/null
+++ b/feature-detects/webanimations.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "Web Animation API",
+  "property": "webanimations",
+  "caniuse": "web-animation",
+  "tags": ["webanimations"],
+  "polyfills": ["webanimationsjs"],
+  "notes": [{
+    "name": "Introducing Web Animations",
+    "href": "https://birtles.wordpress.com/2013/06/26/introducing-web-animations/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the Web Animation API, a way to create css animations in js
+*/
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  Modernizr.addTest('webanimations', 'animate' in createElement('div'));
+});
diff --git a/feature-detects/webauthn/publickeycredential.js b/feature-detects/webauthn/publickeycredential.js
new file mode 100644
index 0000000..a63d753
--- /dev/null
+++ b/feature-detects/webauthn/publickeycredential.js
@@ -0,0 +1,31 @@
+/*!
+{
+  "name": "PublicKeyCredential",
+  "notes": [
+    {
+      "name": "MDN Documentation",
+      "href": "https://developer.mozilla.org/en-US/docs/Web/API/PublicKeyCredential"
+    },
+    {
+      "name": "Google Developers solution",
+      "href": "https://developers.google.com/web/updates/2018/03/webauthn-credential-management#the_solution"
+    }
+  ],
+  "property": "publickeycredential",
+  "tags": ["webauthn", "web authentication"],
+  "authors": ["Eric Delia"]
+}
+!*/
+/* DOC
+Detects support for PublicKeyCredential as part of the Web Authentication API (also known as webauthn)
+*/
+
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('publicKeyCredential', function() {
+    if (window.PublicKeyCredential) {
+      return true;
+    }
+
+    return false;
+  });
+});
diff --git a/feature-detects/webgl-extensions.js b/feature-detects/webgl-extensions.js
deleted file mode 100644
index c005c00..0000000
--- a/feature-detects/webgl-extensions.js
+++ /dev/null
@@ -1,42 +0,0 @@
-
-// Grab the WebGL extensions currently supported and add to the Modernizr.webgl object
-// spec: www.khronos.org/registry/webgl/specs/latest/#5.13.14
-
-// based on code from ilmari heikkinen
-// code.google.com/p/graphics-detect/source/browse/js/detect.js
-
-
-(function(){
-
-    if (!Modernizr.webgl) return;
-
-    var canvas, ctx, exts;
-
-    try {
-        canvas  = document.createElement('canvas');
-        ctx     = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
-        exts    = ctx.getSupportedExtensions();
-    }
-    catch (e) {
-        return;
-    }
-
-    if (ctx === undefined) {
-        Modernizr.webgl = new Boolean(false);
-    }
-    else {
-        Modernizr.webgl = new Boolean(true);
-    }
-
-
-    for (var i = -1, len = exts.length; ++i < len; ){
-        Modernizr.webgl[exts[i]] = true;
-    }
-
-    // hack for addressing modernizr testsuite failures. sorry.
-    if (window.TEST && TEST.audvid){
-        TEST.audvid.push('webgl');
-    }
-
-    canvas = undefined;
-})();
\ No newline at end of file
diff --git a/feature-detects/webgl/extensions.js b/feature-detects/webgl/extensions.js
new file mode 100644
index 0000000..045dbb1
--- /dev/null
+++ b/feature-detects/webgl/extensions.js
@@ -0,0 +1,64 @@
+/*!
+{
+  "name": "WebGL Extensions",
+  "property": "webglextensions",
+  "tags": ["webgl", "graphics"],
+  "builderAliases": ["webgl_extensions"],
+  "async": true,
+  "authors": ["Ilmari Heikkinen"],
+  "notes": [{
+    "name": "Kronos extensions registry",
+    "href": "https://www.khronos.org/registry/webgl/extensions/"
+  }]
+}
+!*/
+/* DOC
+Detects support for OpenGL extensions in WebGL. It's `true` if the [WebGL extensions API](https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Using_Extensions) is supported, then exposes the supported extensions as subproperties, e.g.:
+
+```javascript
+if (Modernizr.webglextensions) {
+  // WebGL extensions API supported
+}
+if ('OES_vertex_array_object' in Modernizr.webglextensions) {
+  // Vertex Array Objects extension supported
+}
+```
+*/
+define(['Modernizr', 'createElement', 'test/webgl/webgl'], function(Modernizr, createElement) {
+  // based on code from ilmari heikkinen
+  // code.google.com/p/graphics-detect/source/browse/js/detect.js
+
+  // Not Async but handles it's own self
+  Modernizr.addAsyncTest(function() {
+
+    // Not a good candidate for css classes, so we avoid addTest stuff
+    Modernizr.webglextensions = false;
+
+    if (!Modernizr.webgl) {
+      return;
+    }
+
+    var canvas;
+    var ctx;
+    var exts;
+
+    try {
+      canvas = createElement('canvas');
+      ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
+      exts = ctx.getSupportedExtensions();
+    }
+    catch (e) {
+      return;
+    }
+
+    if (ctx !== undefined) {
+      Modernizr.webglextensions = new Boolean(true);
+    }
+
+    for (var i = -1, len = exts.length; ++i < len;) {
+      Modernizr.webglextensions[exts[i]] = true;
+    }
+
+    canvas = undefined;
+  });
+});
diff --git a/feature-detects/webgl/webgl.js b/feature-detects/webgl/webgl.js
new file mode 100644
index 0000000..582c795
--- /dev/null
+++ b/feature-detects/webgl/webgl.js
@@ -0,0 +1,14 @@
+/*!
+{
+  "name": "WebGL",
+  "property": "webgl",
+  "caniuse": "webgl",
+  "tags": ["webgl", "graphics"],
+  "polyfills": ["jebgl", "cwebgl", "iewebgl"]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('webgl', function() {
+    return 'WebGLRenderingContext' in window;
+  });
+});
diff --git a/feature-detects/webrtc/datachannel.js b/feature-detects/webrtc/datachannel.js
new file mode 100644
index 0000000..3ce1609
--- /dev/null
+++ b/feature-detects/webrtc/datachannel.js
@@ -0,0 +1,32 @@
+/*!
+{
+  "name": "RTC Data Channel",
+  "property": "datachannel",
+  "notes": [{
+    "name": "HTML5 Rocks Tutorial",
+    "href": "https://www.html5rocks.com/en/tutorials/webrtc/datachannels/"
+  }]
+}
+!*/
+/* DOC
+Detect for the RTCDataChannel API that allows for transfer data directly from one peer to another
+*/
+define(['Modernizr', 'prefixed', 'domPrefixesAll', 'test/webrtc/peerconnection'], function(Modernizr, prefixed, domPrefixesAll) {
+  Modernizr.addTest('datachannel', function() {
+    if (!Modernizr.peerconnection) {
+      return false;
+    }
+    for (var i = 0, len = domPrefixesAll.length; i < len; i++) {
+      var PeerConnectionConstructor = window[domPrefixesAll[i] + 'RTCPeerConnection'];
+      if (PeerConnectionConstructor) {
+        // Wrapped in a try catch to avoid "Error creating RTCPeerConnection" #2599 & #2221
+        try {
+          var peerConnection = new PeerConnectionConstructor({});
+          return 'createDataChannel' in peerConnection;
+        } catch (e) {
+        }
+      }
+    }
+    return false;
+  });
+});
diff --git a/feature-detects/webrtc/getusermedia.js b/feature-detects/webrtc/getusermedia.js
new file mode 100644
index 0000000..ec5cbce
--- /dev/null
+++ b/feature-detects/webrtc/getusermedia.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "getUserMedia",
+  "property": "getusermedia",
+  "caniuse": "stream",
+  "tags": ["webrtc"],
+  "authors": ["Eric Bidelman", "Masataka Yakura"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://w3c.github.io/mediacapture-main/#dom-mediadevices-getusermedia"
+  }]
+}
+!*/
+/* DOC
+Detects support for the new Promise-based `getUserMedia` API.
+*/
+define(['Modernizr'], function (Modernizr) {
+  Modernizr.addTest('getUserMedia', 'mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices);
+});
diff --git a/feature-detects/webrtc/mediastream.js b/feature-detects/webrtc/mediastream.js
new file mode 100644
index 0000000..02a03ab
--- /dev/null
+++ b/feature-detects/webrtc/mediastream.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "MediaStream Recording API",
+  "property": "mediarecorder",
+  "caniuse": "mediarecorder",
+  "tags": ["mediarecorder", "media"],
+  "authors": ["Onkar Dahale"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/MediaStream_Recording_API"
+  }]
+}
+!*/
+/* DOC
+Detects support for the MediaStream Recording API.
+*/
+define(['Modernizr'], function (Modernizr) {
+    Modernizr.addTest('mediastream', typeof MediaRecorder !== "undefined" );
+});
diff --git a/feature-detects/webrtc/peerconnection.js b/feature-detects/webrtc/peerconnection.js
new file mode 100644
index 0000000..8afbefe
--- /dev/null
+++ b/feature-detects/webrtc/peerconnection.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "RTC Peer Connection",
+  "property": "peerconnection",
+  "caniuse": "rtcpeerconnection",
+  "tags": ["webrtc"],
+  "authors": ["Ankur Oberoi"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/webrtc/"
+  }]
+}
+!*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('peerconnection', !!prefixed('RTCPeerConnection', window));
+});
diff --git a/feature-detects/websockets-binary.js b/feature-detects/websockets-binary.js
deleted file mode 100644
index 8f15c25..0000000
--- a/feature-detects/websockets-binary.js
+++ /dev/null
@@ -1,7 +0,0 @@
-
-// binaryType is truthy if there is support.. returns "blob" in new-ish chrome.
-// plus.google.com/115535723976198353696/posts/ERN6zYozENV
-
-Modernizr.addTest('websocketsbinary', 
-  !!(window.WebSocket && (new WebSocket('ws://.')).binaryType)
-);
diff --git a/feature-detects/websockets.js b/feature-detects/websockets.js
new file mode 100644
index 0000000..9986deb
--- /dev/null
+++ b/feature-detects/websockets.js
@@ -0,0 +1,30 @@
+/*!
+{
+  "name": "WebSockets Support",
+  "property": "websockets",
+  "authors": ["Phread (@fearphage)", "Mike Sherov (@mikesherov)", "Burak Yigit Kaya (@BYK)"],
+  "caniuse": "websockets",
+  "tags": ["html5"],
+  "knownBugs": ["This test will reject any old version of WebSockets even if it is not prefixed such as in Safari 5.1"],
+  "notes": [{
+    "name": "CLOSING State and Spec",
+    "href": "https://www.w3.org/TR/websockets/#the-websocket-interface"
+  }],
+  "polyfills": [
+    "sockjs",
+    "socketio",
+    "websocketjs",
+    "atmosphere",
+    "graceful-websocket",
+    "portal",
+    "datachannel"
+  ]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  var supports = false;
+  try {
+    supports = 'WebSocket' in window && window.WebSocket.CLOSING === 2;
+  } catch (e) {}
+  Modernizr.addTest('websockets', supports);
+});
diff --git a/feature-detects/websockets/binary.js b/feature-detects/websockets/binary.js
new file mode 100644
index 0000000..44b3677
--- /dev/null
+++ b/feature-detects/websockets/binary.js
@@ -0,0 +1,30 @@
+/*!
+{
+  "name": "Binary WebSockets",
+  "property": "websocketsbinary",
+  "tags": ["websockets"],
+  "builderAliases": ["websockets_binary"]
+}
+!*/
+define(['Modernizr'], function(Modernizr) {
+  // binaryType is truthy if there is support.. returns "blob" in new-ish chrome.
+  // plus.google.com/115535723976198353696/posts/ERN6zYozENV
+  // github.com/Modernizr/Modernizr/issues/370
+
+  Modernizr.addTest('websocketsbinary', function() {
+    var protocol = 'https:' === location.protocol ? 'wss' : 'ws',
+      protoBin;
+
+    if ('WebSocket' in window) {
+      protoBin = 'binaryType' in WebSocket.prototype;
+      if (protoBin) {
+        return protoBin;
+      }
+      try {
+        return !!(new WebSocket(protocol + '://.').binaryType);
+      } catch (e) {}
+    }
+
+    return false;
+  });
+});
diff --git a/feature-detects/window-framed.js b/feature-detects/window-framed.js
deleted file mode 100644
index f8a6704..0000000
--- a/feature-detects/window-framed.js
+++ /dev/null
@@ -1,8 +0,0 @@
-
-// tests if page is iframed
-
-// github.com/Modernizr/Modernizr/issues/242
-
-Modernizr.addTest('framed', function(){
-  return window.location != top.location;
-});
diff --git a/feature-detects/window/atob-btoa.js b/feature-detects/window/atob-btoa.js
new file mode 100644
index 0000000..d8fb548
--- /dev/null
+++ b/feature-detects/window/atob-btoa.js
@@ -0,0 +1,24 @@
+/*!
+{
+  "name": "Base 64 encoding/decoding",
+  "property": "atobbtoa",
+  "builderAliases": ["atob-btoa"],
+  "caniuse": "atob-btoa",
+  "tags": ["atob", "base64", "WindowBase64", "btoa"],
+  "authors": ["Christian Ulbrich"],
+  "notes": [{
+    "name": "WindowBase64",
+    "href": "https://www.w3.org/TR/html5/webappapis.html#windowbase64"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/atob"
+  }],
+  "polyfills": ["base64js"]
+}
+!*/
+/* DOC
+Detects support for WindowBase64 API (window.atob && window.btoa).
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('atobbtoa', 'atob' in window && 'btoa' in window, {aliases: ['atob-btoa']});
+});
diff --git a/feature-detects/window/framed.js b/feature-detects/window/framed.js
new file mode 100644
index 0000000..8352b93
--- /dev/null
+++ b/feature-detects/window/framed.js
@@ -0,0 +1,16 @@
+/*!
+{
+  "name": "Framed window",
+  "property": "framed",
+  "tags": ["window"],
+  "builderAliases": ["window_framed"]
+}
+!*/
+/* DOC
+Tests if page is iframed.
+*/
+define(['Modernizr'], function(Modernizr) {
+  // github.com/Modernizr/Modernizr/issues/242
+
+  Modernizr.addTest('framed', window.location !== top.location);
+});
diff --git a/feature-detects/window/matchmedia.js b/feature-detects/window/matchmedia.js
new file mode 100644
index 0000000..1e1cebc
--- /dev/null
+++ b/feature-detects/window/matchmedia.js
@@ -0,0 +1,23 @@
+/*!
+{
+  "name": "matchMedia",
+  "property": "matchmedia",
+  "caniuse": "matchmedia",
+  "tags": ["matchmedia"],
+  "authors": ["Alberto Elias"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://drafts.csswg.org/cssom-view/#the-mediaquerylist-interface"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Window.matchMedia"
+  }],
+  "polyfills": ["matchmediajs"]
+}
+!*/
+/* DOC
+Detects support for matchMedia.
+*/
+define(['Modernizr', 'prefixed'], function(Modernizr, prefixed) {
+  Modernizr.addTest('matchmedia', !!prefixed('matchMedia', window));
+});
diff --git a/feature-detects/window/pushmanager.js b/feature-detects/window/pushmanager.js
new file mode 100644
index 0000000..bbdb896
--- /dev/null
+++ b/feature-detects/window/pushmanager.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "PushManager",
+  "property": "pushmanager",
+  "caniuse": "mdn-api_pushmanager",
+  "authors": ["Dawid Kulpa (@dawidkulpa)"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/PushManager"
+  }]
+}
+!*/
+
+/* DOC
+Detects support for PushManager.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('pushmanager', 'PushManager' in window);
+});
diff --git a/feature-detects/window/resizeobserver.js b/feature-detects/window/resizeobserver.js
new file mode 100644
index 0000000..c95e2b6
--- /dev/null
+++ b/feature-detects/window/resizeobserver.js
@@ -0,0 +1,29 @@
+/*!
+{
+  "name": "ResizeObserver",
+  "property": "resizeobserver",
+  "caniuse": "resizeobserver",
+  "tags": ["ResizeObserver"],
+  "authors": ["Christian Andersson"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/resize-observer/"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver"
+  }, {
+    "name": "Web.dev Article",
+    "href": "https://web.dev/resize-observer/"
+  }, {
+    "name": "Digital Ocean tutorial",
+    "href": "https://www.digitalocean.com/community/tutorials/js-resize-observer"
+  }]
+}
+!*/
+
+/* DOC
+Detects support for ResizeObserver.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('resizeobserver', 'ResizeObserver' in window);
+});
diff --git a/feature-detects/workers-blobworkers.js b/feature-detects/workers-blobworkers.js
deleted file mode 100644
index 509127f..0000000
--- a/feature-detects/workers-blobworkers.js
+++ /dev/null
@@ -1,48 +0,0 @@
-// by jussi-kalliokoski
-
-
-// This test is asynchronous. Watch out.
-
-// The test will potentially add garbage to console.
-
-(function(){
-  try {
-
-    // we're avoiding using Modernizr._domPrefixes as the prefix capitalization on
-    // these guys are notoriously peculiar.
-    var BlobBuilder = window.MozBlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder || window.OBlobBuilder || window.BlobBuilder,
-        URL         = window.MozURL || window.webkitURL || window.MSURL || window.OURL || window.URL;
-
-    var data    = 'Modernizr',
-        bb      = new BlobBuilder();
-
-    bb.append('this.onmessage=function(e){postMessage(e.data)}');
-
-    var url     = URL.createObjectURL(bb.getBlob()),
-        worker  = new Worker(url);
-
-    bb = null;
-
-    worker.onmessage = function(e) {
-      worker.terminate();
-      URL.revokeObjectURL(url);
-      Modernizr.addTest('blobworkers', data === e.data);
-      worker = null;
-    };
-
-    // Just in case...
-    worker.onerror = function() {
-      Modernizr.addTest('blobworkers', false);
-      worker = null;
-    };
-
-    setTimeout(function() {
-        Modernizr.addTest('blobworkers', false);
-    }, 200);
-
-    worker.postMessage(data);
-
-  } catch (e) {
-    Modernizr.addTest('blobworkers', false);
-  }
-}());
diff --git a/feature-detects/workers-dataworkers.js b/feature-detects/workers-dataworkers.js
deleted file mode 100644
index efa95a5..0000000
--- a/feature-detects/workers-dataworkers.js
+++ /dev/null
@@ -1,34 +0,0 @@
-// by jussi-kalliokoski
-
-
-// This test is asynchronous. Watch out.
-
-// The test will potentially add garbage to console.
-
-(function(){
-  try {
-    var data    = 'Modernizr',
-        worker  = new Worker('data:text/javascript;base64,dGhpcy5vbm1lc3NhZ2U9ZnVuY3Rpb24oZSl7cG9zdE1lc3NhZ2UoZS5kYXRhKX0=');
-
-    worker.onmessage = function(e) {
-      worker.terminate();
-      Modernizr.addTest('dataworkers', data === e.data);
-      worker = null;
-    };
-
-    // Just in case...
-    worker.onerror = function() {
-      Modernizr.addTest('dataworkers', false);
-      worker = null;
-    };
-
-    setTimeout(function() {
-        Modernizr.addTest('dataworkers', false);
-    }, 200);
-
-    worker.postMessage(data);
-
-  } catch (e) {
-    Modernizr.addTest('dataworkers', false);
-  }
-}());
diff --git a/feature-detects/workers-sharedworkers.js b/feature-detects/workers-sharedworkers.js
deleted file mode 100644
index a9d78eb..0000000
--- a/feature-detects/workers-sharedworkers.js
+++ /dev/null
@@ -1,3 +0,0 @@
-Modernizr.addTest('sharedworkers', function(){
-  return !!window.SharedWorker;
-});
\ No newline at end of file
diff --git a/feature-detects/workers/blobworkers.js b/feature-detects/workers/blobworkers.js
new file mode 100644
index 0000000..560a8d6
--- /dev/null
+++ b/feature-detects/workers/blobworkers.js
@@ -0,0 +1,83 @@
+/*!
+{
+  "name": "Workers from Blob URIs",
+  "property": "blobworkers",
+  "tags": ["performance", "workers"],
+  "builderAliases": ["workers_blobworkers"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/workers/"
+  }],
+  "warnings": ["This test may output garbage to console."],
+  "authors": ["Jussi Kalliokoski"],
+  "async": true
+}
+!*/
+/* DOC
+Detects support for creating Web Workers from Blob URIs.
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+  Modernizr.addAsyncTest(function() {
+    try {
+      // we're avoiding using Modernizr._domPrefixes as the prefix capitalization on
+      // these guys are notoriously peculiar.
+      var BlobBuilder = window.BlobBuilder;
+      var URL = window.URL;
+      if (Modernizr._config.usePrefix) {
+        BlobBuilder = BlobBuilder || window.MozBlobBuilder || window.WebKitBlobBuilder || window.MSBlobBuilder || window.OBlobBuilder;
+        URL = URL || window.MozURL || window.webkitURL || window.MSURL || window.OURL;
+      }
+      var data = 'Modernizr',
+        blob,
+        bb,
+        worker,
+        url,
+        timeout,
+        scriptText = 'this.onmessage=function(e){postMessage(e.data)}';
+
+      try {
+        blob = new Blob([scriptText], {type: 'text/javascript'});
+      } catch (e) {
+        // we'll fall back to the deprecated BlobBuilder
+      }
+      if (!blob) {
+        bb = new BlobBuilder();
+        bb.append(scriptText);
+        blob = bb.getBlob();
+      }
+
+      url = URL.createObjectURL(blob);
+      worker = new Worker(url);
+
+      worker.onmessage = function(e) {
+        addTest('blobworkers', data === e.data);
+        cleanup();
+      };
+
+      // Just in case...
+      worker.onerror = fail;
+      timeout = setTimeout(fail, 200);
+
+      worker.postMessage(data);
+    } catch (e) {
+      fail();
+    }
+
+    function fail() {
+      addTest('blobworkers', false);
+      cleanup();
+    }
+
+    function cleanup() {
+      if (url) {
+        URL.revokeObjectURL(url);
+      }
+      if (worker) {
+        worker.terminate();
+      }
+      if (timeout) {
+        clearTimeout(timeout);
+      }
+    }
+  });
+});
diff --git a/feature-detects/workers/dataworkers.js b/feature-detects/workers/dataworkers.js
new file mode 100644
index 0000000..c4fe7c3
--- /dev/null
+++ b/feature-detects/workers/dataworkers.js
@@ -0,0 +1,48 @@
+/*!
+{
+  "name": "Workers from Data URIs",
+  "property": "dataworkers",
+  "tags": ["performance", "workers"],
+  "builderAliases": ["workers_dataworkers"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/workers/"
+  }],
+  "warnings": ["This test may output garbage to console."],
+  "authors": ["Jussi Kalliokoski"],
+  "async": true
+}
+!*/
+/* DOC
+Detects support for creating Web Workers from Data URIs.
+*/
+define(['Modernizr', 'addTest'], function(Modernizr, addTest) {
+  Modernizr.addAsyncTest(function() {
+    try {
+      var data = 'Modernizr',
+        worker = new Worker('data:text/javascript;base64,dGhpcy5vbm1lc3NhZ2U9ZnVuY3Rpb24oZSl7cG9zdE1lc3NhZ2UoZS5kYXRhKX0=');
+
+      worker.onmessage = function(e) {
+        worker.terminate();
+        addTest('dataworkers', data === e.data);
+        worker = null;
+      };
+
+      // Just in case...
+      worker.onerror = function() {
+        addTest('dataworkers', false);
+        worker = null;
+      };
+
+      setTimeout(function() {
+        addTest('dataworkers', false);
+      }, 200);
+
+      worker.postMessage(data);
+    } catch (e) {
+      setTimeout(function() {
+        addTest('dataworkers', false);
+      }, 0);
+    }
+  });
+});
diff --git a/feature-detects/workers/sharedworkers.js b/feature-detects/workers/sharedworkers.js
new file mode 100644
index 0000000..3f0d697
--- /dev/null
+++ b/feature-detects/workers/sharedworkers.js
@@ -0,0 +1,19 @@
+/*!
+{
+  "name": "Shared Workers",
+  "property": "sharedworkers",
+  "caniuse": "sharedworkers",
+  "tags": ["performance", "workers"],
+  "builderAliases": ["workers_sharedworkers"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/workers/"
+  }]
+}
+!*/
+/* DOC
+Detects support for the `SharedWorker` API from the Web Workers spec.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('sharedworkers', 'SharedWorker' in window);
+});
diff --git a/feature-detects/workers/transferables.js b/feature-detects/workers/transferables.js
new file mode 100644
index 0000000..74ac5fa
--- /dev/null
+++ b/feature-detects/workers/transferables.js
@@ -0,0 +1,72 @@
+/*!
+{
+  "name": "Transferables Objects",
+  "property": "transferables",
+  "tags": ["performance", "workers"],
+  "builderAliases": ["transferables"],
+  "notes": [{
+    "name": "Transferable Objects: Lightning Fast!",
+    "href": "https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast"
+  }],
+  "async": true
+}
+!*/
+/* DOC
+Detects whether web workers can use `transferables` objects.
+*/
+define(['Modernizr', 'addTest', 'test/blob', 'test/url/bloburls', 'test/workers/webworkers', 'test/typed-arrays'], function(Modernizr, addTest) {
+  Modernizr.addAsyncTest(function() {
+    var prerequisites = !!(Modernizr.blobconstructor &&
+                           Modernizr.bloburls &&
+                           Modernizr.webworkers &&
+                           Modernizr.typedarrays);
+
+    // Early exit
+    if (!prerequisites) {
+      return addTest('transferables', false);
+    }
+
+    // Proper test if prerequisites are met
+    try {
+      var buffer,
+        scriptText = 'var hello = "world"',
+        blob = new Blob([scriptText], {type: 'text/javascript'}),
+        url = URL.createObjectURL(blob),
+        worker = new Worker(url),
+        timeout;
+
+      // Just in case...
+      worker.onerror = fail;
+      timeout = setTimeout(fail, 200);
+
+      // Building an minimal array buffer to send to the worker
+      buffer = new ArrayBuffer(1);
+
+      // Sending the buffer to the worker
+      worker.postMessage(buffer, [buffer]);
+
+      // If length of buffer is now 0, transferables are working
+      addTest('transferables', buffer.byteLength === 0);
+      cleanup();
+    } catch (e) {
+      fail();
+    }
+
+    function fail() {
+      addTest('transferables', false);
+      cleanup();
+    }
+
+    function cleanup() {
+      if (url) {
+        URL.revokeObjectURL(url);
+      }
+      if (worker) {
+        worker.terminate();
+      }
+      if (timeout) {
+        clearTimeout(timeout);
+      }
+    }
+  });
+});
diff --git a/feature-detects/workers/webworkers.js b/feature-detects/workers/webworkers.js
new file mode 100644
index 0000000..768a8ee
--- /dev/null
+++ b/feature-detects/workers/webworkers.js
@@ -0,0 +1,25 @@
+/*!
+{
+  "name": "Web Workers",
+  "property": "webworkers",
+  "caniuse": "webworkers",
+  "tags": ["performance", "workers"],
+  "notes": [{
+    "name": "W3C Spec",
+    "href": "https://www.w3.org/TR/workers/"
+  }, {
+    "name": "HTML5 Rocks Tutorial",
+    "href": "https://www.html5rocks.com/en/tutorials/workers/basics/"
+  }, {
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers"
+  }],
+  "polyfills": ["fakeworker", "html5shims"]
+}
+!*/
+/* DOC
+Detects support for the basic `Worker` API from the Web Workers spec. Web Workers provide a simple means for web content to run scripts in background threads.
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('webworkers', 'Worker' in window);
+});
diff --git a/feature-detects/workers/workertypeoption.js b/feature-detects/workers/workertypeoption.js
new file mode 100644
index 0000000..0f61c75
--- /dev/null
+++ b/feature-detects/workers/workertypeoption.js
@@ -0,0 +1,42 @@
+/*!
+{
+  "name": "worker type option test",
+  "property": "workertypeoption",
+  "caniuse":"mdn-api_worker_worker_ecmascript_modules",
+  "tags": ["web worker type options", "web worker"],
+  "builderAliases": ["worker_type_options"],
+  "authors": ["Debadutta Panda"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker"
+  }]
+}
+!*/
+/* DOC
+Detect working status of all Workeroptions
+https://developer.mozilla.org/en-US/docs/Web/API/Worker/Worker
+*/
+define(['Modernizr'], function (Modernizr) {
+    Modernizr.addTest("workertypeoption", function () {
+        if ('Worker' in window) {
+            var isTypeOptionSupported = false,
+                textTypeOption = {
+                    get type() {
+                        isTypeOptionSupported = true;
+                        return "module"
+                    }
+                },
+                scriptText = `var message='hello'`,
+                blob = new Blob([scriptText], { type: 'text/javascript' }),
+                url = URL.createObjectURL(blob)
+            try {
+                new Worker(url, textTypeOption).terminate();
+                return isTypeOptionSupported;
+            } catch (err) {
+                return false;
+            }
+        } else {
+            return false;
+        }
+    });
+});
\ No newline at end of file
diff --git a/feature-detects/xdomainrequest.js b/feature-detects/xdomainrequest.js
new file mode 100644
index 0000000..d38673e
--- /dev/null
+++ b/feature-detects/xdomainrequest.js
@@ -0,0 +1,18 @@
+/*!
+{
+  "name": "XDomainRequest",
+  "property": "xdomainrequest",
+  "tags": ["cors", "xdomainrequest", "ie9", "ie8"],
+  "authors": ["Ivan Pan (@hypotenuse)"],
+  "notes": [{
+    "name": "MDN Docs",
+    "href": "https://developer.mozilla.org/en-US/docs/Web/API/XDomainRequest"
+  }]
+}
+!*/
+/* DOC
+Detects support for XDomainRequest in IE9 & IE8
+*/
+define(['Modernizr'], function(Modernizr) {
+  Modernizr.addTest('xdomainrequest', 'XDomainRequest' in window);
+});
diff --git a/grunt.js b/grunt.js
deleted file mode 100644
index 7368365..0000000
--- a/grunt.js
+++ /dev/null
@@ -1,69 +0,0 @@
-/*global module */
-module.exports = function( grunt ) {
-    'use strict';
-
-    grunt.initConfig({
-        meta: {
-          version: '2.5.3',
-          banner: '/*!\n' +
-            ' * Modernizr v<%= meta.version %>\n' +
-            ' * www.modernizr.com\n *\n' +
-            ' * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton\n' +
-            ' * Available under the BSD and MIT licenses: www.modernizr.com/license/\n */'
-        },
-        qunit: {
-            files: ['test/index.html']
-        },
-        lint: {
-            files: [
-                'grunt.js',
-                'modernizr.js',
-                'feature-detects/*.js'
-            ]
-        },
-        min: {
-            dist: {
-                src: [
-                    '<banner:meta.banner>',
-                    'modernizr.js'
-                ],
-                dest: 'modernizr.min.js'
-            }
-        },
-        watch: {
-            files: '<config:lint.files>',
-            tasks: 'lint'
-        },
-        jshint: {
-            options: {
-                boss: true,
-                browser: true,
-                curly: false,
-                devel: true,
-                eqeqeq: false,
-                eqnull: true,
-                expr: true,
-                evil: true,
-                immed: false,
-                laxcomma: true,
-                newcap: false,
-                noarg: true,
-                smarttabs: true,
-                sub: true,
-                undef: true
-            },
-            globals: {
-                Modernizr: true,
-                DocumentTouch: true,
-                TEST: true,
-                SVGFEColorMatrixElement : true,
-                Blob: true
-            }
-        }
-    });
-
-    grunt.registerTask('default', 'min');
-
-    // Travis CI task.
-    grunt.registerTask('travis', 'qunit');
-};
diff --git a/lib/build-query.js b/lib/build-query.js
new file mode 100644
index 0000000..5b5d4dd
--- /dev/null
+++ b/lib/build-query.js
@@ -0,0 +1,51 @@
+define(['lodash', 'metadata'], function(_, metadata) {
+
+  function getDetectObjByAmdPath(amdPath) {
+    return _.find(metadata, function(detect) {
+      return detect.amdPath === amdPath || detect.amdPath === 'test/' + amdPath;
+    });
+  }
+
+  return function generateBuildQuery(config) {
+    // Format:
+    // ?-<prop1>-<prop2>-…-<propN>-<option1>-<option2>-…<optionN>[-dontmin][-cssclassprefix:<prefix>]
+    // where prop1…N and option1…N are sorted alphabetically (for consistency)
+    var dontmin = !config.minify;
+
+    // Config uses amdPaths, but build query uses property names
+    var props = _.chain(config['feature-detects'])
+      .map(function(amdPath) {
+        var detect = getDetectObjByAmdPath(amdPath);
+        var property = detect && detect.property;
+        if (property) {
+          property = _.isArray(property) ?
+            property.join('_').replace('-', '_') :
+            property.replace('-', '_');
+          return property;
+        }
+      })
+      .filter()
+      .value();
+
+    // Config uses amdPaths, but the option's just use their names.
+    // A few of the values have to be massaged in order to match
+    // the `value`
+    var opts = _.map(config.options, function(opt) {
+      if (opt.indexOf('html5') === 0) {
+        opt = opt.replace('html5', '');
+      }
+      return opt.toLowerCase();
+    });
+
+    var sortedProps = props.sort();
+    var sortedOpts = opts.sort();
+
+    // Options are AMD paths in the config, but need to be converted to
+    var buildQuery = '?-' + sortedProps.concat(sortedOpts).join('-') +
+        (dontmin ? '-dontmin' : '') +
+        ((config.classPrefix) ?
+          '-cssclassprefix:' + config.classPrefix : '');
+
+    return buildQuery;
+  };
+});
diff --git a/lib/build.js b/lib/build.js
new file mode 100644
index 0000000..ffa47fd
--- /dev/null
+++ b/lib/build.js
@@ -0,0 +1,170 @@
+// this file configures require.js based on environment
+'use strict';
+
+var inBrowser = typeof define === 'function' && typeof define.amd === 'object';
+
+var _extend = function(a, b) {
+  for (var prop in b) {
+    var supplied = b[prop];
+    if (Object.prototype.toString.call(supplied) === '[object Object]') {
+      a[prop] = a[prop] || {};
+      _extend(a[prop], supplied);
+    } else {
+      a[prop] = b[prop];
+    }
+  }
+};
+
+var baseRequireConfig = {
+  optimize: 'none',
+  generateSourceMaps: false,
+  optimizeCss: 'none',
+  useStrict: true,
+  include: ['modernizr-init'],
+  fileExclusionRegExp: /^(.git|node_modules|modulizr|media|test)$/,
+  wrap: {
+    start: '\n;(function(scriptGlobalObject, window, document, undefined){',
+    end: '})(window, window, document);'
+  },
+  onBuildWrite: function(id, path, contents) {
+    if (this.optimize === 'uglify') {
+      // strip out documentation comments
+      contents = contents.replace(/\/\*\![\s\S]*\!\*\//m, '');
+    }
+
+    if ((/define\(.*?\{/).test(contents)) {
+      // remove AMD ceremony for use without require.js or almond.js
+      contents = contents.replace(/define\(.*?\{/, '');
+
+      contents = contents.replace(/\}\);\s*?$/, '');
+
+      if (!contents.match(/Modernizr\.add(Async)?Test\(/)) {
+      // remove last return statement and trailing })
+        contents = contents.replace(/return.*[^return]*$/, '');
+      }
+    } else if ((/require\([^\{]*?\{/).test(contents)) {
+      contents = contents.replace(/require[^\{]+\{/, '');
+      contents = contents.replace(/\}\);\s*$/, '');
+    }
+
+    contents = contents.replace(/return addTest;/, '');
+
+    return contents;
+  }
+};
+
+function build(generate, generateBanner, pkg) {
+  return function build(config, cb) {
+    var requireConfig = {};
+    var banner;
+    config = config || {};
+    cb = cb || function noop() {};
+
+    _extend(requireConfig, baseRequireConfig);
+
+    requireConfig.rawText = {
+      'modernizr-init': generate(config)
+    };
+
+    if (config.minify) {
+      banner = generateBanner('compact', config);
+      requireConfig.optimize = 'uglify';
+      requireConfig.uglify = {
+        mangle: {
+          except: ['Modernizr']
+        },
+        beautify: {
+          ascii_only: true
+        }
+      };
+    } else {
+      banner = generateBanner('full', config);
+      requireConfig.optimize = 'none';
+    }
+
+    if(config.scriptGlobalName) {
+      requireConfig.wrap.end = '})(' + config.scriptGlobalName + ', window, document);';
+    }
+
+    requireConfig.out = function(output) {
+      output = banner + output;
+
+      // Remove `define('modernizr-init' ...)` and `define('modernizr-build' ...)`
+      output = output.replace(/(,\s*)?define\("modernizr-(init|build)",\s*function\(\)\{\};?\)/g, '');
+      output = output.replace(/__VERSION__/g, pkg.version);
+
+      // Hack the prefix into place. Anything is way too big for something so small.
+      if (config && config.classPrefix) {
+        output = output.replace(/(classPrefix'?:\s?)['"]{2}(,)/, '$1\'' + config.classPrefix.replace(/'/g, '\\\'') + '\'$2');
+      }
+      ['enableClasses', 'enableJSClass', 'usePrefixes'].forEach(function(configName) {
+        if (config && typeof config[configName] === 'boolean') {
+          if (config.minify) {
+            output = output.replace(new RegExp('(' + configName + '\\\'?\\s?:\\s?)(!?0)([,\\n])'), '$1' + (config[configName] ? "!0" : "!1") + '$3');
+          } else {
+            output = output.replace(new RegExp('(' + configName + '\\\'?\\s?:\\s?)(true|false)([,\\n])'), '$1' + Boolean(config[configName]) + '$3');
+          }
+        }
+      });
+
+      cb(output);
+    };
+
+    requirejs.optimize(requireConfig);
+  };
+}
+
+if (inBrowser) {
+  var suppliedConfig = self._modernizrConfig;
+  var metadataUrl = 'i/js/metadata.json';
+  var packageUrl = 'i/js/modernizr-git/package.json';
+  baseRequireConfig.baseUrl = '/i/js/modernizr-git/src';
+  baseRequireConfig.paths = {
+    text: '/i/js/requirejs-plugins/lib/text',
+    lib: '/i/js/modernizr-git/lib',
+    json: '/i/js/requirejs-plugins/src/json',
+    lodash: '/i/js/lodash',
+    test: '/i/js/modernizr-git/feature-detects'
+  };
+
+  if (suppliedConfig) {
+    metadataUrl = suppliedConfig.metadataUrl || metadataUrl;
+    packageUrl = suppliedConfig.packageUrl || packageUrl;
+    _extend(baseRequireConfig, suppliedConfig);
+  }
+
+  if (self._modernizrMetadata) {
+    requirejs.define('metadata', [], function() {return self._modernizrMetadata;});
+  } else {
+    requirejs.define('metadata', ['json!' + metadataUrl], function(pkg) {return pkg;});
+  }
+  requirejs.define('package', ['json!' + packageUrl], function(pkg) {return pkg;});
+} else {
+  var requirejs = require('requirejs');
+  var metadata = require('./metadata')();
+  var pkgj = require('../package.json');
+
+  requirejs.define('metadata', [], function() {return metadata;});
+  requirejs.define('package', function() {return pkgj;});
+
+  baseRequireConfig.baseUrl = __dirname + '/../src';
+  baseRequireConfig.paths = {
+    lodash: __dirname + '/../node_modules/lodash/lodash',
+    test: __dirname + '/../feature-detects',
+    lib: __dirname
+  };
+}
+
+requirejs.config(baseRequireConfig);
+
+if (inBrowser) {
+  define('build', ['generate', 'lib/generate-banner', 'package'], build);
+} else {
+  var generateBanner = requirejs(__dirname + '/generate-banner.js');
+  var generate = requirejs('generate');
+  var pakg = requirejs('package');
+  var _build = build;
+  module.exports = function build() {
+    return _build(generate, generateBanner, pakg).apply(undefined, arguments);
+  };
+}
diff --git a/lib/cli.js b/lib/cli.js
new file mode 100644
index 0000000..886add9
--- /dev/null
+++ b/lib/cli.js
@@ -0,0 +1,7 @@
+'use strict';
+
+module.exports = {
+  build: require('./build'),
+  metadata: require('./metadata'),
+  options: require('./options')
+};
diff --git a/lib/config-all.json b/lib/config-all.json
new file mode 100644
index 0000000..3e8eb70
--- /dev/null
+++ b/lib/config-all.json
@@ -0,0 +1,331 @@
+{
+  "classPrefix": "",
+  "enableClasses": true,
+  "enableJSClass": true,
+  "scriptGlobalName": "window",
+  "usePrefixes": true,
+  "minify": false,
+  "options": [
+    "addTest",
+    "atRule",
+    "domPrefixes",
+    "hasEvent",
+    "html5shiv",
+    "html5printshiv",
+    "load",
+    "mq",
+    "prefixed",
+    "prefixes",
+    "prefixedCSS",
+    "setClasses",
+    "testAllProps",
+    "testProp",
+    "testStyles"
+  ],
+  "feature-detects": [
+    "a/download",
+    "a/aping",
+    "a/areaping",
+    "ambientlight",
+    "applicationcache",
+    "audio/audio",
+    "audio/autoplay",
+    "audio/loop",
+    "audio/preload",
+    "audio/webaudio",
+    "battery/battery",
+    "battery/lowbattery",
+    "blob",
+    "canvas/canvas",
+    "canvas/blending",
+    "canvas/todataurl",
+    "canvas/winding",
+    "canvas/text",
+    "clipboard",
+    "contenteditable",
+    "contextmenu",
+    "cors",
+    "crypto",
+    "crypto/getrandomvalues",
+    "css/all",
+    "css/animations",
+    "css/appearance",
+    "css/aspectratio",
+    "css/backdropfilter",
+    "css/backgroundblendmode",
+    "css/backgroundcliptext",
+    "css/backgroundposition-shorthand",
+    "css/backgroundposition-xy",
+    "css/backgroundrepeat",
+    "css/backgroundsize",
+    "css/backgroundsizecover",
+    "css/borderimage",
+    "css/borderradius",
+    "css/boxdecorationbreak",
+    "css/boxshadow",
+    "css/boxsizing",
+    "css/calc",
+    "css/checked",
+    "css/chunit",
+    "css/columns",
+    "css/cssgrid",
+    "css/cubicbezierrange",
+    "css/customproperties",
+    "css/displayrunin",
+    "css/displaytable",
+    "css/ellipsis",
+    "css/escape",
+    "css/exunit",
+    "css/filters",
+    "css/flexbox",
+    "css/flexboxlegacy",
+    "css/flexboxtweener",
+    "css/flexgap",
+    "css/flexwrap",
+    "css/focusvisible",
+    "css/focuswithin",
+    "css/fontdisplay",
+    "css/fontface",
+    "css/generatedcontent",
+    "css/gradients",
+    "css/hairline",
+    "css/hsla",
+    "css/hyphens",
+    "css/invalid",
+    "css/lastchild",
+    "css/mask",
+    "css/mediaqueries",
+    "css/multiplebgs",
+    "css/nthchild",
+    "css/objectfit",
+    "css/opacity",
+    "css/overflow-scrolling",
+    "css/pointerevents",
+    "css/positionsticky",
+    "css/pseudoanimations",
+    "css/pseudotransitions",
+    "css/reflections",
+    "css/regions",
+    "css/remunit",
+    "css/resize",
+    "css/rgba",
+    "css/scrollbars",
+    "css/scrollsnappoints",
+    "css/shapes",
+    "css/siblinggeneral",
+    "css/subpixelfont",
+    "css/supports",
+    "css/target",
+    "css/textalignlast",
+    "css/textdecoration",
+    "css/textshadow",
+    "css/transforms",
+    "css/transforms3d",
+    "css/transformslevel2",
+    "css/transformstylepreserve3d",
+    "css/transitions",
+    "css/userselect",
+    "css/valid",
+    "css/variablefonts",
+    "css/vhunit",
+    "css/vmaxunit",
+    "css/vminunit",
+    "css/vwunit",
+    "css/will-change",
+    "css/wrapflow",
+    "custom-elements",
+    "custom-protocol-handler",
+    "dart",
+    "dataview-api",
+    "dom/classlist",
+    "dom/createElement-attrs",
+    "dom/dataset",
+    "dom/documentfragment",
+    "dom/hidden",
+    "dom/intersection-observer",
+    "dom/microdata",
+    "dom/mutationObserver",
+    "dom/passiveeventlisteners",
+    "dom/shadowroot",
+    "dom/shadowrootlegacy",
+    "elem/bdi",
+    "elem/details",
+    "elem/output",
+    "elem/picture",
+    "elem/progress-meter",
+    "elem/ruby",
+    "elem/template",
+    "elem/time",
+    "elem/track",
+    "elem/unknown",
+    "emoji",
+    "es5/array",
+    "es5/date",
+    "es5/function",
+    "es5/object",
+    "es5/specification",
+    "es5/strictmode",
+    "es5/string",
+    "es5/syntax",
+    "es5/undefined",
+    "es6/array",
+    "es6/arrow",
+    "es6/class",
+    "es6/collections",
+    "es6/generators",
+    "es6/math",
+    "es6/number",
+    "es6/object",
+    "es6/promises",
+    "es6/rest-parameters",
+    "es6/spread-array",
+    "es6/string-template",
+    "es6/string",
+    "es6/symbol",
+    "es7/array",
+    "es7/rest-destructuring",
+    "es7/spread-object",
+    "es8/object",
+    "event/customevent",
+    "event/deviceorientation-motion",
+    "event/eventlistener",
+    "event/forcetouch",
+    "event/hashchange",
+    "event/oninput",
+    "event/pointerevents",
+    "event/proximity",
+    "file/api",
+    "file/filesystem",
+    "flash",
+    "fullscreen-api",
+    "gamepad",
+    "geolocation",
+    "hiddenscroll",
+    "history",
+    "htmlimports",
+    "ie8compat",
+    "iframe/sandbox",
+    "iframe/seamless",
+    "iframe/srcdoc",
+    "img/apng",
+    "img/avif",
+    "img/crossorigin",
+    "img/exif-orientation",
+    "img/jpeg2000",
+    "img/jpegxr",
+    "img/lazyloading",
+    "img/sizes",
+    "img/srcset",
+    "img/webp-alpha",
+    "img/webp-animation",
+    "img/webp-lossless",
+    "img/webp",
+    "input/capture",
+    "input/fileinput",
+    "input/fileinputdirectory",
+    "input/formaction",
+    "input/formattribute",
+    "input/formenctype",
+    "input/formmethod",
+    "input/formnovalidate",
+    "input/formtarget",
+    "input/input",
+    "input/inputnumber-l10n",
+    "input/inputsearchevent",
+    "input/inputtypes",
+    "input/placeholder",
+    "input/requestautocomplete",
+    "input/validation",
+    "intl",
+    "json",
+    "ligatures",
+    "lists-reversed",
+    "mathml",
+    "media-source-extension-api",
+    "mediaquery/hovermq",
+    "mediaquery/pointermq",
+    "messagechannel",
+    "network/beacon",
+    "network/connection-effectivetype",
+    "network/connection",
+    "network/eventsource",
+    "network/fetch",
+    "network/xhr-responsetype-arraybuffer",
+    "network/xhr-responsetype-blob",
+    "network/xhr-responsetype-document",
+    "network/xhr-responsetype-json",
+    "network/xhr-responsetype-text",
+    "network/xhr-responsetype",
+    "network/xhr2",
+    "notification",
+    "pagevisibility-api",
+    "performance",
+    "pointerlock-api",
+    "postmessage",
+    "proxy",
+    "queryselector",
+    "link/prefetch",
+    "requestanimationframe",
+    "script/async",
+    "script/defer",
+    "scrolltooptions",
+    "serviceworker",
+    "speech/speech-recognition",
+    "speech/speech-synthesis",
+    "storage/cookies",
+    "storage/indexeddb",
+    "storage/indexeddbblob",
+    "storage/indexeddb2",
+    "storage/localstorage",
+    "storage/quota-management-api",
+    "storage/sessionstorage",
+    "storage/userdata",
+    "storage/websqldatabase",
+    "style/scoped",
+    "svg/svg",
+    "svg/asimg",
+    "svg/clippaths",
+    "svg/filters",
+    "svg/foreignobject",
+    "svg/inline",
+    "svg/smil",
+    "textarea/maxlength",
+    "textencoding",
+    "typed-arrays",
+    "unicode-range",
+    "url/bloburls",
+    "url/data-uri",
+    "url/parser",
+    "url/urlsearchparams",
+    "vibration",
+    "video/video",
+    "video/autoplay",
+    "video/crossorigin",
+    "video/loop",
+    "video/preload",
+    "vml",
+    "web-intents",
+    "webanimations",
+    "webauthn/publickeycredential",
+    "webgl/webgl",
+    "webgl/extensions",
+    "webrtc/datachannel",
+    "webrtc/getusermedia",
+    "webrtc/mediastream",
+    "webrtc/peerconnection",
+    "websockets",
+    "websockets/binary",
+    "window/atob-btoa",
+    "window/framed",
+    "window/matchmedia",
+    "window/pushmanager",
+    "window/resizeobserver",
+    "workers/workertypeoption",
+    "workers/blobworkers",
+    "workers/dataworkers",
+    "workers/sharedworkers",
+    "workers/transferables",
+    "workers/webworkers",
+    "xdomainrequest"
+  ]
+}
diff --git a/lib/generate-banner.js b/lib/generate-banner.js
new file mode 100644
index 0000000..28563d7
--- /dev/null
+++ b/lib/generate-banner.js
@@ -0,0 +1,39 @@
+define(['lodash', 'package', 'lib/build-query'], function(_, pkg, buildQuery) {
+  var domain = 'modernizr.com';
+  if (typeof location !== 'undefined' && 'host' in location) {
+    domain = location.host;
+  }
+
+  // Return a Modernizr file banner.
+  // Usage:
+  //   require('banners')(type);
+  // Arguments:
+  //   type (String, required): either 'compact' or 'full'.
+
+  return function banners(type, config) {
+    config = config || {};
+    var query = buildQuery(config);
+    if (!type || type === 'compact') {
+      return '/*! ' + pkg.name + ' ' + pkg.version + ' (Custom Build) | ' + pkg.license + ' *\n' +
+        ' * https://' + domain + '/download/' + query +
+        ' !*/\n';
+    }
+    else if (type === 'full') {
+      return '/*!\n' +
+        ' * ' + pkg.name + ' v' + pkg.version + '\n' +
+        ' * Build https://' + domain + '/download' + query + '\n' +
+        ' *\n' +
+        ' * Copyright (c)\n *  ' + _.map(pkg.contributors, 'name').join('\n *  ') + '\n\n' +
+        ' * ' + pkg.license + ' License\n */\n' +
+      '\n' +
+        '/*\n' +
+        ' * Modernizr tests which native CSS3 and HTML5 features are available in the\n' +
+        ' * current UA and makes the results available to you in two ways: as properties on\n' +
+        ' * a global `Modernizr` object, and as classes on the `<html>` element. This\n' +
+        ' * information allows you to progressively enhance your pages with a granular level\n' +
+        ' * of control over the experience.\n*/\n';
+    } else {
+      throw 'banners() must be passed "compact" or "full" as an argument.';
+    }
+  };
+});
diff --git a/lib/metadata.js b/lib/metadata.js
new file mode 100644
index 0000000..1eea86f
--- /dev/null
+++ b/lib/metadata.js
@@ -0,0 +1,150 @@
+var fs = require('fs');
+var file = require('file');
+var MarkdownIt = require('markdown-it');
+var polyfills = require('./polyfills.json');
+var viewRoot = fs.realpathSync(__dirname + '/../feature-detects');
+
+function metadata(cb) {
+  var tests = [];
+  var md = new MarkdownIt();
+  file.walkSync(viewRoot, function(start, dirs, files) {
+    files.forEach(function(file) {
+      if (file === '.DS_Store') {
+        return;
+      }
+      var test = fs.readFileSync(start + '/' + file, 'utf8');
+      // TODO:: make this regex not suck
+      var metaRE = /\/\*\!([\s\S]*)\!\*\//m;
+      var matches = test.match(metaRE);
+      var docRE = /\/\*\sDOC([\s\S]*?)\*\//m;
+      var docmatches = test.match(docRE);
+      var depRE = /define\((\[[^\]]*\]),/;
+      var depMatches = test.match(depRE);
+
+      var metadata;
+
+      if (matches && matches[1]) {
+        try {
+          metadata = JSON.parse(matches[1]);
+        } catch (e) {
+          throw new Error('Error Parsing Metadata: ' + file + '\nInput: `' + matches[1] + '`');
+        }
+      }
+      else {
+        metadata = {};
+      }
+
+      var docs = null;
+
+      if (docmatches && docmatches[1]) {
+        docs = md.render(docmatches[1].trim());
+      }
+
+      metadata.doc = docs;
+
+      var deps = [];
+      var matchedDeps;
+
+      if (depMatches && depMatches[1]) {
+        try {
+          matchedDeps = JSON.parse(depMatches[1].replace(/'/g, '"'));
+        } catch (e) {
+          throw new Error('Couldn\'t parse dependencies for `' + file + '`:\n`' + depMatches[1] + '\n`');
+        }
+        matchedDeps.forEach(function(dep) {
+          if (dep === 'Modernizr') {
+            return;
+          }
+          deps.push(dep);
+        });
+      } else {
+        throw new Error('Couldn\'t find the define for `' + file + '`');
+      }
+      metadata.deps = deps;
+
+      var baseDir = __dirname.replace(/lib$/, '');
+      metadata.path = './' + (start + '/' + file).replace(baseDir, '').replace(/\\/g, '/');
+      metadata.amdPath = metadata.path.replace(/^\.\/feature\-detects/, 'test').replace(/\.js$/i, '');
+
+      // Force minimal metadata #2551
+      // Consider adding new tests in test/node/lib/metadata.js if you add new minimal requirements
+      if (!metadata.name || !metadata.property) {
+        throw new Error('Minimal metadata not found in `' + file + '`');
+      }
+
+      var pfs = [];
+      if (metadata.polyfills && metadata.polyfills.length) {
+        metadata.polyfills.forEach(function(polyname) {
+          if (polyfills[polyname]) {
+            pfs.push(polyfills[polyname]);
+          }
+          else {
+            throw new Error(metadata.name + ': Polyfill not found in `' + file + '`: ' + polyname);
+          }
+        });
+      }
+      metadata.polyfills = pfs;
+
+      //metadata.property can only have lowercase alphanumeric and dashes
+      const properties = Array.isArray(metadata.property) ? metadata.property : [metadata.property];
+      properties.forEach(function (property) {
+        if (!property.match(/^[a-z0-9-]+$/)) {
+          throw new Error(metadata.name + ' : ' + property + ': Property can only have lowercase alphanumeric characters and dashes');
+        }
+      });
+
+      if (!metadata.async) {
+        metadata.async = false;
+      }
+
+      if (!metadata.notes) {
+        metadata.notes = [];
+      }
+
+      if (!metadata.warnings) {
+        metadata.warnings = [];
+      }
+
+      if (!metadata.caniuse) {
+        metadata.caniuse = null;
+      }
+
+      if (!metadata.cssclass && metadata.property) {
+        metadata.cssclass = metadata.property;
+      } else {
+        metadata.cssclass = null;
+      }
+
+      // Maybe catch a bug
+      if (!metadata.doc && metadata.docs) {
+        metadata.doc = metadata.docs;
+        delete metadata.docs;
+      }
+
+      // If you want markdown parsed code minus the docs and metadata, this'll do it.
+      // Off by default for now.
+      // metadata.code =  md.render('```javascript\n' + test.replace(metaRE, '').replace(docRE, '') + '\n```');
+
+      if (!metadata.tags) {
+        metadata.tags = [];
+      }
+
+      if (!metadata.authors) {
+        metadata.authors = [];
+      }
+
+      if (!metadata.knownBugs) {
+        metadata.knownBugs = [];
+      }
+
+      tests.push(metadata);
+    });
+  });
+
+  if (cb && typeof cb === 'function') {
+    return cb(tests);
+  }
+  return tests;
+}
+
+module.exports = metadata;
diff --git a/lib/options.js b/lib/options.js
new file mode 100644
index 0000000..0892c28
--- /dev/null
+++ b/lib/options.js
@@ -0,0 +1,90 @@
+var fs = require('fs');
+var _ = require('lodash');
+var file = require('file');
+var jsdoc = require('doctrine');
+var srcRoot = fs.realpathSync(__dirname + '/../src');
+var commentRE = /^(\s+)?(\/\*)?\*(\/)?\s?/mg;
+var jsdocRE = /[^\S\r\n]*\/(?:\*{2})([\W\w]+?)\*\//mg;
+
+var stripComments = function(str) {
+  return str.replace(commentRE, '');
+};
+
+function options(cb, allMetadata) {
+  var opts;
+
+  file.walkSync(srcRoot, function(start, dirs, files) {
+    opts = _.chain(files)
+      .map(function(file) {
+        var srcFile = fs.readFileSync(start + '/' + file, 'utf8');
+        var docs = srcFile.match(jsdocRE);
+
+        if (docs) {
+          docs = docs
+            .map(stripComments)
+            .map(function(str) {
+              return jsdoc.parse(str, {
+                sloppy: true,
+                tags: [
+                  'access',
+                  'author',
+                  'class',
+                  'example',
+                  'function',
+                  'memberOf',
+                  'name',
+                  'optionName',
+                  'optionProp',
+                  'param',
+                  'params',
+                  'preserve',
+                  'private',
+                  'returns',
+                  'type'
+                ]
+              });
+            });
+
+          var option = _.chain(docs)
+            .flatten()
+            .filter(function(doc) {
+              if (allMetadata) {
+                return true;
+              } else {
+                return doc && _.some(doc.tags, {title: 'optionName'});
+              }
+            })
+            .map(function(opt) {
+              if (allMetadata) {
+                return opt;
+              } else {
+                var tags = opt.tags.filter(function(tag) {
+                  return tag.title.indexOf('option') === 0;
+                });
+
+                return {
+                  name: _.filter(tags, {title: 'optionName'})[0].description,
+                  property: _.filter(tags, {title: 'optionProp'})[0].description
+                };
+              }
+            })
+            .value();
+
+          return option;
+        }
+      })
+      .filter(function(doc) {
+        return doc && doc.length;
+      })
+      .flatten()
+      .value();
+  });
+
+  if (cb) {
+    cb(opts);
+  }
+
+  return opts;
+}
+
+module.exports = options;
diff --git a/lib/polyfills.json b/lib/polyfills.json
new file mode 100644
index 0000000..6e7bd3e
--- /dev/null
+++ b/lib/polyfills.json
@@ -0,0 +1,709 @@
+{
+  "html5shiv": {
+    "name": "HTML5 Shiv",
+    "authors": ["Alexander Farkas (@aFarkas)", "Jonathan Neal (@jonathantneal)", "Paul Irish (@paulirish)"],
+    "href": "https://github.com/aFarkas/html5shiv",
+    "licenses": ["MIT", "GPL2"],
+    "notes": ["The HTML5 Shiv enables use of HTML5 sectioning elements in legacy Internet Explorer and provides basic HTML5 styling for Internet Explorer 6-9, Safari 4.x (and iPhone 3.x), and Firefox 3.x."]
+  },
+  "html5-notifications": {
+    "name": "HTML5 Notifications",
+    "authors": ["Hendrik Beskow"],
+    "href": "https://gist.github.com/Asmod4n/6030828",
+    "licenses": ["MIT"],
+    "notes": ["A Polyfill to fix the differences in WebKit, Blink and Gecko HTML5 Desktop Notifications, also adds a way to add your own JavaScript Notifications in case your Browser doesn't support them natively."]
+  },
+  "desktop-notify": {
+    "name": "HTML5-Desktop-Notifications",
+    "authors": ["Tsvetan Tsvetkov"],
+    "href": "https://github.com/ttsvetko/HTML5-Desktop-Notifications",
+    "licenses": ["Apache2"],
+    "notes": ["A small library that unifies the HTML5 Notifications APIs across different browsers including IE9 & IE10."]
+  },
+  "css3pie": {
+    "name": "CSS3 PIE",
+    "authors": ["Jason Johnston"],
+    "href": "http://css3pie.com/",
+    "licenses": ["Apache2", "GPL2"],
+    "notes": ["CSS3 decoration rendering for IE 6-9. Supports: border-radius, box-shadow, multiple backgrounds, linear gradients, border-image"]
+  },
+  "dynamicaudiojs": {
+    "name": "dynamicaudio.js",
+    "authors": ["Ben Firshman"],
+    "href": "https://github.com/bfirsh/dynamicaudio.js",
+    "licenses": ["BSD"],
+    "notes": []
+  },
+  "audiolibjs": {
+    "name": "audiolib.js",
+    "authors": ["Jussi Kalliokoski"],
+    "href": "https://github.com/jussi-kalliokoski/audiolib.js",
+    "licenses": ["MIT"],
+    "notes": ["specs: incubator group proposed spec, Mozilla Audio Data API (temporary)"]
+  },
+  "transformie": {
+    "name": "transformie",
+    "authors": ["Paul Bakaus"],
+    "href": "https://github.com/pbakaus/transformie",
+    "licenses": ["GPL2", "MIT"],
+    "notes": []
+  },
+  "csssandpaper": {
+    "name": "CSS Sandpaper",
+    "authors": ["Zoltan Hawryluk"],
+    "href": "https://www.useragentman.com/blog/2010/03/09/cross-browser-css-transforms-even-in-ie/",
+    "licenses": ["MIT"],
+    "notes": []
+  },
+  "css-escape": {
+    "name": "CSS.escape()",
+    "authors": ["Mathias Bynens"],
+    "href": "https://github.com/mathiasbynens/CSS.escape",
+    "licenses": ["MIT"],
+    "notes": []
+  },
+  "borderboxmodel": {
+    "name": "borderBoxModel",
+    "authors": ["Alberto Gasparin"],
+    "href": "https://github.com/albertogasparin/borderBoxModel",
+    "licenses": ["MIT"],
+    "notes": ["box-sizing: border-box; javascript polyfill for IE6+"]
+  },
+  "boxsizingpolyfill": {
+    "name": "box-sizing-polyfill",
+    "authors": ["Christian \"Schepp\" Schaefer"],
+    "href": "https://github.com/Schepp/box-sizing-polyfill",
+    "licenses": ["LGPL3"],
+    "notes": ["box-sizing: border-box; for IE6 and IE7 via Microsoft's proprietary CSS behavior / .htc-script"]
+  },
+  "borderbox": {
+    "name": "Borderbox for Compass",
+    "authors": ["Richard Herrera"],
+    "href": "https://github.com/doctyper/compass-borderbox",
+    "licenses": [],
+    "notes": ["box-sizing: border-box; polyfill for SASS/Compass. Outputs equivalent CSS for IE6 & 7"]
+  },
+  "polyfilter": {
+    "name": "Polyfilter",
+    "authors": ["Christian \"Schepp\" Schaefer"],
+    "href": "https://github.com/Schepp/CSS-Filters-Polyfill",
+    "licenses": ["MIT"],
+    "notes": ["CSS filter effects for Chrome 20+, Safari 6+, Firefox 4+, IE 6 - 9 and some mobile browsers."]
+  },
+  "flexie": {
+    "name": "Flexie",
+    "authors": ["Richard Herrera"],
+    "href": "https://github.com/doctyper/flexie",
+    "licenses": ["MIT"],
+    "notes": ["Flexible box model - old spec from 2009. (flexbox) Supports: box-orient, box-align, box-direction, box-pack, box-flex, box-ordinal-group"]
+  },
+  "es5shim": {
+    "name": "ES5 Shim",
+    "href": "https://github.com/kriskowal/es5-shim",
+    "licenses": ["MIT"]
+  },
+  "es5sham": {
+    "name": "ES5 Sham",
+    "href": "https://github.com/kriskowal/es5-shim",
+    "notes": ["Adds the rest of Object, read carefully before using"],
+    "licenses": ["MIT"]
+  },
+  "es6shim": {
+    "name": "ES6 Shim",
+    "href": "https://github.com/paulmillr/es6-shim",
+    "licenses": ["MIT"]
+  },
+  "html5gears": {
+    "name": "html5-gears",
+    "authors": ["Brad Neuberg"],
+    "href": "https://code.google.com/archive/p/html5-gears/",
+    "licenses": ["Apache2"]
+  },
+  "blobjs": {
+    "name": "Blob.js",
+    "authors": ["Eli Grey"],
+    "href": "https://github.com/eligrey/Blob.js",
+    "licenses": ["MIT"]
+  },
+  "excanvas": {
+    "name": "Explorer Canvas",
+    "authors": ["Erik Arvidsson"],
+    "href": "https://github.com/arv/explorercanvas",
+    "licenses": ["Apache2"]
+  },
+  "slcanvas": {
+    "name": "Silverlight HTML 5 Canvas",
+    "href": "https://archive.codeplex.com/?p=slcanvas",
+    "licenses": ["Microsoft Public License (Ms-PL)"]
+  },
+  "canvastext": {
+    "name": "canvas-text",
+    "authors": ["Fabien Ménager"],
+    "href": "https://code.google.com/archive/p/canvas-text/",
+    "licenses": ["MIT"]
+  },
+  "jquery-contextmenu": {
+    "name": "jQuery-contextMenu",
+    "authors": ["Rodney Rehm", "Björn Brala"],
+    "href": "https://github.com/swisnl/jQuery-contextMenu",
+    "licenses": ["MIT", "GPL3"]
+  },
+  "pmxdr": {
+    "name": "pmxdr",
+    "authors": ["Eli Grey"],
+    "href": "https://github.com/eligrey/pmxdr",
+    "notes": ["Implements a CORS-compliant cross-domain XMLHttpRequest with postMessage. Note that sites being requested must have a pmxdr host."],
+    "licenses": ["MIT"]
+  },
+  "ppx": {
+    "name": "postmessage-proxied-xhr",
+    "authors": ["Atul Varma"],
+    "href": "https://github.com/toolness/postmessage-proxied-xhr",
+    "licenses": ["MIT"]
+  },
+  "flxhr": {
+    "name": "flXHR",
+    "authors": ["Kyle Simpson"],
+    "href": "https://github.com/flensed/flXHR",
+    "licenses": ["MIT"]
+  },
+  "dropfile": {
+    "name": "dropfile",
+    "authors": ["Andrew Dodson"],
+    "href": "https://github.com/MrSwitch/dropfile",
+    "licenses": ["MIT"]
+  },
+  "moxie": {
+    "name": "mOxie",
+    "authors": ["Moxiecode"],
+    "href": "https://github.com/moxiecode/moxie",
+    "licenses": ["GPL2"]
+  },
+  "fileapi": {
+    "name": "FileAPI",
+    "authors": ["Konstantin Lebedev", "Demidov Vladimir"],
+    "href": "https://github.com/mailru/FileAPI",
+    "licenses": ["MIT"]
+  },
+  "jdataview": {
+    "name": "jDataView",
+    "authors": ["Christopher Chedeau", "Ingvar Stepanyan"],
+    "href": "https://github.com/jDataView/jDataView/",
+    "licenses": ["WTFPL"]
+  },
+  "screenfulljs": {
+    "name": "screenfull.js",
+    "authors": ["Sindre Sorhus"],
+    "href": "https://github.com/sindresorhus/screenfull.js",
+    "licenses": ["MIT"]
+  },
+  "geo-location-javascript": {
+    "name": "geo-location-javascript",
+    "authors": ["whoisstan"],
+    "href": "https://code.google.com/archive/p/geo-location-javascript/",
+    "notes": ["Mobile-centric: uses non-standard Blackberry and WebOS tricks"],
+    "licenses": ["MIT"]
+  },
+  "geolocation-api-polyfill": {
+    "name": "Geolocation-API-Polyfill",
+    "authors": ["Manuel Bieh"],
+    "href": "https://github.com/manuelbieh/Geolocation-API-Polyfill",
+    "licenses": ["LGPL"]
+  },
+  "jquery-hashchange": {
+    "name": "jQuery hashchange event",
+    "authors": ["Ben Alman"],
+    "href": "http://benalman.com/projects/jquery-hashchange-plugin/",
+    "licenses": ["MIT", "GPL2"]
+  },
+  "moo-historymanager": {
+    "name": "HistoryManager Mootools Plugin",
+    "authors": ["Arieh Glazer"],
+    "href": "https://mootools.net/forge/p/historymanager/",
+    "licenses": ["MIT"]
+  },
+  "jquery-ajaxy": {
+    "name": "jQuery Ajaxy",
+    "authors": ["Benjamin Lupton"],
+    "href": "https://github.com/balupton/jquery-ajaxy",
+    "licenses": ["MIT"]
+  },
+  "hasher": {
+    "name": "Hasher",
+    "authors": ["Miller Medeiros"],
+    "href": "https://github.com/millermedeiros/hasher/",
+    "licenses": ["MIT"]
+  },
+  "shistory": {
+    "name": "sHistory",
+    "authors": ["Andrew Udvare"],
+    "href": "https://github.com/tatsh/sHistory",
+    "licenses": ["MIT"]
+  },
+  "historyjs": {
+    "name": "History.js",
+    "authors": ["Benjamin Lupton"],
+    "href": "https://github.com/browserstate/history.js",
+    "licenses": ["BSD"]
+  },
+  "html5historyapi": {
+    "name": "HTML5 History API",
+    "authors": ["Dmitrii Pakhtinov"],
+    "href": "https://github.com/devote/HTML5-History-API",
+    "licenses": ["GPL3", "MIT"]
+  },
+  "indexeddb": {
+    "name": "IndexedDB",
+    "authors": ["Parashuram"],
+    "href": "https://nparashuram.com/IndexedDBShim/",
+    "licenses": ["GPL2", "BSD"]
+  },
+  "jquerytools": {
+    "name": "jQuery Tools",
+    "href": "https://jquerytools.org",
+    "licenses": ["public domain"]
+  },
+  "webshims": {
+    "name": "Webshims",
+    "authors": ["Alexander Farkas"],
+    "href": "https://afarkas.github.io/webshim/demos/",
+    "licenses": ["MIT"]
+  },
+  "h5f": {
+    "name": "H5F",
+    "authors": ["Ryan Seddon"],
+    "href": "https://github.com/ryanseddon/H5F",
+    "licenses": ["MIT"]
+  },
+  "webforms2": {
+    "name": "Web Forms 2.0",
+    "authors": ["Weston Ruter"],
+    "href": "https://github.com/westonruter/webforms2",
+    "licenses": ["MIT", "GPL2"]
+  },
+  "nwxforms": {
+    "name": "NWX Forms",
+    "authors": ["Diego Perini"],
+    "href": "https://github.com/dperini/nwxforms",
+    "licenses": ["MIT"]
+  },
+  "html5formsjs": {
+    "name": "HTML5Forms.js",
+    "authors": ["Zoltan Dulac"],
+    "href": "https://github.com/zoltan-dulac/html5Forms.js"
+  },
+  "fdslider": {
+    "name": "fd-slider",
+    "authors": ["Brian McAllister"],
+    "href": "https://github.com/freqdec/fd-slider",
+    "licenses": ["MIT"]
+  },
+  "html5slider": {
+    "name": "html5slider",
+    "authors": ["Frank Yan"],
+    "href": "https://github.com/fryn/html5slider",
+    "licenses": ["MIT"]
+  },
+  "number-polyfill": {
+    "name": "Number polyfill",
+    "authors": ["jonstipe"],
+    "href": "https://github.com/jonstipe/number-polyfill",
+    "licenses": ["MIT"]
+  },
+  "galleryhtml5forms": {
+    "name": "YUI Gallery HTML5 Forms",
+    "authors": ["Matt Snider"],
+    "href": "https://yuilibrary.com/gallery-archive/gallery/show/html5-forms.html",
+    "licenses": ["BSD"]
+  },
+  "jscolor": {
+    "name": "JSColor",
+    "authors": ["Johannes Jörg Schmidt"],
+    "href": "https://github.com/jo/JSColor",
+    "licenses": ["LGPL"]
+  },
+  "html5formshim": {
+    "name": "HTML5 Form Shim",
+    "authors": ["Dmitry Sheiko"],
+    "href": "https://github.com/dsheiko/HTML5-Form-Shim",
+    "licenses": ["MIT"]
+  },
+  "selectedoptionsjs": {
+    "name": "selectedOptions.js",
+    "authors": ["Brett Zamir"],
+    "href": "https://gist.github.com/brettz9/4212217",
+    "licenses": ["MIT", "GPL", "public domain"]
+  },
+  "formvalidationjs": {
+    "name": "formvalidation.js",
+    "authors": ["Maksim Chemerisuk"],
+    "href": "https://github.com/chemerisuk/formvalidation.js",
+    "licenses": ["MIT"]
+  },
+  "json2": {
+    "name": "JSON2",
+    "authors": ["Douglas Crockford"],
+    "href": "https://github.com/douglascrockford/JSON-js",
+    "licenses": ["public domain"]
+  },
+  "mathjax": {
+    "name": "MathJax",
+    "authors": ["Davide P. Cervone"],
+    "href": "https://www.mathjax.org/",
+    "licenses": ["Apache2"]
+  },
+  "visibilityjs": {
+    "name": "Visibility.js",
+    "authors": ["Andrey Sitnik"],
+    "href": "https://github.com/ai/visibility.js",
+    "licenses": ["GPL3"]
+  },
+  "visiblyjs": {
+    "name": "visibly.js",
+    "authors": ["Addy Osmani"],
+    "href": "https://github.com/addyosmani/visibly.js",
+    "licenses": ["MIT"]
+  },
+  "jquery-visibility": {
+    "name": "Page Visibility shim for jQuery",
+    "authors": ["Mathias Bynens"],
+    "href": "https://github.com/mathiasbynens/jquery-visibility",
+    "licenses": ["MIT", "GPL"]
+  },
+  "notificationjs": {
+    "name": "notification.js",
+    "authors": ["Andrew Dodson"],
+    "href": "https://adodson.com/notification.js/",
+    "licenses": ["MIT"]
+  },
+  "perfnow": {
+    "name": "perf.now() polyfill",
+    "authors": ["Paul Irish"],
+    "href": "https://gist.github.com/paulirish/5438650",
+    "licenses": ["MIT"]
+  },
+  "easyxdm": {
+    "name": "easyXDM",
+    "authors": ["Sean Kinsey"],
+    "href": "https://github.com/oyvindkinsey/easyXDM",
+    "notes": ["Implements XDM and RPC in most browsers since IE6. Also ships with an endpoint for exposing ajax across the domain boundary."],
+    "licenses": ["MIT"]
+  },
+  "postmessage-jquery": {
+    "name": "postMessage jquery plugin",
+    "authors": ["Ben Alman"],
+    "href": "http://benalman.com/projects/jquery-postmessage-plugin/",
+    "licenses": ["MIT", "GPL2"]
+  },
+  "raf": {
+    "name": "requestAnimationFrame polyfill",
+    "authors": ["Erik Möller"],
+    "href": "https://gist.github.com/paulirish/1579671",
+    "licenses": ["MIT"]
+  },
+  "cupcake": {
+    "name": "CupCake.js",
+    "authors": ["Rivindu Perera"],
+    "href": "https://github.com/rivindu/cupcakejs",
+    "licenses": ["MIT"]
+  },
+  "customelements": {
+    "name": "Custom Elements",
+    "authors": ["Webcomponents"],
+    "href": "https://github.com/webcomponents/custom-elements",
+    "licenses": ["BSD"]
+  },
+  "storagepolyfill": {
+    "name": "Storage Polyfill",
+    "authors": ["Remy Sharp"],
+    "href": "https://gist.github.com/remy/350433",
+    "licenses": ["MIT"]
+  },
+  "amplifyjs": {
+    "name": "Amplify.js",
+    "authors": ["appendTo"],
+    "href": "https://amplifyjs.com/",
+    "licenses": ["MIT", "GPL2"]
+  },
+  "yui-cacheoffline": {
+    "name": "YUI3 CacheOffline",
+    "authors": ["YUI Team"],
+    "href": "https://yuilibrary.com/yui/docs/cache/#offline",
+    "licenses": ["BSD"]
+  },
+  "scoped-styles": {
+    "name": "Scoped Styles",
+    "authors": ["Simon Madine"],
+    "notes": ["jQuery Plugin to enable the scoped attribute on style blocks so they only affect their parent element's children."],
+    "href": "https://github.com/thingsinjars/jQuery-Scoped-CSS-plugin",
+    "licenses": ["MIT"]
+  },
+  "svgweb": {
+    "name": "SVG Web",
+    "authors": ["Rick Masters", "Brad Neuberg", "James Hight"],
+    "href": "https://code.google.com/archive/p/svgweb/",
+    "licenses": ["Apache2"]
+  },
+  "raphael": {
+    "name": "Raphaël",
+    "authors": ["Dmitry Baranovsky"],
+    "href": "http://raphaeljs.com/",
+    "notes": ["Abstracted API. adds features. fallback for IE via VML"],
+    "licenses": ["MIT"]
+  },
+  "canvg": {
+    "name": "canvg",
+    "authors": ["Gabe Lerner"],
+    "href": "https://github.com/canvg/canvg",
+    "notes": ["Writes SVG to canvas. Good for Android"],
+    "licenses": ["MIT"]
+  },
+  "svg-boilerplate": {
+    "name": "SVG Boilerplate",
+    "authors": ["Robin Berjon"],
+    "href": "https://github.com/darobin/svgboilerplate",
+    "notes": ["Alpha and still buggy, but handle multiple concurrent SVG shims together"],
+    "licenses": ["public domain"]
+  },
+  "sie": {
+    "name": "SIE SVG library",
+    "authors": ["Hiroki Dehara"],
+    "href": "https://sie.osdn.jp/",
+    "notes": ["Fallback to VML for oldIE"],
+    "licenses": ["Mozilla1.1", "GPL2", "LGPL2.1"]
+  },
+  "fabricjs": {
+    "name": "fabric.js",
+    "authors": ["Juriy Zaytsev (@kangax)"],
+    "href": "https://github.com/kangax/fabric.js",
+    "notes": ["Can render SVG via canvas"],
+    "licenses": ["MIT"]
+  },
+  "inline-svg-polyfill": {
+    "name": "inline SVG polyfill",
+    "authors": ["Marc Stalfoort (@mstalfoort)"],
+    "href": "https://gist.github.com/mstalfoort/1293822",
+    "licenses": ["MIT"]
+  },
+  "joshuabell-polyfill": {
+    "name": "polyfill",
+    "authors": ["Joshua Bell"],
+    "href": "https://github.com/inexorabletash/polyfill",
+    "licenses": ["various"]
+  },
+  "html5media": {
+    "name": "html5media",
+    "authors": ["Dave Hall"],
+    "href": "https://github.com/etianen/html5media",
+    "licenses": ["GPL3"]
+  },
+  "mediaelementjs": {
+    "name": "MediaElement.js",
+    "authors": ["John Dyer"],
+    "href": "https://www.mediaelementjs.com/",
+    "licenses": ["MIT"]
+  },
+  "videojs": {
+    "name": "video.js",
+    "authors": ["Steve Heffernan"],
+    "href": "https://videojs.com/",
+    "licenses": ["Apache2"]
+  },
+  "leanbackplayer": {
+    "name": "LeanBack Player",
+    "authors": ["Kapelan Medien GmbH"],
+    "href": "https://www.leanbackplayer.com/",
+    "licenses": ["GPL3"]
+  },
+  "videoforeverybody": {
+    "name": "Video For Everybody",
+    "authors": ["Kroc Camen"],
+    "href": "http://camendesign.com/code/video_for_everybody",
+    "licenses": ["public domain"]
+  },
+  "jebgl": {
+    "name": "jebgl",
+    "authors": ["Martin Qvist"],
+    "href": "https://code.google.com/archive/p/jebgl/",
+    "licenses": ["MIT"]
+  },
+  "cwebgl": {
+    "name": "cwebgl",
+    "authors": ["Cimaron Shanahan"],
+    "href": "https://code.google.com/archive/p/cwebgl/",
+    "licenses": ["MIT"]
+  },
+  "iewebgl": {
+    "name": "IEWebGL",
+    "href": "http://iewebgl.com/",
+    "licenses": ["MIT"]
+  },
+  "sockjs": {
+    "name": "SockJS",
+    "authors": ["Bryce Kahle"],
+    "href": "https://github.com/sockjs/sockjs-client",
+    "licenses": ["MIT"]
+  },
+  "socketio": {
+    "name": "socket.io",
+    "authors": ["Guillermo Rauch"],
+    "href": "https://socket.io/",
+    "licenses": ["MIT"]
+  },
+  "websocketjs": {
+    "name": "web-socket-js",
+    "authors": ["Hiroshi Ichikawa"],
+    "href": "https://github.com/gimite/web-socket-js/",
+    "licenses": ["BSD"]
+  },
+  "atmosphere": {
+    "name": "atmosphere jQuery plugin",
+    "authors": ["Jeanfrancois Arcand"],
+    "href": "https://jfarcand.wordpress.com/2010/06/15/using-atmospheres-jquery-plug-in-to-build-applicationsupporting-both-websocket-and-comet/",
+    "licenses": ["Apache2"]
+  },
+  "graceful-websocket": {
+    "name": "Graceful WebSocket jQuery plugin",
+    "authors": ["David Lindkvist"],
+    "href": "https://github.com/ffdead/jquery-graceful-websocket",
+    "licenses": ["MIT"]
+  },
+  "portal": {
+    "name": "Portal",
+    "authors": ["Donghwan Kim"],
+    "href": "https://github.com/flowersinthesand/portal",
+    "licenses": ["Apache2"]
+  },
+  "datachannel": {
+    "name": "DataChannel",
+    "authors": ["Jesús Leganés Combarro"],
+    "href": "https://github.com/piranna/DataChannel-polyfill",
+    "licenses": ["GPL3"]
+  },
+  "getusermedia": {
+    "name": "getUserMedia.js",
+    "authors": ["Addy Osmani"],
+    "href": "https://github.com/addyosmani/getUserMedia.js",
+    "licenses": ["MIT"]
+  },
+  "fakeworker": {
+    "name": "fakeworker.js",
+    "authors": ["Shumpei Shiraishi"],
+    "href": "https://code.google.com/archive/p/fakeworker-js/",
+    "licenses": ["Apache2"]
+  },
+  "html5shims": {
+    "name": "web worker api shim",
+    "authors": ["Jonathan 'J5' Cook"],
+    "href": "https://code.google.com/archive/p/html5-shims/",
+    "licenses": ["Apache2"]
+  },
+  "webanimationsjs": {
+    "name": "web-animations-js",
+    "authors": ["web-animations"],
+    "href": "https://github.com/web-animations/web-animations-js",
+    "licenses": ["Apache2"]
+  },
+  "shumway": {
+    "name": "JavaScript Flash VM",
+    "authors": ["Mozilla Foundation"],
+    "href": "https://github.com/mozilla/shumway",
+    "licenses": ["Apache2"]
+  },
+  "maxlength": {
+    "name": "maxlength plugin",
+    "authors": ["Remy Sharp"],
+    "href": "https://remysharp.com/2008/06/30/maxlength-plugin/",
+    "licenses": ["CC SA"]
+  },
+  "weakmap": {
+    "name": "ES6 WeakMap",
+    "authors": ["Google Inc."],
+    "href": "https://github.com/Polymer/WeakMap",
+    "licenses": ["BSD"]
+  },
+  "eventlistener": {
+    "name": "EventListener",
+    "authors": ["Jonathan Neal"],
+    "href": "https://github.com/jonathantneal/EventListener",
+    "licenses": ["MIT"]
+  },
+  "es6promises": {
+    "name": "ES6-Promises",
+    "authors": ["Jake Archibald"],
+    "href": "https://github.com/jakearchibald/ES6-Promises",
+    "licenses": ["MIT"]
+  },
+  "es6symbol":{
+    "name": "ES6-Symbol",
+    "authors": ["Mariusz Nowak"],
+    "href": "https://github.com/medikoo/es6-symbol",
+    "licenses": ["ISC"]
+  },
+  "urlparser": {
+    "authors": ["Google Inc."],
+    "href": "https://github.com/Polymer/URL",
+    "licenses": ["BSD"],
+    "name": "Polymer URL parser polyfill"
+  },
+  "css-selector-engine": {
+    "name": "CSS Selector Engine",
+    "authors": ["Егор Халимоненко"],
+    "href": "https://github.com/termi/CSS_selector_engine",
+    "licenses": ["MIT"]
+  },
+  "mutationobservers": {
+    "authors": ["Google Inc."],
+    "href": "https://github.com/Polymer/MutationObservers",
+    "licenses": ["BSD"],
+    "name": "Mutation Observers polyfill"
+  },
+  "polymer-htmlimports": {
+    "authors": ["Google Inc."],
+    "href": "https://github.com/polymer/HTMLImports",
+    "licenses": ["BSD"],
+    "name": "Polymer HTMLImports polyfill"
+  },
+  "matchmediajs": {
+    "authors": ["Scott Jehl", "Paul Irish", "Nicholas Zakas"],
+    "href": "https://github.com/paulirish/matchMedia.js/",
+    "licenses": ["MIT"],
+    "name": "matchMedia.js"
+  },
+  "fetch": {
+    "authors": ["Github"],
+    "href": "https://github.com/github/fetch",
+    "licenses": ["MIT"],
+    "name": "window.fetch polyfill"
+  },
+  "base64js": {
+    "authors": ["David Chambers"],
+    "href": "https://github.com/davidchambers/Base64.js",
+    "licenses": ["Apache2", "WTFPL"],
+    "name": "window.atob and window.btoa polyfill"
+  },
+  "scrollsnap": {
+    "authors": ["Clemens Krack"],
+    "href": "https://github.com/ckrack/scrollsnap-polyfill",
+    "licenses": ["MIT"],
+    "name": "scrollsnap-polyfill.js"
+  },
+  "pep": {
+    "authors": ["jQuery Foundation and other contributors"],
+    "href": "https://github.com/jquery/PEP",
+    "licenses": ["MIT"],
+    "name": "pep.js"
+  },
+  "harmony-reflect": {
+    "name": "Proxy Object Polyfill",
+    "authors": ["Tom Van Cutsem"],
+    "href": "https://github.com/tvcutsem/harmony-reflect",
+    "licenses": ["Apache2"]
+  },
+  "avifjs": {
+    "name": "Avif.js",
+    "authors": ["Kagami"],
+    "href": "https://github.com/Kagami/avif.js",
+    "licenses": ["CC0"]
+  }
+}
diff --git a/media/Modernizr 2 Logo.ai b/media/Modernizr 2 Logo.ai
deleted file mode 100644
index 60874e0..0000000
--- a/media/Modernizr 2 Logo.ai	
+++ /dev/null
@@ -1,291 +0,0 @@
-%PDF-1.5
%����
-1 0 obj
<</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R]/Order 6 0 R/RBGroups[]>>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>>
endobj
2 0 obj
<</Length 18095/Subtype/XML/Type/Metadata>>stream
-<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
-<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.0-c060 61.134777, 2010/02/12-17:32:00        ">
-   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
-      <rdf:Description rdf:about=""
-            xmlns:xmp="http://ns.adobe.com/xap/1.0/"
-            xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
-         <xmp:CreatorTool>Adobe Illustrator CS5</xmp:CreatorTool>
-         <xmp:CreateDate>2011-03-28T13:28:59+11:00</xmp:CreateDate>
-         <xmp:MetadataDate>2011-03-28T13:28:59+11:00</xmp:MetadataDate>
-         <xmp:ModifyDate>2011-03-28T13:28:59+11:00</xmp:ModifyDate>
-         <xmp:Thumbnails>
-            <rdf:Alt>
-               <rdf:li rdf:parseType="Resource">
-                  <xmpGImg:width>256</xmpGImg:width>
-                  <xmpGImg:height>40</xmpGImg:height>
-                  <xmpGImg:format>JPEG</xmpGImg:format>
-                  <xmpGImg:image>/9j/4AAQSkZJRgABAgEBLAEsAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABABLAAAAAEA&#xA;AQEsAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAKAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq+TfzF/5TvXf&#xA;+YyX/iWZmL6Q+o9k/wCK4/6oTP8AJn/yZWj/APRz/wBQsuOX6S4/b/8Aic/83/dBJ/OU00PnfX3h&#xA;do3GpXdGQlT/AH79xhiLiHK0EQdNjBF+iP8AuQitE/M3zvo7L9W1WaWJf90XJ9eMjwpJyKj/AFSM&#xA;BxRLVqOx9Nl5wAPeNvueu+Svzz0fVpEstcjXTL1zxScEm2c+5O8Z/wBao98oniIeV7Q9nMmIcWI8&#xA;cft/b+NnqAIIBBqDuCOlMqebdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi&#xA;rsVdirsVYv588+Wfk+ztbm5tZLpbqRolWJlUgqvKp5ZKMTI0HZdm9my1cjGJAoML/wChi9E/6tFz&#xA;/wAHHlngF3H+hXL/AD4/a8a8z6tFrHmHUNUijaKO9neZY2ILKHNaGmZEI0Keu0eA4sMYHcxFMi/J&#xA;n/yZWj/9HP8A1Cy5HL9JcDt//E5/5v8Augknnf8A5TTX/wDtpXf/ACffJQ5BzOzv8Wx/1I/cEkyT&#xA;mOxV6r+Un5qz6Vcw6FrcxfSZSEtbhzU27E7Asf8AdZ/4X5ZRlx9Q8x252KMgOXEPWOY7/wBv3voD&#xA;ruMxnhXYqwvz7+Z1h5Ou7W2urKW6a6jaRWiZVACtxoeWThAy5O37N7Inq4kxkBw97KNH1S11bSrT&#xA;U7U1t7yJJo/EBhWh9x0OQIp1ufDLFMwlziaXapqVtpmm3Wo3Tcbe0ieaU/5KCu3ucUYcRyTEI85G&#xA;mK+QvzOsPON3dW1rZS2rWsayM0rKwIZuNBxyc4GPN2faXZE9JEGUgeLuZpkHUOxV2KuxVjvnrzpa&#xA;+UNIh1K5tnuo5rhbYRxkKQWR3r8X/GPJRiZHZ2HZ3Z8tVkMIkChf3frT+GQSwpKBQOoYD5iuRcCQ&#xA;o0vxQ7FXYq7FXYq7FWOecPPug+UhZHVfV/052WL0UD0EfHm7VK7LzHSp9slGBPJ2Gh7Ny6ri8OvT&#xA;3sjyLr3Yq7FXYq7FXkf/ADkX/wAcTSP+Yl/+TeXYOb1Xsr/ez/q/peDZlPbuxVm35M/+TK0f/o5/&#xA;6hZcry/SXT9v/wCJz/zf90Ek87/8ppr/AP20rv8A5Pvkocg5nZ3+LY/6kfuCSZJzHYq7FX0h+Sfn&#xA;GTXPLjaddyc9Q0njEWY1Z4GB9JjXqRQqfkPHMPLCi+e+0GgGHNxx+me/x6/rei5W6B41+c9hDqHn&#xA;zylp89fRvHSCWnXjLcKjU+g5diOxeu7AyHHps0xziL+USnH5K6jc2kOq+T9Qal7olw/pKe8TsQ3H&#xA;2Em/+yGRyd/e4ntBiEjDUQ+nIPt/s+5d+dmqXMthpvlSwNb/AF24RGQf76RhStOgaQr9AOOMb33I&#xA;9n8IE5Z5/TjH2/2JV+UOmQaX5+806bb/ANzZqsCE9SI5ONT86YchsBye3Mxy6XDM85bsq88fmSmg&#xA;39voml2Tar5guwDFaISFQN9kuQCamleI7bkjIxhe/R1nZ3ZJzxOScuDFHqkd3+YH5oaDGNQ8yeWo&#xA;DpOxlks5PjiBNPjpJMNvcAe+S4InkXNh2Zos54MOU8f9Ic/sD0PRNc03WtKg1TT5RJZ3C8lY7EU2&#xA;ZWHYqdjlZFOh1GnnhmYTFSDz2f8ANPzRrmsXGn+RdGj1CC1bjLqFySIjvTkKPEApp8NWqfDLOAD6&#xA;nex7Gw4cYnqpmJl/COf3H7mK/mz5q8wXvlq30jzHo7aXqkd6lxHJG3qW00SxSoxRwWAKl1+Hkcni&#xA;AvYuz7E0eKGY5MM+OHDXcQbD2e81jT9G8vfpPUJPStLaBXkbqT8IAVR3ZjsBmOBbyOPBPLl4IC5E&#xA;sGtPPX5n6/F+kPLnly2TSWY+hJfSUklUGlV/eRAdPAj3OWGMRzLusnZ2iwHgzZZcfXhGw+wp55K/&#xA;ME63fXGi6vYtpHmG0HKWyckh0/njJp49PDcEjBKNb9HC7Q7M8GIyY5ceKXX9aC85/miPK/m6z0i4&#xA;s/Wsbi0+svLHVpvUYyrHGidDyeNRv44Y47Ft2g7H/M4JZBKpCVeXSyfgUb5a8z+cr6DVL3WtEXSr&#xA;OCD1tPjZiZHIDFhIa16AfsDIyAHItOr0mngYRx5OORNS7vh/axvQfzb80+YrD09D8u/WtVVyJ2L8&#xA;LSGPbiWdivJjv8NRk5Y6O5dhqexMOnl+9ycMOm3qPwROi/mX5qtfNVp5d85aRDYTX5C2lxbE8CzE&#xA;hOryhgzfDs2x7YDAVYLXqOycEsBzaeZkI8wf7B9ybfmZr9tpH6E9fS7XU/rd6sSfWkD+kxp+8jqD&#xA;RsjEXfucXsnTSy+JU5Q4Y3t18imvnDV/NenRWreXtIXVnkZxcK0gj4AAcTuVrXfBEDqXG0ODBkJ8&#xA;WfB3bWwnWvzO/MbRLI3uq+V4LS1DBPUe4BqzdAArEn6BlggCaBdxp+x9JmlwwymUv6rLdK826pc/&#xA;l9N5nvLFba6S0uLyO0qeLJErPGanejhQfpyHDvTq82ihHVDBGVx4hG/fz+TE7D82/Neu6XD/AIb8&#xA;um91MBjfSMWFrC3NgiBiU5sUAY/EOuTOMA7l2mXsTBgmfGycMOn849/fW+3J5H/ysXz3/wBX28/5&#xA;Gtl/hR7nqv5J0v8AqcfkgNW8z+YdYiji1TUJ72OJi0azOXCsRSorkowA5N+DR4cRuEREnuSvJOS7&#xA;FWbfkz/5MrR/+jn/AKhZcry/SXT9v/4nP/N/3QSTzv8A8ppr/wD20rv/AJPvkocg5nZ3+LY/6kfu&#xA;CSZJzHYq7FWd/krrL6d59s4uREOoK9rKP9Zeabf66LlWYel0ntBgGTSk9Y0f1/Y+msxHzl5H+an/&#xA;AJM3yR/zEwf9RaZdj5F6rsX/ABPP/VP+5Kp55/51P8zdG82J8Fhqg+p6mR0qAELN/sOLf7DBHeJD&#xA;Ds7/AArRzwfxQ9Ufx8/m35SH+LvzU1XzK/x6bog+p6ceql90DD/h3/2QxltEDvXW/wCC6GGH+PJ6&#xA;pfj5D4L/AMuf/Jqedf8AjIf+TxwS+kI7V/xLB7v0KX5fIlz+bnnC6vBW9gZ47YNQkRCXhyH+wRB8&#xA;jhn9IZdpnh0GGMfpPP31+u3ql5bW9zaTW1yoe2mjaOZW6FGBDA19sqeahMxkCOYeK/lrd3cX5V+c&#xA;BbOzQ24ujayGtRW3+IjwoAGy/IPUHr+1oROuw8XM8N/6ZmP5H21pF+XtnJCAJbiWeS5I6mQSsgr/&#xA;ALBFyGX6nU+0U5HVyB5ACvlf32lv/OQwH+DLI03/AEjHv/zwmyWDm5Hst/jEv6h++KF/Pee4TyRp&#xA;ESVEEtxH61DSpWFiqn8T9GDDzbfZuIOpmeoifvTu11b81IbaGG28s2C28aKkKreLxCKKKBv0pkKH&#xA;e4M8GiJJOWd/1Ur/AEF+YepeftF8x32kW+nrZfubp4LhHLwtyB5CtTQOclYAIcr8zpMelnhjOUuL&#xA;cXHqu8xxo/5++WldQyjTnYBhUVVbtlO/cEVGSj9BXSkjsvLX8/8A4h6Lrf8Axxr/AP5hpf8AiByl&#xA;5/B/eR94YH+QX/KCt/zGzf8AEUyzL9Tu/aX/ABr/ADR+lD/myq/42/L5qDkdRoT3oJ7Wn68lj5Ft&#xA;7E/xbU/1P97Nd+d3/TMf9tJf4ZHH19zH2e/yv/Cy9LmmighkmmcRwxKXkkY0VVUVJJPYDK3nYxJN&#xA;DmXkFlFcfmj5yN9OrDybokhWCJqgXEnXcf5fVvBaDvlx9A8y9XkI7N0/CP8AGMnP+iPx9vuej+dl&#xA;VfJOvKoAUabdgAbAAQPlcOYef7P/AMZx/wBeP+6CSfkuiL+W2klVALm5LkClT9ZkFT9AAyWX6i5v&#xA;b5/wyf8Am/7kPFv+VM/mV/1Z/wDp5tf+quZHix73sP5f0f8AP/2Mv1O/5Uz+ZX/Vn/6ebX/qrj4s&#xA;e9f5f0f8/wD2Mv1O/wCVM/mV/wBWf/p5tf8Aqrj4se9f5f0f8/8A2Mv1O/5Uz+ZX/Vn/AOnm1/6q&#xA;4+LHvX+X9H/P/wBjL9TKPyy/LLzvovnfTdT1PTfq9jb+v603r270528iL8KSMxqzAbDIZMgIoOs7&#xA;X7X02bTShCVyNdJfzgeoSvzV+Uv5g33mfV7210r1LW6vbmaCT6xbLyjklZlNGkBFQe4wxyRADlaL&#xA;tvSQwwjKfqjGIO0ug9yV/wDKmfzK/wCrP/082v8A1VyXix73J/l/R/z/APYy/U7/AJUz+ZX/AFZ/&#xA;+nm1/wCquPix71/l/R/z/wDYy/U7/lTP5lf9Wf8A6ebX/qrj4se9f5f0f8//AGMv1Jn5X/Kn8xdN&#xA;8y6VqE2klIbS8gmmYXNttGkis/2ZCfsg9BkZZIkFxtZ21pMmGcBPeUSPpl3e59GZivn7zrz/AOUv&#xA;MGreevK2qafa+tY6bPE97N6kacFS4V2PF2Vm+EV+EHLISABd/wBma3Fi02aEzUpg1sf5pDIPzF8r&#xA;t5l8pXumxKGvABNZVIH76PdRU7DkKrv45GEqNuD2VrPy+eMz9PI+4/i1P8tPKr+WfKVrY3EYjv5S&#xA;Z74Aq1JX/ZqtQeKgLse2GcrNsu19b+YzmQ+nkPd+N0p8leVtd03z/wCaNVvbX0rDUXJs5ucbcx6h&#xA;b7KsWXb+YDGRFBye0NZiyaXFjiblDnz7kN5z8keZLXzQnnLycY21MrwvrCQhVmAAFRUqp5KAGFR0&#xA;qDXDGQqi2aDtDDLD+X1F8HSXcgdU1b84fMlm2j2+gJoqXI9K7v5JRsjbNxNagH/JDHCBEb3bfhwd&#xA;n6eXiHJ4lco1+P0M28p+TdO8v+WF0JP38Tq/1yRhT1XlFJCR2BGwHhkJSs26bW6+efN4p2PTyrk8&#xA;/wBL0X8yPy+vrq10WxGveXrmQyQxcwroT9NVamx2INO2WExlz2Lvc2o0euiJZJeFlA380N530D82&#xA;vOWlQyXGnQ2tvFOrQaNHLH6m6ODPLJI6r8P2Qta/F0wwlGJbOztToNJkIEjIkbzo102AA/Fc3pPm&#xA;jynbeZPKraLdn0nKIYpgORimjHwt138D7ZTGVG3ntHrTp8/iR3/SGGaTqv5t+WLRNIu9AXXYLZfT&#xA;tL2CYKSiii8jRiae6g/rywiJ3unb58Og1EvEjk8InmCGR+UH/Ma91WbUfMcdvp2mtF6dvpMdJJA3&#xA;KokZwWoae/0DISro6/XDSQgIYSZzveXIe6vx70HrHlnXLj83tD8wQ23LSLOyeG5uecY4yFbkAcCw&#xA;c/3q9F75ISHAQ3YNZijoMmIn95KVgb/0fh0LM9Uhkn0y7hiHKWWGREWoFWZCAKnbrlbqMMgJgnoQ&#xA;xL8ovLms+X/KbWGr2/1a7NzJL6fNJPgZVANY2de3jk8hBOztO3NVjz5+PGbjwjv/AEqP5h+Wdc1f&#xA;zP5OvdOtvXtdKvTNfyc409OP1YGrR2UttG32QcMJAAs+y9ZixYc0ZmpTjUee+0v1t/mn5Z1vXP0F&#xA;+i7b6x9SvlnufjjTjGKfF+8Za/Rggav3I7H1ePD4nGa4oUOfP4O/N7SfOWsaHBpnlyD1o7hz+kQJ&#xA;I4m9NQCi1kdNmbrTww4yAd09h5tPiymeY1X07E7/AACR6DP+b2h6Tb6Xp/lCyjtbZeK/6TFyY9Wd&#xA;j6+7MdzhIiermamOgzZDOeaXEf6J/wCJZfInmjWPIOpwapYR2mu3lndwLZRSIy8nR0iAfmy/FUdW&#xA;yIoSdVE4cWqiYS4scZRN15i9qd+WWi6lovkjTdM1OH6vfW/r+tDyR6c7iR1+JCymqsDscchs2F7X&#xA;1EM2plOBuJr/AHIHV//Z</xmpGImg:image>
-               </rdf:li>
-            </rdf:Alt>
-         </xmp:Thumbnails>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
-         <photoshop:ColorMode>3</photoshop:ColorMode>
-         <photoshop:ICCProfile>sRGB IEC61966-2.1</photoshop:ICCProfile>
-         <photoshop:TextLayers>
-            <rdf:Bag>
-               <rdf:li rdf:parseType="Resource">
-                  <photoshop:LayerName>Modernizr</photoshop:LayerName>
-                  <photoshop:LayerText>Modernizr</photoshop:LayerText>
-               </rdf:li>
-            </rdf:Bag>
-         </photoshop:TextLayers>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:dc="http://purl.org/dc/elements/1.1/">
-         <dc:format>application/pdf</dc:format>
-         <dc:title>
-            <rdf:Alt>
-               <rdf:li xml:lang="x-default">Modernizr 2 Logo</rdf:li>
-            </rdf:Alt>
-         </dc:title>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
-            xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
-            xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#">
-         <xmpMM:InstanceID>uuid:d2ad3950-7c02-824a-aed8-40a8f4f3f557</xmpMM:InstanceID>
-         <xmpMM:DocumentID>xmp.did:03801174072068118083F1FA8E5E4F1F</xmpMM:DocumentID>
-         <xmpMM:OriginalDocumentID>xmp.did:F77F117407206811BB3F9C0632107F53</xmpMM:OriginalDocumentID>
-         <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
-         <xmpMM:History>
-            <rdf:Seq>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>created</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:F77F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T17:17:50-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:F87F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T17:18:53-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:F97F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:02:32-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FA7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:18:57-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FB7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:25:21-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FC7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:26:04-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FD7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:37:06-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>converted</stEvt:action>
-                  <stEvt:parameters>from application/vnd.adobe.photoshop to application/pdf</stEvt:parameters>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>derived</stEvt:action>
-                  <stEvt:parameters>converted from application/vnd.adobe.photoshop to application/pdf</stEvt:parameters>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FE7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:37:07-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:03801174072068118083F1FA8E5E4F1F</stEvt:instanceID>
-                  <stEvt:when>2011-03-28T13:28:58+11:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Illustrator CS5</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-            </rdf:Seq>
-         </xmpMM:History>
-         <xmpMM:DerivedFrom rdf:parseType="Resource">
-            <stRef:instanceID>uuid:edd0f61a-a49d-1d49-acc4-68ea7894e484</stRef:instanceID>
-            <stRef:documentID>xmp.did:F77F117407206811BB3F9C0632107F53</stRef:documentID>
-            <stRef:originalDocumentID>xmp.did:F77F117407206811BB3F9C0632107F53</stRef:originalDocumentID>
-         </xmpMM:DerivedFrom>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
-         <pdf:Producer>Adobe PDF library 9.90</pdf:Producer>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
-            xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
-            xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
-         <xmpTPg:NPages>1</xmpTPg:NPages>
-         <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
-         <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
-         <xmpTPg:MaxPageSize rdf:parseType="Resource">
-            <stDim:w>600.000000</stDim:w>
-            <stDim:h>88.799805</stDim:h>
-            <stDim:unit>Pixels</stDim:unit>
-         </xmpTPg:MaxPageSize>
-         <xmpTPg:PlateNames>
-            <rdf:Seq>
-               <rdf:li>Cyan</rdf:li>
-               <rdf:li>Magenta</rdf:li>
-               <rdf:li>Yellow</rdf:li>
-            </rdf:Seq>
-         </xmpTPg:PlateNames>
-         <xmpTPg:SwatchGroups>
-            <rdf:Seq>
-               <rdf:li rdf:parseType="Resource">
-                  <xmpG:groupName>Default Swatch Group</xmpG:groupName>
-                  <xmpG:groupType>0</xmpG:groupType>
-               </rdf:li>
-            </rdf:Seq>
-         </xmpTPg:SwatchGroups>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
-         <illustrator:Type>Document</illustrator:Type>
-      </rdf:Description>
-   </rdf:RDF>
-</x:xmpmeta>
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                           
-<?xpacket end="w"?>
endstream
endobj
3 0 obj
<</Count 1/Kids[7 0 R]/Type/Pages>>
endobj
7 0 obj
<</ArtBox[0.0 1.36328 583.011 88.7998]/BleedBox[0.0 0.0 600.0 88.7998]/Contents 8 0 R/LastModified(D:20110328132859+11'00')/MediaBox[0.0 0.0 600.0 88.7998]/Parent 3 0 R/PieceInfo<</Illustrator 9 0 R>>/Resources<</ExtGState<</GS0 10 0 R>>/Properties<</MC0 5 0 R>>>>/Thumb 11 0 R/TrimBox[0.0 0.0 600.0 88.7998]/Type/Page>>
endobj
8 0 obj
<</Filter/FlateDecode/Length 1080>>stream
-H��Vˎ$5��W��T�L�}e@�VhŁh1��,���KD�Y���K���|83"�^~~u/�^�}�ë[ī'���߀��cy��q���|s
-,���ך��'���p��k{�}��1����
���<|�ŗ�m��|C�ƭ"8V�����<��#�n)�#�T}Uz���|i�~#ry��1�c���M|��mE��{M^
-���'��8_U}����Kp�o��(/�շ�l'��&�^��h^bv�+.��:ܩ��L�\>�	V���H}
�PZa�������Y}I-�Y9�{�p1���u���#����B� ���F�_WS�a4dM��(N�}G�j�"B6e��u�}�z���#]�댫�pb�
-[R�LR���x���y8�n��B%��?˜�����\��	f�i����K���G�DL���&���
�n��K>k�k���9�
-��b�Q|*�6��r���F���Fu|Ek""#b��|edt���%�c�:��Z��&�Ҙᄧ�pT-A�-�O���M7E>۹���C���h=k�^5����I�p_�]�
-A##�y0�-¹b
E�������N���6	7p��6Rĵ�ߠc�㚪ǁ�k��ƦF��wJq�gL�~h��[��B�_Ay�����X"�H<��G�,�%������#��D�
�5�
M��
g7Eg�L�V�,p�FȐP8��� RW(,�H��N�Y�
5�ռ���U�CV��43�3���Z
�wd��)#AW7,Pm!?��ī�-�[�&~�6�P�Ξ�t�Uf�Wd�v�1X� =�GIߟ��*�Q�f�yt@Ԣ>����5�
��=�9�R�)ER@5�9�8-�F�lF�1���9'NOE�Y/��A�0eu����T1�_�0�,����uw��gI�v�̶y�ٖA�4?dl
-�/���-��G�!�N��{�S:�	Z��#��r�tg\�f�gL��dW��/�h��A��Gr�Z� 
-���+����6�;a3F���@��e������˞��?~�������0�
endstream
endobj
11 0 obj
<</BitsPerComponent 8/ColorSpace 12 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 11/Length 217/Width 75>>stream
-8;X.*5o.B]#Xe'qAYk1P*4a@.!l]_ep/*-_RXPW`fG[D6f.h*1a7H@op([&VW*Y^*
-W0WFo2Q9;Fb+MFP43tonNU43q7k''P:'9+35"AmKh.O9'J#%\IT$_Z*W;Z'Oj7LaA
-9^>Zd/+=U[R&s-+Brt<DrD5OMUCQS3iH5`HV"Ec'MamVcE^1X21/>.'Lp'%G5RL>:
-;0"gleOf`E!,b_4ci~>
endstream
endobj
12 0 obj
[/Indexed/DeviceRGB 255 13 0 R]
endobj
13 0 obj
<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
-8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
-b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
-E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
-6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
-VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
-PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
-l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>
endstream
endobj
5 0 obj
<</Intent 14 0 R/Name(Layer 1)/Type/OCG/Usage 15 0 R>>
endobj
14 0 obj
[/View/Design]
endobj
15 0 obj
<</CreatorInfo<</Creator(Adobe Illustrator 15.0)/Subtype/Artwork>>>>
endobj
10 0 obj
<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>
endobj
9 0 obj
<</LastModified(D:20110328132859+11'00')/Private 16 0 R>>
endobj
16 0 obj
<</AIMetaData 17 0 R/AIPrivateData1 18 0 R/AIPrivateData2 19 0 R/ContainerVersion 11/CreatorVersion 15/NumBlock 2/RoundtripStreamType 1/RoundtripVersion 15>>
endobj
17 0 obj
<</Length 969>>stream
-%!PS-Adobe-3.0 
%%Creator: Adobe Illustrator(R) 15.0
%%AI8_CreatorVersion: 15.0.2
%%For: (Marc Edwards) ()
%%Title: (Modernizr 2 Logo.pdf)
%%CreationDate: 28/03/11 1:28 PM
%%Canvassize: 16383
%%BoundingBox: -1 1 584 89
%%HiResBoundingBox: -0.000488 1.36328 583.0107 88.7998
%%DocumentProcessColors: Cyan Magenta Yellow
%AI5_FileFormat 11.0
%AI12_BuildNumber: 399
%AI3_ColorUsage: Color
%AI7_ImageSettings: 0
%%CMYKProcessColor: 1 1 1 1 ([Registration])
%AI3_Cropmarks: 0 0 600 88.7998
%AI3_TemplateBox: 299.5 44.5 299.5 44.5
%AI3_TileBox: -103 -235.0996 680 323.8999
%AI3_DocumentPreview: None
%AI5_ArtSize: 14400 14400
%AI5_RulerUnits: 6
%AI9_ColorModel: 2
%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0
%AI5_TargetResolution: 800
%AI5_NumLayers: 1
%AI9_OpenToView: -70.5 304 2 1572 1032 26 0 0 66 96 0 0 0 1 1 0 1 1 0 1
%AI5_OpenViewLayers: 7
%%PageOrigin:228 -28
%AI7_GridSettings: 144 144 144 144 1 0 0.8 0.8 0.8 0.9 0.9 0.9
%AI9_Flatten: 1
%AI12_CMSettings: 00.MS
%%EndComments

endstream
endobj
18 0 obj
<</Length 5017>>stream
-%%BoundingBox: -1 1 584 89
%%HiResBoundingBox: -0.000488 1.36328 583.0107 88.7998
%AI7_Thumbnail: 128 20 8
%%BeginData: 4872 Hex Bytes
%0000330000660000990000CC0033000033330033660033990033CC0033FF
%0066000066330066660066990066CC0066FF009900009933009966009999
%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66
%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333
%3333663333993333CC3333FF3366003366333366663366993366CC3366FF
%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99
%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033
%6600666600996600CC6600FF6633006633336633666633996633CC6633FF
%6666006666336666666666996666CC6666FF669900669933669966669999
%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33
%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF
%9933009933339933669933999933CC9933FF996600996633996666996699
%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33
%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF
%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399
%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933
%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF
%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC
%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699
%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33
%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100
%000011111111220000002200000022222222440000004400000044444444
%550000005500000055555555770000007700000077777777880000008800
%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB
%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF
%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF
%524C45FD0CFFCA8EB78EB78EB7FFCA8EB794C3C4FD72FFA1958E948E9594
%FFA1958E948E958E9BA1FD6FFFCA8EB794958EB7FFC48EB794958EB78E95
%94CAFD6DFFA1948E958E948EFFA1948E958E948E958E948EC3FD6CFFCA8E
%B794B78EB7FFC48EB794B78EB794B78EB78EBDCAFD6AFFA2948E958E9494
%FFA1948E958E948E958E948E958E95A8FD63FFC49BC39BBD9BBD8E958EB7
%8E95FFC48E958EB794958EB794958EB78EBDCBFD09FFCABD9BCBFD06FFCA
%BD9BCBFD13FFCA9BFD1EFFCAA2FD16FF9A948E948E948E958E948E9494FF
%A1948E948E958E948E958E948E958E9BFD09FFCA8E949BFD06FFA18E94A2
%FD13FF9B94A8FD1DFF8E94A8FD15FFBD8EB794B78EB794B78EB78EB7FFCA
%8EB78EB794B78EB794B78EB794B78ECAFD08FFCAB78EB7CBFD05FF94B78E
%CAFD13FFC48EFD1EFFCAA2FD16FF9B948E958E948E958E948E9594FFA195
%8E948E958E948E958E948E958E948EFD08FFCA8E9B8EC4FD04FFA1949B95
%A8FD04FFCAA1C4A2FD07FFA1C3A1FFA194A8FD04FFCA9BC3A8FD05FFA8FF
%A8C4CAFFA2FFFFC49BC4CAFFFFFFCAFFFFFFA8CAA2CAA2CAA2FFFFCBA2FF
%CAC4FD06FFC38E958EB794958EB794958EB7FFC48EB794958EB794958EB7
%94958EB794959BFD07FFA8B7A1BD94FD04FFBD9BCA8ECAFFFFFFC38E958E
%B795FD04FFCB94B7949594C38EFFFFFFCBBD8EB794959BFFFFFFA1B7A195
%8EFFCA959BBD94958EBDFFFFFFBD9BFFFFBD8E958EB78E95CAFFA195A1B7
%8EFD06FF9B948E948E958E948E958E948EFFA1948E958E948E958E948E95
%8E948E958E94A8FD06FFCA8EC4A294A2FFFFCA8EC4A294A2FFFF9B8EC4FF
%FFA19494FFFFFF9494A1FFCBC48E95A8FFCA9B8ECAFFFFA1949BFFFFC38E
%95A1CBFFCA8E94A1FFFFC38EC4FFFF949BFFFFA8CBA8FFA1949BFFFFC48E
%95A1FFCAA2CAC4CAA2BD8EB78EB794B78EB794B78EB7FFC48EB794B78EB7
%94B78EB794B78EB794B78ECAFD06FFCAB7A1FF8EC3FFFF9BB7FFCA8ECBFF
%FF8EC4FD04FFC495A1FFC495A1FD04FFC48EFFFFCA8ECBFD04FFA1B7FFFF
%A1B7CAFFFFFFCA95A2FD04FFB7A1FFFFBD9BFD06FFB794FFFFFFA1B7CAFF
%FF8E948E958E948E958E948E958E948E958E9494FFA1948E958E948E958E
%948E958E948E958E9494FD06FFCA8EC4FFC38EFFFF949BFFA194A2FFA194
%A2FD05FF8E9BFFC38EFD05FFA195CAFF9B95A2CAA2CAA8C38ECAFFC38EFD
%04FFCA8EC4FD04FF8EC4FFFF94BDFD05FF9B8ECBFFFFFFC48EFFFFFFB78E
%958EB78E958EB794958EB794958EB78E95FFC48E958EB794958EB794958E
%B794958EB78E95CAFD05FFCA95A1FFCA95A1CA8ECAFFCA8ECAFFC48EFD06
%FFBD9BFF9BB7FD05FFC48EFFFFBD8EBD95BD94BD95BDA2FFA195FD04FFA8
%B7C4FD04FF95A1FFFFBD9BFD04FFC48EC4FD04FFA1B7FFFFFF8E958E948E
%958E948E958E948E958E948E9494FFA1948E948E958E948E958E948E958E
%948E948ECAFD05FFCA8EC3FFFF9495949BFFFFA194A2FFA194A2FD05FF8E
%C3FFC38EFD05FFA194A8FF9B94A8FFFFFFA8FD04FFC48EFD04FFCA8EC4FD
%04FF8EC3FFFF949BFFFFFFCA8EBDFD05FFC38EFFFFFFB794B78EB794B78E
%B794B78EB794B78EB78EB7FFCA8EB78EB794B78EB794B78EB794B78EB794
%B7A1FD05FFCA95A1FFFFCA8EB7C4FFFFCA8ECAFFFF8EBDFD04FFA1B7C4FF
%CAB7A1FD04FFC38EFFFFCA8EC4FD08FFA1B7FD04FFCAB7C4FD04FFB7A1FF
%FFBD9BFFFFFF94BDFD06FFA1B7FFFFFF8E958E948E958E948E958E948E95
%8E948E9594FFA1958E948E958E948E958E948E958E948E958EC3FD05FFCA
%8EC3FFFFFF958EFFFFFFA195A8FFFFC48E9BA8CBA1949AFFFFFF94949BCB
%A8BD8E94A8FFFF9B8EC4CAFFA2959BFFFFC48EFD04FFCA8ECAFD04FF8EC3
%FFFF949BFFFF9B949BCAA1C4A1FFFFC38EFFFFFF9594B7949594B7949594
%B7949594B7949594BDFFC48EB7949594B7949594B7949594B7949594B7A1
%FD05FFCAB7A1FFFFFFA1C3FFFFFFCA8ECBFFFFFFC48E958EB79BFD05FF9B
%B78E959BC494FD04FFC38EB794959BFFFFFFA1B7FD04FFCA95A2FD04FFB7
%A1FFFFBD9BFFFFBD94958EB78E95CAFFA195FFFFFFCAFFA8FFCAFFA8FFCA
%FFA8FFCAFFA8FFCAFFA8FFFFFFA8FFCAFFA8FFCAFFA8FFCAFFA8FFCAFFA8
%FD07FFA8FD0BFFCAFD05FFA8CAA8FD07FFA8CAA8FD09FFA2CAA8FD05FFA8
%FD05FFCAFD05FFA8FFFFFFA8FFFFFFA8FFCAFFA8FFCAFFFFFFCAFFFFFF
%%EndData

endstream
endobj
19 0 obj
<</Length 21034>>stream
-%AI12_CompressedDatax�ݽ�Z2K�(���*
-M���**N8�����Z����ǾS�S�P=�y���u-o�.��T*���J8ԼN��]1!0l0�$�3K� ~<�ә�E��A.Ͱ���8�V�Di:�
-����*�u�#������?�#Qxq3�
E�j����� l�?�̤�UQ�rg��\���
-|.�<C
:��:����5�r<+���`�Q��L@�`:�
-���>����,òl*�r��n:���l0�c��|~V��?�h֔�=q:-��ciZ��tF�������p�w�nWC��ә9�������`�?��tE���ϣ�B���>�����<�g3�(�B$.�=��=�+�E��ď� �KT�,�'?���˰�>$��F�����|>Ϥ����?*�`4
--Y!����|>��ؠ�L.��E����@��<�D�$G��Z��T
-:���o��CQ�
f��z��i�xb�~_v>������#}�3���p>��S1��?"�2NFp1G7��c"��p6�ǥ���� ����	�3JN�+CFp|��	w!
>���s�֤A_�P ����������.��g3q�ةtF�˜]�ʨ_��)���L1��?�w�g�~>������0[Mi0B0��M����UM�'ǣ�q "��Ӄf���؛�jV蟮烙�t��# �$��c�U����e����s�ie��8O�ړΨ��Hw��agԑ����1��t�F:l����% �	nbB�Ѐx�Qg�,���3�����3wx�=�}R�(ͧ����x��5�Ҡ+��S��߁��0���bR�1����a��t�����Rg�9��!�y�a���a�??��p0����x��H�Ao(^����'h���*A,��ގ&H�^v&"�9�����t$0)c	gᛗߠ�s�g(N������,"O �:���%L�w~�`<����.�M��E�Uv�o�tPw�Ӏ�����?��>|���a���^�`�_Іw�$e��&/��{C���:�fg[��{��h���4`Qj��@��!Qa�!a��t��7Xd�8V~%3��)���!��WU������w�N�m�C��H���烹T�c�H#K^��asP�a�@�G�j��9C��s�����ۄ�l0Y��}�N����t�3b�kM��V�H��c���T�T��I����3VZw���<��I�x(�<U�m(
�]��xb�m���t��?׳Z�~Fv-�ƣ�����Y�4T<
���2K��gҌ"����A���g����p�4�+�!_��L���#I��so���8��e���X��H�Nw�l�鿡��}�oRaGo��+SRW�Y`
A���u4�_Y���´�6$����yH��߸w3�9��{�)�Jc���w�1X��(��mx�������^�qA.����c��Ѫ;�� ��G*rVf�{�b�}|��F��ű���'���,�7/�D2�}�����8z�����@��s�'b��rL�.�H�w�g.ˤ�LZV��5�v�:��O�Qɮ{���
K��~�:"�x��6O�������_6�?vc�b�Y����>4�~����:��F�������6�u�p>`VdYu�}7;L�L�����T�Uǣ��
-�uN�?&�54o��ȭ	-e�S[�P�S�W��~������p�z��3bxk�?ql�]>���x>Fbp&��ꩲm9�I�o�:�qo8�{cd��'(�Е)A=�ae��ԙ�P���X
-v;�Ψg�hR�����}0IR[[�}z�6-m{��,J���_�4Aĩ��:�%Gߗ����L��h8�E�C�\�|����y<�RQ��4�	\ƓcRsϕ����˹L�pyoNA��luF��'t�޻I�{F�M�C>b�tOk���L�~����;C���G�������Y,�Z��7�:��£�p
�A�o]M����d�6��*v��vz���ch҅�=s�ћ����6�?��B!�0˝�p�,��J��d�ȏ��ڑI��7-��d<�d��q�h>k,��������Q�v�bЖf��L��?#���Ѡ�*��J��p�@��I�&�B�����ب߀��K�k_]*�3]��R�����,`�`"����A�_"��vF`
R�b>��Xq��,�C���c���w�a_����XE��>��:5���,M�4��b��i�O�y��u<\}d��}Hm�'���}*j�Ck���Z[�Uܠv�񜤹�A�F�t.���D�3<�rh����I���bˀl�4��6*ז��R�\�6,ܔ]�Β�֡)�;��G��TA���{��I<���Fg�1�|���x��((Q���9l�`=���Tu��z���`�!up�(��H;G��V��i?D��Y���Ւ=��?P���6j@&O��?gI�`Q�!)MApތ�dT��x:�D?���;�T��Y�7�q�uP���+�;J\�g̜�SG����`����V�"�<��)��a;�4���P��4�I��q
-\��Q�6��/u�����wI�a*���Q3��~&]�;���a[�3�������V
-���7�Q�ဖ3�t�������^��V�s9wQ�OQ׺F� (z%dD�#�4"�iRJ�y�U�dK����ȑ���n�#l�"Ƶ�q����k[9��Db��Q����-��ݔ�~v�g���èfj���7���?F�L)�a*���E��H��#��A�Ϥ�	�2"�u�a�lO{b`�)���3:���fL8�����D�����2
�tޝ:�#H8�}�K�~1��ˇَ뙽4vs'��(�8�z��-�|�|38�|���H����l<��v��Q�4���������we�1)��ݡ(�
]��V��n[�,�rO�s�S����M��HN���!=)�NR��Ͷ4uxd�+,��>�\:!���'��L���'��F�\$�(m#�f?��Y�Q&�P�Pߓ��=3�4���dЅ!��S����_[��>���ag��E�!0��	�0�W�%uqb�؇���ljh��:��a�Q���s�J3�m��L{���v��L�=�;l�;���V�(���Ӎ҇
-˱ͧ�;��x�&�$zC����9{&���D��	Kw�9���oo<�3��s�����ф�?��mNZ��Y��/N#�a��;(y�7��`��W����T�O;Nj�!��,M��6R�F����v��hN��T D$k��k���T�u�D�0���,�"�Q�{?M*L�Ϭ���t�\���$���t6T����Q�chc™�� �����>H����
-(tC���.f����D�8�v75
�uSHܘ�̓�� �.|�ĿD�ZgN��Ս�d⨚ ���d���.b���^��/ TG����ڐ�׍�~��P��o�Q�\������p��Xѽ���u�	e]!?v��@�a�:���a;T�����Z"���89?>/���������]��4�4��Hj�ޝ�$�Һ�9��8T�ʁn�9�Łf�Y��o��r���<�D��_b|:c��T�0Pַ�AmךG���t6)'zÁ����F��J�ןs�2U��|�V�����0"9�ij���H"��r�1��Pi�3�KX�NMtr���`�`H��07��t�G��C��X�9Km�K�S�{I�Ҕ������Ӽ`5���=�'��l<�>��h;1�N���d~���]4n��_��ӽ]<e�ה����|��Qw�z$�����,[�#=����ϝJG��;s+}<���$��r֑uV�ݰG=i������BQ1��i�}X�����S�|B_��„٧TԮ�T�"���8
-N;!��yQK�,ؙ��Jz��B1AX�$�5�3�'�0��QPD����3�C
-Q<ȴ��������>����?(�3���ɱ�y�u�xTƖ�F�6�Y{58~������eD3ި�{�`bU��-��ʟ�3�:�B�@_���#��-gb���ً��i���ng�M:�7p���̼*	֫��Y�L�����34��>L�+�Ё<*��:3��s��uC'�a��=�MU��tw7�����ч���;�qQ�zleǎ�i-jG��.nlTx�
�Mm��G�r�Ȏh���n�_�悳���yoP�:���9v���̬�!�֟0՘؃�����r��謞���g��@�;��B"57<�U�f�Y����_��
-�wd�ر�����(P/�K*�]���ޑO��{t]:>Υ�"��jl?�����I6;��>g�ħv/���R��_�7�b�=_���_�u���þ����]e>CQ��J$���Pl�{7=̇�x��΄b��u(~v_%�3�M�=D0�t��LM��t���:�x��9!�y��<�&ު������l�-�aI����'�'����~��{�TǏ�VEz~dˏՇ����^��>ʎ,†�����IR*o���D.�1�hT9������Pt�=Eg�Z�Z*~�>�#�Gx���Ɨ>�@iz�*�[�keS#&9������+|�
���CYFc*I;Ӗ�<̝��ԵLT�N���px���&�)q�ϛ�R�>d�Fnۯ�6���HS��
�����6!Uǒ�����'�-���c����>�&��뭇&`�����~��tb�4��K�R�f��[��iR��M=<��b���Z�+�1v�vH��{�NE�ɧ*xUڌ5��gk5��~���[�t�Es�[�t맠 mnma��2���J~b���݊qV���r���F���zI͘ۄ=�I�$6�Ցf�ٝuҞ����푞W��3�3i ����O�U��?�푦������-ҵj'�В�zzY� ͬ�ӹ��C���ont�0mmco�!~��"�]�Zԑn&B�2����aѬE���a|��n[�Zo��+5;1#m��(H�H�i�yԑ��c},���ˬ=��y�����"��u*�@������ǚz��׍߹=�S�Q��l���u�0/F��g��7�2�b_��H���~{{�)H���ޔ:�VDlOhH�ػ�A����;�I%�46��1~�JE��v�(R�>gؗ�[�)������>������ME:"4�g�[�Q�H����-�v?�<�C*I�uiW��M,�]d���YMG����PA�%��[�^�E~_+���tO2�4��C\A���6!
�?��c��0_|���⊭�?�҄U�'ԝ�43��R�bd��J\G
-299Mn�c�T6
-�S�(c{��'�4iE�	��=���$dB��)���%c��x��-#=�m4�[9���s��7���,�o��O�/����ڎ��7CB�gb��T�~Z�������X���^T���m�q�m
-<~k��l�� E{{�6���6�y_b�Bw9گ+�E������^��g����g�[�!ʯ����,B{�foC������e�*ﭒ�ζnC{�[�BCoO��G�����m�T�Yߟ�w�J���&���}���b_��Mou�=gٗ��8���y��vG��=dۙv��-�X���4�}'����3���:W�|���^s��k'T�����7?�����N7�ߦ_G7;��G��i3�=�:U,�Hݰ��G!�~�/�5K>~6��N��ߦ�� av��K��������ؾR,>�h��H�&VO�e鵿7	�Y�Y,*��d�a)(I\�09�*Uo�ظ,?Vvx�VKE�W*��1���D��[x�z#�������O~ds�v2|��f�,7��~���ﻚͺ��u���*`��a-��[{̈́j�\��}�VE������HS�t�k�~҄v1
-[�)^R��b|18�А�9 �%�}�����#����TC*�����Ǝ��64�w-B"M]o�:Zi��1T���(H�����i��	[I$Z�x*Rl;P�"ˡ�#��Њt����{:R��P�#��M�eV�q=���y���0J�OS�
o��M��X�od�"�ҭ��N�z*)�߹*b�O.*e���o����I�E�P<Dr=��F���on�Q��.}H
-&��$�?h:���B�OY�U�H�wr�8�j�M��V�t�˺�o��A�2Wy��d?�2`������'~6��#���8�GX2��{1�)�������{��)�	�K�J\��Г#���*}����2>l�ێ��LJ�J��?W�	d3�c���_{��$��Edr}�L�M��|}�wb>�Eg���	��!qbw{f�=L�9K�+���žsk(�Lw���������a��̋;����[D�C|b@����~f���Q#@h]6���&�Jڪ|�Ϩ�Q:��Qh���6��<�L�����R6|l�v��6<-6
�0�ĺ���?b��ܟDw'�4�5a�v��jS�=��VXq�}�<���l�x�Z{>��n�tu��`���U�Mߥa,��6����ɲ}c�;���"vd��&�u��=��n�t~�O����=�]�,��$�c9hܩ�/�">dd<eB�����0>�4��#�Kز z���}/1O�A^\�ia���3NI��2%�9�y�s=�.����6&[�Ѩ1�[3IU�*�����׸��V݃��k���*"V>�F��nĹK��N�����}�4m������W��a�z~o8*�.:?9�.*���Cr�Ӿ]
0V�[v���f�P��EHK������Q�E��3��B�qe3I4�S<[�f��k2\���+U��c]7�����u�F���o�ut:Sw�c��m�+����V�*���ԏ����G=6vNKQ����S��xv#��B>��mk��	x銛p�:}�o�Kӄ��qGa�mX��ߢf�S����2�G�����ܘ���$p�tw6����@�����a�a^����A[ _�&��h�v�ХٺW`���,���,�������b[vヱ�&���`���X��F�=��g�v񫺂�M?y]������`�Ԟ���#���#����Vb�\�b8��b�%�sb\�#�ջ$l�ּxH}	?'v��%K�(Z��n�w�,ڑ�֒n���usFZ���C����˸7�XZ�d�S	����0M's�D���!�D��?�_sb���9y���`T�
-͙I�n�!��EGe�:�S_>3M�����sv�5a�6x��Ae�trnzЄ'��mp��rp�]��1'ON�۟Go4��ːq�#;s��wR
-��N-���b��P���a�VG�eu���>���ڬ�V��׷��X�T�g��1���U��^�|�U��C�%y���U��ou\/���y�y��h�p���ѬE#&(�g|�p�}���LÉ�dT������<�|��&:1F۾E�V���f�]�0�ݵ�v��e8��v�G%e��r0(�N
L�t�$��Y����NF\4��ۥ%�P+}i�N
@�H49"��	�%��5%��^�� ~{k��@�1W8^d�3���E|��&I5�%>���\d�l�LX��HH9:D���b�]���T�ͳm�g^&�K�U	^SϞ=jf�-]Ȫ{����]���ٖ��;1������ٚ��J�Y35Q%�+�jO�b�+58ˆ@�P4�����������f���Z�	O�l���y7�5<�4.V5����V��?ӣ4m��n��{����E����9��ҫ��:kg+����΀8[:����#c���p���y/��0�Z��n�"(�ڼ">�J`	:�4S�}��)=�*�
-�9�I�Y���70�t�~~�����mG����5R,�<��nU4�-/Z���)a��;����t�.a�[�//;#�/�?$Lے)r‹?�j�=8mKd��1��5�����fG���e�ü���k��v�_�7�{���Ň�M?*�9����g�
-��ػS��[�����Kt��yq)�b����]Sm۲�28[n��6lu�����R�o�Vo���A�&�.�AGd-�CGQY3��[�ɡsΠӳ�ˡ#��d���K��9gБق���9g�9d�ʡsΠ#��ɡsΠ3f.�C�A'�b���9g�!N^E�s�<9tƀd��7�/�����u��_]���N�n����s9��l��/�T6j����斯Xr��S��bZ�Nj^�9��if0������������aQ�g��9�y|f��Do;���]����r��Ĩ'�M��!k^+(�iI�!t�b�
-"[�A*˜͑����*��ih�Q7��n~CAl�}����clP��f%�%�y�JK �M0�Bf�d�Z^B����ؤB`W�K�7����n�I������Dئ����9�0�r�!$���5�I(�3��i�q�����R1Fw,��F�و�4Oy`���:�#��u�+��!�Ϡy���m�N+zj�HM�1��.1�5���+ͳ�2J�[��<>�q2��G�Ƀ��8"��%��k���ܢ�����-~��O/��K��?�	�3:~��%
�N8��%{Ɠ.[7�|�C�b��/� -(м�{xus����ng����z0�f.���0f�6��0؟�6W��Wm�i4qK������-'#f5��v�׾+9<�h�q�,9��F�\ЀR�YbG��S(�,��b_�3;�9VF=��ɰu�r[D	��%A�E��3��D�c_���/���t�\��t�:���q�3����J�,��g�v#�m�|yd��""V�ON��.o���1YIF�����A)I�xdt�9Y�##l"vv)a<�
'�=2T{��di�-�GwxOC��q�O	��-�AIh�)#u�̉�L�[~�#�)9G�au|��8FI$Mʲ�c咇�IY>�H��I,\�L"�6��\	�Y���
;�#gi1����ʟ�?fϡ�C���P肇lA׼:w!�W�%�q���G����:4���i���2r�|�
-���@Dv�>,�g��Ԍ�U��-{���|87[M>�|��9#�?�|8�����z2���|8�AW��
���+ȇ#+�,����1�挸U��Q�8W��l�юuj��
-2���K�9&@q�tK1��_��z_{8��U�H��U��%2��	/�c4�]{c��p�α�P�EH��!���g��v1�"�A��6/��sə�r\��e��ԥ����}�����[���.Ǩ��[���I��x�.��7��Vs0��v�����mw��J�a���oӢ�Y�,W�݆s���g�*B�|Ԕ�����c��[eF��*3R�V�������Tn-���T����Tg��Te�({��hS\5�å�����s@@X�a[Zگ%K"n��T8r��c�W���.�U���RI��GR��+}���� Ze*���t*�C��y/�h�u�T��5XBxK|2H����J��_���_�&S���ȷ�kf��-��<�/v?\�f��$6G8N��"Q��[-��=���%�M�F� ���cPu���o���G�E�\mdC�ϯkT�����������P�kT@�&�}s�A���e)�8m����wVٌ���d�U���\���Eؕ�d�f�%�l�;�nm����d�Hw�ꛖa��>;%��&�HqQm
-��:N��gؽ:%���t�����T�����^��]^HM��P�ij�]�s��n{BK{pJv�`MH���^����w�ե!�8 ���z|'�T�����-��q�����iV�rM`�����7�{jw�.czi-�.�B J��7y7���j�1u�¯�ӆ��;v��h���s��٣�Pj�\�jBu<�{M�u�m�j��\�S{\k�X��|}�U�3vin��_U%9����kn�-�
�{z���Gq}���%�ܽp>��Q��^�ͭ؈���ݥ�p
-��:#^��R���za��gOt"}��t�ŷ�l:;�§�C6��`�[*��.���~��tv>�@x��tv�th��6�Ύs+Ϧ�z�W�MgH��o�tn1��ɦ�;��?{]&��8�r.�dd�l:���Ug��sFV�M��%���{-���Tt�l:��(`p�"�ήK�i�����r�l*�,�Mg7ڝ�+˦����0��.��&gd�l�E)�/�΅b+ʦ�˥�I1�tv�t��%���4Osn���tv�X7a�tv�%خ\i6������`6��<SOFΦ#gH=Zq�_̦��+��X0�� ��J�3�ͦ�qM)E�Z������%y'RvU1���>|c�p[㢉O��¨]��^��v��zu�6���otr�lK0)�(��¹&�{ct�[%�moS�I�lm#흪˹����%�u��r��%���(a��.a�����N-��Ed�>2;�(ղ����Y��Ŵx�*��2w/���a߅[�;��t+�={�2wd'�Н�4%J�;�����zͅ�|�*Y��Yn�+t�@��D-�E�:]a���t5�u�y)\.��s���EB�&������Fs�t��Sj�9Rŵ@=��kV�M���-��&뉓�� ш�PF�x�����|�� ׼��.��t�h��#�#
-�����¹�K���K �����`(��f�=���Q#���V�
-������c`��=T`7'�~�Kb��z��=��K�T��F��Ft�mOŒػ���aR����t�ښ5��%_z�\%Ӌ�d�Y,3�v�oWW��֔Ȱ��o�}������2��1����o	��,V��`� 8!C�bUa��$2,q���u�3�D�<�T��ͯl-�	P��[�V�Λ6�l�;"�ѶƝ��J���*���'�T�[v�*�9���!?�[���9�v�
-w^o5�=�.�؅ni��\n��X˭�ڍ�݃�k�5Uҩ�������G5�}�{�0O�,�+g��Z��'��9�w��J?���O��HƜ�d
�A�[����_˾��2���t�O����}�S�Z��S���j��O�f��~U�o��C�=��WcW�%g�lWR��B�q�etUM^�c�_Ű+������U�݆������Jy~s\K=�N�{�2–���B���{�N�X��j:L��z�5=Vʻo{�J;K��VV���tw��W}���F���hL%��m�J��I�e�ݠ?��X�9Ai}%������6u�&�)��iҔK:R���:lk|!o����I͇��o=	����s1��Mu=-K��)��3�/�ܿ��k*�M�ݣ!�SS��i�xM�՘�6]�i�p����Ə6RS>\�H��j���H�j�=� ͬo\��vHa4V��õ�4EGZ����H��H�S�\���'��-*Riz��C˹�/�ì�y=��LD�������u�3"%�ef���r�
-1���M���#�ҩGDD~,^��\�oQ�F�!lR��m΃��+)BPF�V�xb�2�P�Π��U1��)���փ.R�üU�����M�\��,�=IOe�"(z$�3���V�d�mS�+Yi�M�=����g�5���5&�k��ݎ��{֝K4[�G����\/;U���Xcc����e����*L���u�}���2�-�*�-�P��֕���<$֗��UVqo#�TW���Z�z��w���ra��@��bnVK�1J˓�4�Y�v����J�Nuu6rWX�2��;kg���D����
-��p�ꠑ3�yU�ssY�����ȷиf���F������~�Ys�H�����er��.���2,-��m�{<h㤦dqx�M$��t�h���9�ӵ�e�h�=�9�5Q�33Hj�yF�W�����(���b��s�QO.��CB�%]�p»`�W��X+�o�qU�smn��h�=�T�g��@E�SM �l��|dRD�%бF�k���B�U�H��%�)NJJ���md�Y�^s�6�ŭ��*ʷ`E6�E���+-���UXQQ��w��DQ>��������E+�y-ʧz��٢|��P��٢|��W.R��֫�:%��ĺ�����Ȫ~d�U�
e_��w&���wC-P׏:��
���[&N�{]?笻�
���-7���~��+���S�Εa�����w��{P�5�������Z����#�U�̑*���s�c�Ju����-]D���<������E�����s!�@�G̙C]?�իj���#�u��7:�>�p]?C�����7P��9�NVT��=�cu�������G���ߢu��P�U�(7����G'�������,ǖ��瘞���W�%F��g�{]����9
��WQ��9����곮-�8MX2�������ѩ�����L]?��l��-X���-�z|��=U���渥�ަ#bOѶ��9�j���2\����}z]����i)W���dƐ��#k]?w9���~�U�VS��-H�k=��/�ѭ���S�����no���s-�G�0��sJ�x�������ٲ�V�o٬4ojq^�T]?g5�Ȭ_���Nm�,�E����¥��[֛e��\=>�Y�1W6u�M�Wr���gX���~�
-����l�U�d9�|]?�@'�������ٮPle9O�U���-�3��[خ�U׏&�~+�,9W�3�6�p]?�~���POg[0!�vG^���sU?}�{B�cU?£�T]�t���Qg�xήu���%�r��~Λ򎚷qf���}sP�Kć��Ut����4�vᙃ�w�7�-�l��&&LN��/{��jlD��	h)P��QI�'�2F�Œ$�_
��ݓ#.ww�o���q�OU��4;R(��!GPh��b���b;�������C�f�=f+��$[�J����H��x�`k���8>o�����b(~��gB��9�����;�bgC���7g������/ݵ�����m_	3�M��b��"��$U���y�#͹Q+���\d���D*���vn%��E�<�~�zy�mo����a1ܼ��l~~���������>N�7/�_���m504�OR�oxJp�Y :��܄�
�O�c[���/�NQ:i#�(>���J�B�D,L*�X���r�ٷ�ר$�'b�X-#ME�c���![-���{]��L�_3]��R���Vb{��'6Ym���K��ʶq�?6y!�Mʖq�J��E~t+14}���}9�v3�=O�ɭʸ-�6ʹd(=<D�NB�˵s�v{�^�GB??�����a��ߜ��r�L>����]�v�Ҡ��иڇ;���'�Z��r��z��?>��S���l�{���6�?3��0I�	ň��K܆_ԣ2����^/���I��	�k#��)0����l2}���ӣӻ�������lT�G���,ī�FiO}UJ�/������8�����H}q�i/^a��C6Y����zJ⮕�zss�zǷa+{���(�2��Ë+I�W?���۱r<<�F���\�#�`�]�1���F��� �YY �{j���
���1��KN���-��Ow���<��M���$����� ,;����8d>�����F��8t�[�'�d�����"�Wwe[l�`/{�bz�����c���z�1�<��,!����h^�@M=T���UPY�&E��|�����N�O�|YB!wI�������G�8E%O���;F��SJQ�����Gb�WE��T��j�8ܛ@X���:P��(}+o(K��+���1#6��c��u��G_w���_�)��p��L�6�FG*lF/Q_���J�}�O<���#���T9f��e���P*�r�j�r�ʑrSQJ�~�����0�%-wѧ��@���Ʌ��4Nn��ѢaG�m���z�ڻ�F��(�y��{G�P�,!�U:�v���HI��\�T�~�h���"��$_N<��X�{quV���e�J���	�*FE����$�E���R�B �R\���S$RP�^#�U^�O��\�C��Tf]�
����1��)<����pmT�ǟ*ϞG/�,�j�5��a�����,Wy>��ժ	YFn�]���F�MwO�x8�I��3
6��I�i���1���'�V�g��>����Y����Ÿ�b��|�-l�˅@��.Ə+wE�����ۄ��u5��ޯ�7����������w&%�@ޮ�L�]��I�4M�,��dg66��B��� �������s��p��Gɣ���`Z-�����@U٦��u���Y��i%6x�<�i�I;b^�1���֯�Ng�����u!����U���R��qi¬W.���/3��]�={�wN��|7�۟o�,�-�@@�H��(�:T�1���>
-Ŝ�ˬW@mqP��D.�1c������悘wN7���Zm���,��$�=��ܱ��^
�Ͷ�T��e�?�+]@;܃e����x幊���4��4��M鰵u�{8�K�v��~t��"�6���+�����2��ʰ*��L�Q[������?�aŮ�˽��C_p�����W�h����p$���ތ�b��؉Q�b#Hww���Sk��n��|pzTO�$���b���+�^�"�^w��ڰu�M����t�ǧp����nZ��(��	�T*~o���LvkJe>�b��W-�`� W�`9<�@�ÀUF�l���}%����W�X[l���c��
=�5�<���A��Rb��n�c�
Ŵ�����b.`Y\i�Lh�6`��f�R�e5�L]WK�'mM�Ŝ�
-v�u~''�,��?�s_,W��*�u¡�v�%�+�Ȧk ��^%$d�]��1h%r��Pt0�%F����,6��H{A��mɗy�����s	¸f��Q�y�R-��oG7;_���S�f#�v�{Pe4��>���HB0yӘ+n
-�x�:�;�9�	U�2������uk��W�|��}����.3WoR�}o����Z���	����[Y �u�՞<R�Y,Lo�c�'4%�l�W�?8�$�J���;�/a��ׅ-����p��fg�{��|1����1�g������<�-4�3���{��Ak�g���v
�K#��S�P��?A_Y��C���#�����A.Bѷ�\(�z����|��?��,*Tqk2V���������/̕�[��p��|�Wv�r�j�Z��������
����ႄim��;c`Yb��Xo�����e�}s���.�����B���Bmld?�kAn�}-�1�o^�ׂ�+�ri�<��.�����__��1㻠�/��0ޗ���B4�_�s@9�UVe�Ȱ|��p~���G���j� �>9��[����娞y;?|���T������ʕ���J�`�"To�ή?��c�Y�[Ơ]���n���7��w`W.t��y��ǫ�]��Lբ����h�����*,Gg*^���a�8�����c':b���iJ���W}�n������E6���@�K�*v�(�m���g�E���cJT`�36K��Q@A�:��9�Ӟ������nn�^=�6�����BEv���M����N{Tm��G�Η���x�:
�--��Y�۶"�A�)��!љ\�1�)��y�#�R�;��h4�������]^����/�[.0�xڑw��x�S�UO<�v���ى���x��+������iW�c���[4Xlj�U{���?�͐��P,b��1c��p���CA�n+����"�=�b�Cb��L��*�l�t���4��x�X�(	 >���<�����������?[[�?����x�=��j5�`ŵt� ��oi "�3�g��*�;	as����j���(�������˴�BI��j�`{��aGՍ�2>/:[�vzg(�q�T�GΏP��}x�����(:?~�<�@GS5x�;6R�e��C��Ӧ�*���ź�{n<{�����1�FM��Y���+K.��ֵ�u��Ge���	�u���ӅF�{#b�$����$(=�_U�L�e%ݫ@%��A���/����@	�J�yJ�$�5�,D@�I����V���9�|���>4NV��A*><�D�t7��)|�T�ވ�Q4&	��G�������D��"�׃^/)_v	*rU:�`q;Pr�a�&�2���Ɏ 8g���@x���� v�����,�P���l��>8�g
-ۂ`<̆px�(:FK�1U��ŕx�Ap^(���y@f/.EZN�j�%C���rc$�4��r?���	���\V�$T�ʦI/��@��R'�xl�a��:v<��\�I�ˎ\O흕b2i?-@�Hӎ���)��[��)�<� G�;2oVo�
-.�.u�vdlr�eu8�Sd�R��=|��==��Z�Uv.���#�|�ޏ#�2!�%�D$�kFID�]c0X5O>��-�d:�_�D�t'+n)�8�ÄC�8�,l���YM﯇jR�)��8;z�^�	��R�����/n�~ ��b�W{���xa�7�ͧZc��=���h���'�W���s-+%���z�! +"��d�p[K|j��<�Y�e(��!S>��m���`4/�ȗǷ$��[�FΤM6�����7Z�71"m��ɀQ���sX�T,�%������n>F[���J����$S��;��F^�jW�8C�ﹲ�cpQDOr��\�z�%ޔ��{!���p�i9�<�v:l�+������!�~���@�,0l�6��#w�Y��8�§'NI�����c���O��'���+1��U���I���O���UO��[�}�7�}�x��x)�og�a5-�'�H�@F|���>3Ջ�0��#‘P� �w�����dS�Qc��{=ᮧ����_�#�é����RYij���7�Y����ɶkgշ�p^�Ӭe���=�i���GX4m���z�4�_$F
-�&�`DŽ�ϸ����<q��<q�
i�3�:�(b��} �8�2�=N�g��<�bX�
-;��K턃���NـzE]���禴r�c�{1�˧J"6�'4�S��V���}�7�7X5c�#s��Z�7��q��ʶ6��,����������D��ِ���/9�����]��!���r��������<��B&���E�B|F�x`'�<:��Q\�D�F�Ϭ<����,X&��K�ǹtY��b�O��lWz��-y��!�N��.��k�����N��}�7G�E������K��ʇX���'
-�cB�y�\�C	���Lgw��~��<�&ު����I�"I�c�{���������S?�Z���-?Vn�{G{=<���Ky�p�m�TA��+�����P$�Y��wP�qF�i:�#'���iv�î�f25��l�<�Bgk�!-����6f���!�~���ڎ�V��)"�q���j�S�qFr\
H�E�3��I-���դ��~*B\�`�)&V�����H�jH-&��a�9��Z+0Qs�0f����]���+.K(���v��}:�l̵[�9r;j�J��rET4��:�����J���������^��?u9��G_�e��^F�r/�U���c<�1򚉇f�-�,�-��*i/^�-K��۽B��vs���=����d�����
-���7ڻ�.9�����6�^ �}�+FV	*�����֒�=%��?
-u�w�I���GZ����[)z�Zn��v�y��w�'��hר|�����X�j��e���?JB�����%�q���j>��h[�Ty>�ɟ�~�>��/>�*��d���{xz
-���}����]�p��z~��կl���τKs���=���Ԯ�/�H�xvR���ar��+,sC�eBݘv���m)��(sUETs�����X �J�ש|w�`����]3U��a��m�!|�nq���},u�aX,�K
QAO�3eii�x�ծ:�$.8�R�̶ƨ,j)<Q����z��]�`4�&%V���t�
L��x�m��;�/lx��
-���`"%IQDE�ծ�X�v��C�d����g�w��9�Lo��״v�wisޗ��}j��f/wj>2�"S
D�"�]�1p��>I�M�.1�#��z(\��BZ{����z��5N��B�rH�������m�7Ry��P��~�gRrp1���9V~
+G��ꙸ�jw��J����@N��(�a�;��J2�8�+u^:��O�u"r��$�	�r&�H�zC�W6�Ip(`=Y%��(DH%u"��|���Ig�G*	���H� �ț�˂��`�ל-x,�^(�x�v�i�JȀ�P(aVn ���e��$ح�ˬ|�s�C�i�H|)R���@��.3�F��Ї@��r�~�d�0����[�}u;�m�����^A��϶��0HS���������X���[.a�Ne�$g��{����\����T�>���Uˬ
�B��!���%6�99l�V/� 2����hW+�F�v�/N�Xf=�:/��-kۮ<�4��m��:�J����#J�Mk)3��[����D=��:���a��r5�X=Qe�F=��(<�u���x�>H���RPO͘�]rG溯aw�r�C�#��Aݑi�P@L8Le�`�mdK��^b�q&%ڑW/SZH�`#;�EpP��*MA�\�;���W�@<�R��$�����]�Ȼ����BL�V�f��M.ų��n�'��S:�'���$�	՟U���<�������F�W��vHwJ��ƣ��yJ��n j/�F+����=���yN�?�������GG}���$X���1�9�xG����Vru+��ty���[5[��c5@:&���.�^ lwe�/lU��tekl��l�l]����+Ƶ��_ت�&��l�xakQ?�V�d���(B�ڎb�Ŗ�	����F�_�;�zR�yה�9G�+n�hobG�)���B�W�H&p=�Faɵ$��/�+����x�-��ó���aI]v��/ �b��R������RB�̽L�����Ap����C�0�q��q�����Q��D��(n���ݡ�}�����s��;�0:	lWF}�0Ókq6���vQ���?����,���f�A���t����F7�m�\4����4+z��xԑ����Y���,�mh��@o�6��WQt�؆�l����;0�.,ñ\>ؙ|.��������V���|9�_��� �ςO/l����
-$X�e�Tz��|�����Y�6|�ɱ�`�$�
��L�e9�\����9x�� �y�'*ֆMO��@^`��|F��O�Kq��eu`�Pi�<�qY^�3)�a>X���O��(�αL�M�B��ee:�aR���=Jg9�PHCWr�`:�gX
ȓO�y��=�Q�3<���g6�R)�P���C�GB�Ies���@2�l���5��,#�Y�Y�asP#'0,�f��'��#��N�gx�O�Gi.
C�qL*������QJA&����C"qy&�����G��|�£��t^����A�(�|��� �IWr�l:��|:���]�y�w��C��<9$}��v�#��m��L.�A|���F 0|�x�fa}e�Bz��Y�A�I�`/�?�)���ryDE�<��q����ph�A�T �w��H�
-D�iD�5R�Q�O�Q�g�,��i���9~��E�e@��d
-�"����;�A/����s�MF`2�4<�	r����r��`3"�#�>)d�0;�}
-���<Fe�{`x��E��v`[>ϡ%�e`��@ppB&�=�1�S6����`0i�:R,��pY��BcP=6��)�@��@ey>�=J	)&���+��da��K{D��a$yxk󈠐�C�G��J�l�0ߚ�B���2��J�2L:l��.�.�R�6�qiMv�����������%�f�����,$<��bI��&P��Ұ4�,�C�ъŋN�{�Aӓ���`��h�f��3��1x`�|:�&[e� ���#�y؈_���)����<L����$�_�K�\+�Rt�`w�"�����!�EP�����@p�r���@����X��A�g�`��q������9��^N�M�Z ���f�\
-d%�6�py�i�2�"�ʀ&��C�$+lN����.	��H�R��!��
Tm�0��>>��`�ƒ�@;L� ��a���z�:�,i`��'��aJ�*���65�A"P��<⍔�=@��r9^{��,��p<��B���dE���Ve�+W*��菀Ks|
-��) n
-q��J�a��|�V� �F�0��Z�B*�CB]�����y<���PAhL��љu%���&
҂��0@U4u@*?��1�F���g�v��h��6��`�HALȴ,=`
p��lY�/��_i��r�D�,(=��m�
�泠i����<��Q�����G�s��hm�ު{�� �aM�dSid&V&�� �Av�s]v�s�������C{āB�!�U��S�""�q~.�?S�*�!��G� S�h�5���̶�\�%4�,��A��G<,q�3t�N:��#U���
�:+*"b�@
-`�M�Wk�
-�9R��
��]ӈz�����H4xhe{�gl�&`J7;���z��v����h<���	�	~H�t6����s�7z?Q��~Q
�_��
endstream
endobj
6 0 obj
[5 0 R]
endobj
20 0 obj
<</CreationDate(D:20110328132859+11'00')/Creator(Adobe Illustrator CS5)/ModDate(D:20110328132859+11'00')/Producer(Adobe PDF library 9.90)/Title(Modernizr 2 Logo)>>
endobj
xref
0 21
0000000000 65535 f
-0000000016 00000 n
-0000000144 00000 n
-0000018316 00000 n
-0000000000 00000 f
-0000020771 00000 n
-0000048490 00000 n
-0000018367 00000 n
-0000018703 00000 n
-0000021070 00000 n
-0000020957 00000 n
-0000019852 00000 n
-0000020210 00000 n
-0000020258 00000 n
-0000020841 00000 n
-0000020872 00000 n
-0000021143 00000 n
-0000021317 00000 n
-0000022336 00000 n
-0000027404 00000 n
-0000048513 00000 n
-trailer
<</Size 21/Root 1 0 R/Info 20 0 R/ID[<8D44613111B047A982BB568568FC0997><DE399FA33D7D4432BF16917DBD7AD64E>]>>
startxref
48693
%%EOF
\ No newline at end of file
diff --git a/media/Modernizr 2 Logo.eps b/media/Modernizr 2 Logo.eps
deleted file mode 100644
index 31ae492..0000000
Binary files a/media/Modernizr 2 Logo.eps and /dev/null differ
diff --git a/media/Modernizr 2 Logo.pdf b/media/Modernizr 2 Logo.pdf
deleted file mode 100644
index 60874e0..0000000
--- a/media/Modernizr 2 Logo.pdf	
+++ /dev/null
@@ -1,291 +0,0 @@
-%PDF-1.5
%����
-1 0 obj
<</Metadata 2 0 R/OCProperties<</D<</ON[5 0 R]/Order 6 0 R/RBGroups[]>>/OCGs[5 0 R]>>/Pages 3 0 R/Type/Catalog>>
endobj
2 0 obj
<</Length 18095/Subtype/XML/Type/Metadata>>stream
-<?xpacket begin="" id="W5M0MpCehiHzreSzNTczkc9d"?>
-<x:xmpmeta xmlns:x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.0-c060 61.134777, 2010/02/12-17:32:00        ">
-   <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
-      <rdf:Description rdf:about=""
-            xmlns:xmp="http://ns.adobe.com/xap/1.0/"
-            xmlns:xmpGImg="http://ns.adobe.com/xap/1.0/g/img/">
-         <xmp:CreatorTool>Adobe Illustrator CS5</xmp:CreatorTool>
-         <xmp:CreateDate>2011-03-28T13:28:59+11:00</xmp:CreateDate>
-         <xmp:MetadataDate>2011-03-28T13:28:59+11:00</xmp:MetadataDate>
-         <xmp:ModifyDate>2011-03-28T13:28:59+11:00</xmp:ModifyDate>
-         <xmp:Thumbnails>
-            <rdf:Alt>
-               <rdf:li rdf:parseType="Resource">
-                  <xmpGImg:width>256</xmpGImg:width>
-                  <xmpGImg:height>40</xmpGImg:height>
-                  <xmpGImg:format>JPEG</xmpGImg:format>
-                  <xmpGImg:image>/9j/4AAQSkZJRgABAgEBLAEsAAD/7QAsUGhvdG9zaG9wIDMuMAA4QklNA+0AAAAAABABLAAAAAEA&#xA;AQEsAAAAAQAB/+4ADkFkb2JlAGTAAAAAAf/bAIQABgQEBAUEBgUFBgkGBQYJCwgGBggLDAoKCwoK&#xA;DBAMDAwMDAwQDA4PEA8ODBMTFBQTExwbGxscHx8fHx8fHx8fHwEHBwcNDA0YEBAYGhURFRofHx8f&#xA;Hx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8fHx8f/8AAEQgAKAEAAwER&#xA;AAIRAQMRAf/EAaIAAAAHAQEBAQEAAAAAAAAAAAQFAwIGAQAHCAkKCwEAAgIDAQEBAQEAAAAAAAAA&#xA;AQACAwQFBgcICQoLEAACAQMDAgQCBgcDBAIGAnMBAgMRBAAFIRIxQVEGE2EicYEUMpGhBxWxQiPB&#xA;UtHhMxZi8CRygvElQzRTkqKyY3PCNUQnk6OzNhdUZHTD0uIIJoMJChgZhJRFRqS0VtNVKBry4/PE&#xA;1OT0ZXWFlaW1xdXl9WZ2hpamtsbW5vY3R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo+Ck5SVlpeYmZ&#xA;qbnJ2en5KjpKWmp6ipqqusra6voRAAICAQIDBQUEBQYECAMDbQEAAhEDBCESMUEFURNhIgZxgZEy&#xA;obHwFMHR4SNCFVJicvEzJDRDghaSUyWiY7LCB3PSNeJEgxdUkwgJChgZJjZFGidkdFU38qOzwygp&#xA;0+PzhJSktMTU5PRldYWVpbXF1eX1RlZmdoaWprbG1ub2R1dnd4eXp7fH1+f3OEhYaHiImKi4yNjo&#xA;+DlJWWl5iZmpucnZ6fkqOkpaanqKmqq6ytrq+v/aAAwDAQACEQMRAD8A9U4q7FXYq+TfzF/5TvXf&#xA;+YyX/iWZmL6Q+o9k/wCK4/6oTP8AJn/yZWj/APRz/wBQsuOX6S4/b/8Aic/83/dBJ/OU00PnfX3h&#xA;do3GpXdGQlT/AH79xhiLiHK0EQdNjBF+iP8AuQitE/M3zvo7L9W1WaWJf90XJ9eMjwpJyKj/AFSM&#xA;BxRLVqOx9Nl5wAPeNvueu+Svzz0fVpEstcjXTL1zxScEm2c+5O8Z/wBao98oniIeV7Q9nMmIcWI8&#xA;cft/b+NnqAIIBBqDuCOlMqebdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdirsVdi&#xA;rsVdirsVYv588+Wfk+ztbm5tZLpbqRolWJlUgqvKp5ZKMTI0HZdm9my1cjGJAoML/wChi9E/6tFz&#xA;/wAHHlngF3H+hXL/AD4/a8a8z6tFrHmHUNUijaKO9neZY2ILKHNaGmZEI0Keu0eA4sMYHcxFMi/J&#xA;n/yZWj/9HP8A1Cy5HL9JcDt//E5/5v8Augknnf8A5TTX/wDtpXf/ACffJQ5BzOzv8Wx/1I/cEkyT&#xA;mOxV6r+Un5qz6Vcw6FrcxfSZSEtbhzU27E7Asf8AdZ/4X5ZRlx9Q8x252KMgOXEPWOY7/wBv3voD&#xA;ruMxnhXYqwvz7+Z1h5Ou7W2urKW6a6jaRWiZVACtxoeWThAy5O37N7Inq4kxkBw97KNH1S11bSrT&#xA;U7U1t7yJJo/EBhWh9x0OQIp1ufDLFMwlziaXapqVtpmm3Wo3Tcbe0ieaU/5KCu3ucUYcRyTEI85G&#xA;mK+QvzOsPON3dW1rZS2rWsayM0rKwIZuNBxyc4GPN2faXZE9JEGUgeLuZpkHUOxV2KuxVjvnrzpa&#xA;+UNIh1K5tnuo5rhbYRxkKQWR3r8X/GPJRiZHZ2HZ3Z8tVkMIkChf3frT+GQSwpKBQOoYD5iuRcCQ&#xA;o0vxQ7FXYq7FXYq7FWOecPPug+UhZHVfV/052WL0UD0EfHm7VK7LzHSp9slGBPJ2Gh7Ny6ri8OvT&#xA;3sjyLr3Yq7FXYq7FXkf/ADkX/wAcTSP+Yl/+TeXYOb1Xsr/ez/q/peDZlPbuxVm35M/+TK0f/o5/&#xA;6hZcry/SXT9v/wCJz/zf90Ek87/8ppr/AP20rv8A5Pvkocg5nZ3+LY/6kfuCSZJzHYq7FX0h+Sfn&#xA;GTXPLjaddyc9Q0njEWY1Z4GB9JjXqRQqfkPHMPLCi+e+0GgGHNxx+me/x6/rei5W6B41+c9hDqHn&#xA;zylp89fRvHSCWnXjLcKjU+g5diOxeu7AyHHps0xziL+USnH5K6jc2kOq+T9Qal7olw/pKe8TsQ3H&#xA;2Em/+yGRyd/e4ntBiEjDUQ+nIPt/s+5d+dmqXMthpvlSwNb/AF24RGQf76RhStOgaQr9AOOMb33I&#xA;9n8IE5Z5/TjH2/2JV+UOmQaX5+806bb/ANzZqsCE9SI5ONT86YchsBye3Mxy6XDM85bsq88fmSmg&#xA;39voml2Tar5guwDFaISFQN9kuQCamleI7bkjIxhe/R1nZ3ZJzxOScuDFHqkd3+YH5oaDGNQ8yeWo&#xA;DpOxlks5PjiBNPjpJMNvcAe+S4InkXNh2Zos54MOU8f9Ic/sD0PRNc03WtKg1TT5RJZ3C8lY7EU2&#xA;ZWHYqdjlZFOh1GnnhmYTFSDz2f8ANPzRrmsXGn+RdGj1CC1bjLqFySIjvTkKPEApp8NWqfDLOAD6&#xA;nex7Gw4cYnqpmJl/COf3H7mK/mz5q8wXvlq30jzHo7aXqkd6lxHJG3qW00SxSoxRwWAKl1+Hkcni&#xA;AvYuz7E0eKGY5MM+OHDXcQbD2e81jT9G8vfpPUJPStLaBXkbqT8IAVR3ZjsBmOBbyOPBPLl4IC5E&#xA;sGtPPX5n6/F+kPLnly2TSWY+hJfSUklUGlV/eRAdPAj3OWGMRzLusnZ2iwHgzZZcfXhGw+wp55K/&#xA;ME63fXGi6vYtpHmG0HKWyckh0/njJp49PDcEjBKNb9HC7Q7M8GIyY5ceKXX9aC85/miPK/m6z0i4&#xA;s/Wsbi0+svLHVpvUYyrHGidDyeNRv44Y47Ft2g7H/M4JZBKpCVeXSyfgUb5a8z+cr6DVL3WtEXSr&#xA;OCD1tPjZiZHIDFhIa16AfsDIyAHItOr0mngYRx5OORNS7vh/axvQfzb80+YrD09D8u/WtVVyJ2L8&#xA;LSGPbiWdivJjv8NRk5Y6O5dhqexMOnl+9ycMOm3qPwROi/mX5qtfNVp5d85aRDYTX5C2lxbE8CzE&#xA;hOryhgzfDs2x7YDAVYLXqOycEsBzaeZkI8wf7B9ybfmZr9tpH6E9fS7XU/rd6sSfWkD+kxp+8jqD&#xA;RsjEXfucXsnTSy+JU5Q4Y3t18imvnDV/NenRWreXtIXVnkZxcK0gj4AAcTuVrXfBEDqXG0ODBkJ8&#xA;WfB3bWwnWvzO/MbRLI3uq+V4LS1DBPUe4BqzdAArEn6BlggCaBdxp+x9JmlwwymUv6rLdK826pc/&#xA;l9N5nvLFba6S0uLyO0qeLJErPGanejhQfpyHDvTq82ihHVDBGVx4hG/fz+TE7D82/Neu6XD/AIb8&#xA;um91MBjfSMWFrC3NgiBiU5sUAY/EOuTOMA7l2mXsTBgmfGycMOn849/fW+3J5H/ysXz3/wBX28/5&#xA;Gtl/hR7nqv5J0v8AqcfkgNW8z+YdYiji1TUJ72OJi0azOXCsRSorkowA5N+DR4cRuEREnuSvJOS7&#xA;FWbfkz/5MrR/+jn/AKhZcry/SXT9v/4nP/N/3QSTzv8A8ppr/wD20rv/AJPvkocg5nZ3+LY/6kfu&#xA;CSZJzHYq7FWd/krrL6d59s4uREOoK9rKP9Zeabf66LlWYel0ntBgGTSk9Y0f1/Y+msxHzl5H+an/&#xA;AJM3yR/zEwf9RaZdj5F6rsX/ABPP/VP+5Kp55/51P8zdG82J8Fhqg+p6mR0qAELN/sOLf7DBHeJD&#xA;Ds7/AArRzwfxQ9Ufx8/m35SH+LvzU1XzK/x6bog+p6ceql90DD/h3/2QxltEDvXW/wCC6GGH+PJ6&#xA;pfj5D4L/AMuf/Jqedf8AjIf+TxwS+kI7V/xLB7v0KX5fIlz+bnnC6vBW9gZ47YNQkRCXhyH+wRB8&#xA;jhn9IZdpnh0GGMfpPP31+u3ql5bW9zaTW1yoe2mjaOZW6FGBDA19sqeahMxkCOYeK/lrd3cX5V+c&#xA;BbOzQ24ujayGtRW3+IjwoAGy/IPUHr+1oROuw8XM8N/6ZmP5H21pF+XtnJCAJbiWeS5I6mQSsgr/&#xA;ALBFyGX6nU+0U5HVyB5ACvlf32lv/OQwH+DLI03/AEjHv/zwmyWDm5Hst/jEv6h++KF/Pee4TyRp&#xA;ESVEEtxH61DSpWFiqn8T9GDDzbfZuIOpmeoifvTu11b81IbaGG28s2C28aKkKreLxCKKKBv0pkKH&#xA;e4M8GiJJOWd/1Ur/AEF+YepeftF8x32kW+nrZfubp4LhHLwtyB5CtTQOclYAIcr8zpMelnhjOUuL&#xA;cXHqu8xxo/5++WldQyjTnYBhUVVbtlO/cEVGSj9BXSkjsvLX8/8A4h6Lrf8Axxr/AP5hpf8AiByl&#xA;5/B/eR94YH+QX/KCt/zGzf8AEUyzL9Tu/aX/ABr/ADR+lD/myq/42/L5qDkdRoT3oJ7Wn68lj5Ft&#xA;7E/xbU/1P97Nd+d3/TMf9tJf4ZHH19zH2e/yv/Cy9LmmighkmmcRwxKXkkY0VVUVJJPYDK3nYxJN&#xA;DmXkFlFcfmj5yN9OrDybokhWCJqgXEnXcf5fVvBaDvlx9A8y9XkI7N0/CP8AGMnP+iPx9vuej+dl&#xA;VfJOvKoAUabdgAbAAQPlcOYef7P/AMZx/wBeP+6CSfkuiL+W2klVALm5LkClT9ZkFT9AAyWX6i5v&#xA;b5/wyf8Am/7kPFv+VM/mV/1Z/wDp5tf+quZHix73sP5f0f8AP/2Mv1O/5Uz+ZX/Vn/6ebX/qrj4s&#xA;e9f5f0f8/wD2Mv1O/wCVM/mV/wBWf/p5tf8Aqrj4se9f5f0f8/8A2Mv1O/5Uz+ZX/Vn/AOnm1/6q&#xA;4+LHvX+X9H/P/wBjL9TKPyy/LLzvovnfTdT1PTfq9jb+v603r270528iL8KSMxqzAbDIZMgIoOs7&#xA;X7X02bTShCVyNdJfzgeoSvzV+Uv5g33mfV7210r1LW6vbmaCT6xbLyjklZlNGkBFQe4wxyRADlaL&#xA;tvSQwwjKfqjGIO0ug9yV/wDKmfzK/wCrP/082v8A1VyXix73J/l/R/z/APYy/U7/AJUz+ZX/AFZ/&#xA;+nm1/wCquPix71/l/R/z/wDYy/U7/lTP5lf9Wf8A6ebX/qrj4se9f5f0f8//AGMv1Jn5X/Kn8xdN&#xA;8y6VqE2klIbS8gmmYXNttGkis/2ZCfsg9BkZZIkFxtZ21pMmGcBPeUSPpl3e59GZivn7zrz/AOUv&#xA;MGreevK2qafa+tY6bPE97N6kacFS4V2PF2Vm+EV+EHLISABd/wBma3Fi02aEzUpg1sf5pDIPzF8r&#xA;t5l8pXumxKGvABNZVIH76PdRU7DkKrv45GEqNuD2VrPy+eMz9PI+4/i1P8tPKr+WfKVrY3EYjv5S&#xA;Z74Aq1JX/ZqtQeKgLse2GcrNsu19b+YzmQ+nkPd+N0p8leVtd03z/wCaNVvbX0rDUXJs5ucbcx6h&#xA;b7KsWXb+YDGRFBye0NZiyaXFjiblDnz7kN5z8keZLXzQnnLycY21MrwvrCQhVmAAFRUqp5KAGFR0&#xA;qDXDGQqi2aDtDDLD+X1F8HSXcgdU1b84fMlm2j2+gJoqXI9K7v5JRsjbNxNagH/JDHCBEb3bfhwd&#xA;n6eXiHJ4lco1+P0M28p+TdO8v+WF0JP38Tq/1yRhT1XlFJCR2BGwHhkJSs26bW6+efN4p2PTyrk8&#xA;/wBL0X8yPy+vrq10WxGveXrmQyQxcwroT9NVamx2INO2WExlz2Lvc2o0euiJZJeFlA380N530D82&#xA;vOWlQyXGnQ2tvFOrQaNHLH6m6ODPLJI6r8P2Qta/F0wwlGJbOztToNJkIEjIkbzo102AA/Fc3pPm&#xA;jynbeZPKraLdn0nKIYpgORimjHwt138D7ZTGVG3ntHrTp8/iR3/SGGaTqv5t+WLRNIu9AXXYLZfT&#xA;tL2CYKSiii8jRiae6g/rywiJ3unb58Og1EvEjk8InmCGR+UH/Ma91WbUfMcdvp2mtF6dvpMdJJA3&#xA;KokZwWoae/0DISro6/XDSQgIYSZzveXIe6vx70HrHlnXLj83tD8wQ23LSLOyeG5uecY4yFbkAcCw&#xA;c/3q9F75ISHAQ3YNZijoMmIn95KVgb/0fh0LM9Uhkn0y7hiHKWWGREWoFWZCAKnbrlbqMMgJgnoQ&#xA;xL8ovLms+X/KbWGr2/1a7NzJL6fNJPgZVANY2de3jk8hBOztO3NVjz5+PGbjwjv/AEqP5h+Wdc1f&#xA;zP5OvdOtvXtdKvTNfyc409OP1YGrR2UttG32QcMJAAs+y9ZixYc0ZmpTjUee+0v1t/mn5Z1vXP0F&#xA;+i7b6x9SvlnufjjTjGKfF+8Za/Rggav3I7H1ePD4nGa4oUOfP4O/N7SfOWsaHBpnlyD1o7hz+kQJ&#xA;I4m9NQCi1kdNmbrTww4yAd09h5tPiymeY1X07E7/AACR6DP+b2h6Tb6Xp/lCyjtbZeK/6TFyY9Wd&#xA;j6+7MdzhIiermamOgzZDOeaXEf6J/wCJZfInmjWPIOpwapYR2mu3lndwLZRSIy8nR0iAfmy/FUdW&#xA;yIoSdVE4cWqiYS4scZRN15i9qd+WWi6lovkjTdM1OH6vfW/r+tDyR6c7iR1+JCymqsDscchs2F7X&#xA;1EM2plOBuJr/AHIHV//Z</xmpGImg:image>
-               </rdf:li>
-            </rdf:Alt>
-         </xmp:Thumbnails>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:photoshop="http://ns.adobe.com/photoshop/1.0/">
-         <photoshop:ColorMode>3</photoshop:ColorMode>
-         <photoshop:ICCProfile>sRGB IEC61966-2.1</photoshop:ICCProfile>
-         <photoshop:TextLayers>
-            <rdf:Bag>
-               <rdf:li rdf:parseType="Resource">
-                  <photoshop:LayerName>Modernizr</photoshop:LayerName>
-                  <photoshop:LayerText>Modernizr</photoshop:LayerText>
-               </rdf:li>
-            </rdf:Bag>
-         </photoshop:TextLayers>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:dc="http://purl.org/dc/elements/1.1/">
-         <dc:format>application/pdf</dc:format>
-         <dc:title>
-            <rdf:Alt>
-               <rdf:li xml:lang="x-default">Modernizr 2 Logo</rdf:li>
-            </rdf:Alt>
-         </dc:title>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:xmpMM="http://ns.adobe.com/xap/1.0/mm/"
-            xmlns:stEvt="http://ns.adobe.com/xap/1.0/sType/ResourceEvent#"
-            xmlns:stRef="http://ns.adobe.com/xap/1.0/sType/ResourceRef#">
-         <xmpMM:InstanceID>uuid:d2ad3950-7c02-824a-aed8-40a8f4f3f557</xmpMM:InstanceID>
-         <xmpMM:DocumentID>xmp.did:03801174072068118083F1FA8E5E4F1F</xmpMM:DocumentID>
-         <xmpMM:OriginalDocumentID>xmp.did:F77F117407206811BB3F9C0632107F53</xmpMM:OriginalDocumentID>
-         <xmpMM:RenditionClass>proof:pdf</xmpMM:RenditionClass>
-         <xmpMM:History>
-            <rdf:Seq>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>created</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:F77F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T17:17:50-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:F87F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T17:18:53-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:F97F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:02:32-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FA7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:18:57-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FB7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:25:21-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FC7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:26:04-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FD7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:37:06-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>converted</stEvt:action>
-                  <stEvt:parameters>from application/vnd.adobe.photoshop to application/pdf</stEvt:parameters>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>derived</stEvt:action>
-                  <stEvt:parameters>converted from application/vnd.adobe.photoshop to application/pdf</stEvt:parameters>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:FE7F117407206811BB3F9C0632107F53</stEvt:instanceID>
-                  <stEvt:when>2011-03-27T18:37:07-07:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Photoshop CS5 Macintosh</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-               <rdf:li rdf:parseType="Resource">
-                  <stEvt:action>saved</stEvt:action>
-                  <stEvt:instanceID>xmp.iid:03801174072068118083F1FA8E5E4F1F</stEvt:instanceID>
-                  <stEvt:when>2011-03-28T13:28:58+11:00</stEvt:when>
-                  <stEvt:softwareAgent>Adobe Illustrator CS5</stEvt:softwareAgent>
-                  <stEvt:changed>/</stEvt:changed>
-               </rdf:li>
-            </rdf:Seq>
-         </xmpMM:History>
-         <xmpMM:DerivedFrom rdf:parseType="Resource">
-            <stRef:instanceID>uuid:edd0f61a-a49d-1d49-acc4-68ea7894e484</stRef:instanceID>
-            <stRef:documentID>xmp.did:F77F117407206811BB3F9C0632107F53</stRef:documentID>
-            <stRef:originalDocumentID>xmp.did:F77F117407206811BB3F9C0632107F53</stRef:originalDocumentID>
-         </xmpMM:DerivedFrom>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:pdf="http://ns.adobe.com/pdf/1.3/">
-         <pdf:Producer>Adobe PDF library 9.90</pdf:Producer>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:xmpTPg="http://ns.adobe.com/xap/1.0/t/pg/"
-            xmlns:stDim="http://ns.adobe.com/xap/1.0/sType/Dimensions#"
-            xmlns:xmpG="http://ns.adobe.com/xap/1.0/g/">
-         <xmpTPg:NPages>1</xmpTPg:NPages>
-         <xmpTPg:HasVisibleTransparency>False</xmpTPg:HasVisibleTransparency>
-         <xmpTPg:HasVisibleOverprint>False</xmpTPg:HasVisibleOverprint>
-         <xmpTPg:MaxPageSize rdf:parseType="Resource">
-            <stDim:w>600.000000</stDim:w>
-            <stDim:h>88.799805</stDim:h>
-            <stDim:unit>Pixels</stDim:unit>
-         </xmpTPg:MaxPageSize>
-         <xmpTPg:PlateNames>
-            <rdf:Seq>
-               <rdf:li>Cyan</rdf:li>
-               <rdf:li>Magenta</rdf:li>
-               <rdf:li>Yellow</rdf:li>
-            </rdf:Seq>
-         </xmpTPg:PlateNames>
-         <xmpTPg:SwatchGroups>
-            <rdf:Seq>
-               <rdf:li rdf:parseType="Resource">
-                  <xmpG:groupName>Default Swatch Group</xmpG:groupName>
-                  <xmpG:groupType>0</xmpG:groupType>
-               </rdf:li>
-            </rdf:Seq>
-         </xmpTPg:SwatchGroups>
-      </rdf:Description>
-      <rdf:Description rdf:about=""
-            xmlns:illustrator="http://ns.adobe.com/illustrator/1.0/">
-         <illustrator:Type>Document</illustrator:Type>
-      </rdf:Description>
-   </rdf:RDF>
-</x:xmpmeta>
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                                                                                                    
-                           
-<?xpacket end="w"?>
endstream
endobj
3 0 obj
<</Count 1/Kids[7 0 R]/Type/Pages>>
endobj
7 0 obj
<</ArtBox[0.0 1.36328 583.011 88.7998]/BleedBox[0.0 0.0 600.0 88.7998]/Contents 8 0 R/LastModified(D:20110328132859+11'00')/MediaBox[0.0 0.0 600.0 88.7998]/Parent 3 0 R/PieceInfo<</Illustrator 9 0 R>>/Resources<</ExtGState<</GS0 10 0 R>>/Properties<</MC0 5 0 R>>>>/Thumb 11 0 R/TrimBox[0.0 0.0 600.0 88.7998]/Type/Page>>
endobj
8 0 obj
<</Filter/FlateDecode/Length 1080>>stream
-H��Vˎ$5��W��T�L�}e@�VhŁh1��,���KD�Y���K���|83"�^~~u/�^�}�ë[ī'���߀��cy��q���|s
-,���ך��'���p��k{�}��1����
���<|�ŗ�m��|C�ƭ"8V�����<��#�n)�#�T}Uz���|i�~#ry��1�c���M|��mE��{M^
-���'��8_U}����Kp�o��(/�շ�l'��&�^��h^bv�+.��:ܩ��L�\>�	V���H}
�PZa�������Y}I-�Y9�{�p1���u���#����B� ���F�_WS�a4dM��(N�}G�j�"B6e��u�}�z���#]�댫�pb�
-[R�LR���x���y8�n��B%��?˜�����\��	f�i����K���G�DL���&���
�n��K>k�k���9�
-��b�Q|*�6��r���F���Fu|Ek""#b��|edt���%�c�:��Z��&�Ҙᄧ�pT-A�-�O���M7E>۹���C���h=k�^5����I�p_�]�
-A##�y0�-¹b
E�������N���6	7p��6Rĵ�ߠc�㚪ǁ�k��ƦF��wJq�gL�~h��[��B�_Ay�����X"�H<��G�,�%������#��D�
�5�
M��
g7Eg�L�V�,p�FȐP8��� RW(,�H��N�Y�
5�ռ���U�CV��43�3���Z
�wd��)#AW7,Pm!?��ī�-�[�&~�6�P�Ξ�t�Uf�Wd�v�1X� =�GIߟ��*�Q�f�yt@Ԣ>����5�
��=�9�R�)ER@5�9�8-�F�lF�1���9'NOE�Y/��A�0eu����T1�_�0�,����uw��gI�v�̶y�ٖA�4?dl
-�/���-��G�!�N��{�S:�	Z��#��r�tg\�f�gL��dW��/�h��A��Gr�Z� 
-���+����6�;a3F���@��e������˞��?~�������0�
endstream
endobj
11 0 obj
<</BitsPerComponent 8/ColorSpace 12 0 R/Filter[/ASCII85Decode/FlateDecode]/Height 11/Length 217/Width 75>>stream
-8;X.*5o.B]#Xe'qAYk1P*4a@.!l]_ep/*-_RXPW`fG[D6f.h*1a7H@op([&VW*Y^*
-W0WFo2Q9;Fb+MFP43tonNU43q7k''P:'9+35"AmKh.O9'J#%\IT$_Z*W;Z'Oj7LaA
-9^>Zd/+=U[R&s-+Brt<DrD5OMUCQS3iH5`HV"Ec'MamVcE^1X21/>.'Lp'%G5RL>:
-;0"gleOf`E!,b_4ci~>
endstream
endobj
12 0 obj
[/Indexed/DeviceRGB 255 13 0 R]
endobj
13 0 obj
<</Filter[/ASCII85Decode/FlateDecode]/Length 428>>stream
-8;X]O>EqN@%''O_@%e@?J;%+8(9e>X=MR6S?i^YgA3=].HDXF.R$lIL@"pJ+EP(%0
-b]6ajmNZn*!='OQZeQ^Y*,=]?C.B+\Ulg9dhD*"iC[;*=3`oP1[!S^)?1)IZ4dup`
-E1r!/,*0[*9.aFIR2&b-C#s<Xl5FH@[<=!#6V)uDBXnIr.F>oRZ7Dl%MLY\.?d>Mn
-6%Q2oYfNRF$$+ON<+]RUJmC0I<jlL.oXisZ;SYU[/7#<&37rclQKqeJe#,UF7Rgb1
-VNWFKf>nDZ4OTs0S!saG>GGKUlQ*Q?45:CI&4J'_2j<etJICj7e7nPMb=O6S7UOH<
-PO7r\I.Hu&e0d&E<.')fERr/l+*W,)q^D*ai5<uuLX.7g/>$XKrcYp0n+Xl_nU*O(
-l[$6Nn+Z_Nq0]s7hs]`XX1nZ8&94a\~>
endstream
endobj
5 0 obj
<</Intent 14 0 R/Name(Layer 1)/Type/OCG/Usage 15 0 R>>
endobj
14 0 obj
[/View/Design]
endobj
15 0 obj
<</CreatorInfo<</Creator(Adobe Illustrator 15.0)/Subtype/Artwork>>>>
endobj
10 0 obj
<</AIS false/BM/Normal/CA 1.0/OP false/OPM 1/SA true/SMask/None/Type/ExtGState/ca 1.0/op false>>
endobj
9 0 obj
<</LastModified(D:20110328132859+11'00')/Private 16 0 R>>
endobj
16 0 obj
<</AIMetaData 17 0 R/AIPrivateData1 18 0 R/AIPrivateData2 19 0 R/ContainerVersion 11/CreatorVersion 15/NumBlock 2/RoundtripStreamType 1/RoundtripVersion 15>>
endobj
17 0 obj
<</Length 969>>stream
-%!PS-Adobe-3.0 
%%Creator: Adobe Illustrator(R) 15.0
%%AI8_CreatorVersion: 15.0.2
%%For: (Marc Edwards) ()
%%Title: (Modernizr 2 Logo.pdf)
%%CreationDate: 28/03/11 1:28 PM
%%Canvassize: 16383
%%BoundingBox: -1 1 584 89
%%HiResBoundingBox: -0.000488 1.36328 583.0107 88.7998
%%DocumentProcessColors: Cyan Magenta Yellow
%AI5_FileFormat 11.0
%AI12_BuildNumber: 399
%AI3_ColorUsage: Color
%AI7_ImageSettings: 0
%%CMYKProcessColor: 1 1 1 1 ([Registration])
%AI3_Cropmarks: 0 0 600 88.7998
%AI3_TemplateBox: 299.5 44.5 299.5 44.5
%AI3_TileBox: -103 -235.0996 680 323.8999
%AI3_DocumentPreview: None
%AI5_ArtSize: 14400 14400
%AI5_RulerUnits: 6
%AI9_ColorModel: 2
%AI5_ArtFlags: 0 0 0 1 0 0 1 0 0
%AI5_TargetResolution: 800
%AI5_NumLayers: 1
%AI9_OpenToView: -70.5 304 2 1572 1032 26 0 0 66 96 0 0 0 1 1 0 1 1 0 1
%AI5_OpenViewLayers: 7
%%PageOrigin:228 -28
%AI7_GridSettings: 144 144 144 144 1 0 0.8 0.8 0.8 0.9 0.9 0.9
%AI9_Flatten: 1
%AI12_CMSettings: 00.MS
%%EndComments

endstream
endobj
18 0 obj
<</Length 5017>>stream
-%%BoundingBox: -1 1 584 89
%%HiResBoundingBox: -0.000488 1.36328 583.0107 88.7998
%AI7_Thumbnail: 128 20 8
%%BeginData: 4872 Hex Bytes
%0000330000660000990000CC0033000033330033660033990033CC0033FF
%0066000066330066660066990066CC0066FF009900009933009966009999
%0099CC0099FF00CC0000CC3300CC6600CC9900CCCC00CCFF00FF3300FF66
%00FF9900FFCC3300003300333300663300993300CC3300FF333300333333
%3333663333993333CC3333FF3366003366333366663366993366CC3366FF
%3399003399333399663399993399CC3399FF33CC0033CC3333CC6633CC99
%33CCCC33CCFF33FF0033FF3333FF6633FF9933FFCC33FFFF660000660033
%6600666600996600CC6600FF6633006633336633666633996633CC6633FF
%6666006666336666666666996666CC6666FF669900669933669966669999
%6699CC6699FF66CC0066CC3366CC6666CC9966CCCC66CCFF66FF0066FF33
%66FF6666FF9966FFCC66FFFF9900009900339900669900999900CC9900FF
%9933009933339933669933999933CC9933FF996600996633996666996699
%9966CC9966FF9999009999339999669999999999CC9999FF99CC0099CC33
%99CC6699CC9999CCCC99CCFF99FF0099FF3399FF6699FF9999FFCC99FFFF
%CC0000CC0033CC0066CC0099CC00CCCC00FFCC3300CC3333CC3366CC3399
%CC33CCCC33FFCC6600CC6633CC6666CC6699CC66CCCC66FFCC9900CC9933
%CC9966CC9999CC99CCCC99FFCCCC00CCCC33CCCC66CCCC99CCCCCCCCCCFF
%CCFF00CCFF33CCFF66CCFF99CCFFCCCCFFFFFF0033FF0066FF0099FF00CC
%FF3300FF3333FF3366FF3399FF33CCFF33FFFF6600FF6633FF6666FF6699
%FF66CCFF66FFFF9900FF9933FF9966FF9999FF99CCFF99FFFFCC00FFCC33
%FFCC66FFCC99FFCCCCFFCCFFFFFF33FFFF66FFFF99FFFFCC110000001100
%000011111111220000002200000022222222440000004400000044444444
%550000005500000055555555770000007700000077777777880000008800
%000088888888AA000000AA000000AAAAAAAABB000000BB000000BBBBBBBB
%DD000000DD000000DDDDDDDDEE000000EE000000EEEEEEEE0000000000FF
%00FF0000FFFFFF0000FF00FFFFFF00FFFFFF
%524C45FD0CFFCA8EB78EB78EB7FFCA8EB794C3C4FD72FFA1958E948E9594
%FFA1958E948E958E9BA1FD6FFFCA8EB794958EB7FFC48EB794958EB78E95
%94CAFD6DFFA1948E958E948EFFA1948E958E948E958E948EC3FD6CFFCA8E
%B794B78EB7FFC48EB794B78EB794B78EB78EBDCAFD6AFFA2948E958E9494
%FFA1948E958E948E958E948E958E95A8FD63FFC49BC39BBD9BBD8E958EB7
%8E95FFC48E958EB794958EB794958EB78EBDCBFD09FFCABD9BCBFD06FFCA
%BD9BCBFD13FFCA9BFD1EFFCAA2FD16FF9A948E948E948E958E948E9494FF
%A1948E948E958E948E958E948E958E9BFD09FFCA8E949BFD06FFA18E94A2
%FD13FF9B94A8FD1DFF8E94A8FD15FFBD8EB794B78EB794B78EB78EB7FFCA
%8EB78EB794B78EB794B78EB794B78ECAFD08FFCAB78EB7CBFD05FF94B78E
%CAFD13FFC48EFD1EFFCAA2FD16FF9B948E958E948E958E948E9594FFA195
%8E948E958E948E958E948E958E948EFD08FFCA8E9B8EC4FD04FFA1949B95
%A8FD04FFCAA1C4A2FD07FFA1C3A1FFA194A8FD04FFCA9BC3A8FD05FFA8FF
%A8C4CAFFA2FFFFC49BC4CAFFFFFFCAFFFFFFA8CAA2CAA2CAA2FFFFCBA2FF
%CAC4FD06FFC38E958EB794958EB794958EB7FFC48EB794958EB794958EB7
%94958EB794959BFD07FFA8B7A1BD94FD04FFBD9BCA8ECAFFFFFFC38E958E
%B795FD04FFCB94B7949594C38EFFFFFFCBBD8EB794959BFFFFFFA1B7A195
%8EFFCA959BBD94958EBDFFFFFFBD9BFFFFBD8E958EB78E95CAFFA195A1B7
%8EFD06FF9B948E948E958E948E958E948EFFA1948E958E948E958E948E95
%8E948E958E94A8FD06FFCA8EC4A294A2FFFFCA8EC4A294A2FFFF9B8EC4FF
%FFA19494FFFFFF9494A1FFCBC48E95A8FFCA9B8ECAFFFFA1949BFFFFC38E
%95A1CBFFCA8E94A1FFFFC38EC4FFFF949BFFFFA8CBA8FFA1949BFFFFC48E
%95A1FFCAA2CAC4CAA2BD8EB78EB794B78EB794B78EB7FFC48EB794B78EB7
%94B78EB794B78EB794B78ECAFD06FFCAB7A1FF8EC3FFFF9BB7FFCA8ECBFF
%FF8EC4FD04FFC495A1FFC495A1FD04FFC48EFFFFCA8ECBFD04FFA1B7FFFF
%A1B7CAFFFFFFCA95A2FD04FFB7A1FFFFBD9BFD06FFB794FFFFFFA1B7CAFF
%FF8E948E958E948E958E948E958E948E958E9494FFA1948E958E948E958E
%948E958E948E958E9494FD06FFCA8EC4FFC38EFFFF949BFFA194A2FFA194
%A2FD05FF8E9BFFC38EFD05FFA195CAFF9B95A2CAA2CAA8C38ECAFFC38EFD
%04FFCA8EC4FD04FF8EC4FFFF94BDFD05FF9B8ECBFFFFFFC48EFFFFFFB78E
%958EB78E958EB794958EB794958EB78E95FFC48E958EB794958EB794958E
%B794958EB78E95CAFD05FFCA95A1FFCA95A1CA8ECAFFCA8ECAFFC48EFD06
%FFBD9BFF9BB7FD05FFC48EFFFFBD8EBD95BD94BD95BDA2FFA195FD04FFA8
%B7C4FD04FF95A1FFFFBD9BFD04FFC48EC4FD04FFA1B7FFFFFF8E958E948E
%958E948E958E948E958E948E9494FFA1948E948E958E948E958E948E958E
%948E948ECAFD05FFCA8EC3FFFF9495949BFFFFA194A2FFA194A2FD05FF8E
%C3FFC38EFD05FFA194A8FF9B94A8FFFFFFA8FD04FFC48EFD04FFCA8EC4FD
%04FF8EC3FFFF949BFFFFFFCA8EBDFD05FFC38EFFFFFFB794B78EB794B78E
%B794B78EB794B78EB78EB7FFCA8EB78EB794B78EB794B78EB794B78EB794
%B7A1FD05FFCA95A1FFFFCA8EB7C4FFFFCA8ECAFFFF8EBDFD04FFA1B7C4FF
%CAB7A1FD04FFC38EFFFFCA8EC4FD08FFA1B7FD04FFCAB7C4FD04FFB7A1FF
%FFBD9BFFFFFF94BDFD06FFA1B7FFFFFF8E958E948E958E948E958E948E95
%8E948E9594FFA1958E948E958E948E958E948E958E948E958EC3FD05FFCA
%8EC3FFFFFF958EFFFFFFA195A8FFFFC48E9BA8CBA1949AFFFFFF94949BCB
%A8BD8E94A8FFFF9B8EC4CAFFA2959BFFFFC48EFD04FFCA8ECAFD04FF8EC3
%FFFF949BFFFF9B949BCAA1C4A1FFFFC38EFFFFFF9594B7949594B7949594
%B7949594B7949594BDFFC48EB7949594B7949594B7949594B7949594B7A1
%FD05FFCAB7A1FFFFFFA1C3FFFFFFCA8ECBFFFFFFC48E958EB79BFD05FF9B
%B78E959BC494FD04FFC38EB794959BFFFFFFA1B7FD04FFCA95A2FD04FFB7
%A1FFFFBD9BFFFFBD94958EB78E95CAFFA195FFFFFFCAFFA8FFCAFFA8FFCA
%FFA8FFCAFFA8FFCAFFA8FFFFFFA8FFCAFFA8FFCAFFA8FFCAFFA8FFCAFFA8
%FD07FFA8FD0BFFCAFD05FFA8CAA8FD07FFA8CAA8FD09FFA2CAA8FD05FFA8
%FD05FFCAFD05FFA8FFFFFFA8FFFFFFA8FFCAFFA8FFCAFFFFFFCAFFFFFF
%%EndData

endstream
endobj
19 0 obj
<</Length 21034>>stream
-%AI12_CompressedDatax�ݽ�Z2K�(���*
-M���**N8�����Z����ǾS�S�P=�y���u-o�.��T*���J8ԼN��]1!0l0�$�3K� ~<�ә�E��A.Ͱ���8�V�Di:�
-����*�u�#������?�#Qxq3�
E�j����� l�?�̤�UQ�rg��\���
-|.�<C
:��:����5�r<+���`�Q��L@�`:�
-���>����,òl*�r��n:���l0�c��|~V��?�h֔�=q:-��ciZ��tF�������p�w�nWC��ә9�������`�?��tE���ϣ�B���>�����<�g3�(�B$.�=��=�+�E��ď� �KT�,�'?���˰�>$��F�����|>Ϥ����?*�`4
--Y!����|>��ؠ�L.��E����@��<�D�$G��Z��T
-:���o��CQ�
f��z��i�xb�~_v>������#}�3���p>��S1��?"�2NFp1G7��c"��p6�ǥ���� ����	�3JN�+CFp|��	w!
>���s�֤A_�P ����������.��g3q�ةtF�˜]�ʨ_��)���L1��?�w�g�~>������0[Mi0B0��M����UM�'ǣ�q "��Ӄf���؛�jV蟮烙�t��# �$��c�U����e����s�ie��8O�ړΨ��Hw��agԑ����1��t�F:l����% �	nbB�Ѐx�Qg�,���3�����3wx�=�}R�(ͧ����x��5�Ҡ+��S��߁��0���bR�1����a��t�����Rg�9��!�y�a���a�??��p0����x��H�Ao(^����'h���*A,��ގ&H�^v&"�9�����t$0)c	gᛗߠ�s�g(N������,"O �:���%L�w~�`<����.�M��E�Uv�o�tPw�Ӏ�����?��>|���a���^�`�_Іw�$e��&/��{C���:�fg[��{��h���4`Qj��@��!Qa�!a��t��7Xd�8V~%3��)���!��WU������w�N�m�C��H���烹T�c�H#K^��asP�a�@�G�j��9C��s�����ۄ�l0Y��}�N����t�3b�kM��V�H��c���T�T��I����3VZw���<��I�x(�<U�m(
�]��xb�m���t��?׳Z�~Fv-�ƣ�����Y�4T<
���2K��gҌ"����A���g����p�4�+�!_��L���#I��so���8��e���X��H�Nw�l�鿡��}�oRaGo��+SRW�Y`
A���u4�_Y���´�6$����yH��߸w3�9��{�)�Jc���w�1X��(��mx�������^�qA.����c��Ѫ;�� ��G*rVf�{�b�}|��F��ű���'���,�7/�D2�}�����8z�����@��s�'b��rL�.�H�w�g.ˤ�LZV��5�v�:��O�Qɮ{���
K��~�:"�x��6O�������_6�?vc�b�Y����>4�~����:��F�������6�u�p>`VdYu�}7;L�L�����T�Uǣ��
-�uN�?&�54o��ȭ	-e�S[�P�S�W��~������p�z��3bxk�?ql�]>���x>Fbp&��ꩲm9�I�o�:�qo8�{cd��'(�Е)A=�ae��ԙ�P���X
-v;�Ψg�hR�����}0IR[[�}z�6-m{��,J���_�4Aĩ��:�%Gߗ����L��h8�E�C�\�|����y<�RQ��4�	\ƓcRsϕ����˹L�pyoNA��luF��'t�޻I�{F�M�C>b�tOk���L�~����;C���G�������Y,�Z��7�:��£�p
�A�o]M����d�6��*v��vz���ch҅�=s�ћ����6�?��B!�0˝�p�,��J��d�ȏ��ڑI��7-��d<�d��q�h>k,��������Q�v�bЖf��L��?#���Ѡ�*��J��p�@��I�&�B�����ب߀��K�k_]*�3]��R�����,`�`"����A�_"��vF`
R�b>��Xq��,�C���c���w�a_����XE��>��:5���,M�4��b��i�O�y��u<\}d��}Hm�'���}*j�Ck���Z[�Uܠv�񜤹�A�F�t.���D�3<�rh����I���bˀl�4��6*ז��R�\�6,ܔ]�Β�֡)�;��G��TA���{��I<���Fg�1�|���x��((Q���9l�`=���Tu��z���`�!up�(��H;G��V��i?D��Y���Ւ=��?P���6j@&O��?gI�`Q�!)MApތ�dT��x:�D?���;�T��Y�7�q�uP���+�;J\�g̜�SG����`����V�"�<��)��a;�4���P��4�I��q
-\��Q�6��/u�����wI�a*���Q3��~&]�;���a[�3�������V
-���7�Q�ဖ3�t�������^��V�s9wQ�OQ׺F� (z%dD�#�4"�iRJ�y�U�dK����ȑ���n�#l�"Ƶ�q����k[9��Db��Q����-��ݔ�~v�g���èfj���7���?F�L)�a*���E��H��#��A�Ϥ�	�2"�u�a�lO{b`�)���3:���fL8�����D�����2
�tޝ:�#H8�}�K�~1��ˇَ뙽4vs'��(�8�z��-�|�|38�|���H����l<��v��Q�4���������we�1)��ݡ(�
]��V��n[�,�rO�s�S����M��HN���!=)�NR��Ͷ4uxd�+,��>�\:!���'��L���'��F�\$�(m#�f?��Y�Q&�P�Pߓ��=3�4���dЅ!��S����_[��>���ag��E�!0��	�0�W�%uqb�؇���ljh��:��a�Q���s�J3�m��L{���v��L�=�;l�;���V�(���Ӎ҇
-˱ͧ�;��x�&�$zC����9{&���D��	Kw�9���oo<�3��s�����ф�?��mNZ��Y��/N#�a��;(y�7��`��W����T�O;Nj�!��,M��6R�F����v��hN��T D$k��k���T�u�D�0���,�"�Q�{?M*L�Ϭ���t�\���$���t6T����Q�chc™�� �����>H����
-(tC���.f����D�8�v75
�uSHܘ�̓�� �.|�ĿD�ZgN��Ս�d⨚ ���d���.b���^��/ TG����ڐ�׍�~��P��o�Q�\������p��Xѽ���u�	e]!?v��@�a�:���a;T�����Z"���89?>/���������]��4�4��Hj�ޝ�$�Һ�9��8T�ʁn�9�Łf�Y��o��r���<�D��_b|:c��T�0Pַ�AmךG���t6)'zÁ����F��J�ןs�2U��|�V�����0"9�ij���H"��r�1��Pi�3�KX�NMtr���`�`H��07��t�G��C��X�9Km�K�S�{I�Ҕ������Ӽ`5���=�'��l<�>��h;1�N���d~���]4n��_��ӽ]<e�ה����|��Qw�z$�����,[�#=����ϝJG��;s+}<���$��r֑uV�ݰG=i������BQ1��i�}X�����S�|B_��„٧TԮ�T�"���8
-N;!��yQK�,ؙ��Jz��B1AX�$�5�3�'�0��QPD����3�C
-Q<ȴ��������>����?(�3���ɱ�y�u�xTƖ�F�6�Y{58~������eD3ި�{�`bU��-��ʟ�3�:�B�@_���#��-gb���ً��i���ng�M:�7p���̼*	֫��Y�L�����34��>L�+�Ё<*��:3��s��uC'�a��=�MU��tw7�����ч���;�qQ�zleǎ�i-jG��.nlTx�
�Mm��G�r�Ȏh���n�_�悳���yoP�:���9v���̬�!�֟0՘؃�����r��謞���g��@�;��B"57<�U�f�Y����_��
-�wd�ر�����(P/�K*�]���ޑO��{t]:>Υ�"��jl?�����I6;��>g�ħv/���R��_�7�b�=_���_�u���þ����]e>CQ��J$���Pl�{7=̇�x��΄b��u(~v_%�3�M�=D0�t��LM��t���:�x��9!�y��<�&ު������l�-�aI����'�'����~��{�TǏ�VEz~dˏՇ����^��>ʎ,†�����IR*o���D.�1�hT9������Pt�=Eg�Z�Z*~�>�#�Gx���Ɨ>�@iz�*�[�keS#&9������+|�
���CYFc*I;Ӗ�<̝��ԵLT�N���px���&�)q�ϛ�R�>d�Fnۯ�6���HS��
�����6!Uǒ�����'�-���c����>�&��뭇&`�����~��tb�4��K�R�f��[��iR��M=<��b���Z�+�1v�vH��{�NE�ɧ*xUڌ5��gk5��~���[�t�Es�[�t맠 mnma��2���J~b���݊qV���r���F���zI͘ۄ=�I�$6�Ցf�ٝuҞ����푞W��3�3i ����O�U��?�푦������-ҵj'�В�zzY� ͬ�ӹ��C���ont�0mmco�!~��"�]�Zԑn&B�2����aѬE���a|��n[�Zo��+5;1#m��(H�H�i�yԑ��c},���ˬ=��y�����"��u*�@������ǚz��׍߹=�S�Q��l���u�0/F��g��7�2�b_��H���~{{�)H���ޔ:�VDlOhH�ػ�A����;�I%�46��1~�JE��v�(R�>gؗ�[�)������>������ME:"4�g�[�Q�H����-�v?�<�C*I�uiW��M,�]d���YMG����PA�%��[�^�E~_+���tO2�4��C\A���6!
�?��c��0_|���⊭�?�҄U�'ԝ�43��R�bd��J\G
-299Mn�c�T6
-�S�(c{��'�4iE�	��=���$dB��)���%c��x��-#=�m4�[9���s��7���,�o��O�/����ڎ��7CB�gb��T�~Z�������X���^T���m�q�m
-<~k��l�� E{{�6���6�y_b�Bw9گ+�E������^��g����g�[�!ʯ����,B{�foC������e�*ﭒ�ζnC{�[�BCoO��G�����m�T�Yߟ�w�J���&���}���b_��Mou�=gٗ��8���y��vG��=dۙv��-�X���4�}'����3���:W�|���^s��k'T�����7?�����N7�ߦ_G7;��G��i3�=�:U,�Hݰ��G!�~�/�5K>~6��N��ߦ�� av��K��������ؾR,>�h��H�&VO�e鵿7	�Y�Y,*��d�a)(I\�09�*Uo�ظ,?Vvx�VKE�W*��1���D��[x�z#�������O~ds�v2|��f�,7��~���ﻚͺ��u���*`��a-��[{̈́j�\��}�VE������HS�t�k�~҄v1
-[�)^R��b|18�А�9 �%�}�����#����TC*�����Ǝ��64�w-B"M]o�:Zi��1T���(H�����i��	[I$Z�x*Rl;P�"ˡ�#��Њt����{:R��P�#��M�eV�q=���y���0J�OS�
o��M��X�od�"�ҭ��N�z*)�߹*b�O.*e���o����I�E�P<Dr=��F���on�Q��.}H
-&��$�?h:���B�OY�U�H�wr�8�j�M��V�t�˺�o��A�2Wy��d?�2`������'~6��#���8�GX2��{1�)�������{��)�	�K�J\��Г#���*}����2>l�ێ��LJ�J��?W�	d3�c���_{��$��Edr}�L�M��|}�wb>�Eg���	��!qbw{f�=L�9K�+���žsk(�Lw���������a��̋;����[D�C|b@����~f���Q#@h]6���&�Jڪ|�Ϩ�Q:��Qh���6��<�L�����R6|l�v��6<-6
�0�ĺ���?b��ܟDw'�4�5a�v��jS�=��VXq�}�<���l�x�Z{>��n�tu��`���U�Mߥa,��6����ɲ}c�;���"vd��&�u��=��n�t~�O����=�]�,��$�c9hܩ�/�">dd<eB�����0>�4��#�Kز z���}/1O�A^\�ia���3NI��2%�9�y�s=�.����6&[�Ѩ1�[3IU�*�����׸��V݃��k���*"V>�F��nĹK��N�����}�4m������W��a�z~o8*�.:?9�.*���Cr�Ӿ]
0V�[v���f�P��EHK������Q�E��3��B�qe3I4�S<[�f��k2\���+U��c]7�����u�F���o�ut:Sw�c��m�+����V�*���ԏ����G=6vNKQ����S��xv#��B>��mk��	x銛p�:}�o�Kӄ��qGa�mX��ߢf�S����2�G�����ܘ���$p�tw6����@�����a�a^����A[ _�&��h�v�ХٺW`���,���,�������b[vヱ�&���`���X��F�=��g�v񫺂�M?y]������`�Ԟ���#���#����Vb�\�b8��b�%�sb\�#�ջ$l�ּxH}	?'v��%K�(Z��n�w�,ڑ�֒n���usFZ���C����˸7�XZ�d�S	����0M's�D���!�D��?�_sb���9y���`T�
-͙I�n�!��EGe�:�S_>3M�����sv�5a�6x��Ae�trnzЄ'��mp��rp�]��1'ON�۟Go4��ːq�#;s��wR
-��N-���b��P���a�VG�eu���>���ڬ�V��׷��X�T�g��1���U��^�|�U��C�%y���U��ou\/���y�y��h�p���ѬE#&(�g|�p�}���LÉ�dT������<�|��&:1F۾E�V���f�]�0�ݵ�v��e8��v�G%e��r0(�N
L�t�$��Y����NF\4��ۥ%�P+}i�N
@�H49"��	�%��5%��^�� ~{k��@�1W8^d�3���E|��&I5�%>���\d�l�LX��HH9:D���b�]���T�ͳm�g^&�K�U	^SϞ=jf�-]Ȫ{����]���ٖ��;1������ٚ��J�Y35Q%�+�jO�b�+58ˆ@�P4�����������f���Z�	O�l���y7�5<�4.V5����V��?ӣ4m��n��{����E����9��ҫ��:kg+����΀8[:����#c���p���y/��0�Z��n�"(�ڼ">�J`	:�4S�}��)=�*�
-�9�I�Y���70�t�~~�����mG����5R,�<��nU4�-/Z���)a��;����t�.a�[�//;#�/�?$Lے)r‹?�j�=8mKd��1��5�����fG���e�ü���k��v�_�7�{���Ň�M?*�9����g�
-��ػS��[�����Kt��yq)�b����]Sm۲�28[n��6lu�����R�o�Vo���A�&�.�AGd-�CGQY3��[�ɡsΠӳ�ˡ#��d���K��9gБق���9g�9d�ʡsΠ#��ɡsΠ3f.�C�A'�b���9g�!N^E�s�<9tƀd��7�/�����u��_]���N�n����s9��l��/�T6j����斯Xr��S��bZ�Nj^�9��if0������������aQ�g��9�y|f��Do;���]����r��Ĩ'�M��!k^+(�iI�!t�b�
-"[�A*˜͑����*��ih�Q7��n~CAl�}����clP��f%�%�y�JK �M0�Bf�d�Z^B����ؤB`W�K�7����n�I������Dئ����9�0�r�!$���5�I(�3��i�q�����R1Fw,��F�و�4Oy`���:�#��u�+��!�Ϡy���m�N+zj�HM�1��.1�5���+ͳ�2J�[��<>�q2��G�Ƀ��8"��%��k���ܢ�����-~��O/��K��?�	�3:~��%
�N8��%{Ɠ.[7�|�C�b��/� -(м�{xus����ng����z0�f.���0f�6��0؟�6W��Wm�i4qK������-'#f5��v�׾+9<�h�q�,9��F�\ЀR�YbG��S(�,��b_�3;�9VF=��ɰu�r[D	��%A�E��3��D�c_���/���t�\��t�:���q�3����J�,��g�v#�m�|yd��""V�ON��.o���1YIF�����A)I�xdt�9Y�##l"vv)a<�
'�=2T{��di�-�GwxOC��q�O	��-�AIh�)#u�̉�L�[~�#�)9G�au|��8FI$Mʲ�c咇�IY>�H��I,\�L"�6��\	�Y���
;�#gi1����ʟ�?fϡ�C���P肇lA׼:w!�W�%�q���G����:4���i���2r�|�
-���@Dv�>,�g��Ԍ�U��-{���|87[M>�|��9#�?�|8�����z2���|8�AW��
���+ȇ#+�,����1�挸U��Q�8W��l�юuj��
-2���K�9&@q�tK1��_��z_{8��U�H��U��%2��	/�c4�]{c��p�α�P�EH��!���g��v1�"�A��6/��sə�r\��e��ԥ����}�����[���.Ǩ��[���I��x�.��7��Vs0��v�����mw��J�a���oӢ�Y�,W�݆s���g�*B�|Ԕ�����c��[eF��*3R�V�������Tn-���T����Tg��Te�({��hS\5�å�����s@@X�a[Zگ%K"n��T8r��c�W���.�U���RI��GR��+}���� Ze*���t*�C��y/�h�u�T��5XBxK|2H����J��_���_�&S���ȷ�kf��-��<�/v?\�f��$6G8N��"Q��[-��=���%�M�F� ���cPu���o���G�E�\mdC�ϯkT�����������P�kT@�&�}s�A���e)�8m����wVٌ���d�U���\���Eؕ�d�f�%�l�;�nm����d�Hw�ꛖa��>;%��&�HqQm
-��:N��gؽ:%���t�����T�����^��]^HM��P�ij�]�s��n{BK{pJv�`MH���^����w�ե!�8 ���z|'�T�����-��q�����iV�rM`�����7�{jw�.czi-�.�B J��7y7���j�1u�¯�ӆ��;v��h���s��٣�Pj�\�jBu<�{M�u�m�j��\�S{\k�X��|}�U�3vin��_U%9����kn�-�
�{z���Gq}���%�ܽp>��Q��^�ͭ؈���ݥ�p
-��:#^��R���za��gOt"}��t�ŷ�l:;�§�C6��`�[*��.���~��tv>�@x��tv�th��6�Ύs+Ϧ�z�W�MgH��o�tn1��ɦ�;��?{]&��8�r.�dd�l:���Ug��sFV�M��%���{-���Tt�l:��(`p�"�ήK�i�����r�l*�,�Mg7ڝ�+˦����0��.��&gd�l�E)�/�΅b+ʦ�˥�I1�tv�t��%���4Osn���tv�X7a�tv�%خ\i6������`6��<SOFΦ#gH=Zq�_̦��+��X0�� ��J�3�ͦ�qM)E�Z������%y'RvU1���>|c�p[㢉O��¨]��^��v��zu�6���otr�lK0)�(��¹&�{ct�[%�moS�I�lm#흪˹����%�u��r��%���(a��.a�����N-��Ed�>2;�(ղ����Y��Ŵx�*��2w/���a߅[�;��t+�={�2wd'�Н�4%J�;�����zͅ�|�*Y��Yn�+t�@��D-�E�:]a���t5�u�y)\.��s���EB�&������Fs�t��Sj�9Rŵ@=��kV�M���-��&뉓�� ш�PF�x�����|�� ׼��.��t�h��#�#
-�����¹�K���K �����`(��f�=���Q#���V�
-������c`��=T`7'�~�Kb��z��=��K�T��F��Ft�mOŒػ���aR����t�ښ5��%_z�\%Ӌ�d�Y,3�v�oWW��֔Ȱ��o�}������2��1����o	��,V��`� 8!C�bUa��$2,q���u�3�D�<�T��ͯl-�	P��[�V�Λ6�l�;"�ѶƝ��J���*���'�T�[v�*�9���!?�[���9�v�
-w^o5�=�.�؅ni��\n��X˭�ڍ�݃�k�5Uҩ�������G5�}�{�0O�,�+g��Z��'��9�w��J?���O��HƜ�d
�A�[����_˾��2���t�O����}�S�Z��S���j��O�f��~U�o��C�=��WcW�%g�lWR��B�q�etUM^�c�_Ű+������U�݆������Jy~s\K=�N�{�2–���B���{�N�X��j:L��z�5=Vʻo{�J;K��VV���tw��W}���F���hL%��m�J��I�e�ݠ?��X�9Ai}%������6u�&�)��iҔK:R���:lk|!o����I͇��o=	����s1��Mu=-K��)��3�/�ܿ��k*�M�ݣ!�SS��i�xM�՘�6]�i�p����Ə6RS>\�H��j���H�j�=� ͬo\��vHa4V��õ�4EGZ����H��H�S�\���'��-*Riz��C˹�/�ì�y=��LD�������u�3"%�ef���r�
-1���M���#�ҩGDD~,^��\�oQ�F�!lR��m΃��+)BPF�V�xb�2�P�Π��U1��)���փ.R�üU�����M�\��,�=IOe�"(z$�3���V�d�mS�+Yi�M�=����g�5���5&�k��ݎ��{֝K4[�G����\/;U���Xcc����e����*L���u�}���2�-�*�-�P��֕���<$֗��UVqo#�TW���Z�z��w���ra��@��bnVK�1J˓�4�Y�v����J�Nuu6rWX�2��;kg���D����
-��p�ꠑ3�yU�ssY�����ȷиf���F������~�Ys�H�����er��.���2,-��m�{<h㤦dqx�M$��t�h���9�ӵ�e�h�=�9�5Q�33Hj�yF�W�����(���b��s�QO.��CB�%]�p»`�W��X+�o�qU�smn��h�=�T�g��@E�SM �l��|dRD�%бF�k���B�U�H��%�)NJJ���md�Y�^s�6�ŭ��*ʷ`E6�E���+-���UXQQ��w��DQ>��������E+�y-ʧz��٢|��P��٢|��W.R��֫�:%��ĺ�����Ȫ~d�U�
e_��w&���wC-P׏:��
���[&N�{]?笻�
���-7���~��+���S�Εa�����w��{P�5�������Z����#�U�̑*���s�c�Ju����-]D���<������E�����s!�@�G̙C]?�իj���#�u��7:�>�p]?C�����7P��9�NVT��=�cu�������G���ߢu��P�U�(7����G'�������,ǖ��瘞���W�%F��g�{]����9
��WQ��9����곮-�8MX2�������ѩ�����L]?��l��-X���-�z|��=U���渥�ަ#bOѶ��9�j���2\����}z]����i)W���dƐ��#k]?w9���~�U�VS��-H�k=��/�ѭ���S�����no���s-�G�0��sJ�x�������ٲ�V�o٬4ojq^�T]?g5�Ȭ_���Nm�,�E����¥��[֛e��\=>�Y�1W6u�M�Wr���gX���~�
-����l�U�d9�|]?�@'�������ٮPle9O�U���-�3��[خ�U׏&�~+�,9W�3�6�p]?�~���POg[0!�vG^���sU?}�{B�cU?£�T]�t���Qg�xήu���%�r��~Λ򎚷qf���}sP�Kć��Ut����4�vᙃ�w�7�-�l��&&LN��/{��jlD��	h)P��QI�'�2F�Œ$�_
��ݓ#.ww�o���q�OU��4;R(��!GPh��b���b;�������C�f�=f+��$[�J����H��x�`k���8>o�����b(~��gB��9�����;�bgC���7g������/ݵ�����m_	3�M��b��"��$U���y�#͹Q+���\d���D*���vn%��E�<�~�zy�mo����a1ܼ��l~~���������>N�7/�_���m504�OR�oxJp�Y :��܄�
�O�c[���/�NQ:i#�(>���J�B�D,L*�X���r�ٷ�ר$�'b�X-#ME�c���![-���{]��L�_3]��R���Vb{��'6Ym���K��ʶq�?6y!�Mʖq�J��E~t+14}���}9�v3�=O�ɭʸ-�6ʹd(=<D�NB�˵s�v{�^�GB??�����a��ߜ��r�L>����]�v�Ҡ��иڇ;���'�Z��r��z��?>��S���l�{���6�?3��0I�	ň��K܆_ԣ2����^/���I��	�k#��)0����l2}���ӣӻ�������lT�G���,ī�FiO}UJ�/������8�����H}q�i/^a��C6Y����zJ⮕�zss�zǷa+{���(�2��Ë+I�W?���۱r<<�F���\�#�`�]�1���F��� �YY �{j���
���1��KN���-��Ow���<��M���$����� ,;����8d>�����F��8t�[�'�d�����"�Wwe[l�`/{�bz�����c���z�1�<��,!����h^�@M=T���UPY�&E��|�����N�O�|YB!wI�������G�8E%O���;F��SJQ�����Gb�WE��T��j�8ܛ@X���:P��(}+o(K��+���1#6��c��u��G_w���_�)��p��L�6�FG*lF/Q_���J�}�O<���#���T9f��e���P*�r�j�r�ʑrSQJ�~�����0�%-wѧ��@���Ʌ��4Nn��ѢaG�m���z�ڻ�F��(�y��{G�P�,!�U:�v���HI��\�T�~�h���"��$_N<��X�{quV���e�J���	�*FE����$�E���R�B �R\���S$RP�^#�U^�O��\�C��Tf]�
����1��)<����pmT�ǟ*ϞG/�,�j�5��a�����,Wy>��ժ	YFn�]���F�MwO�x8�I��3
6��I�i���1���'�V�g��>����Y����Ÿ�b��|�-l�˅@��.Ə+wE�����ۄ��u5��ޯ�7����������w&%�@ޮ�L�]��I�4M�,��dg66��B��� �������s��p��Gɣ���`Z-�����@U٦��u���Y��i%6x�<�i�I;b^�1���֯�Ng�����u!����U���R��qi¬W.���/3��]�={�wN��|7�۟o�,�-�@@�H��(�:T�1���>
-Ŝ�ˬW@mqP��D.�1c������悘wN7���Zm���,��$�=��ܱ��^
�Ͷ�T��e�?�+]@;܃e����x幊���4��4��M鰵u�{8�K�v��~t��"�6���+�����2��ʰ*��L�Q[������?�aŮ�˽��C_p�����W�h����p$���ތ�b��؉Q�b#Hww���Sk��n��|pzTO�$���b���+�^�"�^w��ڰu�M����t�ǧp����nZ��(��	�T*~o���LvkJe>�b��W-�`� W�`9<�@�ÀUF�l���}%����W�X[l���c��
=�5�<���A��Rb��n�c�
Ŵ�����b.`Y\i�Lh�6`��f�R�e5�L]WK�'mM�Ŝ�
-v�u~''�,��?�s_,W��*�u¡�v�%�+�Ȧk ��^%$d�]��1h%r��Pt0�%F����,6��H{A��mɗy�����s	¸f��Q�y�R-��oG7;_���S�f#�v�{Pe4��>���HB0yӘ+n
-�x�:�;�9�	U�2������uk��W�|��}����.3WoR�}o����Z���	����[Y �u�՞<R�Y,Lo�c�'4%�l�W�?8�$�J���;�/a��ׅ-����p��fg�{��|1����1�g������<�-4�3���{��Ak�g���v
�K#��S�P��?A_Y��C���#�����A.Bѷ�\(�z����|��?��,*Tqk2V���������/̕�[��p��|�Wv�r�j�Z��������
����ႄim��;c`Yb��Xo�����e�}s���.�����B���Bmld?�kAn�}-�1�o^�ׂ�+�ri�<��.�����__��1㻠�/��0ޗ���B4�_�s@9�UVe�Ȱ|��p~���G���j� �>9��[����娞y;?|���T������ʕ���J�`�"To�ή?��c�Y�[Ơ]���n���7��w`W.t��y��ǫ�]��Lբ����h�����*,Gg*^���a�8�����c':b���iJ���W}�n������E6���@�K�*v�(�m���g�E���cJT`�36K��Q@A�:��9�Ӟ������nn�^=�6�����BEv���M����N{Tm��G�Η���x�:
�--��Y�۶"�A�)��!љ\�1�)��y�#�R�;��h4�������]^����/�[.0�xڑw��x�S�UO<�v���ى���x��+������iW�c���[4Xlj�U{���?�͐��P,b��1c��p���CA�n+����"�=�b�Cb��L��*�l�t���4��x�X�(	 >���<�����������?[[�?����x�=��j5�`ŵt� ��oi "�3�g��*�;	as����j���(�������˴�BI��j�`{��aGՍ�2>/:[�vzg(�q�T�GΏP��}x�����(:?~�<�@GS5x�;6R�e��C��Ӧ�*���ź�{n<{�����1�FM��Y���+K.��ֵ�u��Ge���	�u���ӅF�{#b�$����$(=�_U�L�e%ݫ@%��A���/����@	�J�yJ�$�5�,D@�I����V���9�|���>4NV��A*><�D�t7��)|�T�ވ�Q4&	��G�������D��"�׃^/)_v	*rU:�`q;Pr�a�&�2���Ɏ 8g���@x���� v�����,�P���l��>8�g
-ۂ`<̆px�(:FK�1U��ŕx�Ap^(���y@f/.EZN�j�%C���rc$�4��r?���	���\V�$T�ʦI/��@��R'�xl�a��:v<��\�I�ˎ\O흕b2i?-@�Hӎ���)��[��)�<� G�;2oVo�
-.�.u�vdlr�eu8�Sd�R��=|��==��Z�Uv.���#�|�ޏ#�2!�%�D$�kFID�]c0X5O>��-�d:�_�D�t'+n)�8�ÄC�8�,l���YM﯇jR�)��8;z�^�	��R�����/n�~ ��b�W{���xa�7�ͧZc��=���h���'�W���s-+%���z�! +"��d�p[K|j��<�Y�e(��!S>��m���`4/�ȗǷ$��[�FΤM6�����7Z�71"m��ɀQ���sX�T,�%������n>F[���J����$S��;��F^�jW�8C�ﹲ�cpQDOr��\�z�%ޔ��{!���p�i9�<�v:l�+������!�~���@�,0l�6��#w�Y��8�§'NI�����c���O��'���+1��U���I���O���UO��[�}�7�}�x��x)�og�a5-�'�H�@F|���>3Ջ�0��#‘P� �w�����dS�Qc��{=ᮧ����_�#�é����RYij���7�Y����ɶkgշ�p^�Ӭe���=�i���GX4m���z�4�_$F
-�&�`DŽ�ϸ����<q��<q�
i�3�:�(b��} �8�2�=N�g��<�bX�
-;��K턃���NـzE]���禴r�c�{1�˧J"6�'4�S��V���}�7�7X5c�#s��Z�7��q��ʶ6��,����������D��ِ���/9�����]��!���r��������<��B&���E�B|F�x`'�<:��Q\�D�F�Ϭ<����,X&��K�ǹtY��b�O��lWz��-y��!�N��.��k�����N��}�7G�E������K��ʇX���'
-�cB�y�\�C	���Lgw��~��<�&ު����I�"I�c�{���������S?�Z���-?Vn�{G{=<���Ky�p�m�TA��+�����P$�Y��wP�qF�i:�#'���iv�î�f25��l�<�Bgk�!-����6f���!�~���ڎ�V��)"�q���j�S�qFr\
H�E�3��I-���դ��~*B\�`�)&V�����H�jH-&��a�9��Z+0Qs�0f����]���+.K(���v��}:�l̵[�9r;j�J��rET4��:�����J���������^��?u9��G_�e��^F�r/�U���c<�1򚉇f�-�,�-��*i/^�-K��۽B��vs���=����d�����
-���7ڻ�.9�����6�^ �}�+FV	*�����֒�=%��?
-u�w�I���GZ����[)z�Zn��v�y��w�'��hר|�����X�j��e���?JB�����%�q���j>��h[�Ty>�ɟ�~�>��/>�*��d���{xz
-���}����]�p��z~��կl���τKs���=���Ԯ�/�H�xvR���ar��+,sC�eBݘv���m)��(sUETs�����X �J�ש|w�`����]3U��a��m�!|�nq���},u�aX,�K
QAO�3eii�x�ծ:�$.8�R�̶ƨ,j)<Q����z��]�`4�&%V���t�
L��x�m��;�/lx��
-���`"%IQDE�ծ�X�v��C�d����g�w��9�Lo��״v�wisޗ��}j��f/wj>2�"S
D�"�]�1p��>I�M�.1�#��z(\��BZ{����z��5N��B�rH�������m�7Ry��P��~�gRrp1���9V~
+G��ꙸ�jw��J����@N��(�a�;��J2�8�+u^:��O�u"r��$�	�r&�H�zC�W6�Ip(`=Y%��(DH%u"��|���Ig�G*	���H� �ț�˂��`�ל-x,�^(�x�v�i�JȀ�P(aVn ���e��$ح�ˬ|�s�C�i�H|)R���@��.3�F��Ї@��r�~�d�0����[�}u;�m�����^A��϶��0HS���������X���[.a�Ne�$g��{����\����T�>���Uˬ
�B��!���%6�99l�V/� 2����hW+�F�v�/N�Xf=�:/��-kۮ<�4��m��:�J����#J�Mk)3��[����D=��:���a��r5�X=Qe�F=��(<�u���x�>H���RPO͘�]rG溯aw�r�C�#��Aݑi�P@L8Le�`�mdK��^b�q&%ڑW/SZH�`#;�EpP��*MA�\�;���W�@<�R��$�����]�Ȼ����BL�V�f��M.ų��n�'��S:�'���$�	՟U���<�������F�W��vHwJ��ƣ��yJ��n j/�F+����=���yN�?�������GG}���$X���1�9�xG����Vru+��ty���[5[��c5@:&���.�^ lwe�/lU��tekl��l�l]����+Ƶ��_ت�&��l�xakQ?�V�d���(B�ڎb�Ŗ�	����F�_�;�zR�yה�9G�+n�hobG�)���B�W�H&p=�Faɵ$��/�+����x�-��ó���aI]v��/ �b��R������RB�̽L�����Ap����C�0�q��q�����Q��D��(n���ݡ�}�����s��;�0:	lWF}�0Ókq6���vQ���?����,���f�A���t����F7�m�\4����4+z��xԑ����Y���,�mh��@o�6��WQt�؆�l����;0�.,ñ\>ؙ|.��������V���|9�_��� �ςO/l����
-$X�e�Tz��|�����Y�6|�ɱ�`�$�
��L�e9�\����9x�� �y�'*ֆMO��@^`��|F��O�Kq��eu`�Pi�<�qY^�3)�a>X���O��(�αL�M�B��ee:�aR���=Jg9�PHCWr�`:�gX
ȓO�y��=�Q�3<���g6�R)�P���C�GB�Ies���@2�l���5��,#�Y�Y�asP#'0,�f��'��#��N�gx�O�Gi.
C�qL*������QJA&����C"qy&�����G��|�£��t^����A�(�|��� �IWr�l:��|:���]�y�w��C��<9$}��v�#��m��L.�A|���F 0|�x�fa}e�Bz��Y�A�I�`/�?�)���ryDE�<��q����ph�A�T �w��H�
-D�iD�5R�Q�O�Q�g�,��i���9~��E�e@��d
-�"����;�A/����s�MF`2�4<�	r����r��`3"�#�>)d�0;�}
-���<Fe�{`x��E��v`[>ϡ%�e`��@ppB&�=�1�S6����`0i�:R,��pY��BcP=6��)�@��@ey>�=J	)&���+��da��K{D��a$yxk󈠐�C�G��J�l�0ߚ�B���2��J�2L:l��.�.�R�6�qiMv�����������%�f�����,$<��bI��&P��Ұ4�,�C�ъŋN�{�Aӓ���`��h�f��3��1x`�|:�&[e� ���#�y؈_���)����<L����$�_�K�\+�Rt�`w�"�����!�EP�����@p�r���@����X��A�g�`��q������9��^N�M�Z ���f�\
-d%�6�py�i�2�"�ʀ&��C�$+lN����.	��H�R��!��
Tm�0��>>��`�ƒ�@;L� ��a���z�:�,i`��'��aJ�*���65�A"P��<⍔�=@��r9^{��,��p<��B���dE���Ve�+W*��菀Ks|
-��) n
-q��J�a��|�V� �F�0��Z�B*�CB]�����y<���PAhL��љu%���&
҂��0@U4u@*?��1�F���g�v��h��6��`�HALȴ,=`
p��lY�/��_i��r�D�,(=��m�
�泠i����<��Q�����G�s��hm�ު{�� �aM�dSid&V&�� �Av�s]v�s�������C{āB�!�U��S�""�q~.�?S�*�!��G� S�h�5���̶�\�%4�,��A��G<,q�3t�N:��#U���
�:+*"b�@
-`�M�Wk�
-�9R��
��]ӈz�����H4xhe{�gl�&`J7;���z��v����h<���	�	~H�t6����s�7z?Q��~Q
�_��
endstream
endobj
6 0 obj
[5 0 R]
endobj
20 0 obj
<</CreationDate(D:20110328132859+11'00')/Creator(Adobe Illustrator CS5)/ModDate(D:20110328132859+11'00')/Producer(Adobe PDF library 9.90)/Title(Modernizr 2 Logo)>>
endobj
xref
0 21
0000000000 65535 f
-0000000016 00000 n
-0000000144 00000 n
-0000018316 00000 n
-0000000000 00000 f
-0000020771 00000 n
-0000048490 00000 n
-0000018367 00000 n
-0000018703 00000 n
-0000021070 00000 n
-0000020957 00000 n
-0000019852 00000 n
-0000020210 00000 n
-0000020258 00000 n
-0000020841 00000 n
-0000020872 00000 n
-0000021143 00000 n
-0000021317 00000 n
-0000022336 00000 n
-0000027404 00000 n
-0000048513 00000 n
-trailer
<</Size 21/Root 1 0 R/Info 20 0 R/ID[<8D44613111B047A982BB568568FC0997><DE399FA33D7D4432BF16917DBD7AD64E>]>>
startxref
48693
%%EOF
\ No newline at end of file
diff --git a/media/Modernizr 2 Logo.png b/media/Modernizr 2 Logo.png
deleted file mode 100644
index 0a945de..0000000
Binary files a/media/Modernizr 2 Logo.png and /dev/null differ
diff --git a/media/Modernizr 2 Logo.svg b/media/Modernizr 2 Logo.svg
deleted file mode 100644
index 5cb6bbc..0000000
--- a/media/Modernizr 2 Logo.svg	
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Generator: Adobe Illustrator 15.0.2, SVG Export Plug-In . SVG Version: 6.00 Build 0)  -->
-<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
-<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
-	 width="600px" height="88.8px" viewBox="0 0 600 88.8" enable-background="new 0 0 600 88.8" xml:space="preserve">
-<g>
-	<polygon fill-rule="evenodd" clip-rule="evenodd" fill="#D91B77" points="0,86.4 0,57.6 28.8,57.6 28.8,28.8 57.6,28.8 57.6,0 
-		86.4,0 86.4,86.4 	"/>
-	<path fill-rule="evenodd" clip-rule="evenodd" fill="#D91B77" d="M93.6,0C141.318,0,180,38.683,180,86.399H93.6V0z"/>
-	<path fill="#D91B77" d="M580.505,50.198c-4.061,0-9.504,3.283-11.405,6.652v29.549h-6.479V44.668h6.479v6.653
-		c3.37-4.319,8.208-7.603,13.911-7.603v6.653C582.232,50.284,581.455,50.198,580.505,50.198z"/>
-	<polygon fill="#D91B77" points="551.648,86.399 519.854,86.399 519.854,81.303 542.836,50.371 519.854,50.371 519.854,44.668 
-		551.303,44.668 551.303,49.594 528.147,80.697 551.648,80.697 	"/>
-	<rect x="502.401" y="44.668" fill="#D91B77" width="6.479" height="41.731"/>
-	<path fill="#D91B77" d="M505.685,38.707c-2.42,0-4.407-1.901-4.407-4.32c0-2.419,1.987-4.407,4.407-4.407
-		c2.419,0,4.319,1.988,4.319,4.407C510.004,36.806,508.104,38.707,505.685,38.707z"/>
-	<path fill="#D91B77" d="M482.963,86.399V59.098c0-7.431-3.803-9.678-9.418-9.678c-5.098,0-9.85,3.111-12.355,6.48v30.499h-6.48
-		V44.668h6.48v6.048c2.938-3.542,8.64-7.084,14.947-7.084c8.64,0,13.219,4.407,13.219,13.479v29.289H482.963z"/>
-	<path fill="#D91B77" d="M444.083,50.198c-4.061,0-9.504,3.283-11.404,6.652v29.549h-6.479V44.668h6.479v6.653
-		c3.369-4.319,8.208-7.603,13.911-7.603v6.653C445.812,50.284,445.034,50.198,444.083,50.198z"/>
-	<polygon fill="#D91B77" points="258.067,86.399 258.067,37.93 238.541,86.399 235.604,86.399 215.991,37.93 215.991,86.399 
-		208.819,86.399 208.819,28.771 219.101,28.771 237.072,73.181 254.957,28.771 265.239,28.771 265.239,86.399 	"/>
-	<path fill="#D91B77" d="M415.746,66.01c0-12.528-7.431-22.378-20.046-22.378c-11.923,0-20.562,9.763-20.562,21.86
-		c0,13.047,8.898,21.945,21.341,21.945c6.739,0,12.355-2.333,16.589-6.479l-3.111-4.234c-3.369,3.456-8.121,5.356-12.96,5.356
-		c-8.985,0-14.429-6.565-14.946-14.428h33.696V66.01z M381.963,62.812c0.346-6.307,4.752-13.824,13.651-13.824
-		c9.504,0,13.651,7.69,13.737,13.824H381.963z"/>
-	<path fill="#D91B77" d="M358.117,28.771v22.205c-3.37-4.579-8.468-7.344-14.084-7.344c-10.887,0-18.575,8.554-18.575,21.946
-		c0,13.565,7.688,21.859,18.575,21.859c5.876,0,10.974-3.023,14.084-7.258v6.221h6.479V28.771H358.117z M358.117,74.995
-		c-2.247,3.628-7.344,6.652-12.442,6.652c-8.467,0-13.478-6.825-13.478-16.07s5.011-16.157,13.478-16.157
-		c5.099,0,10.195,3.111,12.442,6.739V74.995z"/>
-	<path fill="#D91B77" d="M296.687,43.631c-12.701,0-20.649,9.763-20.649,21.86c0,12.096,7.948,21.945,20.649,21.945
-		s20.65-9.85,20.65-21.945C317.337,53.395,309.388,43.631,296.687,43.631z M296.687,81.647c-8.899,0-13.824-7.603-13.824-16.156
-		c0-8.468,4.925-16.071,13.824-16.071c8.9,0,13.824,7.604,13.824,16.071C310.511,74.045,305.587,81.647,296.687,81.647z"/>
-</g>
-</svg>
diff --git a/modernizr.js b/modernizr.js
deleted file mode 100644
index 56a0022..0000000
--- a/modernizr.js
+++ /dev/null
@@ -1,1393 +0,0 @@
-/*!
- * Modernizr v2.6.2
- * www.modernizr.com
- *
- * Copyright (c) Faruk Ates, Paul Irish, Alex Sexton
- * Available under the BSD and MIT licenses: www.modernizr.com/license/
- */
-
-/*
- * Modernizr tests which native CSS3 and HTML5 features are available in
- * the current UA and makes the results available to you in two ways:
- * as properties on a global Modernizr object, and as classes on the
- * <html> element. This information allows you to progressively enhance
- * your pages with a granular level of control over the experience.
- *
- * Modernizr has an optional (not included) conditional resource loader
- * called Modernizr.load(), based on Yepnope.js (yepnopejs.com).
- * To get a build that includes Modernizr.load(), as well as choosing
- * which tests to include, go to www.modernizr.com/download/
- *
- * Authors        Faruk Ates, Paul Irish, Alex Sexton
- * Contributors   Ryan Seddon, Ben Alman
- */
-
-window.Modernizr = (function( window, document, undefined ) {
-
-    var version = '2.6.2',
-
-    Modernizr = {},
-
-    /*>>cssclasses*/
-    // option for enabling the HTML classes to be added
-    enableClasses = true,
-    /*>>cssclasses*/
-
-    docElement = document.documentElement,
-
-    /**
-     * Create our "modernizr" element that we do most feature tests on.
-     */
-    mod = 'modernizr',
-    modElem = document.createElement(mod),
-    mStyle = modElem.style,
-
-    /**
-     * Create the input element for various Web Forms feature tests.
-     */
-    inputElem /*>>inputelem*/ = document.createElement('input') /*>>inputelem*/ ,
-
-    /*>>smile*/
-    smile = ':)',
-    /*>>smile*/
-
-    toString = {}.toString,
-
-    // TODO :: make the prefixes more granular
-    /*>>prefixes*/
-    // List of property values to set for css tests. See ticket #21
-    prefixes = ' -webkit- -moz- -o- -ms- '.split(' '),
-    /*>>prefixes*/
-
-    /*>>domprefixes*/
-    // Following spec is to expose vendor-specific style properties as:
-    //   elem.style.WebkitBorderRadius
-    // and the following would be incorrect:
-    //   elem.style.webkitBorderRadius
-
-    // Webkit ghosts their properties in lowercase but Opera & Moz do not.
-    // Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
-    //   erik.eae.net/archives/2008/03/10/21.48.10/
-
-    // More here: github.com/Modernizr/Modernizr/issues/issue/21
-    omPrefixes = 'Webkit Moz O ms',
-
-    cssomPrefixes = omPrefixes.split(' '),
-
-    domPrefixes = omPrefixes.toLowerCase().split(' '),
-    /*>>domprefixes*/
-
-    /*>>ns*/
-    ns = {'svg': 'http://www.w3.org/2000/svg'},
-    /*>>ns*/
-
-    tests = {},
-    inputs = {},
-    attrs = {},
-
-    classes = [],
-
-    slice = classes.slice,
-
-    featureName, // used in testing loop
-
-
-    /*>>teststyles*/
-    // Inject element with style element and some CSS rules
-    injectElementWithStyles = function( rule, callback, nodes, testnames ) {
-
-      var style, ret, node, docOverflow,
-          div = document.createElement('div'),
-          // After page load injecting a fake body doesn't work so check if body exists
-          body = document.body,
-          // IE6 and 7 won't return offsetWidth or offsetHeight unless it's in the body element, so we fake it.
-          fakeBody = body || document.createElement('body');
-
-      if ( parseInt(nodes, 10) ) {
-          // In order not to give false positives we create a node for each test
-          // This also allows the method to scale for unspecified uses
-          while ( nodes-- ) {
-              node = document.createElement('div');
-              node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
-              div.appendChild(node);
-          }
-      }
-
-      // <style> elements in IE6-9 are considered 'NoScope' elements and therefore will be removed
-      // when injected with innerHTML. To get around this you need to prepend the 'NoScope' element
-      // with a 'scoped' element, in our case the soft-hyphen entity as it won't mess with our measurements.
-      // msdn.microsoft.com/en-us/library/ms533897%28VS.85%29.aspx
-      // Documents served as xml will throw if using &shy; so use xml friendly encoded version. See issue #277
-      style = ['&#173;','<style id="s', mod, '">', rule, '</style>'].join('');
-      div.id = mod;
-      // 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.
-      // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
-      (body ? div : fakeBody).innerHTML += style;
-      fakeBody.appendChild(div);
-      if ( !body ) {
-          //avoid crashing IE8, if background image is used
-          fakeBody.style.background = '';
-          //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
-          fakeBody.style.overflow = 'hidden';
-          docOverflow = docElement.style.overflow;
-          docElement.style.overflow = 'hidden';
-          docElement.appendChild(fakeBody);
-      }
-
-      ret = callback(div, rule);
-      // If this is done after page load we don't want to remove the body so check if body exists
-      if ( !body ) {
-          fakeBody.parentNode.removeChild(fakeBody);
-          docElement.style.overflow = docOverflow;
-      } else {
-          div.parentNode.removeChild(div);
-      }
-
-      return !!ret;
-
-    },
-    /*>>teststyles*/
-
-    /*>>mq*/
-    // adapted from matchMedia polyfill
-    // by Scott Jehl and Paul Irish
-    // gist.github.com/786768
-    testMediaQuery = function( mq ) {
-
-      var matchMedia = window.matchMedia || window.msMatchMedia;
-      if ( matchMedia ) {
-        return matchMedia(mq).matches;
-      }
-
-      var bool;
-
-      injectElementWithStyles('@media ' + mq + ' { #' + mod + ' { position: absolute; } }', function( node ) {
-        bool = (window.getComputedStyle ?
-                  getComputedStyle(node, null) :
-                  node.currentStyle)['position'] == 'absolute';
-      });
-
-      return bool;
-
-     },
-     /*>>mq*/
-
-
-    /*>>hasevent*/
-    //
-    // isEventSupported determines if a given element supports the given event
-    // kangax.github.com/iseventsupported/
-    //
-    // The following results are known incorrects:
-    //   Modernizr.hasEvent("webkitTransitionEnd", elem) // false negative
-    //   Modernizr.hasEvent("textInput") // in Webkit. github.com/Modernizr/Modernizr/issues/333
-    //   ...
-    isEventSupported = (function() {
-
-      var TAGNAMES = {
-        'select': 'input', 'change': 'input',
-        'submit': 'form', 'reset': 'form',
-        'error': 'img', 'load': 'img', 'abort': 'img'
-      };
-
-      function isEventSupported( eventName, element ) {
-
-        element = element || document.createElement(TAGNAMES[eventName] || 'div');
-        eventName = 'on' + eventName;
-
-        // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and "resize", whereas `in` "catches" those
-        var isSupported = eventName in element;
-
-        if ( !isSupported ) {
-          // If it has no `setAttribute` (i.e. doesn't implement Node interface), try generic element
-          if ( !element.setAttribute ) {
-            element = document.createElement('div');
-          }
-          if ( element.setAttribute && element.removeAttribute ) {
-            element.setAttribute(eventName, '');
-            isSupported = is(element[eventName], 'function');
-
-            // If property was created, "remove it" (by setting value to `undefined`)
-            if ( !is(element[eventName], 'undefined') ) {
-              element[eventName] = undefined;
-            }
-            element.removeAttribute(eventName);
-          }
-        }
-
-        element = null;
-        return isSupported;
-      }
-      return isEventSupported;
-    })(),
-    /*>>hasevent*/
-
-    // TODO :: Add flag for hasownprop ? didn't last time
-
-    // hasOwnProperty shim by kangax needed for Safari 2.0 support
-    _hasOwnProperty = ({}).hasOwnProperty, hasOwnProp;
-
-    if ( !is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined') ) {
-      hasOwnProp = function (object, property) {
-        return _hasOwnProperty.call(object, property);
-      };
-    }
-    else {
-      hasOwnProp = function (object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
-        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
-      };
-    }
-
-    // Adapted from ES5-shim https://github.com/kriskowal/es5-shim/blob/master/es5-shim.js
-    // es5.github.com/#x15.3.4.5
-
-    if (!Function.prototype.bind) {
-      Function.prototype.bind = function bind(that) {
-
-        var target = this;
-
-        if (typeof target != "function") {
-            throw new TypeError();
-        }
-
-        var args = slice.call(arguments, 1),
-            bound = function () {
-
-            if (this instanceof bound) {
-
-              var F = function(){};
-              F.prototype = target.prototype;
-              var self = new F();
-
-              var result = target.apply(
-                  self,
-                  args.concat(slice.call(arguments))
-              );
-              if (Object(result) === result) {
-                  return result;
-              }
-              return self;
-
-            } else {
-
-              return target.apply(
-                  that,
-                  args.concat(slice.call(arguments))
-              );
-
-            }
-
-        };
-
-        return bound;
-      };
-    }
-
-    /**
-     * setCss applies given styles to the Modernizr DOM node.
-     */
-    function setCss( str ) {
-        mStyle.cssText = str;
-    }
-
-    /**
-     * setCssAll extrapolates all vendor-specific css strings.
-     */
-    function setCssAll( str1, str2 ) {
-        return setCss(prefixes.join(str1 + ';') + ( str2 || '' ));
-    }
-
-    /**
-     * is returns a boolean for if typeof obj is exactly type.
-     */
-    function is( obj, type ) {
-        return typeof obj === type;
-    }
-
-    /**
-     * contains returns a boolean for if substr is found within str.
-     */
-    function contains( str, substr ) {
-        return !!~('' + str).indexOf(substr);
-    }
-
-    /*>>testprop*/
-
-    // testProps is a generic CSS / DOM property test.
-
-    // In testing support for a given CSS property, it's legit to test:
-    //    `elem.style[styleName] !== undefined`
-    // If the property is supported it will return an empty string,
-    // if unsupported it will return undefined.
-
-    // We'll take advantage of this quick test and skip setting a style
-    // on our modernizr element, but instead just testing undefined vs
-    // empty string.
-
-    // Because the testing of the CSS property names (with "-", as
-    // opposed to the camelCase DOM properties) is non-portable and
-    // non-standard but works in WebKit and IE (but not Gecko or Opera),
-    // we explicitly reject properties with dashes so that authors
-    // developing in WebKit or IE first don't end up with
-    // browser-specific content by accident.
-
-    function testProps( props, prefixed ) {
-        for ( var i in props ) {
-            var prop = props[i];
-            if ( !contains(prop, "-") && mStyle[prop] !== undefined ) {
-                return prefixed == 'pfx' ? prop : true;
-            }
-        }
-        return false;
-    }
-    /*>>testprop*/
-
-    // TODO :: add testDOMProps
-    /**
-     * testDOMProps is a generic DOM property test; if a browser supports
-     *   a certain property, it won't return undefined for it.
-     */
-    function testDOMProps( props, obj, elem ) {
-        for ( var i in props ) {
-            var item = obj[props[i]];
-            if ( item !== undefined) {
-
-                // return the property name as a string
-                if (elem === false) return props[i];
-
-                // let's bind a function
-                if (is(item, 'function')){
-                  // default to autobind unless override
-                  return item.bind(elem || obj);
-                }
-
-                // return the unbound function or obj or value
-                return item;
-            }
-        }
-        return false;
-    }
-
-    /*>>testallprops*/
-    /**
-     * testPropsAll tests a list of DOM properties we want to check against.
-     *   We specify literally ALL possible (known and/or likely) properties on
-     *   the element including the non-vendor prefixed one, for forward-
-     *   compatibility.
-     */
-    function testPropsAll( prop, prefixed, elem ) {
-
-        var ucProp  = prop.charAt(0).toUpperCase() + prop.slice(1),
-            props   = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
-
-        // did they call .prefixed('boxSizing') or are we just testing a prop?
-        if(is(prefixed, "string") || is(prefixed, "undefined")) {
-          return testProps(props, prefixed);
-
-        // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
-        } else {
-          props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
-          return testDOMProps(props, prefixed, elem);
-        }
-    }
-    /*>>testallprops*/
-
-
-    /**
-     * Tests
-     * -----
-     */
-
-    // The *new* flexbox
-    // dev.w3.org/csswg/css3-flexbox
-
-    tests['flexbox'] = function() {
-      return testPropsAll('flexWrap');
-    };
-
-    // The *old* flexbox
-    // www.w3.org/TR/2009/WD-css3-flexbox-20090723/
-
-    tests['flexboxlegacy'] = function() {
-        return testPropsAll('boxDirection');
-    };
-
-    // On the S60 and BB Storm, getContext exists, but always returns undefined
-    // so we actually have to call getContext() to verify
-    // github.com/Modernizr/Modernizr/issues/issue/97/
-
-    tests['canvas'] = function() {
-        var elem = document.createElement('canvas');
-        return !!(elem.getContext && elem.getContext('2d'));
-    };
-
-    tests['canvastext'] = function() {
-        return !!(Modernizr['canvas'] && is(document.createElement('canvas').getContext('2d').fillText, 'function'));
-    };
-
-    // webk.it/70117 is tracking a legit WebGL feature detect proposal
-
-    // We do a soft detect which may false positive in order to avoid
-    // an expensive context creation: bugzil.la/732441
-
-    tests['webgl'] = function() {
-        return !!window.WebGLRenderingContext;
-    };
-
-    /*
-     * The Modernizr.touch test only indicates if the browser supports
-     *    touch events, which does not necessarily reflect a touchscreen
-     *    device, as evidenced by tablets running Windows 7 or, alas,
-     *    the Palm Pre / WebOS (touch) phones.
-     *
-     * Additionally, Chrome (desktop) used to lie about its support on this,
-     *    but that has since been rectified: crbug.com/36415
-     *
-     * We also test for Firefox 4 Multitouch Support.
-     *
-     * For more info, see: modernizr.github.com/Modernizr/touch.html
-     */
-
-    tests['touch'] = function() {
-        var bool;
-
-        if(('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
-          bool = true;
-        } else {
-          injectElementWithStyles(['@media (',prefixes.join('touch-enabled),('),mod,')','{#modernizr{top:9px;position:absolute}}'].join(''), function( node ) {
-            bool = node.offsetTop === 9;
-          });
-        }
-
-        return bool;
-    };
-
-
-    // geolocation is often considered a trivial feature detect...
-    // Turns out, it's quite tricky to get right:
-    //
-    // Using !!navigator.geolocation does two things we don't want. It:
-    //   1. Leaks memory in IE9: github.com/Modernizr/Modernizr/issues/513
-    //   2. Disables page caching in WebKit: webk.it/43956
-    //
-    // Meanwhile, in Firefox < 8, an about:config setting could expose
-    // a false positive that would throw an exception: bugzil.la/688158
-
-    tests['geolocation'] = function() {
-        return 'geolocation' in navigator;
-    };
-
-
-    tests['postmessage'] = function() {
-      return !!window.postMessage;
-    };
-
-
-    // Chrome incognito mode used to throw an exception when using openDatabase
-    // It doesn't anymore.
-    tests['websqldatabase'] = function() {
-      return !!window.openDatabase;
-    };
-
-    // Vendors had inconsistent prefixing with the experimental Indexed DB:
-    // - Webkit's implementation is accessible through webkitIndexedDB
-    // - Firefox shipped moz_indexedDB before FF4b9, but since then has been mozIndexedDB
-    // For speed, we don't test the legacy (and beta-only) indexedDB
-    tests['indexedDB'] = function() {
-      return !!testPropsAll("indexedDB", window);
-    };
-
-    // documentMode logic from YUI to filter out IE8 Compat Mode
-    //   which false positives.
-    tests['hashchange'] = function() {
-      return isEventSupported('hashchange', window) && (document.documentMode === undefined || document.documentMode > 7);
-    };
-
-    // Per 1.6:
-    // This used to be Modernizr.historymanagement but the longer
-    // name has been deprecated in favor of a shorter and property-matching one.
-    // The old API is still available in 1.6, but as of 2.0 will throw a warning,
-    // and in the first release thereafter disappear entirely.
-    tests['history'] = function() {
-      return !!(window.history && history.pushState);
-    };
-
-    tests['draganddrop'] = function() {
-        var div = document.createElement('div');
-        return ('draggable' in div) || ('ondragstart' in div && 'ondrop' in div);
-    };
-
-    // FF3.6 was EOL'ed on 4/24/12, but the ESR version of FF10
-    // will be supported until FF19 (2/12/13), at which time, ESR becomes FF17.
-    // FF10 still uses prefixes, so check for it until then.
-    // for more ESR info, see: mozilla.org/en-US/firefox/organizations/faq/
-    tests['websockets'] = function() {
-        return 'WebSocket' in window || 'MozWebSocket' in window;
-    };
-
-
-    // css-tricks.com/rgba-browser-support/
-    tests['rgba'] = function() {
-        // Set an rgba() color and check the returned value
-
-        setCss('background-color:rgba(150,255,150,.5)');
-
-        return contains(mStyle.backgroundColor, 'rgba');
-    };
-
-    tests['hsla'] = function() {
-        // Same as rgba(), in fact, browsers re-map hsla() to rgba() internally,
-        //   except IE9 who retains it as hsla
-
-        setCss('background-color:hsla(120,40%,100%,.5)');
-
-        return contains(mStyle.backgroundColor, 'rgba') || contains(mStyle.backgroundColor, 'hsla');
-    };
-
-    tests['multiplebgs'] = function() {
-        // Setting multiple images AND a color on the background shorthand property
-        //  and then querying the style.background property value for the number of
-        //  occurrences of "url(" is a reliable method for detecting ACTUAL support for this!
-
-        setCss('background:url(https://),url(https://),red url(https://)');
-
-        // If the UA supports multiple backgrounds, there should be three occurrences
-        //   of the string "url(" in the return value for elemStyle.background
-
-        return (/(url\s*\(.*?){3}/).test(mStyle.background);
-    };
-
-
-
-    // this will false positive in Opera Mini
-    //   github.com/Modernizr/Modernizr/issues/396
-
-    tests['backgroundsize'] = function() {
-        return testPropsAll('backgroundSize');
-    };
-
-    tests['borderimage'] = function() {
-        return testPropsAll('borderImage');
-    };
-
-
-    // Super comprehensive table about all the unique implementations of
-    // border-radius: muddledramblings.com/table-of-css3-border-radius-compliance
-
-    tests['borderradius'] = function() {
-        return testPropsAll('borderRadius');
-    };
-
-    // WebOS unfortunately false positives on this test.
-    tests['boxshadow'] = function() {
-        return testPropsAll('boxShadow');
-    };
-
-    // FF3.0 will false positive on this test
-    tests['textshadow'] = function() {
-        return document.createElement('div').style.textShadow === '';
-    };
-
-
-    tests['opacity'] = function() {
-        // Browsers that actually have CSS Opacity implemented have done so
-        //  according to spec, which means their return values are within the
-        //  range of [0.0,1.0] - including the leading zero.
-
-        setCssAll('opacity:.55');
-
-        // The non-literal . in this regex is intentional:
-        //   German Chrome returns this value as 0,55
-        // github.com/Modernizr/Modernizr/issues/#issue/59/comment/516632
-        return (/^0.55$/).test(mStyle.opacity);
-    };
-
-
-    // Note, Android < 4 will pass this test, but can only animate
-    //   a single property at a time
-    //   daneden.me/2011/12/putting-up-with-androids-bullshit/
-    tests['cssanimations'] = function() {
-        return testPropsAll('animationName');
-    };
-
-
-    tests['csscolumns'] = function() {
-        return testPropsAll('columnCount');
-    };
-
-
-    tests['cssgradients'] = function() {
-        /**
-         * For CSS Gradients syntax, please see:
-         * webkit.org/blog/175/introducing-css-gradients/
-         * developer.mozilla.org/en/CSS/-moz-linear-gradient
-         * developer.mozilla.org/en/CSS/-moz-radial-gradient
-         * dev.w3.org/csswg/css3-images/#gradients-
-         */
-
-        var str1 = 'background-image:',
-            str2 = 'gradient(linear,left top,right bottom,from(#9f9),to(white));',
-            str3 = 'linear-gradient(left top,#9f9, white);';
-
-        setCss(
-             // legacy webkit syntax (FIXME: remove when syntax not in use anymore)
-              (str1 + '-webkit- '.split(' ').join(str2 + str1) +
-             // standard syntax             // trailing 'background-image:'
-              prefixes.join(str3 + str1)).slice(0, -str1.length)
-        );
-
-        return contains(mStyle.backgroundImage, 'gradient');
-    };
-
-
-    tests['cssreflections'] = function() {
-        return testPropsAll('boxReflect');
-    };
-
-
-    tests['csstransforms'] = function() {
-        return !!testPropsAll('transform');
-    };
-
-
-    tests['csstransforms3d'] = function() {
-
-        var ret = !!testPropsAll('perspective');
-
-        // Webkit's 3D transforms are passed off to the browser's own graphics renderer.
-        //   It works fine in Safari on Leopard and Snow Leopard, but not in Chrome in
-        //   some conditions. As a result, Webkit typically recognizes the syntax but
-        //   will sometimes throw a false positive, thus we must do a more thorough check:
-        if ( ret && 'webkitPerspective' in docElement.style ) {
-
-          // Webkit allows this media query to succeed only if the feature is enabled.
-          // `@media (transform-3d),(-webkit-transform-3d){ ... }`
-          injectElementWithStyles('@media (transform-3d),(-webkit-transform-3d){#modernizr{left:9px;position:absolute;height:3px;}}', function( node, rule ) {
-            ret = node.offsetLeft === 9 && node.offsetHeight === 3;
-          });
-        }
-        return ret;
-    };
-
-
-    tests['csstransitions'] = function() {
-        return testPropsAll('transition');
-    };
-
-
-    /*>>fontface*/
-    // @font-face detection routine by Diego Perini
-    // javascript.nwbox.com/CSSSupport/
-
-    // false positives:
-    //   WebOS github.com/Modernizr/Modernizr/issues/342
-    //   WP7   github.com/Modernizr/Modernizr/issues/538
-    tests['fontface'] = function() {
-        var bool;
-
-        injectElementWithStyles('@font-face {font-family:"font";src:url("https://")}', function( node, rule ) {
-          var style = document.getElementById('smodernizr'),
-              sheet = style.sheet || style.styleSheet,
-              cssText = sheet ? (sheet.cssRules && sheet.cssRules[0] ? sheet.cssRules[0].cssText : sheet.cssText || '') : '';
-
-          bool = /src/i.test(cssText) && cssText.indexOf(rule.split(' ')[0]) === 0;
-        });
-
-        return bool;
-    };
-    /*>>fontface*/
-
-    // CSS generated content detection
-    tests['generatedcontent'] = function() {
-        var bool;
-
-        injectElementWithStyles(['#',mod,'{font:0/0 a}#',mod,':after{content:"',smile,'";visibility:hidden;font:3px/1 a}'].join(''), function( node ) {
-          bool = node.offsetHeight >= 3;
-        });
-
-        return bool;
-    };
-
-
-
-    // These tests evaluate support of the video/audio elements, as well as
-    // testing what types of content they support.
-    //
-    // We're using the Boolean constructor here, so that we can extend the value
-    // e.g.  Modernizr.video     // true
-    //       Modernizr.video.ogg // 'probably'
-    //
-    // Codec values from : github.com/NielsLeenheer/html5test/blob/9106a8/index.html#L845
-    //                     thx to NielsLeenheer and zcorpan
-
-    // Note: in some older browsers, "no" was a return value instead of empty string.
-    //   It was live in FF3.5.0 and 3.5.1, but fixed in 3.5.2
-    //   It was also live in Safari 4.0.0 - 4.0.4, but fixed in 4.0.5
-
-    tests['video'] = function() {
-        var elem = document.createElement('video'),
-            bool = false;
-
-        // IE9 Running on Windows Server SKU can cause an exception to be thrown, bug #224
-        try {
-            if ( bool = !!elem.canPlayType ) {
-                bool      = new Boolean(bool);
-                bool.ogg  = elem.canPlayType('video/ogg; codecs="theora"')      .replace(/^no$/,'');
-
-                // Without QuickTime, this value will be `undefined`. github.com/Modernizr/Modernizr/issues/546
-                bool.h264 = elem.canPlayType('video/mp4; codecs="avc1.42E01E"') .replace(/^no$/,'');
-
-                bool.webm = elem.canPlayType('video/webm; codecs="vp8, vorbis"').replace(/^no$/,'');
-            }
-
-        } catch(e) { }
-
-        return bool;
-    };
-
-    tests['audio'] = function() {
-        var elem = document.createElement('audio'),
-            bool = false;
-
-        try {
-            if ( bool = !!elem.canPlayType ) {
-                bool      = new Boolean(bool);
-                bool.ogg  = elem.canPlayType('audio/ogg; codecs="vorbis"').replace(/^no$/,'');
-                bool.mp3  = elem.canPlayType('audio/mpeg;')               .replace(/^no$/,'');
-
-                // Mimetypes accepted:
-                //   developer.mozilla.org/En/Media_formats_supported_by_the_audio_and_video_elements
-                //   bit.ly/iphoneoscodecs
-                bool.wav  = elem.canPlayType('audio/wav; codecs="1"')     .replace(/^no$/,'');
-                bool.m4a  = ( elem.canPlayType('audio/x-m4a;')            ||
-                              elem.canPlayType('audio/aac;'))             .replace(/^no$/,'');
-            }
-        } catch(e) { }
-
-        return bool;
-    };
-
-
-    // In FF4, if disabled, window.localStorage should === null.
-
-    // Normally, we could not test that directly and need to do a
-    //   `('localStorage' in window) && ` test first because otherwise Firefox will
-    //   throw bugzil.la/365772 if cookies are disabled
-
-    // Also in iOS5 Private Browsing mode, attempting to use localStorage.setItem
-    // will throw the exception:
-    //   QUOTA_EXCEEDED_ERRROR DOM Exception 22.
-    // Peculiarly, getItem and removeItem calls do not throw.
-
-    // Because we are forced to try/catch this, we'll go aggressive.
-
-    // Just FWIW: IE8 Compat mode supports these features completely:
-    //   www.quirksmode.org/dom/html5.html
-    // But IE8 doesn't support either with local files
-
-    tests['localstorage'] = function() {
-        try {
-            localStorage.setItem(mod, mod);
-            localStorage.removeItem(mod);
-            return true;
-        } catch(e) {
-            return false;
-        }
-    };
-
-    tests['sessionstorage'] = function() {
-        try {
-            sessionStorage.setItem(mod, mod);
-            sessionStorage.removeItem(mod);
-            return true;
-        } catch(e) {
-            return false;
-        }
-    };
-
-
-    tests['webworkers'] = function() {
-        return !!window.Worker;
-    };
-
-
-    tests['applicationcache'] = function() {
-        return !!window.applicationCache;
-    };
-
-
-    // Thanks to Erik Dahlstrom
-    tests['svg'] = function() {
-        return !!document.createElementNS && !!document.createElementNS(ns.svg, 'svg').createSVGRect;
-    };
-
-    // specifically for SVG inline in HTML, not within XHTML
-    // test page: paulirish.com/demo/inline-svg
-    tests['inlinesvg'] = function() {
-      var div = document.createElement('div');
-      div.innerHTML = '<svg/>';
-      return (div.firstChild && div.firstChild.namespaceURI) == ns.svg;
-    };
-
-    // SVG SMIL animation
-    tests['smil'] = function() {
-        return !!document.createElementNS && /SVGAnimate/.test(toString.call(document.createElementNS(ns.svg, 'animate')));
-    };
-
-    // This test is only for clip paths in SVG proper, not clip paths on HTML content
-    // demo: srufaculty.sru.edu/david.dailey/svg/newstuff/clipPath4.svg
-
-    // However read the comments to dig into applying SVG clippaths to HTML content here:
-    //   github.com/Modernizr/Modernizr/issues/213#issuecomment-1149491
-    tests['svgclippaths'] = function() {
-        return !!document.createElementNS && /SVGClipPath/.test(toString.call(document.createElementNS(ns.svg, 'clipPath')));
-    };
-
-    /*>>webforms*/
-    // input features and input types go directly onto the ret object, bypassing the tests loop.
-    // Hold this guy to execute in a moment.
-    function webforms() {
-        /*>>input*/
-        // Run through HTML5's new input attributes to see if the UA understands any.
-        // We're using f which is the <input> element created early on
-        // Mike Taylr has created a comprehensive resource for testing these attributes
-        //   when applied to all input types:
-        //   miketaylr.com/code/input-type-attr.html
-        // spec: www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#input-type-attr-summary
-
-        // Only input placeholder is tested while textarea's placeholder is not.
-        // Currently Safari 4 and Opera 11 have support only for the input placeholder
-        // Both tests are available in feature-detects/forms-placeholder.js
-        Modernizr['input'] = (function( props ) {
-            for ( var i = 0, len = props.length; i < len; i++ ) {
-                attrs[ props[i] ] = !!(props[i] in inputElem);
-            }
-            if (attrs.list){
-              // safari false positive's on datalist: webk.it/74252
-              // see also github.com/Modernizr/Modernizr/issues/146
-              attrs.list = !!(document.createElement('datalist') && window.HTMLDataListElement);
-            }
-            return attrs;
-        })('autocomplete autofocus list placeholder max min multiple pattern required step'.split(' '));
-        /*>>input*/
-
-        /*>>inputtypes*/
-        // Run through HTML5's new input types to see if the UA understands any.
-        //   This is put behind the tests runloop because it doesn't return a
-        //   true/false like all the other tests; instead, it returns an object
-        //   containing each input type with its corresponding true/false value
-
-        // Big thanks to @miketaylr for the html5 forms expertise. miketaylr.com/
-        Modernizr['inputtypes'] = (function(props) {
-
-            for ( var i = 0, bool, inputElemType, defaultView, len = props.length; i < len; i++ ) {
-
-                inputElem.setAttribute('type', inputElemType = props[i]);
-                bool = inputElem.type !== 'text';
-
-                // We first check to see if the type we give it sticks..
-                // If the type does, we feed it a textual value, which shouldn't be valid.
-                // If the value doesn't stick, we know there's input sanitization which infers a custom UI
-                if ( bool ) {
-
-                    inputElem.value         = smile;
-                    inputElem.style.cssText = 'position:absolute;visibility:hidden;';
-
-                    if ( /^range$/.test(inputElemType) && inputElem.style.WebkitAppearance !== undefined ) {
-
-                      docElement.appendChild(inputElem);
-                      defaultView = document.defaultView;
-
-                      // Safari 2-4 allows the smiley as a value, despite making a slider
-                      bool =  defaultView.getComputedStyle &&
-                              defaultView.getComputedStyle(inputElem, null).WebkitAppearance !== 'textfield' &&
-                              // Mobile android web browser has false positive, so must
-                              // check the height to see if the widget is actually there.
-                              (inputElem.offsetHeight !== 0);
-
-                      docElement.removeChild(inputElem);
-
-                    } else if ( /^(search|tel)$/.test(inputElemType) ){
-                      // Spec doesn't define any special parsing or detectable UI
-                      //   behaviors so we pass these through as true
-
-                      // Interestingly, opera fails the earlier test, so it doesn't
-                      //  even make it here.
-
-                    } else if ( /^(url|email)$/.test(inputElemType) ) {
-                      // Real url and email support comes with prebaked validation.
-                      bool = inputElem.checkValidity && inputElem.checkValidity() === false;
-
-                    } else {
-                      // If the upgraded input compontent rejects the :) text, we got a winner
-                      bool = inputElem.value != smile;
-                    }
-                }
-
-                inputs[ props[i] ] = !!bool;
-            }
-            return inputs;
-        })('search tel url email datetime date month week time datetime-local number range color'.split(' '));
-        /*>>inputtypes*/
-    }
-    /*>>webforms*/
-
-
-    // End of test definitions
-    // -----------------------
-
-
-
-    // Run through all tests and detect their support in the current UA.
-    // todo: hypothetically we could be doing an array of tests and use a basic loop here.
-    for ( var feature in tests ) {
-        if ( hasOwnProp(tests, feature) ) {
-            // run the test, throw the return value into the Modernizr,
-            //   then based on that boolean, define an appropriate className
-            //   and push it into an array of classes we'll join later.
-            featureName  = feature.toLowerCase();
-            Modernizr[featureName] = tests[feature]();
-
-            classes.push((Modernizr[featureName] ? '' : 'no-') + featureName);
-        }
-    }
-
-    /*>>webforms*/
-    // input tests need to run.
-    Modernizr.input || webforms();
-    /*>>webforms*/
-
-
-    /**
-     * addTest allows the user to define their own feature tests
-     * the result will be added onto the Modernizr object,
-     * as well as an appropriate className set on the html element
-     *
-     * @param feature - String naming the feature
-     * @param test - Function returning true if feature is supported, false if not
-     */
-     Modernizr.addTest = function ( feature, test ) {
-       if ( typeof feature == 'object' ) {
-         for ( var key in feature ) {
-           if ( hasOwnProp( feature, key ) ) {
-             Modernizr.addTest( key, feature[ key ] );
-           }
-         }
-       } else {
-
-         feature = feature.toLowerCase();
-
-         if ( Modernizr[feature] !== undefined ) {
-           // we're going to quit if you're trying to overwrite an existing test
-           // if we were to allow it, we'd do this:
-           //   var re = new RegExp("\\b(no-)?" + feature + "\\b");
-           //   docElement.className = docElement.className.replace( re, '' );
-           // but, no rly, stuff 'em.
-           return Modernizr;
-         }
-
-         test = typeof test == 'function' ? test() : test;
-
-         if (typeof enableClasses !== "undefined" && enableClasses) {
-           docElement.className += ' ' + (test ? '' : 'no-') + feature;
-         }
-         Modernizr[feature] = test;
-
-       }
-
-       return Modernizr; // allow chaining.
-     };
-
-
-    // Reset modElem.cssText to nothing to reduce memory footprint.
-    setCss('');
-    modElem = inputElem = null;
-
-    /*>>shiv*/
-    /*! HTML5 Shiv v3.6.1 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed */
-    ;(function(window, document) {
-    /*jshint evil:true */
-      /** Preset options */
-      var options = window.html5 || {};
-
-      /** Used to skip problem elements */
-      var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
-
-      /** Not all elements can be cloned in IE **/
-      var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
-
-      /** Detect whether the browser supports default html5 styles */
-      var supportsHtml5Styles;
-
-      /** Name of the expando, to work with multiple documents or to re-shiv one document */
-      var expando = '_html5shiv';
-
-      /** The id for the the documents expando */
-      var expanID = 0;
-
-      /** Cached data for each document */
-      var expandoData = {};
-
-      /** Detect whether the browser supports unknown elements */
-      var supportsUnknownElements;
-
-      (function() {
-        try {
-            var a = document.createElement('a');
-            a.innerHTML = '<xyz></xyz>';
-            //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
-            supportsHtml5Styles = ('hidden' in a);
-
-            supportsUnknownElements = a.childNodes.length == 1 || (function() {
-              // assign a false positive if unable to shiv
-              (document.createElement)('a');
-              var frag = document.createDocumentFragment();
-              return (
-                typeof frag.cloneNode == 'undefined' ||
-                typeof frag.createDocumentFragment == 'undefined' ||
-                typeof frag.createElement == 'undefined'
-              );
-            }());
-        } catch(e) {
-          supportsHtml5Styles = true;
-          supportsUnknownElements = true;
-        }
-
-      }());
-
-      /*--------------------------------------------------------------------------*/
-
-      /**
-       * Creates a style sheet with the given CSS text and adds it to the document.
-       * @private
-       * @param {Document} ownerDocument The document.
-       * @param {String} cssText The CSS text.
-       * @returns {StyleSheet} The style element.
-       */
-      function addStyleSheet(ownerDocument, cssText) {
-        var p = ownerDocument.createElement('p'),
-            parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
-
-        p.innerHTML = 'x<style>' + cssText + '</style>';
-        return parent.insertBefore(p.lastChild, parent.firstChild);
-      }
-
-      /**
-       * Returns the value of `html5.elements` as an array.
-       * @private
-       * @returns {Array} An array of shived element node names.
-       */
-      function getElements() {
-        var elements = html5.elements;
-        return typeof elements == 'string' ? elements.split(' ') : elements;
-      }
-
-        /**
-       * Returns the data associated to the given document
-       * @private
-       * @param {Document} ownerDocument The document.
-       * @returns {Object} An object of data.
-       */
-      function getExpandoData(ownerDocument) {
-        var data = expandoData[ownerDocument[expando]];
-        if (!data) {
-            data = {};
-            expanID++;
-            ownerDocument[expando] = expanID;
-            expandoData[expanID] = data;
-        }
-        return data;
-      }
-
-      /**
-       * returns a shived element for the given nodeName and document
-       * @memberOf html5
-       * @param {String} nodeName name of the element
-       * @param {Document} ownerDocument The context document.
-       * @returns {Object} The shived element.
-       */
-      function createElement(nodeName, ownerDocument, data){
-        if (!ownerDocument) {
-            ownerDocument = document;
-        }
-        if(supportsUnknownElements){
-            return ownerDocument.createElement(nodeName);
-        }
-        if (!data) {
-            data = getExpandoData(ownerDocument);
-        }
-        var node;
-
-        if (data.cache[nodeName]) {
-            node = data.cache[nodeName].cloneNode();
-        } else if (saveClones.test(nodeName)) {
-            node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
-        } else {
-            node = data.createElem(nodeName);
-        }
-
-        // Avoid adding some elements to fragments in IE < 9 because
-        // * Attributes like `name` or `type` cannot be set/changed once an element
-        //   is inserted into a document/fragment
-        // * Link elements with `src` attributes that are inaccessible, as with
-        //   a 403 response, will cause the tab/window to crash
-        // * Script elements appended to fragments will execute when their `src`
-        //   or `text` property is set
-        return node.canHaveChildren && !reSkip.test(nodeName) ? data.frag.appendChild(node) : node;
-      }
-
-      /**
-       * returns a shived DocumentFragment for the given document
-       * @memberOf html5
-       * @param {Document} ownerDocument The context document.
-       * @returns {Object} The shived DocumentFragment.
-       */
-      function createDocumentFragment(ownerDocument, data){
-        if (!ownerDocument) {
-            ownerDocument = document;
-        }
-        if(supportsUnknownElements){
-            return ownerDocument.createDocumentFragment();
-        }
-        data = data || getExpandoData(ownerDocument);
-        var clone = data.frag.cloneNode(),
-            i = 0,
-            elems = getElements(),
-            l = elems.length;
-        for(;i<l;i++){
-            clone.createElement(elems[i]);
-        }
-        return clone;
-      }
-
-      /**
-       * Shivs the `createElement` and `createDocumentFragment` methods of the document.
-       * @private
-       * @param {Document|DocumentFragment} ownerDocument The document.
-       * @param {Object} data of the document.
-       */
-      function shivMethods(ownerDocument, data) {
-        if (!data.cache) {
-            data.cache = {};
-            data.createElem = ownerDocument.createElement;
-            data.createFrag = ownerDocument.createDocumentFragment;
-            data.frag = data.createFrag();
-        }
-
-
-        ownerDocument.createElement = function(nodeName) {
-          //abort shiv
-          if (!html5.shivMethods) {
-              return data.createElem(nodeName);
-          }
-          return createElement(nodeName, ownerDocument, data);
-        };
-
-        ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
-          'var n=f.cloneNode(),c=n.createElement;' +
-          'h.shivMethods&&(' +
-            // unroll the `createElement` calls
-            getElements().join().replace(/\w+/g, function(nodeName) {
-              data.createElem(nodeName);
-              data.frag.createElement(nodeName);
-              return 'c("' + nodeName + '")';
-            }) +
-          ');return n}'
-        )(html5, data.frag);
-      }
-
-      /*--------------------------------------------------------------------------*/
-
-      /**
-       * Shivs the given document.
-       * @memberOf html5
-       * @param {Document} ownerDocument The document to shiv.
-       * @returns {Document} The shived document.
-       */
-      function shivDocument(ownerDocument) {
-        if (!ownerDocument) {
-            ownerDocument = document;
-        }
-        var data = getExpandoData(ownerDocument);
-
-        if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
-          data.hasCSS = !!addStyleSheet(ownerDocument,
-            // corrects block display not defined in IE6/7/8/9
-            'article,aside,figcaption,figure,footer,header,hgroup,nav,section{display:block}' +
-            // adds styling not present in IE6/7/8/9
-            'mark{background:#FF0;color:#000}'
-          );
-        }
-        if (!supportsUnknownElements) {
-          shivMethods(ownerDocument, data);
-        }
-        return ownerDocument;
-      }
-
-      /*--------------------------------------------------------------------------*/
-
-      /**
-       * The `html5` object is exposed so that more elements can be shived and
-       * existing shiving can be detected on iframes.
-       * @type Object
-       * @example
-       *
-       * // options can be changed before the script is included
-       * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
-       */
-      var html5 = {
-
-        /**
-         * An array or space separated string of node names of the elements to shiv.
-         * @memberOf html5
-         * @type Array|String
-         */
-        'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details figcaption figure footer header hgroup mark meter nav output progress section summary time video',
-
-        /**
-         * A flag to indicate that the HTML5 style sheet should be inserted.
-         * @memberOf html5
-         * @type Boolean
-         */
-        'shivCSS': (options.shivCSS !== false),
-
-        /**
-         * Is equal to true if a browser supports creating unknown/HTML5 elements
-         * @memberOf html5
-         * @type boolean
-         */
-        'supportsUnknownElements': supportsUnknownElements,
-
-        /**
-         * A flag to indicate that the document's `createElement` and `createDocumentFragment`
-         * methods should be overwritten.
-         * @memberOf html5
-         * @type Boolean
-         */
-        'shivMethods': (options.shivMethods !== false),
-
-        /**
-         * A string to describe the type of `html5` object ("default" or "default print").
-         * @memberOf html5
-         * @type String
-         */
-        'type': 'default',
-
-        // shivs the document according to the specified `html5` object options
-        'shivDocument': shivDocument,
-
-        //creates a shived element
-        createElement: createElement,
-
-        //creates a shived documentFragment
-        createDocumentFragment: createDocumentFragment
-      };
-
-      /*--------------------------------------------------------------------------*/
-
-      // expose html5
-      window.html5 = html5;
-
-      // shiv the document
-      shivDocument(document);
-
-    }(this, document));
-    /*>>shiv*/
-
-    // Assign private properties to the return object with prefix
-    Modernizr._version      = version;
-
-    // expose these for the plugin API. Look in the source for how to join() them against your input
-    /*>>prefixes*/
-    Modernizr._prefixes     = prefixes;
-    /*>>prefixes*/
-    /*>>domprefixes*/
-    Modernizr._domPrefixes  = domPrefixes;
-    Modernizr._cssomPrefixes  = cssomPrefixes;
-    /*>>domprefixes*/
-
-    /*>>mq*/
-    // Modernizr.mq tests a given media query, live against the current state of the window
-    // A few important notes:
-    //   * If a browser does not support media queries at all (eg. oldIE) the mq() will always return false
-    //   * A max-width or orientation query will be evaluated against the current state, which may change later.
-    //   * You must specify values. Eg. If you are testing support for the min-width media query use:
-    //       Modernizr.mq('(min-width:0)')
-    // usage:
-    // Modernizr.mq('only screen and (max-width:768)')
-    Modernizr.mq            = testMediaQuery;
-    /*>>mq*/
-
-    /*>>hasevent*/
-    // Modernizr.hasEvent() detects support for a given event, with an optional element to test on
-    // Modernizr.hasEvent('gesturestart', elem)
-    Modernizr.hasEvent      = isEventSupported;
-    /*>>hasevent*/
-
-    /*>>testprop*/
-    // Modernizr.testProp() investigates whether a given style property is recognized
-    // Note that the property names must be provided in the camelCase variant.
-    // Modernizr.testProp('pointerEvents')
-    Modernizr.testProp      = function(prop){
-        return testProps([prop]);
-    };
-    /*>>testprop*/
-
-    /*>>testallprops*/
-    // Modernizr.testAllProps() investigates whether a given style property,
-    //   or any of its vendor-prefixed variants, is recognized
-    // Note that the property names must be provided in the camelCase variant.
-    // Modernizr.testAllProps('boxSizing')
-    Modernizr.testAllProps  = testPropsAll;
-    /*>>testallprops*/
-
-
-    /*>>teststyles*/
-    // Modernizr.testStyles() allows you to add custom styles to the document and test an element afterwards
-    // Modernizr.testStyles('#modernizr { position:absolute }', function(elem, rule){ ... })
-    Modernizr.testStyles    = injectElementWithStyles;
-    /*>>teststyles*/
-
-
-    /*>>prefixed*/
-    // Modernizr.prefixed() returns the prefixed or nonprefixed property name variant of your input
-    // Modernizr.prefixed('boxSizing') // 'MozBoxSizing'
-
-    // Properties must be passed as dom-style camelcase, rather than `box-sizing` hypentated style.
-    // Return values will also be the camelCase variant, if you need to translate that to hypenated style use:
-    //
-    //     str.replace(/([A-Z])/g, function(str,m1){ return '-' + m1.toLowerCase(); }).replace(/^ms-/,'-ms-');
-
-    // If you're trying to ascertain which transition end event to bind to, you might do something like...
-    //
-    //     var transEndEventNames = {
-    //       'WebkitTransition' : 'webkitTransitionEnd',
-    //       'MozTransition'    : 'transitionend',
-    //       'OTransition'      : 'oTransitionEnd',
-    //       'msTransition'     : 'MSTransitionEnd',
-    //       'transition'       : 'transitionend'
-    //     },
-    //     transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
-
-    Modernizr.prefixed      = function(prop, obj, elem){
-      if(!obj) {
-        return testPropsAll(prop, 'pfx');
-      } else {
-        // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
-        return testPropsAll(prop, obj, elem);
-      }
-    };
-    /*>>prefixed*/
-
-
-    /*>>cssclasses*/
-    // Remove "no-js" class from <html> element, if it exists:
-    docElement.className = docElement.className.replace(/(^|\s)no-js(\s|$)/, '$1$2') +
-
-                            // Add the new classes to the <html> element.
-                            (enableClasses ? ' js ' + classes.join(' ') : '');
-    /*>>cssclasses*/
-
-    return Modernizr;
-
-})(this, this.document);
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..f866e2e
--- /dev/null
+++ b/package.json
@@ -0,0 +1,118 @@
+{
+  "name": "modernizr",
+  "version": "4.0.0-alpha",
+  "description": "Modernizr is a JavaScript library that detects HTML5 and CSS3 features in the user’s browser.",
+  "main": "./lib/cli.js",
+  "bin": "./bin/modernizr",
+  "bugs": "https://github.com/Modernizr/Modernizr/issues",
+  "homepage": "https://github.com/Modernizr/Modernizr",
+  "repository": "https://github.com/Modernizr/Modernizr.git",
+  "license": "MIT",
+  "author": {
+    "name": "Modernizr",
+    "url": "https://modernizr.com/"
+  },
+  "contributors": [
+    {
+      "name": "Faruk Ates",
+      "url": "https://twitter.com/KuraFire"
+    },
+    {
+      "name": "Paul Irish",
+      "url": "https://twitter.com/paul_irish"
+    },
+    {
+      "name": "Alex Sexton",
+      "url": "https://twitter.com/SlexAxton"
+    },
+    {
+      "name": "Ryan Seddon",
+      "url": "https://twitter.com/ryanseddon"
+    },
+    {
+      "name": "Patrick Kettner",
+      "url": "https://twitter.com/patrickkettner"
+    },
+    {
+      "name": "Stu Cox",
+      "url": "https://twitter.com/stucoxmedia"
+    },
+    {
+      "name": "Richard Herrera",
+      "url": "https://twitter.com/doctyper"
+    },
+    {
+      "name": "Veeck",
+      "url": "https://twitter.com/hansalbern"
+    }
+  ],
+  "dependencies": {
+    "doctrine": "^3.0.0",
+    "file": "^0.2.2",
+    "lodash": "^4.17.21",
+    "markdown-it": "^12.2.0",
+    "mkdirp": "1.0.4",
+    "requirejs": "^2.3.6",
+    "yargs": "^17.5.1"
+  },
+  "devDependencies": {
+    "@babel/core": "^7.19.0",
+    "@babel/preset-env": "^7.19.0",
+    "@babel/register": "^7.18.9",
+    "auto-changelog": "^2.4.0",
+    "chai": "^4.3.6",
+    "codecov": "^3.8.3",
+    "del": "^6.0.0",
+    "eslint": "^7.32.0",
+    "eslint-plugin-jsdoc": "^36.1.1",
+    "find-parent-dir": "^0.3.1",
+    "fs-extra": "^10.1.0",
+    "globby": "^11.0.4",
+    "gulp": "^4.0.2",
+    "gulp-connect": "^5.7.0",
+    "gulp-eslint": "^6.0.0",
+    "gulp-pug": "^5.0.0",
+    "joi": "^17.6.0",
+    "jquery": "^3.6.1",
+    "json3": "^3.3.3",
+    "mocha": "^9.1.2",
+    "mocha-headless-chrome": "^4.0.0",
+    "nyc": "^15.1.0",
+    "proxyquire": "^2.1.3",
+    "serve-static": "^1.15.0",
+    "sinon": "^11.1.2",
+    "ua-parser-js": "^0.7.28"
+  },
+  "scripts": {
+    "--- DEFAULT SCRIPTS ---": "",
+    "start": "gulp default",
+    "test": "nyc gulp test",
+    "--- GULP SCRIPTS ---": "",
+    "clean": "gulp clean",
+    "lint": "gulp eslint",
+    "--- MODERNIZR SCRIPTS ---": "",
+    "serve-gh-pages": "gulp serve:gh-pages",
+    "update-gh-pages": "scripts/generate-gh-pages.sh",
+    "update-changelog": "auto-changelog --commit-limit false --package",
+    "update-license": "node scripts/generate-license.js && git add LICENSE"
+  },
+  "engines": {
+    "node": ">=12"
+  },
+  "files": [
+    "LICENSE",
+    "README.md",
+    "bin/",
+    "feature-detects/",
+    "lib/",
+    "src/"
+  ],
+  "keywords": [
+    "modernizr",
+    "html5",
+    "css3",
+    "javascript",
+    "browser",
+    "feature detection"
+  ]
+}
diff --git a/readme.md b/readme.md
deleted file mode 100644
index e025d02..0000000
--- a/readme.md
+++ /dev/null
@@ -1,28 +0,0 @@
-Modernizr [![Build Status](https://secure.travis-ci.org/Modernizr/Modernizr.png?branch=master)](http://travis-ci.org/Modernizr/Modernizr)
-=========
-
-### a JavaScript library allowing you to use CSS3 & HTML5 while maintaining control over unsupported browsers 
-
-Modernizr tests which native CSS3 and HTML5 features are available in
-the current UA and makes the results available to you in two ways:
-as properties on a global `Modernizr` object, and as classes on the
-`<html>` element. This information allows you to progressively enhance
-your pages with a granular level of control over the experience.
-
-Modernizr has an optional (*not included*) conditional resource loader
-called `Modernizr.load()`, based on Yepnope.js ([yepnopejs.com](http://yepnopejs.com/)).
-To get a build that includes `Modernizr.load()`, as well as choosing
-which tests to include, go to [www.modernizr.com/download/](http://www.modernizr.com/download/)
-
-[Full documentation on modernizr.com/docs/](http://www.modernizr.com/docs/)
-
-* * *
-
-Modernizr is dual-licensed under the [BSD and MIT licenses](http://www.modernizr.com/license/).
-
-[modernizr.com](http://www.modernizr.com/)
-
-
-#### Try it out: 
-
-Run the test suite: [http://modernizr.github.com/Modernizr/test/](http://modernizr.github.com/Modernizr/test/)
diff --git a/src/Modernizr.js b/src/Modernizr.js
new file mode 100644
index 0000000..fa5499a
--- /dev/null
+++ b/src/Modernizr.js
@@ -0,0 +1,11 @@
+define(['ModernizrProto'], function(ModernizrProto) {
+  // Fake some of Object.create so we can force non test results to be non "own" properties.
+  var Modernizr = function() {};
+  Modernizr.prototype = ModernizrProto;
+
+  // Leak modernizr globally when you `require` it rather than force it here.
+  // Overwrite name so constructor name is nicer :D
+  Modernizr = new Modernizr();
+
+  return Modernizr;
+});
diff --git a/src/ModernizrProto.js b/src/ModernizrProto.js
new file mode 100644
index 0000000..f14c2b0
--- /dev/null
+++ b/src/ModernizrProto.js
@@ -0,0 +1,47 @@
+define(['tests'], function(tests) {
+  /**
+   * ModernizrProto is the constructor for Modernizr
+   *
+   * @class
+   * @access public
+   */
+  var ModernizrProto = {
+    _version: '__VERSION__',
+
+    // Any settings that don't work as separate modules
+    // can go in here as configuration.
+    _config: {
+      'classPrefix': '',
+      'enableClasses': true,
+      'enableJSClass': true,
+      'usePrefixes': true
+    },
+
+    // Queue of tests
+    _q: [],
+
+    // Stub these for people who are listening
+    on: function(test, cb) {
+      // I don't really think people should do this, but we can
+      // safe guard it a bit.
+      // -- NOTE:: this gets WAY overridden in src/addTest for actual async tests.
+      // This is in case people listen to synchronous tests. I would leave it out,
+      // but the code to *disallow* sync tests in the real version of this
+      // function is actually larger than this.
+      var self = this;
+      setTimeout(function() {
+        cb(self[test]);
+      }, 0);
+    },
+
+    addTest: function(name, fn, options) {
+      tests.push({name: name, fn: fn, options: options});
+    },
+
+    addAsyncTest: function(fn) {
+      tests.push({name: null, fn: fn});
+    }
+  };
+
+  return ModernizrProto;
+});
diff --git a/src/addTest.js b/src/addTest.js
new file mode 100644
index 0000000..d979a3c
--- /dev/null
+++ b/src/addTest.js
@@ -0,0 +1,209 @@
+define(['ModernizrProto', 'Modernizr', 'hasOwnProp', 'setClasses'], function(ModernizrProto, Modernizr, hasOwnProp, setClasses) {
+
+  // _l tracks listeners for async tests, as well as tests that execute after the initial run
+  ModernizrProto._l = {};
+
+  /**
+   * Modernizr.on is a way to listen for the completion of async tests. Being
+   * asynchronous, they may not finish before your scripts run. As a result you
+   * will get a possibly false negative `undefined` value.
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.on
+   * @access public
+   * @function on
+   * @param {string} feature - String name of the feature detect
+   * @param {Function} cb - Callback function returning a Boolean - true if feature is supported, false if not
+   * @returns {void}
+   * @example
+   *
+   * ```js
+   * Modernizr.on('flash', function( result ) {
+   *   if (result) {
+   *    // the browser has flash
+   *   } else {
+   *     // the browser does not have flash
+   *   }
+   * });
+   * ```
+   */
+  ModernizrProto.on = function(feature, cb) {
+    // Create the list of listeners if it doesn't exist
+    if (!this._l[feature]) {
+      this._l[feature] = [];
+    }
+
+    // Push this test on to the listener list
+    this._l[feature].push(cb);
+
+    // If it's already been resolved, trigger it on next tick
+    if (Modernizr.hasOwnProperty(feature)) {
+      // Next Tick
+      setTimeout(function() {
+        Modernizr._trigger(feature, Modernizr[feature]);
+      }, 0);
+    }
+  };
+
+  /**
+   * _trigger is the private function used to signal test completion and run any
+   * callbacks registered through [Modernizr.on](#modernizr-on)
+   *
+   * @memberOf Modernizr
+   * @name Modernizr._trigger
+   * @access private
+   * @function _trigger
+   * @param {string} feature - string name of the feature detect
+   * @param {Function|boolean} [res] - A feature detection function, or the boolean =
+   * result of a feature detection function
+   * @returns {void}
+   */
+  ModernizrProto._trigger = function(feature, res) {
+    if (!this._l[feature]) {
+      return;
+    }
+
+    var cbs = this._l[feature];
+
+    // Force async
+    setTimeout(function() {
+      var i, cb;
+      for (i = 0; i < cbs.length; i++) {
+        cb = cbs[i];
+        cb(res);
+      }
+    }, 0);
+
+    // Don't trigger these again
+    delete this._l[feature];
+  };
+
+  /**
+   * addTest allows you to define your own feature detects that are not currently
+   * included in Modernizr (under the covers it's the exact same code Modernizr
+   * uses for its own [feature detections](https://github.com/Modernizr/Modernizr/tree/master/feature-detects)).
+   * Just like the official detects, the result
+   * will be added onto the Modernizr object, as well as an appropriate className set on
+   * the html element when configured to do so
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.addTest
+   * @optionName Modernizr.addTest()
+   * @optionProp addTest
+   * @access public
+   * @function addTest
+   * @param {string|object} feature - The string name of the feature detect, or an
+   * object of feature detect names and test
+   * @param {Function|boolean} test - Function returning true if feature is supported,
+   * false if not. Otherwise a boolean representing the results of a feature detection
+   * @returns {object} the Modernizr object to allow chaining
+   * @example
+   *
+   * The most common way of creating your own feature detects is by calling
+   * `Modernizr.addTest` with a string (preferably just lowercase, without any
+   * punctuation), and a function you want executed that will return a boolean result
+   *
+   * ```js
+   * Modernizr.addTest('itsTuesday', function() {
+   *  var d = new Date();
+   *  return d.getDay() === 2;
+   * });
+   * ```
+   *
+   * When the above is run, it will set Modernizr.itstuesday to `true` when it is tuesday,
+   * and to `false` every other day of the week. One thing to notice is that the names of
+   * feature detect functions are always lowercased when added to the Modernizr object. That
+   * means that `Modernizr.itsTuesday` will not exist, but `Modernizr.itstuesday` will.
+   *
+   *
+   *  Since we only look at the returned value from any feature detection function,
+   *  you do not need to actually use a function. For simple detections, just passing
+   *  in a statement that will return a boolean value works just fine.
+   *
+   * ```js
+   * Modernizr.addTest('hasjquery', 'jQuery' in window);
+   * ```
+   *
+   * Just like before, when the above runs `Modernizr.hasjquery` will be true if
+   * jQuery has been included on the page. Not using a function saves a small amount
+   * of overhead for the browser, as well as making your code much more readable.
+   *
+   * Finally, you also have the ability to pass in an object of feature names and
+   * their tests. This is handy if you want to add multiple detections in one go.
+   * The keys should always be a string, and the value can be either a boolean or
+   * function that returns a boolean.
+   *
+   * ```js
+   * var detects = {
+   *  'hasjquery': 'jQuery' in window,
+   *  'itstuesday': function() {
+   *    var d = new Date();
+   *    return d.getDay() === 2;
+   *  }
+   * }
+   *
+   * Modernizr.addTest(detects);
+   * ```
+   *
+   * There is really no difference between the first methods and this one, it is
+   * just a convenience to let you write more readable code.
+   */
+  function addTest(feature, test) {
+
+    if (typeof feature === 'object') {
+      for (var key in feature) {
+        if (hasOwnProp(feature, key)) {
+          addTest(key, feature[ key ]);
+        }
+      }
+    } else {
+
+      feature = feature.toLowerCase();
+      var featureNameSplit = feature.split('.');
+      var last = Modernizr[featureNameSplit[0]];
+
+      // Again, we don't check for parent test existence. Get that right, though.
+      if (featureNameSplit.length === 2) {
+        last = last[featureNameSplit[1]];
+      }
+
+      if (typeof last !== 'undefined') {
+        // we're going to quit if you're trying to overwrite an existing test
+        // if we were to allow it, we'd do this:
+        //   var re = new RegExp("\\b(no-)?" + feature + "\\b");
+        //   docElement.className = docElement.className.replace( re, '' );
+        // but, no rly, stuff 'em.
+        return Modernizr;
+      }
+
+      test = typeof test === 'function' ? test() : test;
+
+      // Set the value (this is the magic, right here).
+      if (featureNameSplit.length === 1) {
+        Modernizr[featureNameSplit[0]] = test;
+      } else {
+        // cast to a Boolean, if not one already
+        if (Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
+          Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
+        }
+
+        Modernizr[featureNameSplit[0]][featureNameSplit[1]] = test;
+      }
+
+      // Set a single class (either `feature` or `no-feature`)
+      setClasses([(!!test && test !== false ? '' : 'no-') + featureNameSplit.join('-')]);
+
+      // Trigger the event
+      Modernizr._trigger(feature, test);
+    }
+
+    return Modernizr; // allow chaining.
+  }
+
+  // After all the tests are run, add self to the Modernizr prototype
+  Modernizr._q.push(function() {
+    ModernizrProto.addTest = addTest;
+  });
+
+  return addTest;
+});
diff --git a/src/atRule.js b/src/atRule.js
new file mode 100644
index 0000000..0264c83
--- /dev/null
+++ b/src/atRule.js
@@ -0,0 +1,66 @@
+define(['ModernizrProto', 'cssomPrefixes'], function(ModernizrProto, prefixes) {
+  /**
+   * atRule returns a given CSS property at-rule (eg @keyframes), possibly in
+   * some prefixed form, or false, in the case of an unsupported rule
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.atRule
+   * @optionName Modernizr.atRule()
+   * @optionProp atRule
+   * @access public
+   * @function atRule
+   * @param {string} prop - String name of the @-rule to test for
+   * @returns {string|boolean} The string representing the (possibly prefixed)
+   * valid version of the @-rule, or `false` when it is unsupported.
+   * @example
+   * ```js
+   *  var keyframes = Modernizr.atRule('@keyframes');
+   *
+   *  if (keyframes) {
+   *    // keyframes are supported
+   *    // could be `@-webkit-keyframes` or `@keyframes`
+   *  } else {
+   *    // keyframes === `false`
+   *  }
+   * ```
+   */
+  var atRule = function(prop) {
+    var length = prefixes.length;
+    var cssrule = window.CSSRule;
+    var rule;
+
+    if (typeof cssrule === 'undefined') {
+      return undefined;
+    }
+
+    if (!prop) {
+      return false;
+    }
+
+    // remove literal @ from beginning of provided property
+    prop = prop.replace(/^@/, '');
+
+    // CSSRules use underscores instead of dashes
+    rule = prop.replace(/-/g, '_').toUpperCase() + '_RULE';
+
+    if (rule in cssrule) {
+      return '@' + prop;
+    }
+
+    for (var i = 0; i < length; i++) {
+      // prefixes gives us something like -o-, and we want O_
+      var prefix = prefixes[i];
+      var thisRule = prefix.toUpperCase() + '_' + rule;
+
+      if (thisRule in cssrule) {
+        return '@-' + prefix.toLowerCase() + '-' + prop;
+      }
+    }
+
+    return false;
+  };
+
+  ModernizrProto.atRule = atRule;
+
+  return atRule;
+});
diff --git a/src/classes.js b/src/classes.js
new file mode 100644
index 0000000..ea06d38
--- /dev/null
+++ b/src/classes.js
@@ -0,0 +1,4 @@
+define(function() {
+  var classes = [];
+  return classes;
+});
diff --git a/src/computedStyle.js b/src/computedStyle.js
new file mode 100644
index 0000000..412feca
--- /dev/null
+++ b/src/computedStyle.js
@@ -0,0 +1,39 @@
+define(function() {
+
+  /**
+   * wrapper around getComputedStyle, to fix issues with Firefox returning null when
+   * called inside of a hidden iframe
+   *
+   * @access private
+   * @function computedStyle
+   * @param {HTMLElement|SVGElement} elem - The element we want to find the computed styles of
+   * @param {string|null} [pseudo] - An optional pseudo element selector (e.g. :before), of null if none
+   * @param {string} prop - A CSS property
+   * @returns {CSSStyleDeclaration} the value of the specified CSS property
+   */
+  function computedStyle(elem, pseudo, prop) {
+    var result;
+
+    if ('getComputedStyle' in window) {
+      result = getComputedStyle.call(window, elem, pseudo);
+      var console = window.console;
+
+      if (result !== null) {
+        if (prop) {
+          result = result.getPropertyValue(prop);
+        }
+      } else {
+        if (console) {
+          var method = console.error ? 'error' : 'log';
+          console[method].call(console, 'getComputedStyle returning null, its possible modernizr test results are inaccurate');
+        }
+      }
+    } else {
+      result = !pseudo && elem.currentStyle && elem.currentStyle[prop];
+    }
+
+    return result;
+  }
+
+  return computedStyle;
+});
diff --git a/src/contains.js b/src/contains.js
new file mode 100644
index 0000000..d0fc83b
--- /dev/null
+++ b/src/contains.js
@@ -0,0 +1,16 @@
+define(function() {
+  /**
+   * contains checks to see if a string contains another string
+   *
+   * @access private
+   * @function contains
+   * @param {string} str - The string we want to check for substrings
+   * @param {string} substr - The substring we want to search the first string for
+   * @returns {boolean} true if and only if the first string 'str' contains the second string 'substr'
+   */
+  function contains(str, substr) {
+    return !!~('' + str).indexOf(substr);
+  }
+
+  return contains;
+});
diff --git a/src/createElement.js b/src/createElement.js
new file mode 100644
index 0000000..b782fe1
--- /dev/null
+++ b/src/createElement.js
@@ -0,0 +1,25 @@
+define(['isSVG'], function(isSVG) {
+  /**
+   * createElement is a convenience wrapper around document.createElement. Since we
+   * use createElement all over the place, this allows for (slightly) smaller code
+   * as well as abstracting away issues with creating elements in contexts other than
+   * HTML documents (e.g. SVG documents).
+   *
+   * @access private
+   * @function createElement
+   * @returns {HTMLElement|SVGElement} An HTML or SVG element
+   */
+  function createElement() {
+    if (typeof document.createElement !== 'function') {
+      // This is the case in IE7, where the type of createElement is "object".
+      // For this reason, we cannot call apply() as Object is not a Function.
+      return document.createElement(arguments[0]);
+    } else if (isSVG) {
+      return document.createElementNS.call(document, 'http://www.w3.org/2000/svg', arguments[0]);
+    } else {
+      return document.createElement.apply(document, arguments);
+    }
+  }
+
+  return createElement;
+});
diff --git a/src/cssToDOM.js b/src/cssToDOM.js
new file mode 100644
index 0000000..5ac069d
--- /dev/null
+++ b/src/cssToDOM.js
@@ -0,0 +1,18 @@
+define(function() {
+  /**
+   * cssToDOM takes a hyphen-case string and converts it to camelCase
+   * e.g. box-sizing -> boxSizing
+   *
+   * @access private
+   * @function cssToDOM
+   * @param {string} name - String name of hyphen-case prop we want to convert
+   * @returns {string} The camelCase version of the supplied name
+   */
+  function cssToDOM(name) {
+    return name.replace(/([a-z])-([a-z])/g, function(str, m1, m2) {
+      return m1 + m2.toUpperCase();
+    }).replace(/^-/, '');
+  }
+
+  return cssToDOM;
+});
diff --git a/src/cssomPrefixes.js b/src/cssomPrefixes.js
new file mode 100644
index 0000000..e5b589f
--- /dev/null
+++ b/src/cssomPrefixes.js
@@ -0,0 +1,5 @@
+define(['ModernizrProto', 'omPrefixes'], function(ModernizrProto, omPrefixes) {
+  var cssomPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.split(' ') : []);
+  ModernizrProto._cssomPrefixes = cssomPrefixes;
+  return cssomPrefixes;
+});
diff --git a/src/docElement.js b/src/docElement.js
new file mode 100644
index 0000000..04c3897
--- /dev/null
+++ b/src/docElement.js
@@ -0,0 +1,10 @@
+define(function() {
+  /**
+   * docElement is a convenience wrapper to grab the root element of the document
+   *
+   * @access private
+   * @returns {HTMLElement|SVGElement} The root element of the document
+   */
+  var docElement = document.documentElement;
+  return docElement;
+});
diff --git a/src/domPrefixes.js b/src/domPrefixes.js
new file mode 100644
index 0000000..6761a44
--- /dev/null
+++ b/src/domPrefixes.js
@@ -0,0 +1,22 @@
+define(['ModernizrProto', 'omPrefixes'], function(ModernizrProto, omPrefixes) {
+  /**
+   * List of JavaScript DOM values used for tests
+   *
+   * @memberOf Modernizr
+   * @name Modernizr._domPrefixes
+   * @optionName Modernizr._domPrefixes
+   * @optionProp domPrefixes
+   * @access public
+   * @example
+   *
+   * Modernizr._domPrefixes is exactly the same as [_prefixes](#modernizr-_prefixes), but rather
+   * than hyphen-case properties, all properties are their Capitalized variant
+   *
+   * ```js
+   * Modernizr._domPrefixes === [ "Moz", "O", "ms", "Webkit" ];
+   * ```
+   */
+  var domPrefixes = (ModernizrProto._config.usePrefixes ? omPrefixes.toLowerCase().split(' ') : []);
+  ModernizrProto._domPrefixes = domPrefixes;
+  return domPrefixes;
+});
diff --git a/src/domPrefixesAll.js b/src/domPrefixesAll.js
new file mode 100644
index 0000000..94baeff
--- /dev/null
+++ b/src/domPrefixesAll.js
@@ -0,0 +1,22 @@
+define(['ModernizrProto', 'domPrefixes'], function(ModernizrProto, domPrefixes) {
+  /**
+   * List of JavaScript DOM values used for tests including a NON-prefix
+   *
+   * @memberOf Modernizr
+   * @name Modernizr._domPrefixesAll
+   * @optionName Modernizr._domPrefixesAll
+   * @optionProp domPrefixesAll
+   * @access public
+   * @example
+   *
+   * Modernizr._domPrefixesAll is exactly the same as [_domPrefixes](#modernizr-_domPrefixes), but also
+   * adds an empty string in the array to test for a non-prefixed value
+   *
+   * ```js
+   * Modernizr._domPrefixesAll === [ "", "Moz", "O", "ms", "Webkit" ];
+   * ```
+   */
+  var domPrefixesAll = [''].concat(domPrefixes);
+  ModernizrProto._domPrefixesAll = domPrefixesAll;
+  return domPrefixesAll;
+});
diff --git a/src/domToCSS.js b/src/domToCSS.js
new file mode 100644
index 0000000..c3c26cd
--- /dev/null
+++ b/src/domToCSS.js
@@ -0,0 +1,18 @@
+define(function() {
+  /**
+   * domToCSS takes a camelCase string and converts it to hyphen-case
+   * e.g. boxSizing -> box-sizing
+   *
+   * @access private
+   * @function domToCSS
+   * @param {string} name - String name of camelCase prop we want to convert
+   * @returns {string} The hyphen-case version of the supplied name
+   */
+  function domToCSS(name) {
+    return name.replace(/([A-Z])/g, function(str, m1) {
+      return '-' + m1.toLowerCase();
+    }).replace(/^ms-/, '-ms-');
+  }
+
+  return domToCSS;
+});
diff --git a/src/fnBind.js b/src/fnBind.js
new file mode 100644
index 0000000..5a1a94e
--- /dev/null
+++ b/src/fnBind.js
@@ -0,0 +1,18 @@
+define(function() {
+  /**
+   * fnBind is a super small [bind](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/bind) polyfill.
+   *
+   * @access private
+   * @function fnBind
+   * @param {Function} fn - a function you want to change `this` reference to
+   * @param {object} that - the `this` you want to call the function with
+   * @returns {Function} The wrapped version of the supplied function
+   */
+  function fnBind(fn, that) {
+    return function() {
+      return fn.apply(that, arguments);
+    };
+  }
+
+  return fnBind;
+});
diff --git a/src/generate.js b/src/generate.js
new file mode 100644
index 0000000..96a972e
--- /dev/null
+++ b/src/generate.js
@@ -0,0 +1,85 @@
+define(['lodash'], function(_) {
+  /**
+   * generate creates the base version of a Modernizr build, before the r.js
+   * optimizer actually generates the final code
+   *
+   * @access private
+   * @function generate
+   * @param {object} [config] - A configuration object consisting of:
+   *                 [config.options] - An array of options to include in the build
+   *                 [config.feature-detects] - An array of the feature detects to include
+   * @returns {string} A string of the require.js build
+   */
+  return function generate(config) {
+    // Set some defaults
+    if (!config) {
+      config = {};
+    }
+
+    config.options = config.options || [];
+    config['feature-detects'] = config['feature-detects'] || [];
+
+    // Some special cases
+    var setClasses = _.includes(config.options, 'setClasses');
+
+    var output = 'require(["ModernizrProto", "Modernizr", "testRunner"';
+
+    // Needed named module requires
+    if (setClasses) {
+      output += ', "setClasses", "classes"';
+    }
+
+    // Only allow one shiv at a time
+    if (_.includes(config.options, 'html5printshiv')) {
+      config.options = _.without(config.options, 'html5shiv');
+    }
+
+    // Load in the rest of the options, excluding special cases
+    // (they dont return values, so they aren't declared)
+    _.forEach(_.without(config.options, 'setClasses'), function(option) {
+      output += ', "' + option + '"';
+    });
+
+    // Load in all the detects
+    _.forEach(config['feature-detects'], function(detect) {
+      detect = detect.indexOf('test/') === 0 ? detect : 'test/' + detect;
+      output += ', "' + detect + '"';
+    });
+
+    output += '], function( ModernizrProto, Modernizr, testRunner';
+
+    // Needed named module declarations
+    if (setClasses) {
+      output += ', setClasses, classes';
+    }
+
+    output += ') {\n' +
+    '  // Run each test\n' +
+    '  testRunner();\n' +
+    '\n';
+
+    // Actually run the setClasses function
+    if (setClasses) {
+      output += '  // Remove the "no-js" class if it exists\n' +
+      '  setClasses(classes);\n' +
+      '\n';
+    }
+
+    output += '  delete ModernizrProto.addTest;\n';
+    output += '  delete ModernizrProto.addAsyncTest;\n' +
+    '\n';
+
+    // TODO :: if there's a way to figure out if there will be no items in this queue, then we could avoid the code.
+    output += '  // Run the things that are supposed to run after the tests\n' +
+    '  for (var i = 0; i < Modernizr._q.length; i++) {\n' +
+    '    Modernizr._q[i]();\n' +
+    '  }\n\n';
+
+    output += '  // Leak Modernizr namespace\n' +
+    '  scriptGlobalObject.Modernizr = Modernizr;\n' +
+    '\n' +
+    '});';
+
+    return output;
+  };
+});
diff --git a/src/getBody.js b/src/getBody.js
new file mode 100644
index 0000000..19251bd
--- /dev/null
+++ b/src/getBody.js
@@ -0,0 +1,25 @@
+define(['createElement', 'isSVG'], function(createElement, isSVG) {
+  /**
+   * getBody returns the body of a document, or an element that can stand in for
+   * the body if a real body does not exist
+   *
+   * @access private
+   * @function getBody
+   * @returns {HTMLElement|SVGElement} Returns the real body of a document, or an
+   * artificially created element that stands in for the body
+   */
+  function getBody() {
+    // After page load injecting a fake body doesn't work so check if body exists
+    var body = document.body;
+
+    if (!body) {
+      // Can't use the real body create a fake one.
+      body = createElement(isSVG ? 'svg' : 'body');
+      body.fake = true;
+    }
+
+    return body;
+  }
+
+  return getBody;
+});
diff --git a/src/hasEvent.js b/src/hasEvent.js
new file mode 100644
index 0000000..ab6e49c
--- /dev/null
+++ b/src/hasEvent.js
@@ -0,0 +1,74 @@
+define(['ModernizrProto', 'createElement', 'docElement'], function(ModernizrProto, createElement, docElement) {
+  /**
+   * Modernizr.hasEvent() detects support for a given event
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.hasEvent
+   * @optionName Modernizr.hasEvent()
+   * @optionProp hasEvent
+   * @access public
+   * @function hasEvent
+   * @param {string|*} eventName - the name of an event to test for (e.g. "resize")
+   * @param {Element|string} [element=HTMLDivElement] - is the element|document|window|tagName to test on
+   * @returns {boolean}
+   * @example
+   *  `Modernizr.hasEvent` lets you determine if the browser supports a supplied event.
+   *  By default, it does this detection on a div element
+   *
+   * ```js
+   *  hasEvent('blur') // true;
+   * ```
+   *
+   * However, you are able to give an object as a second argument to hasEvent to
+   * detect an event on something other than a div.
+   *
+   * ```js
+   *  hasEvent('devicelight', window) // true;
+   * ```
+   */
+  var hasEvent = (function() {
+
+    // Detect whether event support can be detected via `in`. Test on a DOM element
+    // using the "blur" event b/c it should always exist. bit.ly/event-detection
+    var needsFallback = !('onblur' in docElement);
+
+    function inner(eventName, element) {
+
+      var isSupported;
+      if (!eventName) { return false; }
+      if (!element || typeof element === 'string') {
+        element = createElement(element || 'div');
+      }
+
+      // Testing via the `in` operator is sufficient for modern browsers and IE.
+      // When using `setAttribute`, IE skips "unload", WebKit skips "unload" and
+      // "resize", whereas `in` "catches" those.
+      eventName = 'on' + eventName;
+      isSupported = eventName in element;
+
+      // Fallback technique for old Firefox - bit.ly/event-detection
+      if (!isSupported && needsFallback) {
+        if (!element.setAttribute) {
+          // Switch to generic element if it lacks `setAttribute`.
+          // It could be the `document`, `window`, or something else.
+          element = createElement('div');
+        }
+
+        element.setAttribute(eventName, '');
+        isSupported = typeof element[eventName] === 'function';
+
+        if (element[eventName] !== undefined) {
+          // If property was created, "remove it" by setting value to `undefined`.
+          element[eventName] = undefined;
+        }
+        element.removeAttribute(eventName);
+      }
+
+      return isSupported;
+    }
+    return inner;
+  })();
+
+  ModernizrProto.hasEvent = hasEvent;
+  return hasEvent;
+});
diff --git a/src/hasOwnProp.js b/src/hasOwnProp.js
new file mode 100644
index 0000000..88aca8a
--- /dev/null
+++ b/src/hasOwnProp.js
@@ -0,0 +1,34 @@
+define(['is'], function(is) {
+  /**
+   * hasOwnProp is a shim for hasOwnProperty that is needed for Safari 2.0 support
+   *
+   * @author kangax
+   * @access private
+   * @function hasOwnProp
+   * @param {object} object - The object to check for a property
+   * @param {string} property - The property to check for
+   * @returns {boolean}
+   */
+
+  // hasOwnProperty shim by kangax needed for Safari 2.0 support
+  var hasOwnProp;
+
+  (function() {
+    var _hasOwnProperty = ({}).hasOwnProperty;
+    /* istanbul ignore else */
+    /* we have no way of testing IE 5.5 or safari 2,
+     * so just assume the else gets hit */
+    if (!is(_hasOwnProperty, 'undefined') && !is(_hasOwnProperty.call, 'undefined')) {
+      hasOwnProp = function(object, property) {
+        return _hasOwnProperty.call(object, property);
+      };
+    }
+    else {
+      hasOwnProp = function(object, property) { /* yes, this can give false positives/negatives, but most of the time we don't care about those */
+        return ((property in object) && is(object.constructor.prototype[property], 'undefined'));
+      };
+    }
+  })();
+
+  return hasOwnProp;
+});
diff --git a/src/html5printshiv.js b/src/html5printshiv.js
new file mode 100644
index 0000000..733b87d
--- /dev/null
+++ b/src/html5printshiv.js
@@ -0,0 +1,537 @@
+define(['isSVG'], function(isSVG) {
+  /**
+   * @optionName html5printshiv
+   * @optionProp html5printshiv
+   */
+
+  // Take the html5 variable out of the html5shiv scope so we can return it.
+  var html5;
+  if (!isSVG) {
+    /**
+     * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
+     */
+    ;(function(window, document) {
+      /*jshint evil:true */
+      /** version */
+      var version = '3.7.3';
+
+      /** Preset options */
+      var options = window.html5 || {};
+
+      /** Used to skip problem elements */
+      var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
+
+      /** Not all elements can be cloned in IE **/
+      var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
+
+      /** Detect whether the browser supports default html5 styles */
+      var supportsHtml5Styles;
+
+      /** Name of the expando, to work with multiple documents or to re-shiv one document */
+      var expando = '_html5shiv';
+
+      /** The id for the the documents expando */
+      var expanID = 0;
+
+      /** Cached data for each document */
+      var expandoData = {};
+
+      /** Detect whether the browser supports unknown elements */
+      var supportsUnknownElements;
+
+      (function() {
+        try {
+          var a = document.createElement('a');
+          a.innerHTML = '<xyz></xyz>';
+          //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
+          supportsHtml5Styles = ('hidden' in a);
+
+          supportsUnknownElements = a.childNodes.length == 1 || (function() {
+            // assign a false positive if unable to shiv
+            (document.createElement)('a');
+            var frag = document.createDocumentFragment();
+            return (
+              typeof frag.cloneNode == 'undefined' ||
+              typeof frag.createDocumentFragment == 'undefined' ||
+              typeof frag.createElement == 'undefined'
+            );
+          }());
+        } catch(e) {
+          // assign a false positive if detection fails => unable to shiv
+          supportsHtml5Styles = true;
+          supportsUnknownElements = true;
+        }
+
+      }());
+
+      /*--------------------------------------------------------------------------*/
+
+      /**
+       * Creates a style sheet with the given CSS text and adds it to the document.
+       * @private
+       * @param {Document} ownerDocument The document.
+       * @param {String} cssText The CSS text.
+       * @returns {StyleSheet} The style element.
+       */
+      function addStyleSheet(ownerDocument, cssText) {
+        var p = ownerDocument.createElement('p'),
+          parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
+
+        p.innerHTML = 'x<style>' + cssText + '</style>';
+        return parent.insertBefore(p.lastChild, parent.firstChild);
+      }
+
+      /**
+       * Returns the value of `html5.elements` as an array.
+       * @private
+       * @returns {Array} An array of shived element node names.
+       */
+      function getElements() {
+        var elements = html5.elements;
+        return typeof elements == 'string' ? elements.split(' ') : elements;
+      }
+
+      /**
+       * Extends the built-in list of html5 elements
+       * @memberOf html5
+       * @param {String|Array} newElements whitespace separated list or array of new element names to shiv
+       * @param {Document} ownerDocument The context document.
+       */
+      function addElements(newElements, ownerDocument) {
+        var elements = html5.elements;
+        if(typeof elements != 'string'){
+          elements = elements.join(' ');
+        }
+        if(typeof newElements != 'string'){
+          newElements = newElements.join(' ');
+        }
+        html5.elements = elements +' '+ newElements;
+        shivDocument(ownerDocument);
+      }
+
+      /**
+       * Returns the data associated to the given document
+       * @private
+       * @param {Document} ownerDocument The document.
+       * @returns {Object} An object of data.
+       */
+      function getExpandoData(ownerDocument) {
+        var data = expandoData[ownerDocument[expando]];
+        if (!data) {
+          data = {};
+          expanID++;
+          ownerDocument[expando] = expanID;
+          expandoData[expanID] = data;
+        }
+        return data;
+      }
+
+      /**
+       * returns a shived element for the given nodeName and document
+       * @memberOf html5
+       * @param {String} nodeName name of the element
+       * @param {Document} ownerDocument The context document.
+       * @returns {Object} The shived element.
+       */
+      function createElement(nodeName, ownerDocument, data){
+        if (!ownerDocument) {
+          ownerDocument = document;
+        }
+        if(supportsUnknownElements){
+          return ownerDocument.createElement(nodeName);
+        }
+        if (!data) {
+          data = getExpandoData(ownerDocument);
+        }
+        var node;
+
+        if (data.cache[nodeName]) {
+          node = data.cache[nodeName].cloneNode();
+        } else if (saveClones.test(nodeName)) {
+          node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
+        } else {
+          node = data.createElem(nodeName);
+        }
+
+        // Avoid adding some elements to fragments in IE < 9 because
+        // * Attributes like `name` or `type` cannot be set/changed once an element
+        //   is inserted into a document/fragment
+        // * Link elements with `src` attributes that are inaccessible, as with
+        //   a 403 response, will cause the tab/window to crash
+        // * Script elements appended to fragments will execute when their `src`
+        //   or `text` property is set
+        return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
+      }
+
+      /**
+       * returns a shived DocumentFragment for the given document
+       * @memberOf html5
+       * @param {Document} ownerDocument The context document.
+       * @returns {Object} The shived DocumentFragment.
+       */
+      function createDocumentFragment(ownerDocument, data){
+        if (!ownerDocument) {
+          ownerDocument = document;
+        }
+        if(supportsUnknownElements){
+          return ownerDocument.createDocumentFragment();
+        }
+        data = data || getExpandoData(ownerDocument);
+        var clone = data.frag.cloneNode(),
+          i = 0,
+          elems = getElements(),
+          l = elems.length;
+        for(;i<l;i++){
+          clone.createElement(elems[i]);
+        }
+        return clone;
+      }
+
+      /**
+       * Shivs the `createElement` and `createDocumentFragment` methods of the document.
+       * @private
+       * @param {Document|DocumentFragment} ownerDocument The document.
+       * @param {Object} data of the document.
+       */
+      function shivMethods(ownerDocument, data) {
+        if (!data.cache) {
+          data.cache = {};
+          data.createElem = ownerDocument.createElement;
+          data.createFrag = ownerDocument.createDocumentFragment;
+          data.frag = data.createFrag();
+        }
+
+
+        ownerDocument.createElement = function(nodeName) {
+          //abort shiv
+          if (!html5.shivMethods) {
+            return data.createElem(nodeName);
+          }
+          return createElement(nodeName, ownerDocument, data);
+        };
+
+        ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
+          'var n=f.cloneNode(),c=n.createElement;' +
+          'h.shivMethods&&(' +
+          // unroll the `createElement` calls
+          getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
+            data.createElem(nodeName);
+            data.frag.createElement(nodeName);
+            return 'c("' + nodeName + '")';
+          }) +
+          ');return n}'
+        )(html5, data.frag);
+      }
+
+      /*--------------------------------------------------------------------------*/
+
+      /**
+       * Shivs the given document.
+       * @memberOf html5
+       * @param {Document} ownerDocument The document to shiv.
+       * @returns {Document} The shived document.
+       */
+      function shivDocument(ownerDocument) {
+        if (!ownerDocument) {
+          ownerDocument = document;
+        }
+        var data = getExpandoData(ownerDocument);
+
+        if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
+          data.hasCSS = !!addStyleSheet(ownerDocument,
+            // corrects block display not defined in IE6/7/8/9
+            'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
+            // adds styling not present in IE6/7/8/9
+            'mark{background:#FF0;color:#000}' +
+            // hides non-rendered elements
+            'template{display:none}'
+          );
+        }
+        if (!supportsUnknownElements) {
+          shivMethods(ownerDocument, data);
+        }
+        return ownerDocument;
+      }
+
+      /*--------------------------------------------------------------------------*/
+
+      /**
+       * The `html5` object is exposed so that more elements can be shived and
+       * existing shiving can be detected on iframes.
+       * @type Object
+       * @example
+       *
+       * // options can be changed before the script is included
+       * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
+       */
+      var html5 = {
+
+        /**
+         * An array or space separated string of node names of the elements to shiv.
+         * @memberOf html5
+         * @type Array|String
+         */
+        'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
+
+        /**
+         * current version of html5shiv
+         */
+        'version': version,
+
+        /**
+         * A flag to indicate that the HTML5 style sheet should be inserted.
+         * @memberOf html5
+         * @type Boolean
+         */
+        'shivCSS': (options.shivCSS !== false),
+
+        /**
+         * Is equal to true if a browser supports creating unknown/HTML5 elements
+         * @memberOf html5
+         * @type boolean
+         */
+        'supportsUnknownElements': supportsUnknownElements,
+
+        /**
+         * A flag to indicate that the document's `createElement` and `createDocumentFragment`
+         * methods should be overwritten.
+         * @memberOf html5
+         * @type Boolean
+         */
+        'shivMethods': (options.shivMethods !== false),
+
+        /**
+         * A string to describe the type of `html5` object ("default" or "default print").
+         * @memberOf html5
+         * @type String
+         */
+        'type': 'default',
+
+        // shivs the document according to the specified `html5` object options
+        'shivDocument': shivDocument,
+
+        //creates a shived element
+        createElement: createElement,
+
+        //creates a shived documentFragment
+        createDocumentFragment: createDocumentFragment,
+
+        //extends list of elements
+        addElements: addElements
+      };
+
+      /*--------------------------------------------------------------------------*/
+
+      // expose html5
+      window.html5 = html5;
+
+      // shiv the document
+      shivDocument(document);
+
+      /*------------------------------- Print Shiv -------------------------------*/
+
+      /** Used to filter media types */
+      var reMedia = /^$|\b(?:all|print)\b/;
+
+      /** Used to namespace printable elements */
+      var shivNamespace = 'html5shiv';
+
+      /** Detect whether the browser supports shivable style sheets */
+      var supportsShivableSheets = !supportsUnknownElements && (function() {
+        // assign a false negative if unable to shiv
+        var docEl = document.documentElement;
+        return !(
+          typeof document.namespaces == 'undefined' ||
+          typeof document.parentWindow == 'undefined' ||
+          typeof docEl.applyElement == 'undefined' ||
+          typeof docEl.removeNode == 'undefined' ||
+          typeof window.attachEvent == 'undefined'
+        );
+      }());
+
+      /*--------------------------------------------------------------------------*/
+
+      /**
+       * Wraps all HTML5 elements in the given document with printable elements.
+       * (eg. the "header" element is wrapped with the "html5shiv:header" element)
+       * @private
+       * @param {Document} ownerDocument The document.
+       * @returns {Array} An array wrappers added.
+       */
+      function addWrappers(ownerDocument) {
+        var node,
+          nodes = ownerDocument.getElementsByTagName('*'),
+          index = nodes.length,
+          reElements = RegExp('^(?:' + getElements().join('|') + ')$', 'i'),
+          result = [];
+
+        while (index--) {
+          node = nodes[index];
+          if (reElements.test(node.nodeName)) {
+            result.push(node.applyElement(createWrapper(node)));
+          }
+        }
+        return result;
+      }
+
+      /**
+       * Creates a printable wrapper for the given element.
+       * @private
+       * @param {Element} element The element.
+       * @returns {Element} The wrapper.
+       */
+      function createWrapper(element) {
+        var node,
+          nodes = element.attributes,
+          index = nodes.length,
+          wrapper = element.ownerDocument.createElement(shivNamespace + ':' + element.nodeName);
+
+        // copy element attributes to the wrapper
+        while (index--) {
+          node = nodes[index];
+          node.specified && wrapper.setAttribute(node.nodeName, node.nodeValue);
+        }
+        // copy element styles to the wrapper
+        wrapper.style.cssText = element.style.cssText;
+        return wrapper;
+      }
+
+      /**
+       * Shivs the given CSS text.
+       * (eg. header{} becomes html5shiv\:header{})
+       * @private
+       * @param {String} cssText The CSS text to shiv.
+       * @returns {String} The shived CSS text.
+       */
+      function shivCssText(cssText) {
+        var pair,
+          parts = cssText.split('{'),
+          index = parts.length,
+          reElements = RegExp('(^|[\\s,>+~])(' + getElements().join('|') + ')(?=[[\\s,>+~#.:]|$)', 'gi'),
+          replacement = '$1' + shivNamespace + '\\:$2';
+
+        while (index--) {
+          pair = parts[index] = parts[index].split('}');
+          pair[pair.length - 1] = pair[pair.length - 1].replace(reElements, replacement);
+          parts[index] = pair.join('}');
+        }
+        return parts.join('{');
+      }
+
+      /**
+       * Removes the given wrappers, leaving the original elements.
+       * @private
+       * @params {Array} wrappers An array of printable wrappers.
+       */
+      function removeWrappers(wrappers) {
+        var index = wrappers.length;
+        while (index--) {
+          wrappers[index].removeNode();
+        }
+      }
+
+      /*--------------------------------------------------------------------------*/
+
+      /**
+       * Shivs the given document for print.
+       * @memberOf html5
+       * @param {Document} ownerDocument The document to shiv.
+       * @returns {Document} The shived document.
+       */
+      function shivPrint(ownerDocument) {
+        var shivedSheet,
+          wrappers,
+          data = getExpandoData(ownerDocument),
+          namespaces = ownerDocument.namespaces,
+          ownerWindow = ownerDocument.parentWindow;
+
+        if (!supportsShivableSheets || ownerDocument.printShived) {
+          return ownerDocument;
+        }
+        if (typeof namespaces[shivNamespace] == 'undefined') {
+          namespaces.add(shivNamespace);
+        }
+
+        function removeSheet() {
+          clearTimeout(data._removeSheetTimer);
+          if (shivedSheet) {
+            shivedSheet.removeNode(true);
+          }
+          shivedSheet= null;
+        }
+
+        ownerWindow.attachEvent('onbeforeprint', function() {
+
+          removeSheet();
+
+          var imports,
+            length,
+            sheet,
+            collection = ownerDocument.styleSheets,
+            cssText = [],
+            index = collection.length,
+            sheets = Array(index);
+
+          // convert styleSheets collection to an array
+          while (index--) {
+            sheets[index] = collection[index];
+          }
+          // concat all style sheet CSS text
+          while ((sheet = sheets.pop())) {
+            // IE does not enforce a same origin policy for external style sheets...
+            // but has trouble with some dynamically created stylesheets
+            if (!sheet.disabled && reMedia.test(sheet.media)) {
+
+              try {
+                imports = sheet.imports;
+                length = imports.length;
+              } catch(er){
+                length = 0;
+              }
+
+              for (index = 0; index < length; index++) {
+                sheets.push(imports[index]);
+              }
+
+              try {
+                cssText.push(sheet.cssText);
+              } catch(er){}
+            }
+          }
+
+          // wrap all HTML5 elements with printable elements and add the shived style sheet
+          cssText = shivCssText(cssText.reverse().join(''));
+          wrappers = addWrappers(ownerDocument);
+          shivedSheet = addStyleSheet(ownerDocument, cssText);
+
+        });
+
+        ownerWindow.attachEvent('onafterprint', function() {
+          // remove wrappers, leaving the original elements, and remove the shived style sheet
+          removeWrappers(wrappers);
+          clearTimeout(data._removeSheetTimer);
+          data._removeSheetTimer = setTimeout(removeSheet, 500);
+        });
+
+        ownerDocument.printShived = true;
+        return ownerDocument;
+      }
+
+      /*--------------------------------------------------------------------------*/
+
+      // expose API
+      html5.type += ' print';
+      html5.shivPrint = shivPrint;
+
+      // shiv for print
+      shivPrint(document);
+
+      if(typeof module == 'object' && module.exports){
+        module.exports = html5;
+      }
+
+    }(typeof window !== "undefined" ? window : this, document));
+  }
+
+  return html5;
+});
diff --git a/src/html5shiv.js b/src/html5shiv.js
new file mode 100644
index 0000000..db9dbd3
--- /dev/null
+++ b/src/html5shiv.js
@@ -0,0 +1,338 @@
+define(['isSVG'], function(isSVG) {
+  /**
+   * @optionName html5shiv
+   * @optionProp html5shiv
+   */
+
+  // Take the html5 variable out of the html5shiv scope so we can return it.
+  var html5;
+  if (!isSVG) {
+    /**
+     * @preserve HTML5 Shiv 3.7.3 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
+     */
+    ;(function(window, document) {
+      /*jshint evil:true */
+      /** version */
+      var version = '3.7.3';
+
+      /** Preset options */
+      var options = window.html5 || {};
+
+      /** Used to skip problem elements */
+      var reSkip = /^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i;
+
+      /** Not all elements can be cloned in IE **/
+      var saveClones = /^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i;
+
+      /** Detect whether the browser supports default html5 styles */
+      var supportsHtml5Styles;
+
+      /** Name of the expando, to work with multiple documents or to re-shiv one document */
+      var expando = '_html5shiv';
+
+      /** The id for the the documents expando */
+      var expanID = 0;
+
+      /** Cached data for each document */
+      var expandoData = {};
+
+      /** Detect whether the browser supports unknown elements */
+      var supportsUnknownElements;
+
+      (function() {
+        try {
+          var a = document.createElement('a');
+          a.innerHTML = '<xyz></xyz>';
+          //if the hidden property is implemented we can assume, that the browser supports basic HTML5 Styles
+          supportsHtml5Styles = ('hidden' in a);
+
+          supportsUnknownElements = a.childNodes.length == 1 || (function() {
+            // assign a false positive if unable to shiv
+            (document.createElement)('a');
+            var frag = document.createDocumentFragment();
+            return (
+              typeof frag.cloneNode == 'undefined' ||
+              typeof frag.createDocumentFragment == 'undefined' ||
+              typeof frag.createElement == 'undefined'
+            );
+          }());
+        } catch(e) {
+          // assign a false positive if detection fails => unable to shiv
+          supportsHtml5Styles = true;
+          supportsUnknownElements = true;
+        }
+
+      }());
+
+      /*--------------------------------------------------------------------------*/
+
+      /**
+       * Creates a style sheet with the given CSS text and adds it to the document.
+       * @private
+       * @param {Document} ownerDocument The document.
+       * @param {String} cssText The CSS text.
+       * @returns {StyleSheet} The style element.
+       */
+      function addStyleSheet(ownerDocument, cssText) {
+        var p = ownerDocument.createElement('p'),
+          parent = ownerDocument.getElementsByTagName('head')[0] || ownerDocument.documentElement;
+
+        p.innerHTML = 'x<style>' + cssText + '</style>';
+        return parent.insertBefore(p.lastChild, parent.firstChild);
+      }
+
+      /**
+       * Returns the value of `html5.elements` as an array.
+       * @private
+       * @returns {Array} An array of shived element node names.
+       */
+      function getElements() {
+        var elements = html5.elements;
+        return typeof elements == 'string' ? elements.split(' ') : elements;
+      }
+
+      /**
+       * Extends the built-in list of html5 elements
+       * @memberOf html5
+       * @param {String|Array} newElements whitespace separated list or array of new element names to shiv
+       * @param {Document} ownerDocument The context document.
+       */
+      function addElements(newElements, ownerDocument) {
+        var elements = html5.elements;
+        if(typeof elements != 'string'){
+          elements = elements.join(' ');
+        }
+        if(typeof newElements != 'string'){
+          newElements = newElements.join(' ');
+        }
+        html5.elements = elements +' '+ newElements;
+        shivDocument(ownerDocument);
+      }
+
+      /**
+       * Returns the data associated to the given document
+       * @private
+       * @param {Document} ownerDocument The document.
+       * @returns {Object} An object of data.
+       */
+      function getExpandoData(ownerDocument) {
+        var data = expandoData[ownerDocument[expando]];
+        if (!data) {
+          data = {};
+          expanID++;
+          ownerDocument[expando] = expanID;
+          expandoData[expanID] = data;
+        }
+        return data;
+      }
+
+      /**
+       * returns a shived element for the given nodeName and document
+       * @memberOf html5
+       * @param {String} nodeName name of the element
+       * @param {Document|DocumentFragment} ownerDocument The context document.
+       * @returns {Object} The shived element.
+       */
+      function createElement(nodeName, ownerDocument, data){
+        if (!ownerDocument) {
+          ownerDocument = document;
+        }
+        if(supportsUnknownElements){
+          return ownerDocument.createElement(nodeName);
+        }
+        if (!data) {
+          data = getExpandoData(ownerDocument);
+        }
+        var node;
+
+        if (data.cache[nodeName]) {
+          node = data.cache[nodeName].cloneNode();
+        } else if (saveClones.test(nodeName)) {
+          node = (data.cache[nodeName] = data.createElem(nodeName)).cloneNode();
+        } else {
+          node = data.createElem(nodeName);
+        }
+
+        // Avoid adding some elements to fragments in IE < 9 because
+        // * Attributes like `name` or `type` cannot be set/changed once an element
+        //   is inserted into a document/fragment
+        // * Link elements with `src` attributes that are inaccessible, as with
+        //   a 403 response, will cause the tab/window to crash
+        // * Script elements appended to fragments will execute when their `src`
+        //   or `text` property is set
+        return node.canHaveChildren && !reSkip.test(nodeName) && !node.tagUrn ? data.frag.appendChild(node) : node;
+      }
+
+      /**
+       * returns a shived DocumentFragment for the given document
+       * @memberOf html5
+       * @param {Document} ownerDocument The context document.
+       * @returns {Object} The shived DocumentFragment.
+       */
+      function createDocumentFragment(ownerDocument, data){
+        if (!ownerDocument) {
+          ownerDocument = document;
+        }
+        if(supportsUnknownElements){
+          return ownerDocument.createDocumentFragment();
+        }
+        data = data || getExpandoData(ownerDocument);
+        var clone = data.frag.cloneNode(),
+          i = 0,
+          elems = getElements(),
+          l = elems.length;
+        for(;i<l;i++){
+          clone.createElement(elems[i]);
+        }
+        return clone;
+      }
+
+      /**
+       * Shivs the `createElement` and `createDocumentFragment` methods of the document.
+       * @private
+       * @param {Document|DocumentFragment} ownerDocument The document.
+       * @param {Object} data of the document.
+       */
+      function shivMethods(ownerDocument, data) {
+        if (!data.cache) {
+          data.cache = {};
+          data.createElem = ownerDocument.createElement;
+          data.createFrag = ownerDocument.createDocumentFragment;
+          data.frag = data.createFrag();
+        }
+
+
+        ownerDocument.createElement = function(nodeName) {
+          //abort shiv
+          if (!html5.shivMethods) {
+            return data.createElem(nodeName);
+          }
+          return createElement(nodeName, ownerDocument, data);
+        };
+
+        ownerDocument.createDocumentFragment = Function('h,f', 'return function(){' +
+          'var n=f.cloneNode(),c=n.createElement;' +
+          'h.shivMethods&&(' +
+          // unroll the `createElement` calls
+          getElements().join().replace(/[\w\-:]+/g, function(nodeName) {
+            data.createElem(nodeName);
+            data.frag.createElement(nodeName);
+            return 'c("' + nodeName + '")';
+          }) +
+          ');return n}'
+        )(html5, data.frag);
+      }
+
+      /*--------------------------------------------------------------------------*/
+
+      /**
+       * Shivs the given document.
+       * @memberOf html5
+       * @param {Document} ownerDocument The document to shiv.
+       * @returns {Document} The shived document.
+       */
+      function shivDocument(ownerDocument) {
+        if (!ownerDocument) {
+          ownerDocument = document;
+        }
+        var data = getExpandoData(ownerDocument);
+
+        if (html5.shivCSS && !supportsHtml5Styles && !data.hasCSS) {
+          data.hasCSS = !!addStyleSheet(ownerDocument,
+            // corrects block display not defined in IE6/7/8/9
+            'article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}' +
+            // adds styling not present in IE6/7/8/9
+            'mark{background:#FF0;color:#000}' +
+            // hides non-rendered elements
+            'template{display:none}'
+          );
+        }
+        if (!supportsUnknownElements) {
+          shivMethods(ownerDocument, data);
+        }
+        return ownerDocument;
+      }
+
+      /*--------------------------------------------------------------------------*/
+
+      /**
+       * The `html5` object is exposed so that more elements can be shived and
+       * existing shiving can be detected on iframes.
+       * @type Object
+       * @example
+       *
+       * // options can be changed before the script is included
+       * html5 = { 'elements': 'mark section', 'shivCSS': false, 'shivMethods': false };
+       */
+      var html5 = {
+
+        /**
+         * An array or space separated string of node names of the elements to shiv.
+         * @memberOf html5
+         * @type Array|String
+         */
+        'elements': options.elements || 'abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video',
+
+        /**
+         * current version of html5shiv
+         */
+        'version': version,
+
+        /**
+         * A flag to indicate that the HTML5 style sheet should be inserted.
+         * @memberOf html5
+         * @type Boolean
+         */
+        'shivCSS': (options.shivCSS !== false),
+
+        /**
+         * Is equal to true if a browser supports creating unknown/HTML5 elements
+         * @memberOf html5
+         * @type boolean
+         */
+        'supportsUnknownElements': supportsUnknownElements,
+
+        /**
+         * A flag to indicate that the document's `createElement` and `createDocumentFragment`
+         * methods should be overwritten.
+         * @memberOf html5
+         * @type Boolean
+         */
+        'shivMethods': (options.shivMethods !== false),
+
+        /**
+         * A string to describe the type of `html5` object ("default" or "default print").
+         * @memberOf html5
+         * @type String
+         */
+        'type': 'default',
+
+        // shivs the document according to the specified `html5` object options
+        'shivDocument': shivDocument,
+
+        //creates a shived element
+        createElement: createElement,
+
+        //creates a shived documentFragment
+        createDocumentFragment: createDocumentFragment,
+
+        //extends list of elements
+        addElements: addElements
+      };
+
+      /*--------------------------------------------------------------------------*/
+
+      // expose html5
+      window.html5 = html5;
+
+      // shiv the document
+      shivDocument(document);
+
+      if(typeof module == 'object' && module.exports){
+        module.exports = html5;
+      }
+
+    }(typeof window !== "undefined" ? window : this, document));
+  }
+  return html5;
+});
diff --git a/src/injectElementWithStyles.js b/src/injectElementWithStyles.js
new file mode 100644
index 0000000..bab6463
--- /dev/null
+++ b/src/injectElementWithStyles.js
@@ -0,0 +1,74 @@
+define(['ModernizrProto', 'docElement', 'createElement', 'getBody'], function(ModernizrProto, docElement, createElement, getBody) {
+  /**
+   * injectElementWithStyles injects an element with style element and some CSS rules
+   *
+   * @access private
+   * @function injectElementWithStyles
+   * @param {string} rule - String representing a css rule
+   * @param {Function} callback - A function that is used to test the injected element
+   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
+   * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
+   * @returns {boolean} the result of the specified callback test
+   */
+  function injectElementWithStyles(rule, callback, nodes, testnames) {
+    var mod = 'modernizr';
+    var style;
+    var ret;
+    var node;
+    var docOverflow;
+    var div = createElement('div');
+    var body = getBody();
+
+    if (parseInt(nodes, 10)) {
+      // In order not to give false positives we create a node for each test
+      // This also allows the method to scale for unspecified uses
+      while (nodes--) {
+        node = createElement('div');
+        node.id = testnames ? testnames[nodes] : mod + (nodes + 1);
+        div.appendChild(node);
+      }
+    }
+
+    style = createElement('style');
+    style.type = 'text/css';
+    style.id = 's' + mod;
+
+    // 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.
+    // Opera will act all quirky when injecting elements in documentElement when page is served as xml, needs fakebody too. #270
+    (!body.fake ? div : body).appendChild(style);
+    body.appendChild(div);
+
+    if (style.styleSheet) {
+      style.styleSheet.cssText = rule;
+    } else {
+      style.appendChild(document.createTextNode(rule));
+    }
+    div.id = mod;
+
+    if (body.fake) {
+      //avoid crashing IE8, if background image is used
+      body.style.background = '';
+      //Safari 5.13/5.1.4 OSX stops loading if ::-webkit-scrollbar is used and scrollbars are visible
+      body.style.overflow = 'hidden';
+      docOverflow = docElement.style.overflow;
+      docElement.style.overflow = 'hidden';
+      docElement.appendChild(body);
+    }
+
+    ret = callback(div, rule);
+    // If this is done after page load we don't want to remove the body so check if body exists
+    if (body.fake && body.parentNode) {
+      body.parentNode.removeChild(body);
+      docElement.style.overflow = docOverflow;
+      // Trigger layout so kinetic scrolling isn't disabled in iOS6+
+      // eslint-disable-next-line
+      docElement.offsetHeight;
+    } else {
+      div.parentNode.removeChild(div);
+    }
+
+    return !!ret;
+  }
+
+  return injectElementWithStyles;
+});
diff --git a/src/inputElem.js b/src/inputElem.js
new file mode 100644
index 0000000..3e161e3
--- /dev/null
+++ b/src/inputElem.js
@@ -0,0 +1,12 @@
+define(['createElement'], function(createElement) {
+  /**
+   * since we have a fairly large number of input tests that don't mutate the input
+   * we create a single element that can be shared with all of those tests for a
+   * minor perf boost
+   *
+   * @access private
+   * @returns {HTMLInputElement}
+   */
+  var inputElem = createElement('input');
+  return inputElem;
+});
diff --git a/src/is.js b/src/is.js
new file mode 100644
index 0000000..18cbe57
--- /dev/null
+++ b/src/is.js
@@ -0,0 +1,16 @@
+define(function() {
+  /**
+   * is returns a boolean if the typeof an obj is exactly type.
+   *
+   * @access private
+   * @function is
+   * @param {*} obj - A thing we want to check the type of
+   * @param {string} type - A string to compare the typeof against
+   * @returns {boolean} true if the typeof the first parameter is exactly the specified type, false otherwise
+   */
+  function is(obj, type) {
+    return typeof obj === type;
+  }
+
+  return is;
+});
diff --git a/src/isSVG.js b/src/isSVG.js
new file mode 100644
index 0000000..b55ae8c
--- /dev/null
+++ b/src/isSVG.js
@@ -0,0 +1,11 @@
+define(['docElement'], function(docElement) {
+  /**
+   * A convenience helper to check if the document we are running in is an SVG document
+   *
+   * @access private
+   * @returns {boolean}
+   */
+  var isSVG = docElement.nodeName.toLowerCase() === 'svg';
+
+  return isSVG;
+});
diff --git a/src/load.js b/src/load.js
new file mode 100644
index 0000000..96411f2
--- /dev/null
+++ b/src/load.js
@@ -0,0 +1,36 @@
+define(['ModernizrProto'], function(ModernizrProto) {
+  var err = function() {};
+  var warn = function() {};
+
+  if (window.console) {
+    err = function() {
+      var method = console.error ? 'error' : 'log';
+      window.console[method].apply(window.console, Array.prototype.slice.call(arguments));
+    };
+
+    warn = function() {
+      var method = console.warn ? 'warn' : 'log';
+      window.console[method].apply(window.console, Array.prototype.slice.call(arguments));
+    };
+  }
+
+  /**
+   * Previously, Modernizr.load was an alias for yepnope. Since yepnope was
+   * deprecated, we removed it as well. It is not available on the website builder,
+   * this is only included as an improved warning to those who build a custom
+   * version locally.
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.load
+   * @function load
+   * @returns {void}
+   */
+  ModernizrProto.load = function() {
+    if ('yepnope' in window) {
+      warn('yepnope.js (aka Modernizr.load) is no longer included as part of Modernizr. yepnope appears to be available on the page, so we’ll use it to handle this call to Modernizr.load, but please update your code to use yepnope directly.\n See http://github.com/Modernizr/Modernizr/issues/1182 for more information.');
+      window.yepnope.apply(window, [].slice.call(arguments, 0));
+    } else {
+      err('yepnope.js (aka Modernizr.load) is no longer included as part of Modernizr. Get it from http://yepnopejs.com. See http://github.com/Modernizr/Modernizr/issues/1182 for more information.');
+    }
+  };
+});
diff --git a/src/mStyle.js b/src/mStyle.js
new file mode 100644
index 0000000..e3ac96d
--- /dev/null
+++ b/src/mStyle.js
@@ -0,0 +1,13 @@
+define(['Modernizr', 'modElem'], function(Modernizr, modElem) {
+  var mStyle = {
+    style: modElem.elem.style
+  };
+
+  // kill ref for gc, must happen before mod.elem is removed, so we unshift on to
+  // the front of the queue.
+  Modernizr._q.unshift(function() {
+    delete mStyle.style;
+  });
+
+  return mStyle;
+});
diff --git a/src/modElem.js b/src/modElem.js
new file mode 100644
index 0000000..29a1ea3
--- /dev/null
+++ b/src/modElem.js
@@ -0,0 +1,17 @@
+define(['Modernizr', 'createElement'], function(Modernizr, createElement) {
+  /**
+   * Create our "modernizr" element that we do most feature tests on.
+   *
+   * @access private
+   */
+  var modElem = {
+    elem: createElement('modernizr')
+  };
+
+  // Clean up this element
+  Modernizr._q.push(function() {
+    delete modElem.elem;
+  });
+
+  return modElem;
+});
diff --git a/src/mq.js b/src/mq.js
new file mode 100644
index 0000000..c22069f
--- /dev/null
+++ b/src/mq.js
@@ -0,0 +1,70 @@
+define(['ModernizrProto', 'injectElementWithStyles', 'computedStyle'], function(ModernizrProto, injectElementWithStyles, computedStyle) {
+  /**
+   * Modernizr.mq tests a given media query, live against the current state of the window
+   * adapted from matchMedia polyfill by Scott Jehl and Paul Irish
+   * gist.github.com/786768
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.mq
+   * @optionName Modernizr.mq()
+   * @optionProp mq
+   * @access public
+   * @function mq
+   * @param {string} mq - String of the media query we want to test
+   * @returns {boolean}
+   * @example
+   * Modernizr.mq allows for you to programmatically check if the current browser
+   * window state matches a media query.
+   *
+   * ```js
+   *  var query = Modernizr.mq('(min-width: 900px)');
+   *
+   *  if (query) {
+   *    // the browser window is larger than 900px
+   *  }
+   * ```
+   *
+   * Only valid media queries are supported, therefore you must always include values
+   * with your media query
+   *
+   * ```js
+   * // good
+   *  Modernizr.mq('(min-width: 900px)');
+   *
+   * // bad
+   *  Modernizr.mq('min-width');
+   * ```
+   *
+   * If you would just like to test that media queries are supported in general, use
+   *
+   * ```js
+   *  Modernizr.mq('only all'); // true if MQ are supported, false if not
+   * ```
+   *
+   * Note that if the browser does not support media queries (e.g. old IE) mq will
+   * always return false.
+   */
+  var mq = (function() {
+    var matchMedia = window.matchMedia || window.msMatchMedia;
+    if (matchMedia) {
+      return function(mq) {
+        var mql = matchMedia(mq);
+        return mql && mql.matches || false;
+      };
+    }
+
+    return function(mq) {
+      var bool = false;
+
+      injectElementWithStyles('@media ' + mq + ' { #modernizr { position: absolute; } }', function(node) {
+        bool = computedStyle(node, null, 'position') === 'absolute';
+      });
+
+      return bool;
+    };
+  })();
+
+  ModernizrProto.mq = mq;
+
+  return mq;
+});
diff --git a/src/nativeTestProps.js b/src/nativeTestProps.js
new file mode 100644
index 0000000..5dee302
--- /dev/null
+++ b/src/nativeTestProps.js
@@ -0,0 +1,41 @@
+define(['injectElementWithStyles', 'domToCSS', 'computedStyle'], function(injectElementWithStyles, domToCSS, computedStyle) {
+  /**
+   * nativeTestProps allows for us to use native feature detection functionality if available.
+   * some prefixed form, or false, in the case of an unsupported rule
+   *
+   * @access private
+   * @function nativeTestProps
+   * @param {Array} props - An array of property names
+   * @param {string} value - A string representing the value we want to check via @supports
+   * @returns {boolean|undefined} A boolean when @supports exists, undefined otherwise
+   */
+  // Accepts a list of property names and a single value
+  // Returns `undefined` if native detection not available
+  function nativeTestProps(props, value) {
+    var i = props.length;
+    // Start with the JS API: https://www.w3.org/TR/css3-conditional/#the-css-interface
+    if ('CSS' in window && 'supports' in window.CSS) {
+      // Try every prefixed variant of the property
+      while (i--) {
+        if (window.CSS.supports(domToCSS(props[i]), value)) {
+          return true;
+        }
+      }
+      return false;
+    }
+    // Otherwise fall back to at-rule (for Opera 12.x)
+    else if ('CSSSupportsRule' in window) {
+      // Build a condition string for every prefixed variant
+      var conditionText = [];
+      while (i--) {
+        conditionText.push('(' + domToCSS(props[i]) + ':' + value + ')');
+      }
+      conditionText = conditionText.join(' or ');
+      return injectElementWithStyles('@supports (' + conditionText + ') { #modernizr { position: absolute; } }', function(node) {
+        return computedStyle(node, null, 'position') === 'absolute';
+      });
+    }
+    return undefined;
+  }
+  return nativeTestProps;
+});
diff --git a/src/omPrefixes.js b/src/omPrefixes.js
new file mode 100644
index 0000000..fade480
--- /dev/null
+++ b/src/omPrefixes.js
@@ -0,0 +1,19 @@
+define(function() {
+  /**
+   * If the browsers follow the spec, then they would expose vendor-specific styles as:
+   *   elem.style.WebkitBorderRadius
+   * instead of something like the following (which is technically incorrect):
+   *   elem.style.webkitBorderRadius
+   *
+   * WebKit ghosts their properties in lowercase but Opera & Moz do not.
+   * Microsoft uses a lowercase `ms` instead of the correct `Ms` in IE8+
+   *   erik.eae.net/archives/2008/03/10/21.48.10/
+   *
+   * More here: github.com/Modernizr/Modernizr/issues/issue/21
+   *
+   * @access private
+   * @returns {string} The string representing the vendor-specific style properties
+   */
+  var omPrefixes = 'Moz O ms Webkit';
+  return omPrefixes;
+});
diff --git a/src/prefixed.js b/src/prefixed.js
new file mode 100644
index 0000000..d901e92
--- /dev/null
+++ b/src/prefixed.js
@@ -0,0 +1,84 @@
+define(['ModernizrProto', 'testPropsAll', 'cssToDOM', 'atRule'], function(ModernizrProto, testPropsAll, cssToDOM, atRule) {
+  /**
+   * prefixed returns the prefixed or nonprefixed property name variant of your input
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.prefixed
+   * @optionName Modernizr.prefixed()
+   * @optionProp prefixed
+   * @access public
+   * @function prefixed
+   * @param {string} prop - String name of the property to test for
+   * @param {object} [obj] - An object to test for the prefixed properties on
+   * @param {HTMLElement} [elem] - An element used to test specific properties against
+   * @returns {string|boolean} The string representing the (possibly prefixed) valid
+   * version of the property, or `false` when it is unsupported.
+   * @example
+   *
+   * Modernizr.prefixed takes a string css value in the DOM style camelCase (as
+   * opposed to the css style hyphen-case) form and returns the (possibly prefixed)
+   * version of that property that the browser actually supports.
+   *
+   * For example, in older Firefox...
+   * ```js
+   * prefixed('boxSizing')
+   * ```
+   * returns 'MozBoxSizing'
+   *
+   * In newer Firefox, as well as any other browser that support the unprefixed
+   * version would simply return `boxSizing`. Any browser that does not support
+   * the property at all, it will return `false`.
+   *
+   * By default, prefixed is checked against a DOM element. If you want to check
+   * for a property on another object, just pass it as a second argument
+   *
+   * ```js
+   * var rAF = prefixed('requestAnimationFrame', window);
+   *
+   * raf(function() {
+   *  renderFunction();
+   * })
+   * ```
+   *
+   * Note that this will return _the actual function_ - not the name of the function.
+   * If you need the actual name of the property, pass in `false` as a third argument
+   *
+   * ```js
+   * var rAFProp = prefixed('requestAnimationFrame', window, false);
+   *
+   * rafProp === 'WebkitRequestAnimationFrame' // in older webkit
+   * ```
+   *
+   * One common use case for prefixed is if you're trying to determine which transition
+   * end event to bind to, you might do something like...
+   * ```js
+   * var transEndEventNames = {
+   *     'WebkitTransition' : 'webkitTransitionEnd', * Saf 6, Android Browser
+   *     'MozTransition'    : 'transitionend',       * only for FF < 15
+   *     'transition'       : 'transitionend'        * IE10, Opera, Chrome, FF 15+, Saf 7+
+   * };
+   *
+   * var transEndEventName = transEndEventNames[ Modernizr.prefixed('transition') ];
+   * ```
+   *
+   * If you want a similar lookup, but in hyphen-case, you can use [prefixedCSS](#modernizr-prefixedcss).
+   */
+  var prefixed = ModernizrProto.prefixed = function(prop, obj, elem) {
+    if (prop.indexOf('@') === 0) {
+      return atRule(prop);
+    }
+
+    if (prop.indexOf('-') !== -1) {
+      // Convert hyphen-case to camelCase
+      prop = cssToDOM(prop);
+    }
+    if (!obj) {
+      return testPropsAll(prop, 'pfx');
+    } else {
+      // Testing DOM property e.g. Modernizr.prefixed('requestAnimationFrame', window) // 'mozRequestAnimationFrame'
+      return testPropsAll(prop, obj, elem);
+    }
+  };
+
+  return prefixed;
+});
diff --git a/src/prefixedCSS.js b/src/prefixedCSS.js
new file mode 100644
index 0000000..e37aa1e
--- /dev/null
+++ b/src/prefixedCSS.js
@@ -0,0 +1,35 @@
+define(['ModernizrProto', 'prefixed', 'domToCSS'], function(ModernizrProto, prefixed, domToCSS) {
+  /**
+   * prefixedCSS is just like [prefixed](#modernizr-prefixed), but the returned values are in
+   * hyphen-case (e.g. `box-sizing`) rather than camelCase (boxSizing).
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.prefixedCSS
+   * @optionName Modernizr.prefixedCSS()
+   * @optionProp prefixedCSS
+   * @access public
+   * @function prefixedCSS
+   * @param {string} prop - String name of the property to test for
+   * @returns {string|boolean} The string representing the (possibly prefixed)
+   * valid version of the property, or `false` when it is unsupported.
+   * @example
+   *
+   * `Modernizr.prefixedCSS` is like `Modernizr.prefixed`, but returns the result
+   * in hyphenated form
+   *
+   * ```js
+   * Modernizr.prefixedCSS('transition') // '-moz-transition' in old Firefox
+   * ```
+   *
+   * Since it is only useful for CSS style properties, it can only be tested against
+   * an HTMLElement.
+   *
+   * Properties can be passed as both the DOM style camelCase or CSS style hyphen-case.
+   */
+  var prefixedCSS = ModernizrProto.prefixedCSS = function(prop) {
+    var prefixedProp = prefixed(prop);
+    return prefixedProp && domToCSS(prefixedProp);
+  };
+
+  return prefixedCSS;
+});
diff --git a/src/prefixedCSSValue.js b/src/prefixedCSSValue.js
new file mode 100644
index 0000000..e429ff0
--- /dev/null
+++ b/src/prefixedCSSValue.js
@@ -0,0 +1,49 @@
+define(['ModernizrProto', 'domPrefixes', 'createElement'], function(ModernizrProto, domPrefixes, createElement) {
+  /**
+   * prefixedCSSValue is a way test for prefixed css properties (e.g. display: -webkit-flex)
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.prefixedCSSValue
+   * @optionName Modernizr.prefixedCSSValue()
+   * @optionProp prefixedCSSValue
+   * @access public
+   * @function prefixedCSSValue
+   * @param {string} prop - String name of the property to test for
+   * @param {string} value - String value of the non prefixed version of the value you want to test for
+   * @returns {string|boolean} The string representing the (possibly prefixed)
+   * valid version of the property, or `false` when it is unsupported.
+   * @example
+   *
+   * `Modernizr.prefixedCSSValue` is a way test for prefixed css properties (e.g. display: -webkit-flex)
+   *
+   * ```js
+   * Modernizr.prefixedCSSValue('background', 'linear-gradient(left, red, red)')
+   * ```
+   */
+  var prefixedCSSValue = function(prop, value) {
+    var result = false;
+    var elem = createElement('div');
+    var style = elem.style;
+
+    if (prop in style) {
+      var i = domPrefixes.length;
+
+      style[prop] = value;
+      result = style[prop];
+
+      while (i-- && !result) {
+        style[prop] = '-' + domPrefixes[i] + '-' + value;
+        result = style[prop];
+      }
+    }
+
+    if (result === '') {
+      result = false;
+    }
+
+    return result;
+  };
+
+  ModernizrProto.prefixedCSSValue = prefixedCSSValue;
+  return prefixedCSSValue;
+});
diff --git a/src/prefixes.js b/src/prefixes.js
new file mode 100644
index 0000000..817f6f3
--- /dev/null
+++ b/src/prefixes.js
@@ -0,0 +1,41 @@
+define(['ModernizrProto'], function(ModernizrProto) {
+  /**
+   * List of property values to set for css tests. See ticket #21
+   * https://github.com/modernizr/modernizr/issues/21
+   *
+   * @memberOf Modernizr
+   * @name Modernizr._prefixes
+   * @optionName Modernizr._prefixes
+   * @optionProp prefixes
+   * @access public
+   * @example
+   *
+   * Modernizr._prefixes is the internal list of prefixes that we test against
+   * inside of things like [prefixed](#modernizr-prefixed) and [prefixedCSS](#-code-modernizr-prefixedcss). It is simply
+   * an array of hyphen-case vendor prefixes you can use within your code.
+   *
+   * Some common use cases include
+   *
+   * Generating all possible prefixed version of a CSS property
+   * ```js
+   * var rule = Modernizr._prefixes.join('transform: rotate(20deg); ');
+   *
+   * rule === 'transform: rotate(20deg); webkit-transform: rotate(20deg); moz-transform: rotate(20deg); o-transform: rotate(20deg); ms-transform: rotate(20deg);'
+   * ```
+   *
+   * Generating all possible prefixed version of a CSS value
+   * ```js
+   * rule = 'display:' +  Modernizr._prefixes.join('flex; display:') + 'flex';
+   *
+   * rule === 'display:flex; display:-webkit-flex; display:-moz-flex; display:-o-flex; display:-ms-flex; display:flex'
+   * ```
+   */
+  // we use ['',''] rather than an empty array in order to allow a pattern of .`join()`ing prefixes to test
+  // values in feature detects to continue to work
+  var prefixes = (ModernizrProto._config.usePrefixes ? ' -webkit- -moz- -o- -ms- '.split(' ') : ['','']);
+
+  // expose these for the plugin API. Look in the source for how to join() them against your input
+  ModernizrProto._prefixes = prefixes;
+
+  return prefixes;
+});
diff --git a/src/roundedEquals.js b/src/roundedEquals.js
new file mode 100644
index 0000000..63ce9f1
--- /dev/null
+++ b/src/roundedEquals.js
@@ -0,0 +1,16 @@
+define(function() {
+  /**
+   * roundedEquals takes two integers and checks if the first is within 1 of the second
+   *
+   * @access private
+   * @function roundedEquals
+   * @param {number} a - first integer
+   * @param {number} b - second integer
+   * @returns {boolean} true if the first integer is within 1 of the second, false otherwise
+   */
+  function roundedEquals(a, b) {
+    return a - 1 === b || a === b || a + 1 === b;
+  }
+
+  return roundedEquals;
+});
diff --git a/src/setClasses.js b/src/setClasses.js
new file mode 100644
index 0000000..115278c
--- /dev/null
+++ b/src/setClasses.js
@@ -0,0 +1,40 @@
+define(['Modernizr', 'docElement', 'isSVG'], function(Modernizr, docElement, isSVG) {
+  /**
+   * setClasses takes an array of class names and adds them to the root element
+   *
+   * @access private
+   * @function setClasses
+   * @param {string[]} classes - Array of class names
+   */
+  // Pass in an and array of class names, e.g.:
+  //  ['no-webp', 'borderradius', ...]
+  function setClasses(classes) {
+    var className = docElement.className;
+    var classPrefix = Modernizr._config.classPrefix || '';
+
+    if (isSVG) {
+      className = className.baseVal;
+    }
+
+    // Change `no-js` to `js` (independently of the `enableClasses` option)
+    // Handle classPrefix on this too
+    if (Modernizr._config.enableJSClass) {
+      var reJS = new RegExp('(^|\\s)' + classPrefix + 'no-js(\\s|$)');
+      className = className.replace(reJS, '$1' + classPrefix + 'js$2');
+    }
+
+    if (Modernizr._config.enableClasses) {
+      // Add the new classes
+      if (classes.length > 0) {
+        className += ' ' + classPrefix + classes.join(' ' + classPrefix);
+      }
+      if (isSVG) {
+        docElement.className.baseVal = className;
+      } else {
+        docElement.className = className;
+      }
+    }
+  }
+
+  return setClasses;
+});
diff --git a/src/slice.js b/src/slice.js
new file mode 100644
index 0000000..4a9c069
--- /dev/null
+++ b/src/slice.js
@@ -0,0 +1,11 @@
+define(['classes'], function(classes) {
+  /**
+   * slice exposes Array.prototype.slice to convert array-like objects to actual
+   * arrays in a compact format without recreating new arrays over and over again
+   * (which leads to decreased performance)
+   *
+   * @access private
+   */
+  var slice = classes.slice;
+  return slice;
+});
diff --git a/src/testAllProps.js b/src/testAllProps.js
new file mode 100644
index 0000000..e61ebd6
--- /dev/null
+++ b/src/testAllProps.js
@@ -0,0 +1,46 @@
+define(['ModernizrProto', 'testPropsAll'], function(ModernizrProto, testPropsAll) {
+  /**
+   * testAllProps determines whether a given CSS property is supported in the browser
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.testAllProps
+   * @optionName Modernizr.testAllProps()
+   * @optionProp testAllProps
+   * @access public
+   * @function testAllProps
+   * @param {string} prop - String naming the property to test (either camelCase or hyphen-case)
+   * @param {string} [value] - String of the value to test
+   * @param {boolean} [skipValueTest=false] - Whether to skip testing that the value is supported when using non-native detection
+   * @returns {string|boolean} returns the string version of the property, or `false` if it is unsupported
+   * @example
+   *
+   * testAllProps determines whether a given CSS property, in some prefixed form,
+   * is supported by the browser.
+   *
+   * ```js
+   * testAllProps('boxSizing')  // true
+   * ```
+   *
+   * It can optionally be given a CSS value in string form to test if a property
+   * value is valid
+   *
+   * ```js
+   * testAllProps('display', 'block') // true
+   * testAllProps('display', 'penguin') // false
+   * ```
+   *
+   * A boolean can be passed as a third parameter to skip the value check when
+   * native detection (@supports) isn't available.
+   *
+   * ```js
+   * testAllProps('shapeOutside', 'content-box', true);
+   * ```
+   */
+  function testAllProps(prop, value, skipValueTest) {
+    return testPropsAll(prop, undefined, undefined, value, skipValueTest);
+  }
+
+  ModernizrProto.testAllProps = testAllProps;
+
+  return testAllProps;
+});
diff --git a/src/testDOMProps.js b/src/testDOMProps.js
new file mode 100644
index 0000000..7892d53
--- /dev/null
+++ b/src/testDOMProps.js
@@ -0,0 +1,40 @@
+define(['is', 'fnBind'], function(is, fnBind) {
+  /**
+   * testDOMProps is a generic DOM property test; if a browser supports
+   *   a certain property, it won't return undefined for it.
+   *
+   * @access private
+   * @function testDOMProps
+   * @param {Array<string>} props - An array of properties to test for
+   * @param {object} obj - An object or Element you want to use to test the parameters again
+   * @param {boolean|object} elem - An Element to bind the property lookup again. Use `false` to prevent the check
+   * @returns {boolean|*} returns `false` if the prop is unsupported, otherwise the value that is supported
+   */
+  function testDOMProps(props, obj, elem) {
+    var item;
+
+    for (var i in props) {
+      if (props[i] in obj) {
+
+        // return the property name as a string
+        if (elem === false) {
+          return props[i];
+        }
+
+        item = obj[props[i]];
+
+        // let's bind a function
+        if (is(item, 'function')) {
+          // bind to obj unless overridden
+          return fnBind(item, elem || obj);
+        }
+
+        // return the unbound function or obj or value
+        return item;
+      }
+    }
+    return false;
+  }
+
+  return testDOMProps;
+});
diff --git a/src/testProp.js b/src/testProp.js
new file mode 100644
index 0000000..d283a48
--- /dev/null
+++ b/src/testProp.js
@@ -0,0 +1,40 @@
+define(['ModernizrProto', 'testProps'], function(ModernizrProto, testProps) {
+  /**
+   * testProp() investigates whether a given style property is recognized
+   * Property names can be provided in either camelCase or hyphen-case.
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.testProp
+   * @access public
+   * @optionName Modernizr.testProp()
+   * @optionProp testProp
+   * @function testProp
+   * @param {string} prop - Name of the CSS property to check
+   * @param {string} [value] - Name of the CSS value to check
+   * @param {boolean} [useValue] - Whether or not to check the value if @supports isn't supported
+   * @returns {boolean} an empty string if the property is supported, undefined if its unsupported
+   * @example
+   *
+   * Just like [testAllProps](#modernizr-testallprops), only it does not check any vendor prefixed
+   * version of the string.
+   *
+   * Note that the property name must be provided in camelCase (e.g. boxSizing not box-sizing)
+   *
+   * ```js
+   * Modernizr.testProp('pointerEvents')  // true
+   * ```
+   *
+   * You can also provide a value as an optional second argument to check if a
+   * specific value is supported
+   *
+   * ```js
+   * Modernizr.testProp('pointerEvents', 'none') // true
+   * Modernizr.testProp('pointerEvents', 'penguin') // false
+   * ```
+   */
+  var testProp = ModernizrProto.testProp = function(prop, value, useValue) {
+    return testProps([prop], undefined, value, useValue);
+  };
+
+  return testProp;
+});
diff --git a/src/testProps.js b/src/testProps.js
new file mode 100644
index 0000000..d9f3c96
--- /dev/null
+++ b/src/testProps.js
@@ -0,0 +1,95 @@
+define(['contains', 'mStyle', 'createElement', 'nativeTestProps', 'is', 'cssToDOM'], function(contains, mStyle, createElement, nativeTestProps, is, cssToDOM) {
+  // testProps is a generic CSS / DOM property test.
+
+  // In testing support for a given CSS property, it's legit to test:
+  //    `elem.style[styleName] !== undefined`
+  // If the property is supported it will return an empty string,
+  // if unsupported it will return undefined.
+
+  // We'll take advantage of this quick test and skip setting a style
+  // on our modernizr element, but instead just testing undefined vs
+  // empty string.
+
+  // Property names can be provided in either camelCase or hyphen-case.
+
+  function testProps(props, prefixed, value, skipValueTest) {
+    skipValueTest = is(skipValueTest, 'undefined') ? false : skipValueTest;
+
+    // Try native detect first
+    if (!is(value, 'undefined')) {
+      var result = nativeTestProps(props, value);
+      if (!is(result, 'undefined')) {
+        return result;
+      }
+    }
+
+    // Otherwise do it properly
+    var afterInit, i, propsLength, prop, before;
+
+    // If we don't have a style element, that means we're running async or after
+    // the core tests, so we'll need to create our own elements to use.
+
+    // Inside of an SVG element, in certain browsers, the `style` element is only
+    // defined for valid tags. Therefore, if `modernizr` does not have one, we
+    // fall back to a less used element and hope for the best.
+    // For strict XHTML browsers the hardly used samp element is used.
+    var elems = ['modernizr', 'tspan', 'samp'];
+    while (!mStyle.style && elems.length) {
+      afterInit = true;
+      mStyle.modElem = createElement(elems.shift());
+      mStyle.style = mStyle.modElem.style;
+    }
+
+    // Delete the objects if we created them.
+    function cleanElems() {
+      if (afterInit) {
+        delete mStyle.style;
+        delete mStyle.modElem;
+      }
+    }
+
+    propsLength = props.length;
+    for (i = 0; i < propsLength; i++) {
+      prop = props[i];
+      before = mStyle.style[prop];
+
+      if (contains(prop, '-')) {
+        prop = cssToDOM(prop);
+      }
+
+      if (mStyle.style[prop] !== undefined) {
+
+        // If value to test has been passed in, do a set-and-check test.
+        // 0 (integer) is a valid property value, so check that `value` isn't
+        // undefined, rather than just checking it's truthy.
+        if (!skipValueTest && !is(value, 'undefined')) {
+
+          // Needs a try catch block because of old IE. This is slow, but will
+          // be avoided in most cases because `skipValueTest` will be used.
+          try {
+            mStyle.style[prop] = value;
+          } catch (e) {}
+
+          // If the property value has changed, we assume the value used is
+          // supported. If `value` is empty string, it'll fail here (because
+          // it hasn't changed), which matches how browsers have implemented
+          // CSS.supports()
+          if (mStyle.style[prop] !== before) {
+            cleanElems();
+            return prefixed === 'pfx' ? prop : true;
+          }
+        }
+        // Otherwise just return true, or the property name if this is a
+        // `prefixed()` call
+        else {
+          cleanElems();
+          return prefixed === 'pfx' ? prop : true;
+        }
+      }
+    }
+    cleanElems();
+    return false;
+  }
+
+  return testProps;
+});
diff --git a/src/testPropsAll.js b/src/testPropsAll.js
new file mode 100644
index 0000000..84bcda1
--- /dev/null
+++ b/src/testPropsAll.js
@@ -0,0 +1,41 @@
+define(['ModernizrProto', 'cssomPrefixes', 'is', 'testProps', 'domPrefixes', 'testDOMProps'], function(ModernizrProto, cssomPrefixes, is, testProps, domPrefixes, testDOMProps) {
+  /**
+   * testPropsAll tests a list of DOM properties we want to check against.
+   * We specify literally ALL possible (known and/or likely) properties on
+   * the element including the non-vendor prefixed one, for forward-
+   * compatibility.
+   *
+   * @access private
+   * @function testPropsAll
+   * @param {string} prop - A string of the property to test for
+   * @param {string|object} [prefixed] - An object to check the prefixed properties on. Use a string to skip
+   * @param {HTMLElement|SVGElement} [elem] - An element used to test the property and value against
+   * @param {string} [value] - A string of a css value
+   * @param {boolean} [skipValueTest] - An boolean representing if you want to test if value sticks when set
+   * @returns {string|boolean} returns the string version of the property, or `false` if it is unsupported
+   */
+  function testPropsAll(prop, prefixed, elem, value, skipValueTest) {
+
+    var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1),
+      props = (prop + ' ' + cssomPrefixes.join(ucProp + ' ') + ucProp).split(' ');
+
+    // did they call .prefixed('boxSizing') or are we just testing a prop?
+    if (is(prefixed, 'string') || is(prefixed, 'undefined')) {
+      return testProps(props, prefixed, value, skipValueTest);
+
+      // otherwise, they called .prefixed('requestAnimationFrame', window[, elem])
+    } else {
+      props = (prop + ' ' + (domPrefixes).join(ucProp + ' ') + ucProp).split(' ');
+      return testDOMProps(props, prefixed, elem);
+    }
+  }
+
+  // Modernizr.testAllProps() investigates whether a given style property,
+  // or any of its vendor-prefixed variants, is recognized
+  //
+  // Note that the property names must be provided in the camelCase variant.
+  // Modernizr.testAllProps('boxSizing')
+  ModernizrProto.testAllProps = testPropsAll;
+
+  return testPropsAll;
+});
diff --git a/src/testRunner.js b/src/testRunner.js
new file mode 100644
index 0000000..a067903
--- /dev/null
+++ b/src/testRunner.js
@@ -0,0 +1,70 @@
+define(['tests', 'Modernizr', 'classes', 'is'], function(tests, Modernizr, classes, is) {
+  /**
+   * Run through all tests and detect their support in the current UA.
+   *
+   * @access private
+   * @returns {void}
+   */
+  function testRunner() {
+    var featureNames;
+    var feature;
+    var aliasIdx;
+    var result;
+    var nameIdx;
+    var featureName;
+    var featureNameSplit;
+
+    for (var featureIdx in tests) {
+      if (tests.hasOwnProperty(featureIdx)) {
+        featureNames = [];
+        feature = tests[featureIdx];
+        // run the test, throw the return value into the Modernizr,
+        // then based on that boolean, define an appropriate className
+        // and push it into an array of classes we'll join later.
+        //
+        // If there is no name, it's an 'async' test that is run,
+        // but not directly added to the object. That should
+        // be done with a post-run addTest call.
+        if (feature.name) {
+          featureNames.push(feature.name.toLowerCase());
+
+          if (feature.options && feature.options.aliases && feature.options.aliases.length) {
+            // Add all the aliases into the names list
+            for (aliasIdx = 0; aliasIdx < feature.options.aliases.length; aliasIdx++) {
+              featureNames.push(feature.options.aliases[aliasIdx].toLowerCase());
+            }
+          }
+        }
+
+        // Run the test, or use the raw value if it's not a function
+        result = is(feature.fn, 'function') ? feature.fn() : feature.fn;
+
+        // Set each of the names on the Modernizr object
+        for (nameIdx = 0; nameIdx < featureNames.length; nameIdx++) {
+          featureName = featureNames[nameIdx];
+          // Support dot properties as sub tests. We don't do checking to make sure
+          // that the implied parent tests have been added. You must call them in
+          // order (either in the test, or make the parent test a dependency).
+          //
+          // Cap it to TWO to make the logic simple and because who needs that kind of subtesting
+          // hashtag famous last words
+          featureNameSplit = featureName.split('.');
+
+          if (featureNameSplit.length === 1) {
+            Modernizr[featureNameSplit[0]] = result;
+          } else {
+            // cast to a Boolean, if not one already or if it doesnt exist yet (like inputtypes)
+            if (!Modernizr[featureNameSplit[0]] || Modernizr[featureNameSplit[0]] && !(Modernizr[featureNameSplit[0]] instanceof Boolean)) {
+              Modernizr[featureNameSplit[0]] = new Boolean(Modernizr[featureNameSplit[0]]);
+            }
+
+            Modernizr[featureNameSplit[0]][featureNameSplit[1]] = result;
+          }
+
+          classes.push((result ? '' : 'no-') + featureNameSplit.join('-'));
+        }
+      }
+    }
+  }
+  return testRunner;
+});
diff --git a/src/testStyles.js b/src/testStyles.js
new file mode 100644
index 0000000..9b86873
--- /dev/null
+++ b/src/testStyles.js
@@ -0,0 +1,59 @@
+define(['ModernizrProto', 'injectElementWithStyles'], function(ModernizrProto, injectElementWithStyles) {
+  /**
+   * testStyles injects an element with style element and some CSS rules
+   *
+   * @memberOf Modernizr
+   * @name Modernizr.testStyles
+   * @optionName Modernizr.testStyles()
+   * @optionProp testStyles
+   * @access public
+   * @function testStyles
+   * @param {string} rule - String representing a css rule
+   * @param {Function} callback - A function that is used to test the injected element
+   * @param {number} [nodes] - An integer representing the number of additional nodes you want injected
+   * @param {string[]} [testnames] - An array of strings that are used as ids for the additional nodes
+   * @returns {boolean}
+   * @example
+   *
+   * `Modernizr.testStyles` takes a CSS rule and injects it onto the current page
+   * along with (possibly multiple) DOM elements. This lets you check for features
+   * 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).
+   *
+   * ```js
+   * Modernizr.testStyles('#modernizr { width: 9px; color: papayawhip; }', function(elem, rule) {
+   *   // elem is the first DOM node in the page (by default #modernizr)
+   *   // rule is the first argument you supplied - the CSS rule in string form
+   *
+   *   addTest('widthworks', elem.style.width === '9px')
+   * });
+   * ```
+   *
+   * If your test requires multiple nodes, you can include a third argument
+   * indicating how many additional div elements to include on the page. The
+   * additional nodes are injected as children of the `elem` that is returned as
+   * the first argument to the callback.
+   *
+   * ```js
+   * Modernizr.testStyles('#modernizr {width: 1px}; #modernizr2 {width: 2px}', function(elem) {
+   *   document.getElementById('modernizr').style.width === '1px'; // true
+   *   document.getElementById('modernizr2').style.width === '2px'; // true
+   *   elem.firstChild === document.getElementById('modernizr2'); // true
+   * }, 1);
+   * ```
+   *
+   * By default, all of the additional elements have an ID of `modernizr[n]`, where
+   * `n` is its index (e.g. the first additional, second overall is `#modernizr2`,
+   * the second additional is `#modernizr3`, etc.).
+   * If you want to have more meaningful IDs for your function, you can provide
+   * them as the fourth argument, as an array of strings
+   *
+   * ```js
+   * Modernizr.testStyles('#foo {width: 10px}; #bar {height: 20px}', function(elem) {
+   *   elem.firstChild === document.getElementById('foo'); // true
+   *   elem.lastChild === document.getElementById('bar'); // true
+   * }, 2, ['foo', 'bar']);
+   * ```
+   */
+  var testStyles = ModernizrProto.testStyles = injectElementWithStyles;
+  return testStyles;
+});
diff --git a/src/testXhrType.js b/src/testXhrType.js
new file mode 100644
index 0000000..608360e
--- /dev/null
+++ b/src/testXhrType.js
@@ -0,0 +1,26 @@
+define(function() {
+  /**
+   * https://mathiasbynens.be/notes/xhr-responsetype-json#comment-4
+   *
+   * @author Mathias Bynens
+   * @access private
+   * @function testXhrType
+   * @param {string} type - String name of the XHR type you want to detect
+   * @returns {boolean} true if the responseType is of the specified type
+   */
+  var testXhrType = function(type) {
+    if (typeof XMLHttpRequest === 'undefined') {
+      return false;
+    }
+    var xhr = new XMLHttpRequest();
+    xhr.open('get', '/', true);
+    try {
+      xhr.responseType = type;
+    } catch (error) {
+      return false;
+    }
+    return 'response' in xhr && xhr.responseType === type;
+  };
+
+  return testXhrType;
+});
diff --git a/src/tests.js b/src/tests.js
new file mode 100644
index 0000000..3a022e6
--- /dev/null
+++ b/src/tests.js
@@ -0,0 +1,4 @@
+define(function() {
+  var tests = [];
+  return tests;
+});
diff --git a/src/toStringFn.js b/src/toStringFn.js
new file mode 100644
index 0000000..5e4686a
--- /dev/null
+++ b/src/toStringFn.js
@@ -0,0 +1,13 @@
+define(function() {
+  /**
+   * Object.prototype.toString can be used with every object and allows you to
+   * get its class easily. Abstracting it off of an object prevents situations
+   * where the toString property has been overridden
+   *
+   * @access private
+   * @function toStringFn
+   * @returns {Function} An abstracted toString function
+   */
+  var toStringFn = ({}).toString;
+  return toStringFn;
+});

More details

Full run details

Historical runs