Parcourir la source

Initial commit

rigwild il y a 4 ans
commit
00ff5af349
14 fichiers modifiés avec 601 ajouts et 0 suppressions
  1. 5 0
      .editorconfig
  2. 143 0
      .eslintrc.js
  3. 23 0
      .gitignore
  4. 21 0
      LICENSE
  5. 38 0
      README.md
  6. 23 0
      example.js
  7. 74 0
      lib/db/Data/controller.js
  8. 3 0
      lib/db/Data/index.js
  9. 11 0
      lib/db/Data/model.js
  10. 29 0
      lib/db/index.js
  11. 9 0
      lib/index.js
  12. 17 0
      lib/utils.js
  13. 16 0
      package.json
  14. 189 0
      yarn.lock

+ 5 - 0
.editorconfig

@@ -0,0 +1,5 @@
+[*.{js,jsx,ts,tsx,vue}]
+indent_style = space
+indent_size = 2
+trim_trailing_whitespace = true
+insert_final_newline = true

+ 143 - 0
.eslintrc.js

@@ -0,0 +1,143 @@
+/*
+rigwild's personal ESLint configuration
+Using modern JavaScript syntax, very restrictive.
+Preferably use with autofix on save.
+
+https://github.com/rigwild
+*/
+
+// prettier-ignore
+module.exports = {
+  parserOptions: {
+    parser: 'babel-eslint',
+    ecmaVersion: 2019,
+    sourceType: 'module'
+  },
+
+  root: true,
+  env: {
+    node: true,
+    es6: true
+  },
+
+  rules: {
+    // Possible Errors
+    // The following rules point out areas where you might have made mistakes.
+    'comma-dangle': 1,
+    'no-cond-assign': 2,
+    'no-constant-condition': 2,
+    'no-control-regex': 2,
+    'no-debugger': 2,
+    'no-dupe-args': 2,
+    'no-dupe-keys': 2,
+    'no-duplicate-case': 2,
+    'no-empty': 2,
+    'no-ex-assign': 2,
+    'no-extra-boolean-cast': 2,
+    'no-extra-parens': 0,
+    'no-extra-semi': 2,
+    'no-func-assign': 2,
+    'no-inner-declarations': 2,
+    'no-invalid-regexp': 2,
+    'no-irregular-whitespace': 2,
+    'no-negated-in-lhs': 2,
+    'no-obj-calls': 2,
+    'no-regex-spaces': 2,
+    'no-sparse-arrays': 2,
+    'no-unreachable': 2,
+    'use-isnan': 2,
+    'valid-jsdoc': 2,
+    'valid-typeof': 2,
+
+    // Best Practices
+    // These are rules designed to prevent you from making mistakes.
+    'block-scoped-var': 0,
+    'complexity': 0,
+    'curly': 'off',
+    'default-case': 2,
+    'dot-notation': 2,
+    'eqeqeq': 2,
+    'guard-for-in': 2,
+    'no-alert': 2,
+    'no-caller': 2,
+    'no-div-regex': 2,
+    'no-else-return': 2,
+    'no-eq-null': 2,
+    'no-eval': 2,
+    'no-extend-native': 2,
+    'no-extra-bind': 2,
+    'no-fallthrough': 2,
+    'no-floating-decimal': 2,
+    'no-implied-eval': 2,
+    'no-iterator': 2,
+    'no-labels': 2,
+    'no-lone-blocks': 2,
+    'no-loop-func': 2,
+    'no-multi-spaces': 2,
+    'no-multi-str': 2,
+    'no-native-reassign': 2,
+    'no-new': 2,
+    'no-new-func': 2,
+    'no-new-wrappers': 2,
+    'no-octal': 2,
+    'no-octal-escape': 2,
+    'no-proto': 2,
+    'no-redeclare': 2,
+    'no-script-url': 2,
+    'no-self-compare': 2,
+    'no-sequences': 2,
+    'no-throw-literal': 2,
+    'no-void': 2,
+    'no-warning-comments': [0, { terms: ['todo', 'fixme'], location: 'start' }],
+    'no-with': 2,
+    'radix': 2,
+    'vars-on-top': 2,
+    'wrap-iife': 2,
+    'yoda': 2,
+
+    // Strict Mode
+    // These rules relate to using strict mode.
+    'strict': 0,
+
+    // Variables
+    // These rules have to do with variable declarations.
+    'no-catch-shadow': 2,
+    'no-delete-var': 2,
+    'no-label-var': 2,
+    'no-shadow': 2,
+    'no-shadow-restricted-names': 2,
+    'no-undef': 2,
+    'no-unused-vars': ['warn', { argsIgnorePattern: '^_' }],
+    'no-use-before-define': 2,
+
+    // Stylistic Issues
+    // These rules are purely matters of style and are quite subjective.
+    'indent': [1, 2],
+    'brace-style': ['error', 'stroustrup'],
+    'camelcase': 1,
+    'comma-spacing': [1, { before: false, after: true }],
+    'comma-style': [1, 'last'],
+    'consistent-this': [1, '_this'],
+    'eol-last': 1,
+    'key-spacing': [1, { beforeColon: false, afterColon: true }],
+    'new-cap': [1, { newIsCap: true, capIsNew: false }],
+    'new-parens': 1,
+    'newline-after-var': 0,
+    'no-array-constructor': 1,
+    'no-mixed-spaces-and-tabs': 1,
+    'no-multiple-empty-lines': [1, { max: 2 }],
+    'no-trailing-spaces': 1,
+    'no-underscore-dangle': 1,
+    'quote-props': [1, 'consistent'],
+    'quotes': [1, 'single'],
+    'semi': ['error', 'never'],
+    'keyword-spacing': 'warn',
+    'space-before-function-paren': [1, { anonymous: 'always', named: 'never' }],
+    'space-in-parens': [1, 'never'],
+    'spaced-comment': 'warn',
+
+    // ECMAScript 6
+    // These rules are only relevant to ES6 environments and are off by default.
+    'no-var': 2
+  }
+}

