Przeglądaj źródła

Merge branch 'master' into improvements/ui-tweaks

Artur Paikin 7 lat temu
rodzic
commit
82f0731f30
66 zmienionych plików z 5074 dodań i 335 usunięć
  1. 2 2
      .babelrc
  2. 37 2
      CHANGELOG.md
  3. 3 3
      README.md
  4. 3 0
      bin/build-css.js
  5. 1 1
      bin/upload-to-cdn.sh
  6. 1 1
      examples/aws-presigned-url/main.js
  7. 8 1
      examples/aws-uppy-server/main.js
  8. 53 1
      examples/aws-uppy-server/package-lock.json
  9. 4 1
      examples/aws-uppy-server/package.json
  10. 31 2
      examples/aws-uppy-server/server.js
  11. 1 2
      examples/bundled-example/main.js
  12. 2 2
      examples/cdn-example/index.html
  13. 17 0
      examples/digitalocean-spaces/index.html
  14. 18 0
      examples/digitalocean-spaces/main.js
  15. 3564 0
      examples/digitalocean-spaces/package-lock.json
  16. 17 0
      examples/digitalocean-spaces/package.json
  17. 19 0
      examples/digitalocean-spaces/readme.md
  18. 67 0
      examples/digitalocean-spaces/server.js
  19. 2 2
      examples/uppy-with-server/client/index.html
  20. 664 96
      package-lock.json
  21. 6 6
      package.json
  22. 1 0
      src/core/Core.js
  23. 21 8
      src/core/Core.test.js
  24. 3 3
      src/core/Translator.test.js
  25. 1 1
      src/core/UppySocket.test.js
  26. 3 1
      src/core/Utils.js
  27. 1 1
      src/core/Utils.test.js
  28. 1 1
      src/core/index.test.js
  29. 14 14
      src/locales/it_IT.js
  30. 23 5
      src/plugins/AwsS3/index.js
  31. 3 1
      src/plugins/Form.js
  32. 1 3
      src/plugins/GoldenRetriever/index.js
  33. 15 0
      src/plugins/ThumbnailGenerator/index.js
  34. 56 5
      src/plugins/ThumbnailGenerator/index.test.js
  35. 8 8
      src/plugins/Transloadit/index.js
  36. 4 4
      src/plugins/Transloadit/index.test.js
  37. 0 1
      src/react/DashboardModal.js
  38. 2 2
      test/mocks/acquirerPlugin1.js
  39. 2 2
      test/mocks/acquirerPlugin2.js
  40. 1 1
      test/mocks/invalidPlugin.js
  41. 2 2
      test/mocks/invalidPluginWithoutId.js
  42. 2 2
      test/mocks/invalidPluginWithoutType.js
  43. 3 3
      website/src/_posts/2017-08-0.18.md
  44. 1 1
      website/src/_posts/2017-10-0.20.md
  45. 2 2
      website/src/_posts/2017-12-0.22.md
  46. 36 4
      website/src/docs/aws-s3.md
  47. 5 3
      website/src/docs/contributing.md
  48. 5 6
      website/src/docs/dashboard.md
  49. 5 1
      website/src/docs/dragdrop.md
  50. 1 1
      website/src/docs/form.md
  51. 6 4
      website/src/docs/golden-retriever.md
  52. 0 8
      website/src/docs/how-to-plugin.md
  53. 3 3
      website/src/docs/index.md
  54. 3 3
      website/src/docs/plugins.md
  55. 1 1
      website/src/docs/progressbar.md
  56. 3 1
      website/src/docs/redux.md
  57. 17 37
      website/src/docs/server.md
  58. 1 1
      website/src/docs/stores.md
  59. 26 25
      website/src/docs/transloadit.md
  60. 1 1
      website/src/docs/tus.md
  61. 67 33
      website/src/docs/uppy.md
  62. 2 3
      website/src/docs/webcam.md
  63. 195 0
      website/src/docs/writing-plugins.md
  64. 3 3
      website/src/docs/xhrupload.md
  65. 2 2
      website/src/examples/i18n/app.html
  66. 2 2
      website/themes/uppy/layout/index.ejs

+ 2 - 2
.babelrc

@@ -1,11 +1,11 @@
 {
 {
   "presets": [
   "presets": [
-    ["es2015", {
+    ["env", {
+      "modules": false,
       "loose": true
       "loose": true
     }]
     }]
   ],
   ],
   "plugins": [
   "plugins": [
-    "add-module-exports",
     "transform-object-assign",
     "transform-object-assign",
     "es6-promise",
     "es6-promise",
     ["transform-react-jsx", { "pragma":"h" }]
     ["transform-react-jsx", { "pragma":"h" }]

+ 37 - 2
CHANGELOG.md

@@ -48,6 +48,8 @@ Ideas that will be planned and find their way into a release at one point
 - [ ] feature: improved UI for Provider, Google Drive and Instagram, grid/list views
 - [ ] feature: improved UI for Provider, Google Drive and Instagram, grid/list views
 - [ ] feature: React Native support
 - [ ] feature: React Native support
 - [ ] consider iframe / more security for Transloadit/Uppy integration widget and Uppy itself. Page can’t get files from Google Drive if its an iframe; possibility for folder restriction for provider plugins
 - [ ] consider iframe / more security for Transloadit/Uppy integration widget and Uppy itself. Page can’t get files from Google Drive if its an iframe; possibility for folder restriction for provider plugins
+- [ ] It would be nice in the long run to have a dynamic package builder here right on the website where you can select the plugins you need/want and it builds and downloads a minified version of them?
+Sort of like jQuery UI: https://jqueryui.com/download/
 - [ ] test: add https://github.com/pa11y/pa11y for automated accessibility testing?
 - [ ] test: add https://github.com/pa11y/pa11y for automated accessibility testing?
 - [ ] test: add tests for `npm pack`
 - [ ] test: add tests for `npm pack`
 - [ ] test: add deepFreeze to test that state in not mutated anywhere by accident #320
 - [ ] test: add deepFreeze to test that state in not mutated anywhere by accident #320
@@ -55,6 +57,11 @@ Ideas that will be planned and find their way into a release at one point
 - [ ] add typescript definitions and JSDoc everywhere? https://github.com/Microsoft/TypeScript/wiki/Type-Checking-JavaScript-Files
 - [ ] add typescript definitions and JSDoc everywhere? https://github.com/Microsoft/TypeScript/wiki/Type-Checking-JavaScript-Files
 - [ ] transloadit plugin: maybe add option to disable uppy server endpoint overrides
 - [ ] transloadit plugin: maybe add option to disable uppy server endpoint overrides
 - [ ] dragdrop: change border color when files doesn’t pass restrictions on drag https://github.com/transloadit/uppy/issues/607
 - [ ] dragdrop: change border color when files doesn’t pass restrictions on drag https://github.com/transloadit/uppy/issues/607
+- [ ] website: automatically generated page with all locale strings used in plugins
+- [ ] transloadit: option for StatusBar’s upload button to act as a "Start assembly" button? Useful if an assembly uses only import robots, such as /s3/import to start a batch transcoding job.
+- [ ] provider: Add Facebook
+- [ ] provider: Add OneDrive
+- [ ] provider: Add Box
 
 
 ## 1.0 Goals
 ## 1.0 Goals
 
 
@@ -85,7 +92,7 @@ What we need to do to release Uppy 1.0
 
 
 ## 0.24.0
 ## 0.24.0
 
 
-To be released: 2018-03-01.
+To be released: 2018-03-29.
 
 
 - [ ] dashboard: allow minimizing the Dashboard during upload (Uppy then becomes just a tiny progress indicator) (@arturi)
 - [ ] dashboard: allow minimizing the Dashboard during upload (Uppy then becomes just a tiny progress indicator) (@arturi)
 - [ ] dashboard: cancel button for any kind of uploads? currently resume/pause only for tus, and cancel for XHR (@arturi, @goto-bus-stop)
 - [ ] dashboard: cancel button for any kind of uploads? currently resume/pause only for tus, and cancel for XHR (@arturi, @goto-bus-stop)
@@ -105,7 +112,6 @@ To be released: 2018-03-01.
 - [ ] core: update file-type
 - [ ] core: update file-type
 - [x] goldenretriever: warn, not error, when files cannot be saved by goldenretriever (#641 / @goto-bus-stop)
 - [x] goldenretriever: warn, not error, when files cannot be saved by goldenretriever (#641 / @goto-bus-stop)
 - [ ] docs: quick start guide: https://community.transloadit.com/t/quick-start-guide-would-be-really-helpful/14605 (@arturi)
 - [ ] docs: quick start guide: https://community.transloadit.com/t/quick-start-guide-would-be-really-helpful/14605 (@arturi)
-- [ ] docs: on writing plugins (@goto-bus-stop)
 - [ ] docs: all useful events (@arturi)
 - [ ] docs: all useful events (@arturi)
 - [ ] s3: rename `AWS S3` to something more general if it works with Google Cloud Storage too? See #460
 - [ ] s3: rename `AWS S3` to something more general if it works with Google Cloud Storage too? See #460
 - [ ] dashboard: try adding optional whitelabel “powered by uppy.io”, maybe muted small uppy logo that gains color on hover (@nqst, @arturi)
 - [ ] dashboard: try adding optional whitelabel “powered by uppy.io”, maybe muted small uppy logo that gains color on hover (@nqst, @arturi)
@@ -117,6 +123,35 @@ To be released: 2018-03-01.
 - [ ] test: add typescript with JSDoc (@arturi)
 - [ ] test: add typescript with JSDoc (@arturi)
 - [ ] dragdrop: allow customizing arrow icon https://github.com/transloadit/uppy/pull/374#issuecomment-334116208 (@arturi)
 - [ ] dragdrop: allow customizing arrow icon https://github.com/transloadit/uppy/pull/374#issuecomment-334116208 (@arturi)
 
 
+## 0.23.3
+
+- docs: add “Writing Plugins” (@goto-bus-stop)
+- docs: Update aws-s3.md, xhrupload.md (#692 / @bertho-zero)
+- docs: Typos, fixes and improvements (@tim-kos, @ifedapoolarewaju, @arturi / #704)
+- core: add Google Drive to S3 + uppy-server example, update docs (@goto-bus-stop / #711)
+- s3: Support fake XHR from remote uploads (@goto-bus-stop / #711)
+- dashboard: fix FileItem titles (#696 / @bertho-zero)
+- form: Fix `get-form-data` being undefined when built with Rollup (#698 / @goto-bus-stop)
+- transloadit: Capitalise Assembly in user facing messages (#699 / @goto-bus-stop)
+- core: Add yaml file type (#710 / @jessica-coursera)
+- core: Clear uploads on `cancelAll` (#664 / @goto-bus-stop)
+- core: Remove Redux state sync plugin (#667 / @goto-bus-stop)
+- core: merge of restrictions (#677 / @richmeij)
+- core: Check for empty URL (#681 / @arturi)
+- build: Use babel-preset-env, drop modules transform, use CommonJS in test files (#714 / @goto-bus-stop)
+- dashboard: Remove semiTransparent for good (#704 / @arturi)
+- url: Prevent scrolling when focusing on input when Url tab is opened (#179bdf7 / @arturi)
+
+## 0.23.2
+
+- core: ⚠️ **breaking** Emit full file object instead of fileID in events like uppy.on('event', file, data) (#647 / @arturi)
+- core: Fix merging locale strings in Core (#666 / @goto-bus-stop)
+- s3: Check upload parameters shape, fixes #653 (#665 / @goto-bus-stop)
+- docs: Add more Core events to docs (@arturi)
+- xhrupload: Clear timer when upload is removed in XHRUpload (#647 / @arturi)
+- xhrupload: Fix XHRUpload.js error handling (#656 / @rhymes)
+- tus: Configure uploadUrl for uppy-server uploads (#643 / @goto-bus-stop)
+
 ## 0.23.1
 ## 0.23.1
 
 
 - xhrupload: ⚠️ **breaking** Revamped XHR response handling: This adds a response key to files when the upload completed (regardless of whether it succeeded). file.response contains a status and a data property. data is the result of getResponseData. One change here is that getResponseData is also called if there was an error, not sure if that's a good idea; Also changed events to emit file objects instead of IDs here because it touches many of the same places. (#612 / @goto-bus-stop)
 - xhrupload: ⚠️ **breaking** Revamped XHR response handling: This adds a response key to files when the upload completed (regardless of whether it succeeded). file.response contains a status and a data property. data is the result of getResponseData. One change here is that getResponseData is also called if there was an error, not sure if that's a good idea; Also changed events to emit file objects instead of IDs here because it touches many of the same places. (#612 / @goto-bus-stop)

+ 3 - 3
README.md

@@ -64,7 +64,7 @@ $ npm install uppy --save
 
 
 We recommend installing from npm and then using a module bundler such as [Webpack](http://webpack.github.io/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
 We recommend installing from npm and then using a module bundler such as [Webpack](http://webpack.github.io/), [Browserify](http://browserify.org/) or [Rollup.js](http://rollupjs.org/).
 
 
-Add CSS [uppy.min.css](https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.min.css), either to `<head>` of your HTML page 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://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.min.css), either to `<head>` of your HTML page 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.
 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.
 
 
@@ -73,12 +73,12 @@ Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly
 1\. Add a script to the bottom of `<body>`:
 1\. Add a script to the bottom of `<body>`:
 
 
 ``` html
 ``` html
-<script src="https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.min.js"></script>
+<script src="https://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.min.js"></script>
 ```
 ```
 
 
 2\. Add CSS to `<head>`:
 2\. Add CSS to `<head>`:
 ``` html
 ``` html
-<link href="https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.min.css" rel="stylesheet">
+<link href="https://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.min.css" rel="stylesheet">
 ```
 ```
 
 
 3\. Initialize:
 3\. Initialize:

+ 3 - 0
bin/build-css.js

@@ -29,6 +29,7 @@ function minifyCSS () {
             resolve()
             resolve()
           })
           })
         })
         })
+        .catch(err => handleErr(err))
     })
     })
   })
   })
 }
 }
@@ -49,6 +50,7 @@ function compileCSS () {
             resolve()
             resolve()
           })
           })
         })
         })
+        .catch(err => handleErr(err))
     })
     })
   })
   })
 }
 }
@@ -58,3 +60,4 @@ compileCSS()
   .then(function () {
   .then(function () {
     console.info(chalk.yellow('✓ CSS Bundle 🎉'))
     console.info(chalk.yellow('✓ CSS Bundle 🎉'))
   })
   })
+  .catch(err => handleErr(err))

+ 1 - 1
bin/upload-to-cdn.sh

@@ -8,7 +8,7 @@
 #  - Checks if a tag is being built (on Travis - otherwise opts to continue execution regardless)
 #  - Checks if a tag is being built (on Travis - otherwise opts to continue execution regardless)
 #  - Installs AWS CLI if needed
 #  - Installs AWS CLI if needed
 #  - Assumed a fully built uppy is in root dir (unless a specific tag was specified, then it's fetched from npm)
 #  - Assumed a fully built uppy is in root dir (unless a specific tag was specified, then it's fetched from npm)
-#  - Runs npm pack, and stores files to e.g. https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.css
+#  - Runs npm pack, and stores files to e.g. https://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.css
 #  - Uses local package by default, if [version] argument was specified, takes package from npm
 #  - Uses local package by default, if [version] argument was specified, takes package from npm
 #
 #
 # Run as:
 # Run as:

+ 1 - 1
examples/aws-presigned-url/main.js

@@ -33,7 +33,7 @@ uppy.use(AwsS3, {
       return {
       return {
         method: data.method,
         method: data.method,
         url: data.url,
         url: data.url,
-        fields: {}
+        fields: data.fields
       }
       }
     })
     })
   }
   }

+ 8 - 1
examples/aws-uppy-server/main.js

@@ -1,4 +1,6 @@
 const Uppy = require('uppy/lib/core')
 const Uppy = require('uppy/lib/core')
+const GoogleDrive = require('uppy/lib/plugins/GoogleDrive')
+const Webcam = require('uppy/lib/plugins/Webcam')
 const Dashboard = require('uppy/lib/plugins/Dashboard')
 const Dashboard = require('uppy/lib/plugins/Dashboard')
 const AwsS3 = require('uppy/lib/plugins/AwsS3')
 const AwsS3 = require('uppy/lib/plugins/AwsS3')
 
 
@@ -7,9 +9,14 @@ const uppy = Uppy({
   autoProceed: false
   autoProceed: false
 })
 })
 
 
+uppy.use(GoogleDrive, {
+  host: 'http://localhost:3020'
+})
+uppy.use(Webcam)
 uppy.use(Dashboard, {
 uppy.use(Dashboard, {
   inline: true,
   inline: true,
-  target: 'body'
+  target: 'body',
+  plugins: ['GoogleDrive', 'Webcam']
 })
 })
 uppy.use(AwsS3, {
 uppy.use(AwsS3, {
   host: 'http://localhost:3020'
   host: 'http://localhost:3020'

+ 53 - 1
examples/aws-uppy-server/package-lock.json

@@ -739,6 +739,15 @@
       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
       "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz",
       "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
       "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s="
     },
     },
+    "cookie-parser": {
+      "version": "1.4.3",
+      "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.3.tgz",
+      "integrity": "sha1-D+MfoZ0AC5X0qt8fU/3CuKIDuqU=",
+      "requires": {
+        "cookie": "0.3.1",
+        "cookie-signature": "1.0.6"
+      }
+    },
     "cookie-signature": {
     "cookie-signature": {
       "version": "1.0.6",
       "version": "1.0.6",
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
       "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
@@ -763,6 +772,11 @@
         "vary": "1.1.2"
         "vary": "1.1.2"
       }
       }
     },
     },
+    "crc": {
+      "version": "3.4.4",
+      "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.4.tgz",
+      "integrity": "sha1-naHpgOO9RPxck79as9ozeNheRms="
+    },
     "create-ecdh": {
     "create-ecdh": {
       "version": "4.0.0",
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
       "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
@@ -1111,6 +1125,22 @@
         }
         }
       }
       }
     },
     },
+    "express-session": {
+      "version": "1.15.6",
+      "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.15.6.tgz",
+      "integrity": "sha512-r0nrHTCYtAMrFwZ0kBzZEXa1vtPVrw0dKvGSrKP4dahwBQ1BJpF2/y1Pp4sCD/0kvxV4zZeclyvfmw0B4RMJQA==",
+      "requires": {
+        "cookie": "0.3.1",
+        "cookie-signature": "1.0.6",
+        "crc": "3.4.4",
+        "debug": "2.6.9",
+        "depd": "1.1.1",
+        "on-headers": "1.0.1",
+        "parseurl": "1.3.2",
+        "uid-safe": "2.1.5",
+        "utils-merge": "1.0.1"
+      }
+    },
     "extglob": {
     "extglob": {
       "version": "0.3.2",
       "version": "0.3.2",
       "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
       "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
@@ -1605,7 +1635,8 @@
         },
         },
         "jsbn": {
         "jsbn": {
           "version": "0.1.1",
           "version": "0.1.1",
-          "bundled": true
+          "bundled": true,
+          "optional": true
         },
         },
         "json-schema": {
         "json-schema": {
           "version": "0.2.3",
           "version": "0.2.3",
@@ -3243,6 +3274,11 @@
       "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
       "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
       "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
       "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
     },
     },
+    "random-bytes": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
+      "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
+    },
     "randomatic": {
     "randomatic": {
       "version": "1.1.7",
       "version": "1.1.7",
       "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
       "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
@@ -3447,6 +3483,14 @@
       "resolved": "https://registry.npmjs.org/right-now/-/right-now-1.0.0.tgz",
       "resolved": "https://registry.npmjs.org/right-now/-/right-now-1.0.0.tgz",
       "integrity": "sha1-bolgne69fc2vja7Mmuo5z1haCRg="
       "integrity": "sha1-bolgne69fc2vja7Mmuo5z1haCRg="
     },
     },
+    "rimraf": {
+      "version": "2.6.2",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz",
+      "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==",
+      "requires": {
+        "glob": "7.1.2"
+      }
+    },
     "ripemd160": {
     "ripemd160": {
       "version": "2.0.1",
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
       "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
@@ -3870,6 +3914,14 @@
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
       "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
       "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
       "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
     },
     },
+    "uid-safe": {
+      "version": "2.1.5",
+      "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
+      "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
+      "requires": {
+        "random-bytes": "1.0.0"
+      }
+    },
     "ultron": {
     "ultron": {
       "version": "1.0.2",
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
       "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",

+ 4 - 1
examples/aws-uppy-server/package.json

@@ -13,8 +13,11 @@
     "babelify": "^7.3.0",
     "babelify": "^7.3.0",
     "body-parser": "^1.18.2",
     "body-parser": "^1.18.2",
     "budo": "^10.0.4",
     "budo": "^10.0.4",
+    "cookie-parser": "^1.4.3",
     "cors": "^2.8.4",
     "cors": "^2.8.4",
     "express": "^4.16.2",
     "express": "^4.16.2",
-    "npm-run-all": "^4.1.2"
+    "express-session": "^1.15.6",
+    "npm-run-all": "^4.1.2",
+    "rimraf": "^2.6.2"
   }
   }
 }
 }

+ 31 - 2
examples/aws-uppy-server/server.js

@@ -1,11 +1,27 @@
+const fs = require('fs')
+const path = require('path')
+const rimraf = require('rimraf')
 const uppy = require('uppy-server')
 const uppy = require('uppy-server')
 const app = require('express')()
 const app = require('express')()
 
 
-app.use(require('cors')())
+const DATA_DIR = path.join(__dirname, 'tmp')
+
+app.use(require('cors')({
+  origin: true,
+  credentials: true
+}))
+app.use(require('cookie-parser')())
 app.use(require('body-parser').json())
 app.use(require('body-parser').json())
