Artur Paikin пре 3 година
родитељ
комит
172cc77f63
62 измењених фајлова са 723 додато и 328 уклоњено
  1. 61 58
      .github/CONTRIBUTING.md
  2. 1 1
      BUNDLE-README.md
  3. 83 84
      README.md
  4. 1 0
      examples/bundled/index.js
  5. 2 2
      examples/cdn-example/index.html
  6. 1 0
      examples/dev/Dashboard.js
  7. 1 1
      examples/transloadit-textarea/index.html
  8. 2 2
      examples/uppy-with-companion/client/index.html
  9. 16 16
      package-lock.json
  10. 1 1
      package.json
  11. 6 3
      packages/@uppy/angular/package.json
  12. 1 1
      packages/@uppy/aws-s3/package.json
  13. 1 0
      packages/@uppy/aws-s3/src/MiniXHRUpload.js
  14. 1 1
      packages/@uppy/companion/package.json
  15. 1 1
      packages/@uppy/companion/src/server/Uploader.js
  16. 1 1
      packages/@uppy/core/package.json
  17. 60 2
      packages/@uppy/core/src/index.js
  18. 1 1
      packages/@uppy/core/src/index.test.js
  19. 1 1
      packages/@uppy/dashboard/package.json
  20. 8 1
      packages/@uppy/dashboard/src/components/EditorPanel.js
  21. 29 16
      packages/@uppy/dashboard/src/components/FileCard/index.js
  22. 1 1
      packages/@uppy/dashboard/src/components/PickerPanelContent.js
  23. 14 1
      packages/@uppy/dashboard/src/index.js
  24. 2 1
      packages/@uppy/dashboard/src/style.scss
  25. 2 0
      packages/@uppy/dashboard/types/index.d.ts
  26. 1 1
      packages/@uppy/drag-drop/package.json
  27. 1 1
      packages/@uppy/image-editor/package.json
  28. 5 25
      packages/@uppy/image-editor/src/Editor.js
  29. 27 13
      packages/@uppy/image-editor/src/index.js
  30. 1 1
      packages/@uppy/locales/package.json
  31. 1 1
      packages/@uppy/locales/src/de_DE.js
  32. 2 0
      packages/@uppy/locales/src/en_US.js
  33. 1 1
      packages/@uppy/react/package.json
  34. 2 2
      packages/@uppy/robodog/README.md
  35. 1 1
      packages/@uppy/robodog/package.json
  36. 55 0
      packages/@uppy/robodog/types/index.d.ts
  37. 83 0
      packages/@uppy/robodog/types/index.test-d.ts
  38. 1 1
      packages/@uppy/screen-capture/package.json
  39. 1 1
      packages/@uppy/svelte/package.json
  40. 1 1
      packages/@uppy/transloadit/package.json
  41. 84 1
      packages/@uppy/transloadit/types/index.d.ts
  42. 1 1
      packages/@uppy/vue/package.json
  43. 1 1
      packages/@uppy/webcam/package.json
  44. 1 1
      packages/uppy/package.json
  45. 2 0
      test/endtoend/providers/main.js
  46. 2 0
      test/endtoend/typescript/main.ts
  47. 102 51
      website/src/_template/contributing.md
  48. 1 0
      website/src/docs/box.md
  49. 6 5
      website/src/docs/dashboard.md
  50. 1 1
      website/src/docs/drop-target.md
  51. 5 5
      website/src/docs/index.md
  52. 2 2
      website/src/docs/locales.md
  53. 4 4
      website/src/docs/robodog-form.md
  54. 2 2
      website/src/docs/robodog.md
  55. 2 0
      website/src/docs/uppy.md
  56. 11 1
      website/src/examples/dashboard/app.es6
  57. 3 0
      website/src/examples/dashboard/app.html
  58. 4 1
      website/src/examples/dashboard/index.ejs
  59. 3 3
      website/src/examples/i18n/app.html
  60. 1 1
      website/src/examples/markdown-snippets/app.es6
  61. 1 1
      website/src/examples/markdown-snippets/app.html
  62. 3 2
      website/themes/uppy/layout/index.ejs

+ 61 - 58
.github/CONTRIBUTING.md