+ 23 - 0
.gitignore

@@ -0,0 +1,23 @@
+.DS_Store
+node_modules
+package-lock.json
+
+# local env files
+.env.local
+.env.*.local
+
+# Log files
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.sw*
+
+/searches

+ 21 - 0
LICENSE

@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Prise3D
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.

+ 38 - 0
README.md

@@ -0,0 +1,38 @@
+# wepexpe-data-extract
+
+## Install
+```sh
+yarn add https://gogs.univ-littoral.fr/Prise3D/webexpe-data-extract.git
+```
+
+## Usage
+```js
+'use strict'
+
+const path = require('path')
+const { db, utils } = require('webexpe-data-extract')
+
+const setup = async () => {
+  const connection = await db.connect('mongodb://diran.univ-littoral.fr:27017/webexpe')
+
+  const res = await db.Data.findCustom({
+    msgId: 'EXPERIMENT_DATA'
+  })
+
+  console.log(res)
+  console.log(`Found ${res.length} documents matching your request.`)
+
+  const filePath = path.resolve(__dirname, 'searches', `search-${Date.now()}.json`)
+  await utils.outputToFile(res, filePath, true)
+  console.log(`Your search result was saved to ${filePath}`)
+
+  await db.disconnect(connection)
+}
+
+setup()
+```
+
+## API
+See [`/lib/db/Data/controller.js#L56-L76`](./lib/db/Data/controller.js#L56-L76).
+
+Every functions should be auto-completable in your editor.

+ 23 - 0
example.js

@@ -0,0 +1,23 @@
+'use strict'
+
+const path = require('path')
+const { db, utils } = require('./lib')
+
+const setup = async () => {
+  const connection = await db.connect('mongodb://diran.univ-littoral.fr:27017/webexpe')
+
+  const res = await db.Data.findCustom({
+    msgId: 'EXPERIMENT_DATA'
+  })
+
+  console.log(res)
+  console.log(`Found ${res.length} documents matching your request.`)
+
+  const filePath = path.resolve(__dirname, 'searches', `search-${Date.now()}.json`)
+  await utils.outputToFile(res, filePath, true)
+  console.log(`Your search result was saved to ${filePath}`)
+
+  await db.disconnect(connection)
+}
+
+setup()

+ 74 - 0
lib/db/Data/controller.js

@@ -0,0 +1,74 @@
+'use strict'
+
+const DataModel = require('./model')
+
+// Data controller
+module.exports = {
+  Model: DataModel,
+
+  /**
+   * Add a document
+   * @param {Object} dataObj The new data document (only the data property!)
+   * @returns {Promise<Object>} The newly inserted document
+   */
+  async add(dataObj) {
+    const doc = await DataModel.create({ data: dataObj })
+    console.log(`New document was added. id=${doc.id}`)
+    return doc
+  },
+
+  /**
+   * Delete a document
+   * @param {String} dataId The _id of the document to delete
+   * @returns {Promise<void>} The document was deleted
+   */
+  async del(dataId) {
+    const doc = await DataModel.findByIdAndDelete(dataId)
+    console.log(`A document was deleted. id=${doc.id}`)
+  },
+
+  /**
+   * Update a document
+   * @param {String} dataId The _id of the document to update
+   * @param {Object} newDataObj The new data content of the document (only the data property!)
+   * @returns {Promise<Object>} The newly updated document
+   */
+  async update(dataId, newDataObj) {
+    const doc = await DataModel.findByIdAndUpdate(dataId, { $set: { data: newDataObj } }, { new: true })
+    console.log(`A document was updated. id=${doc.id}`)
+    return doc
+  },
+
+  /**
+   * Find a document
+   * @param {String} dataId The _id of the document to find
+   * @returns {Promise<Object>} The found document
+   */
+  findId(dataId) {
+    return DataModel.findById(dataId)
+  },
+
+  find: DataModel.find,
+
+  /**
+   * Find data by any application parameter
+   * @param {Object} obj Application properties
+   * @param {String} [obj.msgId] Message ID (type of message)
+   * @param {String} [obj.uuid] Unique uuid
+   * @param {String} [obj.experimentName] Experiment name
+   * @param {String} [obj.sceneName] Scene name
+   * @param {String} [obj.userId] User ID
+   * @param {String} [obj.experimentId] Experiment ID
+   * @returns {Promise<Object[]>} Database query result
+   */
+  findCustom({ msgId, uuid, experimentName, sceneName, userId, experimentId }) {
+    let search = {}
+    if (msgId) search['data.msgId'] = msgId
+    if (uuid) search['data.uuid'] = uuid
+    if (experimentName) search['data.msg.experimentName'] = experimentName
+    if (sceneName) search['data.msg.sceneName'] = sceneName
+    if (userId) search['data.userId'] = userId
+    if (experimentId) search['data.experimentId'] = experimentId
+    return DataModel.find(search)
+  }
+}

+ 3 - 0
lib/db/Data/index.js

@@ -0,0 +1,3 @@
+'use strict'
+
+module.exports = require('./controller')

+ 11 - 0
lib/db/Data/model.js

@@ -0,0 +1,11 @@
+'use strict'
+
+const mongoose = require('mongoose')
+
+module.exports = mongoose.model('Data', mongoose.Schema({
+  date: {
+    type: Date,
+    default: () => new Date()
+  },
+  data: Object
+}))

+ 29 - 0
lib/db/index.js

@@ -0,0 +1,29 @@
+'use strict'
+
+const mongoose = require('mongoose')
+const Data = require('./Data')
+
+module.exports = {
+  /**
+   * Connect to MongoDB
+   * @param {String} mongoConnectionString MongoDB connection string
+   * @returns {Object} Connecion object
+   */
+  async connect(mongoConnectionString) {
+    const connection = await mongoose.connect(mongoConnectionString, { useNewUrlParser: true, useFindAndModify: false })
+    mongoose.connection.on('error', err => console.log(err))
+    console.log('The database connection was established.')
+    return connection
+  },
+
+  /**
+   * Disconnect from MongoDB
+   * @param {Object} connectionObj Connecion object
+   * @returns {Promise<void>} The connection was destroyed
+   */
+  async disconnect(connectionObj) {
+    await connectionObj.disconnect()
+    console.log('The database connection was destroyed.')
+  },
+  Data
+}

+ 9 - 0
lib/index.js

@@ -0,0 +1,9 @@
+'use strict'
+
+const db = require('./db')
+const utils = require('./utils')
+
+module.exports = {
+  db,
+  utils
+}

+ 17 - 0
lib/utils.js

@@ -0,0 +1,17 @@
+'use strict'
+
+const fs = require('fs-extra')
+
+/**
+ * Save a search result o to a JSON file
+ * @param {Object[]} obj Your JavaScript object
+ * @param {String} path Output path
+ * @param {Boolean} prettyPrint Should the JSON be pretty-printed
+ * @returns {Promise<void>} Newly created file path
+ */
+const outputToFile = async (obj, path, prettyPrint) => {
+  await fs.ensureFile(path)
+  await fs.outputJson(path, obj, { spaces: prettyPrint ? 2 : undefined })
+}
+
+module.exports = { outputToFile }

+ 16 - 0
package.json

@@ -0,0 +1,16 @@
+{
+  "name": "webexpe-data-extract",
+  "version": "0.1.0",
+  "private": true,
+  "main": "lib/index.js",
+  "directories": {
+    "lib": "lib"
+  },
+  "scripts": {
+    "example": "node example.js"
+  },
+  "dependencies": {
+    "fs-extra": "^8.0.1",
+    "mongoose": "^5.5.5"
+  }
+}

+ 189 - 0
yarn.lock

@@ -0,0 +1,189 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+async@2.6.2:
+  version "2.6.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-2.6.2.tgz#18330ea7e6e313887f5d2f2a904bac6fe4dd5381"
+  integrity sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==
+  dependencies:
+    lodash "^4.17.11"
+
+bluebird@3.5.1:
+  version "3.5.1"
+  resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
+  integrity sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==
+
+bson@^1.1.1, bson@~1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.1.tgz#4330f5e99104c4e751e7351859e2d408279f2f13"
+  integrity sha512-jCGVYLoYMHDkOsbwJZBCqwMHyH4c+wzgI9hG7Z6SZJRXWr+x58pdIbm2i9a/jFGCkRJqRUr8eoI7lDWa0hTkxg==
+
+debug@3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
+  integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==
+  dependencies:
+    ms "2.0.0"
+
+fs-extra@^8.0.1:
+  version "8.0.1"
+  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.0.1.tgz#90294081f978b1f182f347a440a209154344285b"
+  integrity sha512-W+XLrggcDzlle47X/XnS7FXrXu9sDo+Ze9zpndeBxdgv88FHLm1HtmkhEwavruS6koanBjp098rUpHs65EmG7A==
+  dependencies:
+    graceful-fs "^4.1.2"
+    jsonfile "^4.0.0"
+    universalify "^0.1.0"
+
+graceful-fs@^4.1.2, graceful-fs@^4.1.6:
+  version "4.1.15"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.15.tgz#ffb703e1066e8a0eeaa4c8b80ba9253eeefbfb00"
+  integrity sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==
+
+jsonfile@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
+  integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
+  optionalDependencies:
+    graceful-fs "^4.1.6"
+
+kareem@2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/kareem/-/kareem-2.3.0.tgz#ef33c42e9024dce511eeaf440cd684f3af1fc769"
+  integrity sha512-6hHxsp9e6zQU8nXsP+02HGWXwTkOEw6IROhF2ZA28cYbUk4eJ6QbtZvdqZOdD9YPKghG3apk5eOCvs+tLl3lRg==
+
+lodash@^4.17.11:
+  version "4.17.11"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.11.tgz#b39ea6229ef607ecd89e2c8df12536891cac9b8d"
+  integrity sha512-cQKh8igo5QUhZ7lg38DYWAxMvjSAKG0A8wGSVimP07SIUEK2UO+arSRKbRZWtelMtN5V0Hkwh5ryOto/SshYIg==
+
+memory-pager@^1.0.2:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/memory-pager/-/memory-pager-1.5.0.tgz#d8751655d22d384682741c972f2c3d6dfa3e66b5"
+  integrity sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==
+
+mongodb-core@3.2.6:
+  version "3.2.6"
+  resolved "https://registry.yarnpkg.com/mongodb-core/-/mongodb-core-3.2.6.tgz#5522b721a744720a27a07b29177d10fe849ad20e"
+  integrity sha512-i+XRVjur9D0ywGF7cFebOUnALnbvMHajdNhhl3TQuopW6QDE655G8CpPeERbqSqfa3rOKEUo08lENDIiBIuAvQ==
+  dependencies:
+    bson "^1.1.1"
+    require_optional "^1.0.1"
+    safe-buffer "^5.1.2"
+  optionalDependencies:
+    saslprep "^1.0.0"
+
+mongodb@3.2.6:
+  version "3.2.6"
+  resolved "https://registry.yarnpkg.com/mongodb/-/mongodb-3.2.6.tgz#bfd23bc0ae6cc57443cd256aec24aa4dc2b99f2f"
+  integrity sha512-qnHc4tjEkHKemuzBq9R7ycYnhFE0Dlpt6+n6suoZp2DcDdqviQ+teloJU24fsOw/PLmr75yGk4mRx/YabjDQEQ==
+  dependencies:
+    mongodb-core "3.2.6"
+    safe-buffer "^5.1.2"
+
+mongoose-legacy-pluralize@1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/mongoose-legacy-pluralize/-/mongoose-legacy-pluralize-1.0.2.tgz#3ba9f91fa507b5186d399fb40854bff18fb563e4"
+  integrity sha512-Yo/7qQU4/EyIS8YDFSeenIvXxZN+ld7YdV9LqFVQJzTLye8unujAWPZ4NWKfFA+RNjh+wvTWKY9Z3E5XM6ZZiQ==
+
+mongoose@^5.5.5:
+  version "5.5.12"
+  resolved "https://registry.yarnpkg.com/mongoose/-/mongoose-5.5.12.tgz#02c96a8bbddbb73f8b86e0c6e44c61288b584430"
+  integrity sha512-G6KfSHfxfoBw7zpRRdbG1GzLZSkY71nY3CMHMMfg5o+xVAGc3Q78Qu+kA3P+Ka15KHLu6LNyvAc1Zvtv1JhGfw==
+  dependencies:
+    async "2.6.2"
+    bson "~1.1.1"
+    kareem "2.3.0"
+    mongodb "3.2.6"
+    mongodb-core "3.2.6"
+    mongoose-legacy-pluralize "1.0.2"
+    mpath "0.6.0"
+    mquery "3.2.0"
+    ms "2.1.1"
+    regexp-clone "0.0.1"
+    safe-buffer "5.1.2"
+    sift "7.0.1"
+    sliced "1.0.1"
+
+mpath@0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/mpath/-/mpath-0.6.0.tgz#aa922029fca4f0f641f360e74c5c1b6a4c47078e"
+  integrity sha512-i75qh79MJ5Xo/sbhxrDrPSEG0H/mr1kcZXJ8dH6URU5jD/knFxCVqVC/gVSW7GIXL/9hHWlT9haLbCXWOll3qw==
+
+mquery@3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/mquery/-/mquery-3.2.0.tgz#e276472abd5109686a15eb2a8e0761db813c81cc"
+  integrity sha512-qPJcdK/yqcbQiKoemAt62Y0BAc0fTEKo1IThodBD+O5meQRJT/2HSe5QpBNwaa4CjskoGrYWsEyjkqgiE0qjhg==
+  dependencies:
+    bluebird "3.5.1"
+    debug "3.1.0"
+    regexp-clone "0.0.1"
+    safe-buffer "5.1.2"
+    sliced "1.0.1"
+
+ms@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+  integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+  integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
+regexp-clone@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-0.0.1.tgz#a7c2e09891fdbf38fbb10d376fb73003e68ac589"
+  integrity sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk=
+
+require_optional@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/require_optional/-/require_optional-1.0.1.tgz#4cf35a4247f64ca3df8c2ef208cc494b1ca8fc2e"
+  integrity sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==
+  dependencies:
+    resolve-from "^2.0.0"
+    semver "^5.1.0"
+
+resolve-from@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57"
+  integrity sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=
+
+safe-buffer@5.1.2, safe-buffer@^5.1.2:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+  integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+saslprep@^1.0.0:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/saslprep/-/saslprep-1.0.3.tgz#4c02f946b56cf54297e347ba1093e7acac4cf226"
+  integrity sha512-/MY/PEMbk2SuY5sScONwhUDsV2p77Znkb/q3nSVstq/yQzYJOH/Azh29p9oJLsl3LnQwSvZDKagDGBsBwSooag==
+  dependencies:
+    sparse-bitfield "^3.0.3"
+
+semver@^5.1.0:
+  version "5.7.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
+  integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
+
+sift@7.0.1:
+  version "7.0.1"
+  resolved "https://registry.yarnpkg.com/sift/-/sift-7.0.1.tgz#47d62c50b159d316f1372f8b53f9c10cd21a4b08"
+  integrity sha512-oqD7PMJ+uO6jV9EQCl0LrRw1OwsiPsiFQR5AR30heR+4Dl7jBBbDLnNvWiak20tzZlSE1H7RB30SX/1j/YYT7g==
+
+sliced@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/sliced/-/sliced-1.0.1.tgz#0b3a662b5d04c3177b1926bea82b03f837a2ef41"
+  integrity sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=
+
+sparse-bitfield@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz#ff4ae6e68656056ba4b3e792ab3334d38273ca11"
+  integrity sha1-/0rm5oZWBWuks+eSqzM004JzyhE=
+  dependencies:
+    memory-pager "^1.0.2"
+
+universalify@^0.1.0:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
+  integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==