+app.use(require('express-session')({
+  secret: 'hello planet'
+}))
 
 
 const options = {
 const options = {
   providerOptions: {
   providerOptions: {
+    google: {
+      key: process.env.UPPYSERVER_GOOGLE_KEY,
+      secret: process.env.UPPYSERVER_GOOGLE_SECRET
+    },
     s3: {
     s3: {
       getKey: (req, filename) =>
       getKey: (req, filename) =>
         `whatever/${Math.random().toString(32).slice(2)}/${filename}`,
         `whatever/${Math.random().toString(32).slice(2)}/${filename}`,
@@ -15,8 +31,21 @@ const options = {
       region: process.env.UPPYSERVER_AWS_REGION
       region: process.env.UPPYSERVER_AWS_REGION
     }
     }
   },
   },
-  server: { host: 'localhost:3020' }
+  server: { host: 'localhost:3020' },
+  filePath: DATA_DIR,
+  secret: 'blah blah',
+  debug: true
+}
+
+// Create the data directory here for the sake of the example.
+try {
+  fs.accessSync(DATA_DIR)
+} catch (err) {
+  fs.mkdirSync(DATA_DIR)
 }
 }
+process.on('exit', function () {
+  rimraf.sync(DATA_DIR)
+})
 
 
 app.use(uppy.app(options))
 app.use(uppy.app(options))
 
 

+ 1 - 2
examples/bundled-example/main.js

@@ -15,8 +15,7 @@ const Form = require('../../src/plugins/Form')
 // const DragDrop = require('../../src/plugins/DragDrop')
 // const DragDrop = require('../../src/plugins/DragDrop')
 // const GoldenRetriever = require('../../src/plugins/GoldenRetriever')
 // const GoldenRetriever = require('../../src/plugins/GoldenRetriever')
 
 
-const PROTOCOL = location.protocol === 'https:' ? 'https' : 'http'
-const TUS_ENDPOINT = PROTOCOL + '://master.tus.io/files/'
+const TUS_ENDPOINT = 'https://master.tus.io/files/'
 
 
 const uppy = Uppy({
 const uppy = Uppy({
   debug: true,
   debug: true,

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

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

+ 17 - 0
examples/digitalocean-spaces/index.html

@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <title>Uppy DigitalOcean Example</title>
+    <link href="uppy.min.css" rel="stylesheet">
+  </head>
+  <body>
+    <h1>DigitalOcean Spaces</h1>
+    <p>
+      Using the <a href="https://uppy.io/docs/aws-s3">AwsS3</a> plugin to upload to DigitalOcean Spaces ✌️
+    </p>
+
+    <script src="main.js"></script>
+  </body>
+</html>

+ 18 - 0
examples/digitalocean-spaces/main.js

@@ -0,0 +1,18 @@
+const Uppy = require('uppy/lib/core')
+const Dashboard = require('uppy/lib/plugins/Dashboard')
+const AwsS3 = require('uppy/lib/plugins/AwsS3')
+
+const uppy = Uppy({
+  debug: true,
+  autoProceed: false
+})
+
+uppy.use(Dashboard, {
+  inline: true,
+  target: 'body'
+})
+
+// No client side changes needed!
+uppy.use(AwsS3, { host: '/uppy-server' })
+
+uppy.run()

+ 3564 - 0
examples/digitalocean-spaces/package-lock.json

@@ -0,0 +1,3564 @@
+{
+  "name": "uppy-digitalocean-spaces",
+  "requires": true,
+  "lockfileVersion": 1,
+  "dependencies": {
+    "@browserify/acorn5-object-spread": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/@browserify/acorn5-object-spread/-/acorn5-object-spread-5.0.1.tgz",
+      "integrity": "sha512-sFCUPzgeEjdq3rinwy4TFXtak2YZdhqpj6MdNusxkdTFr9TXAUEYK4YQSamR8Joqt/yii1drgl5hk8q/AtJDKA==",
+      "requires": {
+        "acorn": "5.4.1"
+      }
+    },
+    "JSONStream": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.2.tgz",
+      "integrity": "sha1-wQI3G27Dp887hHygDCC7D85Mbeo=",
+      "requires": {
+        "jsonparse": "1.3.1",
+        "through": "2.3.8"
+      }
+    },
+    "acorn": {
+      "version": "5.4.1",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.4.1.tgz",
+      "integrity": "sha512-XLmq3H/BVvW6/GbxKryGxWORz1ebilSsUDlyC27bXhWGWAZWkGwS6FLHjOlwFXNFoWFQEO/Df4u0YYd0K3BQgQ=="
+    },
+    "acorn-node": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.3.0.tgz",
+      "integrity": "sha512-efP54n3d1aLfjL2UMdaXa6DsswwzJeI5rqhbFvXMrKiJ6eJFpf+7R0zN7t8IC+XKn2YOAFAv6xbBNgHUkoHWLw==",
+      "requires": {
+        "acorn": "5.4.1",
+        "xtend": "4.0.1"
+      }
+    },
+    "aliasify": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/aliasify/-/aliasify-2.1.0.tgz",
+      "integrity": "sha1-fDCCW5RQueYYW6J1M+r24gZ9S0I=",
+      "dev": true,
+      "requires": {
+        "browserify-transform-tools": "1.7.0"
+      }
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+    },
+    "ansi-styles": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=",
+      "dev": true
+    },
+    "anymatch": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
+      "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
+      "requires": {
+        "micromatch": "2.3.11",
+        "normalize-path": "2.1.1"
+      }
+    },
+    "arr-diff": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
+      "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
+      "requires": {
+        "arr-flatten": "1.1.0"
+      }
+    },
+    "arr-flatten": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
+    },
+    "array-filter": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz",
+      "integrity": "sha1-fajPLiZijtcygDWB/SH2fKzS7uw="
+    },
+    "array-map": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz",
+      "integrity": "sha1-iKK6tz0c97zVwbEYoAP2b2ZfpmI="
+    },
+    "array-reduce": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz",
+      "integrity": "sha1-FziZ0//Rx9k4PkR5Ul2+J4yrXys="
+    },
+    "array-unique": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
+      "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
+    },
+    "asn1.js": {
+      "version": "4.10.1",
+      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
+      "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
+      "requires": {
+        "bn.js": "4.11.8",
+        "inherits": "2.0.3",
+        "minimalistic-assert": "1.0.0"
+      }
+    },
+    "assert": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
+      "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
+      "requires": {
+        "util": "0.10.3"
+      }
+    },
+    "astw": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/astw/-/astw-2.2.0.tgz",
+      "integrity": "sha1-e9QXhNMkk5h66yOba04cV6hzuRc=",
+      "requires": {
+        "acorn": "4.0.13"
+      },
+      "dependencies": {
+        "acorn": {
+          "version": "4.0.13",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
+          "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c="
+        }
+      }
+    },
+    "async-each": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
+      "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0="
+    },
+    "babel-code-frame": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
+      "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
+      "dev": true,
+      "requires": {
+        "chalk": "1.1.3",
+        "esutils": "2.0.2",
+        "js-tokens": "3.0.2"
+      }
+    },
+    "babel-core": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.0.tgz",
+      "integrity": "sha1-rzL3izGm/O8RnIew/Y2XU/A6C7g=",
+      "dev": true,
+      "requires": {
+        "babel-code-frame": "6.26.0",
+        "babel-generator": "6.26.1",
+        "babel-helpers": "6.24.1",
+        "babel-messages": "6.23.0",
+        "babel-register": "6.26.0",
+        "babel-runtime": "6.26.0",
+        "babel-template": "6.26.0",
+        "babel-traverse": "6.26.0",
+        "babel-types": "6.26.0",
+        "babylon": "6.18.0",
+        "convert-source-map": "1.5.1",
+        "debug": "2.6.9",
+        "json5": "0.5.1",
+        "lodash": "4.17.5",
+        "minimatch": "3.0.4",
+        "path-is-absolute": "1.0.1",
+        "private": "0.1.8",
+        "slash": "1.0.0",
+        "source-map": "0.5.7"
+      }
+    },
+    "babel-generator": {
+      "version": "6.26.1",
+      "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
+      "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
+      "dev": true,
+      "requires": {
+        "babel-messages": "6.23.0",
+        "babel-runtime": "6.26.0",
+        "babel-types": "6.26.0",
+        "detect-indent": "4.0.0",
+        "jsesc": "1.3.0",
+        "lodash": "4.17.5",
+        "source-map": "0.5.7",
+        "trim-right": "1.0.1"
+      }
+    },
+    "babel-helpers": {
+      "version": "6.24.1",
+      "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
+      "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "6.26.0",
+        "babel-template": "6.26.0"
+      }
+    },
+    "babel-messages": {
+      "version": "6.23.0",
+      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
+      "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "6.26.0"
+      }
+    },
+    "babel-register": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
+      "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
+      "dev": true,
+      "requires": {
+        "babel-core": "6.26.0",
+        "babel-runtime": "6.26.0",
+        "core-js": "2.5.3",
+        "home-or-tmp": "2.0.0",
+        "lodash": "4.17.5",
+        "mkdirp": "0.5.1",
+        "source-map-support": "0.4.18"
+      }
+    },
+    "babel-runtime": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
+      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
+      "dev": true,
+      "requires": {
+        "core-js": "2.5.3",
+        "regenerator-runtime": "0.11.1"
+      }
+    },
+    "babel-template": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
+      "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "6.26.0",
+        "babel-traverse": "6.26.0",
+        "babel-types": "6.26.0",
+        "babylon": "6.18.0",
+        "lodash": "4.17.5"
+      }
+    },
+    "babel-traverse": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
+      "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
+      "dev": true,
+      "requires": {
+        "babel-code-frame": "6.26.0",
+        "babel-messages": "6.23.0",
+        "babel-runtime": "6.26.0",
+        "babel-types": "6.26.0",
+        "babylon": "6.18.0",
+        "debug": "2.6.9",
+        "globals": "9.18.0",
+        "invariant": "2.2.3",
+        "lodash": "4.17.5"
+      }
+    },
+    "babel-types": {
+      "version": "6.26.0",
+      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
+      "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
+      "dev": true,
+      "requires": {
+        "babel-runtime": "6.26.0",
+        "esutils": "2.0.2",
+        "lodash": "4.17.5",
+        "to-fast-properties": "1.0.3"
+      }
+    },
+    "babelify": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/babelify/-/babelify-7.3.0.tgz",
+      "integrity": "sha1-qlau3nBn/XvVSWZu4W3ChQh+iOU=",
+      "dev": true,
+      "requires": {
+        "babel-core": "6.26.0",
+        "object-assign": "4.1.1"
+      }
+    },
+    "babylon": {
+      "version": "6.18.0",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
+      "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
+      "dev": true
+    },
+    "balanced-match": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
+    },
+    "base64-js": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.3.tgz",
+      "integrity": "sha512-MsAhsUW1GxCdgYSO6tAfZrNapmUKk7mWx/k5mFY/A1gBtkaCaNapTg+FExCw1r9yeaZhqx/xPg43xgTFH6KL5w=="
+    },
+    "binary-extensions": {
+      "version": "1.11.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz",
+      "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU="
+    },
+    "bn.js": {
+      "version": "4.11.8",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz",
+      "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA=="
+    },
+    "body-parser": {
+      "version": "1.18.2",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.18.2.tgz",
+      "integrity": "sha1-h2eKGdhLR9hZuDGZvVm84iKxBFQ=",
+      "requires": {
+        "bytes": "3.0.0",
+        "content-type": "1.0.4",
+        "debug": "2.6.9",
+        "depd": "1.1.2",
+        "http-errors": "1.6.2",
+        "iconv-lite": "0.4.19",
+        "on-finished": "2.3.0",
+        "qs": "6.5.1",
+        "raw-body": "2.3.2",
+        "type-is": "1.6.16"
+      }
+    },
+    "bole": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/bole/-/bole-2.0.0.tgz",
+      "integrity": "sha1-2KocaQRnv7T+Ebh0rLLoOH44JhU=",
+      "requires": {
+        "core-util-is": "1.0.2",
+        "individual": "3.0.0",
+        "json-stringify-safe": "5.0.1"
+      }
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "requires": {
+        "balanced-match": "1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "braces": {
+      "version": "1.8.5",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
+      "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
+      "requires": {
+        "expand-range": "1.8.2",
+        "preserve": "0.2.0",
+        "repeat-element": "1.1.2"
+      }
+    },
+    "brorand": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
+      "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8="
+    },
+    "browser-pack": {
+      "version": "6.0.4",
+      "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.0.4.tgz",
+      "integrity": "sha512-Q4Rvn7P6ObyWfc4stqLWHtG1MJ8vVtjgT24Zbu+8UTzxYuZouqZsmNRRTFVMY/Ux0eIKv1d+JWzsInTX+fdHPQ==",
+      "requires": {
+        "JSONStream": "1.3.2",
+        "combine-source-map": "0.8.0",
+        "defined": "1.0.0",
+        "safe-buffer": "5.1.1",
+        "through2": "2.0.3",
+        "umd": "3.0.1"
+      }
+    },
+    "browser-resolve": {
+      "version": "1.11.2",
+      "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.2.tgz",
+      "integrity": "sha1-j/CbCixCFxihBRwmCzLkj0QpOM4=",
+      "requires": {
+        "resolve": "1.1.7"
+      },
+      "dependencies": {
+        "resolve": {
+          "version": "1.1.7",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz",
+          "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs="
+        }
+      }
+    },
+    "browserify": {
+      "version": "15.2.0",
+      "resolved": "https://registry.npmjs.org/browserify/-/browserify-15.2.0.tgz",
+      "integrity": "sha512-IHYyFPm2XjJCL+VV0ZtFv8wn/sAHVOm83q3yfSn8YWbZ9jcybgPKxSDdiuMU+35jUL1914l74RnXXPD9Iyo9yg==",
+      "requires": {
+        "JSONStream": "1.3.2",
+        "assert": "1.4.1",
+        "browser-pack": "6.0.4",
+        "browser-resolve": "1.11.2",
+        "browserify-zlib": "0.2.0",
+        "buffer": "5.1.0",
+        "cached-path-relative": "1.0.1",
+        "concat-stream": "1.5.2",
+        "console-browserify": "1.1.0",
+        "constants-browserify": "1.0.0",
+        "crypto-browserify": "3.12.0",
+        "defined": "1.0.0",
+        "deps-sort": "2.0.0",
+        "domain-browser": "1.1.7",
+        "duplexer2": "0.1.4",
+        "events": "1.1.1",
+        "glob": "7.1.2",
+        "has": "1.0.1",
+        "htmlescape": "1.1.1",
+        "https-browserify": "1.0.0",
+        "inherits": "2.0.3",
+        "insert-module-globals": "7.0.1",
+        "labeled-stream-splicer": "2.0.0",
+        "mkdirp": "0.5.1",
+        "module-deps": "5.0.1",
+        "os-browserify": "0.3.0",
+        "parents": "1.0.1",
+        "path-browserify": "0.0.0",
+        "process": "0.11.10",
+        "punycode": "1.3.2",
+        "querystring-es3": "0.2.1",
+        "read-only-stream": "2.0.0",
+        "readable-stream": "2.3.4",
+        "resolve": "1.5.0",
+        "shasum": "1.0.2",
+        "shell-quote": "1.6.1",
+        "stream-browserify": "2.0.1",
+        "stream-http": "2.8.0",
+        "string_decoder": "1.0.3",
+        "subarg": "1.0.0",
+        "syntax-error": "1.4.0",
+        "through2": "2.0.3",
+        "timers-browserify": "1.4.2",
+        "tty-browserify": "0.0.1",
+        "url": "0.11.0",
+        "util": "0.10.3",
+        "vm-browserify": "0.0.4",
+        "xtend": "4.0.1"
+      },
+      "dependencies": {
+        "buffer": {
+          "version": "5.1.0",
+          "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.1.0.tgz",
+          "integrity": "sha512-YkIRgwsZwJWTnyQrsBTWefizHh+8GYj3kbL1BTiAQ/9pwpino0G7B2gp5tx/FUBqUlvtxV85KNR3mwfAtv15Yw==",
+          "requires": {
+            "base64-js": "1.2.3",
+            "ieee754": "1.1.8"
+          }
+        },
+        "url": {
+          "version": "0.11.0",
+          "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+          "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
+          "requires": {
+            "punycode": "1.3.2",
+            "querystring": "0.2.0"
+          }
+        }
+      }
+    },
+    "browserify-aes": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.1.1.tgz",
+      "integrity": "sha512-UGnTYAnB2a3YuYKIRy1/4FB2HdM866E0qC46JXvVTYKlBlZlnvfpSfY6OKfXZAkv70eJ2a1SqzpAo5CRhZGDFg==",
+      "requires": {
+        "buffer-xor": "1.0.3",
+        "cipher-base": "1.0.4",
+        "create-hash": "1.1.3",
+        "evp_bytestokey": "1.0.3",
+        "inherits": "2.0.3",
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "browserify-cipher": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz",
+      "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=",
+      "requires": {
+        "browserify-aes": "1.1.1",
+        "browserify-des": "1.0.0",
+        "evp_bytestokey": "1.0.3"
+      }
+    },
+    "browserify-des": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz",
+      "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=",
+      "requires": {
+        "cipher-base": "1.0.4",
+        "des.js": "1.0.0",
+        "inherits": "2.0.3"
+      }
+    },
+    "browserify-rsa": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
+      "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
+      "requires": {
+        "bn.js": "4.11.8",
+        "randombytes": "2.0.6"
+      }
+    },
+    "browserify-sign": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
+      "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
+      "requires": {
+        "bn.js": "4.11.8",
+        "browserify-rsa": "4.0.1",
+        "create-hash": "1.1.3",
+        "create-hmac": "1.1.6",
+        "elliptic": "6.4.0",
+        "inherits": "2.0.3",
+        "parse-asn1": "5.1.0"
+      }
+    },
+    "browserify-transform-tools": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/browserify-transform-tools/-/browserify-transform-tools-1.7.0.tgz",
+      "integrity": "sha1-g+J3Ih9jJZvtLn6yooOpcKUB9MQ=",
+      "dev": true,
+      "requires": {
+        "falafel": "2.1.0",
+        "through": "2.3.8"
+      }
+    },
+    "browserify-zlib": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
+      "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
+      "requires": {
+        "pako": "1.0.6"
+      }
+    },
+    "budo": {
+      "version": "11.1.7",
+      "resolved": "https://registry.npmjs.org/budo/-/budo-11.1.7.tgz",
+      "integrity": "sha512-m3WzjiO/ZzPAn1TiHM4gIRc/TfOKqf6VmM4SWSCRMCHKzHVpgoYdoY4zIwSoSItEC0dcOIM78+ECRNIDTvdwcw==",
+      "requires": {
+        "bole": "2.0.0",
+        "browserify": "15.2.0",
+        "chokidar": "1.7.0",
+        "connect-pushstate": "1.1.0",
+        "escape-html": "1.0.3",
+        "events": "1.1.1",
+        "garnish": "5.2.0",
+        "get-ports": "1.0.3",
+        "inject-lr-script": "2.1.0",
+        "internal-ip": "3.0.1",
+        "micromatch": "2.3.11",
+        "on-finished": "2.3.0",
+        "on-headers": "1.0.1",
+        "once": "1.4.0",
+        "opn": "3.0.3",
+        "path-is-absolute": "1.0.1",
+        "pem": "1.12.3",
+        "reload-css": "1.0.2",
+        "resolve": "1.5.0",
+        "serve-static": "1.13.2",
+        "simple-html-index": "1.5.0",
+        "stacked": "1.1.1",
+        "stdout-stream": "1.4.0",
+        "strip-ansi": "3.0.1",
+        "subarg": "1.0.0",
+        "term-color": "1.0.1",
+        "url-trim": "1.0.0",
+        "watchify-middleware": "1.8.0",
+        "ws": "1.1.5",
+        "xtend": "4.0.1"
+      }
+    },
+    "buffer-xor": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
+      "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk="
+    },
+    "builtin-status-codes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
+      "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug="
+    },
+    "bytes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+      "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
+    },
+    "cached-path-relative": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.0.1.tgz",
+      "integrity": "sha1-0JxLUoAKpMB44t2BqGmqyQ0uVOc="
+    },
+    "chalk": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+      "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "2.2.1",
+        "escape-string-regexp": "1.0.5",
+        "has-ansi": "2.0.0",
+        "strip-ansi": "3.0.1",
+        "supports-color": "2.0.0"
+      }
+    },
+    "charenc": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
+      "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc="
+    },
+    "chokidar": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
+      "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
+      "requires": {
+        "anymatch": "1.3.2",
+        "async-each": "1.0.1",
+        "fsevents": "1.1.3",
+        "glob-parent": "2.0.0",
+        "inherits": "2.0.3",
+        "is-binary-path": "1.0.1",
+        "is-glob": "2.0.1",
+        "path-is-absolute": "1.0.1",
+        "readdirp": "2.1.0"
+      }
+    },
+    "cipher-base": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+      "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+      "requires": {
+        "inherits": "2.0.3",
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "combine-source-map": {
+      "version": "0.8.0",
+      "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz",
+      "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=",
+      "requires": {
+        "convert-source-map": "1.1.3",
+        "inline-source-map": "0.6.2",
+        "lodash.memoize": "3.0.4",
+        "source-map": "0.5.7"
+      },
+      "dependencies": {
+        "convert-source-map": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+          "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA="
+        }
+      }
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+    },
+    "concat-stream": {
+      "version": "1.5.2",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.5.2.tgz",
+      "integrity": "sha1-cIl4Yk2FavQaWnQd790mHadSwmY=",
+      "requires": {
+        "inherits": "2.0.3",
+        "readable-stream": "2.0.6",
+        "typedarray": "0.0.6"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+        },
+        "process-nextick-args": {
+          "version": "1.0.7",
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
+          "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
+        },
+        "readable-stream": {
+          "version": "2.0.6",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz",
+          "integrity": "sha1-j5A0HmilPMySh4jaz80Rs265t44=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "1.0.0",
+            "process-nextick-args": "1.0.7",
+            "string_decoder": "0.10.31",
+            "util-deprecate": "1.0.2"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        }
+      }
+    },
+    "connect-pushstate": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/connect-pushstate/-/connect-pushstate-1.1.0.tgz",
+      "integrity": "sha1-vKsiQnHEOWBKD7D2FMCl9WPojiQ="
+    },
+    "console-browserify": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
+      "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
+      "requires": {
+        "date-now": "0.1.4"
+      }
+    },
+    "constants-browserify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
+      "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U="
+    },
+    "content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+    },
+    "convert-source-map": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.5.1.tgz",
+      "integrity": "sha1-uCeAl7m8IpNl3lxiz1/K7YtVmeU=",
+      "dev": true
+    },
+    "core-js": {
+      "version": "2.5.3",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.3.tgz",
+      "integrity": "sha1-isw4NFgk8W2DZbfJtCWRaOjtYD4=",
+      "dev": true
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+    },
+    "cors": {
+      "version": "2.8.4",
+      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.4.tgz",
+      "integrity": "sha1-K9OB8usgECAQXNUOpZ2mMJBpRoY=",
+      "requires": {
+        "object-assign": "4.1.1",
+        "vary": "1.1.2"
+      }
+    },
+    "create-ecdh": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
+      "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=",
+      "requires": {
+        "bn.js": "4.11.8",
+        "elliptic": "6.4.0"
+      }
+    },
+    "create-hash": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
+      "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=",
+      "requires": {
+        "cipher-base": "1.0.4",
+        "inherits": "2.0.3",
+        "ripemd160": "2.0.1",
+        "sha.js": "2.4.10"
+      }
+    },
+    "create-hmac": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
+      "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=",
+      "requires": {
+        "cipher-base": "1.0.4",
+        "create-hash": "1.1.3",
+        "inherits": "2.0.3",
+        "ripemd160": "2.0.1",
+        "safe-buffer": "5.1.1",
+        "sha.js": "2.4.10"
+      }
+    },
+    "cross-spawn": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz",
+      "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=",
+      "requires": {
+        "lru-cache": "4.1.1",
+        "shebang-command": "1.2.0",
+        "which": "1.3.0"
+      }
+    },
+    "crypt": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
+      "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs="
+    },
+    "crypto-browserify": {
+      "version": "3.12.0",
+      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz",
+      "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==",
+      "requires": {
+        "browserify-cipher": "1.0.0",
+        "browserify-sign": "4.0.4",
+        "create-ecdh": "4.0.0",
+        "create-hash": "1.1.3",
+        "create-hmac": "1.1.6",
+        "diffie-hellman": "5.0.2",
+        "inherits": "2.0.3",
+        "pbkdf2": "3.0.14",
+        "public-encrypt": "4.0.0",
+        "randombytes": "2.0.6",
+        "randomfill": "1.0.4"
+      }
+    },
+    "date-now": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
+      "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs="
+    },
+    "debounce": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/debounce/-/debounce-1.1.0.tgz",
+      "integrity": "sha512-ZQVKfRVlwRfD150ndzEK8M90ABT+Y/JQKs4Y7U4MXdpuoUkkrr4DwKbVux3YjylA5bUMUj0Nc3pMxPJX6N2QQQ=="
+    },
+    "debug": {
+      "version": "2.6.9",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+      "requires": {
+        "ms": "2.0.0"
+      }
+    },
+    "default-gateway": {
+      "version": "2.7.0",
+      "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-2.7.0.tgz",
+      "integrity": "sha512-bDPiro+T7ZBbt6HlObvUVHv+VHw1WGvF/UI3D+ZN2mqPTPgx5JM5YDgTj06zkr/tq2N5pCgGFMetNrSBi+IjLw==",
+      "requires": {
+        "execa": "0.9.0",
+        "ip-regex": "2.1.0"
+      }
+    },
+    "defined": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
+      "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM="
+    },
+    "depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+    },
+    "deps-sort": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.0.tgz",
+      "integrity": "sha1-CRckkC6EZYJg65EHSMzNGvbiH7U=",
+      "requires": {
+        "JSONStream": "1.3.2",
+        "shasum": "1.0.2",
+        "subarg": "1.0.0",
+        "through2": "2.0.3"
+      }
+    },
+    "des.js": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
+      "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
+      "requires": {
+        "inherits": "2.0.3",
+        "minimalistic-assert": "1.0.0"
+      }
+    },
+    "destroy": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+    },
+    "detect-indent": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
+      "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
+      "dev": true,
+      "requires": {
+        "repeating": "2.0.1"
+      }
+    },
+    "detective": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/detective/-/detective-5.0.2.tgz",
+      "integrity": "sha512-NUsLoezj4wb9o7vpxS9F3L5vcO87ceyRBcl48op06YFNwkyIEY997JpSCA5lDlDuDc6JxOtaL5qfK3muoWxpMA==",
+      "requires": {
+        "@browserify/acorn5-object-spread": "5.0.1",
+        "acorn": "5.4.1",
+        "defined": "1.0.0"
+      }
+    },
+    "diffie-hellman": {
+      "version": "5.0.2",
+      "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz",
+      "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=",
+      "requires": {
+        "bn.js": "4.11.8",
+        "miller-rabin": "4.0.1",
+        "randombytes": "2.0.6"
+      }
+    },
+    "domain-browser": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
+      "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw="
+    },
+    "duplexer2": {
+      "version": "0.1.4",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
+      "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
+      "requires": {
+        "readable-stream": "2.3.4"
+      }
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+    },
+    "elliptic": {
+      "version": "6.4.0",
+      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
+      "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
+      "requires": {
+        "bn.js": "4.11.8",
+        "brorand": "1.1.0",
+        "hash.js": "1.1.3",
+        "hmac-drbg": "1.0.1",
+        "inherits": "2.0.3",
+        "minimalistic-assert": "1.0.0",
+        "minimalistic-crypto-utils": "1.0.1"
+      }
+    },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+    },
+    "esutils": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
+      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
+      "dev": true
+    },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+    },
+    "events": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
+      "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ="
+    },
+    "evp_bytestokey": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
+      "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
+      "requires": {
+        "md5.js": "1.3.4",
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "execa": {
+      "version": "0.9.0",
+      "resolved": "https://registry.npmjs.org/execa/-/execa-0.9.0.tgz",
+      "integrity": "sha512-BbUMBiX4hqiHZUA5+JujIjNb6TyAlp2D5KLheMjMluwOuzcnylDL4AxZYLLn1n2AGB49eSWwyKvvEQoRpnAtmA==",
+      "requires": {
+        "cross-spawn": "5.1.0",
+        "get-stream": "3.0.0",
+        "is-stream": "1.1.0",
+        "npm-run-path": "2.0.2",
+        "p-finally": "1.0.0",
+        "signal-exit": "3.0.2",
+        "strip-eof": "1.0.0"
+      }
+    },
+    "expand-brackets": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
+      "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
+      "requires": {
+        "is-posix-bracket": "0.1.1"
+      }
+    },
+    "expand-range": {
+      "version": "1.8.2",
+      "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
+      "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
+      "requires": {
+        "fill-range": "2.2.3"
+      }
+    },
+    "extglob": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
+      "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
+      "requires": {
+        "is-extglob": "1.0.0"
+      }
+    },
+    "falafel": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.1.0.tgz",
+      "integrity": "sha1-lrsXdh2rqU9G0AFzizzt86Z/4Gw=",
+      "dev": true,
+      "requires": {
+        "acorn": "5.4.1",
+        "foreach": "2.0.5",
+        "isarray": "0.0.1",
+        "object-keys": "1.0.11"
+      }
+    },
+    "filename-regex": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
+      "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY="
+    },
+    "fill-range": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
+      "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
+      "requires": {
+        "is-number": "2.1.0",
+        "isobject": "2.1.0",
+        "randomatic": "1.1.7",
+        "repeat-element": "1.1.2",
+        "repeat-string": "1.6.1"
+      }
+    },
+    "for-in": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
+    },
+    "for-own": {
+      "version": "0.1.5",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
+      "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
+      "requires": {
+        "for-in": "1.0.2"
+      }
+    },
+    "foreach": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz",
+      "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=",
+      "dev": true
+    },
+    "fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+    },
+    "from2": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz",
+      "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=",
+      "requires": {
+        "inherits": "2.0.3",
+        "readable-stream": "2.3.4"
+      }
+    },
+    "from2-string": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/from2-string/-/from2-string-1.1.0.tgz",
+      "integrity": "sha1-GCgrJ9CKJnyzAwzSuLSw8hKvdSo=",
+      "requires": {
+        "from2": "2.3.0"
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+    },
+    "fsevents": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz",
+      "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==",
+      "optional": true,
+      "requires": {
+        "nan": "2.9.2",
+        "node-pre-gyp": "0.6.39"
+      },
+      "dependencies": {
+        "abbrev": {
+          "version": "1.1.0",
+          "bundled": true,
+          "optional": true
+        },
+        "ajv": {
+          "version": "4.11.8",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "co": "4.6.0",
+            "json-stable-stringify": "1.0.1"
+          }
+        },
+        "ansi-regex": {
+          "version": "2.1.1",
+          "bundled": true
+        },
+        "aproba": {
+          "version": "1.1.1",
+          "bundled": true,
+          "optional": true
+        },
+        "are-we-there-yet": {
+          "version": "1.1.4",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "delegates": "1.0.0",
+            "readable-stream": "2.2.9"
+          }
+        },
+        "asn1": {
+          "version": "0.2.3",
+          "bundled": true,
+          "optional": true
+        },
+        "assert-plus": {
+          "version": "0.2.0",
+          "bundled": true,
+          "optional": true
+        },
+        "asynckit": {
+          "version": "0.4.0",
+          "bundled": true,
+          "optional": true
+        },
+        "aws-sign2": {
+          "version": "0.6.0",
+          "bundled": true,
+          "optional": true
+        },
+        "aws4": {
+          "version": "1.6.0",
+          "bundled": true,
+          "optional": true
+        },
+        "balanced-match": {
+          "version": "0.4.2",
+          "bundled": true
+        },
+        "bcrypt-pbkdf": {
+          "version": "1.0.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "tweetnacl": "0.14.5"
+          }
+        },
+        "block-stream": {
+          "version": "0.0.9",
+          "bundled": true,
+          "requires": {
+            "inherits": "2.0.3"
+          }
+        },
+        "boom": {
+          "version": "2.10.1",
+          "bundled": true,
+          "requires": {
+            "hoek": "2.16.3"
+          }
+        },
+        "brace-expansion": {
+          "version": "1.1.7",
+          "bundled": true,
+          "requires": {
+            "balanced-match": "0.4.2",
+            "concat-map": "0.0.1"
+          }
+        },
+        "buffer-shims": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "caseless": {
+          "version": "0.12.0",
+          "bundled": true,
+          "optional": true
+        },
+        "co": {
+          "version": "4.6.0",
+          "bundled": true,
+          "optional": true
+        },
+        "code-point-at": {
+          "version": "1.1.0",
+          "bundled": true
+        },
+        "combined-stream": {
+          "version": "1.0.5",
+          "bundled": true,
+          "requires": {
+            "delayed-stream": "1.0.0"
+          }
+        },
+        "concat-map": {
+          "version": "0.0.1",
+          "bundled": true
+        },
+        "console-control-strings": {
+          "version": "1.1.0",
+          "bundled": true
+        },
+        "core-util-is": {
+          "version": "1.0.2",
+          "bundled": true
+        },
+        "cryptiles": {
+          "version": "2.0.5",
+          "bundled": true,
+          "requires": {
+            "boom": "2.10.1"
+          }
+        },
+        "dashdash": {
+          "version": "1.14.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "assert-plus": "1.0.0"
+          },
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true,
+              "optional": true
+            }
+          }
+        },
+        "debug": {
+          "version": "2.6.8",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "deep-extend": {
+          "version": "0.4.2",
+          "bundled": true,
+          "optional": true
+        },
+        "delayed-stream": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "delegates": {
+          "version": "1.0.0",
+          "bundled": true,
+          "optional": true
+        },
+        "detect-libc": {
+          "version": "1.0.2",
+          "bundled": true,
+          "optional": true
+        },
+        "ecc-jsbn": {
+          "version": "0.1.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "jsbn": "0.1.1"
+          }
+        },
+        "extend": {
+          "version": "3.0.1",
+          "bundled": true,
+          "optional": true
+        },
+        "extsprintf": {
+          "version": "1.0.2",
+          "bundled": true
+        },
+        "forever-agent": {
+          "version": "0.6.1",
+          "bundled": true,
+          "optional": true
+        },
+        "form-data": {
+          "version": "2.1.4",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "asynckit": "0.4.0",
+            "combined-stream": "1.0.5",
+            "mime-types": "2.1.15"
+          }
+        },
+        "fs.realpath": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "fstream": {
+          "version": "1.0.11",
+          "bundled": true,
+          "requires": {
+            "graceful-fs": "4.1.11",
+            "inherits": "2.0.3",
+            "mkdirp": "0.5.1",
+            "rimraf": "2.6.1"
+          }
+        },
+        "fstream-ignore": {
+          "version": "1.0.5",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "fstream": "1.0.11",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4"
+          }
+        },
+        "gauge": {
+          "version": "2.7.4",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "aproba": "1.1.1",
+            "console-control-strings": "1.1.0",
+            "has-unicode": "2.0.1",
+            "object-assign": "4.1.1",
+            "signal-exit": "3.0.2",
+            "string-width": "1.0.2",
+            "strip-ansi": "3.0.1",
+            "wide-align": "1.1.2"
+          }
+        },
+        "getpass": {
+          "version": "0.1.7",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "assert-plus": "1.0.0"
+          },
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true,
+              "optional": true
+            }
+          }
+        },
+        "glob": {
+          "version": "7.1.2",
+          "bundled": true,
+          "requires": {
+            "fs.realpath": "1.0.0",
+            "inflight": "1.0.6",
+            "inherits": "2.0.3",
+            "minimatch": "3.0.4",
+            "once": "1.4.0",
+            "path-is-absolute": "1.0.1"
+          }
+        },
+        "graceful-fs": {
+          "version": "4.1.11",
+          "bundled": true
+        },
+        "har-schema": {
+          "version": "1.0.5",
+          "bundled": true,
+          "optional": true
+        },
+        "har-validator": {
+          "version": "4.2.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "ajv": "4.11.8",
+            "har-schema": "1.0.5"
+          }
+        },
+        "has-unicode": {
+          "version": "2.0.1",
+          "bundled": true,
+          "optional": true
+        },
+        "hawk": {
+          "version": "3.1.3",
+          "bundled": true,
+          "requires": {
+            "boom": "2.10.1",
+            "cryptiles": "2.0.5",
+            "hoek": "2.16.3",
+            "sntp": "1.0.9"
+          }
+        },
+        "hoek": {
+          "version": "2.16.3",
+          "bundled": true
+        },
+        "http-signature": {
+          "version": "1.1.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "assert-plus": "0.2.0",
+            "jsprim": "1.4.0",
+            "sshpk": "1.13.0"
+          }
+        },
+        "inflight": {
+          "version": "1.0.6",
+          "bundled": true,
+          "requires": {
+            "once": "1.4.0",
+            "wrappy": "1.0.2"
+          }
+        },
+        "inherits": {
+          "version": "2.0.3",
+          "bundled": true
+        },
+        "ini": {
+          "version": "1.3.4",
+          "bundled": true,
+          "optional": true
+        },
+        "is-fullwidth-code-point": {
+          "version": "1.0.0",
+          "bundled": true,
+          "requires": {
+            "number-is-nan": "1.0.1"
+          }
+        },
+        "is-typedarray": {
+          "version": "1.0.0",
+          "bundled": true,
+          "optional": true
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "bundled": true
+        },
+        "isstream": {
+          "version": "0.1.2",
+          "bundled": true,
+          "optional": true
+        },
+        "jodid25519": {
+          "version": "1.0.2",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "jsbn": "0.1.1"
+          }
+        },
+        "jsbn": {
+          "version": "0.1.1",
+          "bundled": true,
+          "optional": true
+        },
+        "json-schema": {
+          "version": "0.2.3",
+          "bundled": true,
+          "optional": true
+        },
+        "json-stable-stringify": {
+          "version": "1.0.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "jsonify": "0.0.0"
+          }
+        },
+        "json-stringify-safe": {
+          "version": "5.0.1",
+          "bundled": true,
+          "optional": true
+        },
+        "jsonify": {
+          "version": "0.0.0",
+          "bundled": true,
+          "optional": true
+        },
+        "jsprim": {
+          "version": "1.4.0",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "assert-plus": "1.0.0",
+            "extsprintf": "1.0.2",
+            "json-schema": "0.2.3",
+            "verror": "1.3.6"
+          },
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true,
+              "optional": true
+            }
+          }
+        },
+        "mime-db": {
+          "version": "1.27.0",
+          "bundled": true
+        },
+        "mime-types": {
+          "version": "2.1.15",
+          "bundled": true,
+          "requires": {
+            "mime-db": "1.27.0"
+          }
+        },
+        "minimatch": {
+          "version": "3.0.4",
+          "bundled": true,
+          "requires": {
+            "brace-expansion": "1.1.7"
+          }
+        },
+        "minimist": {
+          "version": "0.0.8",
+          "bundled": true
+        },
+        "mkdirp": {
+          "version": "0.5.1",
+          "bundled": true,
+          "requires": {
+            "minimist": "0.0.8"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "bundled": true,
+          "optional": true
+        },
+        "node-pre-gyp": {
+          "version": "0.6.39",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "detect-libc": "1.0.2",
+            "hawk": "3.1.3",
+            "mkdirp": "0.5.1",
+            "nopt": "4.0.1",
+            "npmlog": "4.1.0",
+            "rc": "1.2.1",
+            "request": "2.81.0",
+            "rimraf": "2.6.1",
+            "semver": "5.3.0",
+            "tar": "2.2.1",
+            "tar-pack": "3.4.0"
+          }
+        },
+        "nopt": {
+          "version": "4.0.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "abbrev": "1.1.0",
+            "osenv": "0.1.4"
+          }
+        },
+        "npmlog": {
+          "version": "4.1.0",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "are-we-there-yet": "1.1.4",
+            "console-control-strings": "1.1.0",
+            "gauge": "2.7.4",
+            "set-blocking": "2.0.0"
+          }
+        },
+        "number-is-nan": {
+          "version": "1.0.1",
+          "bundled": true
+        },
+        "oauth-sign": {
+          "version": "0.8.2",
+          "bundled": true,
+          "optional": true
+        },
+        "object-assign": {
+          "version": "4.1.1",
+          "bundled": true,
+          "optional": true
+        },
+        "once": {
+          "version": "1.4.0",
+          "bundled": true,
+          "requires": {
+            "wrappy": "1.0.2"
+          }
+        },
+        "os-homedir": {
+          "version": "1.0.2",
+          "bundled": true,
+          "optional": true
+        },
+        "os-tmpdir": {
+          "version": "1.0.2",
+          "bundled": true,
+          "optional": true
+        },
+        "osenv": {
+          "version": "0.1.4",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "os-homedir": "1.0.2",
+            "os-tmpdir": "1.0.2"
+          }
+        },
+        "path-is-absolute": {
+          "version": "1.0.1",
+          "bundled": true
+        },
+        "performance-now": {
+          "version": "0.2.0",
+          "bundled": true,
+          "optional": true
+        },
+        "process-nextick-args": {
+          "version": "1.0.7",
+          "bundled": true
+        },
+        "punycode": {
+          "version": "1.4.1",
+          "bundled": true,
+          "optional": true
+        },
+        "qs": {
+          "version": "6.4.0",
+          "bundled": true,
+          "optional": true
+        },
+        "rc": {
+          "version": "1.2.1",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "deep-extend": "0.4.2",
+            "ini": "1.3.4",
+            "minimist": "1.2.0",
+            "strip-json-comments": "2.0.1"
+          },
+          "dependencies": {
+            "minimist": {
+              "version": "1.2.0",
+              "bundled": true,
+              "optional": true
+            }
+          }
+        },
+        "readable-stream": {
+          "version": "2.2.9",
+          "bundled": true,
+          "requires": {
+            "buffer-shims": "1.0.0",
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "1.0.0",
+            "process-nextick-args": "1.0.7",
+            "string_decoder": "1.0.1",
+            "util-deprecate": "1.0.2"
+          }
+        },
+        "request": {
+          "version": "2.81.0",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "aws-sign2": "0.6.0",
+            "aws4": "1.6.0",
+            "caseless": "0.12.0",
+            "combined-stream": "1.0.5",
+            "extend": "3.0.1",
+            "forever-agent": "0.6.1",
+            "form-data": "2.1.4",
+            "har-validator": "4.2.1",
+            "hawk": "3.1.3",
+            "http-signature": "1.1.1",
+            "is-typedarray": "1.0.0",
+            "isstream": "0.1.2",
+            "json-stringify-safe": "5.0.1",
+            "mime-types": "2.1.15",
+            "oauth-sign": "0.8.2",
+            "performance-now": "0.2.0",
+            "qs": "6.4.0",
+            "safe-buffer": "5.0.1",
+            "stringstream": "0.0.5",
+            "tough-cookie": "2.3.2",
+            "tunnel-agent": "0.6.0",
+            "uuid": "3.0.1"
+          }
+        },
+        "rimraf": {
+          "version": "2.6.1",
+          "bundled": true,
+          "requires": {
+            "glob": "7.1.2"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.0.1",
+          "bundled": true
+        },
+        "semver": {
+          "version": "5.3.0",
+          "bundled": true,
+          "optional": true
+        },
+        "set-blocking": {
+          "version": "2.0.0",
+          "bundled": true,
+          "optional": true
+        },
+        "signal-exit": {
+          "version": "3.0.2",
+          "bundled": true,
+          "optional": true
+        },
+        "sntp": {
+          "version": "1.0.9",
+          "bundled": true,
+          "requires": {
+            "hoek": "2.16.3"
+          }
+        },
+        "sshpk": {
+          "version": "1.13.0",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "asn1": "0.2.3",
+            "assert-plus": "1.0.0",
+            "bcrypt-pbkdf": "1.0.1",
+            "dashdash": "1.14.1",
+            "ecc-jsbn": "0.1.1",
+            "getpass": "0.1.7",
+            "jodid25519": "1.0.2",
+            "jsbn": "0.1.1",
+            "tweetnacl": "0.14.5"
+          },
+          "dependencies": {
+            "assert-plus": {
+              "version": "1.0.0",
+              "bundled": true,
+              "optional": true
+            }
+          }
+        },
+        "string-width": {
+          "version": "1.0.2",
+          "bundled": true,
+          "requires": {
+            "code-point-at": "1.1.0",
+            "is-fullwidth-code-point": "1.0.0",
+            "strip-ansi": "3.0.1"
+          }
+        },
+        "string_decoder": {
+          "version": "1.0.1",
+          "bundled": true,
+          "requires": {
+            "safe-buffer": "5.0.1"
+          }
+        },
+        "stringstream": {
+          "version": "0.0.5",
+          "bundled": true,
+          "optional": true
+        },
+        "strip-ansi": {
+          "version": "3.0.1",
+          "bundled": true,
+          "requires": {
+            "ansi-regex": "2.1.1"
+          }
+        },
+        "strip-json-comments": {
+          "version": "2.0.1",
+          "bundled": true,
+          "optional": true
+        },
+        "tar": {
+          "version": "2.2.1",
+          "bundled": true,
+          "requires": {
+            "block-stream": "0.0.9",
+            "fstream": "1.0.11",
+            "inherits": "2.0.3"
+          }
+        },
+        "tar-pack": {
+          "version": "3.4.0",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "debug": "2.6.8",
+            "fstream": "1.0.11",
+            "fstream-ignore": "1.0.5",
+            "once": "1.4.0",
+            "readable-stream": "2.2.9",
+            "rimraf": "2.6.1",
+            "tar": "2.2.1",
+            "uid-number": "0.0.6"
+          }
+        },
+        "tough-cookie": {
+          "version": "2.3.2",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "punycode": "1.4.1"
+          }
+        },
+        "tunnel-agent": {
+          "version": "0.6.0",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "safe-buffer": "5.0.1"
+          }
+        },
+        "tweetnacl": {
+          "version": "0.14.5",
+          "bundled": true,
+          "optional": true
+        },
+        "uid-number": {
+          "version": "0.0.6",
+          "bundled": true,
+          "optional": true
+        },
+        "util-deprecate": {
+          "version": "1.0.2",
+          "bundled": true
+        },
+        "uuid": {
+          "version": "3.0.1",
+          "bundled": true,
+          "optional": true
+        },
+        "verror": {
+          "version": "1.3.6",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "extsprintf": "1.0.2"
+          }
+        },
+        "wide-align": {
+          "version": "1.1.2",
+          "bundled": true,
+          "optional": true,
+          "requires": {
+            "string-width": "1.0.2"
+          }
+        },
+        "wrappy": {
+          "version": "1.0.2",
+          "bundled": true
+        }
+      }
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+    },
+    "garnish": {
+      "version": "5.2.0",
+      "resolved": "https://registry.npmjs.org/garnish/-/garnish-5.2.0.tgz",
+      "integrity": "sha1-vtQ2WTguSxmOM8eTiXvnxwHmVXc=",
+      "requires": {
+        "chalk": "0.5.1",
+        "minimist": "1.2.0",
+        "pad-left": "2.1.0",
+        "pad-right": "0.2.2",
+        "prettier-bytes": "1.0.4",
+        "pretty-ms": "2.1.0",
+        "right-now": "1.0.0",
+        "split2": "0.2.1",
+        "stdout-stream": "1.4.0",
+        "url-trim": "1.0.0"
+      },
+      "dependencies": {
+        "ansi-regex": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz",
+          "integrity": "sha1-DY6UaWej2BQ/k+JOKYUl/BsiNfk="
+        },
+        "ansi-styles": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz",
+          "integrity": "sha1-6uy/Zs1waIJ2Cy9GkVgrj1XXp94="
+        },
+        "chalk": {
+          "version": "0.5.1",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz",
+          "integrity": "sha1-Zjs6ZItotV0EaQ1JFnqoN4WPIXQ=",
+          "requires": {
+            "ansi-styles": "1.1.0",
+            "escape-string-regexp": "1.0.5",
+            "has-ansi": "0.1.0",
+            "strip-ansi": "0.3.0",
+            "supports-color": "0.2.0"
+          }
+        },
+        "has-ansi": {
+          "version": "0.1.0",
+          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz",
+          "integrity": "sha1-hPJlqujA5qiKEtcCKJS3VoiUxi4=",
+          "requires": {
+            "ansi-regex": "0.2.1"
+          }
+        },
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+        },
+        "strip-ansi": {
+          "version": "0.3.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz",
+          "integrity": "sha1-JfSOoiynkYfzF0pNuHWTR7sSYiA=",
+          "requires": {
+            "ansi-regex": "0.2.1"
+          }
+        },
+        "supports-color": {
+          "version": "0.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz",
+          "integrity": "sha1-2S3iaU6z9nMjlz1649i1W0wiGQo="
+        }
+      }
+    },
+    "get-ports": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/get-ports/-/get-ports-1.0.3.tgz",
+      "integrity": "sha1-9AvVgKyn7A77e5bL/L6wPviUteg=",
+      "requires": {
+        "map-limit": "0.0.1"
+      }
+    },
+    "get-stream": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz",
+      "integrity": "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+    },
+    "glob": {
+      "version": "7.1.2",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
+      "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
+      "requires": {
+        "fs.realpath": "1.0.0",
+        "inflight": "1.0.6",
+        "inherits": "2.0.3",
+        "minimatch": "3.0.4",
+        "once": "1.4.0",
+        "path-is-absolute": "1.0.1"
+      }
+    },
+    "glob-base": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
+      "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
+      "requires": {
+        "glob-parent": "2.0.0",
+        "is-glob": "2.0.1"
+      }
+    },
+    "glob-parent": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
+      "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
+      "requires": {
+        "is-glob": "2.0.1"
+      }
+    },
+    "globals": {
+      "version": "9.18.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
+      "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
+      "dev": true
+    },
+    "graceful-fs": {
+      "version": "4.1.11",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+      "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
+    },
+    "has": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz",
+      "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=",
+      "requires": {
+        "function-bind": "1.1.1"
+      }
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
+      "dev": true,
+      "requires": {
+        "ansi-regex": "2.1.1"
+      }
+    },
+    "hash-base": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
+      "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=",
+      "requires": {
+        "inherits": "2.0.3"
+      }
+    },
+    "hash.js": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
+      "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
+      "requires": {
+        "inherits": "2.0.3",
+        "minimalistic-assert": "1.0.0"
+      }
+    },
+    "hmac-drbg": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
+      "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
+      "requires": {
+        "hash.js": "1.1.3",
+        "minimalistic-assert": "1.0.0",
+        "minimalistic-crypto-utils": "1.0.1"
+      }
+    },
+    "home-or-tmp": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
+      "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
+      "dev": true,
+      "requires": {
+        "os-homedir": "1.0.2",
+        "os-tmpdir": "1.0.2"
+      }
+    },
+    "htmlescape": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz",
+      "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E="
+    },
+    "http-errors": {
+      "version": "1.6.2",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
+      "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
+      "requires": {
+        "depd": "1.1.1",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.0.3",
+        "statuses": "1.4.0"
+      },
+      "dependencies": {
+        "depd": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
+          "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
+        }
+      }
+    },
+    "https-browserify": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
+      "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM="
+    },
+    "iconv-lite": {
+      "version": "0.4.19",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz",
+      "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ=="
+    },
+    "ieee754": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
+      "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q="
+    },
+    "indexof": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
+      "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
+    },
+    "individual": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/individual/-/individual-3.0.0.tgz",
+      "integrity": "sha1-58pPhfiVewGHNPKFdQ3CLsL5hi0="
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "requires": {
+        "once": "1.4.0",
+        "wrappy": "1.0.2"
+      }
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+    },
+    "inject-lr-script": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/inject-lr-script/-/inject-lr-script-2.1.0.tgz",
+      "integrity": "sha1-5htehMEYczkGy+oB7D10Zpijn2U=",
+      "requires": {
+        "resp-modifier": "6.0.2"
+      }
+    },
+    "inline-source-map": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz",
+      "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=",
+      "requires": {
+        "source-map": "0.5.7"
+      }
+    },
+    "insert-module-globals": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.0.1.tgz",
+      "integrity": "sha1-wDv04BywhtW15azorQr+eInWOMM=",
+      "requires": {
+        "JSONStream": "1.3.2",
+        "combine-source-map": "0.7.2",
+        "concat-stream": "1.5.2",
+        "is-buffer": "1.1.6",
+        "lexical-scope": "1.2.0",
+        "process": "0.11.10",
+        "through2": "2.0.3",
+        "xtend": "4.0.1"
+      },
+      "dependencies": {
+        "combine-source-map": {
+          "version": "0.7.2",
+          "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.7.2.tgz",
+          "integrity": "sha1-CHAxKFazB6h8xKxIbzqaYq7MwJ4=",
+          "requires": {
+            "convert-source-map": "1.1.3",
+            "inline-source-map": "0.6.2",
+            "lodash.memoize": "3.0.4",
+            "source-map": "0.5.7"
+          }
+        },
+        "convert-source-map": {
+          "version": "1.1.3",
+          "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz",
+          "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA="
+        }
+      }
+    },
+    "internal-ip": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-3.0.1.tgz",
+      "integrity": "sha512-NXXgESC2nNVtU+pqmC9e6R8B1GpKxzsAQhffvh5AL79qKnodd+L7tnEQmTiUAVngqLalPbSqRA7XGIEL5nCd0Q==",
+      "requires": {
+        "default-gateway": "2.7.0",
+        "ipaddr.js": "1.6.0"
+      }
+    },
+    "invariant": {
+      "version": "2.2.3",
+      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.3.tgz",
+      "integrity": "sha512-7Z5PPegwDTyjbaeCnV0efcyS6vdKAU51kpEmS7QFib3P4822l8ICYyMn7qvJnc+WzLoDsuI9gPMKbJ8pCu8XtA==",
+      "dev": true,
+      "requires": {
+        "loose-envify": "1.3.1"
+      }
+    },
+    "ip-regex": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz",
+      "integrity": "sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk="
+    },
+    "ipaddr.js": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.6.0.tgz",
+      "integrity": "sha1-4/o1e3c9phnybpXwSdBVxyeW+Gs="
+    },
+    "is-binary-path": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
+      "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
+      "requires": {
+        "binary-extensions": "1.11.0"
+      }
+    },
+    "is-buffer": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
+      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
+    },
+    "is-dotfile": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
+      "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE="
+    },
+    "is-equal-shallow": {
+      "version": "0.1.3",
+      "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
+      "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
+      "requires": {
+        "is-primitive": "2.0.0"
+      }
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
+      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
+    },
+    "is-extglob": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
+      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
+    },
+    "is-finite": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
+      "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
+      "requires": {
+        "number-is-nan": "1.0.1"
+      }
+    },
+    "is-glob": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
+      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
+      "requires": {
+        "is-extglob": "1.0.0"
+      }
+    },
+    "is-number": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
+      "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
+      "requires": {
+        "kind-of": "3.2.2"
+      }
+    },
+    "is-posix-bracket": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
+      "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q="
+    },
+    "is-primitive": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
+      "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU="
+    },
+    "is-stream": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
+      "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+    },
+    "isarray": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+      "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+    },
+    "isexe": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+    },
+    "isobject": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+      "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
+      "requires": {
+        "isarray": "1.0.0"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+        }
+      }
+    },
+    "js-tokens": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
+      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
+      "dev": true
+    },
+    "jsesc": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
+      "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
+      "dev": true
+    },
+    "json-stable-stringify": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz",
+      "integrity": "sha1-YRwj6BTbN1Un34URk9tZ3Sryf0U=",
+      "requires": {
+        "jsonify": "0.0.0"
+      }
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
+      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+    },
+    "json5": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
+      "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
+      "dev": true
+    },
+    "jsonify": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
+      "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
+    },
+    "jsonparse": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
+      "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
+    },
+    "kind-of": {
+      "version": "3.2.2",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+      "requires": {
+        "is-buffer": "1.1.6"
+      }
+    },
+    "labeled-stream-splicer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz",
+      "integrity": "sha1-pS4dE4AkwAuGscDJH2d5GLiuClk=",
+      "requires": {
+        "inherits": "2.0.3",
+        "isarray": "0.0.1",
+        "stream-splicer": "2.0.0"
+      }
+    },
+    "lexical-scope": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/lexical-scope/-/lexical-scope-1.2.0.tgz",
+      "integrity": "sha1-/Ope3HBKSzqHls3KQZw6CvryLfQ=",
+      "requires": {
+        "astw": "2.2.0"
+      }
+    },
+    "lodash": {
+      "version": "4.17.5",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.5.tgz",
+      "integrity": "sha512-svL3uiZf1RwhH+cWrfZn3A4+U58wbP0tGVTLQPbjplZxZ8ROD9VLuNgsRniTlLe7OlSqR79RUehXgpBW/s0IQw==",
+      "dev": true
+    },
+    "lodash.memoize": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz",
+      "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8="
+    },
+    "loose-envify": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
+      "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
+      "dev": true,
+      "requires": {
+        "js-tokens": "3.0.2"
+      }
+    },
+    "lru-cache": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
+      "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
+      "requires": {
+        "pseudomap": "1.0.2",
+        "yallist": "2.1.2"
+      }
+    },
+    "map-limit": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/map-limit/-/map-limit-0.0.1.tgz",
+      "integrity": "sha1-63lhAxwPDo0AG/LVb6toXViCLzg=",
+      "requires": {
+        "once": "1.3.3"
+      },
+      "dependencies": {
+        "once": {
+          "version": "1.3.3",
+          "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz",
+          "integrity": "sha1-suJhVXzkwxTsgwTz+oJmPkKXyiA=",
+          "requires": {
+            "wrappy": "1.0.2"
+          }
+        }
+      }
+    },
+    "md5": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
+      "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=",
+      "requires": {
+        "charenc": "0.0.2",
+        "crypt": "0.0.2",
+        "is-buffer": "1.1.6"
+      }
+    },
+    "md5.js": {
+      "version": "1.3.4",
+      "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.4.tgz",
+      "integrity": "sha1-6b296UogpawYsENA/Fdk1bCdkB0=",
+      "requires": {
+        "hash-base": "3.0.4",
+        "inherits": "2.0.3"
+      },
+      "dependencies": {
+        "hash-base": {
+          "version": "3.0.4",
+          "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz",
+          "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=",
+          "requires": {
+            "inherits": "2.0.3",
+            "safe-buffer": "5.1.1"
+          }
+        }
+      }
+    },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+    },
+    "methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+    },
+    "micromatch": {
+      "version": "2.3.11",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
+      "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
+      "requires": {
+        "arr-diff": "2.0.0",
+        "array-unique": "0.2.1",
+        "braces": "1.8.5",
+        "expand-brackets": "0.1.5",
+        "extglob": "0.3.2",
+        "filename-regex": "2.0.1",
+        "is-extglob": "1.0.0",
+        "is-glob": "2.0.1",
+        "kind-of": "3.2.2",
+        "normalize-path": "2.1.1",
+        "object.omit": "2.0.1",
+        "parse-glob": "3.0.4",
+        "regex-cache": "0.4.4"
+      }
+    },
+    "miller-rabin": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
+      "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
+      "requires": {
+        "bn.js": "4.11.8",
+        "brorand": "1.1.0"
+      }
+    },
+    "mime": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz",
+      "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
+    },
+    "mime-db": {
+      "version": "1.33.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.33.0.tgz",
+      "integrity": "sha512-BHJ/EKruNIqJf/QahvxwQZXKygOQ256myeN/Ew+THcAa5q+PjyTTMMeNQC4DZw5AwfvelsUrA6B67NKMqXDbzQ=="
+    },
+    "mime-types": {
+      "version": "2.1.18",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.18.tgz",
+      "integrity": "sha512-lc/aahn+t4/SWV/qcmumYjymLsWfN3ELhpmVuUFjgsORruuZPVSwAQryq+HHGvO/SI2KVX26bx+En+zhM8g8hQ==",
+      "requires": {
+        "mime-db": "1.33.0"
+      }
+    },
+    "minimalistic-assert": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
+      "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M="
+    },
+    "minimalistic-crypto-utils": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
+      "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo="
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "requires": {
+        "brace-expansion": "1.1.11"
+      }
+    },
+    "minimist": {
+      "version": "0.0.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
+      "requires": {
+        "minimist": "0.0.8"
+      }
+    },
+    "module-deps": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-5.0.1.tgz",
+      "integrity": "sha512-sigq/hm/L+Z5IGi1DDl0x2ptkw7S86aFh213QhPLD8v9Opv90IHzKIuWJrRa5bJ77DVKHco2CfIEuThcT/vDJA==",
+      "requires": {
+        "JSONStream": "1.3.2",
+        "browser-resolve": "1.11.2",
+        "cached-path-relative": "1.0.1",
+        "concat-stream": "1.6.0",
+        "defined": "1.0.0",
+        "detective": "5.0.2",
+        "duplexer2": "0.1.4",
+        "inherits": "2.0.3",
+        "parents": "1.0.1",
+        "readable-stream": "2.3.4",
+        "resolve": "1.5.0",
+        "stream-combiner2": "1.1.1",
+        "subarg": "1.0.0",
+        "through2": "2.0.3",
+        "xtend": "4.0.1"
+      },
+      "dependencies": {
+        "concat-stream": {
+          "version": "1.6.0",
+          "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz",
+          "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=",
+          "requires": {
+            "inherits": "2.0.3",
+            "readable-stream": "2.3.4",
+            "typedarray": "0.0.6"
+          }
+        }
+      }
+    },
+    "ms": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+    },
+    "nan": {
+      "version": "2.9.2",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.9.2.tgz",
+      "integrity": "sha512-ltW65co7f3PQWBDbqVvaU1WtFJUsNW7sWWm4HINhbMQIyVyzIeyZ8toX5TC5eeooE6piZoaEh4cZkueSKG3KYw==",
+      "optional": true
+    },
+    "normalize-path": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
+      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
+      "requires": {
+        "remove-trailing-separator": "1.1.0"
+      }
+    },
+    "npm-run-path": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
+      "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
+      "requires": {
+        "path-key": "2.0.1"
+      }
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+    },
+    "object-keys": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz",
+      "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=",
+      "dev": true
+    },
+    "object.omit": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
+      "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
+      "requires": {
+        "for-own": "0.1.5",
+        "is-extendable": "0.1.1"
+      }
+    },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
+    "on-headers": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
+      "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "requires": {
+        "wrappy": "1.0.2"
+      }
+    },
+    "opn": {
+      "version": "3.0.3",
+      "resolved": "https://registry.npmjs.org/opn/-/opn-3.0.3.tgz",
+      "integrity": "sha1-ttmec5n3jWXDuq/+8fsojpuFJDo=",
+      "requires": {
+        "object-assign": "4.1.1"
+      }
+    },
+    "options": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz",
+      "integrity": "sha1-7CLTEoBrtT5zF3Pnza788cZDEo8="
+    },
+    "os-browserify": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
+      "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc="
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
+      "dev": true
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+    },
+    "outpipe": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/outpipe/-/outpipe-1.1.1.tgz",
+      "integrity": "sha1-UM+GFjZeh+Ax4ppeyTOaPaRyX6I=",
+      "requires": {
+        "shell-quote": "1.6.1"
+      }
+    },
+    "p-finally": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
+      "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+    },
+    "pad-left": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pad-left/-/pad-left-2.1.0.tgz",
+      "integrity": "sha1-FuajstRKjhOMsIOMx8tAOk/J6ZQ=",
+      "requires": {
+        "repeat-string": "1.6.1"
+      }
+    },
+    "pad-right": {
+      "version": "0.2.2",
+      "resolved": "https://registry.npmjs.org/pad-right/-/pad-right-0.2.2.tgz",
+      "integrity": "sha1-b7ySQEXSRPKiokRQMGDTv8YAl3Q=",
+      "requires": {
+        "repeat-string": "1.6.1"
+      }
+    },
+    "pako": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.6.tgz",
+      "integrity": "sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg=="
+    },
+    "parents": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz",
+      "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=",
+      "requires": {
+        "path-platform": "0.11.15"
+      }
+    },
+    "parse-asn1": {
+      "version": "5.1.0",
+      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz",
+      "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=",
+      "requires": {
+        "asn1.js": "4.10.1",
+        "browserify-aes": "1.1.1",
+        "create-hash": "1.1.3",
+        "evp_bytestokey": "1.0.3",
+        "pbkdf2": "3.0.14"
+      }
+    },
+    "parse-glob": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
+      "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
+      "requires": {
+        "glob-base": "0.3.0",
+        "is-dotfile": "1.0.3",
+        "is-extglob": "1.0.0",
+        "is-glob": "2.0.1"
+      }
+    },
+    "parse-ms": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz",
+      "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0="
+    },
+    "parseurl": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.2.tgz",
+      "integrity": "sha1-/CidTtiZMRlGDBViUyYs3I3mW/M="
+    },
+    "path-browserify": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
+      "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo="
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+    },
+    "path-key": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
+      "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A="
+    },
+    "path-parse": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz",
+      "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME="
+    },
+    "path-platform": {
+      "version": "0.11.15",
+      "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz",
+      "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I="
+    },
+    "path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+    },
+    "pbkdf2": {
+      "version": "3.0.14",
+      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.14.tgz",
+      "integrity": "sha512-gjsZW9O34fm0R7PaLHRJmLLVfSoesxztjPjE9o6R+qtVJij90ltg1joIovN9GKrRW3t1PzhDDG3UMEMFfZ+1wA==",
+      "requires": {
+        "create-hash": "1.1.3",
+        "create-hmac": "1.1.6",
+        "ripemd160": "2.0.1",
+        "safe-buffer": "5.1.1",
+        "sha.js": "2.4.10"
+      }
+    },
+    "pem": {
+      "version": "1.12.3",
+      "resolved": "https://registry.npmjs.org/pem/-/pem-1.12.3.tgz",
+      "integrity": "sha512-hT7GwvQL35+0iqgYUl8vn5I5pAVR0HcJas07TXL8bNaR4c5kAFRquk4ZqQk1F9YMcQOr6WjGdY5OnDC0RBnzig==",
+      "requires": {
+        "md5": "2.2.1",
+        "os-tmpdir": "1.0.2",
+        "safe-buffer": "5.1.1",
+        "which": "1.3.0"
+      }
+    },
+    "plur": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz",
+      "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY="
+    },
+    "preserve": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
+      "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
+    },
+    "prettier-bytes": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/prettier-bytes/-/prettier-bytes-1.0.4.tgz",
+      "integrity": "sha1-mUsCqkb2mcULYle1+qp/4lV+YtY="
+    },
+    "pretty-ms": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz",
+      "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=",
+      "requires": {
+        "is-finite": "1.0.2",
+        "parse-ms": "1.0.1",
+        "plur": "1.0.0"
+      }
+    },
+    "private": {
+      "version": "0.1.8",
+      "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
+      "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==",
+      "dev": true
+    },
+    "process": {
+      "version": "0.11.10",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+      "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI="
+    },
+    "process-nextick-args": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+      "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw=="
+    },
+    "pseudomap": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
+      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
+    },
+    "public-encrypt": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz",
+      "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=",
+      "requires": {
+        "bn.js": "4.11.8",
+        "browserify-rsa": "4.0.1",
+        "create-hash": "1.1.3",
+        "parse-asn1": "5.1.0",
+        "randombytes": "2.0.6"
+      }
+    },
+    "punycode": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
+      "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0="
+    },
+    "qs": {
+      "version": "6.5.1",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
+      "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
+    },
+    "query-string": {
+      "version": "4.3.4",
+      "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
+      "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
+      "requires": {
+        "object-assign": "4.1.1",
+        "strict-uri-encode": "1.1.0"
+      }
+    },
+    "querystring": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
+      "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA="
+    },
+    "querystring-es3": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
+      "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM="
+    },
+    "randomatic": {
+      "version": "1.1.7",
+      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
+      "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
+      "requires": {
+        "is-number": "3.0.0",
+        "kind-of": "4.0.0"
+      },
+      "dependencies": {
+        "is-number": {
+          "version": "3.0.0",
+          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
+          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
+          "requires": {
+            "kind-of": "3.2.2"
+          },
+          "dependencies": {
+            "kind-of": {
+              "version": "3.2.2",
+              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
+              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
+              "requires": {
+                "is-buffer": "1.1.6"
+              }
+            }
+          }
+        },
+        "kind-of": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
+          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
+          "requires": {
+            "is-buffer": "1.1.6"
+          }
+        }
+      }
+    },
+    "randombytes": {
+      "version": "2.0.6",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.6.tgz",
+      "integrity": "sha512-CIQ5OFxf4Jou6uOKe9t1AOgqpeU5fd70A8NPdHSGeYXqXsPe6peOwI0cUl88RWZ6sP1vPMV3avd/R6cZ5/sP1A==",
+      "requires": {
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "randomfill": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
+      "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
+      "requires": {
+        "randombytes": "2.0.6",
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "range-parser": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
+      "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
+    },
+    "raw-body": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.3.2.tgz",
+      "integrity": "sha1-vNYMd9Prk83gBQKVw/N5OJvIj4k=",
+      "requires": {
+        "bytes": "3.0.0",
+        "http-errors": "1.6.2",
+        "iconv-lite": "0.4.19",
+        "unpipe": "1.0.0"
+      }
+    },
+    "read-only-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz",
+      "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=",
+      "requires": {
+        "readable-stream": "2.3.4"
+      }
+    },
+    "readable-stream": {
+      "version": "2.3.4",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.4.tgz",
+      "integrity": "sha512-vuYxeWYM+fde14+rajzqgeohAI7YoJcHE7kXDAc4Nk0EbuKnJfqtY9YtRkLo/tqkuF7MsBQRhPnPeyjYITp3ZQ==",
+      "requires": {
+        "core-util-is": "1.0.2",
+        "inherits": "2.0.3",
+        "isarray": "1.0.0",
+        "process-nextick-args": "2.0.0",
+        "safe-buffer": "5.1.1",
+        "string_decoder": "1.0.3",
+        "util-deprecate": "1.0.2"
+      },
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+        }
+      }
+    },
+    "readdirp": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
+      "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
+      "requires": {
+        "graceful-fs": "4.1.11",
+        "minimatch": "3.0.4",
+        "readable-stream": "2.3.4",
+        "set-immediate-shim": "1.0.1"
+      }
+    },
+    "regenerator-runtime": {
+      "version": "0.11.1",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
+      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==",
+      "dev": true
+    },
+    "regex-cache": {
+      "version": "0.4.4",
+      "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
+      "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
+      "requires": {
+        "is-equal-shallow": "0.1.3"
+      }
+    },
+    "reload-css": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/reload-css/-/reload-css-1.0.2.tgz",
+      "integrity": "sha1-avsRFi4jFP7M2tbcX96CH9cxgzE=",
+      "requires": {
+        "query-string": "4.3.4"
+      }
+    },
+    "remove-trailing-separator": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
+    },
+    "repeat-element": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
+      "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo="
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
+      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
+    },
+    "repeating": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
+      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
+      "dev": true,
+      "requires": {
+        "is-finite": "1.0.2"
+      }
+    },
+    "resolve": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz",
+      "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==",
+      "requires": {
+        "path-parse": "1.0.5"
+      }
+    },
+    "resp-modifier": {
+      "version": "6.0.2",
+      "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz",
+      "integrity": "sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08=",
+      "requires": {
+        "debug": "2.6.9",
+        "minimatch": "3.0.4"
+      }
+    },
+    "right-now": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/right-now/-/right-now-1.0.0.tgz",
+      "integrity": "sha1-bolgne69fc2vja7Mmuo5z1haCRg="
+    },
+    "ripemd160": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
+      "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=",
+      "requires": {
+        "hash-base": "2.0.2",
+        "inherits": "2.0.3"
+      }
+    },
+    "router": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/router/-/router-1.3.2.tgz",
+      "integrity": "sha1-v6oWiIpSg9XuQNmZ2nqfoVKWpgw=",
+      "requires": {
+        "array-flatten": "2.1.1",
+        "debug": "2.6.9",
+        "methods": "1.1.2",
+        "parseurl": "1.3.2",
+        "path-to-regexp": "0.1.7",
+        "setprototypeof": "1.1.0",
+        "utils-merge": "1.0.1"
+      },
+      "dependencies": {
+        "array-flatten": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.1.tgz",
+          "integrity": "sha1-Qmu52oQJDBg42BLIFQryCoMx4pY="
+        },
+        "setprototypeof": {
+          "version": "1.1.0",
+          "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
+          "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
+        }
+      }
+    },
+    "safe-buffer": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
+      "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
+    },
+    "send": {
+      "version": "0.16.2",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz",
+      "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==",
+      "requires": {
+        "debug": "2.6.9",
+        "depd": "1.1.2",
+        "destroy": "1.0.4",
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "etag": "1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "1.6.2",
+        "mime": "1.4.1",
+        "ms": "2.0.0",
+        "on-finished": "2.3.0",
+        "range-parser": "1.2.0",
+        "statuses": "1.4.0"
+      }
+    },
+    "serve-static": {
+      "version": "1.13.2",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz",
+      "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==",
+      "requires": {
+        "encodeurl": "1.0.2",
+        "escape-html": "1.0.3",
+        "parseurl": "1.3.2",
+        "send": "0.16.2"
+      }
+    },
+    "set-immediate-shim": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
+      "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
+    },
+    "setprototypeof": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
+      "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
+    },
+    "sha.js": {
+      "version": "2.4.10",
+      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.10.tgz",
+      "integrity": "sha512-vnwmrFDlOExK4Nm16J2KMWHLrp14lBrjxMxBJpu++EnsuBmpiYaM/MEs46Vxxm/4FvdP5yTwuCTO9it5FSjrqA==",
+      "requires": {
+        "inherits": "2.0.3",
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "shasum": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/shasum/-/shasum-1.0.2.tgz",
+      "integrity": "sha1-5wEjENj0F/TetXEhUOVni4euVl8=",
+      "requires": {
+        "json-stable-stringify": "0.0.1",
+        "sha.js": "2.4.10"
+      }
+    },
+    "shebang-command": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
+      "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
+      "requires": {
+        "shebang-regex": "1.0.0"
+      }
+    },
+    "shebang-regex": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
+      "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+    },
+    "shell-quote": {
+      "version": "1.6.1",
+      "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.6.1.tgz",
+      "integrity": "sha1-9HgZSczkAmlxJ0MOo7PFR29IF2c=",
+      "requires": {
+        "array-filter": "0.0.1",
+        "array-map": "0.0.0",
+        "array-reduce": "0.0.0",
+        "jsonify": "0.0.0"
+      }
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
+    },
+    "simple-html-index": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/simple-html-index/-/simple-html-index-1.5.0.tgz",
+      "integrity": "sha1-LJPurrrAAdihNfwAIr1K3o9YmW8=",
+      "requires": {
+        "from2-string": "1.1.0"
+      }
+    },
+    "slash": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
+      "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
+      "dev": true
+    },
+    "source-map": {
+      "version": "0.5.7",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
+      "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+    },
+    "source-map-support": {
+      "version": "0.4.18",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
+      "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
+      "dev": true,
+      "requires": {
+        "source-map": "0.5.7"
+      }
+    },
+    "split2": {
+      "version": "0.2.1",
+      "resolved": "https://registry.npmjs.org/split2/-/split2-0.2.1.tgz",
+      "integrity": "sha1-At2smtwD7Au3jBKC7Aecpuha6QA=",
+      "requires": {
+        "through2": "0.6.5"
+      },
+      "dependencies": {
+        "readable-stream": {
+          "version": "1.0.34",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz",
+          "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=",
+          "requires": {
+            "core-util-is": "1.0.2",
+            "inherits": "2.0.3",
+            "isarray": "0.0.1",
+            "string_decoder": "0.10.31"
+          }
+        },
+        "string_decoder": {
+          "version": "0.10.31",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+        },
+        "through2": {
+          "version": "0.6.5",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz",
+          "integrity": "sha1-QaucZ7KdVyCQcUEOHXp6lozTrUg=",
+          "requires": {
+            "readable-stream": "1.0.34",
+            "xtend": "4.0.1"
+          }
+        }
+      }
+    },
+    "stacked": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stacked/-/stacked-1.1.1.tgz",
+      "integrity": "sha1-LH+jjMfjejQRp3zY55LeRI+faXU="
+    },
+    "statuses": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz",
+      "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
+    },
+    "stdout-stream": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz",
+      "integrity": "sha1-osfIWH5U2UJ+qe2zrD8s1SLfN4s=",
+      "requires": {
+        "readable-stream": "2.3.4"
+      }
+    },
+    "stream-browserify": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
+      "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
+      "requires": {
+        "inherits": "2.0.3",
+        "readable-stream": "2.3.4"
+      }
+    },
+    "stream-combiner2": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz",
+      "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=",
+      "requires": {
+        "duplexer2": "0.1.4",
+        "readable-stream": "2.3.4"
+      }
+    },
+    "stream-http": {
+      "version": "2.8.0",
+      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.0.tgz",
+      "integrity": "sha512-sZOFxI/5xw058XIRHl4dU3dZ+TTOIGJR78Dvo0oEAejIt4ou27k+3ne1zYmCV+v7UucbxIFQuOgnkTVHh8YPnw==",
+      "requires": {
+        "builtin-status-codes": "3.0.0",
+        "inherits": "2.0.3",
+        "readable-stream": "2.3.4",
+        "to-arraybuffer": "1.0.1",
+        "xtend": "4.0.1"
+      }
+    },
+    "stream-splicer": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.0.tgz",
+      "integrity": "sha1-G2O+Q4oTPktnHMGTUZdgAXWRDYM=",
+      "requires": {
+        "inherits": "2.0.3",
+        "readable-stream": "2.3.4"
+      }
+    },
+    "strict-uri-encode": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
+      "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM="
+    },
+    "string_decoder": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
+      "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
+      "requires": {
+        "safe-buffer": "5.1.1"
+      }
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
+      "requires": {
+        "ansi-regex": "2.1.1"
+      }
+    },
+    "strip-eof": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
+      "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8="
+    },
+    "subarg": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz",
+      "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=",
+      "requires": {
+        "minimist": "1.2.0"
+      },
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+          "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+        }
+      }
+    },
+    "supports-color": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=",
+      "dev": true
+    },
+    "syntax-error": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz",
+      "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==",
+      "requires": {
+        "acorn-node": "1.3.0"
+      }
+    },
+    "term-color": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/term-color/-/term-color-1.0.1.tgz",
+      "integrity": "sha1-OOGSVTpHPjXkFgT/UZmEa/gRejo=",
+      "requires": {
+        "ansi-styles": "2.0.1",
+        "supports-color": "1.3.1"
+      },
+      "dependencies": {
+        "ansi-styles": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.0.1.tgz",
+          "integrity": "sha1-sDP1f5Pi0oreuLwRE4+hPaD9IKM="
+        },
+        "supports-color": {
+          "version": "1.3.1",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.3.1.tgz",
+          "integrity": "sha1-FXWN8J2P87SswwdTn6vicJXhBC0="
+        }
+      }
+    },
+    "through": {
+      "version": "2.3.8",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+    },
+    "through2": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+      "integrity": "sha1-AARWmzfHx0ujnEPzzteNGtlBQL4=",
+      "requires": {
+        "readable-stream": "2.3.4",
+        "xtend": "4.0.1"
+      }
+    },
+    "timers-browserify": {
+      "version": "1.4.2",
+      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz",
+      "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=",
+      "requires": {
+        "process": "0.11.10"
+      }
+    },
+    "to-arraybuffer": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
+      "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M="
+    },
+    "to-fast-properties": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
+      "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
+      "dev": true
+    },
+    "trim-right": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
+      "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
+      "dev": true
+    },
+    "tty-browserify": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz",
+      "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw=="
+    },
+    "type-is": {
+      "version": "1.6.16",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.16.tgz",
+      "integrity": "sha512-HRkVv/5qY2G6I8iab9cI7v1bOIdhm94dVjQCPFElW9W+3GeDOSHmy2EBYe4VTApuzolPcmgFTN3ftVJRKR2J9Q==",
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "2.1.18"
+      }
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
+      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+    },
+    "ultron": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz",
+      "integrity": "sha1-rOEWq1V80Zc4ak6I9GhTeMiy5Po="
+    },
+    "umd": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.1.tgz",
+      "integrity": "sha1-iuVW4RAR9jwllnCKiDclnwGz1g4="
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+    },
+    "url-trim": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/url-trim/-/url-trim-1.0.0.tgz",
+      "integrity": "sha1-QAV+LxZLiOXaynJp2kfm0d2Detw="
+    },
+    "util": {
+      "version": "0.10.3",
+      "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+      "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
+      "requires": {
+        "inherits": "2.0.1"
+      },
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
+          "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE="
+        }
+      }
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+    },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+    },
+    "vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+    },
+    "vm-browserify": {
+      "version": "0.0.4",
+      "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
+      "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
+      "requires": {
+        "indexof": "0.0.1"
+      }
+    },
+    "watchify": {
+      "version": "3.10.0",
+      "resolved": "https://registry.npmjs.org/watchify/-/watchify-3.10.0.tgz",
+      "integrity": "sha512-SRSumWalHAxciSaEtua1HFqB8L+et5ieHjJRuNssqj4qXz4pJoR6cAeFWni3reXyOY3cVE6b55sJ8WYR43abBQ==",
+      "requires": {
+        "anymatch": "1.3.2",
+        "browserify": "15.2.0",
+        "chokidar": "1.7.0",
+        "defined": "1.0.0",
+        "outpipe": "1.1.1",
+        "through2": "2.0.3",
+        "xtend": "4.0.1"
+      }
+    },
+    "watchify-middleware": {
+      "version": "1.8.0",
+      "resolved": "https://registry.npmjs.org/watchify-middleware/-/watchify-middleware-1.8.0.tgz",
+      "integrity": "sha512-INYU5/3zTZtWQvJKPelr47j0JeLTZK4GUDF0PoMltMPzMUEh/lW6g1t+Qe/tGHxm70AUc0NQrth3k3PTfOU9Nw==",
+      "requires": {
+        "concat-stream": "1.5.2",
+        "debounce": "1.1.0",
+        "events": "1.1.1",
+        "object-assign": "4.1.1",
+        "strip-ansi": "3.0.1",
+        "watchify": "3.10.0"
+      }
+    },
+    "which": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
+      "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
+      "requires": {
+        "isexe": "2.0.0"
+      }
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+    },
+    "ws": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.5.tgz",
+      "integrity": "sha512-o3KqipXNUdS7wpQzBHSe180lBGO60SoK0yVo3CYJgb2MkobuWuBX6dhkYP5ORCLd55y+SaflMOV5fqAB53ux4w==",
+      "requires": {
+        "options": "0.0.6",
+        "ultron": "1.0.2"
+      }
+    },
+    "xtend": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
+      "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68="
+    },
+    "yallist": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
+      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
+    }
+  }
+}