@@ -14,8 +14,8 @@ Our website’s examples section is also our playground, please read the [Local
 
 ### Requiring files
 
-- If we are `require()`ing a file from the same subpackage (e.g. require `@uppy/dashboard/utils/hi.js` from `@uppy/dashboard/src/index.js`) - we can freely use relative imports, as long as the required file is under the `src` directory (`/:packageName/src/**/*.js`).
-- But if we want to require some file from another subpackage - we should use global @uppy requires, and they should always be in the form of `@uppy/:packageName/(lib instead of src)/(same path).js`
+*   If we are `require()`ing a file from the same subpackage, we can freely use relative imports as long as the required file is under the `src` directory (for example to import `@uppy/dashboard/src/utils/hi.js` from `@uppy/dashboard/src/index.js`, use `require('./utils/hi.js')`).
+*   But if we want to `require()` some file from another subpackage - we should use global @uppy requires, and they should always be in the form of `@uppy/:packageName/(lib instead of src)/(same path).js`
 
 ## Tests
 
@@ -25,7 +25,7 @@ Unit tests are using Jest and can be run with:
 npm run test:unit
 ```
 
-For end-to-end tests, we use [Webdriverio](http://webdriver.io). For it to run locally, you need to install a Selenium standalone server. Just follow [the guide](http://webdriver.io/guide.html) to do so. You can also install a Selenium standalone server from NPM:
+For end-to-end tests, we use [Webdriverio](http://webdriver.io). For it to run locally, you need to install a Selenium standalone server. Follow [the Webdriverio guide](http://webdriver.io/guide.html) to do so. You can also install a Selenium standalone server from NPM:
 
 ```bash
 npm install selenium-standalone -g
@@ -52,13 +52,13 @@ npm run test:endtoend:local -- -b chrome
 
 > Note: The `--` is important, it tells npm that the remaining arguments should be interpreted by the script itself, not by npm.
 
-You can run in multiple browsers by passing multiple `-b` flags:
+You can run in several browsers by passing several `-b` flags:
 
 ```bash
 npm run test:endtoend:local -- -b chrome -b firefox
 ```
 
-When trying to get a specific integration test to pass, it's not that helpful to continuously run _all_ tests. You can use the `--suite` flag to run tests from a single `./test/endtoend` folder. For example, `--suite thumbnails` will only run the tests from `./test/endtoend/thumbnails`. Of course, it can also be combined with one or more `-b` flags.
+When trying to get a specific integration test to pass, its not that helpful to continuously run _all_ tests. You can use the `--suite` flag to run tests from a single `./test/endtoend` folder. For example, `--suite thumbnails` will only run the tests from `./test/endtoend/thumbnails`. It can also be used in conjunction with one or more `-b` flags.
 
 ```bash
 npm run test:endtoend:local -- -b chrome --suite thumbnails
@@ -70,26 +70,27 @@ These tests are also run automatically on Travis builds with [SauceLabs](https:/
 
 ### Instagram integration
 
-Even though facebook [allows using](https://developers.facebook.com/blog/post/2018/06/08/enforce-https-facebook-login/) http://localhost in dev mode, Instagram doesn't seem to support that, and seems to need a publically available domain name with HTTPS.
+Even though facebook [allows using](https://developers.facebook.com/blog/post/2018/06/08/enforce-https-facebook-login/) http://localhost in dev mode, Instagram doesnt seem to support that, and seems to need a publically available domain name with HTTPS.
 
 Make sure that you are using a development facebook app at <https://developers.facebook.com/apps>
 
-Go to "Instagram Basic Display" and find `Instagram App ID` and `Instagram App Secret`. Put them in a file called `env.sh` in the repo root:
+Go to “Instagram Basic Display” and find `Instagram App ID` and `Instagram App Secret`. Put them in a file called `env.sh` in the repo root:
+
 ```bash
 export COMPANION_INSTAGRAM_KEY="Instagram App ID"
 export COMPANION_INSTAGRAM_SECRET="Instagram App Secret"
 ```
 
 Run
+
 ```bash
 ngrok http 3020
 ```
-Note the ngrok https base URL, e.g. `https://e0c7de09808d.ngrok.io` and
-append `/instagram/redirect` to it, e.g.:
 
-```
-https://e0c7de09808d.ngrok.io/instagram/redirect
-```
+Note the ngrok https base URL, for example `https://e0c7de09808d.ngrok.io` and
+append `/instagram/redirect` to it, such as:
+
+    https://e0c7de09808d.ngrok.io/instagram/redirect
 
 Add this full ngrok URL to `Valid OAuth Redirect URIs` under `Instagram Basic Display`.
 
@@ -102,7 +103,7 @@ COMPANION_PROTOCOL="https"
 
 Edit `examples/dev/Dashboard.js`:
 
-```
+```js
 const COMPANION_URL = 'https://e0c7de09808d.ngrok.io'
 ```
 
@@ -137,37 +138,37 @@ Releases are managed by [Lerna](https://github.com/lerna/lerna). We do some clea
 npm run release
 ```
 
-If you have two-factor authentication enabled on your account, Lerna will ask for a one-time password. There is an issue with the CLI where the OTP prompt may be obscured by a publishing progress bar. If Lerna appears to hang just as it starts publishing, chances are it's waiting for the password. Try typing in your OTP and hitting enter.
+If you have two-factor authentication enabled on your account, Lerna will ask for a one-time password. You may stumble upon a known issue with the CLI where the OTP prompt may be obscured by a publishing progress bar. If Lerna appears to freeze as it starts publishing, chances are it’s waiting for the password. Try typing in your OTP and hitting enter.
 
 Other things to keep in mind during release:
 
-* When doing a major release >= 1.0, of the `@uppy/core` package, the `peerDependency` of the plugin packages needs to be updated first. Eg when updating from 1.y.z to 2.0.0, the peerDependency of each should be `"@uppy/core": "^2.0.0"` before doing `npm run release`.
-* When adding a new package, add the following key to its package.json:
-  ```json
-  "publishConfig": { "access": "public" }
-  ```
-  Else, npm will try and fail to publish a _private_ package, because the `@uppy` scope on npm does not support that.
+*   When doing a major release >= 1.0, of the `@uppy/core` package, the `peerDependency` of the plugin packages needs to be updated first. Eg when updating from 1.y.z to 2.0.0, the peerDependency of each should be `"@uppy/core": "^2.0.0"` before doing `npm run release`.
+*   When adding a new package, add the following key to its package.json:
+    ```json
+    "publishConfig": { "access": "public" }
+    ```
+    Else, npm will try and fail to publish a _private_ package, because the `@uppy` scope on npm does not support that.
 
 After a release, the demos on transloadit.com should also be updated. After updating, check that some things work locally:
 
- - the demos in the demo section work (try one that uses an import robot, and one that you need to upload to)
- - the demos on the homepage work and can import from Google Drive, Instagram, Dropbox, etc.
+*   the demos in the demo section work (try one that uses an import robot, and one that you need to upload to)
+*   the demos on the homepage work and can import from Google Drive, Instagram, Dropbox, etc.
 
-If you don't have access to the transloadit.com source code ping @arturi or @goto-bus-stop and we'll pick it up. :sparkles:
+If you don’t have access to the transloadit.com source code ping @arturi or @goto-bus-stop and we’ll pick it up. :sparkles:
 
 ## Website development
 
-We keep the [uppy.io](http://uppy.io) website in `./website`, so it’s easy to keep docs and code in sync as we are still iterating at high velocity.
+We keep the [uppy.io](http://uppy.io) website in `./website` to keep docs and code in sync as we are still iterating at high velocity.
 
-The site is built with [Hexo](http://hexo.io/), and Travis automatically deploys this onto GitHub Pages (it overwrites the `gh-pages` branch with Hexo's build at every change to `master`). The content is written in Markdown and located in `./website/src`. Feel free to fork & hack!
+The site is built with [Hexo](http://hexo.io/), and Travis automatically deploys this onto GitHub Pages (it overwrites the `gh-pages` branch with Hexos build at every change to `master`). The content is written in Markdown and located in `./website/src`. Feel free to fork & hack!
 
 Even though bundled in this repo, the website is regarded as a separate project. As such, it has its own `package.json` and we aim to keep the surface where the two projects interface as small as possible. `./website/update.js` is called during website builds to inject the Uppy knowledge into the site.
 
 ### Local previews
 
-1. `npm install`
-1. `npm start`
-1. Go to http://localhost:4000. Your changes in `/website` and `/packages/@uppy` will be watched, your browser will refresh as files change.
+1.  `npm install`
+2.  `npm start`
+3.  Go to http://localhost:4000. Your changes in `/website` and `/packages/@uppy` will be watched, your browser will refresh as files change.
 
 Then, to work on, for instance, the XHRUpload example, you would edit the following files:
 
@@ -182,7 +183,7 @@ And open <http://localhost:4000/examples/xhrupload/> in your web browser.
 
 ## CSS guidelines
 
-The CSS standards followed in this project closely resemble those from [Medium's CSS Guidelines](https://gist.github.com/fat/a47b882eb5f84293c4ed). If something is not mentioned here, follow their guidelines.
+The CSS standards followed in this project closely resemble those from [Mediums CSS Guidelines](https://gist.github.com/fat/a47b882eb5f84293c4ed). If something is not mentioned here, follow their guidelines.
 
 ### Naming conventions
 
@@ -221,7 +222,7 @@ Syntax: `[<namespace>-]<ComponentName>[-descendentName][--modifierName]`
 
 ### SASS
 
-This project uses SASS, with some limitations on nesting.  One-level-deep nesting is allowed, but nesting may not extend a selector by using the `&` operator.  For example:
+This project uses SASS, with some limitations on nesting. One-level-deep nesting is allowed, but nesting may not extend a selector by using the `&` operator. For example:
 
 ```sass
 /* BAD */
@@ -247,11 +248,11 @@ Style to the mobile breakpoint with your selectors, then use `min-width` media q
 
 ### Selector, rule ordering
 
-- All selectors are sorted alphabetically and by type.
-- HTML elements go above classes and IDs in a file.
-- Rules are sorted alphabetically.
+*   All selectors are sorted alphabetically and by type.
+*   HTML elements go above classes and IDs in a file.
+*   Rules are sorted alphabetically.
 
-```sass
+```scss
 /* BAD */
 .wrapper {
   width: 940px;
@@ -287,28 +288,29 @@ h1 {
 
 Before opening a pull request for the new integration, open an issue to discuss said integration with the Uppy team. After discussing the integration, you can get started on it. First off, you need to construct the basic components for your integration. The following components are the current standard:
 
-- `Dashboard`: Inline Dashboard (`inline: true`)
-- `DashboardModal`: Dashboard as a modal
-- `DragDrop`
-- `ProgressBar`
-- `StatusBar`
+*   `Dashboard`: Inline Dashboard (`inline: true`)
+*   `DashboardModal`: Dashboard as a modal
+*   `DragDrop`
+*   `ProgressBar`
+*   `StatusBar`
 
-All of these components should function as references to the normal component. Depending on how the framework you're using handles references to the DOM, your approach to creating these may be different. For example, in React, you can assign a property of the component to the reference of a component ([see here](https://github.com/transloadit/uppy/blob/425f9ecfbc8bc48ce6b734e4fc14fa60d25daa97/packages/%40uppy/react/src/Dashboard.js#L47-L54)). This may differ in your framework, but from what we've found, the concepts are generally pretty similar.
+All these components should function as references to the normal component. Depending on how the framework youre using handles references to the DOM, your approach to creating these may be different. For example, in React, you can assign a property of the component to the reference of a component ([see here](https://github.com/transloadit/uppy/blob/425f9ecfbc8bc48ce6b734e4fc14fa60d25daa97/packages/%40uppy/react/src/Dashboard.js#L47-L54)). This may differ in your framework, but from what weve found, the concepts are generally pretty similar.
 
-If you're familiar with React, Vue or soon Svelte, it might be useful to read through the code of those integrations, as they lay out a pretty good structure. After the basic components have been built, there are a few more important tasks to get done:
+If youre familiar with React, Vue or soon Svelte, it might be useful to read through the code of those integrations, as they lay out a pretty good structure. After the basic components have been built, here are a few more important tasks to get done:
 
-- Add TypeScript support in some capacity (if possible)
-- Write documentation
-- Add an example
-- Configuring the build system
+*   Add TypeScript support in some capacity (if possible)
+*   Write documentation
+*   Add an example
+*   Configuring the build system
 
 ### Common issues
 
-Before going into these tasks, there are a few common gotchas that you should be aware of.
+Before going into these tasks, here are a few common gotchas that you should be aware of.
 
 #### Dependencies
 
 Your `package.json` should resemble something like this:
+
 ```json
 {
   "name": "@uppy/framework",
@@ -333,20 +335,21 @@ The most important part about this is that `@uppy/core` is a peer dependency. If
 
 ### Adding TypeScript Support
 
-This section won't be too in-depth, because TypeScript depends on your framework. As general advice, prefer using `d.ts` files and vanilla JavaScript over TypeScript files. This is of course circumstantial, but it makes handling the build system a lot easier when TypeScript doesn't have to transpiled. The version of typescript in the monorepo is `3.7.5`, so features like `import type` will not work at build time. For upcoming integrations, like Angular, this may be updated.
+This section wont be too in-depth, because TypeScript depends on your framework. As general advice, prefer using `d.ts` files and vanilla JavaScript over TypeScript files. This is circumstantial, but it makes handling the build system a lot easier when TypeScript doesn’t have to transpiled. The version of typescript in the monorepo is `4.1`.
 
 ### Writing docs
 
 Generally, documentation for integrations can be broken down into a few pieces that apply to every component, and then documentation for each component. The structure should look something like this:
 
-- Installation
-- Initializing Uppy (may vary depending on how the framework handles reactivity)
-- Usage
-- *For each component*
-  - Loading CSS
-  - Props
+*   Installation
+*   Initializing Uppy (may vary depending on how the framework handles reactivity)
+*   Usage
+*   _For each component_
+    *   Loading CSS
+    *   Props
 
 It may be easier to copy the documentation of earlier integrations and change the parts that need to be changed rather than writing this from scratch. Preferably, keep the documentation to one page. For the front-matter, write something like:
+
 ```markdown
 title: Framework Name
 type: docs
@@ -355,17 +358,17 @@ order: 0
 category: "Other Integrations"
 ```
 
-This data is used to generate Uppy's website. Refer to [the section about running the website locally](#website-previews) if you'd like to see how the docs look on the website.
+This data is used to generate Uppy’s website. Refer to [the section about running the website locally](#website-previews) if you’d like to see how the docs look on the website.
 
 ### Adding an example
 
-This is pretty simple to do, as you can likely use whatever code generation tool for your framework (ex. `create-react-app`) to create this example. Make sure you add the same version of `@uppy/core` to this as your peer dependency required, or you may run into strange issues. Try to include all of the components are some of their functionality. [The React example](https://github.com/transloadit/uppy/blob/master/examples/react-example/App.js) is a great... well example of how to do this well.
+You can likely use whatever code generation tool for your framework (ex. `create-react-app`) to create this example. Make sure you add the same version of `@uppy/core` to this as your peer dependency required, or you may run into strange issues. Try to include all the components are some of their functionality. [The React example](https://github.com/transloadit/uppy/blob/master/examples/react-example/App.js) is a great... well example of how to do this well.
 
 ### Integrating the build system
 
-The biggest part of this is understanding Uppy's build system. The high level description is basically `babel` goes through almost all of the packages and transpiles all the Javascript files in the `src` directory to more compatible JavaScript in the `lib` folder. If you're using vanilla JavaScript for your integration (like React and Vue do), then you can just use this build system and use the files generated as your entry points. 
+The biggest part of this is understanding Uppy’s build system. The high level description is that `babel` goes through almost all the packages and transpiles all the Javascript files in the `src` directory to more compatible JavaScript in the `lib` folder. If youre using vanilla JavaScript for your integration (like React and Vue do), then you can use this build system and use the files generated as your entry points.
 
-If you're using some kind of more abstract file format (like Svelte), then you probably want do to a few things: add the directory name to [this `IGNORE` regex](https://github.com/transloadit/uppy/blob/425f9ecfbc8bc48ce6b734e4fc14fa60d25daa97/bin/build-lib.js#L15); add all of your build dependencies to the root `package.json` (try to keep this small); add a new `build:framework` script to the root `package.json`. This script usually looks something like this:
+If youre using some kind of more abstract file format (like Svelte), then you probably want do to a few things: add the directory name to [this `IGNORE` regex](https://github.com/transloadit/uppy/blob/425f9ecfbc8bc48ce6b734e4fc14fa60d25daa97/bin/build-lib.js#L15); add all your build dependencies to the root `package.json` (try to keep this small); add a new `build:framework` script to the root `package.json`. This script usually looks something like this:
 
 ```json
 {
@@ -375,4 +378,4 @@ If you're using some kind of more abstract file format (like Svelte), then you p
 }
 ```
 
-Then, add this script to the `build:js` script. Try running the `build:js` script and make sure it does not error. It may also be of use to ensure that global dependencies aren't being used (ex. not having rollup locally and relying on a global install), as these dependencies won't be present on the machine's handling building.
+Then, add this script to the `build:js` script. Try running the `build:js` script and make sure it does not error. It may also be of use to make sure that global dependencies aren’t being used (ex. not having rollup locally and relying on a global install), as these dependencies won’t be present on the machine’s handling building.

+ 1 - 1
BUNDLE-README.md

@@ -1,7 +1,7 @@
 # Uppy
 
 Hi, thanks for trying out the bundled version of the Uppy File Uploader. You can use
-this from a CDN (e.g. `<script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.js"></script>`) or bundle it with your webapp. 
+this from a CDN (e.g. `<script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>`) or bundle it with your webapp. 
 
 Note that the recommended way to use Uppy is to install it with yarn/npm and use a 
 bundler like Webpack so that you can create a smaller custom build with just the

+ 83 - 84
README.md

@@ -69,7 +69,7 @@ $ npm install @uppy/core @uppy/dashboard @uppy/tus
 
 We recommend installing from npm and then using a module bundler such as [Webpack](https://webpack.js.org/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
 
-Add CSS [uppy.min.css](https://releases.transloadit.com/uppy/v1.30.0/uppy.min.css), either to your HTML page's `<head>` or include in JS, if your bundler of choice supports it — transforms and plugins are available for Browserify and Webpack.
+Add CSS [uppy.min.css](https://releases.transloadit.com/uppy/v1.31.0/uppy.min.css), either to your HTML page's `<head>` or include in JS, if your bundler of choice supports it — transforms and plugins are available for Browserify and Webpack.
 
 Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly. In that case `Uppy` will attach itself to the global `window.Uppy` object.
 
@@ -77,10 +77,10 @@ Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly
 
 ```html
 <!-- 1. Add CSS to `<head>` -->
-<link href="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.css" rel="stylesheet">
+<link href="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.css" rel="stylesheet">
 
 <!-- 2. Add JS before the closing `</body>` -->
-<script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.js"></script>
+<script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
 
 <!-- 3. Initialize -->
 <div class="UppyDragDrop"></div>
@@ -190,8 +190,7 @@ If you're using Uppy from CDN, those polyfills are already included in the legac
 bundle, so no need to include anything additionally:
 
 ```html
-<script nomodule src="https://releases.transloadit.com/uppy/v2.0.0/uppy.legacy.min.js"></script>
-<script type="module">import"https://releases.transloadit.com/uppy/v2.0.0/uppy.min.js";</script>
+<script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
 ```
 
 ## FAQ
@@ -256,25 +255,25 @@ Use Uppy in your project? [Let us know](https://github.com/transloadit/uppy/issu
 :---: |:---: |:---: |:---: |:---: |:---: |
 [nqst](https://github.com/nqst) |[lakesare](https://github.com/lakesare) |[kiloreux](https://github.com/kiloreux) |[sadovnychyi](https://github.com/sadovnychyi) |[samuelayo](https://github.com/samuelayo) |[richardwillars](https://github.com/richardwillars) |
 
-[<img alt="ajkachnic" src="https://avatars.githubusercontent.com/u/44317699?v=4&s=117" width="117">](https://github.com/ajkachnic) |[<img alt="dependabot[bot]" src="https://avatars.githubusercontent.com/in/29110?v=4&s=117" width="117">](https://github.com/apps/dependabot) |[<img alt="zcallan" src="https://avatars.githubusercontent.com/u/13760738?v=4&s=117" width="117">](https://github.com/zcallan) |[<img alt="tim-kos" src="https://avatars.githubusercontent.com/u/15005?v=4&s=117" width="117">](https://github.com/tim-kos) |[<img alt="janko" src="https://avatars.githubusercontent.com/u/795488?v=4&s=117" width="117">](https://github.com/janko) |[<img alt="wilkoklak" src="https://avatars.githubusercontent.com/u/17553085?v=4&s=117" width="117">](https://github.com/wilkoklak) |
+[<img alt="ajkachnic" src="https://avatars.githubusercontent.com/u/44317699?v=4&s=117" width="117">](https://github.com/ajkachnic) |[<img alt="dependabot[bot]" src="https://avatars.githubusercontent.com/in/29110?v=4&s=117" width="117">](https://github.com/apps/dependabot) |[<img alt="zcallan" src="https://avatars.githubusercontent.com/u/13760738?v=4&s=117" width="117">](https://github.com/zcallan) |[<img alt="aduh95" src="https://avatars.githubusercontent.com/u/14309773?v=4&s=117" width="117">](https://github.com/aduh95) |[<img alt="tim-kos" src="https://avatars.githubusercontent.com/u/15005?v=4&s=117" width="117">](https://github.com/tim-kos) |[<img alt="janko" src="https://avatars.githubusercontent.com/u/795488?v=4&s=117" width="117">](https://github.com/janko) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[ajkachnic](https://github.com/ajkachnic) |[dependabot[bot]](https://github.com/apps/dependabot) |[zcallan](https://github.com/zcallan) |[tim-kos](https://github.com/tim-kos) |[janko](https://github.com/janko) |[wilkoklak](https://github.com/wilkoklak) |
+[ajkachnic](https://github.com/ajkachnic) |[dependabot[bot]](https://github.com/apps/dependabot) |[zcallan](https://github.com/zcallan) |[aduh95](https://github.com/aduh95) |[tim-kos](https://github.com/tim-kos) |[janko](https://github.com/janko) |
 
-[<img alt="oliverpool" src="https://avatars.githubusercontent.com/u/3864879?v=4&s=117" width="117">](https://github.com/oliverpool) |[<img alt="Botz" src="https://avatars.githubusercontent.com/u/2706678?v=4&s=117" width="117">](https://github.com/Botz) |[<img alt="aduh95" src="https://avatars.githubusercontent.com/u/14309773?v=4&s=117" width="117">](https://github.com/aduh95) |[<img alt="mifi" src="https://avatars.githubusercontent.com/u/402547?v=4&s=117" width="117">](https://github.com/mifi) |[<img alt="mcallistertyler" src="https://avatars.githubusercontent.com/u/14939210?v=4&s=117" width="117">](https://github.com/mcallistertyler) |[<img alt="mokutsu-coursera" src="https://avatars.githubusercontent.com/u/65177495?v=4&s=117" width="117">](https://github.com/mokutsu-coursera) |
+[<img alt="wilkoklak" src="https://avatars.githubusercontent.com/u/17553085?v=4&s=117" width="117">](https://github.com/wilkoklak) |[<img alt="mifi" src="https://avatars.githubusercontent.com/u/402547?v=4&s=117" width="117">](https://github.com/mifi) |[<img alt="oliverpool" src="https://avatars.githubusercontent.com/u/3864879?v=4&s=117" width="117">](https://github.com/oliverpool) |[<img alt="Botz" src="https://avatars.githubusercontent.com/u/2706678?v=4&s=117" width="117">](https://github.com/Botz) |[<img alt="mcallistertyler" src="https://avatars.githubusercontent.com/u/14939210?v=4&s=117" width="117">](https://github.com/mcallistertyler) |[<img alt="mokutsu-coursera" src="https://avatars.githubusercontent.com/u/65177495?v=4&s=117" width="117">](https://github.com/mokutsu-coursera) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[oliverpool](https://github.com/oliverpool) |[Botz](https://github.com/Botz) |[aduh95](https://github.com/aduh95) |[mifi](https://github.com/mifi) |[mcallistertyler](https://github.com/mcallistertyler) |[mokutsu-coursera](https://github.com/mokutsu-coursera) |
+[wilkoklak](https://github.com/wilkoklak) |[mifi](https://github.com/mifi) |[oliverpool](https://github.com/oliverpool) |[Botz](https://github.com/Botz) |[mcallistertyler](https://github.com/mcallistertyler) |[mokutsu-coursera](https://github.com/mokutsu-coursera) |
 
 [<img alt="DJWassink" src="https://avatars.githubusercontent.com/u/1822404?v=4&s=117" width="117">](https://github.com/DJWassink) |[<img alt="taoqf" src="https://avatars.githubusercontent.com/u/15901911?v=4&s=117" width="117">](https://github.com/taoqf) |[<img alt="Murderlon" src="https://avatars.githubusercontent.com/u/9060226?v=4&s=117" width="117">](https://github.com/Murderlon) |[<img alt="tuoxiansp" src="https://avatars.githubusercontent.com/u/3960056?v=4&s=117" width="117">](https://github.com/tuoxiansp) |[<img alt="dominiceden" src="https://avatars.githubusercontent.com/u/6367692?v=4&s=117" width="117">](https://github.com/dominiceden) |[<img alt="elenalape" src="https://avatars.githubusercontent.com/u/22844059?v=4&s=117" width="117">](https://github.com/elenalape) |
 :---: |:---: |:---: |:---: |:---: |:---: |
 [DJWassink](https://github.com/DJWassink) |[taoqf](https://github.com/taoqf) |[Murderlon](https://github.com/Murderlon) |[tuoxiansp](https://github.com/tuoxiansp) |[dominiceden](https://github.com/dominiceden) |[elenalape](https://github.com/elenalape) |
 
-[<img alt="gavboulton" src="https://avatars.githubusercontent.com/u/3900826?v=4&s=117" width="117">](https://github.com/gavboulton) |[<img alt="bertho-zero" src="https://avatars.githubusercontent.com/u/8525267?v=4&s=117" width="117">](https://github.com/bertho-zero) |[<img alt="tranvansang" src="https://avatars.githubusercontent.com/u/13043196?v=4&s=117" width="117">](https://github.com/tranvansang) |[<img alt="ap--" src="https://avatars.githubusercontent.com/u/1463443?v=4&s=117" width="117">](https://github.com/ap--) |[<img alt="mrbatista" src="https://avatars.githubusercontent.com/u/6544817?v=4&s=117" width="117">](https://github.com/mrbatista) |[<img alt="MikeKovarik" src="https://avatars.githubusercontent.com/u/3995401?v=4&s=117" width="117">](https://github.com/MikeKovarik) |
+[<img alt="mejiaej" src="https://avatars.githubusercontent.com/u/4699893?v=4&s=117" width="117">](https://github.com/mejiaej) |[<img alt="gavboulton" src="https://avatars.githubusercontent.com/u/3900826?v=4&s=117" width="117">](https://github.com/gavboulton) |[<img alt="bertho-zero" src="https://avatars.githubusercontent.com/u/8525267?v=4&s=117" width="117">](https://github.com/bertho-zero) |[<img alt="tranvansang" src="https://avatars.githubusercontent.com/u/13043196?v=4&s=117" width="117">](https://github.com/tranvansang) |[<img alt="ap--" src="https://avatars.githubusercontent.com/u/1463443?v=4&s=117" width="117">](https://github.com/ap--) |[<img alt="mrbatista" src="https://avatars.githubusercontent.com/u/6544817?v=4&s=117" width="117">](https://github.com/mrbatista) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[gavboulton](https://github.com/gavboulton) |[bertho-zero](https://github.com/bertho-zero) |[tranvansang](https://github.com/tranvansang) |[ap--](https://github.com/ap--) |[mrbatista](https://github.com/mrbatista) |[MikeKovarik](https://github.com/MikeKovarik) |
+[mejiaej](https://github.com/mejiaej) |[gavboulton](https://github.com/gavboulton) |[bertho-zero](https://github.com/bertho-zero) |[tranvansang](https://github.com/tranvansang) |[ap--](https://github.com/ap--) |[mrbatista](https://github.com/mrbatista) |
 
-[<img alt="pauln" src="https://avatars.githubusercontent.com/u/574359?v=4&s=117" width="117">](https://github.com/pauln) |[<img alt="szh" src="https://avatars.githubusercontent.com/u/546965?v=4&s=117" width="117">](https://github.com/szh) |[<img alt="toadkicker" src="https://avatars.githubusercontent.com/u/523330?v=4&s=117" width="117">](https://github.com/toadkicker) |[<img alt="ofhope" src="https://avatars.githubusercontent.com/u/1826459?v=4&s=117" width="117">](https://github.com/ofhope) |[<img alt="mejiaej" src="https://avatars.githubusercontent.com/u/4699893?v=4&s=117" width="117">](https://github.com/mejiaej) |[<img alt="johnnyperkins" src="https://avatars.githubusercontent.com/u/16482282?v=4&s=117" width="117">](https://github.com/johnnyperkins) |
+[<img alt="MikeKovarik" src="https://avatars.githubusercontent.com/u/3995401?v=4&s=117" width="117">](https://github.com/MikeKovarik) |[<img alt="pauln" src="https://avatars.githubusercontent.com/u/574359?v=4&s=117" width="117">](https://github.com/pauln) |[<img alt="szh" src="https://avatars.githubusercontent.com/u/546965?v=4&s=117" width="117">](https://github.com/szh) |[<img alt="toadkicker" src="https://avatars.githubusercontent.com/u/523330?v=4&s=117" width="117">](https://github.com/toadkicker) |[<img alt="ofhope" src="https://avatars.githubusercontent.com/u/1826459?v=4&s=117" width="117">](https://github.com/ofhope) |[<img alt="johnnyperkins" src="https://avatars.githubusercontent.com/u/16482282?v=4&s=117" width="117">](https://github.com/johnnyperkins) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[pauln](https://github.com/pauln) |[szh](https://github.com/szh) |[toadkicker](https://github.com/toadkicker) |[ofhope](https://github.com/ofhope) |[mejiaej](https://github.com/mejiaej) |[johnnyperkins](https://github.com/johnnyperkins) |
+[MikeKovarik](https://github.com/MikeKovarik) |[pauln](https://github.com/pauln) |[szh](https://github.com/szh) |[toadkicker](https://github.com/toadkicker) |[ofhope](https://github.com/ofhope) |[johnnyperkins](https://github.com/johnnyperkins) |
 
 [<img alt="dargmuesli" src="https://avatars.githubusercontent.com/u/4778485?v=4&s=117" width="117">](https://github.com/dargmuesli) |[<img alt="manuelkiessling" src="https://avatars.githubusercontent.com/u/206592?v=4&s=117" width="117">](https://github.com/manuelkiessling) |[<img alt="nndevstudio" src="https://avatars.githubusercontent.com/u/22050968?v=4&s=117" width="117">](https://github.com/nndevstudio) |[<img alt="ogtfaber" src="https://avatars.githubusercontent.com/u/320955?v=4&s=117" width="117">](https://github.com/ogtfaber) |[<img alt="sksavant" src="https://avatars.githubusercontent.com/u/1040701?v=4&s=117" width="117">](https://github.com/sksavant) |[<img alt="suchoproduction" src="https://avatars.githubusercontent.com/u/6931349?v=4&s=117" width="117">](https://github.com/suchoproduction) |
 :---: |:---: |:---: |:---: |:---: |:---: |
@@ -292,145 +291,145 @@ Use Uppy in your project? [Let us know](https://github.com/transloadit/uppy/issu
 :---: |:---: |:---: |:---: |:---: |:---: |
 [DenysNosov](https://github.com/DenysNosov) |[ethanwillis](https://github.com/ethanwillis) |[frobinsonj](https://github.com/frobinsonj) |[geertclerx](https://github.com/geertclerx) |[jasonbosco](https://github.com/jasonbosco) |[jedwood](https://github.com/jedwood) |
 
-[<img alt="dogrocker" src="https://avatars.githubusercontent.com/u/8379027?v=4&s=117" width="117">](https://github.com/dogrocker) |[<img alt="lamartire" src="https://avatars.githubusercontent.com/u/13414205?v=4&s=117" width="117">](https://github.com/lamartire) |[<img alt="Mactaivsh" src="https://avatars.githubusercontent.com/u/12948083?v=4&s=117" width="117">](https://github.com/Mactaivsh) |[<img alt="maferland" src="https://avatars.githubusercontent.com/u/5889721?v=4&s=117" width="117">](https://github.com/maferland) |[<img alt="Martin005" src="https://avatars.githubusercontent.com/u/10096404?v=4&s=117" width="117">](https://github.com/Martin005) |[<img alt="martiuslim" src="https://avatars.githubusercontent.com/u/17944339?v=4&s=117" width="117">](https://github.com/martiuslim) |
+[<img alt="juliangruber" src="https://avatars.githubusercontent.com/u/10247?v=4&s=117" width="117">](https://github.com/juliangruber) |[<img alt="dogrocker" src="https://avatars.githubusercontent.com/u/8379027?v=4&s=117" width="117">](https://github.com/dogrocker) |[<img alt="lamartire" src="https://avatars.githubusercontent.com/u/13414205?v=4&s=117" width="117">](https://github.com/lamartire) |[<img alt="Mactaivsh" src="https://avatars.githubusercontent.com/u/12948083?v=4&s=117" width="117">](https://github.com/Mactaivsh) |[<img alt="maferland" src="https://avatars.githubusercontent.com/u/5889721?v=4&s=117" width="117">](https://github.com/maferland) |[<img alt="Martin005" src="https://avatars.githubusercontent.com/u/10096404?v=4&s=117" width="117">](https://github.com/Martin005) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[dogrocker](https://github.com/dogrocker) |[lamartire](https://github.com/lamartire) |[Mactaivsh](https://github.com/Mactaivsh) |[maferland](https://github.com/maferland) |[Martin005](https://github.com/Martin005) |[martiuslim](https://github.com/martiuslim) |
+[juliangruber](https://github.com/juliangruber) |[dogrocker](https://github.com/dogrocker) |[lamartire](https://github.com/lamartire) |[Mactaivsh](https://github.com/Mactaivsh) |[maferland](https://github.com/maferland) |[Martin005](https://github.com/Martin005) |
 
-[<img alt="MatthiasKunnen" src="https://avatars.githubusercontent.com/u/16807587?v=4&s=117" width="117">](https://github.com/MatthiasKunnen) |[<img alt="msand" src="https://avatars.githubusercontent.com/u/1131362?v=4&s=117" width="117">](https://github.com/msand) |[<img alt="richartkeil" src="https://avatars.githubusercontent.com/u/8680858?v=4&s=117" width="117">](https://github.com/richartkeil) |[<img alt="richmeij" src="https://avatars.githubusercontent.com/u/9741858?v=4&s=117" width="117">](https://github.com/richmeij) |[<img alt="rosenfeld" src="https://avatars.githubusercontent.com/u/32246?v=4&s=117" width="117">](https://github.com/rosenfeld) |[<img alt="jrschumacher" src="https://avatars.githubusercontent.com/u/46549?v=4&s=117" width="117">](https://github.com/jrschumacher) |
+[<img alt="martiuslim" src="https://avatars.githubusercontent.com/u/17944339?v=4&s=117" width="117">](https://github.com/martiuslim) |[<img alt="MatthiasKunnen" src="https://avatars.githubusercontent.com/u/16807587?v=4&s=117" width="117">](https://github.com/MatthiasKunnen) |[<img alt="msand" src="https://avatars.githubusercontent.com/u/1131362?v=4&s=117" width="117">](https://github.com/msand) |[<img alt="richartkeil" src="https://avatars.githubusercontent.com/u/8680858?v=4&s=117" width="117">](https://github.com/richartkeil) |[<img alt="richmeij" src="https://avatars.githubusercontent.com/u/9741858?v=4&s=117" width="117">](https://github.com/richmeij) |[<img alt="rosenfeld" src="https://avatars.githubusercontent.com/u/32246?v=4&s=117" width="117">](https://github.com/rosenfeld) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[MatthiasKunnen](https://github.com/MatthiasKunnen) |[msand](https://github.com/msand) |[richartkeil](https://github.com/richartkeil) |[richmeij](https://github.com/richmeij) |[rosenfeld](https://github.com/rosenfeld) |[jrschumacher](https://github.com/jrschumacher) |
+[martiuslim](https://github.com/martiuslim) |[MatthiasKunnen](https://github.com/MatthiasKunnen) |[msand](https://github.com/msand) |[richartkeil](https://github.com/richartkeil) |[richmeij](https://github.com/richmeij) |[rosenfeld](https://github.com/rosenfeld) |
 
-[<img alt="ThomasG77" src="https://avatars.githubusercontent.com/u/642120?v=4&s=117" width="117">](https://github.com/ThomasG77) |[<img alt="sparanoid" src="https://avatars.githubusercontent.com/u/96356?v=4&s=117" width="117">](https://github.com/sparanoid) |[<img alt="zhuangya" src="https://avatars.githubusercontent.com/u/499038?v=4&s=117" width="117">](https://github.com/zhuangya) |[<img alt="allenfantasy" src="https://avatars.githubusercontent.com/u/1009294?v=4&s=117" width="117">](https://github.com/allenfantasy) |[<img alt="Zyclotrop-j" src="https://avatars.githubusercontent.com/u/4939546?v=4&s=117" width="117">](https://github.com/Zyclotrop-j) |[<img alt="fortrieb" src="https://avatars.githubusercontent.com/u/4126707?v=4&s=117" width="117">](https://github.com/fortrieb) |
+[<img alt="jrschumacher" src="https://avatars.githubusercontent.com/u/46549?v=4&s=117" width="117">](https://github.com/jrschumacher) |[<img alt="ThomasG77" src="https://avatars.githubusercontent.com/u/642120?v=4&s=117" width="117">](https://github.com/ThomasG77) |[<img alt="sparanoid" src="https://avatars.githubusercontent.com/u/96356?v=4&s=117" width="117">](https://github.com/sparanoid) |[<img alt="zhuangya" src="https://avatars.githubusercontent.com/u/499038?v=4&s=117" width="117">](https://github.com/zhuangya) |[<img alt="allenfantasy" src="https://avatars.githubusercontent.com/u/1009294?v=4&s=117" width="117">](https://github.com/allenfantasy) |[<img alt="Zyclotrop-j" src="https://avatars.githubusercontent.com/u/4939546?v=4&s=117" width="117">](https://github.com/Zyclotrop-j) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[ThomasG77](https://github.com/ThomasG77) |[sparanoid](https://github.com/sparanoid) |[zhuangya](https://github.com/zhuangya) |[allenfantasy](https://github.com/allenfantasy) |[Zyclotrop-j](https://github.com/Zyclotrop-j) |[fortrieb](https://github.com/fortrieb) |
+[jrschumacher](https://github.com/jrschumacher) |[ThomasG77](https://github.com/ThomasG77) |[sparanoid](https://github.com/sparanoid) |[zhuangya](https://github.com/zhuangya) |[allenfantasy](https://github.com/allenfantasy) |[Zyclotrop-j](https://github.com/Zyclotrop-j) |
 
-[<img alt="jarey" src="https://avatars.githubusercontent.com/u/5025224?v=4&s=117" width="117">](https://github.com/jarey) |[<img alt="muhammadInam" src="https://avatars.githubusercontent.com/u/7801708?v=4&s=117" width="117">](https://github.com/muhammadInam) |[<img alt="rettgerst" src="https://avatars.githubusercontent.com/u/11684948?v=4&s=117" width="117">](https://github.com/rettgerst) |[<img alt="mkabatek" src="https://avatars.githubusercontent.com/u/1764486?v=4&s=117" width="117">](https://github.com/mkabatek) |[<img alt="jukakoski" src="https://avatars.githubusercontent.com/u/52720967?v=4&s=117" width="117">](https://github.com/jukakoski) |[<img alt="olemoign" src="https://avatars.githubusercontent.com/u/11632871?v=4&s=117" width="117">](https://github.com/olemoign) |
+[<img alt="fortrieb" src="https://avatars.githubusercontent.com/u/4126707?v=4&s=117" width="117">](https://github.com/fortrieb) |[<img alt="jarey" src="https://avatars.githubusercontent.com/u/5025224?v=4&s=117" width="117">](https://github.com/jarey) |[<img alt="muhammadInam" src="https://avatars.githubusercontent.com/u/7801708?v=4&s=117" width="117">](https://github.com/muhammadInam) |[<img alt="rettgerst" src="https://avatars.githubusercontent.com/u/11684948?v=4&s=117" width="117">](https://github.com/rettgerst) |[<img alt="mkabatek" src="https://avatars.githubusercontent.com/u/1764486?v=4&s=117" width="117">](https://github.com/mkabatek) |[<img alt="jukakoski" src="https://avatars.githubusercontent.com/u/52720967?v=4&s=117" width="117">](https://github.com/jukakoski) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[jarey](https://github.com/jarey) |[muhammadInam](https://github.com/muhammadInam) |[rettgerst](https://github.com/rettgerst) |[mkabatek](https://github.com/mkabatek) |[jukakoski](https://github.com/jukakoski) |[olemoign](https://github.com/olemoign) |
+[fortrieb](https://github.com/fortrieb) |[jarey](https://github.com/jarey) |[muhammadInam](https://github.com/muhammadInam) |[rettgerst](https://github.com/rettgerst) |[mkabatek](https://github.com/mkabatek) |[jukakoski](https://github.com/jukakoski) |
 
-[<img alt="ajschmidt8" src="https://avatars.githubusercontent.com/u/7400326?v=4&s=117" width="117">](https://github.com/ajschmidt8) |[<img alt="superhawk610" src="https://avatars.githubusercontent.com/u/18172185?v=4&s=117" width="117">](https://github.com/superhawk610) |[<img alt="abannach" src="https://avatars.githubusercontent.com/u/43150303?v=4&s=117" width="117">](https://github.com/abannach) |[<img alt="adamelmore" src="https://avatars.githubusercontent.com/u/2363879?v=4&s=117" width="117">](https://github.com/adamelmore) |[<img alt="ajh-sr" src="https://avatars.githubusercontent.com/u/71472057?v=4&s=117" width="117">](https://github.com/ajh-sr) |[<img alt="adamvigneault" src="https://avatars.githubusercontent.com/u/18236120?v=4&s=117" width="117">](https://github.com/adamvigneault) |
+[<img alt="olemoign" src="https://avatars.githubusercontent.com/u/11632871?v=4&s=117" width="117">](https://github.com/olemoign) |[<img alt="ajschmidt8" src="https://avatars.githubusercontent.com/u/7400326?v=4&s=117" width="117">](https://github.com/ajschmidt8) |[<img alt="superhawk610" src="https://avatars.githubusercontent.com/u/18172185?v=4&s=117" width="117">](https://github.com/superhawk610) |[<img alt="abannach" src="https://avatars.githubusercontent.com/u/43150303?v=4&s=117" width="117">](https://github.com/abannach) |[<img alt="adamelmore" src="https://avatars.githubusercontent.com/u/2363879?v=4&s=117" width="117">](https://github.com/adamelmore) |[<img alt="ajh-sr" src="https://avatars.githubusercontent.com/u/71472057?v=4&s=117" width="117">](https://github.com/ajh-sr) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[ajschmidt8](https://github.com/ajschmidt8) |[superhawk610](https://github.com/superhawk610) |[abannach](https://github.com/abannach) |[adamelmore](https://github.com/adamelmore) |[ajh-sr](https://github.com/ajh-sr) |[adamvigneault](https://github.com/adamvigneault) |
+[olemoign](https://github.com/olemoign) |[ajschmidt8](https://github.com/ajschmidt8) |[superhawk610](https://github.com/superhawk610) |[abannach](https://github.com/abannach) |[adamelmore](https://github.com/adamelmore) |[ajh-sr](https://github.com/ajh-sr) |
 
-[<img alt="adritasharma" src="https://avatars.githubusercontent.com/u/29271635?v=4&s=117" width="117">](https://github.com/adritasharma) |[<img alt="asmt3" src="https://avatars.githubusercontent.com/u/1777709?v=4&s=117" width="117">](https://github.com/asmt3) |[<img alt="alexnj" src="https://avatars.githubusercontent.com/u/683500?v=4&s=117" width="117">](https://github.com/alexnj) |[<img alt="aalepis" src="https://avatars.githubusercontent.com/u/35684834?v=4&s=117" width="117">](https://github.com/aalepis) |[<img alt="Dogfalo" src="https://avatars.githubusercontent.com/u/2775751?v=4&s=117" width="117">](https://github.com/Dogfalo) |[<img alt="tekacs" src="https://avatars.githubusercontent.com/u/63247?v=4&s=117" width="117">](https://github.com/tekacs) |
+[<img alt="adamvigneault" src="https://avatars.githubusercontent.com/u/18236120?v=4&s=117" width="117">](https://github.com/adamvigneault) |[<img alt="adritasharma" src="https://avatars.githubusercontent.com/u/29271635?v=4&s=117" width="117">](https://github.com/adritasharma) |[<img alt="asmt3" src="https://avatars.githubusercontent.com/u/1777709?v=4&s=117" width="117">](https://github.com/asmt3) |[<img alt="alexnj" src="https://avatars.githubusercontent.com/u/683500?v=4&s=117" width="117">](https://github.com/alexnj) |[<img alt="aalepis" src="https://avatars.githubusercontent.com/u/35684834?v=4&s=117" width="117">](https://github.com/aalepis) |[<img alt="Dogfalo" src="https://avatars.githubusercontent.com/u/2775751?v=4&s=117" width="117">](https://github.com/Dogfalo) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[adritasharma](https://github.com/adritasharma) |[asmt3](https://github.com/asmt3) |[alexnj](https://github.com/alexnj) |[aalepis](https://github.com/aalepis) |[Dogfalo](https://github.com/Dogfalo) |[tekacs](https://github.com/tekacs) |
+[adamvigneault](https://github.com/adamvigneault) |[adritasharma](https://github.com/adritasharma) |[asmt3](https://github.com/asmt3) |[alexnj](https://github.com/alexnj) |[aalepis](https://github.com/aalepis) |[Dogfalo](https://github.com/Dogfalo) |
 
-[<img alt="amitport" src="https://avatars.githubusercontent.com/u/1131991?v=4&s=117" width="117">](https://github.com/amitport) |[<img alt="functino" src="https://avatars.githubusercontent.com/u/415498?v=4&s=117" width="117">](https://github.com/functino) |[<img alt="radarhere" src="https://avatars.githubusercontent.com/u/3112309?v=4&s=117" width="117">](https://github.com/radarhere) |[<img alt="superandrew213" src="https://avatars.githubusercontent.com/u/13059204?v=4&s=117" width="117">](https://github.com/superandrew213) |[<img alt="andychongyz" src="https://avatars.githubusercontent.com/u/12697240?v=4&s=117" width="117">](https://github.com/andychongyz) |[<img alt="anthony0030" src="https://avatars.githubusercontent.com/u/13033263?v=4&s=117" width="117">](https://github.com/anthony0030) |
+[<img alt="tekacs" src="https://avatars.githubusercontent.com/u/63247?v=4&s=117" width="117">](https://github.com/tekacs) |[<img alt="amitport" src="https://avatars.githubusercontent.com/u/1131991?v=4&s=117" width="117">](https://github.com/amitport) |[<img alt="functino" src="https://avatars.githubusercontent.com/u/415498?v=4&s=117" width="117">](https://github.com/functino) |[<img alt="radarhere" src="https://avatars.githubusercontent.com/u/3112309?v=4&s=117" width="117">](https://github.com/radarhere) |[<img alt="superandrew213" src="https://avatars.githubusercontent.com/u/13059204?v=4&s=117" width="117">](https://github.com/superandrew213) |[<img alt="andychongyz" src="https://avatars.githubusercontent.com/u/12697240?v=4&s=117" width="117">](https://github.com/andychongyz) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[amitport](https://github.com/amitport) |[functino](https://github.com/functino) |[radarhere](https://github.com/radarhere) |[superandrew213](https://github.com/superandrew213) |[andychongyz](https://github.com/andychongyz) |[anthony0030](https://github.com/anthony0030) |
+[tekacs](https://github.com/tekacs) |[amitport](https://github.com/amitport) |[functino](https://github.com/functino) |[radarhere](https://github.com/radarhere) |[superandrew213](https://github.com/superandrew213) |[andychongyz](https://github.com/andychongyz) |
 
-[<img alt="Abourass" src="https://avatars.githubusercontent.com/u/39917231?v=4&s=117" width="117">](https://github.com/Abourass) |[<img alt="arthurdenner" src="https://avatars.githubusercontent.com/u/13774309?v=4&s=117" width="117">](https://github.com/arthurdenner) |[<img alt="apuyou" src="https://avatars.githubusercontent.com/u/520053?v=4&s=117" width="117">](https://github.com/apuyou) |[<img alt="atsawin" src="https://avatars.githubusercontent.com/u/666663?v=4&s=117" width="117">](https://github.com/atsawin) |[<img alt="ayhankesicioglu" src="https://avatars.githubusercontent.com/u/36304312?v=4&s=117" width="117">](https://github.com/ayhankesicioglu) |[<img alt="azeemba" src="https://avatars.githubusercontent.com/u/2160795?v=4&s=117" width="117">](https://github.com/azeemba) |
+[<img alt="anthony0030" src="https://avatars.githubusercontent.com/u/13033263?v=4&s=117" width="117">](https://github.com/anthony0030) |[<img alt="Abourass" src="https://avatars.githubusercontent.com/u/39917231?v=4&s=117" width="117">](https://github.com/Abourass) |[<img alt="arthurdenner" src="https://avatars.githubusercontent.com/u/13774309?v=4&s=117" width="117">](https://github.com/arthurdenner) |[<img alt="apuyou" src="https://avatars.githubusercontent.com/u/520053?v=4&s=117" width="117">](https://github.com/apuyou) |[<img alt="atsawin" src="https://avatars.githubusercontent.com/u/666663?v=4&s=117" width="117">](https://github.com/atsawin) |[<img alt="ayhankesicioglu" src="https://avatars.githubusercontent.com/u/36304312?v=4&s=117" width="117">](https://github.com/ayhankesicioglu) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[Abourass](https://github.com/Abourass) |[arthurdenner](https://github.com/arthurdenner) |[apuyou](https://github.com/apuyou) |[atsawin](https://github.com/atsawin) |[ayhankesicioglu](https://github.com/ayhankesicioglu) |[azeemba](https://github.com/azeemba) |
+[anthony0030](https://github.com/anthony0030) |[Abourass](https://github.com/Abourass) |[arthurdenner](https://github.com/arthurdenner) |[apuyou](https://github.com/apuyou) |[atsawin](https://github.com/atsawin) |[ayhankesicioglu](https://github.com/ayhankesicioglu) |
 
-[<img alt="azizk" src="https://avatars.githubusercontent.com/u/37282?v=4&s=117" width="117">](https://github.com/azizk) |[<img alt="bducharme" src="https://avatars.githubusercontent.com/u/4173569?v=4&s=117" width="117">](https://github.com/bducharme) |[<img alt="Quorafind" src="https://avatars.githubusercontent.com/u/13215013?v=4&s=117" width="117">](https://github.com/Quorafind) |[<img alt="wbaaron" src="https://avatars.githubusercontent.com/u/1048988?v=4&s=117" width="117">](https://github.com/wbaaron) |[<img alt="bedgerotto" src="https://avatars.githubusercontent.com/u/4459657?v=4&s=117" width="117">](https://github.com/bedgerotto) |[<img alt="cyu" src="https://avatars.githubusercontent.com/u/2431?v=4&s=117" width="117">](https://github.com/cyu) |
+[<img alt="azeemba" src="https://avatars.githubusercontent.com/u/2160795?v=4&s=117" width="117">](https://github.com/azeemba) |[<img alt="azizk" src="https://avatars.githubusercontent.com/u/37282?v=4&s=117" width="117">](https://github.com/azizk) |[<img alt="bducharme" src="https://avatars.githubusercontent.com/u/4173569?v=4&s=117" width="117">](https://github.com/bducharme) |[<img alt="Quorafind" src="https://avatars.githubusercontent.com/u/13215013?v=4&s=117" width="117">](https://github.com/Quorafind) |[<img alt="wbaaron" src="https://avatars.githubusercontent.com/u/1048988?v=4&s=117" width="117">](https://github.com/wbaaron) |[<img alt="bedgerotto" src="https://avatars.githubusercontent.com/u/4459657?v=4&s=117" width="117">](https://github.com/bedgerotto) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[azizk](https://github.com/azizk) |[bducharme](https://github.com/bducharme) |[Quorafind](https://github.com/Quorafind) |[wbaaron](https://github.com/wbaaron) |[bedgerotto](https://github.com/bedgerotto) |[cyu](https://github.com/cyu) |
+[azeemba](https://github.com/azeemba) |[azizk](https://github.com/azizk) |[bducharme](https://github.com/bducharme) |[Quorafind](https://github.com/Quorafind) |[wbaaron](https://github.com/wbaaron) |[bedgerotto](https://github.com/bedgerotto) |
 
-[<img alt="cartfisk" src="https://avatars.githubusercontent.com/u/8764375?v=4&s=117" width="117">](https://github.com/cartfisk) |[<img alt="cellvinchung" src="https://avatars.githubusercontent.com/u/5347394?v=4&s=117" width="117">](https://github.com/cellvinchung) |[<img alt="chao" src="https://avatars.githubusercontent.com/u/55872?v=4&s=117" width="117">](https://github.com/chao) |[<img alt="csprance" src="https://avatars.githubusercontent.com/u/7902617?v=4&s=117" width="117">](https://github.com/csprance) |[<img alt="Aarbel" src="https://avatars.githubusercontent.com/u/25119847?v=4&s=117" width="117">](https://github.com/Aarbel) |[<img alt="cbush06" src="https://avatars.githubusercontent.com/u/15720146?v=4&s=117" width="117">](https://github.com/cbush06) |
+[<img alt="cyu" src="https://avatars.githubusercontent.com/u/2431?v=4&s=117" width="117">](https://github.com/cyu) |[<img alt="cartfisk" src="https://avatars.githubusercontent.com/u/8764375?v=4&s=117" width="117">](https://github.com/cartfisk) |[<img alt="cellvinchung" src="https://avatars.githubusercontent.com/u/5347394?v=4&s=117" width="117">](https://github.com/cellvinchung) |[<img alt="chao" src="https://avatars.githubusercontent.com/u/55872?v=4&s=117" width="117">](https://github.com/chao) |[<img alt="csprance" src="https://avatars.githubusercontent.com/u/7902617?v=4&s=117" width="117">](https://github.com/csprance) |[<img alt="Aarbel" src="https://avatars.githubusercontent.com/u/25119847?v=4&s=117" width="117">](https://github.com/Aarbel) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[cartfisk](https://github.com/cartfisk) |[cellvinchung](https://github.com/cellvinchung) |[chao](https://github.com/chao) |[csprance](https://github.com/csprance) |[Aarbel](https://github.com/Aarbel) |[cbush06](https://github.com/cbush06) |
+[cyu](https://github.com/cyu) |[cartfisk](https://github.com/cartfisk) |[cellvinchung](https://github.com/cellvinchung) |[chao](https://github.com/chao) |[csprance](https://github.com/csprance) |[Aarbel](https://github.com/Aarbel) |
 
-[<img alt="czj" src="https://avatars.githubusercontent.com/u/14306?v=4&s=117" width="117">](https://github.com/czj) |[<img alt="ardeois" src="https://avatars.githubusercontent.com/u/1867939?v=4&s=117" width="117">](https://github.com/ardeois) |[<img alt="sercraig" src="https://avatars.githubusercontent.com/u/24261518?v=4&s=117" width="117">](https://github.com/sercraig) |[<img alt="Cruaier" src="https://avatars.githubusercontent.com/u/5204940?v=4&s=117" width="117">](https://github.com/Cruaier) |[<img alt="danmichaelo" src="https://avatars.githubusercontent.com/u/434495?v=4&s=117" width="117">](https://github.com/danmichaelo) |[<img alt="mrboomer" src="https://avatars.githubusercontent.com/u/5942912?v=4&s=117" width="117">](https://github.com/mrboomer) |
+[<img alt="cbush06" src="https://avatars.githubusercontent.com/u/15720146?v=4&s=117" width="117">](https://github.com/cbush06) |[<img alt="czj" src="https://avatars.githubusercontent.com/u/14306?v=4&s=117" width="117">](https://github.com/czj) |[<img alt="ardeois" src="https://avatars.githubusercontent.com/u/1867939?v=4&s=117" width="117">](https://github.com/ardeois) |[<img alt="sercraig" src="https://avatars.githubusercontent.com/u/24261518?v=4&s=117" width="117">](https://github.com/sercraig) |[<img alt="Cruaier" src="https://avatars.githubusercontent.com/u/5204940?v=4&s=117" width="117">](https://github.com/Cruaier) |[<img alt="danmichaelo" src="https://avatars.githubusercontent.com/u/434495?v=4&s=117" width="117">](https://github.com/danmichaelo) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[czj](https://github.com/czj) |[ardeois](https://github.com/ardeois) |[sercraig](https://github.com/sercraig) |[Cruaier](https://github.com/Cruaier) |[danmichaelo](https://github.com/danmichaelo) |[mrboomer](https://github.com/mrboomer) |
+[cbush06](https://github.com/cbush06) |[czj](https://github.com/czj) |[ardeois](https://github.com/ardeois) |[sercraig](https://github.com/sercraig) |[Cruaier](https://github.com/Cruaier) |[danmichaelo](https://github.com/danmichaelo) |
 
-[<img alt="akizor" src="https://avatars.githubusercontent.com/u/1052439?v=4&s=117" width="117">](https://github.com/akizor) |[<img alt="davilima6" src="https://avatars.githubusercontent.com/u/422130?v=4&s=117" width="117">](https://github.com/davilima6) |[<img alt="DennisKofflard" src="https://avatars.githubusercontent.com/u/8669129?v=4&s=117" width="117">](https://github.com/DennisKofflard) |[<img alt="jeetiss" src="https://avatars.githubusercontent.com/u/6726016?v=4&s=117" width="117">](https://github.com/jeetiss) |[<img alt="sweetro" src="https://avatars.githubusercontent.com/u/6228717?v=4&s=117" width="117">](https://github.com/sweetro) |[<img alt="efbautista" src="https://avatars.githubusercontent.com/u/35430671?v=4&s=117" width="117">](https://github.com/efbautista) |
+[<img alt="mrboomer" src="https://avatars.githubusercontent.com/u/5942912?v=4&s=117" width="117">](https://github.com/mrboomer) |[<img alt="akizor" src="https://avatars.githubusercontent.com/u/1052439?v=4&s=117" width="117">](https://github.com/akizor) |[<img alt="davilima6" src="https://avatars.githubusercontent.com/u/422130?v=4&s=117" width="117">](https://github.com/davilima6) |[<img alt="DennisKofflard" src="https://avatars.githubusercontent.com/u/8669129?v=4&s=117" width="117">](https://github.com/DennisKofflard) |[<img alt="jeetiss" src="https://avatars.githubusercontent.com/u/6726016?v=4&s=117" width="117">](https://github.com/jeetiss) |[<img alt="sweetro" src="https://avatars.githubusercontent.com/u/6228717?v=4&s=117" width="117">](https://github.com/sweetro) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[akizor](https://github.com/akizor) |[davilima6](https://github.com/davilima6) |[DennisKofflard](https://github.com/DennisKofflard) |[jeetiss](https://github.com/jeetiss) |[sweetro](https://github.com/sweetro) |[efbautista](https://github.com/efbautista) |
+[mrboomer](https://github.com/mrboomer) |[akizor](https://github.com/akizor) |[davilima6](https://github.com/davilima6) |[DennisKofflard](https://github.com/DennisKofflard) |[jeetiss](https://github.com/jeetiss) |[sweetro](https://github.com/sweetro) |
 
-[<img alt="yoldar" src="https://avatars.githubusercontent.com/u/1597578?v=4&s=117" width="117">](https://github.com/yoldar) |[<img alt="eliOcs" src="https://avatars.githubusercontent.com/u/1283954?v=4&s=117" width="117">](https://github.com/eliOcs) |[<img alt="EnricoSottile" src="https://avatars.githubusercontent.com/u/10349653?v=4&s=117" width="117">](https://github.com/EnricoSottile) |[<img alt="Gkleinereva" src="https://avatars.githubusercontent.com/u/23621633?v=4&s=117" width="117">](https://github.com/Gkleinereva) |[<img alt="fgallinari" src="https://avatars.githubusercontent.com/u/6473638?v=4&s=117" width="117">](https://github.com/fgallinari) |[<img alt="ferdiusa" src="https://avatars.githubusercontent.com/u/1997982?v=4&s=117" width="117">](https://github.com/ferdiusa) |
+[<img alt="efbautista" src="https://avatars.githubusercontent.com/u/35430671?v=4&s=117" width="117">](https://github.com/efbautista) |[<img alt="yoldar" src="https://avatars.githubusercontent.com/u/1597578?v=4&s=117" width="117">](https://github.com/yoldar) |[<img alt="eliOcs" src="https://avatars.githubusercontent.com/u/1283954?v=4&s=117" width="117">](https://github.com/eliOcs) |[<img alt="EnricoSottile" src="https://avatars.githubusercontent.com/u/10349653?v=4&s=117" width="117">](https://github.com/EnricoSottile) |[<img alt="Gkleinereva" src="https://avatars.githubusercontent.com/u/23621633?v=4&s=117" width="117">](https://github.com/Gkleinereva) |[<img alt="fgallinari" src="https://avatars.githubusercontent.com/u/6473638?v=4&s=117" width="117">](https://github.com/fgallinari) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[yoldar](https://github.com/yoldar) |[eliOcs](https://github.com/eliOcs) |[EnricoSottile](https://github.com/EnricoSottile) |[Gkleinereva](https://github.com/Gkleinereva) |[fgallinari](https://github.com/fgallinari) |[ferdiusa](https://github.com/ferdiusa) |
+[efbautista](https://github.com/efbautista) |[yoldar](https://github.com/yoldar) |[eliOcs](https://github.com/eliOcs) |[EnricoSottile](https://github.com/EnricoSottile) |[Gkleinereva](https://github.com/Gkleinereva) |[fgallinari](https://github.com/fgallinari) |
 
-[<img alt="dtrucs" src="https://avatars.githubusercontent.com/u/1926041?v=4&s=117" width="117">](https://github.com/dtrucs) |[<img alt="geoffappleford" src="https://avatars.githubusercontent.com/u/731678?v=4&s=117" width="117">](https://github.com/geoffappleford) |[<img alt="gjungb" src="https://avatars.githubusercontent.com/u/3391068?v=4&s=117" width="117">](https://github.com/gjungb) |[<img alt="roenschg" src="https://avatars.githubusercontent.com/u/9590236?v=4&s=117" width="117">](https://github.com/roenschg) |[<img alt="HughbertD" src="https://avatars.githubusercontent.com/u/1580021?v=4&s=117" width="117">](https://github.com/HughbertD) |[<img alt="HussainAlkhalifah" src="https://avatars.githubusercontent.com/u/43642162?v=4&s=117" width="117">](https://github.com/HussainAlkhalifah) |
+[<img alt="ferdiusa" src="https://avatars.githubusercontent.com/u/1997982?v=4&s=117" width="117">](https://github.com/ferdiusa) |[<img alt="dtrucs" src="https://avatars.githubusercontent.com/u/1926041?v=4&s=117" width="117">](https://github.com/dtrucs) |[<img alt="geoffappleford" src="https://avatars.githubusercontent.com/u/731678?v=4&s=117" width="117">](https://github.com/geoffappleford) |[<img alt="gjungb" src="https://avatars.githubusercontent.com/u/3391068?v=4&s=117" width="117">](https://github.com/gjungb) |[<img alt="roenschg" src="https://avatars.githubusercontent.com/u/9590236?v=4&s=117" width="117">](https://github.com/roenschg) |[<img alt="HughbertD" src="https://avatars.githubusercontent.com/u/1580021?v=4&s=117" width="117">](https://github.com/HughbertD) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[dtrucs](https://github.com/dtrucs) |[geoffappleford](https://github.com/geoffappleford) |[gjungb](https://github.com/gjungb) |[roenschg](https://github.com/roenschg) |[HughbertD](https://github.com/HughbertD) |[HussainAlkhalifah](https://github.com/HussainAlkhalifah) |
+[ferdiusa](https://github.com/ferdiusa) |[dtrucs](https://github.com/dtrucs) |[geoffappleford](https://github.com/geoffappleford) |[gjungb](https://github.com/gjungb) |[roenschg](https://github.com/roenschg) |[HughbertD](https://github.com/HughbertD) |
 
-[<img alt="huydod" src="https://avatars.githubusercontent.com/u/37580530?v=4&s=117" width="117">](https://github.com/huydod) |[<img alt="IanVS" src="https://avatars.githubusercontent.com/u/4616705?v=4&s=117" width="117">](https://github.com/IanVS) |[<img alt="ishendyweb" src="https://avatars.githubusercontent.com/u/10582418?v=4&s=117" width="117">](https://github.com/ishendyweb) |[<img alt="NaxYo" src="https://avatars.githubusercontent.com/u/1963876?v=4&s=117" width="117">](https://github.com/NaxYo) |[<img alt="ghasrfakhri" src="https://avatars.githubusercontent.com/u/4945963?v=4&s=117" width="117">](https://github.com/ghasrfakhri) |[<img alt="intenzive" src="https://avatars.githubusercontent.com/u/11055931?v=4&s=117" width="117">](https://github.com/intenzive) |
+[<img alt="HussainAlkhalifah" src="https://avatars.githubusercontent.com/u/43642162?v=4&s=117" width="117">](https://github.com/HussainAlkhalifah) |[<img alt="huydod" src="https://avatars.githubusercontent.com/u/37580530?v=4&s=117" width="117">](https://github.com/huydod) |[<img alt="IanVS" src="https://avatars.githubusercontent.com/u/4616705?v=4&s=117" width="117">](https://github.com/IanVS) |[<img alt="ishendyweb" src="https://avatars.githubusercontent.com/u/10582418?v=4&s=117" width="117">](https://github.com/ishendyweb) |[<img alt="NaxYo" src="https://avatars.githubusercontent.com/u/1963876?v=4&s=117" width="117">](https://github.com/NaxYo) |[<img alt="ghasrfakhri" src="https://avatars.githubusercontent.com/u/4945963?v=4&s=117" width="117">](https://github.com/ghasrfakhri) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[huydod](https://github.com/huydod) |[IanVS](https://github.com/IanVS) |[ishendyweb](https://github.com/ishendyweb) |[NaxYo](https://github.com/NaxYo) |[ghasrfakhri](https://github.com/ghasrfakhri) |[intenzive](https://github.com/intenzive) |
+[HussainAlkhalifah](https://github.com/HussainAlkhalifah) |[huydod](https://github.com/huydod) |[IanVS](https://github.com/IanVS) |[ishendyweb](https://github.com/ishendyweb) |[NaxYo](https://github.com/NaxYo) |[ghasrfakhri](https://github.com/ghasrfakhri) |
 
-[<img alt="GreenJimmy" src="https://avatars.githubusercontent.com/u/39386?v=4&s=117" width="117">](https://github.com/GreenJimmy) |[<img alt="mazoruss" src="https://avatars.githubusercontent.com/u/17625190?v=4&s=117" width="117">](https://github.com/mazoruss) |[<img alt="JacobMGEvans" src="https://avatars.githubusercontent.com/u/27247160?v=4&s=117" width="117">](https://github.com/JacobMGEvans) |[<img alt="jdssem" src="https://avatars.githubusercontent.com/u/978944?v=4&s=117" width="117">](https://github.com/jdssem) |[<img alt="Jbithell" src="https://avatars.githubusercontent.com/u/8408967?v=4&s=117" width="117">](https://github.com/Jbithell) |[<img alt="jcjmcclean" src="https://avatars.githubusercontent.com/u/1822574?v=4&s=117" width="117">](https://github.com/jcjmcclean) |
+[<img alt="intenzive" src="https://avatars.githubusercontent.com/u/11055931?v=4&s=117" width="117">](https://github.com/intenzive) |[<img alt="Hawxy" src="https://avatars.githubusercontent.com/u/975824?v=4&s=117" width="117">](https://github.com/Hawxy) |[<img alt="GreenJimmy" src="https://avatars.githubusercontent.com/u/39386?v=4&s=117" width="117">](https://github.com/GreenJimmy) |[<img alt="mazoruss" src="https://avatars.githubusercontent.com/u/17625190?v=4&s=117" width="117">](https://github.com/mazoruss) |[<img alt="JacobMGEvans" src="https://avatars.githubusercontent.com/u/27247160?v=4&s=117" width="117">](https://github.com/JacobMGEvans) |[<img alt="jdssem" src="https://avatars.githubusercontent.com/u/978944?v=4&s=117" width="117">](https://github.com/jdssem) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[GreenJimmy](https://github.com/GreenJimmy) |[mazoruss](https://github.com/mazoruss) |[JacobMGEvans](https://github.com/JacobMGEvans) |[jdssem](https://github.com/jdssem) |[Jbithell](https://github.com/Jbithell) |[jcjmcclean](https://github.com/jcjmcclean) |
+[intenzive](https://github.com/intenzive) |[Hawxy](https://github.com/Hawxy) |[GreenJimmy](https://github.com/GreenJimmy) |[mazoruss](https://github.com/mazoruss) |[JacobMGEvans](https://github.com/JacobMGEvans) |[jdssem](https://github.com/jdssem) |
 
-[<img alt="janklimo" src="https://avatars.githubusercontent.com/u/7811733?v=4&s=117" width="117">](https://github.com/janklimo) |[<img alt="janwilts" src="https://avatars.githubusercontent.com/u/16721581?v=4&s=117" width="117">](https://github.com/janwilts) |[<img alt="vith" src="https://avatars.githubusercontent.com/u/3265539?v=4&s=117" width="117">](https://github.com/vith) |[<img alt="jessica-coursera" src="https://avatars.githubusercontent.com/u/35155465?v=4&s=117" width="117">](https://github.com/jessica-coursera) |[<img alt="jhen0409" src="https://avatars.githubusercontent.com/u/3001525?v=4&s=117" width="117">](https://github.com/jhen0409) |[<img alt="Jmales" src="https://avatars.githubusercontent.com/u/22914881?v=4&s=117" width="117">](https://github.com/Jmales) |
+[<img alt="Jbithell" src="https://avatars.githubusercontent.com/u/8408967?v=4&s=117" width="117">](https://github.com/Jbithell) |[<img alt="jcjmcclean" src="https://avatars.githubusercontent.com/u/1822574?v=4&s=117" width="117">](https://github.com/jcjmcclean) |[<img alt="janklimo" src="https://avatars.githubusercontent.com/u/7811733?v=4&s=117" width="117">](https://github.com/janklimo) |[<img alt="janwilts" src="https://avatars.githubusercontent.com/u/16721581?v=4&s=117" width="117">](https://github.com/janwilts) |[<img alt="vith" src="https://avatars.githubusercontent.com/u/3265539?v=4&s=117" width="117">](https://github.com/vith) |[<img alt="jessica-coursera" src="https://avatars.githubusercontent.com/u/35155465?v=4&s=117" width="117">](https://github.com/jessica-coursera) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[janklimo](https://github.com/janklimo) |[janwilts](https://github.com/janwilts) |[vith](https://github.com/vith) |[jessica-coursera](https://github.com/jessica-coursera) |[jhen0409](https://github.com/jhen0409) |[Jmales](https://github.com/Jmales) |
+[Jbithell](https://github.com/Jbithell) |[jcjmcclean](https://github.com/jcjmcclean) |[janklimo](https://github.com/janklimo) |[janwilts](https://github.com/janwilts) |[vith](https://github.com/vith) |[jessica-coursera](https://github.com/jessica-coursera) |
 
-[<img alt="theJoeBiz" src="https://avatars.githubusercontent.com/u/189589?v=4&s=117" width="117">](https://github.com/theJoeBiz) |[<img alt="profsmallpine" src="https://avatars.githubusercontent.com/u/7328006?v=4&s=117" width="117">](https://github.com/profsmallpine) |[<img alt="jonathanarbely" src="https://avatars.githubusercontent.com/u/18177203?v=4&s=117" width="117">](https://github.com/jonathanarbely) |[<img alt="jderrough" src="https://avatars.githubusercontent.com/u/1108358?v=4&s=117" width="117">](https://github.com/jderrough) |[<img alt="jonathanly" src="https://avatars.githubusercontent.com/u/13286473?v=4&s=117" width="117">](https://github.com/jonathanly) |[<img alt="jorgeepc" src="https://avatars.githubusercontent.com/u/3879892?v=4&s=117" width="117">](https://github.com/jorgeepc) |
+[<img alt="jhen0409" src="https://avatars.githubusercontent.com/u/3001525?v=4&s=117" width="117">](https://github.com/jhen0409) |[<img alt="Jmales" src="https://avatars.githubusercontent.com/u/22914881?v=4&s=117" width="117">](https://github.com/Jmales) |[<img alt="theJoeBiz" src="https://avatars.githubusercontent.com/u/189589?v=4&s=117" width="117">](https://github.com/theJoeBiz) |[<img alt="profsmallpine" src="https://avatars.githubusercontent.com/u/7328006?v=4&s=117" width="117">](https://github.com/profsmallpine) |[<img alt="jonathanarbely" src="https://avatars.githubusercontent.com/u/18177203?v=4&s=117" width="117">](https://github.com/jonathanarbely) |[<img alt="jderrough" src="https://avatars.githubusercontent.com/u/1108358?v=4&s=117" width="117">](https://github.com/jderrough) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[theJoeBiz](https://github.com/theJoeBiz) |[profsmallpine](https://github.com/profsmallpine) |[jonathanarbely](https://github.com/jonathanarbely) |[jderrough](https://github.com/jderrough) |[jonathanly](https://github.com/jonathanly) |[jorgeepc](https://github.com/jorgeepc) |
+[jhen0409](https://github.com/jhen0409) |[Jmales](https://github.com/Jmales) |[theJoeBiz](https://github.com/theJoeBiz) |[profsmallpine](https://github.com/profsmallpine) |[jonathanarbely](https://github.com/jonathanarbely) |[jderrough](https://github.com/jderrough) |
 
-[<img alt="jszobody" src="https://avatars.githubusercontent.com/u/203749?v=4&s=117" width="117">](https://github.com/jszobody) |[<img alt="julianocomg" src="https://avatars.githubusercontent.com/u/7483557?v=4&s=117" width="117">](https://github.com/julianocomg) |[<img alt="jmontoyaa" src="https://avatars.githubusercontent.com/u/158935?v=4&s=117" width="117">](https://github.com/jmontoyaa) |[<img alt="firesharkstudios" src="https://avatars.githubusercontent.com/u/17069637?v=4&s=117" width="117">](https://github.com/firesharkstudios) |[<img alt="elkebab" src="https://avatars.githubusercontent.com/u/6313468?v=4&s=117" width="117">](https://github.com/elkebab) |[<img alt="kyleparisi" src="https://avatars.githubusercontent.com/u/1286753?v=4&s=117" width="117">](https://github.com/kyleparisi) |
+[<img alt="jonathanly" src="https://avatars.githubusercontent.com/u/13286473?v=4&s=117" width="117">](https://github.com/jonathanly) |[<img alt="jorgeepc" src="https://avatars.githubusercontent.com/u/3879892?v=4&s=117" width="117">](https://github.com/jorgeepc) |[<img alt="jszobody" src="https://avatars.githubusercontent.com/u/203749?v=4&s=117" width="117">](https://github.com/jszobody) |[<img alt="julianocomg" src="https://avatars.githubusercontent.com/u/7483557?v=4&s=117" width="117">](https://github.com/julianocomg) |[<img alt="jmontoyaa" src="https://avatars.githubusercontent.com/u/158935?v=4&s=117" width="117">](https://github.com/jmontoyaa) |[<img alt="firesharkstudios" src="https://avatars.githubusercontent.com/u/17069637?v=4&s=117" width="117">](https://github.com/firesharkstudios) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[jszobody](https://github.com/jszobody) |[julianocomg](https://github.com/julianocomg) |[jmontoyaa](https://github.com/jmontoyaa) |[firesharkstudios](https://github.com/firesharkstudios) |[elkebab](https://github.com/elkebab) |[kyleparisi](https://github.com/kyleparisi) |
+[jonathanly](https://github.com/jonathanly) |[jorgeepc](https://github.com/jorgeepc) |[jszobody](https://github.com/jszobody) |[julianocomg](https://github.com/julianocomg) |[jmontoyaa](https://github.com/jmontoyaa) |[firesharkstudios](https://github.com/firesharkstudios) |
 
-[<img alt="lafe" src="https://avatars.githubusercontent.com/u/4070008?v=4&s=117" width="117">](https://github.com/lafe) |[<img alt="leaanthony" src="https://avatars.githubusercontent.com/u/1943904?v=4&s=117" width="117">](https://github.com/leaanthony) |[<img alt="larowlan" src="https://avatars.githubusercontent.com/u/555254?v=4&s=117" width="117">](https://github.com/larowlan) |[<img alt="dviry" src="https://avatars.githubusercontent.com/u/1230260?v=4&s=117" width="117">](https://github.com/dviry) |[<img alt="galli-leo" src="https://avatars.githubusercontent.com/u/5339762?v=4&s=117" width="117">](https://github.com/galli-leo) |[<img alt="leods92" src="https://avatars.githubusercontent.com/u/879395?v=4&s=117" width="117">](https://github.com/leods92) |
+[<img alt="elkebab" src="https://avatars.githubusercontent.com/u/6313468?v=4&s=117" width="117">](https://github.com/elkebab) |[<img alt="kyleparisi" src="https://avatars.githubusercontent.com/u/1286753?v=4&s=117" width="117">](https://github.com/kyleparisi) |[<img alt="lafe" src="https://avatars.githubusercontent.com/u/4070008?v=4&s=117" width="117">](https://github.com/lafe) |[<img alt="leaanthony" src="https://avatars.githubusercontent.com/u/1943904?v=4&s=117" width="117">](https://github.com/leaanthony) |[<img alt="larowlan" src="https://avatars.githubusercontent.com/u/555254?v=4&s=117" width="117">](https://github.com/larowlan) |[<img alt="dviry" src="https://avatars.githubusercontent.com/u/1230260?v=4&s=117" width="117">](https://github.com/dviry) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[lafe](https://github.com/lafe) |[leaanthony](https://github.com/leaanthony) |[larowlan](https://github.com/larowlan) |[dviry](https://github.com/dviry) |[galli-leo](https://github.com/galli-leo) |[leods92](https://github.com/leods92) |
+[elkebab](https://github.com/elkebab) |[kyleparisi](https://github.com/kyleparisi) |[lafe](https://github.com/lafe) |[leaanthony](https://github.com/leaanthony) |[larowlan](https://github.com/larowlan) |[dviry](https://github.com/dviry) |
 
-[<img alt="louim" src="https://avatars.githubusercontent.com/u/923718?v=4&s=117" width="117">](https://github.com/louim) |[<img alt="lucaperret" src="https://avatars.githubusercontent.com/u/1887122?v=4&s=117" width="117">](https://github.com/lucaperret) |[<img alt="mperrando" src="https://avatars.githubusercontent.com/u/525572?v=4&s=117" width="117">](https://github.com/mperrando) |[<img alt="marcosthejew" src="https://avatars.githubusercontent.com/u/1500967?v=4&s=117" width="117">](https://github.com/marcosthejew) |[<img alt="marcusforsberg" src="https://avatars.githubusercontent.com/u/1009069?v=4&s=117" width="117">](https://github.com/marcusforsberg) |[<img alt="Acconut" src="https://avatars.githubusercontent.com/u/1375043?v=4&s=117" width="117">](https://github.com/Acconut) |
+[<img alt="galli-leo" src="https://avatars.githubusercontent.com/u/5339762?v=4&s=117" width="117">](https://github.com/galli-leo) |[<img alt="leods92" src="https://avatars.githubusercontent.com/u/879395?v=4&s=117" width="117">](https://github.com/leods92) |[<img alt="louim" src="https://avatars.githubusercontent.com/u/923718?v=4&s=117" width="117">](https://github.com/louim) |[<img alt="lucaperret" src="https://avatars.githubusercontent.com/u/1887122?v=4&s=117" width="117">](https://github.com/lucaperret) |[<img alt="mperrando" src="https://avatars.githubusercontent.com/u/525572?v=4&s=117" width="117">](https://github.com/mperrando) |[<img alt="marcosthejew" src="https://avatars.githubusercontent.com/u/1500967?v=4&s=117" width="117">](https://github.com/marcosthejew) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[louim](https://github.com/louim) |[lucaperret](https://github.com/lucaperret) |[mperrando](https://github.com/mperrando) |[marcosthejew](https://github.com/marcosthejew) |[marcusforsberg](https://github.com/marcusforsberg) |[Acconut](https://github.com/Acconut) |
+[galli-leo](https://github.com/galli-leo) |[leods92](https://github.com/leods92) |[louim](https://github.com/louim) |[lucaperret](https://github.com/lucaperret) |[mperrando](https://github.com/mperrando) |[marcosthejew](https://github.com/marcosthejew) |
 
-[<img alt="masaok" src="https://avatars.githubusercontent.com/u/1320083?v=4&s=117" width="117">](https://github.com/masaok) |[<img alt="mattfik" src="https://avatars.githubusercontent.com/u/1638028?v=4&s=117" width="117">](https://github.com/mattfik) |[<img alt="matthewhartstonge" src="https://avatars.githubusercontent.com/u/6119549?v=4&s=117" width="117">](https://github.com/matthewhartstonge) |[<img alt="hrsh" src="https://avatars.githubusercontent.com/u/1929359?v=4&s=117" width="117">](https://github.com/hrsh) |[<img alt="mhulet" src="https://avatars.githubusercontent.com/u/293355?v=4&s=117" width="117">](https://github.com/mhulet) |[<img alt="mkopinsky" src="https://avatars.githubusercontent.com/u/591435?v=4&s=117" width="117">](https://github.com/mkopinsky) |
+[<img alt="marcusforsberg" src="https://avatars.githubusercontent.com/u/1009069?v=4&s=117" width="117">](https://github.com/marcusforsberg) |[<img alt="Acconut" src="https://avatars.githubusercontent.com/u/1375043?v=4&s=117" width="117">](https://github.com/Acconut) |[<img alt="masaok" src="https://avatars.githubusercontent.com/u/1320083?v=4&s=117" width="117">](https://github.com/masaok) |[<img alt="mattfik" src="https://avatars.githubusercontent.com/u/1638028?v=4&s=117" width="117">](https://github.com/mattfik) |[<img alt="matthewhartstonge" src="https://avatars.githubusercontent.com/u/6119549?v=4&s=117" width="117">](https://github.com/matthewhartstonge) |[<img alt="hrsh" src="https://avatars.githubusercontent.com/u/1929359?v=4&s=117" width="117">](https://github.com/hrsh) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[masaok](https://github.com/masaok) |[mattfik](https://github.com/mattfik) |[matthewhartstonge](https://github.com/matthewhartstonge) |[hrsh](https://github.com/hrsh) |[mhulet](https://github.com/mhulet) |[mkopinsky](https://github.com/mkopinsky) |
+[marcusforsberg](https://github.com/marcusforsberg) |[Acconut](https://github.com/Acconut) |[masaok](https://github.com/masaok) |[mattfik](https://github.com/mattfik) |[matthewhartstonge](https://github.com/matthewhartstonge) |[hrsh](https://github.com/hrsh) |
 
-[<img alt="achmiral" src="https://avatars.githubusercontent.com/u/10906059?v=4&s=117" width="117">](https://github.com/achmiral) |[<img alt="mnafees" src="https://avatars.githubusercontent.com/u/1763885?v=4&s=117" width="117">](https://github.com/mnafees) |[<img alt="shahimclt" src="https://avatars.githubusercontent.com/u/8318002?v=4&s=117" width="117">](https://github.com/shahimclt) |[<img alt="pleasespammelater" src="https://avatars.githubusercontent.com/u/11870394?v=4&s=117" width="117">](https://github.com/pleasespammelater) |[<img alt="naveed-ahmad" src="https://avatars.githubusercontent.com/u/701567?v=4&s=117" width="117">](https://github.com/naveed-ahmad) |[<img alt="nicojones" src="https://avatars.githubusercontent.com/u/6078915?v=4&s=117" width="117">](https://github.com/nicojones) |
+[<img alt="mhulet" src="https://avatars.githubusercontent.com/u/293355?v=4&s=117" width="117">](https://github.com/mhulet) |[<img alt="mkopinsky" src="https://avatars.githubusercontent.com/u/591435?v=4&s=117" width="117">](https://github.com/mkopinsky) |[<img alt="achmiral" src="https://avatars.githubusercontent.com/u/10906059?v=4&s=117" width="117">](https://github.com/achmiral) |[<img alt="mnafees" src="https://avatars.githubusercontent.com/u/1763885?v=4&s=117" width="117">](https://github.com/mnafees) |[<img alt="shahimclt" src="https://avatars.githubusercontent.com/u/8318002?v=4&s=117" width="117">](https://github.com/shahimclt) |[<img alt="pleasespammelater" src="https://avatars.githubusercontent.com/u/11870394?v=4&s=117" width="117">](https://github.com/pleasespammelater) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[achmiral](https://github.com/achmiral) |[mnafees](https://github.com/mnafees) |[shahimclt](https://github.com/shahimclt) |[pleasespammelater](https://github.com/pleasespammelater) |[naveed-ahmad](https://github.com/naveed-ahmad) |[nicojones](https://github.com/nicojones) |
+[mhulet](https://github.com/mhulet) |[mkopinsky](https://github.com/mkopinsky) |[achmiral](https://github.com/achmiral) |[mnafees](https://github.com/mnafees) |[shahimclt](https://github.com/shahimclt) |[pleasespammelater](https://github.com/pleasespammelater) |
 
-[<img alt="coreprocess" src="https://avatars.githubusercontent.com/u/1226918?v=4&s=117" width="117">](https://github.com/coreprocess) |[<img alt="nil1511" src="https://avatars.githubusercontent.com/u/2058170?v=4&s=117" width="117">](https://github.com/nil1511) |[<img alt="leftdevel" src="https://avatars.githubusercontent.com/u/843337?v=4&s=117" width="117">](https://github.com/leftdevel) |[<img alt="cryptic022" src="https://avatars.githubusercontent.com/u/18145703?v=4&s=117" width="117">](https://github.com/cryptic022) |[<img alt="patricklindsay" src="https://avatars.githubusercontent.com/u/7923681?v=4&s=117" width="117">](https://github.com/patricklindsay) |[<img alt="pedrofs" src="https://avatars.githubusercontent.com/u/56484?v=4&s=117" width="117">](https://github.com/pedrofs) |
+[<img alt="naveed-ahmad" src="https://avatars.githubusercontent.com/u/701567?v=4&s=117" width="117">](https://github.com/naveed-ahmad) |[<img alt="nicojones" src="https://avatars.githubusercontent.com/u/6078915?v=4&s=117" width="117">](https://github.com/nicojones) |[<img alt="coreprocess" src="https://avatars.githubusercontent.com/u/1226918?v=4&s=117" width="117">](https://github.com/coreprocess) |[<img alt="nil1511" src="https://avatars.githubusercontent.com/u/2058170?v=4&s=117" width="117">](https://github.com/nil1511) |[<img alt="leftdevel" src="https://avatars.githubusercontent.com/u/843337?v=4&s=117" width="117">](https://github.com/leftdevel) |[<img alt="cryptic022" src="https://avatars.githubusercontent.com/u/18145703?v=4&s=117" width="117">](https://github.com/cryptic022) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[coreprocess](https://github.com/coreprocess) |[nil1511](https://github.com/nil1511) |[leftdevel](https://github.com/leftdevel) |[cryptic022](https://github.com/cryptic022) |[patricklindsay](https://github.com/patricklindsay) |[pedrofs](https://github.com/pedrofs) |
+[naveed-ahmad](https://github.com/naveed-ahmad) |[nicojones](https://github.com/nicojones) |[coreprocess](https://github.com/coreprocess) |[nil1511](https://github.com/nil1511) |[leftdevel](https://github.com/leftdevel) |[cryptic022](https://github.com/cryptic022) |
 
-[<img alt="phillipalexander" src="https://avatars.githubusercontent.com/u/1577682?v=4&s=117" width="117">](https://github.com/phillipalexander) |[<img alt="ppadmavilasom" src="https://avatars.githubusercontent.com/u/11167452?v=4&s=117" width="117">](https://github.com/ppadmavilasom) |[<img alt="Pzoco" src="https://avatars.githubusercontent.com/u/3101348?v=4&s=117" width="117">](https://github.com/Pzoco) |[<img alt="eman8519" src="https://avatars.githubusercontent.com/u/2380804?v=4&s=117" width="117">](https://github.com/eman8519) |[<img alt="luarmr" src="https://avatars.githubusercontent.com/u/817416?v=4&s=117" width="117">](https://github.com/luarmr) |[<img alt="SxDx" src="https://avatars.githubusercontent.com/u/2004247?v=4&s=117" width="117">](https://github.com/SxDx) |
+[<img alt="paescuj" src="https://avatars.githubusercontent.com/u/5363448?v=4&s=117" width="117">](https://github.com/paescuj) |[<img alt="patricklindsay" src="https://avatars.githubusercontent.com/u/7923681?v=4&s=117" width="117">](https://github.com/patricklindsay) |[<img alt="pedrofs" src="https://avatars.githubusercontent.com/u/56484?v=4&s=117" width="117">](https://github.com/pedrofs) |[<img alt="phillipalexander" src="https://avatars.githubusercontent.com/u/1577682?v=4&s=117" width="117">](https://github.com/phillipalexander) |[<img alt="ppadmavilasom" src="https://avatars.githubusercontent.com/u/11167452?v=4&s=117" width="117">](https://github.com/ppadmavilasom) |[<img alt="Pzoco" src="https://avatars.githubusercontent.com/u/3101348?v=4&s=117" width="117">](https://github.com/Pzoco) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[phillipalexander](https://github.com/phillipalexander) |[ppadmavilasom](https://github.com/ppadmavilasom) |[Pzoco](https://github.com/Pzoco) |[eman8519](https://github.com/eman8519) |[luarmr](https://github.com/luarmr) |[SxDx](https://github.com/SxDx) |
+[paescuj](https://github.com/paescuj) |[patricklindsay](https://github.com/patricklindsay) |[pedrofs](https://github.com/pedrofs) |[phillipalexander](https://github.com/phillipalexander) |[ppadmavilasom](https://github.com/ppadmavilasom) |[Pzoco](https://github.com/Pzoco) |
 
-[<img alt="phobos101" src="https://avatars.githubusercontent.com/u/7114944?v=4&s=117" width="117">](https://github.com/phobos101) |[<img alt="romain-preston" src="https://avatars.githubusercontent.com/u/1517040?v=4&s=117" width="117">](https://github.com/romain-preston) |[<img alt="scherroman" src="https://avatars.githubusercontent.com/u/7923938?v=4&s=117" width="117">](https://github.com/scherroman) |[<img alt="rart" src="https://avatars.githubusercontent.com/u/3928341?v=4&s=117" width="117">](https://github.com/rart) |[<img alt="fortunto2" src="https://avatars.githubusercontent.com/u/1236751?v=4&s=117" width="117">](https://github.com/fortunto2) |[<img alt="samuelcolburn" src="https://avatars.githubusercontent.com/u/9741902?v=4&s=117" width="117">](https://github.com/samuelcolburn) |
+[<img alt="eman8519" src="https://avatars.githubusercontent.com/u/2380804?v=4&s=117" width="117">](https://github.com/eman8519) |[<img alt="luarmr" src="https://avatars.githubusercontent.com/u/817416?v=4&s=117" width="117">](https://github.com/luarmr) |[<img alt="SxDx" src="https://avatars.githubusercontent.com/u/2004247?v=4&s=117" width="117">](https://github.com/SxDx) |[<img alt="phobos101" src="https://avatars.githubusercontent.com/u/7114944?v=4&s=117" width="117">](https://github.com/phobos101) |[<img alt="romain-preston" src="https://avatars.githubusercontent.com/u/1517040?v=4&s=117" width="117">](https://github.com/romain-preston) |[<img alt="scherroman" src="https://avatars.githubusercontent.com/u/7923938?v=4&s=117" width="117">](https://github.com/scherroman) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[phobos101](https://github.com/phobos101) |[romain-preston](https://github.com/romain-preston) |[scherroman](https://github.com/scherroman) |[rart](https://github.com/rart) |[fortunto2](https://github.com/fortunto2) |[samuelcolburn](https://github.com/samuelcolburn) |
+[eman8519](https://github.com/eman8519) |[luarmr](https://github.com/luarmr) |[SxDx](https://github.com/SxDx) |[phobos101](https://github.com/phobos101) |[romain-preston](https://github.com/romain-preston) |[scherroman](https://github.com/scherroman) |
 
-[<img alt="sergei-zelinsky" src="https://avatars.githubusercontent.com/u/19428086?v=4&s=117" width="117">](https://github.com/sergei-zelinsky) |[<img alt="SpazzMarticus" src="https://avatars.githubusercontent.com/u/5716457?v=4&s=117" width="117">](https://github.com/SpazzMarticus) |[<img alt="waptik" src="https://avatars.githubusercontent.com/u/1687551?v=4&s=117" width="117">](https://github.com/waptik) |[<img alt="steverob" src="https://avatars.githubusercontent.com/u/1220480?v=4&s=117" width="117">](https://github.com/steverob) |[<img alt="taj" src="https://avatars.githubusercontent.com/u/16062635?v=4&s=117" width="117">](https://github.com/taj) |[<img alt="Tashows" src="https://avatars.githubusercontent.com/u/16656928?v=4&s=117" width="117">](https://github.com/Tashows) |
+[<img alt="rart" src="https://avatars.githubusercontent.com/u/3928341?v=4&s=117" width="117">](https://github.com/rart) |[<img alt="fortunto2" src="https://avatars.githubusercontent.com/u/1236751?v=4&s=117" width="117">](https://github.com/fortunto2) |[<img alt="samuelcolburn" src="https://avatars.githubusercontent.com/u/9741902?v=4&s=117" width="117">](https://github.com/samuelcolburn) |[<img alt="sergei-zelinsky" src="https://avatars.githubusercontent.com/u/19428086?v=4&s=117" width="117">](https://github.com/sergei-zelinsky) |[<img alt="SpazzMarticus" src="https://avatars.githubusercontent.com/u/5716457?v=4&s=117" width="117">](https://github.com/SpazzMarticus) |[<img alt="waptik" src="https://avatars.githubusercontent.com/u/1687551?v=4&s=117" width="117">](https://github.com/waptik) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[sergei-zelinsky](https://github.com/sergei-zelinsky) |[SpazzMarticus](https://github.com/SpazzMarticus) |[waptik](https://github.com/waptik) |[steverob](https://github.com/steverob) |[taj](https://github.com/taj) |[Tashows](https://github.com/Tashows) |
+[rart](https://github.com/rart) |[fortunto2](https://github.com/fortunto2) |[samuelcolburn](https://github.com/samuelcolburn) |[sergei-zelinsky](https://github.com/sergei-zelinsky) |[SpazzMarticus](https://github.com/SpazzMarticus) |[waptik](https://github.com/waptik) |
 
-[<img alt="twarlop" src="https://avatars.githubusercontent.com/u/2856082?v=4&s=117" width="117">](https://github.com/twarlop) |[<img alt="tmaier" src="https://avatars.githubusercontent.com/u/350038?v=4&s=117" width="117">](https://github.com/tmaier) |[<img alt="tomsaleeba" src="https://avatars.githubusercontent.com/u/1773838?v=4&s=117" width="117">](https://github.com/tomsaleeba) |[<img alt="tvaliasek" src="https://avatars.githubusercontent.com/u/8644946?v=4&s=117" width="117">](https://github.com/tvaliasek) |[<img alt="vially" src="https://avatars.githubusercontent.com/u/433598?v=4&s=117" width="117">](https://github.com/vially) |[<img alt="nagyv" src="https://avatars.githubusercontent.com/u/126671?v=4&s=117" width="117">](https://github.com/nagyv) |
+[<img alt="steverob" src="https://avatars.githubusercontent.com/u/1220480?v=4&s=117" width="117">](https://github.com/steverob) |[<img alt="taj" src="https://avatars.githubusercontent.com/u/16062635?v=4&s=117" width="117">](https://github.com/taj) |[<img alt="Tashows" src="https://avatars.githubusercontent.com/u/16656928?v=4&s=117" width="117">](https://github.com/Tashows) |[<img alt="twarlop" src="https://avatars.githubusercontent.com/u/2856082?v=4&s=117" width="117">](https://github.com/twarlop) |[<img alt="tmaier" src="https://avatars.githubusercontent.com/u/350038?v=4&s=117" width="117">](https://github.com/tmaier) |[<img alt="tomsaleeba" src="https://avatars.githubusercontent.com/u/1773838?v=4&s=117" width="117">](https://github.com/tomsaleeba) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[twarlop](https://github.com/twarlop) |[tmaier](https://github.com/tmaier) |[tomsaleeba](https://github.com/tomsaleeba) |[tvaliasek](https://github.com/tvaliasek) |[vially](https://github.com/vially) |[nagyv](https://github.com/nagyv) |
+[steverob](https://github.com/steverob) |[taj](https://github.com/taj) |[Tashows](https://github.com/Tashows) |[twarlop](https://github.com/twarlop) |[tmaier](https://github.com/tmaier) |[tomsaleeba](https://github.com/tomsaleeba) |
 
-[<img alt="willycamargo" src="https://avatars.githubusercontent.com/u/5041887?v=4&s=117" width="117">](https://github.com/willycamargo) |[<img alt="xhocquet" src="https://avatars.githubusercontent.com/u/8116516?v=4&s=117" width="117">](https://github.com/xhocquet) |[<img alt="yaegor" src="https://avatars.githubusercontent.com/u/3315?v=4&s=117" width="117">](https://github.com/yaegor) |[<img alt="YehudaKremer" src="https://avatars.githubusercontent.com/u/946652?v=4&s=117" width="117">](https://github.com/YehudaKremer) |[<img alt="zachconner" src="https://avatars.githubusercontent.com/u/11339326?v=4&s=117" width="117">](https://github.com/zachconner) |[<img alt="zacharylawson" src="https://avatars.githubusercontent.com/u/7375444?v=4&s=117" width="117">](https://github.com/zacharylawson) |
+[<img alt="tvaliasek" src="https://avatars.githubusercontent.com/u/8644946?v=4&s=117" width="117">](https://github.com/tvaliasek) |[<img alt="vially" src="https://avatars.githubusercontent.com/u/433598?v=4&s=117" width="117">](https://github.com/vially) |[<img alt="nagyv" src="https://avatars.githubusercontent.com/u/126671?v=4&s=117" width="117">](https://github.com/nagyv) |[<img alt="dwnste" src="https://avatars.githubusercontent.com/u/17119722?v=4&s=117" width="117">](https://github.com/dwnste) |[<img alt="willycamargo" src="https://avatars.githubusercontent.com/u/5041887?v=4&s=117" width="117">](https://github.com/willycamargo) |[<img alt="xhocquet" src="https://avatars.githubusercontent.com/u/8116516?v=4&s=117" width="117">](https://github.com/xhocquet) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[willycamargo](https://github.com/willycamargo) |[xhocquet](https://github.com/xhocquet) |[yaegor](https://github.com/yaegor) |[YehudaKremer](https://github.com/YehudaKremer) |[zachconner](https://github.com/zachconner) |[zacharylawson](https://github.com/zacharylawson) |
+[tvaliasek](https://github.com/tvaliasek) |[vially](https://github.com/vially) |[nagyv](https://github.com/nagyv) |[dwnste](https://github.com/dwnste) |[willycamargo](https://github.com/willycamargo) |[xhocquet](https://github.com/xhocquet) |
 
-[<img alt="agreene-coursera" src="https://avatars.githubusercontent.com/u/30501355?v=4&s=117" width="117">](https://github.com/agreene-coursera) |[<img alt="alfatv" src="https://avatars.githubusercontent.com/u/62238673?v=4&s=117" width="117">](https://github.com/alfatv) |[<img alt="anark" src="https://avatars.githubusercontent.com/u/101184?v=4&s=117" width="117">](https://github.com/anark) |[<img alt="arggh" src="https://avatars.githubusercontent.com/u/17210302?v=4&s=117" width="117">](https://github.com/arggh) |[<img alt="avalla" src="https://avatars.githubusercontent.com/u/986614?v=4&s=117" width="117">](https://github.com/avalla) |[<img alt="bdirito" src="https://avatars.githubusercontent.com/u/8117238?v=4&s=117" width="117">](https://github.com/bdirito) |
+[<img alt="yaegor" src="https://avatars.githubusercontent.com/u/3315?v=4&s=117" width="117">](https://github.com/yaegor) |[<img alt="YehudaKremer" src="https://avatars.githubusercontent.com/u/946652?v=4&s=117" width="117">](https://github.com/YehudaKremer) |[<img alt="zachconner" src="https://avatars.githubusercontent.com/u/11339326?v=4&s=117" width="117">](https://github.com/zachconner) |[<img alt="zacharylawson" src="https://avatars.githubusercontent.com/u/7375444?v=4&s=117" width="117">](https://github.com/zacharylawson) |[<img alt="agreene-coursera" src="https://avatars.githubusercontent.com/u/30501355?v=4&s=117" width="117">](https://github.com/agreene-coursera) |[<img alt="alfatv" src="https://avatars.githubusercontent.com/u/62238673?v=4&s=117" width="117">](https://github.com/alfatv) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[agreene-coursera](https://github.com/agreene-coursera) |[alfatv](https://github.com/alfatv) |[anark](https://github.com/anark) |[arggh](https://github.com/arggh) |[avalla](https://github.com/avalla) |[bdirito](https://github.com/bdirito) |
+[yaegor](https://github.com/yaegor) |[YehudaKremer](https://github.com/YehudaKremer) |[zachconner](https://github.com/zachconner) |[zacharylawson](https://github.com/zacharylawson) |[agreene-coursera](https://github.com/agreene-coursera) |[alfatv](https://github.com/alfatv) |
 
-[<img alt="c0b41" src="https://avatars.githubusercontent.com/u/2834954?v=4&s=117" width="117">](https://github.com/c0b41) |[<img alt="canvasbh" src="https://avatars.githubusercontent.com/u/44477734?v=4&s=117" width="117">](https://github.com/canvasbh) |[<img alt="craigcbrunner" src="https://avatars.githubusercontent.com/u/2780521?v=4&s=117" width="117">](https://github.com/craigcbrunner) |[<img alt="darthf1" src="https://avatars.githubusercontent.com/u/17253332?v=4&s=117" width="117">](https://github.com/darthf1) |[<img alt="dkisic" src="https://avatars.githubusercontent.com/u/32257921?v=4&s=117" width="117">](https://github.com/dkisic) |[<img alt="fingul" src="https://avatars.githubusercontent.com/u/894739?v=4&s=117" width="117">](https://github.com/fingul) |
+[<img alt="anark" src="https://avatars.githubusercontent.com/u/101184?v=4&s=117" width="117">](https://github.com/anark) |[<img alt="arggh" src="https://avatars.githubusercontent.com/u/17210302?v=4&s=117" width="117">](https://github.com/arggh) |[<img alt="avalla" src="https://avatars.githubusercontent.com/u/986614?v=4&s=117" width="117">](https://github.com/avalla) |[<img alt="bdirito" src="https://avatars.githubusercontent.com/u/8117238?v=4&s=117" width="117">](https://github.com/bdirito) |[<img alt="c0b41" src="https://avatars.githubusercontent.com/u/2834954?v=4&s=117" width="117">](https://github.com/c0b41) |[<img alt="canvasbh" src="https://avatars.githubusercontent.com/u/44477734?v=4&s=117" width="117">](https://github.com/canvasbh) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[c0b41](https://github.com/c0b41) |[canvasbh](https://github.com/canvasbh) |[craigcbrunner](https://github.com/craigcbrunner) |[darthf1](https://github.com/darthf1) |[dkisic](https://github.com/dkisic) |[fingul](https://github.com/fingul) |
+[anark](https://github.com/anark) |[arggh](https://github.com/arggh) |[avalla](https://github.com/avalla) |[bdirito](https://github.com/bdirito) |[c0b41](https://github.com/c0b41) |[canvasbh](https://github.com/canvasbh) |
 
-[<img alt="franckl" src="https://avatars.githubusercontent.com/u/3875803?v=4&s=117" width="117">](https://github.com/franckl) |[<img alt="gaelicwinter" src="https://avatars.githubusercontent.com/u/6510266?v=4&s=117" width="117">](https://github.com/gaelicwinter) |[<img alt="green-mike" src="https://avatars.githubusercontent.com/u/5584225?v=4&s=117" width="117">](https://github.com/green-mike) |[<img alt="hxgf" src="https://avatars.githubusercontent.com/u/56104?v=4&s=117" width="117">](https://github.com/hxgf) |[<img alt="johnmanjiro13" src="https://avatars.githubusercontent.com/u/28798279?v=4&s=117" width="117">](https://github.com/johnmanjiro13) |[<img alt="kode-ninja" src="https://avatars.githubusercontent.com/u/7857611?v=4&s=117" width="117">](https://github.com/kode-ninja) |
+[<img alt="craigcbrunner" src="https://avatars.githubusercontent.com/u/2780521?v=4&s=117" width="117">](https://github.com/craigcbrunner) |[<img alt="darthf1" src="https://avatars.githubusercontent.com/u/17253332?v=4&s=117" width="117">](https://github.com/darthf1) |[<img alt="dkisic" src="https://avatars.githubusercontent.com/u/32257921?v=4&s=117" width="117">](https://github.com/dkisic) |[<img alt="fingul" src="https://avatars.githubusercontent.com/u/894739?v=4&s=117" width="117">](https://github.com/fingul) |[<img alt="franckl" src="https://avatars.githubusercontent.com/u/3875803?v=4&s=117" width="117">](https://github.com/franckl) |[<img alt="gaelicwinter" src="https://avatars.githubusercontent.com/u/6510266?v=4&s=117" width="117">](https://github.com/gaelicwinter) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[franckl](https://github.com/franckl) |[gaelicwinter](https://github.com/gaelicwinter) |[green-mike](https://github.com/green-mike) |[hxgf](https://github.com/hxgf) |[johnmanjiro13](https://github.com/johnmanjiro13) |[kode-ninja](https://github.com/kode-ninja) |
+[craigcbrunner](https://github.com/craigcbrunner) |[darthf1](https://github.com/darthf1) |[dkisic](https://github.com/dkisic) |[fingul](https://github.com/fingul) |[franckl](https://github.com/franckl) |[gaelicwinter](https://github.com/gaelicwinter) |
 
-[<img alt="magumbo" src="https://avatars.githubusercontent.com/u/6683765?v=4&s=117" width="117">](https://github.com/magumbo) |[<img alt="ninesalt" src="https://avatars.githubusercontent.com/u/7952255?v=4&s=117" width="117">](https://github.com/ninesalt) |[<img alt="phil714" src="https://avatars.githubusercontent.com/u/7584581?v=4&s=117" width="117">](https://github.com/phil714) |[<img alt="luntta" src="https://avatars.githubusercontent.com/u/14221637?v=4&s=117" width="117">](https://github.com/luntta) |[<img alt="rhymes" src="https://avatars.githubusercontent.com/u/146201?v=4&s=117" width="117">](https://github.com/rhymes) |[<img alt="rlebosse" src="https://avatars.githubusercontent.com/u/2794137?v=4&s=117" width="117">](https://github.com/rlebosse) |
+[<img alt="green-mike" src="https://avatars.githubusercontent.com/u/5584225?v=4&s=117" width="117">](https://github.com/green-mike) |[<img alt="hxgf" src="https://avatars.githubusercontent.com/u/56104?v=4&s=117" width="117">](https://github.com/hxgf) |[<img alt="johnmanjiro13" src="https://avatars.githubusercontent.com/u/28798279?v=4&s=117" width="117">](https://github.com/johnmanjiro13) |[<img alt="kode-ninja" src="https://avatars.githubusercontent.com/u/7857611?v=4&s=117" width="117">](https://github.com/kode-ninja) |[<img alt="magumbo" src="https://avatars.githubusercontent.com/u/6683765?v=4&s=117" width="117">](https://github.com/magumbo) |[<img alt="ninesalt" src="https://avatars.githubusercontent.com/u/7952255?v=4&s=117" width="117">](https://github.com/ninesalt) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[magumbo](https://github.com/magumbo) |[ninesalt](https://github.com/ninesalt) |[phil714](https://github.com/phil714) |[luntta](https://github.com/luntta) |[rhymes](https://github.com/rhymes) |[rlebosse](https://github.com/rlebosse) |
+[green-mike](https://github.com/green-mike) |[hxgf](https://github.com/hxgf) |[johnmanjiro13](https://github.com/johnmanjiro13) |[kode-ninja](https://github.com/kode-ninja) |[magumbo](https://github.com/magumbo) |[ninesalt](https://github.com/ninesalt) |
 
-[<img alt="rtaieb" src="https://avatars.githubusercontent.com/u/35224301?v=4&s=117" width="117">](https://github.com/rtaieb) |[<img alt="slawexxx44" src="https://avatars.githubusercontent.com/u/11180644?v=4&s=117" width="117">](https://github.com/slawexxx44) |[<img alt="thanhthot" src="https://avatars.githubusercontent.com/u/50633205?v=4&s=117" width="117">](https://github.com/thanhthot) |[<img alt="tinny77" src="https://avatars.githubusercontent.com/u/1872936?v=4&s=117" width="117">](https://github.com/tinny77) |[<img alt="vedran555" src="https://avatars.githubusercontent.com/u/38395951?v=4&s=117" width="117">](https://github.com/vedran555) |[<img alt="yoann-hellopret" src="https://avatars.githubusercontent.com/u/46525558?v=4&s=117" width="117">](https://github.com/yoann-hellopret) |
+[<img alt="phil714" src="https://avatars.githubusercontent.com/u/7584581?v=4&s=117" width="117">](https://github.com/phil714) |[<img alt="luntta" src="https://avatars.githubusercontent.com/u/14221637?v=4&s=117" width="117">](https://github.com/luntta) |[<img alt="rhymes" src="https://avatars.githubusercontent.com/u/146201?v=4&s=117" width="117">](https://github.com/rhymes) |[<img alt="rlebosse" src="https://avatars.githubusercontent.com/u/2794137?v=4&s=117" width="117">](https://github.com/rlebosse) |[<img alt="rtaieb" src="https://avatars.githubusercontent.com/u/35224301?v=4&s=117" width="117">](https://github.com/rtaieb) |[<img alt="slawexxx44" src="https://avatars.githubusercontent.com/u/11180644?v=4&s=117" width="117">](https://github.com/slawexxx44) |
 :---: |:---: |:---: |:---: |:---: |:---: |
-[rtaieb](https://github.com/rtaieb) |[slawexxx44](https://github.com/slawexxx44) |[thanhthot](https://github.com/thanhthot) |[tinny77](https://github.com/tinny77) |[vedran555](https://github.com/vedran555) |[yoann-hellopret](https://github.com/yoann-hellopret) |
+[phil714](https://github.com/phil714) |[luntta](https://github.com/luntta) |[rhymes](https://github.com/rhymes) |[rlebosse](https://github.com/rlebosse) |[rtaieb](https://github.com/rtaieb) |[slawexxx44](https://github.com/slawexxx44) |
 
-[<img alt="olitomas" src="https://avatars.githubusercontent.com/u/6918659?v=4&s=117" width="117">](https://github.com/olitomas) |[<img alt="JimmyLv" src="https://avatars.githubusercontent.com/u/4997466?v=4&s=117" width="117">](https://github.com/JimmyLv) |
-:---: |:---: |
-[olitomas](https://github.com/olitomas) |[JimmyLv](https://github.com/JimmyLv) |
+[<img alt="thanhthot" src="https://avatars.githubusercontent.com/u/50633205?v=4&s=117" width="117">](https://github.com/thanhthot) |[<img alt="tinny77" src="https://avatars.githubusercontent.com/u/1872936?v=4&s=117" width="117">](https://github.com/tinny77) |[<img alt="vedran555" src="https://avatars.githubusercontent.com/u/38395951?v=4&s=117" width="117">](https://github.com/vedran555) |[<img alt="yoann-hellopret" src="https://avatars.githubusercontent.com/u/46525558?v=4&s=117" width="117">](https://github.com/yoann-hellopret) |[<img alt="olitomas" src="https://avatars.githubusercontent.com/u/6918659?v=4&s=117" width="117">](https://github.com/olitomas) |[<img alt="JimmyLv" src="https://avatars.githubusercontent.com/u/4997466?v=4&s=117" width="117">](https://github.com/JimmyLv) |
+:---: |:---: |:---: |:---: |:---: |:---: |
+[thanhthot](https://github.com/thanhthot) |[tinny77](https://github.com/tinny77) |[vedran555](https://github.com/vedran555) |[yoann-hellopret](https://github.com/yoann-hellopret) |[olitomas](https://github.com/olitomas) |[JimmyLv](https://github.com/JimmyLv) |
 
 
 <!--/contributors-->

+ 1 - 0
examples/bundled/index.js

@@ -32,6 +32,7 @@ const uppy = new Uppy({
     showProgressDetails: true,
     proudlyDisplayPoweredByUppy: true,
     note: '2 files, images and video only',
+    restrictions: { requiredMetaFields: ['caption'] },
   })
   .use(GoogleDrive, { target: Dashboard, companionUrl: 'http://localhost:3020' })
   .use(Instagram, { target: Dashboard, companionUrl: 'http://localhost:3020' })

+ 2 - 2
examples/cdn-example/index.html

@@ -4,11 +4,11 @@
     <title></title>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
-    <link href="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.css" rel="stylesheet">
+    <link href="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.css" rel="stylesheet">
   </head>
   <body>
     <button id="uppyModalOpener">Open Modal</button>
-    <script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.js"></script>
+    <script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
     <script>
       const uppy = Uppy.Core({debug: true, autoProceed: false})
         .use(Uppy.Dashboard, { trigger: '#uppyModalOpener' })

+ 1 - 0
examples/dev/Dashboard.js

@@ -58,6 +58,7 @@ module.exports = () => {
       username: 'John',
       license: 'Creative Commons',
     },
+    restrictions: { requiredMetaFields: ['caption'] },
   })
     .use(Dashboard, {
       trigger: '#pick-files',

+ 1 - 1
examples/transloadit-textarea/index.html

@@ -2,7 +2,7 @@
 <html>
   <head>
     <meta charset="utf-8">
-    <link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.10.12/robodog.css">
+    <link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.11.0/robodog.css">
     <style>
       body {
         font-family: Roboto, Open Sans;

+ 2 - 2
examples/uppy-with-companion/client/index.html

@@ -4,11 +4,11 @@
     <title></title>
     <meta charset="UTF-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
-    <link href="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.css" rel="stylesheet">
+    <link href="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.css" rel="stylesheet">
   </head>
   <body>
     <button id="uppyModalOpener">Open Modal</button>
-    <script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.js"></script>
+    <script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
     <script>
       const uppy = Uppy.Core({debug: true, autoProceed: false})
         .use(Uppy.Dashboard, { trigger: '#uppyModalOpener' })

+ 16 - 16
package-lock.json

@@ -75401,7 +75401,7 @@
       }
     },
     "packages/@uppy/angular": {
-      "version": "0.2.0",
+      "version": "0.1.3",
       "dependencies": {
         "@angular/animations": "~12.1.0",
         "@angular/common": "~12.1.0",
@@ -75489,7 +75489,7 @@
       "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="
     },
     "packages/@uppy/aws-s3": {
-      "version": "1.7.12",
+      "version": "1.8.0",
       "license": "MIT",
       "dependencies": {
         "@uppy/companion-client": "file:../companion-client",
@@ -75530,7 +75530,7 @@
       }
     },
     "packages/@uppy/companion": {
-      "version": "2.11.0",
+      "version": "2.12.0",
       "license": "ISC",
       "dependencies": {
         "@purest/providers": "1.0.1",
@@ -75837,7 +75837,7 @@
       }
     },
     "packages/@uppy/core": {
-      "version": "1.19.2",
+      "version": "1.20.0",
       "license": "MIT",
       "dependencies": {
         "@transloadit/prettier-bytes": "0.0.7",
@@ -75851,7 +75851,7 @@
       }
     },
     "packages/@uppy/dashboard": {
-      "version": "1.20.2",
+      "version": "1.21.0",
       "license": "MIT",
       "dependencies": {
         "@transloadit/prettier-bytes": "0.0.7",
@@ -75877,7 +75877,7 @@
       }
     },
     "packages/@uppy/drag-drop": {
-      "version": "1.4.30",
+      "version": "1.4.31",
       "license": "MIT",
       "dependencies": {
         "@uppy/utils": "file:../utils",
@@ -75971,7 +75971,7 @@
       }
     },
     "packages/@uppy/image-editor": {
-      "version": "0.3.0",
+      "version": "0.4.0",
       "license": "MIT",
       "dependencies": {
         "@uppy/utils": "file:../utils",
@@ -76007,7 +76007,7 @@
       }
     },
     "packages/@uppy/locales": {
-      "version": "1.21.0",
+      "version": "1.22.0",
       "license": "MIT"
     },
     "packages/@uppy/onedrive": {
@@ -76047,7 +76047,7 @@
       }
     },
     "packages/@uppy/react": {
-      "version": "1.12.0",
+      "version": "1.12.1",
       "license": "MIT",
       "dependencies": {
         "@uppy/dashboard": "file:../dashboard",
@@ -76094,7 +76094,7 @@
       }
     },
     "packages/@uppy/robodog": {
-      "version": "1.10.12",
+      "version": "1.11.0",
       "license": "MIT",
       "dependencies": {
         "@uppy/core": "file:../core",
@@ -76117,7 +76117,7 @@
       }
     },
     "packages/@uppy/screen-capture": {
-      "version": "1.0.21",
+      "version": "1.1.0",
       "license": "MIT",
       "dependencies": {
         "@uppy/utils": "file:../utils",
@@ -76175,7 +76175,7 @@
       }
     },
     "packages/@uppy/svelte": {
-      "version": "0.1.12",
+      "version": "0.1.13",
       "dependencies": {
         "@uppy/dashboard": "file:../dashboard",
         "@uppy/drag-drop": "file:../drag-drop",
@@ -76231,7 +76231,7 @@
       }
     },
     "packages/@uppy/transloadit": {
-      "version": "1.6.26",
+      "version": "1.7.0",
       "license": "MIT",
       "dependencies": {
         "@uppy/companion-client": "file:../companion-client",
@@ -76293,7 +76293,7 @@
       }
     },
     "packages/@uppy/vue": {
-      "version": "0.2.5",
+      "version": "0.2.6",
       "dependencies": {
         "@uppy/dashboard": "file:../dashboard",
         "@uppy/drag-drop": "file:../drag-drop",
@@ -76310,7 +76310,7 @@
       }
     },
     "packages/@uppy/webcam": {
-      "version": "1.8.12",
+      "version": "1.8.13",
       "license": "MIT",
       "dependencies": {
         "@uppy/utils": "file:../utils",
@@ -76349,7 +76349,7 @@
       }
     },
     "packages/uppy": {
-      "version": "1.30.0",
+      "version": "1.31.0",
       "license": "MIT",
       "dependencies": {
         "@uppy/aws-s3": "file:../@uppy/aws-s3",

+ 1 - 1
package.json

@@ -130,7 +130,7 @@
     "build:companion": "npm run --prefix ./packages/@uppy/companion build",
     "build:css": "node ./bin/build-css.js",
     "build:svelte": "npm run --prefix ./packages/@uppy/svelte build",
-    "build:angular": "npm run --prefix ./packages/@uppy/angular build",
+    "build:angular": "npm run --prefix ./packages/@uppy/angular build:release",
     "build:js": "npm-run-all build:lib build:companion build:locale-pack build:svelte build:angular build:bundle",
     "build:lib": "node ./bin/build-lib.js",
     "build:locale-pack": "node ./bin/locale-packs.js build",

+ 6 - 3
packages/@uppy/angular/package.json

@@ -1,13 +1,13 @@
 {
   "name": "@uppy/angular",
-  "version": "0.2.0",
+  "version": "0.1.3",
   "module": "dist/angular/esm2015/public-api.js",
   "types": "dist/angular/uppy-angular.d.ts",
   "scripts": {
     "ng": "ng",
     "start": "start-storybook -p 6006",
     "build": "ng build",
-    "release": "ng build --prod",
+    "build:release": "ng build --prod",
     "test": "ng test",
     "lint": "ng lint",
     "e2e": "ng e2e",
@@ -75,5 +75,8 @@
   },
   "publishConfig": {
     "access": "public"
-  }
+  },
+  "files": [
+    "/dist"
+  ]
 }

+ 1 - 1
packages/@uppy/aws-s3/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/aws-s3",
   "description": "Upload to Amazon S3 with Uppy",
-  "version": "1.7.12",
+  "version": "1.8.0",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "types/index.d.ts",

+ 1 - 0
packages/@uppy/aws-s3/src/MiniXHRUpload.js

@@ -332,6 +332,7 @@ module.exports = class MiniXHRUpload {
             status: data.response.status,
             body,
             uploadURL,
+            bytesUploaded: data.bytesUploaded,
           }
 
           this.uppy.emit('upload-success', file, uploadResp)

+ 1 - 1
packages/@uppy/companion/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@uppy/companion",
-  "version": "2.11.0",
+  "version": "2.12.0",
   "description": "OAuth helper and remote fetcher for Uppy's (https://uppy.io) extensible file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Dropbox and Google Drive, S3 and more :dog:",
   "main": "lib/companion.js",
   "types": "lib/companion.d.ts",

+ 1 - 1
packages/@uppy/companion/src/server/Uploader.js

@@ -543,7 +543,7 @@ class Uploader {
       logger.error(errMsg, 'upload.multipart.mismatch.error')
       this.emitError(new Error(errMsg))
     } else {
-      this.emitSuccess(null, { response: respObj })
+      this.emitSuccess(null, { response: respObj, bytesUploaded })
     }
 
     this.cleanUp()

+ 1 - 1
packages/@uppy/core/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/core",
   "description": "Core module for the extensible JavaScript file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Instagram, Dropbox, Google Drive, S3 and more :dog:",
-  "version": "1.19.2",
+  "version": "1.20.0",
   "license": "MIT",
   "main": "lib/index.js",
   "style": "dist/style.min.css",

+ 60 - 2
packages/@uppy/core/src/index.js

@@ -22,6 +22,21 @@ class RestrictionError extends Error {
     this.isRestriction = true
   }
 }
+if (typeof AggregateError === 'undefined') {
+  // eslint-disable-next-line no-global-assign
+  AggregateError = class AggregateError extends Error {
+    constructor (message, errors) {
+      super(message)
+      this.errors = errors
+    }
+  }
+}
+class AggregateRestrictionError extends AggregateError {
+  constructor (...args) {
+    super(...args)
+    this.isRestriction = true
+  }
+}
 
 /**
  * Uppy Core module.
@@ -60,6 +75,8 @@ class Uppy {
           1: 'You have to select at least %{smart_count} files',
         },
         exceedsSize: '%{file} exceeds maximum allowed size of %{size}',
+        missingRequiredMetaField: 'Missing required meta fields',
+        missingRequiredMetaFieldOnFile: 'Missing required meta fields in %{fileName}',
         inferiorSize: 'This file is smaller than the allowed size of %{size}',
         youCanOnlyUploadFileTypes: 'You can only upload: %{types}',
         noNewAlreadyUploading: 'Cannot add new files: already uploading',
@@ -108,6 +125,7 @@ class Uppy {
         maxNumberOfFiles: null,
         minNumberOfFiles: null,
         allowedFileTypes: null,
+        requiredMetaFields: [],
       },
       meta: {},
       onBeforeFileAdded: (currentFile) => currentFile,
@@ -239,8 +257,11 @@ class Uppy {
 
   /**
    * Back compat for when uppy.state is used instead of uppy.getState().
+   *
+   * @deprecated
    */
   get state () {
+    // Here, state is a non-enumerable property.
     return this.getState()
   }
 
@@ -535,6 +556,32 @@ class Uppy {
     }
   }
 
+  /**
+   * Check if requiredMetaField restriction is met before uploading.
+   *
+   */
+  #checkRequiredMetaFields (files) {
+    const { requiredMetaFields } = this.opts.restrictions
+    const { hasOwnProperty } = Object.prototype.hasOwnProperty
+
+    const errors = []
+    const fileIDs = Object.keys(files)
+    for (let i = 0; i < fileIDs.length; i++) {
+      const file = this.getFile(fileIDs[i])
+      for (let i = 0; i < requiredMetaFields.length; i++) {
+        if (!hasOwnProperty.call(file.meta, requiredMetaFields[i])) {
+          const err = new RestrictionError(`${this.i18n('missingRequiredMetaFieldOnFile', { fileName: file.name })}`)
+          errors.push(err)
+          this.showOrLogErrorAndThrow(err, { file, throwErr: false })
+        }
+      }
+    }
+
+    if (errors.length) {
+      throw new AggregateRestrictionError(`${this.i18n('missingRequiredMetaField')}`, errors)
+    }
+  }
+
   /**
    * Logs an error, sets Informer message, then throws the error.
    * Emits a 'restriction-failed' event if it’s a restriction error
@@ -1164,6 +1211,14 @@ class Uppy {
         isPaused: false,
       })
 
+      // Remote providers sometimes don't tell us the file size,
+      // but we can know how many bytes we uploaded once the upload is complete.
+      if (file.size == null) {
+        this.setFileState(file.id, {
+          size: uploadResp.bytesUploaded || currentProgress.bytesTotal,
+        })
+      }
+
       this.calculateTotalProgress()
     })
 
@@ -1576,7 +1631,7 @@ class Uppy {
     // Not returning the `catch`ed promise, because we still want to return a rejected
     // promise from this method if the upload failed.
     lastStep.catch((err) => {
-      this.emit('error', err, uploadID)
+      this.emit('error', err)
       this.#removeUpload(uploadID)
     })
 
@@ -1662,7 +1717,10 @@ class Uppy {
     }
 
     return Promise.resolve()
-      .then(() => this.#checkMinNumberOfFiles(files))
+      .then(() => {
+        this.#checkMinNumberOfFiles(files)
+        this.#checkRequiredMetaFields(files)
+      })
       .catch((err) => {
         this.#showOrLogErrorAndThrow(err)
       })

+ 1 - 1
packages/@uppy/core/src/index.test.js

@@ -1365,7 +1365,7 @@ describe('src/Core', () => {
       // wait for success event
       await finishPromise
 
-      expect(core.getFiles()[0].size).toBeNull()
+      expect(core.getFiles()[0].size).toBe(3456)
       expect(core.getFiles()[0].progress).toMatchObject({
         bytesUploaded: 3456,
         bytesTotal: 3456,

+ 1 - 1
packages/@uppy/dashboard/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/dashboard",
   "description": "Universal UI plugin for Uppy.",
-  "version": "1.20.2",
+  "version": "1.21.0",
   "license": "MIT",
   "main": "lib/index.js",
   "style": "dist/style.min.css",

+ 8 - 1
packages/@uppy/dashboard/src/components/EditorPanel.js

@@ -22,7 +22,14 @@ function EditorPanel (props) {
           type="button"
           onClick={props.hideAllPanels}
         >
-          {props.i18n('done')}
+          {props.i18n('cancel')}
+        </button>
+        <button
+          className="uppy-DashboardContent-save"
+          type="button"
+          onClick={props.saveFileEditor}
+        >
+          {props.i18n('save')}
         </button>
       </div>
       <div className="uppy-DashboardContent-panelBody">

+ 29 - 16
packages/@uppy/dashboard/src/components/FileCard/index.js

@@ -1,5 +1,6 @@
 const { h, Component } = require('preact')
 const classNames = require('classnames')
+const { nanoid } = require('nanoid')
 const getFileTypeIcon = require('../../utils/getFileTypeIcon')
 const ignoreEvent = require('../../utils/ignoreEvent.js')
 const FilePreview = require('../FilePreview')
@@ -19,15 +20,8 @@ class FileCard extends Component {
     this.state = {
       formState: storedMetaData,
     }
-  }
 
-  saveOnEnter = (ev) => {
-    if (ev.keyCode === 13) {
-      ev.stopPropagation()
-      ev.preventDefault()
-      const file = this.props.files[this.props.fileCardFor]
-      this.props.saveFileCard(this.state.formState, file.id)
-    }
+    this.form.id = nanoid()
   }
 
   updateMeta = (newVal, name) => {
@@ -39,7 +33,10 @@ class FileCard extends Component {
     }))
   }
 
-  handleSave = () => {
+  form = document.createElement('form');
+
+  handleSave = (e) => {
+    e.preventDefault()
     const fileID = this.props.fileCardFor
     this.props.saveFileCard(this.state.formState, fileID)
   }
@@ -48,6 +45,17 @@ class FileCard extends Component {
     this.props.toggleFileCard(false)
   }
 
+  // TODO(aduh95): move this to `UNSAFE_componentWillMount` when updating to Preact X+.
+  componentWillMount () {
+    this.form.addEventListener('submit', this.handleSave)
+    document.body.appendChild(this.form)
+  }
+
+  componentWillUnmount () {
+    this.form.removeEventListener('submit', this.handleSave)
+    document.body.removeChild(this.form)
+  }
+
   renderMetaFields = () => {
     const metaFields = this.getMetaFields() || []
     const fieldCSSClasses = {
@@ -56,6 +64,7 @@ class FileCard extends Component {
 
     return metaFields.map((field) => {
       const id = `uppy-Dashboard-FileCard-input-${field.id}`
+      const required = this.props.requiredMetaFields.includes(field.id)
       return (
         <fieldset key={field.id} className="uppy-Dashboard-FileCard-fieldset">
           <label className="uppy-Dashboard-FileCard-label" htmlFor={id}>{field.name}</label>
@@ -64,17 +73,18 @@ class FileCard extends Component {
               value: this.state.formState[field.id],
               onChange: (newVal) => this.updateMeta(newVal, field.id),
               fieldCSSClasses,
+              required,
+              form: this.form.id,
             }, h)
             : (
               <input
                 className={fieldCSSClasses.text}
                 id={id}
+                form={this.form.id}
                 type={field.type || 'text'}
+                required={required}
                 value={this.state.formState[field.id]}
                 placeholder={field.placeholder}
-                onKeyUp={this.saveOnEnter}
-                onKeyDown={this.saveOnEnter}
-                onKeyPress={this.saveOnEnter}
                 onInput={ev => this.updateMeta(ev.target.value, field.id)}
                 data-uppy-super-focusable
               />
@@ -112,10 +122,11 @@ class FileCard extends Component {
           <button
             className="uppy-DashboardContent-back"
             type="button"
+            form={this.form.id}
             title={this.props.i18n('finishEditingFile')}
-            onClick={this.handleSave}
+            onClick={this.handleCancel}
           >
-            {this.props.i18n('done')}
+            {this.props.i18n('cancel')}
           </button>
         </div>
 
@@ -128,6 +139,7 @@ class FileCard extends Component {
                 type="button"
                 className="uppy-u-reset uppy-c-btn uppy-Dashboard-FileCard-edit"
                 onClick={() => this.props.openFileEditor(file)}
+                form={this.form.id}
               >
                 {this.props.i18n('editFile')}
               </button>
@@ -141,8 +153,8 @@ class FileCard extends Component {
           <div className="uppy-Dashboard-FileCard-actions">
             <button
               className="uppy-u-reset uppy-c-btn uppy-c-btn-primary uppy-Dashboard-FileCard-actionsBtn"
-              type="button"
-              onClick={this.handleSave}
+              type="submit"
+              form={this.form.id}
             >
               {this.props.i18n('saveChanges')}
             </button>
@@ -150,6 +162,7 @@ class FileCard extends Component {
               className="uppy-u-reset uppy-c-btn uppy-c-btn-link uppy-Dashboard-FileCard-actionsBtn"
               type="button"
               onClick={this.handleCancel}
+              form={this.form.id}
             >
               {this.props.i18n('cancel')}
             </button>

+ 1 - 1
packages/@uppy/dashboard/src/components/PickerPanelContent.js

@@ -23,7 +23,7 @@ function PickerPanelContent (props) {
           type="button"
           onClick={props.hideAllPanels}
         >
-          {props.i18n('done')}
+          {props.i18n('cancel')}
         </button>
       </div>
       <div className="uppy-DashboardContent-panelBody">

+ 14 - 1
packages/@uppy/dashboard/src/index.js

@@ -60,13 +60,13 @@ module.exports = class Dashboard extends UIPlugin {
         copyLinkToClipboardFallback: 'Copy the URL below',
         copyLink: 'Copy link',
         fileSource: 'File source: %{name}',
-        done: 'Done',
         back: 'Back',
         addMore: 'Add more',
         removeFile: 'Remove file',
         editFile: 'Edit file',
         editing: 'Editing %{file}',
         finishEditingFile: 'Finish editing file',
+        save: 'Save',
         saveChanges: 'Save changes',
         cancel: 'Cancel',
         myDevice: 'My Device',
@@ -275,6 +275,17 @@ module.exports = class Dashboard extends UIPlugin {
     })
   }
 
+  saveFileEditor = () => {
+    const { targets } = this.getPluginState()
+    const editors = this._getEditors(targets)
+
+    editors.forEach((editor) => {
+      this.uppy.getPlugin(editor.id).save()
+    })
+
+    this.hideAllPanels()
+  }
+
   openModal = () => {
     const { promise, resolve } = createPromise()
     // save scroll position
@@ -920,6 +931,7 @@ module.exports = class Dashboard extends UIPlugin {
       direction: this.opts.direction,
       activePickerPanel: pluginState.activePickerPanel,
       showFileEditor: pluginState.showFileEditor,
+      saveFileEditor: this.saveFileEditor,
       disableAllFocusableElements: this.disableAllFocusableElements,
       animateOpenClose: this.opts.animateOpenClose,
       isClosing: pluginState.isClosing,
@@ -974,6 +986,7 @@ module.exports = class Dashboard extends UIPlugin {
       parentElement: this.el,
       allowedFileTypes: this.uppy.opts.restrictions.allowedFileTypes,
       maxNumberOfFiles: this.uppy.opts.restrictions.maxNumberOfFiles,
+      requiredMetaFields: this.uppy.opts.restrictions.requiredMetaFields,
       showSelectedFiles: this.opts.showSelectedFiles,
       handleCancelRestore: this.handleCancelRestore,
       handleRequestThumbnail: this.handleRequestThumbnail,

+ 2 - 1
packages/@uppy/dashboard/src/style.scss

@@ -549,7 +549,8 @@
     }
   }
 
-  .uppy-DashboardContent-back {
+  .uppy-DashboardContent-back,
+  .uppy-DashboardContent-save {
     @include reset-button;
     @include highlight-focus;
     border-radius: 3px;

+ 2 - 0
packages/@uppy/dashboard/types/index.d.ts

@@ -5,6 +5,8 @@ import DashboardLocale from './generatedLocale'
 type FieldRenderOptions = {
   value: string,
   onChange: (newVal: string) => void
+  fieldCSSClasses: { text: string }
+  required?: boolean
 }
 
 type PreactRender = (node: any, params: Record<string, unknown> | null, ...children: any[]) => any

+ 1 - 1
packages/@uppy/drag-drop/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/drag-drop",
   "description": "Droppable zone UI for Uppy. Drag and drop files into it to upload.",
-  "version": "1.4.30",
+  "version": "1.4.31",
   "license": "MIT",
   "main": "lib/index.js",
   "style": "dist/style.min.css",

+ 1 - 1
packages/@uppy/image-editor/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/image-editor",
   "description": "Image editor and cropping UI",
-  "version": "0.3.0",
+  "version": "0.4.0",
   "license": "MIT",
   "main": "lib/index.js",
   "style": "dist/style.min.css",

+ 5 - 25
packages/@uppy/image-editor/src/Editor.js

@@ -8,11 +8,14 @@ module.exports = class Editor extends Component {
   }
 
   componentDidMount () {
+    const { opts, storeCropperInstance } = this.props
     this.cropper = new Cropper(
       this.imgElement,
-      this.props.opts.cropperOptions
+      opts.cropperOptions
     )
-    if (this.props.opts.actions.granularRotate) {
+    storeCropperInstance(this.cropper)
+
+    if (opts.actions.granularRotate) {
       this.imgElement.addEventListener('crop', (ev) => {
         const rotationAngle = ev.detail.rotate
         this.setState({
@@ -28,15 +31,6 @@ module.exports = class Editor extends Component {
     this.cropper.destroy()
   }
 
-  save = () => {
-    this.cropper.getCroppedCanvas()
-      .toBlob(
-        (blob) => this.props.save(blob),
-        this.props.currentImage.type,
-        this.props.opts.quality
-      )
-  }
-
   renderRevert () {
     return (
       <button
@@ -236,20 +230,6 @@ module.exports = class Editor extends Component {
         </div>
 
         <div className="uppy-ImageCropper-controls">
-          <button
-            type="button"
-            className="uppy-u-reset uppy-c-btn"
-            aria-label={i18n('save')}
-            data-microtip-position="top"
-            role="tooltip"
-            onClick={() => this.save()}
-          >
-            <svg aria-hidden="true" className="uppy-c-icon" width="24" height="24" viewBox="0 0 24 24">
-              <path d="M0 0h24v24H0z" fill="none" />
-              <path d="M9 16.2L4.8 12l-1.4 1.4L9 19 21 7l-1.4-1.4L9 16.2z" />
-            </svg>
-          </button>
-
           {actions.revert && this.renderRevert()}
           {actions.rotate && this.renderRotate()}
           {actions.granularRotate && this.renderGranularRotate()}

+ 27 - 13
packages/@uppy/image-editor/src/index.js

@@ -14,7 +14,6 @@ module.exports = class ImageEditor extends UIPlugin {
 
     this.defaultLocale = {
       strings: {
-        save: 'Save',
         revert: 'Revert',
         rotate: 'Rotate',
         zoomIn: 'Zoom in',
@@ -91,21 +90,35 @@ module.exports = class ImageEditor extends UIPlugin {
     return false
   }
 
-  save = (blob) => {
+  save = () => {
+    const saveBlobCallback = (blob) => {
+      const { currentImage } = this.getPluginState()
+
+      this.uppy.setFileState(currentImage.id, {
+        data: blob,
+        size: blob.size,
+        preview: null,
+      })
+
+      const updatedFile = this.uppy.getFile(currentImage.id)
+      this.uppy.emit('thumbnail:request', updatedFile)
+      this.setPluginState({
+        currentImage: updatedFile,
+      })
+      this.uppy.emit('file-editor:complete', updatedFile)
+    }
+
     const { currentImage } = this.getPluginState()
 
-    this.uppy.setFileState(currentImage.id, {
-      data: blob,
-      size: blob.size,
-      preview: null,
-    })
+    this.cropper.getCroppedCanvas().toBlob(
+      saveBlobCallback,
+      currentImage.type,
+      this.opts.quality
+    )
+  }
 
-    const updatedFile = this.uppy.getFile(currentImage.id)
-    this.uppy.emit('thumbnail:request', updatedFile)
-    this.setPluginState({
-      currentImage: updatedFile,
-    })
-    this.uppy.emit('file-editor:complete', updatedFile)
+  storeCropperInstance = (cropper) => {
+    this.cropper = cropper
   }
 
   selectFile = (file) => {
@@ -139,6 +152,7 @@ module.exports = class ImageEditor extends UIPlugin {
     return (
       <Editor
         currentImage={currentImage}
+        storeCropperInstance={this.storeCropperInstance}
         save={this.save}
         opts={this.opts}
         i18n={this.i18n}

+ 1 - 1
packages/@uppy/locales/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/locales",
   "description": "Uppy language packs",
-  "version": "1.21.0",
+  "version": "1.22.0",
   "license": "MIT",
   "keywords": [
     "uppy",

+ 1 - 1
packages/@uppy/locales/src/de_DE.js

@@ -110,7 +110,7 @@ de_DE.strings = {
     '1': '+%{smart_count} Dateien hochladen',
     '2': '+%{smart_count} Dateien hochladen',
   },
-  uploading: 'Uploading',
+  uploading: 'Wird hochgeladen',
   uploadingXFiles: {
     '0': '%{smart_count} Datei wird hochgeladen',
     '1': '%{smart_count} Dateien werden hochgeladen',

+ 2 - 0
packages/@uppy/locales/src/en_US.js

@@ -78,6 +78,8 @@ en_US.strings = {
   loading: 'Loading...',
   logOut: 'Log out',
   micDisabled: 'Microphone access denied by user',
+  missingRequiredMetaField: 'Missing required meta fields',
+  missingRequiredMetaFieldOnFile: 'Missing required meta fields in %{fileName}',
   myDevice: 'My Device',
   noCameraDescription: 'In order to take pictures or record video, please connect a camera device',
   noCameraTitle: 'Camera Not Available',

+ 1 - 1
packages/@uppy/react/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/react",
   "description": "React component wrappers around Uppy's official UI plugins.",
-  "version": "1.12.0",
+  "version": "1.12.1",
   "license": "MIT",
   "main": "index.js",
   "module": "index.mjs",

+ 2 - 2
packages/@uppy/robodog/README.md

@@ -18,8 +18,8 @@ We recommend installing from npm and then using a module bundler such as [Webpac
 Alternatively, you can also use this package in a pre-built bundle from Transloadit's CDN: Edgly.
 
 ```html
-<link rel="stylesheet" href="https://releases.transloadit.com/uppy/v1.30.0/robodog.min.css">
-<script src="https://releases.transloadit.com/uppy/v1.30.0/robodog.min.js"></script>
+<link rel="stylesheet" href="https://releases.transloadit.com/uppy/v1.31.0/robodog.min.css">
+<script src="https://releases.transloadit.com/uppy/v1.31.0/robodog.min.js"></script>
 ```
 
 Then, a global `Robodog` variable will be available. For usage instructions, please see the [main Robodog documentation](https://uppy.io/docs/robodog).

+ 1 - 1
packages/@uppy/robodog/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/robodog",
   "description": "Transloadit SDK for browsers based on Uppy",
-  "version": "1.10.12",
+  "version": "1.11.0",
   "license": "MIT",
   "main": "lib/index.js",
   "jsnext:main": "src/index.js",

+ 55 - 0
packages/@uppy/robodog/types/index.d.ts

@@ -0,0 +1,55 @@
+import Uppy = require('@uppy/core');
+import Transloadit = require('@uppy/transloadit')
+import Dashboard = require('@uppy/dashboard')
+import Dropbox = require('@uppy/dropbox')
+import GoogleDrive = require('@uppy/google-drive')
+import Instagram = require('@uppy/instagram');
+import Url = require('@uppy/url')
+import Webcam = require('@uppy/webcam')
+import Onedrive = require('@uppy/onedrive')
+import Facebook = require('@uppy/facebook');
+import Form = require('@uppy/form')
+
+declare namespace Robodog {
+    type Provider = 'dropbox' | 'google-drive' | 'instagram' | 'url' | 'webcam' | 'onedrive' | 'facebook'
+
+    interface RobodogOptionsBase extends Uppy.UppyOptions {
+        providers?: Provider[]
+        companionUrl?: string,
+        companionAllowedHosts?: string | RegExp | Array<string | RegExp>
+        companionHeaders?: Record<string, string>,
+        dropbox?: Dropbox.DropboxOptions
+        googleDrive?: GoogleDrive.GoogleDriveOptions
+        instagram?: Instagram.InstagramOptions
+        url?: Url.UrlOptions
+        webcam?: Webcam.WebcamOptions,
+        onedrive?: Onedrive.OneDriveOptions,
+        facebook?: Facebook.FacebookOptions
+    }
+
+    type RobodogOptions = RobodogOptionsBase & Transloadit.TransloaditOptions & Dashboard.DashboardOptions
+
+    interface RobodogTransloaditResult extends Transloadit.Result {
+        assemblyId: string,
+        stepName: string
+    }
+
+    interface RobodogResult extends Uppy.UploadResult {
+        transloadit: Transloadit.Assembly[],
+        results?: RobodogTransloaditResult[]
+    }
+
+    function pick(opts: RobodogOptions): Promise<RobodogResult>;
+
+    type RobodogFormOptions = RobodogOptions
+        & Pick<Form.FormOptions, 'submitOnSuccess' | 'triggerUploadOnSubmit'>
+        & { modal?: boolean, statusbar?: string }
+
+    function form(target: string, opts: RobodogFormOptions): Uppy.Uppy
+
+    function upload(files: (File | Blob & { name: string })[], opts: RobodogOptions): Promise<RobodogResult>;
+
+    function dashboard(target: string, opts: RobodogOptions): Uppy.Uppy;
+}
+
+export = Robodog;

+ 83 - 0
packages/@uppy/robodog/types/index.test-d.ts

@@ -0,0 +1,83 @@
+import { Transloadit } from 'uppy' // eslint-disable-line import/no-extraneous-dependencies
+import { expectError } from 'tsd'
+import Robodog from '.'
+
+async function performPick () {
+  const { successful, failed, transloadit, results } = await Robodog.pick({
+    target: 'test',
+    errorReporting: true,
+    waitForEncoding: false,
+    waitForMetadata: false,
+    animateOpenClose: true,
+    inline: false,
+    params: {
+      auth: { key: '' },
+      template_id: '',
+    },
+    providers: ['webcam', 'url'],
+    webcam: {
+      countdown: false,
+      modes: [
+        'video-audio',
+        'video-only',
+        'audio-only',
+        'picture',
+      ],
+      mirror: true,
+    },
+    url: {
+      companionUrl: Transloadit.COMPANION,
+    },
+  })
+}
+
+const instance = Robodog.form('string', {
+  submitOnSuccess: true,
+  triggerUploadOnSubmit: false,
+  params: {
+    auth: { key: '' },
+    template_id: '',
+  },
+  modal: true,
+  closeAfterFinish: true,
+  statusbar: 'target',
+})
+
+// should not have access to omitted form settings
+expectError(Robodog.form('string', {
+  addResultToForm: false,
+}))
+
+// target is required
+expectError(Robodog.form({
+  addResultToForm: false,
+}))
+
+const files: File[] = []
+
+const upload = Robodog.upload(files, {
+  debug: true,
+  errorReporting: true,
+  params: {
+    auth: { key: '' },
+    template_id: '',
+  },
+})
+
+// Files array is required
+expectError(Robodog.upload({ debug: true }))
+
+const dashboard = Robodog.dashboard('selector', {
+  debug: true,
+  errorReporting: true,
+  params: {
+    auth: { key: '' },
+    template_id: '',
+  },
+})
+  .on('transloadit:result', (result) => {
+    console.log(result)
+  })
+
+// selector is required
+expectError(Robodog.dashboard({ }))

+ 1 - 1
packages/@uppy/screen-capture/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/screen-capture",
   "description": "Uppy plugin that captures video from display or application.",
-  "version": "1.0.21",
+  "version": "1.1.0",
   "license": "MIT",
   "main": "lib/index.js",
   "style": "dist/style.min.css",

+ 1 - 1
packages/@uppy/svelte/package.json

@@ -3,7 +3,7 @@
   "svelte": "src/index.js",
   "module": "dist/index.mjs",
   "main": "dist/index.js",
-  "version": "0.1.12",
+  "version": "0.1.13",
   "scripts": {
     "build": "rollup -c",
     "prepublishOnly": "npm run build",

+ 1 - 1
packages/@uppy/transloadit/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/transloadit",
   "description": "The Transloadit plugin can be used to upload files to Transloadit for all kinds of processing, such as transcoding video, resizing images, zipping/unzipping, and more",
-  "version": "1.6.26",
+  "version": "1.7.0",
   "license": "MIT",
   "main": "lib/index.js",
   "types": "types/index.d.ts",

+ 84 - 1
packages/@uppy/transloadit/types/index.d.ts

@@ -1,7 +1,90 @@
 import type { PluginOptions, UppyFile, BasePlugin } from '@uppy/core'
 import TransloaditLocale from './generatedLocale'
 
-interface AssemblyParameters {
+  interface FileInfo {
+    id: string,
+    name: string,
+    basename: string,
+    ext: string,
+    size: number,
+    mime: string,
+    type: string,
+    field: string,
+    md5hash: string,
+    is_tus_file: boolean,
+    original_md5hash: string,
+    original_id: string,
+    original_name: string
+    original_basename: string,
+    original_path: string,
+    url: string,
+    ssl_url: string,
+    tus_upload_url: string,
+    meta: Record<string, any>
+  }
+
+  interface Result extends FileInfo {
+    cost: number,
+    execTime: number,
+    queue: string,
+    queueTime: number
+  }
+
+export interface Assembly {
+    ok?: string,
+    message?: string,
+    assembly_id: string,
+    parent_id?: string,
+    account_id: string,
+    template_id?: string,
+    instance: string,
+    assembly_url: string,
+    assembly_ssl_url: string,
+    uppyserver_url: string,
+    companion_url: string,
+    websocket_url: string,
+    tus_url: string,
+    bytes_received: number,
+    bytes_expected: number,
+    upload_duration: number,
+    client_agent?: string,
+    client_ip?: string,
+    client_referer?: string,
+    transloadit_client: string,
+    start_date: string,
+    upload_meta_data_extracted: boolean,
+    warnings: any[],
+    is_infinite: boolean,
+    has_dupe_jobs: boolean,
+    execution_start: string,
+    execution_duration: number,
+    queue_duration: number,
+    jobs_queue_duration: number,
+    notify_start?: any,
+    notify_url?: string,
+    notify_status?: any,
+    notify_response_code?: any,
+    notify_duration?: any,
+    last_job_completed?: string,
+    fields: Record<string, any>,
+    running_jobs: any[],
+    bytes_usage: number,
+    executing_jobs: any[],
+    started_jobs: string[],
+    parent_assembly_status: any,
+    params: string,
+    template?: any,
+    merged_params: string,
+    uploads: FileInfo[],
+    results: Record<string, Result[]>,
+    build_id: string,
+    error?: string,
+    stderr?: string,
+    stdout?: string,
+    reason?: string,
+  }
+
+  interface AssemblyParameters {
     auth: {
       key: string,
       expires?: string

+ 1 - 1
packages/@uppy/vue/package.json

@@ -1,6 +1,6 @@
 {
   "name": "@uppy/vue",
-  "version": "0.2.5",
+  "version": "0.2.6",
   "private": false,
   "main": "lib/index.js",
   "types": "types/index.d.ts",

+ 1 - 1
packages/@uppy/webcam/package.json

@@ -1,7 +1,7 @@
 {
   "name": "@uppy/webcam",
   "description": "Uppy plugin that takes photos or records videos using the device's camera.",
-  "version": "1.8.12",
+  "version": "1.8.13",
   "license": "MIT",
   "main": "lib/index.js",
   "style": "dist/style.min.css",

+ 1 - 1
packages/uppy/package.json

@@ -1,7 +1,7 @@
 {
   "name": "uppy",
   "description": "Extensible JavaScript file upload widget with support for drag&drop, resumable uploads, previews, restrictions, file processing/encoding, remote providers like Instagram, Dropbox, Google Drive, S3 and more :dog:",
-  "version": "1.30.0",
+  "version": "1.31.0",
   "license": "MIT",
   "main": "index.js",
   "module": "index.mjs",

+ 2 - 0
test/endtoend/providers/main.js

@@ -3,6 +3,7 @@ const Dashboard = require('@uppy/dashboard')
 const GoogleDrive = require('@uppy/google-drive')
 const Instagram = require('@uppy/instagram')
 const Dropbox = require('@uppy/dropbox')
+const Box = require('@uppy/box')
 const Tus = require('@uppy/tus')
 
 const isOnTravis = !!(process.env.TRAVIS && process.env.CI)
@@ -20,6 +21,7 @@ window.uppy = new Uppy({
   .use(GoogleDrive, { target: Dashboard, companionUrl })
   .use(Instagram, { target: Dashboard, companionUrl })
   .use(Dropbox, { target: Dashboard, companionUrl })
+  .use(Box, { target: Dashboard, companionUrl })
   .use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/' })
 
 if (window.location.search === '?socketerr=true') {

+ 2 - 0
test/endtoend/typescript/main.ts

@@ -4,6 +4,7 @@ import {
   Instagram,
   Dropbox,
   GoogleDrive,
+  Box,
   Url,
   Webcam,
   Tus,
@@ -36,6 +37,7 @@ const uppy = new Core({
   .use(GoogleDrive, { target: Dashboard, companionUrl: 'http://localhost:3020' })
   .use(Instagram, { target: Dashboard, companionUrl: 'http://localhost:3020' })
   .use(Dropbox, { target: Dashboard, companionUrl: 'http://localhost:3020' })
+  .use(Box, { target: Dashboard, companionUrl: 'http://localhost:3020' })
   .use(Url, { target: Dashboard, companionUrl: 'http://localhost:3020' })
   .use(Webcam, { target: Dashboard })
   .use(Tus, { endpoint: TUS_ENDPOINT })

+ 102 - 51
website/src/_template/contributing.md

@@ -12,12 +12,12 @@ cd uppy
 npm install
 ```
 
-Our websites examples section is also our playground, please read the [Local Previews](#Local-previews) section to get up and running.
+Our website's examples section is also our playground, please read the [Local Previews](#Local-previews) section to get up and running.
 
 ### Requiring files
 
-- If we are `require()`ing a file from the same subpackage (e.g. require `@uppy/dashboard/utils/hi.js` from `@uppy/dashboard/src/index.js`) - we can freely use relative imports, as long as the required file is under the `src` directory (`/:packageName/src/**/*.js`).
-- But if we want to require some file from another subpackage - we should use global @uppy requires, and they should always be in the form of `@uppy/:packageName/(lib instead of src)/(same path).js`
+*   If we are `require()`ing a file from the same subpackage, we can freely use relative imports as long as the required file is under the `src` directory (e.g. to import `@uppy/dashboard/src/utils/hi.js` from `@uppy/dashboard/src/index.js`, use `require('./utils/hi.js')`).
+*   But if we want to `require()` some file from another subpackage - we should use global @uppy requires, and they should always be in the form of `@uppy/:packageName/(lib instead of src)/(same path).js`
 
 ## Tests
 
@@ -27,7 +27,7 @@ Unit tests are using Jest and can be run with:
 npm run test:unit
 ```
 
-For end-to-end tests, we use [Webdriverio](http://webdriver.io). For it to run locally, you need to install a Selenium standalone server. Just follow [the guide](http://webdriver.io/guide.html) to do so. You can also install a Selenium standalone server from NPM:
+For end-to-end tests, we use [Webdriverio](http://webdriver.io). For it to run locally, you need to install a Selenium standalone server. Follow [the Webdriverio guide](http://webdriver.io/guide.html) to do so. You can also install a Selenium standalone server from NPM:
 
 ```bash
 npm install selenium-standalone -g
@@ -54,13 +54,13 @@ npm run test:endtoend:local -- -b chrome
 
 > Note: The `--` is important, it tells npm that the remaining arguments should be interpreted by the script itself, not by npm.
 
-You can run in multiple browsers by passing multiple `-b` flags:
+You can run in several browsers by passing several `-b` flags:
 
 ```bash
 npm run test:endtoend:local -- -b chrome -b firefox
 ```
 
-When trying to get a specific integration test to pass, it's not that helpful to continuously run _all_ tests. You can use the `--suite` flag to run tests from a single `./test/endtoend` folder. For example, `--suite thumbnails` will only run the tests from `./test/endtoend/thumbnails`. Of course, it can also be combined with one or more `-b` flags.
+When trying to get a specific integration test to pass, its not that helpful to continuously run _all_ tests. You can use the `--suite` flag to run tests from a single `./test/endtoend` folder. For example, `--suite thumbnails` will only run the tests from `./test/endtoend/thumbnails`. It can also be joint with one or more `-b` flags.
 
 ```bash
 npm run test:endtoend:local -- -b chrome --suite thumbnails
@@ -68,6 +68,55 @@ npm run test:endtoend:local -- -b chrome --suite thumbnails
 
 These tests are also run automatically on Travis builds with [SauceLabs](https://saucelabs.com/) cloud service using different OSes.
 
+## Development
+
+### Instagram integration
+
+Even though facebook [allows using](https://developers.facebook.com/blog/post/2018/06/08/enforce-https-facebook-login/) http://localhost in dev mode, Instagram doesn’t seem to support that, and seems to need a publically available domain name with HTTPS.
+
+Make sure that you are using a development facebook app at <https://developers.facebook.com/apps>
+
+Go to “Instagram Basic Display” and find `Instagram App ID` and `Instagram App Secret`. Put them in a file called `env.sh` in the repo root:
+
+```bash
+export COMPANION_INSTAGRAM_KEY="Instagram App ID"
+export COMPANION_INSTAGRAM_SECRET="Instagram App Secret"
+```
+
+Run
+
+```bash
+ngrok http 3020
+```
+
+Note the ngrok https base URL, e.g. `https://e0c7de09808d.ngrok.io` and
+append `/instagram/redirect` to it, e.g.:
+
+    https://e0c7de09808d.ngrok.io/instagram/redirect
+
+Add this full ngrok URL to `Valid OAuth Redirect URIs` under `Instagram Basic Display`.
+
+Edit `bin/companion` and change to your ngrok URI:
+
+```bash
+COMPANION_DOMAIN="e0c7de09808d.ngrok.io"
+COMPANION_PROTOCOL="https"
+```
+
+Edit `examples/dev/Dashboard.js`:
+
+```js
+const COMPANION_URL = 'https://e0c7de09808d.ngrok.io'
+```
+
+Go to: Roles -> Roles -> Add Instagram testers -> Add your instagram account
+
+Go to your instagram account at <https://www.instagram.com/accounts/manage_access/>
+
+Tester invites -> Accept
+
+Now you should be able to test the Instagram integration.
+
 ## Releases
 
 Before doing a release, check that the examples on the website work:
@@ -91,37 +140,37 @@ Releases are managed by [Lerna](https://github.com/lerna/lerna). We do some clea
 npm run release
 ```
 
-If you have two-factor authentication enabled on your account, Lerna will ask for a one-time password. There is an issue with the CLI where the OTP prompt may be obscured by a publishing progress bar. If Lerna appears to hang just as it starts publishing, chances are it's waiting for the password. Try typing in your OTP and hitting enter.
+If you have two-factor authentication enabled on your account, Lerna will ask for a one-time password. You may stumble upon a known issue with the CLI where the OTP prompt may be obscured by a publishing progress bar. If Lerna appears to freeze as it starts publishing, chances are it’s waiting for the password. Try typing in your OTP and hitting enter.
 
 Other things to keep in mind during release:
 
-* When doing a major release >= 1.0, of the `@uppy/core` package, the `peerDependency` of the plugin packages needs to be updated first. Eg when updating from 1.y.z to 2.0.0, the peerDependency of each should be `"@uppy/core": "^2.0.0"` before doing `npm run release`.
-* When adding a new package, add the following key to its package.json:
-  ```json
-  "publishConfig": { "access": "public" }
-  ```
-  Else, npm will try and fail to publish a _private_ package, because the `@uppy` scope on npm does not support that.
+*   When doing a major release >= 1.0, of the `@uppy/core` package, the `peerDependency` of the plugin packages needs to be updated first. Eg when updating from 1.y.z to 2.0.0, the peerDependency of each should be `"@uppy/core": "^2.0.0"` before doing `npm run release`.
+*   When adding a new package, add the following key to its package.json:
+    ```json
+    "publishConfig": { "access": "public" }
+    ```
+    Else, npm will try and fail to publish a _private_ package, because the `@uppy` scope on npm does not support that.
 
 After a release, the demos on transloadit.com should also be updated. After updating, check that some things work locally:
 
- - the demos in the demo section work (try one that uses an import robot, and one that you need to upload to)
- - the demos on the homepage work and can import from Google Drive, Instagram, Dropbox, etc.
+*   the demos in the demo section work (try one that uses an import robot, and one that you need to upload to)
+*   the demos on the homepage work and can import from Google Drive, Instagram, Dropbox, etc.
 
-If you don't have access to the transloadit.com source code ping @arturi or @goto-bus-stop and we'll pick it up. :sparkles:
+If you don’t have access to the transloadit.com source code ping @arturi or @goto-bus-stop and we’ll pick it up. :sparkles:
 
 ## Website development
 
-We keep the [uppy.io](http://uppy.io) website in `./website`, so it’s easy to keep docs and code in sync as we are still iterating at high velocity.
+We keep the [uppy.io](http://uppy.io) website in `./website` to keep docs and code in sync as we are still iterating at high velocity.
 
-The site is built with [Hexo](http://hexo.io/), and Travis automatically deploys this onto GitHub Pages (it overwrites the `gh-pages` branch with Hexo's build at every change to `master`). The content is written in Markdown and located in `./website/src`. Feel free to fork & hack!
+The site is built with [Hexo](http://hexo.io/), and Travis automatically deploys this onto GitHub Pages (it overwrites the `gh-pages` branch with Hexos build at every change to `master`). The content is written in Markdown and located in `./website/src`. Feel free to fork & hack!
 
 Even though bundled in this repo, the website is regarded as a separate project. As such, it has its own `package.json` and we aim to keep the surface where the two projects interface as small as possible. `./website/update.js` is called during website builds to inject the Uppy knowledge into the site.
 
 ### Local previews
 
-1. `npm install`
-1. `npm start`
-1. Go to http://localhost:4000. Your changes in `/website` and `/packages/@uppy` will be watched, your browser will refresh as files change.
+1.  `npm install`
+2.  `npm start`
+3.  Go to http://localhost:4000. Your changes in `/website` and `/packages/@uppy` will be watched, your browser will refresh as files change.
 
 Then, to work on, for instance, the XHRUpload example, you would edit the following files:
 
@@ -136,7 +185,7 @@ And open <http://localhost:4000/examples/xhrupload/> in your web browser.
 
 ## CSS guidelines
 
-The CSS standards followed in this project closely resemble those from [Medium's CSS Guidelines](https://gist.github.com/fat/a47b882eb5f84293c4ed). If something is not mentioned here, follow their guidelines.
+The CSS standards followed in this project closely resemble those from [Mediums CSS Guidelines](https://gist.github.com/fat/a47b882eb5f84293c4ed). If something is not mentioned here, follow their guidelines.
 
 ### Naming conventions
 
@@ -175,7 +224,7 @@ Syntax: `[<namespace>-]<ComponentName>[-descendentName][--modifierName]`
 
 ### SASS
 
-This project uses SASS, with some limitations on nesting.  One-level-deep nesting is allowed, but nesting may not extend a selector by using the `&` operator.  For example:
+This project uses SASS, with some limitations on nesting. One-level-deep nesting is allowed, but nesting may not extend a selector by using the `&` operator. For example:
 
 ```sass
 /* BAD */
@@ -201,11 +250,11 @@ Style to the mobile breakpoint with your selectors, then use `min-width` media q
 
 ### Selector, rule ordering
 
-- All selectors are sorted alphabetically and by type.
-- HTML elements go above classes and IDs in a file.
-- Rules are sorted alphabetically.
+*   All selectors are sorted alphabetically and by type.
+*   HTML elements go above classes and IDs in a file.
+*   Rules are sorted alphabetically.
 
-```sass
+```scss
 /* BAD */
 .wrapper {
   width: 940px;
@@ -241,28 +290,29 @@ h1 {
 
 Before opening a pull request for the new integration, open an issue to discuss said integration with the Uppy team. After discussing the integration, you can get started on it. First off, you need to construct the basic components for your integration. The following components are the current standard:
 
-- `Dashboard`: Inline Dashboard (`inline: true`)
-- `DashboardModal`: Dashboard as a modal
-- `DragDrop`
-- `ProgressBar`
-- `StatusBar`
+*   `Dashboard`: Inline Dashboard (`inline: true`)
+*   `DashboardModal`: Dashboard as a modal
+*   `DragDrop`
+*   `ProgressBar`
+*   `StatusBar`
 
-All of these components should function as references to the normal component. Depending on how the framework you're using handles references to the DOM, your approach to creating these may be different. For example, in React, you can assign a property of the component to the reference of a component ([see here](https://github.com/transloadit/uppy/blob/425f9ecfbc8bc48ce6b734e4fc14fa60d25daa97/packages/%40uppy/react/src/Dashboard.js#L47-L54)). This may differ in your framework, but from what we've found, the concepts are generally pretty similar.
+All these components should function as references to the normal component. Depending on how the framework youre using handles references to the DOM, your approach to creating these may be different. For example, in React, you can assign a property of the component to the reference of a component ([see here](https://github.com/transloadit/uppy/blob/425f9ecfbc8bc48ce6b734e4fc14fa60d25daa97/packages/%40uppy/react/src/Dashboard.js#L47-L54)). This may differ in your framework, but from what weve found, the concepts are generally pretty similar.
 
-If you're familiar with React, Vue or soon Svelte, it might be useful to read through the code of those integrations, as they lay out a pretty good structure. After the basic components have been built, there are a few more important tasks to get done:
+If youre familiar with React, Vue or soon Svelte, it might be useful to read through the code of those integrations, as they lay out a pretty good structure. After the basic components have been built, here are a few more important tasks to get done:
 
-- Add TypeScript support in some capacity (if possible)
-- Write documentation
-- Add an example
-- Configuring the build system
+*   Add TypeScript support in some capacity (if possible)
+*   Write documentation
+*   Add an example
+*   Configuring the build system
 
 ### Common issues
 
-Before going into these tasks, there are a few common gotchas that you should be aware of.
+Before going into these tasks, here are a few common gotchas that you should be aware of.
 
 #### Dependencies
 
 Your `package.json` should resemble something like this:
+
 ```json
 {
   "name": "@uppy/framework",
@@ -287,20 +337,21 @@ The most important part about this is that `@uppy/core` is a peer dependency. If
 
 ### Adding TypeScript Support
 
-This section won't be too in-depth, because TypeScript depends on your framework. As general advice, prefer using `d.ts` files and vanilla JavaScript over TypeScript files. This is of course circumstantial, but it makes handling the build system a lot easier when TypeScript doesn't have to transpiled. The version of typescript in the monorepo is `3.7.5`, so features like `import type` will not work at build time. For upcoming integrations, like Angular, this may be updated.
+This section wont be too in-depth, because TypeScript depends on your framework. As general advice, prefer using `d.ts` files and vanilla JavaScript over TypeScript files. This is circumstantial, but it makes handling the build system a lot easier when TypeScript doesn’t have to transpiled. The version of typescript in the monorepo is `4.1`.
 
 ### Writing docs
 
 Generally, documentation for integrations can be broken down into a few pieces that apply to every component, and then documentation for each component. The structure should look something like this:
 
-- Installation
-- Initializing Uppy (may vary depending on how the framework handles reactivity)
-- Usage
-- *For each component*
-  - Loading CSS
-  - Props
+*   Installation
+*   Initializing Uppy (may vary depending on how the framework handles reactivity)
+*   Usage
+*   _For each component_
+    *   Loading CSS
+    *   Props
 
 It may be easier to copy the documentation of earlier integrations and change the parts that need to be changed rather than writing this from scratch. Preferably, keep the documentation to one page. For the front-matter, write something like:
+
 ```markdown
 title: Framework Name
 type: docs
@@ -309,17 +360,17 @@ order: 0
 category: "Other Integrations"
 ```
 
-This data is used to generate Uppy's website. Refer to [the section about running the website locally](#website-previews) if you'd like to see how the docs look on the website.
+This data is used to generate Uppy’s website. Refer to [the section about running the website locally](#website-previews) if you’d like to see how the docs look on the website.
 
 ### Adding an example
 
-This is pretty simple to do, as you can likely use whatever code generation tool for your framework (ex. `create-react-app`) to create this example. Make sure you add the same version of `@uppy/core` to this as your peer dependency required, or you may run into strange issues. Try to include all of the components are some of their functionality. [The React example](https://github.com/transloadit/uppy/blob/master/examples/react-example/App.js) is a great... well example of how to do this well.
+You can likely use whatever code generation tool for your framework (ex. `create-react-app`) to create this example. Make sure you add the same version of `@uppy/core` to this as your peer dependency required, or you may run into strange issues. Try to include all the components are some of their functionality. [The React example](https://github.com/transloadit/uppy/blob/master/examples/react-example/App.js) is a great... well example of how to do this well.
 
 ### Integrating the build system
 
-The biggest part of this is understanding Uppy's build system. The high level description is basically `babel` goes through almost all of the packages and transpiles all the Javascript files in the `src` directory to more compatible JavaScript in the `lib` folder. If you're using vanilla JavaScript for your integration (like React and Vue do), then you can just use this build system and use the files generated as your entry points. 
+The biggest part of this is understanding Uppy’s build system. The high level description is that `babel` goes through almost all the packages and transpiles all the Javascript files in the `src` directory to more compatible JavaScript in the `lib` folder. If youre using vanilla JavaScript for your integration (like React and Vue do), then you can use this build system and use the files generated as your entry points.
 
-If you're using some kind of more abstract file format (like Svelte), then you probably want do to a few things: add the directory name to [this `IGNORE` regex](https://github.com/transloadit/uppy/blob/425f9ecfbc8bc48ce6b734e4fc14fa60d25daa97/bin/build-lib.js#L15); add all of your build dependencies to the root `package.json` (try to keep this small); add a new `build:framework` script to the root `package.json`. This script usually looks something like this:
+If youre using some kind of more abstract file format (like Svelte), then you probably want do to a few things: add the directory name to [this `IGNORE` regex](https://github.com/transloadit/uppy/blob/425f9ecfbc8bc48ce6b734e4fc14fa60d25daa97/bin/build-lib.js#L15); add all your build dependencies to the root `package.json` (try to keep this small); add a new `build:framework` script to the root `package.json`. This script usually looks something like this:
 
 ```json
 {
@@ -329,4 +380,4 @@ If you're using some kind of more abstract file format (like Svelte), then you p
 }
 ```
 
-Then, add this script to the `build:js` script. Try running the `build:js` script and make sure it does not error. It may also be of use to ensure that global dependencies aren't being used (ex. not having rollup locally and relying on a global install), as these dependencies won't be present on the machine's handling building.
+Then, add this script to the `build:js` script. Try running the `build:js` script and make sure it does not error. It may also be of use to make sure that global dependencies aren’t being used (ex. not having rollup locally and relying on a global install), as these dependencies won’t be present on the machine’s handling building.

+ 1 - 0
website/src/docs/box.md

@@ -63,6 +63,7 @@ You can create a Box App on the [Box Developers site](https://app.box.com/develo
 
 Things to note:
 - Choose "Custom App" and select the "Standard OAuth 2.0 (User Authentication)" app type.
+- Oddly you must enable full write access, or you will get [403 when downloading files](https://support.box.com/hc/en-us/community/posts/360049195613-403-error-while-file-download-API-Call)
 
 You'll be redirected to the app page. This page lists the client ID (app key) and client secret (app secret), which you should use to configure Companion as shown above.
 

+ 6 - 5
website/src/docs/dashboard.md

@@ -234,8 +234,8 @@ An array of UI field objects, or a function that takes a [File Object](https://u
 - `name`, the label shown in the interface.
 - `placeholder`, the text shown when no value is set in the field. (Not needed when a custom render function is provided)
 
-Optionally, you can specify `render: ({value, onChange}, h) => void`, a function for rendering a custom form element.
-It gets passed `({value, onChange}, h)` where `value` is the current value of the meta field, `onChange: (newVal) => void` is a function saving the new value and `h` is the `createElement` function from [preact](https://preactjs.com/guide/v10/api-reference#h--createelement).
+Optionally, you can specify `render: ({value, onChange, required}, h) => void`, a function for rendering a custom form element.
+It gets passed `({value, onChange, required}, h)` where `value` is the current value of the meta field, `required` is a boolean that's true if the field `id` is in the `restrictedMetaFields` restriction, and `onChange: (newVal) => void` is a function saving the new value and `h` is the `createElement` function from [preact](https://preactjs.com/guide/v10/api-reference#h--createelement).
 `h` can be useful when using uppy from plain JavaScript, where you cannot write JSX.
 
 ```js
@@ -248,8 +248,8 @@ uppy.use(Dashboard, {
     {
       id: 'public',
       name: 'Public',
-      render ({ value, onChange }, h) {
-        return h('input', { type: 'checkbox', onChange: (ev) => onChange(ev.target.checked ? 'on' : 'off'), defaultChecked: value === 'on' })
+      render ({ value, onChange, required }, h) {
+        return h('input', { type: 'checkbox', required, onChange: (ev) => onChange(ev.target.checked ? 'on' : 'off'), defaultChecked: value === 'on' })
       },
     },
   ],
@@ -269,11 +269,12 @@ uppy.use(Dashboard, {
       fields.push({
         id: 'public',
         name: 'Public',
-        render: ({ value, onChange }, h) => {
+        render: ({ value, onChange, required }, h) => {
           return h('input', {
             type: 'checkbox',
             onChange: (ev) => onChange(ev.target.checked ? 'on' : 'off'),
             defaultChecked: value === 'on',
+            required,
           })
         },
       })

+ 1 - 1
website/src/docs/drop-target.md

@@ -16,7 +16,7 @@ Can be used together with Uppy Dashboard or Drag & Drop plugins, or your custom
 ```js
 import DropTarget from '@uppy/drop-target'
 
-uppy.use(DragDrop, {
+uppy.use(DropTarget, {
   target: document.body,
 })
 ```

+ 5 - 5
website/src/docs/index.md

@@ -19,12 +19,12 @@ Here’s the simplest example html page with Uppy (it uses a CDN bundle, while w
   <head>
     <meta charset="utf-8">
     <title>Uppy</title>
-    <link href="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.css" rel="stylesheet">
+    <link href="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.css" rel="stylesheet">
   </head>
   <body>
     <div id="drag-drop-area"></div>
 
-    <script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.js"></script>
+    <script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
     <script>
       var uppy = Uppy.Core()
         .use(Uppy.Dashboard, {
@@ -118,12 +118,12 @@ You can also use a pre-built bundle from Transloadit's CDN: Edgly. `Uppy` will a
 1\. Add a script at the bottom of the closing `</body>` tag:
 
 ``` html
-<script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.js"></script>
+<script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
 ```
 
 2\. Add CSS to `<head>`:
 ``` html
-<link href="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.css" rel="stylesheet">
+<link href="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.css" rel="stylesheet">
 ```
 
 3\. Initialize at the bottom of the closing `</body>` tag:
@@ -184,5 +184,5 @@ export * from '@uppy/core'
 If you're using Uppy from CDN, those polyfills are already included in the bundle, no need to include anything additionally:
 
 ```html
-<script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.legacy.min.js"></script>
+<script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
 ```

+ 2 - 2
website/src/docs/locales.md

@@ -34,8 +34,8 @@ const uppy = new Uppy({
 Add a `<script>` tag with Uppy bundle and the locale pack you’d like to use. You can copy/paste the link from the CDN column in the [locales table](#List-of-locale-packs). The locale will attach itself to the `Uppy.locales` object.
 
 ```html
-<script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.js"></script>
-<script src="https://releases.transloadit.com/uppy/locales/v1.21.0/de_DE.min.js"></script>
+<script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
+<script src="https://releases.transloadit.com/uppy/locales/v1.22.0/de_DE.min.js"></script>
 
 <script>
 var uppy = Uppy.Core({

+ 4 - 4
website/src/docs/robodog-form.md

@@ -136,7 +136,7 @@ $(selector).transloadit({
 ```
 ```html
 <!-- The new Robodog way! -->
-<script src="//releases.transloadit.com/uppy/robodog/v1.10.12/robodog.min.js"></script>
+<script src="//releases.transloadit.com/uppy/robodog/v1.11.0/robodog.min.js"></script>
 
 <script>
 window.Robodog.form(selector, {
@@ -148,7 +148,7 @@ window.Robodog.form(selector, {
 Make sure to also include the Uppy css file in your `<head>` tag in case you want to use the `modal: true` option:
 ```html
 <head>
-  <link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.10.12/robodog.min.css">
+  <link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.11.0/robodog.min.css">
 </head>
 ```
 
@@ -160,7 +160,7 @@ Notice how the form is submitted to the inexistant `/uploads` route once all tra
 <html>
   <head>
     <title>Testing Robodog</title>
-    <link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.10.12/robodog.min.css">
+    <link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.11.0/robodog.min.css">
   </head>
   <body>
     <form id="upload-form" action="/uploads" enctype="multipart/form-data" method="POST">
@@ -170,7 +170,7 @@ Notice how the form is submitted to the inexistant `/uploads` route once all tra
       <button type="submit">Upload</button>
     </form>
 
-    <script src="https://releases.transloadit.com/uppy/robodog/v1.10.12/robodog.min.js"></script>
+    <script src="https://releases.transloadit.com/uppy/robodog/v1.11.0/robodog.min.js"></script>
     <script type="text/javascript">
     window.Robodog.form('#upload-form', {
       waitForEncoding: true,

+ 2 - 2
website/src/docs/robodog.md

@@ -31,8 +31,8 @@ import '@uppy/robodog/dist/robodog.css'
 If you are not using a bundler, you can also import Robodog using an HTML script tag.
 
 ```html
-<link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.10.12/robodog.min.css">
-<script src="https://releases.transloadit.com/uppy/robodog/v1.10.12/robodog.min.js"></script>
+<link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.11.0/robodog.min.css">
+<script src="https://releases.transloadit.com/uppy/robodog/v1.11.0/robodog.min.js"></script>
 <!-- you can now use: window.Robodog.pick() -->
 ```
 

+ 2 - 0
website/src/docs/uppy.md

@@ -47,6 +47,7 @@ const uppy = new Uppy({
     maxNumberOfFiles: null,
     minNumberOfFiles: null,
     allowedFileTypes: null,
+    requiredMetaFields: [],
   },
   meta: {},
   onBeforeFileAdded: (currentFile, files) => currentFile,
@@ -134,6 +135,7 @@ Optionally, provide rules and conditions to limit the type and/or number of file
 - `maxNumberOfFiles` *null | number* — total number of files that can be selected
 - `minNumberOfFiles` *null | number* — minimum number of files that must be selected before the upload
 - `allowedFileTypes` *null | array* of wildcards `image/*`, exact mime types `image/jpeg`, or file extensions `.jpg`: `['image/*', '.jpg', '.jpeg', '.png', '.gif']`
+- `requiredMetaFields` *array* of strings
 
 `maxNumberOfFiles` also affects the number of files a user is able to select via the system file dialog in UI plugins like `DragDrop`, `FileInput` and `Dashboard`: when set to `1`, they will only be able to select a single file. When `null` or another number is provided, they will be able to select multiple files.
 

+ 11 - 1
website/src/examples/dashboard/app.es6

@@ -6,6 +6,7 @@ const Instagram = require('@uppy/instagram')
 const Facebook = require('@uppy/facebook')
 const OneDrive = require('@uppy/onedrive')
 const Zoom = require('@uppy/zoom')
+const Box = require('@uppy/box')
 const ImageEditor = require('@uppy/image-editor')
 const Url = require('@uppy/url')
 const Webcam = require('@uppy/webcam')
@@ -34,6 +35,7 @@ function uppyInit () {
 
   const uppy = new Uppy({
     logger: Uppy.debugLogger,
+    restrictions: { requiredMetaFields: ['caption'] }
   })
 
   uppy.use(Tus, { endpoint: 'https://tusd.tusdemo.net/files/', resume: true })
@@ -146,6 +148,14 @@ function uppySetOptions () {
     window.uppy.removePlugin(zoomInstance)
   }
 
+  const boxInstance = window.uppy.getPlugin('Box')
+  if (opts.Box && !boxInstance) {
+    window.uppy.use(Box, { target: Dashboard, companionUrl: COMPANION })
+  }
+  if (!opts.Box && boxInstance) {
+    window.uppy.removePlugin(boxInstance)
+  }
+
   const webcamInstance = window.uppy.getPlugin('Webcam')
   if (opts.Webcam && !webcamInstance) {
     window.uppy.use(Webcam, {
@@ -204,7 +214,7 @@ function loadLocaleFromCDN (localeName) {
   const head = document.getElementsByTagName('head')[0]
   const js = document.createElement('script')
   js.type = 'text/javascript'
-  js.src = `https://releases.transloadit.com/uppy/locales/v1.21.0/${localeName}.min.js`
+  js.src = `https://releases.transloadit.com/uppy/locales/v1.22.0/${localeName}.min.js`
 
   head.appendChild(js)
 }

+ 3 - 0
website/src/examples/dashboard/app.html

@@ -16,6 +16,7 @@
     <li><label for="opts-ScreenCapture"><input type="checkbox" id="opts-ScreenCapture" checked/> Screen Capture</label></li>
     <li><label for="opts-GoogleDrive"><input type="checkbox" id="opts-GoogleDrive" checked/> Google Drive</label></li>
     <li><label for="opts-Dropbox"><input type="checkbox" id="opts-Dropbox" checked/> Dropbox</label></li>
+    <li><label for="opts-Box"><input type="checkbox" id="opts-Box" checked/> Box</label></li>
     <li><label for="opts-Instagram"><input type="checkbox" id="opts-Instagram" checked/> Instagram</label></li>
     <li><label for="opts-Facebook"><input type="checkbox" id="opts-Facebook" checked/> Facebook</label></li>
     <li><label for="opts-OneDrive"><input type="checkbox" id="opts-OneDrive" checked/> OneDrive</label></li>
@@ -46,6 +47,7 @@
     ScreenCapture: document.querySelector('#opts-ScreenCapture'),
     GoogleDrive: document.querySelector('#opts-GoogleDrive'),
     Dropbox: document.querySelector('#opts-Dropbox'),
+    Box: document.querySelector('#opts-Box'),
     Instagram: document.querySelector('#opts-Instagram'),
     Facebook: document.querySelector('#opts-Facebook'),
     OneDrive: document.querySelector('#opts-OneDrive'),
@@ -67,6 +69,7 @@
     GoogleDrive: true,
     Instagram: true,
     Dropbox: true,
+    Box: true,
     OneDrive: true,
     Facebook: false,
     Url: true,

+ 4 - 1
website/src/examples/dashboard/index.ejs

@@ -26,6 +26,7 @@ const Uppy = require('@uppy/core')
 const Dashboard = require('@uppy/dashboard')
 const GoogleDrive = require('@uppy/google-drive')
 const Dropbox = require('@uppy/dropbox')
+const Box = require('@uppy/box')
 const Instagram = require('@uppy/instagram')
 const Facebook = require('@uppy/facebook')
 const OneDrive = require('@uppy/onedrive')
@@ -44,7 +45,8 @@ const uppy = new Uppy({
     maxFileSize: 1000000,
     maxNumberOfFiles: 3,
     minNumberOfFiles: 2,
-    allowedFileTypes: ['image/*', 'video/*']
+    allowedFileTypes: ['image/*', 'video/*'],
+    requiredMetaFields: ['caption'],
   }
 })
 .use(Dashboard, {
@@ -63,6 +65,7 @@ const uppy = new Uppy({
 })
 .use(GoogleDrive, { target: Dashboard, companionUrl: 'https://companion.uppy.io' })
 .use(Dropbox, { target: Dashboard, companionUrl: 'https://companion.uppy.io' })
+.use(Box, { target: Dashboard, companionUrl: 'https://companion.uppy.io' })
 .use(Instagram, { target: Dashboard, companionUrl: 'https://companion.uppy.io' })
 .use(Facebook, { target: Dashboard, companionUrl: 'https://companion.uppy.io' })
 .use(OneDrive, { target: Dashboard, companionUrl: 'https://companion.uppy.io' })

+ 3 - 3
website/src/examples/i18n/app.html

@@ -1,7 +1,7 @@
 <!-- Load Uppy CSS bundle. It is advisable to install Uppy
   from npm/yarn instead, and pick and choose the plugins/styles you need.
   But for experimenting, you can use Transloadit’s CDN, Edgly: -->
-<link rel="stylesheet" href="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.css">
+<link rel="stylesheet" href="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.css">
 
 <div class="UppyDragDrop"></div>
 <div class="for-ProgressBar"></div>
@@ -12,8 +12,8 @@
 </div>
 
 <!-- Load Uppy JS bundle. -->
-<script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.js"></script>
-<script src="https://releases.transloadit.com/uppy/locales/v1.21.0/ru_RU.min.js"></script>
+<script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
+<script src="https://releases.transloadit.com/uppy/locales/v1.22.0/ru_RU.min.js"></script>
 <script>
   var uppy = Uppy.Core({
     debug: true,

+ 1 - 1
website/src/examples/markdown-snippets/app.es6

@@ -3,7 +3,7 @@ const marked = require('marked')
 const dragdrop = require('drag-drop')
 // Add Robodog JS. It is advisable to install Robodog from npm/yarn.
 // But for experimenting, you can use also Transloadit’s CDN, Edgly:
-// <script src="https://releases.transloadit.com/uppy/robodog/v1.10.12/robodog.min.js"></script>
+// <script src="https://releases.transloadit.com/uppy/robodog/v1.11.0/robodog.min.js"></script>
 const robodog = require('@uppy/robodog')
 
 const TRANSLOADIT_EXAMPLE_KEY = '35c1aed03f5011e982b6afe82599b6a0'

+ 1 - 1
website/src/examples/markdown-snippets/app.html

@@ -1,6 +1,6 @@
 <!-- Add Robodog styles. It is advisable to install Robodog from npm/yarn.
   But for experimenting, you can use also Transloadit’s CDN, Edgly:
-  <link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.10.12/robodog.min.css"> -->
+  <link rel="stylesheet" href="https://releases.transloadit.com/uppy/robodog/v1.11.0/robodog.min.css"> -->
   <link rel="stylesheet" href="/uppy/robodog.min.css">
   <form id="new" class="form-snippet">
     <h2>Create a new snippet</h2>

+ 3 - 2
website/themes/uppy/layout/index.ejs

@@ -187,8 +187,8 @@
   <p>© <%- date(Date.now(), 'YYYY') %> <a href="https://transloadit.com" target="_blank">Transloadit</a></p>
 </footer>
 
-<link href="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.css" rel="stylesheet">
-<script src="https://releases.transloadit.com/uppy/v1.30.0/uppy.min.js"></script>
+<link href="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.css" rel="stylesheet">
+<script src="https://releases.transloadit.com/uppy/v1.31.0/uppy.min.js"></script>
 
 <script>
   var TUS_ENDPOINT = 'https://tusd.tusdemo.net/files/'
@@ -210,6 +210,7 @@
     .use(Uppy.GoogleDrive, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
     .use(Uppy.Instagram, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
     .use(Uppy.Dropbox, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
+    .use(Uppy.Box, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
     .use(Uppy.Facebook, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
     .use(Uppy.OneDrive, { target: Uppy.Dashboard, companionUrl: COMPANION_ENDPOINT })
     .use(Uppy.Webcam, { target: Uppy.Dashboard })