+ 17 - 0
examples/digitalocean-spaces/package.json

@@ -0,0 +1,17 @@
+{
+  "private": true,
+  "name": "uppy-digitalocean-spaces",
+  "scripts": {
+    "start": "node ./server.js"
+  },
+  "devDependencies": {
+    "aliasify": "^2.1.0",
+    "babelify": "^7.3.0"
+  },
+  "dependencies": {
+    "body-parser": "^1.18.2",
+    "budo": "^11.1.7",
+    "cors": "^2.8.4",
+    "router": "^1.3.2"
+  }
+}

+ 19 - 0
examples/digitalocean-spaces/readme.md

@@ -0,0 +1,19 @@
+# Uploading to DigitalOcean Spaces
+
+This example uses Uppy to upload files to a DigitolOcean Space. DigitalOcean Spaces has an identical API to S3, so we can use the [AwsS3](https://uppy.io/docs/aws-s3) plugin. We use uppy-server with a [custom `endpoint` configuration](./server.js#L32-L33) that points to DigitalOcean.
+
+To try this example, first run:
+
+```bash
+npm install
+```
+
+Then configure some environment variables and run it:
+
+```bash
+UPPYSERVER_AWS_REGION=ams3 \
+UPPYSERVER_AWS_KEY=your_access_key_id \
+UPPYSERVER_AWS_SECRET=your_secret_access_key \
+UPPYSERVER_AWS_BUCKET=your_space_name \
+npm start
+```

+ 67 - 0
examples/digitalocean-spaces/server.js

@@ -0,0 +1,67 @@
+const fs = require('fs')
+const path = require('path')
+const budo = require('budo')
+const router = require('router')
+const uppy = require('uppy-server')
+
+/**
+ * Environment variables:
+ *
+ *   - UPPYSERVER_AWS_REGION - Your space region, eg "ams3"
+ *   - UPPYSERVER_AWS_KEY - Your access key ID
+ *   - UPPYSERVER_AWS_SECRET - Your secret access key
+ *   - UPPYSERVER_AWS_BUCKET - Your space's name.
+ */
+
+if (!process.env.UPPYSERVER_AWS_REGION) throw new Error('Missing Space region, please set the UPPYSERVER_AWS_REGION environment variable (eg. "UPPYSERVER_AWS_REGION=ams3")')
+if (!process.env.UPPYSERVER_AWS_KEY) throw new Error('Missing access key, please set the UPPYSERVER_AWS_KEY environment variable')
+if (!process.env.UPPYSERVER_AWS_SECRET) throw new Error('Missing secret key, please set the UPPYSERVER_AWS_SECRET environment variable')
+if (!process.env.UPPYSERVER_AWS_BUCKET) throw new Error('Missing Space name, please set the UPPYSERVER_AWS_BUCKET environment variable')
+
+// Prepare the server.
+const PORT = process.env.PORT || 3452
+
+const app = router()
+
+// Set up the /params endpoint that will create signed URLs for us.
+app.use(require('cors')())
+app.use(require('body-parser').json())
+app.use('/uppy-server', uppy.app({
+  providerOptions: {
+    s3: {
+      // This is the crucial part; set an endpoint template for the service you want to use.
+      endpoint: 'https://{region}.digitaloceanspaces.com',
+      getKey: (req, filename) => `uploads/${filename}`,
+
+      key: process.env.UPPYSERVER_AWS_KEY,
+      secret: process.env.UPPYSERVER_AWS_SECRET,
+      bucket: process.env.UPPYSERVER_AWS_BUCKET,
+      region: process.env.UPPYSERVER_AWS_REGION
+    }
+  },
+  server: { host: `localhost:${PORT}` }
+}))
+
+// Serve the built CSS file.
+app.get('/uppy.min.css', (req, res) => {
+  res.setHeader('content-type', 'text/css')
+  fs.createReadStream(path.join('../../dist/uppy.min.css')).pipe(res)
+})
+
+// Start the development server, budo.
+budo(path.join(__dirname, 'main.js'), {
+  live: true,
+  stream: process.stdout,
+  port: PORT,
+  middleware: app,
+  browserify: {
+    transform: [
+      'babelify',
+      ['aliasify', {
+        replacements: {
+          '^uppy/lib/(.*?)$': path.join(__dirname, '../../src/$1')
+        }
+      }]
+    ]
+  }
+})

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

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

Plik diff jest za duży
+ 664 - 96
package-lock.json


+ 6 - 6
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "uppy",
   "name": "uppy",
-  "version": "0.23.2",
+  "version": "0.23.3",
   "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:",
   "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:",
   "main": "lib/index.js",
   "main": "lib/index.js",
   "jsnext:main": "src/index.js",
   "jsnext:main": "src/index.js",
@@ -49,13 +49,12 @@
     "babel-cli": "^6.26.0",
     "babel-cli": "^6.26.0",
     "babel-core": "^6.26.0",
     "babel-core": "^6.26.0",
     "babel-jest": "^22.0.6",
     "babel-jest": "^22.0.6",
-    "babel-plugin-add-module-exports": "0.2.1",
     "babel-plugin-es6-promise": "^1.1.1",
     "babel-plugin-es6-promise": "^1.1.1",
     "babel-plugin-transform-object-assign": "^6.22.0",
     "babel-plugin-transform-object-assign": "^6.22.0",
     "babel-plugin-transform-proto-to-assign": "^6.26.0",
     "babel-plugin-transform-proto-to-assign": "^6.26.0",
     "babel-plugin-transform-react-jsx": "^6.24.1",
     "babel-plugin-transform-react-jsx": "^6.24.1",
     "babel-polyfill": "^6.26.0",
     "babel-polyfill": "^6.26.0",
-    "babel-preset-es2015": "^6.24.1",
+    "babel-preset-env": "^1.6.1",
     "babel-register": "^6.26.0",
     "babel-register": "^6.26.0",
     "babelify": "^8.0.0",
     "babelify": "^8.0.0",
     "browser-sync": "^2.23.5",
     "browser-sync": "^2.23.5",
@@ -77,6 +76,7 @@
     "glob": "^7.1.2",
     "glob": "^7.1.2",
     "isomorphic-fetch": "2.2.1",
     "isomorphic-fetch": "2.2.1",
     "jest": "^22.0.6",
     "jest": "^22.0.6",
+    "json3": "^3.3.2",
     "lint-staged": "^6.0.0",
     "lint-staged": "^6.0.0",
     "minify-stream": "^1.1.0",
     "minify-stream": "^1.1.0",
     "mkdirp": "0.5.1",
     "mkdirp": "0.5.1",
@@ -92,13 +92,12 @@
     "sass": "0.5.0",
     "sass": "0.5.0",
     "temp-write": "^3.4.0",
     "temp-write": "^3.4.0",
     "tinyify": "^2.4.0",
     "tinyify": "^2.4.0",
-    "uppy-server": "^0.10.0",
+    "uppy-server": "^0.11.2",
     "watchify": "^3.9.0",
     "watchify": "^3.9.0",
     "wdio-mocha-framework": "^0.5.12",
     "wdio-mocha-framework": "^0.5.12",
     "wdio-sauce-service": "^0.4.6",
     "wdio-sauce-service": "^0.4.6",
     "wdio-static-server-service": "^1.0.1",
     "wdio-static-server-service": "^1.0.1",
-    "webdriverio": "^4.10.1",
-    "json3": "^3.3.2"
+    "webdriverio": "^4.10.1"
   },
   },
   "dependencies": {
   "dependencies": {
     "classnames": "^2.2.5",
     "classnames": "^2.2.5",
@@ -112,6 +111,7 @@
     "preact": "^8.2.7",
     "preact": "^8.2.7",
     "prettier-bytes": "1.0.4",
     "prettier-bytes": "1.0.4",
     "prop-types": "^15.5.10",
     "prop-types": "^15.5.10",
+    "resolve-url": "^0.2.1",
     "socket.io-client": "^2.0.4",
     "socket.io-client": "^2.0.4",
     "tus-js-client": "^1.4.5",
     "tus-js-client": "^1.4.5",
     "url-parse": "^1.2.0",
     "url-parse": "^1.2.0",

+ 1 - 0
src/core/Core.js

@@ -55,6 +55,7 @@ class Uppy {
 
 
     // Merge default options with the ones set by user
     // Merge default options with the ones set by user
     this.opts = Object.assign({}, defaultOptions, opts)
     this.opts = Object.assign({}, defaultOptions, opts)
+    this.opts.restrictions = Object.assign({}, defaultOptions.restrictions, this.opts.restrictions)
 
 
     this.locale = Object.assign({}, defaultLocale, this.opts.locale)
     this.locale = Object.assign({}, defaultLocale, this.opts.locale)
     this.locale.strings = Object.assign({}, defaultLocale.strings, this.opts.locale.strings)
     this.locale.strings = Object.assign({}, defaultLocale.strings, this.opts.locale.strings)

+ 21 - 8
src/core/Core.test.js

@@ -1,11 +1,11 @@
-import Core from './Core'
-import utils from './Utils'
-import Plugin from './Plugin'
-import AcquirerPlugin1 from '../../test/mocks/acquirerPlugin1'
-import AcquirerPlugin2 from '../../test/mocks/acquirerPlugin2'
-import InvalidPlugin from '../../test/mocks/invalidPlugin'
-import InvalidPluginWithoutId from '../../test/mocks/invalidPluginWithoutId'
-import InvalidPluginWithoutType from '../../test/mocks/invalidPluginWithoutType'
+const Core = require('./Core')
+const utils = require('./Utils')
+const Plugin = require('./Plugin')
+const AcquirerPlugin1 = require('../../test/mocks/acquirerPlugin1')
+const AcquirerPlugin2 = require('../../test/mocks/acquirerPlugin2')
+const InvalidPlugin = require('../../test/mocks/invalidPlugin')
+const InvalidPluginWithoutId = require('../../test/mocks/invalidPluginWithoutId')
+const InvalidPluginWithoutType = require('../../test/mocks/invalidPluginWithoutType')
 
 
 jest.mock('cuid', () => {
 jest.mock('cuid', () => {
   return () => 'cjd09qwxb000dlql4tp4doz8h'
   return () => 'cjd09qwxb000dlql4tp4doz8h'
@@ -1213,4 +1213,17 @@ describe('src/Core', () => {
       expect(core.i18n('test')).toBe('beep boop')
       expect(core.i18n('test')).toBe('beep boop')
     })
     })
   })
   })
+
+  describe('default restrictions', () => {
+    it('should be merged with supplied restrictions', () => {
+      const core = new Core({
+        restrictions: {
+          maxNumberOfFiles: 3
+        }
+      })
+
+      expect(core.opts.restrictions.maxNumberOfFiles).toBe(3)
+      expect(core.opts.restrictions.minNumberOfFiles).toBe(false)
+    })
+  })
 })
 })

+ 3 - 3
src/core/Translator.test.js

@@ -1,6 +1,6 @@
-import Core from '../../src/core/index.js'
-import russian from '../../src/locales/ru_RU.js'
-import english from '../../src/locales/en_US.js'
+const Core = require('../../src/core/index.js')
+const russian = require('../../src/locales/ru_RU')
+const english = require('../../src/locales/en_US')
 
 
 describe('core/translator', () => {
 describe('core/translator', () => {
   describe('translate', () => {
   describe('translate', () => {

+ 1 - 1
src/core/UppySocket.test.js

@@ -1,4 +1,4 @@
-import UppySocket from './UppySocket'
+const UppySocket = require('./UppySocket')
 
 
 describe('core/uppySocket', () => {
 describe('core/uppySocket', () => {
   let webSocketConstructorSpy
   let webSocketConstructorSpy

+ 3 - 1
src/core/Utils.js

@@ -124,7 +124,9 @@ function getFileType (file) {
     'svg': 'image/svg+xml',
     'svg': 'image/svg+xml',
     'jpg': 'image/jpeg',
     'jpg': 'image/jpeg',
     'png': 'image/png',
     'png': 'image/png',
-    'gif': 'image/gif'
+    'gif': 'image/gif',
+    'yaml': 'text/yaml',
+    'yml': 'text/yaml'
   }
   }
 
 
   const fileExtension = file.name ? getFileNameAndExtension(file.name).extension : null
   const fileExtension = file.name ? getFileNameAndExtension(file.name).extension : null

Plik diff jest za duży
+ 1 - 1
src/core/Utils.test.js


+ 1 - 1
src/core/index.test.js

@@ -1,4 +1,4 @@
-import Core from './index'
+const Core = require('./index')
 
 
 describe('core/index', () => {
 describe('core/index', () => {
   it('should expose the uppy core as the default export', () => {
   it('should expose the uppy core as the default export', () => {

+ 14 - 14
src/locales/it_IT.js

@@ -3,41 +3,41 @@
 const it_IT = {}
 const it_IT = {}
 
 
 it_IT.strings = {
 it_IT.strings = {
-  chooseFile: 'Seleziona file',
+  chooseFile: 'Seleziona un file',
   youHaveChosen: 'Hai scelto: %{fileName}',
   youHaveChosen: 'Hai scelto: %{fileName}',
-  orDragDrop: 'oppure trascina qui',
+  orDragDrop: 'oppure trascinalo qui',
   filesChosen: {
   filesChosen: {
     0: '%{smart_count} file selezionato',
     0: '%{smart_count} file selezionato',
-    1: '%{smart_count} files selezionati'
+    1: '%{smart_count} file selezionati'
   },
   },
   filesUploaded: {
   filesUploaded: {
     0: '%{smart_count} file caricato',
     0: '%{smart_count} file caricato',
-    1: '%{smart_count} files caricati'
+    1: '%{smart_count} file caricati'
   },
   },
   files: {
   files: {
     0: '%{smart_count} file',
     0: '%{smart_count} file',
-    1: '%{smart_count} files'
+    1: '%{smart_count} file'
   },
   },
   uploadFiles: {
   uploadFiles: {
     0: 'Carica %{smart_count} file',
     0: 'Carica %{smart_count} file',
-    1: 'Carica %{smart_count} files'
+    1: 'Carica %{smart_count} file'
   },
   },
-  selectToUpload: 'Seleziona i files da caricare',
-  closeModal: 'Chiudi finestra',
+  selectToUpload: 'Seleziona i file da caricare',
+  closeModal: 'Chiudi la finestra',
   upload: 'Carica',
   upload: 'Carica',
-  importFrom: 'Importa files da',
+  importFrom: 'Importa i file da',
   dashboardWindowTitle: 'Uppy Dashboard Window (Premi escape per chiuderla)',
   dashboardWindowTitle: 'Uppy Dashboard Window (Premi escape per chiuderla)',
   dashboardTitle: 'Uppy Dashboard',
   dashboardTitle: 'Uppy Dashboard',
   copyLinkToClipboardSuccess: 'Collegamento copiato negli appunti.',
   copyLinkToClipboardSuccess: 'Collegamento copiato negli appunti.',
   copyLinkToClipboardFallback: 'Copia il seguente indirizzo',
   copyLinkToClipboardFallback: 'Copia il seguente indirizzo',
   done: 'Fatto',
   done: 'Fatto',
   localDisk: 'Disco locale',
   localDisk: 'Disco locale',
-  dropPasteImport: 'Trascina i files qui, incolla, importa da uno dei servizi sopra oppure',
-  dropPaste: 'Trascina i files qui, incolla oppure',
+  dropPasteImport: 'Trascina i file qui, incolla, importa da uno dei servizi sopra oppure',
+  dropPaste: 'Trascina i file qui, incolla oppure',
   browse: 'sfoglia',
   browse: 'sfoglia',
-  fileProgress: 'Progresso: velocità di caricamento e tempo rimanente',
-  numberOfSelectedFiles: 'Numero di files selezionati',
-  uploadAllNewFiles: 'Carica tutti i nuovi files'
+  fileProgress: 'Avanzamento del file: velocità di caricamento e tempo rimanente',
+  numberOfSelectedFiles: 'Numero di file selezionati',
+  uploadAllNewFiles: 'Carica tutti i nuovi file'
 }
 }
 
 
 it_IT.pluralize = function (n) {
 it_IT.pluralize = function (n) {

+ 23 - 5
src/plugins/AwsS3/index.js

@@ -1,10 +1,11 @@
+const resolveUrl = require('resolve-url')
 const Plugin = require('../../core/Plugin')
 const Plugin = require('../../core/Plugin')
 const Translator = require('../../core/Translator')
 const Translator = require('../../core/Translator')
 const { limitPromises } = require('../../core/Utils')
 const { limitPromises } = require('../../core/Utils')
 const XHRUpload = require('../XHRUpload')
 const XHRUpload = require('../XHRUpload')
 
 
 function isXml (xhr) {
 function isXml (xhr) {
-  const contentType = xhr.getResponseHeader('Content-Type')
+  const contentType = xhr.headers ? xhr.headers['content-type'] : xhr.getResponseHeader('Content-Type')
   return typeof contentType === 'string' && contentType.toLowerCase() === 'application/xml'
   return typeof contentType === 'string' && contentType.toLowerCase() === 'application/xml'
 }
 }
 
 
@@ -160,12 +161,29 @@ module.exports = class AwsS3 extends Plugin {
         if (!isXml(xhr)) {
         if (!isXml(xhr)) {
           return { location: xhr.responseURL }
           return { location: xhr.responseURL }
         }
         }
-        function getValue (key) {
-          const el = xhr.responseXML.querySelector(key)
-          return el ? el.textContent : ''
+
+        let getValue = () => ''
+        if (xhr.responseXML) {
+          getValue = (key) => {
+            const el = xhr.responseXML.querySelector(key)
+            return el ? el.textContent : ''
+          }
+        }
+
+        if (xhr.responseText) {
+          getValue = (key) => {
+            const start = xhr.responseText.indexOf(`<${key}>`)
+            const end = xhr.responseText.indexOf(`</${key}>`)
+            return start !== -1 && end !== -1
+              ? xhr.responseText.slice(start + key.length + 2, end)
+              : ''
+          }
         }
         }
+
         return {
         return {
-          location: getValue('Location'),
+          // Some S3 alternatives do not reply with an absolute URL.
+          // Eg DigitalOcean Spaces uses /$bucketName/xyz
+          location: resolveUrl(xhr.responseURL, getValue('Location')),
           bucket: getValue('Bucket'),
           bucket: getValue('Bucket'),
           key: getValue('Key'),
           key: getValue('Key'),
           etag: getValue('ETag')
           etag: getValue('ETag')

+ 3 - 1
src/plugins/Form.js

@@ -1,6 +1,8 @@
 const Plugin = require('../core/Plugin')
 const Plugin = require('../core/Plugin')
 const { findDOMElement } = require('../core/Utils')
 const { findDOMElement } = require('../core/Utils')
-const getFormData = require('get-form-data').default
+// Rollup uses get-form-data's ES modules build, and rollup-plugin-commonjs automatically resolves `.default`.
+// So, if we are being built using rollup, this require() won't have a `.default` property.
+const getFormData = require('get-form-data').default || require('get-form-data')
 
 
 /**
 /**
  * Form
  * Form

+ 1 - 3
src/plugins/GoldenRetriever/index.js

@@ -4,7 +4,7 @@ const IndexedDBStore = require('./IndexedDBStore')
 const MetaDataStore = require('./MetaDataStore')
 const MetaDataStore = require('./MetaDataStore')
 
 
 /**
 /**
-* The Golden Retriever plugin — restores selected files and resumes uploads
+* The GoldenRetriever plugin — restores selected files and resumes uploads
 * after a closed tab or a browser crash!
 * after a closed tab or a browser crash!
 *
 *
 * Uses localStorage, IndexedDB and ServiceWorker to do its magic, read more:
 * Uses localStorage, IndexedDB and ServiceWorker to do its magic, read more:
@@ -170,8 +170,6 @@ module.exports = class GoldenRetriever extends Plugin {
       }
       }
       const updatedFile = Object.assign({}, originalFile, updatedFileData)
       const updatedFile = Object.assign({}, originalFile, updatedFileData)
       updatedFiles[fileID] = updatedFile
       updatedFiles[fileID] = updatedFile
-
-      this.uppy.generatePreview(updatedFile)
     })
     })
 
 
     this.uppy.setState({
     this.uppy.setState({

+ 15 - 0
src/plugins/ThumbnailGenerator/index.js

@@ -21,6 +21,7 @@ module.exports = class ThumbnailGenerator extends Plugin {
     this.opts = Object.assign({}, defaultOptions, opts)
     this.opts = Object.assign({}, defaultOptions, opts)
 
 
     this.addToQueue = this.addToQueue.bind(this)
     this.addToQueue = this.addToQueue.bind(this)
+    this.onRestored = this.onRestored.bind(this)
   }
   }
 
 
   /**
   /**
@@ -194,10 +195,24 @@ module.exports = class ThumbnailGenerator extends Plugin {
     return Promise.resolve()
     return Promise.resolve()
   }
   }
 
 
+  onRestored () {
+    const fileIDs = Object.keys(this.uppy.getState().files)
+    fileIDs.forEach((fileID) => {
+      const file = this.uppy.getFile(fileID)
+      if (!file.isRestored) return
+      // Only add blob URLs; they are likely invalid after being restored.
+      if (!file.preview || /^blob:/.test(file.preview)) {
+        this.addToQueue(file)
+      }
+    })
+  }
+
   install () {
   install () {
     this.uppy.on('file-added', this.addToQueue)
     this.uppy.on('file-added', this.addToQueue)
+    this.uppy.on('restored', this.onRestored)
   }
   }
   uninstall () {
   uninstall () {
     this.uppy.off('file-added', this.addToQueue)
     this.uppy.off('file-added', this.addToQueue)
+    this.uppy.off('restored', this.onRestored)
   }
   }
 }
 }

+ 56 - 5
src/plugins/ThumbnailGenerator/index.test.js

@@ -1,5 +1,6 @@
-import ThumbnailGeneratorPlugin from './index'
-import Plugin from '../../core/Plugin'
+const ThumbnailGeneratorPlugin = require('./index')
+const Plugin = require('../../core/Plugin')
+const emitter = require('namespace-emitter')
 
 
 const delay = duration => new Promise(resolve => setTimeout(resolve, duration))
 const delay = duration => new Promise(resolve => setTimeout(resolve, duration))
 
 
@@ -27,7 +28,7 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       plugin.addToQueue = jest.fn()
       plugin.addToQueue = jest.fn()
       plugin.install()
       plugin.install()
 
 
-      expect(core.on).toHaveBeenCalledTimes(1)
+      expect(core.on).toHaveBeenCalledTimes(2)
       expect(core.on).toHaveBeenCalledWith('file-added', plugin.addToQueue)
       expect(core.on).toHaveBeenCalledWith('file-added', plugin.addToQueue)
     })
     })
   })
   })
@@ -43,11 +44,11 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       plugin.addToQueue = jest.fn()
       plugin.addToQueue = jest.fn()
       plugin.install()
       plugin.install()
 
 
-      expect(core.on).toHaveBeenCalledTimes(1)
+      expect(core.on).toHaveBeenCalledTimes(2)
 
 
       plugin.uninstall()
       plugin.uninstall()
 
 
-      expect(core.off).toHaveBeenCalledTimes(1)
+      expect(core.off).toHaveBeenCalledTimes(2)
       expect(core.off).toHaveBeenCalledWith('file-added', plugin.addToQueue)
       expect(core.off).toHaveBeenCalledWith('file-added', plugin.addToQueue)
     })
     })
   })
   })
@@ -347,4 +348,54 @@ describe('uploader/ThumbnailGeneratorPlugin', () => {
       })
       })
     })
     })
   })
   })
+
+  describe('onRestored', () => {
+    it('should enqueue restored files', () => {
+      const files = {
+        a: { preview: 'blob:abc', isRestored: true },
+        b: { preview: 'blob:def' },
+        c: { preview: 'blob:xyz', isRestored: true }
+      }
+      const core = Object.assign(emitter(), {
+        getState () {
+          return { files }
+        },
+        getFile (id) {
+          return files[id]
+        }
+      })
+
+      const plugin = new ThumbnailGeneratorPlugin(core)
+      plugin.addToQueue = jest.fn()
+      plugin.install()
+
+      core.emit('restored')
+
+      expect(plugin.addToQueue).toHaveBeenCalledTimes(2)
+      expect(plugin.addToQueue).toHaveBeenCalledWith(files.a)
+      expect(plugin.addToQueue).toHaveBeenCalledWith(files.c)
+    })
+
+    it('should not regenerate thumbnail for remote files', () => {
+      const files = {
+        a: { preview: 'http://abc', isRestored: true }
+      }
+      const core = Object.assign(emitter(), {
+        getState () {
+          return { files }
+        },
+        getFile (id) {
+          return files[id]
+        }
+      })
+
+      const plugin = new ThumbnailGeneratorPlugin(core)
+      plugin.addToQueue = jest.fn()
+      plugin.install()
+
+      core.emit('restored')
+
+      expect(plugin.addToQueue).not.toHaveBeenCalled()
+    })
+  })
 })
 })

+ 8 - 8
src/plugins/Transloadit/index.js

@@ -25,7 +25,7 @@ module.exports = class Transloadit extends Plugin {
     const defaultLocale = {
     const defaultLocale = {
       strings: {
       strings: {
         creatingAssembly: 'Preparing upload...',
         creatingAssembly: 'Preparing upload...',
-        creatingAssemblyFailed: 'Transloadit: Could not create assembly',
+        creatingAssemblyFailed: 'Transloadit: Could not create Assembly',
         encoding: 'Encoding...'
         encoding: 'Encoding...'
       }
       }
     }
     }
@@ -144,7 +144,7 @@ module.exports = class Transloadit extends Plugin {
   createAssembly (fileIDs, uploadID, options) {
   createAssembly (fileIDs, uploadID, options) {
     const pluginOptions = this.opts
     const pluginOptions = this.opts
 
 
-    this.uppy.log('[Transloadit] create assembly')
+    this.uppy.log('[Transloadit] create Assembly')
 
 
     return this.client.createAssembly({
     return this.client.createAssembly({
       params: options.params,
       params: options.params,
@@ -227,7 +227,7 @@ module.exports = class Transloadit extends Plugin {
       return this.connectSocket(assembly)
       return this.connectSocket(assembly)
         .then(() => assembly)
         .then(() => assembly)
     }).then((assembly) => {
     }).then((assembly) => {
-      this.uppy.log('[Transloadit] Created assembly')
+      this.uppy.log('[Transloadit] Created Assembly')
       return assembly
       return assembly
     }).catch((err) => {
     }).catch((err) => {
       this.uppy.info(this.i18n('creatingAssemblyFailed'), 'error', 0)
       this.uppy.info(this.i18n('creatingAssemblyFailed'), 'error', 0)
@@ -396,7 +396,7 @@ module.exports = class Transloadit extends Plugin {
 
 
       const newAssemblies = state.assemblies
       const newAssemblies = state.assemblies
       const previousAssemblies = prevState.assemblies
       const previousAssemblies = prevState.assemblies
-      this.uppy.log('[Transloadit] Current assembly status after restore')
+      this.uppy.log('[Transloadit] Current Assembly status after restore')
       this.uppy.log(newAssemblies)
       this.uppy.log(newAssemblies)
       this.uppy.log('[Transloadit] Assembly status before restore')
       this.uppy.log('[Transloadit] Assembly status before restore')
       this.uppy.log(previousAssemblies)
       this.uppy.log(previousAssemblies)
@@ -689,10 +689,10 @@ module.exports = class Transloadit extends Plugin {
       const onAssemblyFinished = (assembly) => {
       const onAssemblyFinished = (assembly) => {
         // An assembly for a different upload just finished. We can ignore it.
         // An assembly for a different upload just finished. We can ignore it.
         if (assemblyIDs.indexOf(assembly.assembly_id) === -1) {
         if (assemblyIDs.indexOf(assembly.assembly_id) === -1) {
-          this.uppy.log(`[Transloadit] afterUpload(): Ignoring finished assembly ${assembly.assembly_id}`)
+          this.uppy.log(`[Transloadit] afterUpload(): Ignoring finished Assembly ${assembly.assembly_id}`)
           return
           return
         }
         }
-        this.uppy.log(`[Transloadit] afterUpload(): Got assembly finish ${assembly.assembly_id}`)
+        this.uppy.log(`[Transloadit] afterUpload(): Got Assembly finish ${assembly.assembly_id}`)
 
 
         // TODO set the `file.uploadURL` to a result?
         // TODO set the `file.uploadURL` to a result?
         // We will probably need an option here so the plugin user can tell us
         // We will probably need an option here so the plugin user can tell us
@@ -709,10 +709,10 @@ module.exports = class Transloadit extends Plugin {
       const onAssemblyError = (assembly, error) => {
       const onAssemblyError = (assembly, error) => {
         // An assembly for a different upload just errored. We can ignore it.
         // An assembly for a different upload just errored. We can ignore it.
         if (assemblyIDs.indexOf(assembly.assembly_id) === -1) {
         if (assemblyIDs.indexOf(assembly.assembly_id) === -1) {
-          this.uppy.log(`[Transloadit] afterUpload(): Ignoring errored assembly ${assembly.assembly_id}`)
+          this.uppy.log(`[Transloadit] afterUpload(): Ignoring errored Assembly ${assembly.assembly_id}`)
           return
           return
         }
         }
-        this.uppy.log(`[Transloadit] afterUpload(): Got assembly error ${assembly.assembly_id}`)
+        this.uppy.log(`[Transloadit] afterUpload(): Got Assembly error ${assembly.assembly_id}`)
         this.uppy.log(error)
         this.uppy.log(error)
 
 
         // Clear postprocessing state for all our files.
         // Clear postprocessing state for all our files.

+ 4 - 4
src/plugins/Transloadit/index.test.js

@@ -98,7 +98,7 @@ describe('Transloadit', () => {
     })
     })
   })
   })
 
 
-  it('Should merge files with same parameters into one assembly', () => {
+  it('Should merge files with same parameters into one Assembly', () => {
     const uppy = new Core({ autoProceed: false })
     const uppy = new Core({ autoProceed: false })
 
 
     uppy.use(Transloadit, {
     uppy.use(Transloadit, {
@@ -145,11 +145,11 @@ describe('Transloadit', () => {
     })
     })
   })
   })
 
 
-  it('Does not create an assembly if no files are being uploaded', () => {
+  it('Does not create an Assembly if no files are being uploaded', () => {
     const uppy = new Core()
     const uppy = new Core()
     uppy.use(Transloadit, {
     uppy.use(Transloadit, {
       getAssemblyOptions () {
       getAssemblyOptions () {
-        throw new Error('should not create assembly')
+        throw new Error('should not create Assembly')
       }
       }
     })
     })
     uppy.run()
     uppy.run()
@@ -157,7 +157,7 @@ describe('Transloadit', () => {
     return uppy.upload()
     return uppy.upload()
   })
   })
 
 
-  it('Creates an assembly if no files are being uploaded but `alwaysRunAssembly` is enabled', () => {
+  it('Creates an Assembly if no files are being uploaded but `alwaysRunAssembly` is enabled', () => {
     const uppy = new Core()
     const uppy = new Core()
     uppy.use(Transloadit, {
     uppy.use(Transloadit, {
       alwaysRunAssembly: true,
       alwaysRunAssembly: true,

+ 0 - 1
src/react/DashboardModal.js

@@ -60,7 +60,6 @@ DashboardModal.propTypes = {
   plugins: PropTypes.arrayOf(PropTypes.string),
   plugins: PropTypes.arrayOf(PropTypes.string),
   maxWidth: PropTypes.number,
   maxWidth: PropTypes.number,
   maxHeight: PropTypes.number,
   maxHeight: PropTypes.number,
-  semiTransparent: PropTypes.bool,
   showProgressDetails: PropTypes.bool,
   showProgressDetails: PropTypes.bool,
   hideUploadButton: PropTypes.bool,
   hideUploadButton: PropTypes.bool,
   note: PropTypes.string,
   note: PropTypes.string,

+ 2 - 2
test/mocks/acquirerPlugin1.js

@@ -1,6 +1,6 @@
-import Plugin from '../../src/core/Plugin'
+const Plugin = require('../../src/core/Plugin')
 
 
-export default class TestSelector1 extends Plugin {
+module.exports = class TestSelector1 extends Plugin {
   constructor (uppy, opts) {
   constructor (uppy, opts) {
     super(uppy, opts)
     super(uppy, opts)
     this.type = 'acquirer'
     this.type = 'acquirer'

+ 2 - 2
test/mocks/acquirerPlugin2.js

@@ -1,6 +1,6 @@
-import Plugin from '../../src/core/Plugin'
+const Plugin = require('../../src/core/Plugin')
 
 
-export default class TestSelector2 extends Plugin {
+module.exports = class TestSelector2 extends Plugin {
   constructor (uppy, opts) {
   constructor (uppy, opts) {
     super(uppy, opts)
     super(uppy, opts)
     this.type = 'acquirer'
     this.type = 'acquirer'

+ 1 - 1
test/mocks/invalidPlugin.js

@@ -1 +1 @@
-export default {}
+module.exports = {}

+ 2 - 2
test/mocks/invalidPluginWithoutId.js

@@ -1,6 +1,6 @@
-import Plugin from '../../src/core/Plugin'
+const Plugin = require('../../src/core/Plugin')
 
 
-export default class InvalidPluginWithoutName extends Plugin {
+module.exports = class InvalidPluginWithoutName extends Plugin {
   constructor (uppy, opts) {
   constructor (uppy, opts) {
     super(uppy, opts)
     super(uppy, opts)
     this.type = 'acquirer'
     this.type = 'acquirer'

+ 2 - 2
test/mocks/invalidPluginWithoutType.js

@@ -1,6 +1,6 @@
-import Plugin from '../../src/core/Plugin'
+const Plugin = require('../../src/core/Plugin')
 
 
-export default class InvalidPluginWithoutType extends Plugin {
+module.exports = class InvalidPluginWithoutType extends Plugin {
   constructor (uppy, opts) {
   constructor (uppy, opts) {
     super(uppy, opts)
     super(uppy, opts)
     this.id = 'InvalidPluginWithoutType'
     this.id = 'InvalidPluginWithoutType'

+ 3 - 3
website/src/_posts/2017-08-0.18.md

@@ -1,5 +1,5 @@
 ---
 ---
-title: "Uppy 0.18: Dogumentation and The Golden Retriever"
+title: "Uppy 0.18: Dogumentation and The GoldenRetriever"
 image: "http://uppy.io/images/blog/0.18/golden-retriever.jpg"
 image: "http://uppy.io/images/blog/0.18/golden-retriever.jpg"
 date: 2017-09-15
 date: 2017-09-15
 author: arturi
 author: arturi
@@ -14,9 +14,9 @@ Hi! Another month — a new Uppy release 🎉
 
 
 Documentation for Uppy has been re-written, and now features chapters on Uppy’s settings and API, using various plugins, and running Uppy Server. Check it out: https://uppy.io/docs/. More chapters to come!
 Documentation for Uppy has been re-written, and now features chapters on Uppy’s settings and API, using various plugins, and running Uppy Server. Check it out: https://uppy.io/docs/. More chapters to come!
 
 
-## The Golden Retriever
+## The GoldenRetriever
 
 
-The Golden Retriever has been released as a public beta. For details, please refer to the previous post, [The Golden Retriever: Making uploads survive browser crashes](https://uppy.io/blog/2017/07/golden-retriever/), but the gist is: when enabled, this plugin will save uppy-state to localStorage on every change, and then if your browser crashes, or you accidentaly navigate away from a tab,later when you return, your uploads will resume like nothing happened. Spoiler: it uses Service Workers and IndexedDB.
+The GoldenRetriever has been released as a public beta. For details, please refer to the previous post, [The GoldenRetriever: Making uploads survive browser crashes](https://uppy.io/blog/2017/07/golden-retriever/), but the gist is: when enabled, this plugin will save uppy-state to localStorage on every change, and then if your browser crashes, or you accidentaly navigate away from a tab,later when you return, your uploads will resume like nothing happened. Spoiler: it uses Service Workers and IndexedDB.
 
 
 <img class="border" src="/images/blog/0.18/golden-retriever.jpg">
 <img class="border" src="/images/blog/0.18/golden-retriever.jpg">
 
 

+ 1 - 1
website/src/_posts/2017-10-0.20.md

@@ -141,7 +141,7 @@ We'll hopefully make that require path easier to remember in the future :)
 
 
 ## Misc good stuff
 ## Misc good stuff
 
 
-- The Golden Retriever now detects a serviceWorker registration automatically—it's no longer necessary to emit an `core:sw-file-ready` event.
+- The GoldenRetriever now detects a serviceWorker registration automatically—it's no longer necessary to emit an `core:sw-file-ready` event.
 - Request headers are now configurable in the AWS S3 plugin.
 - Request headers are now configurable in the AWS S3 plugin.
 - A new `setPluginState` allows plugins to set state scoped to the plugin.
 - A new `setPluginState` allows plugins to set state scoped to the plugin.
 - Some unused code was removed 🎉
 - Some unused code was removed 🎉

+ 2 - 2
website/src/_posts/2017-12-0.22.md

@@ -102,9 +102,9 @@ uppy.use(Form, {
 
 
 Read [more about the Form plugin](https://uppy.io/docs/form/) in docs.
 Read [more about the Form plugin](https://uppy.io/docs/form/) in docs.
 
 
-## Encoding support in Golden Retriever
+## Encoding support in GoldenRetriever
 
 
-Our browser crash / page refresh restore plugin `Golden Retriever` (read [more about it](https://uppy.io/docs/golden-retriever/)) now supports correctly restoring [Transloadit](https://transloadit.com) assemblies!
+Our browser crash / page refresh restore plugin `GoldenRetriever` (read [more about it](https://uppy.io/docs/golden-retriever/)) now supports correctly restoring [Transloadit](https://transloadit.com) assemblies!
 
 
 Also, we’ve fixed restoring from paused state. Now uploads will remain paused and not get out of sync.
 Also, we’ve fixed restoring from paused state. Now uploads will remain paused and not get out of sync.
 
 

+ 36 - 4
website/src/docs/aws-s3.md

@@ -14,6 +14,8 @@ uppy.use(AwsS3, {
 })
 })
 ```
 ```
 
 
+There are broadly two ways to upload to S3 in a browser. A server can generate a presigned URL for a [PUT upload](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPUT.html), or a server can generate form data for a [POST upload](https://docs.aws.amazon.com/AmazonS3/latest/API/RESTObjectPOST.html). uppy-server uses a POST upload. See [POST uPloads](#post-uploads) for some caveats if you would like to use POST uploads without uppy-server. See [Generating a presigned upload URL server-side](#example-presigned-url) for an example of a PUT upload.
+
 ## Options
 ## Options
 
 
 ### `host`
 ### `host`
@@ -131,8 +133,25 @@ The final configuration should look something like the below:
 
 
 In-depth documentation about CORS rules is available on the [AWS documentation site](https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html).
 In-depth documentation about CORS rules is available on the [AWS documentation site](https://docs.aws.amazon.com/AmazonS3/latest/dev/cors.html).
 
 
+## POST Uploads
+
+uppy-server uses POST uploads by default, but you can also use them with your own endpoints. There are a few things to be aware of when doing so:
+
+ - The AwsS3 plugin attempts to read the `<Location>` XML tag from POST upload responses. S3 does not respond with an XML document by default. When generating the form data for POST uploads, you must set the `success_action_status` field to `201`.
+   ```js
+   // `s3` is an instance of the AWS JavaScript SDK's S3 client
+   s3.createPresignedPost({
+     ...,
+     Fields: {
+       ...,
+       success_action_status: '201'
+     }
+   })
+   ```
+
 ## Examples
 ## Examples
 
 
+<a id="example-presigned-url"></a>
 ### Generating a presigned upload URL server-side
 ### Generating a presigned upload URL server-side
 
 
 The `getUploadParameters` function can return a Promise, so upload parameters can be prepared server-side.
 The `getUploadParameters` function can return a Promise, so upload parameters can be prepared server-side.
@@ -162,7 +181,7 @@ uppy.use(AwsS3, {
       return {
       return {
         method: data.method,
         method: data.method,
         url: data.url,
         url: data.url,
-        fields: {}
+        fields: data.fields
       }
       }
     })
     })
   }
   }
@@ -171,15 +190,28 @@ uppy.use(AwsS3, {
 
 
 See the [aws-presigned-url example in the uppy repository](https://github.com/transloadit/uppy/tree/master/examples/aws-presigned-url) for a small example that implements both the server-side and the client-side.
 See the [aws-presigned-url example in the uppy repository](https://github.com/transloadit/uppy/tree/master/examples/aws-presigned-url) for a small example that implements both the server-side and the client-side.
 
 
+### S3 Alternatives
+
+Many other object storage providers have an identical API to S3, so you can use the AwsS3 plugin with them. To use them with uppy-server, you can set the `UPPYSERVER_AWS_ENDPOINT` variable to the endpoint of your preferred service.
+
+For example, with DigitalOcean Spaces, you could do something like this:
+
+```
+export UPPYSERVER_AWS_ENDPOINT="https://{region}.digitaloceanspaces.com"
+export UPPYSERVER_AWS_BUCKET="my-space-name"
+```
+
+The `{region}` string will be replaced by the contents of the `UPPYSERVER_AWS_REGION` environment variable.
+
+For a working example that you can run and play around with, see the [digitalocean-spaces](https://github.com/transloadit/uppy/tree/master/examples/digitalocean-spaces) folder in the Uppy repository.
+
 ### Retrieving presign parameters of the uploaded file
 ### Retrieving presign parameters of the uploaded file
 
 
 Once the file is uploaded, it's possible to retrieve the parameters that were
 Once the file is uploaded, it's possible to retrieve the parameters that were
 generated in `getUploadParameters(file)` via the `file.meta` field:
 generated in `getUploadParameters(file)` via the `file.meta` field:
 
 
 ```js
 ```js
-uppy.on("upload-success", (fileId, data) {
-  const file = uppy.getFile(fileId)
-
+uppy.on('upload-success', (file, data) => {
   file.meta['key'] // the S3 object key of the uploaded file
   file.meta['key'] // the S3 object key of the uploaded file
 })
 })
 ```
 ```

+ 5 - 3
website/src/docs/contributing.md

@@ -16,7 +16,7 @@ cd uppy
 npm install
 npm install
 ```
 ```
 
 
-Our website's examples section is also our playground, read "Website Development"'s "Local Previews" section to get up and running.
+Our website’s examples section is also our playground, please read [Local Previews](#Local-Previews) section to get up and running.
 
 
 ## Tests
 ## Tests
 
 
@@ -39,13 +39,15 @@ After you’ve installed and launched the selenium standalone server, run:
 
 
 `npm run test:acceptance:local`
 `npm run test:acceptance:local`
 
 
+These tests are also run automatically on Travis builds with [SauceLabs](https://saucelabs.com/) cloud service using different OSes.
+
 ## Website Development
 ## Website Development
 
 
-We keep the [uppy.io](http://uppy.io) website in `./website` for so it's easy to keep docs & code in sync as we're still iterating at high velocity. For those reading this screaming murder, [HashiCorp does this](https://github.com/hashicorp/terraform/tree/master/website) for all their projects, and it's working well for them on a scale vastly more impressive than Uppy's.
+We keep the [uppy.io](http://uppy.io) website in `./website` so it’s easy to keep docs & code in sync as we’re 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 Hexo's 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. So it has its own `package.json` and we aim 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.
+Even though bundled in this repo, the website is regarded as a separate project. So 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
 ### Local Previews
 
 

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

@@ -25,7 +25,6 @@ uppy.use(Dashboard, {
   plugins: [],
   plugins: [],
   maxWidth: 750,
   maxWidth: 750,
   maxHeight: 550,
   maxHeight: 550,
-  semiTransparent: false,
   showProgressDetails: false,
   showProgressDetails: false,
   hideUploadButton: false,
   hideUploadButton: false,
   hideProgressAfterFinish: false,
   hideProgressAfterFinish: false,
@@ -115,7 +114,7 @@ Optionally specify a string of text that explains something about the upload for
 
 
 ### `metaFields: []`
 ### `metaFields: []`
 
 
-An array of UI field objects that will be shown when a user clicks “edit” button on that file. Each object requires:
+An array of UI field objects that will be shown when a user clicks the “edit” button on that file. Each object requires:
 
 
 - `id`, the name of the meta field.
 - `id`, the name of the meta field.
 - `name`, the label shown in the interface.
 - `name`, the label shown in the interface.
@@ -131,11 +130,11 @@ An array of UI field objects that will be shown when a user clicks “edit” bu
 })
 })
 ```
 ```
 
 
-Note that this meta data will only be set to a file if it’s entered by user. If you want to set certain default meta field to each file regardless of user actions, set [`meta` in Uppy options](/docs/uppy/#meta).
+Note that this meta data will only be set to a file if it’s entered by the user. If you want to set certain meta field to each file regardless of user actions, set [`meta` in Uppy options](/docs/uppy/#meta).
 
 
 ### `closeModalOnClickOutside: false`
 ### `closeModalOnClickOutside: false`
 
 
-Set to true to automatically close the modal when the user clicks outside it.
+Set to true to automatically close the modal when the user clicks outside of it.
 
 
 ### `disablePageScrollWhenModalOpen: true`
 ### `disablePageScrollWhenModalOpen: true`
 
 
@@ -143,11 +142,11 @@ By default when Dashboard modal is open, it will disable page scrolling, so when
 
 
 ### `disableStatusBar: false`
 ### `disableStatusBar: false`
 
 
-Dashboard ships with `StatusBar` plugin that shows upload progress and pause/resume/cancel buttons. If you want, you can disable the StatusBar to provide your custom solution.
+Dashboard ships with the `StatusBar` plugin that shows upload progress and pause/resume/cancel buttons. If you want, you can disable the StatusBar to provide your custom solution.
 
 
 ### `disableInformer: false`
 ### `disableInformer: false`
 
 
-Dashboard ships with `Informer` plugin that notifies when the browser is offline, or when it’s time to smile if `Webcam` is taking a picture. If you want, you can disable the Informer and/or provide your custom solution.
+Dashboard ships with the `Informer` plugin that notifies when the browser is offline, or when it’s time to smile if `Webcam` is taking a picture. If you want, you can disable the Informer and/or provide your custom solution.
 
 
 ### `disableThumbnailGenerator: false`
 ### `disableThumbnailGenerator: false`
 
 

+ 5 - 1
website/src/docs/dragdrop.md

@@ -5,7 +5,7 @@ title: "DragDrop"
 permalink: docs/dragdrop/
 permalink: docs/dragdrop/
 ---
 ---
 
 
-DragDrop renders a simple Drag and Drop area for file selection. Useful when you only want local device as a file source, don’t need file previews and metadata editing UI, and the [Dashboard](/docs/dashboard/) feels like an overkill.
+DragDrop renders a simple Drag and Drop area for file selection. Useful when you only want the local device as a file source, don’t need file previews and metadata editing UI, and the [Dashboard](/docs/dashboard/) feels like an overkill.
 
 
 [Try it live](/examples/dragdrop/)
 [Try it live](/examples/dragdrop/)
 
 
@@ -26,3 +26,7 @@ uppy.use(DragDrop, {
 })
 })
 ```
 ```
 
 
+### `note: null`
+
+Optionally specify a string of text that explains something about the upload for the user. This is a place to explain `restrictions` that are put in place. For example: `'Images and video only, 2–3 files, up to 1 MB'`.
+

+ 1 - 1
website/src/docs/form.md

@@ -25,7 +25,7 @@ DOM element or CSS selector for the form element. Required for the plugin to wor
 
 
 ### `getMetaFromForm: true`
 ### `getMetaFromForm: true`
 
 
-Whether to extract metadata from the form.
+Whether to extract metadata from the form. When set to true, `Form` plugin will extract all fields from a `<form>` element before upload begins. Those fields will then be added to global `uppy.state.meta` and each file’s meta, and appended as (meta)data to the upload in an object with `[file input name attribute]` -> `[file input value]` key/values.
 
 
 ### `addResultToForm: true`
 ### `addResultToForm: true`
 
 

+ 6 - 4
website/src/docs/golden-retriever.md

@@ -1,13 +1,13 @@
 ---
 ---
-title: "Golden Retriever"
+title: "GoldenRetriever"
 type: docs
 type: docs
 permalink: docs/golden-retriever/
 permalink: docs/golden-retriever/
 order: 40
 order: 40
 ---
 ---
 
 
-Golden Retriever plugin saves selected files in your browser cache (Local Storage for metadata, then Service Worker for all blobs + IndexedDB for small blobs), so that if the browser crashes, Uppy can restore everything and continue uploading like nothing happened. Read more about it [on the blog](https://uppy.io/blog/2017/07/golden-retriever/).
+The GoldenRetriever plugin saves selected files in your browser cache (Local Storage for metadata, then Service Worker for all blobs + IndexedDB for small blobs), so that if the browser crashes, Uppy can restore everything and continue uploading like nothing happened. Read more about it [on the blog](https://uppy.io/blog/2017/07/golden-retriever/).
 
 
-1\. Bundle your own service worker `sw.js` file with Uppy Golden Retriever’s service worker. If you’re using Browserify, just bundle it separately, for Webpack there is a plugin [serviceworker-webpack-plugin](https://github.com/oliviertassinari/serviceworker-webpack-plugin).
+1\. Bundle your own service worker `sw.js` file with Uppy GoldenRetriever’s service worker. If you’re using Browserify, just bundle it separately, for Webpack there is a plugin [serviceworker-webpack-plugin](https://github.com/oliviertassinari/serviceworker-webpack-plugin).
 
 
 ```js
 ```js
 // sw.js
 // sw.js
@@ -26,7 +26,7 @@ uppy.run()
 
 
 if ('serviceWorker' in navigator) {
 if ('serviceWorker' in navigator) {
   navigator.serviceWorker
   navigator.serviceWorker
-    .register('/sw.js') // path to your bundled service worker with Golden Retriever service worker
+    .register('/sw.js') // path to your bundled service worker with GoldenRetriever service worker
     .then((registration) => {
     .then((registration) => {
       console.log('ServiceWorker registration successful with scope: ', registration.scope)
       console.log('ServiceWorker registration successful with scope: ', registration.scope)
     })
     })
@@ -35,3 +35,5 @@ if ('serviceWorker' in navigator) {
     })
     })
 }
 }
 ```
 ```
+
+Voila, that’s it. Happy retrieving!

+ 0 - 8
website/src/docs/how-to-plugin.md

@@ -1,8 +0,0 @@
----
-title: "How To Make A Plugin"
-permalink: docs/how-to-plugin/
-order: 20
-published: false
----
-
-There are a few useful Uppy plugins out there, but there might come a time when you’ll want to build your own. This document will guide you.

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

@@ -31,7 +31,7 @@ uppy.on('complete', (result) => {
 
 
 Drag and Drop, Webcam, basic file manipulation (adding metadata), uploading via tus resumable uploads or XHR/Multipart is all possible using just the uppy client module.
 Drag and Drop, Webcam, basic file manipulation (adding metadata), uploading via tus resumable uploads or XHR/Multipart is all possible using just the uppy client module.
 
 
-Adding [Uppy Server](/docs/server/) to the mix enables remote sources such as Instagram, Google Drive, Dropbox, and direct urls. Uploads from remote sources are handled server-to-server, so a 5 GB video won’t be eating into your mobile data plan. Files are removed from Uppy Server after an upload is complete, or after a reasonable timeout. Access tokens also don’t stick around for long, for security reasons.
+Adding [Uppy Server](/docs/server/) to the mix enables remote sources such as Instagram, Google Drive, Dropbox, and remote urls. Uploads from remote sources are handled server-to-server, so a 5 GB video won’t be eating into your mobile data plan. Files are removed from Uppy Server after an upload is complete, or after a reasonable timeout. Access tokens also don’t stick around for long, for security reasons.
 
 
 ## Installation
 ## Installation
 
 
@@ -48,12 +48,12 @@ Alternatively, you can also use a pre-built bundle from Transloadit's CDN: Edgly
 1\. Add a script to the bottom of `<body>`:
 1\. Add a script to the bottom of `<body>`:
 
 
 ``` html
 ``` html
-<script src="https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.min.js"></script>
+<script src="https://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.min.js"></script>
 ```
 ```
 
 
 2\. Add CSS to `<head>`:
 2\. Add CSS to `<head>`:
 ``` html
 ``` html
-<link href="https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.min.css" rel="stylesheet">
+<link href="https://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.min.css" rel="stylesheet">
 ```
 ```
 
 
 3\. Initialize:
 3\. Initialize:

+ 3 - 3
website/src/docs/plugins.md

@@ -78,11 +78,11 @@ uppy.use(GoogleDrive, {target: Dashboard, host: 'http://localhost:3020'})
 
 
 ### `replaceTargetContent: false`
 ### `replaceTargetContent: false`
 
 
-By default Uppy will append any UI to a DOM element, if such element is specified as a `target`. This default is the least dangerous option. However, there might be cases when you’d want to clear the container element before place Uppy UI in there (for example, to provide a fallback `<form>` that will be shown if Uppy or JavaScript is not loaded/supported on the page). Set `replaceTargetContent: true` to clear the `target` before appending.
+By default Uppy will append any UI to a DOM element, if such element is specified as a `target`. This default is the least dangerous option. However, there might be cases when you’d want to clear the container element before placing Uppy UI in there (for example, to provide a fallback `<form>` that will be shown if Uppy or JavaScript is not loaded/supported on the page). Set `replaceTargetContent: true` to clear the `target` before appending.
 
 
 ### `locale: {}`
 ### `locale: {}`
 
 
-Same as with Uppy.Core’s setting from above, this allows you to override plugin’s local string, so that instead of `Select files` in English, your users will see `Выберите файлы` in Russian. Example:
+Same as with Uppy.Core’s setting from above, this allows you to override plugin’s locale string, so that instead of `Select files` in English, your users will see `Выберите файлы` in Russian. Example:
 
 
 ```js
 ```js
 .use(FileInput, {
 .use(FileInput, {
@@ -97,7 +97,7 @@ See plugin documentation pages for other plugin-specific options.
 
 
 ## Provider Plugins
 ## Provider Plugins
 
 
-The Provider plugins help you connect to your accounts with remote file providers such as [Dropbox](https://dropbox.com), [Google Drive](https://drive.google.com), [Instagram](https://instagram.com) and remote urls (import a file by pasting a direct link to it). Because this requires server to server communication, they work tightly with [uppy-server](https://github.com/transloadit/uppy-server) to manage the server to server authroization for your account. Virtually most of the communication (file download/upload) is done on the server-to-server end, so this saves you the stress of data consumption on the client.
+The Provider plugins help you connect to your accounts with remote file providers such as [Dropbox](https://dropbox.com), [Google Drive](https://drive.google.com), [Instagram](https://instagram.com) and remote urls (import a file by pasting a direct link to it). Because this requires server to server communication, they work tightly with [uppy-server](https://github.com/transloadit/uppy-server) to manage the server to server authorization for your account. Virtually most of the communication (file download/upload) is done on the server-to-server end, so this saves you the stress of data consumption on the client.
 
 
 As of now, the supported providers are **Dropbox**, **GoogleDrive**, **Instagram**, and **Url**.
 As of now, the supported providers are **Dropbox**, **GoogleDrive**, **Instagram**, and **Url**.
 
 

+ 1 - 1
website/src/docs/progressbar.md

@@ -36,4 +36,4 @@ uppy.use(ProgressBar, {
 
 
 ### `hideAfterFinish: true`
 ### `hideAfterFinish: true`
 
 
-When true, progress bar hides after the uplaod has finished. If false, it remains visible
+When true, progress bar hides after the uplaod has finished. If false, it remains visible.

+ 3 - 1
website/src/docs/redux.md

@@ -5,7 +5,7 @@ permalink: docs/redux
 order: 57
 order: 57
 ---
 ---
 
 
-Uppy supports Redux in two ways:
+Uppy supports popular [Redux](https://redux.js.org/) state management library in two ways:
 
 
 ## Redux Store
 ## Redux Store
 
 
@@ -48,3 +48,5 @@ const uppy = Uppy({
 ```
 ```
 
 
 After you `.use(ReduxDevTools)`, you should be able to see Uppy’s state in Redux Dev Tools.
 After you `.use(ReduxDevTools)`, you should be able to see Uppy’s state in Redux Dev Tools.
+
+You likely don’t need this if you are actually using Redux yourself and Redux Store in Uppy from above, since it will just work.

+ 17 - 37
website/src/docs/server.md

@@ -7,13 +7,13 @@ order: 2
 
 
 Drag and Drop, Webcam, basic file manipulation (adding metadata, for example) and uploading via tus resumable uploads or XHR/Multipart are all possible using just the uppy client module.
 Drag and Drop, Webcam, basic file manipulation (adding metadata, for example) and uploading via tus resumable uploads or XHR/Multipart are all possible using just the uppy client module.
 
 
-However, if you add [uppy-server](https://github.com/transloadit/uppy-server) to the mix, your users will be able to select files from remote sources, such as Instagram, Google Drive and Dropbox, bypassing the client (so a 5 GB video isn’t eating into your users' data plans), and then uploaded to the final destination. Files are removed from uppy-server after an upload is complete, or after a reasonable timeout. Access tokens also don’t stick around for long, for security.
+However, if you add [Uppy Server](https://github.com/transloadit/uppy-server) to the mix, your users will be able to select files from remote sources, such as Instagram, Google Drive and Dropbox, bypassing the client (so a 5 GB video isn’t eating into your users’ data plans), and then uploaded to the final destination. Files are removed from Uppy Server after an upload is complete, or after a reasonable timeout. Access tokens also don’t stick around for long, for security.
 
 
 Uppy Server handles the server-to-server communication between your server and file storage providers such as Google Drive, Dropbox, Instagram, etc.
 Uppy Server handles the server-to-server communication between your server and file storage providers such as Google Drive, Dropbox, Instagram, etc.
 
 
 ## Supported Providers
 ## Supported Providers
 
 
-As of now uppy-server is integrated to work with:
+As of now Uppy Server is integrated to work with:
 
 
 - Google Drive
 - Google Drive
 - Dropbox
 - Dropbox
@@ -29,11 +29,11 @@ npm install uppy-server
 
 
 ## Usage
 ## Usage
 
 
-Uppy-server may either be used as a pluggable express app, which you plug to your already existing server, or it may simply be run as a standalone server:
+Uppy Server may either be used as a pluggable express app, which you plug to your already existing server, or it may simply be run as a standalone server:
 
 
 ### Plug to already existing server
 ### Plug to already existing server
 
 
-To plug uppy-server to an existing server, simply call on its `.app` method, passing in an [options](#Options) object as parameter.
+To plug Uppy Server to an existing server, simply call on its `.app` method, passing in an [options](#Options) object as parameter.
 
 
 ```javascript
 ```javascript
 
 
@@ -66,7 +66,7 @@ app.use(uppy.app(options))
 ```
 ```
 See [Options](#Options) for valid configuration options.
 See [Options](#Options) for valid configuration options.
 
 
-To enable uppy socket for realtime upload progress, you can call the `socket` method like so.
+To enable Uppy Socket for realtime upload progress, you can call the `socket` method like so:
 
 
 ```javascript
 ```javascript
 ...
 ...
@@ -75,11 +75,11 @@ var server = app.listen(PORT)
 uppy.socket(server, options)
 uppy.socket(server, options)
 
 
 ```
 ```
-This takes your `server` instance and your uppy [options](#Options) as parameters.
+This takes your `server` instance and your Uppy [options](#Options) as parameters.
 
 
 ### Run as standalone server
 ### Run as standalone server
 
 
-> Please ensure that the required environment variables are set before running/using uppy-server as a standalone server. See [Configure Standalone](#Configure-Standalone) for the variables required.
+> Please ensure that the required environment variables are set before running/using Uppy Server as a standalone server. See [Configure Standalone](#Configure-Standalone) for the variables required.
 
 
 Set environment variables first:
 Set environment variables first:
 
 
@@ -117,7 +117,7 @@ Please see [options](#Options) for possible options.
 
 
 #### Configure Standalone
 #### Configure Standalone
 
 
-To run uppy-server as a standalone server, you are required to set your uppy [options](#Options) via environment variables:
+To run Uppy Server as a standalone server, you are required to set your Uppy [options](#Options) via environment variables:
 
 
 ```bash
 ```bash
 ####### Mandatory variables ###########
 ####### Mandatory variables ###########
@@ -239,11 +239,11 @@ See [env.example.sh](https://github.com/transloadit/uppy-server/blob/master/env.
 
 
 6. **customProviders(optional)** - This option enables you to add custom providers along with the already supported providers. See [Adding Custom Providers](#Adding-Custom-Providers) for more information.
 6. **customProviders(optional)** - This option enables you to add custom providers along with the already supported providers. See [Adding Custom Providers](#Adding-Custom-Providers) for more information.
 
 
-7. **uploadUrls(optional)** - An array of urls (full path), which uppy-server should only upload to (i.e uploads will not be permitted to other urls, except for those specified in this array).
+7. **uploadUrls(optional)** - An array of urls (full paths). If specified, Uppy Server will only accept uploads to these urls (useful when you want to make sure an Uppy Server instance is only allowed to upload to your servers, for example).
 
 
-8. **secret(required)** - A secret string which uppy uses to generate authorization tokens.
+8. **secret(required)** - A secret string which Uppy Server uses to generate authorization tokens.
 
 
-9. **debug(optional)** - A boolean flag to tell uppy whether or not to log useful debug information while running.
+9. **debug(optional)** - A boolean flag to tell Uppy Server whether or not to log useful debug information while running.
 
 
 ### S3 Options
 ### S3 Options
 
 
@@ -267,7 +267,7 @@ The default value simply returns `filename`, so all files will be uploaded to th
 
 
 ### Adding Custom Providers
 ### Adding Custom Providers
 
 
-As of now, uppy-server supports **Google Drive**, **Dropbox** and **Instagram** out of the box, but you may also choose to add your custom providers. You can do this by passing the `customProviders` option when calling the uppy `app` method. The custom provider is expected to support Oauth 1 or 2 for authentication/authorization.
+As of now, Uppy Server supports **Google Drive**, **Dropbox**, **Instagram**, and **Url** (remote urls) out of the box, but you may also choose to add your custom providers. You can do this by passing the `customProviders` option when calling the uppy `app` method. The custom provider is expected to support Oauth 1 or 2 for authentication/authorization.
 
 
 ```javascript
 ```javascript
 let options = {
 let options = {
@@ -291,7 +291,7 @@ uppy.app(options)
 
 
 The `customProviders` option should be an object containing each custom provider. Each custom provider would in turn be an object with two keys, `config` and `module`. The `config` option would contain Oauth API settings, while the `module` would point to the provider module.
 The `customProviders` option should be an object containing each custom provider. Each custom provider would in turn be an object with two keys, `config` and `module`. The `config` option would contain Oauth API settings, while the `module` would point to the provider module.
 
 
-To work well with uppy server, the **Module** must be a class with the following methods.
+To work well with Uppy Server, the **Module** must be a class with the following methods.
 
 
 1. `list (options, done)` - lists json data of user files (e.g list of all the files in a particular directory).
 1. `list (options, done)` - lists json data of user files (e.g list of all the files in a particular directory).
   - `options` - is an object containing the following attributes
   - `options` - is an object containing the following attributes
@@ -304,11 +304,11 @@ To work well with uppy server, the **Module** must be a class with the following
     - token - authorization token(retrieved from oauth process) to send along with your request.
     - token - authorization token(retrieved from oauth process) to send along with your request.
     - id - id of the file being downloaded.
     - id - id of the file being downloaded.
   - `onData (chunk)` - a callback that should be called with each data chunk received on download. This is useful if the size of the downloaded file can be pre-determined. This would allow for pipelined upload of the file (to the desired destination), while the download is still going on.
   - `onData (chunk)` - a callback that should be called with each data chunk received on download. This is useful if the size of the downloaded file can be pre-determined. This would allow for pipelined upload of the file (to the desired destination), while the download is still going on.
-  - `onResponse (response)` - if the size of the downloaded file can not be pre-determined by uppy-server, then this callback should be called in place of the `onData` callback. This callback would be called after the download is done, and would take the downloaded data (response) as the argument.
+  - `onResponse (response)` - if the size of the downloaded file can not be pre-determined by Uppy Server, then this callback should be called in place of the `onData` callback. This callback would be called after the download is done, and would take the downloaded data (response) as the argument.
 
 
 ## Development
 ## Development
 
 
-1\. To setup uppy-server for local development, please clone the repo and install like so:
+1\. To setup Uppy Server for local development, please clone the repo and install like so:
 
 
 ```bash
 ```bash
 git clone https://github.com/transloadit/uppy-server && cd uppy-server && npm install
 git clone https://github.com/transloadit/uppy-server && cd uppy-server && npm install
@@ -327,29 +327,9 @@ $EDITOR env.sh
 npm run start:dev
 npm run start:dev
 ```
 ```
 
 
-This would get the uppy-server running on `http://localhost:3020`.
-
-It also expects the [uppy client](https://github.com/transloadit/uppy) to be running on `http://localhost:3452` by default.
+This would get the Uppy Server running on `http://localhost:3020`.
 
 
 ## Running example
 ## Running example
 
 
-An example server is running at http://server.uppy.io, which is deployed via
-[Frey](https://github.com/kvz/frey), using the following [Freyfile](infra/Freyfile.toml).
-
-All the secrets are stored in `env.infra.sh`, so using `env.infra.example.sh`, you could use the same Freyfile but target a different cloud vendor with different secrets, and run your own uppy-server.
-
-## Logging
-
-Requires Frey, if you haven't set it up yet type
-
-```bash
-npm run install:frey
-```
-
-afterwards, production logs are available through:
-
-```bash
-npm run logtail
-```
+An example server is running at http://server.uppy.io, which is deployed with [Kubernetes](https://github.com/transloadit/uppy-server/blob/master/KUBERNETES.md)
 
 
-This requires at least the `FREY_ENCRYPTION_SECRET` key present in your `./env.sh`.

+ 1 - 1
website/src/docs/stores.md

@@ -141,4 +141,4 @@ function defaultStore () {
 
 
 A pattern like this, where users can pass options via a function call if necessary, is recommended.
 A pattern like this, where users can pass options via a function call if necessary, is recommended.
 
 
-See the [./src/store](https://github.com/transloadit/uppy/tree/feature/store/src/store) folder in the repository for more inspiration.
+See the [./src/store](https://github.com/transloadit/uppy/tree/master/src/store) folder in the repository for more inspiration.

+ 26 - 25
website/src/docs/transloadit.md

@@ -12,11 +12,11 @@ The Transloadit plugin can be used to upload files to [Transloadit](https://tran
 ```js
 ```js
 uppy.use(Transloadit, {
 uppy.use(Transloadit, {
   service: 'https://api2.transloadit.com',
   service: 'https://api2.transloadit.com',
+  params: null,
   waitForEncoding: false,
   waitForEncoding: false,
   waitForMetadata: false,
   waitForMetadata: false,
   importFromUploadURLs: false,
   importFromUploadURLs: false,
   alwaysRunAssembly: false,
   alwaysRunAssembly: false,
-  params: null,
   signature: null,
   signature: null,
   fields: {}
   fields: {}
 })
 })
@@ -30,6 +30,31 @@ As of Uppy 0.24 the Transloadit plugin includes the [Tus](/docs/tus) plugin to h
 
 
 The Transloadit API URL to use. Defaults to `https://api2.transloadit.com`, which will attempt to route traffic efficiently based on where your users are. You can set this to something like `https://api2-us-east-1.transloadit.com` if you want to use a particular region.
 The Transloadit API URL to use. Defaults to `https://api2.transloadit.com`, which will attempt to route traffic efficiently based on where your users are. You can set this to something like `https://api2-us-east-1.transloadit.com` if you want to use a particular region.
 
 
+### `params`
+
+The Assembly parameters to use for the upload. See the Transloadit documentation on [Assembly Instructions](https://transloadit.com/docs/#14-assembly-instructions). `params` should be a plain JavaScript object, or a JSON string if you are using the [`signature`](#signature) option.
+
+The `auth.key` Assembly parameter is required. You can also use the `steps` or `template_id` options here as described in the Transloadit documentation.
+
+```js
+uppy.use(Transloadit, {
+  params: {
+    auth: { key: 'YOUR_TRANSLOADIT_KEY' },
+    steps: {
+      encode: {
+        robot: '/video/encode',
+        use: {
+          steps: [ ':original' ],
+          fields: [ 'file_input_field2' ]
+        },
+        preset: 'iphone'
+      }
+    }
+  }
+})
+```
+
+
 ### `waitForEncoding`
 ### `waitForEncoding`
 
 
 Whether to wait for all Assemblies to complete before completing the upload.
 Whether to wait for all Assemblies to complete before completing the upload.
@@ -67,30 +92,6 @@ In order for this to work, the upload plugin must assign a publically accessible
 
 
 When true, always create and run an Assembly when `uppy.upload()` is called, even if no files were selected. This allows running Assemblies that do not receive files, but instead use a robot like [`/s3/import`](https://transloadit.com/docs/transcoding/#s3-import) to download the files from elsewhere, for example for a bulk transcoding job.
 When true, always create and run an Assembly when `uppy.upload()` is called, even if no files were selected. This allows running Assemblies that do not receive files, but instead use a robot like [`/s3/import`](https://transloadit.com/docs/transcoding/#s3-import) to download the files from elsewhere, for example for a bulk transcoding job.
 
 
-### `params`
-
-The Assembly parameters to use for the upload. See the Transloadit documentation on [Assembly Instructions](https://transloadit.com/docs/#14-assembly-instructions). `params` should be a plain JavaScript object, or a JSON string if you are using the [`signature`](#signature) option.
-
-The `auth.key` Assembly parameter is required. You can also use the `steps` or `template_id` options here as described in the Transloadit documentation.
-
-```js
-uppy.use(Transloadit, {
-  params: {
-    auth: { key: 'YOUR_TRANSLOADIT_KEY' },
-    steps: {
-      encode: {
-        robot: '/video/encode',
-        use: {
-          steps: [ ':original' ],
-          fields: [ 'file_input_field2' ]
-        },
-        preset: 'iphone'
-      }
-    }
-  }
-})
-```
-
 ### `signature`
 ### `signature`
 
 
 An optional signature for the Assembly parameters. See the Transloadit documentation on [Signature Authentication](https://transloadit.com/docs/#26-signature-authentication).
 An optional signature for the Assembly parameters. See the Transloadit documentation on [Signature Authentication](https://transloadit.com/docs/#26-signature-authentication).

+ 1 - 1
website/src/docs/tus.md

@@ -24,7 +24,7 @@ The Tus plugin supports all of [tus-js-client][]’s options. Additionally:
 
 
 A boolean indicating whether tus should attempt to resume the upload if the upload has been started in the past. This includes storing the file’s upload url. Use false to force an entire reupload.
 A boolean indicating whether tus should attempt to resume the upload if the upload has been started in the past. This includes storing the file’s upload url. Use false to force an entire reupload.
 
 
-Note that this option is about resuming when you start an upload again with the same file, or when using [Golden Retriever](/docs/golden-retriever/), which will attempt to restore upload state to what it was before page refresh / browser crash. Even if you set `resume: false` when using Tus uploader, users will still be able to pause/resume an ongoing upload.
+Note that this option is about resuming when you start an upload again with the same file, or when using [GoldenRetriever](/docs/golden-retriever/), which will attempt to restore upload state to what it was before page refresh / browser crash. Even if you set `resume: false` when using Tus uploader, users will still be able to pause/resume an ongoing upload.
 
 
 In most cases you should leave this option as is, relax, and enjoy resumable uploads.
 In most cases you should leave this option as is, relax, and enjoy resumable uploads.
 
 

+ 67 - 33
website/src/docs/uppy.md

@@ -44,7 +44,7 @@ const photoUploader = Uppy({ id: 'post' })
 
 
 ### `autoProceed: true`
 ### `autoProceed: true`
 
 
-Starts upload automatically after the first file is selected.
+Uppy will start uploading automatically after the first file is selected.
 
 
 ### `restrictions: {}`
 ### `restrictions: {}`
 
 
@@ -67,7 +67,14 @@ meta: {
 }
 }
 ```
 ```
 
 
-Can be altered with [`uppy.setMeta({ username: 'Peter' })`](/docs/uppy/#uppy-setmeta-data) method.
+This global metadata is added to each file in Uppy. It can be modified with two methods:
+
+1. [`uppy.setMeta({ username: 'Peter' })`](/docs/uppy/#uppy-setmeta-data) — set or update meta for all files.
+2. [`uppy.setFileMeta('myfileID', { resize: 1500 })`](/docs/uppy/#uppy-setFileMeta-fileID-data) — set or update meta for specific file. 
+
+Metadata from each file is then attached to uploads in [Tus](/docs/tus/) and [XHRUpload](/docs/tus/) plugins.
+
+Metadata can also be added from a `<form>` element on your page via [Form](/docs/form/)plugin or via UI if you are using Dashboard with [`metaFields`](/docs/dashboard/#metaFields) option.
 
 
 ### `onBeforeFileAdded: (currentFile, files) => Promise.resolve()`
 ### `onBeforeFileAdded: (currentFile, files) => Promise.resolve()`
 
 
@@ -119,7 +126,7 @@ locale: {
 
 
 As well as the pluralization function, which is used to determine which string will be used for the provided `smart_count` number.
 As well as the pluralization function, which is used to determine which string will be used for the provided `smart_count` number.
 
 
-For example, for Icelandic language the pluralization function will be:
+For example, for Icelandic language the pluralization function would be:
 
 
 ``` js
 ``` js
 locale: {
 locale: {
@@ -193,6 +200,28 @@ file.size      // 3947642 (returns 'N/A' if size cannot be determined)
 file.preview   // value that can be used to populate "src" attribute of an "img" tag
 file.preview   // value that can be used to populate "src" attribute of an "img" tag
 ```
 ```
 
 
+### `uppy.upload()`
+
+Start uploading selected files.
+
+Returns a Promise `result` that resolves with an object containing two arrays of uploaded files:
+
+- `result.successful` - Files that were uploaded successfully.
+- `result.failed` - Files that did not upload successfully. These file objects will have a `.error` property describing what went wrong.
+
+```js
+uppy.upload().then((result) => {
+  console.info('Successful uploads:', result.successful)
+
+  if (result.failed.length > 0) {
+    console.error('Errors:')
+    result.failed.forEach((file) => {
+      console.error(file.error)
+    })
+  }
+})
+```
+
 ### `uppy.setState(patch)`
 ### `uppy.setState(patch)`
 
 
 Update `uppy.state`. Usually this method is called internally, but in some cases it might be useful to alter something in `uppy.state` directly.
 Update `uppy.state`. Usually this method is called internally, but in some cases it might be useful to alter something in `uppy.state` directly.
@@ -203,6 +232,7 @@ Uppy’s default state on initialization:
 {
 {
   plugins: {},
   plugins: {},
   files: {},
   files: {},
+  currentUploads: {},
   capabilities: {
   capabilities: {
     resumableUploads: false
     resumableUploads: false
   },
   },
@@ -245,6 +275,12 @@ uppy.setState({files: updatedFiles})
 
 
 Returns `uppy.state`, which you can also use directly.
 Returns `uppy.state`, which you can also use directly.
 
 
+### `uppy.setFileState(fileID, state)`
+
+Update the state for a single file. This is mostly useful for plugins that may want to store data on file objects, or that need to pass file-specific configuration to other plugins that support it.
+
+`fileID` is the string file ID. `state` is an object that will be merged into the file's state object.
+
 ### `uppy.setMeta(data)`
 ### `uppy.setMeta(data)`
 
 
 Alters global `meta` object is state, the one that can be set in Uppy options and gets merged with all newly added files. Calling `setMeta` will also merge newly added meta data with previously selected files.
 Alters global `meta` object is state, the one that can be set in Uppy options and gets merged with all newly added files. Calling `setMeta` will also merge newly added meta data with previously selected files.
@@ -258,9 +294,7 @@ uppy.setMeta({ resize: 1500, token: 'ab5kjfg' })
 Updated metadata for a specific file.
 Updated metadata for a specific file.
 
 
 ```js
 ```js
-uppy.setFileMeta('myfileID', {
-  resize: 1500
-})
+uppy.setFileMeta('myfileID', { resize: 1500 })
 ```
 ```
 
 
 ### `uppy.reset()`
 ### `uppy.reset()`
@@ -271,45 +305,42 @@ Stop all uploads in progress and clear file selection, set progress to 0. Basica
 
 
 Uninstall all plugins and close down this Uppy instance. Also runs `uppy.reset()` before uninstalling.
 Uninstall all plugins and close down this Uppy instance. Also runs `uppy.reset()` before uninstalling.
 
 
-### `uppy.log(msgString)`
+### `uppy.log()`
 
 
-Logs stuff to console, only if `uppy.opts.debug` is set to true. Silent in production.
+#### Parameters
 
 
-### `uppy.info()`
+- **message** *{string}*
+- **type** *{string=}* `error` or `warning`
+
+Logs stuff to console, only if `uppy.opts.debug` is set to true. Silent in production.
 
 
 ```js
 ```js
-this.info('Oh my, something good happened!', 'success', 5000)
+uppy.log('[Dashboard] adding files...')
 ```
 ```
 
 
-#### Parameters
-
-- **message** *string*
-- **type** *string* `info`, `warning`, `success` or `error`
-- **duration** *number* in milliseconds
-
-### `uppy.upload()`
+### `uppy.info()`
 
 
-Start uploading selected files.
+#### Parameters
 
 
-Returns a Promise `result` that resolves with an object containing two arrays of uploaded files.
+- **message** *{(string|object)}* — `'info message'` or `{ message: 'Oh no!', details: 'File couldn’t be uploaded' }`
+- **type** *{string} [type='info']* — `info`, `warning`, `success` or `error`
+- **duration** *{number} [duration = 3000]* — in milliseconds
 
 
- - `result.successful` - Files that were uploaded successfully.
- - `result.failed` - Files that did not upload successfully.
-   These file objects will have a `.error` property describing what went wrong.
+Sets a message in state, with optional details, that can be shown by notification UI plugins. Currently that means just the [Informer](/docs/informer/) plugin, included by default in Dashboard.
 
 
 ```js
 ```js
-uppy.upload().then((result) => {
-  console.info('Successful uploads:', result.successful)
+this.info('Oh my, something good happened!', 'success', 3000)
+```
 
 
-  if (result.failed.length > 0) {
-    console.error('Errors:')
-    result.failed.forEach((file) => {
-      console.error(file.error)
-    })
-  }
-})
+```js
+this.info({
+    message: 'Oh no, something bad happened!',
+    details: 'File couldn’t be uploaded because there’s no internet connection',
+  }, 'error', 5000)
 ```
 ```
 
 
+`info-visible` and `info-hidden` events are emitted when this info message should be visible or hidden.
+
 ### `uppy.on('event', action)`
 ### `uppy.on('event', action)`
 
 
 Subscribe to an uppy-event. See below for the full list of events.
 Subscribe to an uppy-event. See below for the full list of events.
@@ -343,8 +374,11 @@ uppy.on('file-removed', (file) => {
 Fired when upload starts.
 Fired when upload starts.
 
 
 ```javascript
 ```javascript
-uppy.on('upload', () => {
-  console.log('Starting upload...')
+uppy.on('upload', (data) => {
+  // data object consists of `id` with upload id and `fileIDs` array 
+  // with file ids in current upload
+  // data: { id, fileIDs }
+  console.log(`Starting upload ${id} for files ${fileIDs}`)
 })
 })
 ```
 ```
 
 

+ 2 - 3
website/src/docs/webcam.md

@@ -33,12 +33,11 @@ uppy.use(Webcam, {
 
 
 ### `target: null`
 ### `target: null`
 
 
-DOM element, CSS selector, or plugin to mount the informer into.
+DOM element, CSS selector, or plugin to mount Webcam into.
 
 
 ### `countdown: false`
 ### `countdown: false`
 
 
-When taking a picture: the amount of seconds to wait before actually taking a snapshot. If `false` or 0, the timeout is disabled entirely.
-This also shows a 'Smile!' message in the [Informer](/docs/informer) before the picture is taken.
+When taking a picture: the amount of seconds to wait before actually taking a snapshot. If `false` or 0, the timeout is disabled entirely. This also shows a `Smile!` message with the [Informer](/docs/informer) before the picture is taken.
 
 
 ### `onBeforeSnapshot: () => Promise.resolve()`
 ### `onBeforeSnapshot: () => Promise.resolve()`
 
 

+ 195 - 0
website/src/docs/writing-plugins.md

@@ -0,0 +1,195 @@
+---
+type: docs
+title: "Writing Plugins"
+permalink: docs/writing-plugins/
+order: 20
+---
+
+There are a few useful Uppy plugins out there, but there might come a time when you’ll want to build your own.
+Plugins can hook into the upload process or render a custom UI, typically to:
+
+ - Render some custom UI element, e.g. [StatusBar](/docs/statusbar) or [Dashboard](/docs/dashboard).
+ - Do the actual uploading, e.g. [XHRUpload](/docs/xhrupload) or [Tus](/docs/tus).
+ - Interact with a third party service to process uploads correctly, e.g. [Transloadit](/docs/transloadit) or [AwsS3](/docs/aws-s3).
+
+## Creating A Plugin
+
+Plugins are classes that extend from Uppy's `Plugin` class. Each plugin has an `id` and a `type`. `id`s are used to uniquely identify plugins. A `type` can be anything—some plugins use `type`s to determine whether to do something to some other plugin. For example, when targeting plugins at the builtin `Dashboard` plugin, the Dashboard uses the `type` to figure out where to mount different UI elements. `'acquirer'` type plugins are mounted into the tab bar, while `'progressindicator'` type plugins are mounted into the progress bar area.
+
+The plugin constructor receives the Uppy instance in the first parameter, and any options passed to `uppy.use()` in the second parameter.
+
+```js
+const Plugin = require('uppy/lib/plugins/Plugin')
+module.exports = class MyPlugin extends Plugin {
+  constructor (uppy, opts) {
+    super(uppy, opts)
+    this.id = opts.id || 'MyPlugin'
+    this.type = 'example'
+  }
+}
+```
+
+## Methods
+
+Plugins can implement methods in order to execute certain tasks. The most important method is `install()`, which is called when a plugin is `.use`d.
+
+All of the below methods are optional! Only implement the methods you need.
+
+### `install()`
+
+Called when the plugin is `.use`d. Do any setup work here, like attaching events or adding [upload hooks](#Upload-Hooks).
+
+```js
+install () {
+  this.uppy.on('upload-progress', this.onProgress)
+  this.uppy.addPostProcessor(this.afterUpload)
+}
+```
+
+### `uninstall()`
+
+Called when the plugin is removed, or the Uppy instance is closed. This should undo all of the work done in the `install()` method.
+
+```js
+uninstall () {
+  this.uppy.off('upload-progress', this.onProgress)
+  this.uppy.removePostProcessor(this.afterUpload)
+}
+```
+
+### `update(state)`
+
+Called on each state update. It's rare that you'd need to use this, it's mostly handy if you want to build a UI plugin using something other than preact.
+
+## Upload Hooks
+
+When creating an upload, Uppy runs files through an upload pipeline. The pipeline consists of three parts, each of which can be hooked into: Preprocessing, Uploading, and Postprocessing. Preprocessors can be used to configure uploader plugins, encrypt files, resize images, etc., before uploading them. Uploaders do the actual uploading work, such as creating an XMLHttpRequest object and sending the file. Postprocessors do work after files have been uploaded completely. This could be anything from waiting for a file to propagate across a CDN, to sending another request to relate some metadata to the file.
+
+Each hook is a function that receives an array containing the file IDs that are being uploaded, and returns a Promise to signal completion. Hooks are added and removed through `Uppy` methods: `addPreProcessor`, `addUploader`, `addPostProcessor`, and their `remove*` counterparts. Normally, hooks should be added during the plugin's `install()` method, and removed during the `uninstall()` method.
+
+Additionally, upload hooks can fire events to signal progress.
+
+When adding hooks, make sure to bind the hook `fn` beforehand! Otherwise it will be impossible to remove. For example:
+
+```js
+class MyPlugin extends Plugin {
+  constructor (uppy, opts) {
+    super(uppy, opts)
+    this.id = opts.id || 'MyPlugin'
+    this.type = 'example'
+    this.prepareUpload = this.prepareUpload.bind(this) // ← this!
+  }
+
+  prepareUpload (fileIDs) {
+    return Promise.resolve()
+  }
+
+  install () {
+    this.uppy.addPreProcessor(this.prepareUpload)
+  }
+
+  uninstall () {
+    this.uppy.removePreProcessor(this.prepareUpload)
+  }
+}
+```
+
+### `addPreProcessor(fn)`
+
+Add a preprocessing function. `fn` gets called with a list of file IDs before an upload starts. `fn` should return a Promise. Its resolution value is ignored. To change file data and such, use Uppy state updates, for example using [`setFileState`][core.setfilestate].
+
+### `addUploader(fn)`
+
+Add an uploader function. `fn` gets called with a list of file IDs when an upload should start. Uploader functions should do the actual uploading work, such as creating and sending an XMLHttpRequest or calling into some upload service's SDK. `fn` should return a Promise that resolves once all files have been uploaded.
+
+You may choose to still resolve the Promise if some file uploads fail. This way any postprocessing will still run on the files that were uploaded successfully, while uploads that failed will be retried when `uppy.retryAll` is called.
+
+### `addPostProcessor(fn)`
+
+Add a postprocessing function. `fn` is called with a list of file IDs when an upload has finished. `fn` should return a Promise that resolves when the processing work is complete. Again, the resolution value of the Promise is ignored. This hook can be used to do any finishing work. For example, you could wait for file encoding or CDN propagation to complete, or you could do an HTTP API call to create an album containing all images that were just uploaded.
+
+### `removePreProcessor/removeUploader/removePostProcessor(fn)`
+
+Remove a processor or uploader function that was added previously. Normally this should be done in the `uninstall()` method.
+
+## Progress Events
+
+Progress events can be fired for individual files to show feedback to the user. For upload progress events, only emitting how many bytes are expected and how many have been uploaded is enough. Uppy will handle calculating progress percentages, upload speed, etc.
+
+Preprocessing and postprocessing progress events are plugin-dependent and can refer to anything, so Uppy doesn't try to be smart about them. There are two types of processing progress events: determinate and indeterminate. Some processing does not have meaningful progress beyond "not done" and "done". For example, sending a request to initialize a server-side resource that will be uploaded to. In those situations, indeterminate progress is suitable. Other processing does have meaningful progress. For example, encrypting a large file. In those situations, determinate progress is suitable.
+
+### `preprocess-progress(fileID, progress)`
+
+`progress` is an object with properties:
+
+ - `mode` - Either `'determinate'` or `'indeterminate'`.
+ - `message` - A message to show to the user. Something like `'Preparing upload...'`, but be more specific if possible.
+
+When `mode` is `'determinate'`, also add the `value` property:
+
+ - `value` - A progress value between 0 and 1.
+
+### `upload-progress(progress)`
+
+`progress` is an object with properties:
+
+ - `uploader` - The uploader plugin that fired the event (`this`).
+ - `id` - The file ID.
+ - `bytesTotal` - The full amount of bytes to be uploaded.
+ - `bytesUploaded` - The amount of bytes that have been uploaded so far.
+
+### `postprocess-progress(fileID, progress)`
+
+`progress` is an object with properties:
+
+ - `mode` - Either `'determinate'` or `'indeterminate'`.
+ - `message` - A message to show to the user. Something like `'Preparing upload...'`, but be more specific if possible.
+
+When `mode` is `'determinate'`, also add the `value` property:
+
+ - `value` - A progress value between 0 and 1.
+
+## UI Plugins
+
+UI Plugins can be used to show a user interface. Uppy plugins use [preact](https://preactjs.com) for rendering. preact is a very small React-like library that works really well with Uppy's state architecture. Uppy implements preact rendering in the `mount(target)` and `update()` plugin methods, so if you want to write a custom UI plugin using some other library, you can override those methods.
+
+Plugins can implement certain methods to do so, that will be called by Uppy when necessary:
+
+### `mount(target)`
+
+Mount this plugin to the `target` element. `target` can be a CSS query selector, a DOM element, or another Plugin. If `target` is a Plugin, the source (current) plugin will register with the target plugin, and the latter can decide how and where to render the source plugin.
+
+This method can be overridden to support for different render engines.
+
+### `render()`
+
+Render this plugin's UI. Uppy uses [preact](https://preactjs.com) as its view engine, so `render()` should return a preact element.
+`render` is automatically called by Uppy on each state change.
+
+Note that we are looking into ways to make Uppy render engine agnostic, so that plugins can choose their own favourite library—whether it's preact, choo, jQuery, or anything else. This means that the `render()` API may change in the future, but we'll detail exactly what you need to do on the [blog](https://uppy.io/blog) if and when that happens.
+
+### JSX
+
+Since Uppy uses Preact and not React, the default Babel configuration for JSX elements does not work. You have to import the preact `h` function and tell Babel to use it by adding a `/** @jsx h */` comment at the top of the file.
+
+See the Preact [Getting Started Guide](https://preactjs.com/guide/getting-started) for more on Babel and JSX.
+
+```js
+/** @jsx h */
+const Plugin = require('uppy/lib/core/Plugin')
+const { h } = require('preact')
+
+class NumFiles extends Plugin {
+  render () {
+    const numFiles = Object.keys(this.uppy.state.files).length
+
+    return (
+      <div>
+        Number of files: {numFiles}
+      </div>
+    )
+  }
+}
+```
+
+[core.setfilestate]: /docs/uppy#uppy-setFileState-fileID-state

+ 3 - 3
website/src/docs/xhrupload.md

@@ -72,7 +72,7 @@ uppy.setFileState(otherFileID, {
 })
 })
 ```
 ```
 
 
-### `getResponseData(xhr)`
+### `getResponseData(xhr.responseText, xhr)`
 
 
 When an upload has completed, Uppy will extract response data from the upload endpoint. This response data will be available on the file's `.response` property, and be emitted in the `upload-success` event:
 When an upload has completed, Uppy will extract response data from the upload endpoint. This response data will be available on the file's `.response` property, and be emitted in the `upload-success` event:
 
 
@@ -101,7 +101,7 @@ That object will be emitted in the `upload-success` event. Not all endpoints res
 For example, an endpoint that responds with an XML document:
 For example, an endpoint that responds with an XML document:
 
 
 ```js
 ```js
-getResponseData (xhr) {
+getResponseData (xhr.responseText, xhr) {
   return {
   return {
     url: xhr.responseXML.querySelector('Location').textContent
     url: xhr.responseXML.querySelector('Location').textContent
   }
   }
@@ -124,7 +124,7 @@ getResponseError (responseText, xhr) {
 
 
 ### `responseUrlFieldName: 'url'`
 ### `responseUrlFieldName: 'url'`
 
 
-The field name containing a publically accessible location of the uploaded file in the response data returned by `getResponseData(xhr)`.
+The field name containing a publically accessible location of the uploaded file in the response data returned by `getResponseData(xhr.responseText, xhr)`.
 
 
 ### `timeout: 30 * 1000`
 ### `timeout: 30 * 1000`
 
 

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

@@ -1,11 +1,11 @@
 <!-- Basic Uppy styles. You can use Transloadit's CDN, Edgly: 
 <!-- Basic Uppy styles. You can use Transloadit's CDN, Edgly: 
-https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.min.css -->
+https://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.min.css -->
 <link rel="stylesheet" href="/uppy/uppy.min.css">
 <link rel="stylesheet" href="/uppy/uppy.min.css">
 
 
 <div class="UppyDragDrop"></div>
 <div class="UppyDragDrop"></div>
 
 
 <!-- Load Uppy pre-built bundled version. You can use Transloadit's CDN, Edgly: 
 <!-- Load Uppy pre-built bundled version. You can use Transloadit's CDN, Edgly: 
-https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.min.js -->
+https://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.min.js -->
 <script src="/uppy/uppy.min.js"></script>
 <script src="/uppy/uppy.min.js"></script>
 <script>
 <script>
   var uppy = Uppy.Core({ debug: true });
   var uppy = Uppy.Core({ debug: true });

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

@@ -79,8 +79,8 @@
   <p>© <%- date(Date.now(), 'YYYY') %> <a href="https://transloadit.com" target="_blank">Transloadit</a></p>
   <p>© <%- date(Date.now(), 'YYYY') %> <a href="https://transloadit.com" target="_blank">Transloadit</a></p>
 </footer>
 </footer>
 
 
-<link href="https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.min.css" rel="stylesheet">
-<script src="https://transloadit.edgly.net/releases/uppy/v0.23.2/dist/uppy.min.js"></script>
+<link href="https://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.min.css" rel="stylesheet">
+<script src="https://transloadit.edgly.net/releases/uppy/v0.23.3/dist/uppy.min.js"></script>
 
 
 <script>
 <script>
   var PROTOCOL = location.protocol === 'https:' ? 'https' : 'http'
   var PROTOCOL = location.protocol === 'https:' ? 'https' : 'http'

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików