diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000000..1efb79d093 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,17 @@ +{ + "extends": [ + "eslint:recommended", + "standard", + "prettier" + ], + "parserOptions": { + "ecmaVersion": 2018 + }, + "env": { + "node": true + }, + "rules": { + // Do not allow importing of implicit dependencies. + "import/no-extraneous-dependencies": "error" + } +} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000000..e692368d0e --- /dev/null +++ b/.prettierrc @@ -0,0 +1,8 @@ +{ + "arrowParens": "avoid", + "semi": false, + "singleQuote": true, + "trailingComma": "es5", + "tabWidth": 2, + "useTabs": false +} diff --git a/Dockerfile b/Dockerfile index ace431967f..33f2e0baab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,7 +5,7 @@ ARG SHARELATEX_BASE_TAG=sharelatex/sharelatex-base:latest FROM $SHARELATEX_BASE_TAG -ENV SHARELATEX_CONFIG /etc/sharelatex/settings.coffee +ENV SHARELATEX_CONFIG /etc/sharelatex/settings.js # Add required source files @@ -13,7 +13,7 @@ ENV SHARELATEX_CONFIG /etc/sharelatex/settings.coffee ADD ${baseDir}/bin /var/www/sharelatex/bin ADD ${baseDir}/doc /var/www/sharelatex/doc ADD ${baseDir}/tasks /var/www/sharelatex/tasks -ADD ${baseDir}/Gruntfile.coffee /var/www/sharelatex/Gruntfile.coffee +ADD ${baseDir}/Gruntfile.js /var/www/sharelatex/Gruntfile.js ADD ${baseDir}/package.json /var/www/sharelatex/package.json ADD ${baseDir}/package-lock.json /var/www/sharelatex/package-lock.json ADD ${baseDir}/services.js /var/www/sharelatex/config/services.js @@ -85,7 +85,7 @@ COPY ${baseDir}/init_scripts/ /etc/my_init.d/ # Copy app settings files # ----------------------- -COPY ${baseDir}/settings.coffee /etc/sharelatex/settings.coffee +COPY ${baseDir}/settings.js /etc/sharelatex/settings.js # Set Environment Variables # -------------------------------- diff --git a/Gruntfile.coffee b/Gruntfile.coffee deleted file mode 100644 index 9375096d62..0000000000 --- a/Gruntfile.coffee +++ /dev/null @@ -1,216 +0,0 @@ -coffee = require("coffee-script") -fs = require "fs" -spawn = require("child_process").spawn -exec = require("child_process").exec -rimraf = require "rimraf" -Path = require "path" -semver = require "semver" -knox = require "knox" -crypto = require "crypto" -async = require "async" -settings = require("settings-sharelatex") -_ = require("underscore") - - -SERVICES = require("./config/services") - -module.exports = (grunt) -> - grunt.loadNpmTasks 'grunt-bunyan' - grunt.loadNpmTasks 'grunt-execute' - grunt.loadNpmTasks 'grunt-available-tasks' - grunt.loadNpmTasks 'grunt-concurrent' - grunt.loadNpmTasks "grunt-contrib-coffee" - grunt.loadNpmTasks "grunt-shell" - - grunt.task.loadTasks "./tasks" - - execute = {} - for service in SERVICES - execute[service.name] = - src: "#{service.name}/app.js" - - grunt.initConfig - execute: execute - - concurrent: - all: - tasks: ("run:#{service.name}" for service in SERVICES) - options: - limit: SERVICES.length - logConcurrentOutput: true - - availabletasks: - tasks: - options: - filter: 'exclude', - tasks: [ - 'concurrent' - 'execute' - 'bunyan' - 'availabletasks' - ] - groups: - "Run tasks": [ - "run" - "run:all" - "default" - ].concat ("run:#{service.name}" for service in SERVICES) - "Misc": [ - "help" - ] - "Install tasks": ("install:#{service.name}" for service in SERVICES).concat(["install:all", "install"]) - "Update tasks": ("update:#{service.name}" for service in SERVICES).concat(["update:all", "update"]) - "Checks": ["check", "check:redis", "check:latexmk", "check:s3", "check:make", "check:mongo"] - - for service in SERVICES - do (service) -> - grunt.registerTask "install:#{service.name}", "Download and set up the #{service.name} service", () -> - done = @async() - Helpers.installService(service, done) - - - - grunt.registerTask 'install:all', "Download and set up all ShareLaTeX services", - [].concat( - ("install:#{service.name}" for service in SERVICES) - ).concat(['postinstall']) - - grunt.registerTask 'install', 'install:all' - grunt.registerTask 'postinstall', 'Explain postinstall steps', () -> - Helpers.postinstallMessage @async() - - grunt.registerTask 'update:all', "Checkout and update all ShareLaTeX services", - ["check:make"].concat( - ("update:#{service.name}" for service in SERVICES) - ) - grunt.registerTask 'update', 'update:all' - grunt.registerTask 'run', "Run all of the sharelatex processes", ['concurrent:all'] - grunt.registerTask 'run:all', 'run' - - grunt.registerTask 'help', 'Display this help list', 'availabletasks' - grunt.registerTask 'default', 'run' - - grunt.registerTask "check:redis", "Check that redis is installed and running", () -> - Helpers.checkRedisConnect @async() - - grunt.registerTask "check:mongo", "Check that mongo is installed", () -> - Helpers.checkMongoConnect @async() - - grunt.registerTask "check", "Check that you have the required dependencies installed", ["check:redis", "check:mongo", "check:make"] - - grunt.registerTask "check:make", "Check that make is installed", () -> - Helpers.checkMake @async() - - - Helpers = - installService: (service, callback = (error) ->) -> - console.log "Installing #{service.name}" - Helpers.cloneGitRepo service, (error) -> - if error? - callback(error) - else - callback() - - cloneGitRepo: (service, callback = (error) ->) -> - repo_src = service.repo - dir = service.name - if !fs.existsSync(dir) - proc = spawn "git", [ - "clone", - repo_src, - dir - ], stdio: "inherit" - proc.on "close", () -> - Helpers.checkoutVersion service, callback - else - console.log "#{dir} already installed, skipping." - callback() - - checkoutVersion: (service, callback = (error) ->) -> - dir = service.name - grunt.log.write "checking out #{service.name} #{service.version}" - proc = spawn "git", ["checkout", service.version], stdio: "inherit", cwd: dir - proc.on "close", () -> - callback() - - postinstallMessage: (callback = (error) ->) -> - grunt.log.write """ - Services cloned: - #{service.name for service in SERVICES} - To install services run: - $ source bin/install-services - This will install the required node versions and run `npm install` for each service. - See https://github.com/sharelatex/sharelatex/pull/549 for more info. - """ - callback() - - checkMake: (callback = (error) ->) -> - grunt.log.write "Checking make is installed... " - exec "make --version", (error, stdout, stderr) -> - if error? and error.message.match("not found") - grunt.log.error "FAIL." - grunt.log.errorlns """ - Either make is not installed or is not in your path. - - On Ubuntu you can install make with: - - sudo apt-get install build-essential - - """ - return callback(error) - else if error? - return callback(error) - else - grunt.log.write "OK." - return callback() - checkMongoConnect: (callback = (error) ->) -> - grunt.log.write "Checking can connect to mongo" - mongojs = require("mongojs") - db = mongojs(settings.mongo.url, ["tags"]) - db.runCommand { ping: 1 }, (err, res) -> - if !err and res.ok - grunt.log.write "OK." - return callback() - db.on 'error', (err)-> - err = "Can not connect to mongodb" - grunt.log.error "FAIL." - grunt.log.errorlns """ - !!!!!!!!!!!!!! MONGO ERROR !!!!!!!!!!!!!! - - ShareLaTeX can not talk to the mongodb instance - - Check the mongodb instance is running and accessible on env var SHARELATEX_MONGO_URL - - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - """ - throw new Error("Can not connect to Mongodb") - return callback(err) - - checkRedisConnect: (callback = (error) ->) -> - grunt.log.write "Checking can connect to redis\n" - rclient = require("redis").createClient(settings.redis.web) - - rclient.ping (err, res) -> - if !err? - grunt.log.write "OK." - else - throw new Error("Can not connect to redis") - return callback() - errorHandler = _.once (err)-> - err = "Can not connect to redis" - grunt.log.error "FAIL." - grunt.log.errorlns """ - !!!!!!!!!!!!!! REDIS ERROR !!!!!!!!!!!!!! - - ShareLaTeX can not talk to the redis instance - - Check the redis instance is running and accessible on env var SHARELATEX_REDIS_HOST - - !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - """ - throw new Error("Can not connect to redis") - return callback(err) - rclient.on 'error', errorHandler - - - diff --git a/Gruntfile.js b/Gruntfile.js new file mode 100644 index 0000000000..170ee5b353 --- /dev/null +++ b/Gruntfile.js @@ -0,0 +1,355 @@ +/* eslint-disable + camelcase, + no-return-assign, + no-unreachable, + no-unused-vars, + node/handle-callback-err, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS101: Remove unnecessary use of Array.from + * DS102: Remove unnecessary code created because of implicit returns + * DS103: Rewrite code to no longer use __guard__, or convert again using --optional-chaining + * DS205: Consider reworking code to avoid use of IIFEs + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +const fs = require('fs') +const { spawn } = require('child_process') +const { exec } = require('child_process') +const rimraf = require('rimraf') +const Path = require('path') +const semver = require('semver') +const knox = require('knox') +const crypto = require('crypto') +const async = require('async') +const settings = require('@overleaf/settings') +const _ = require('underscore') + +const SERVICES = require('./config/services') + +module.exports = function (grunt) { + let Helpers + let service + grunt.loadNpmTasks('grunt-bunyan') + grunt.loadNpmTasks('grunt-execute') + grunt.loadNpmTasks('grunt-available-tasks') + grunt.loadNpmTasks('grunt-concurrent') + grunt.loadNpmTasks('grunt-shell') + + grunt.task.loadTasks('./tasks') + + const execute = {} + for (service of Array.from(SERVICES)) { + execute[service.name] = { src: `${service.name}/app.js` } + } + + grunt.initConfig({ + execute, + + concurrent: { + all: { + tasks: (() => { + const result = [] + for (service of Array.from(SERVICES)) { + result.push(`run:${service.name}`) + } + return result + })(), + options: { + limit: SERVICES.length, + logConcurrentOutput: true, + }, + }, + }, + + availabletasks: { + tasks: { + options: { + filter: 'exclude', + tasks: ['concurrent', 'execute', 'bunyan', 'availabletasks'], + groups: { + 'Run tasks': ['run', 'run:all', 'default'].concat( + (() => { + const result1 = [] + for (service of Array.from(SERVICES)) { + result1.push(`run:${service.name}`) + } + return result1 + })() + ), + Misc: ['help'], + 'Install tasks': (() => { + const result2 = [] + for (service of Array.from(SERVICES)) { + result2.push(`install:${service.name}`) + } + return result2 + })().concat(['install:all', 'install']), + 'Update tasks': (() => { + const result3 = [] + for (service of Array.from(SERVICES)) { + result3.push(`update:${service.name}`) + } + return result3 + })().concat(['update:all', 'update']), + Checks: [ + 'check', + 'check:redis', + 'check:latexmk', + 'check:s3', + 'check:make', + 'check:mongo', + ], + }, + }, + }, + }, + }) + + for (service of Array.from(SERVICES)) { + ;(service => + grunt.registerTask( + `install:${service.name}`, + `Download and set up the ${service.name} service`, + function () { + const done = this.async() + return Helpers.installService(service, done) + } + ))(service) + } + + grunt.registerTask( + 'install:all', + 'Download and set up all ShareLaTeX services', + [] + .concat( + (() => { + const result4 = [] + for (service of Array.from(SERVICES)) { + result4.push(`install:${service.name}`) + } + return result4 + })() + ) + .concat(['postinstall']) + ) + + grunt.registerTask('install', 'install:all') + grunt.registerTask('postinstall', 'Explain postinstall steps', function () { + return Helpers.postinstallMessage(this.async()) + }) + + grunt.registerTask( + 'update:all', + 'Checkout and update all ShareLaTeX services', + ['check:make'].concat( + (() => { + const result5 = [] + for (service of Array.from(SERVICES)) { + result5.push(`update:${service.name}`) + } + return result5 + })() + ) + ) + grunt.registerTask('update', 'update:all') + grunt.registerTask('run', 'Run all of the sharelatex processes', [ + 'concurrent:all', + ]) + grunt.registerTask('run:all', 'run') + + grunt.registerTask('help', 'Display this help list', 'availabletasks') + grunt.registerTask('default', 'run') + + grunt.registerTask( + 'check:redis', + 'Check that redis is installed and running', + function () { + return Helpers.checkRedisConnect(this.async()) + } + ) + + grunt.registerTask( + 'check:mongo', + 'Check that mongo is installed', + function () { + return Helpers.checkMongoConnect(this.async()) + } + ) + + grunt.registerTask( + 'check', + 'Check that you have the required dependencies installed', + ['check:redis', 'check:mongo', 'check:make'] + ) + + grunt.registerTask('check:make', 'Check that make is installed', function () { + return Helpers.checkMake(this.async()) + }) + + return (Helpers = { + installService(service, callback) { + if (callback == null) { + callback = function (error) {} + } + console.log(`Installing ${service.name}`) + return Helpers.cloneGitRepo(service, function (error) { + if (error != null) { + return callback(error) + } else { + return callback() + } + }) + }, + + cloneGitRepo(service, callback) { + if (callback == null) { + callback = function (error) {} + } + const repo_src = service.repo + const dir = service.name + if (!fs.existsSync(dir)) { + const proc = spawn('git', ['clone', repo_src, dir], { + stdio: 'inherit', + }) + return proc.on('close', () => + Helpers.checkoutVersion(service, callback) + ) + } else { + console.log(`${dir} already installed, skipping.`) + return callback() + } + }, + + checkoutVersion(service, callback) { + if (callback == null) { + callback = function (error) {} + } + const dir = service.name + grunt.log.write(`checking out ${service.name} ${service.version}`) + const proc = spawn('git', ['checkout', service.version], { + stdio: 'inherit', + cwd: dir, + }) + return proc.on('close', () => callback()) + }, + + postinstallMessage(callback) { + if (callback == null) { + callback = function (error) {} + } + grunt.log.write(`\ +Services cloned: + ${(() => { + const result6 = [] + for (service of Array.from(SERVICES)) { + result6.push(service.name) + } + return result6 + })()} +To install services run: + $ source bin/install-services +This will install the required node versions and run \`npm install\` for each service. +See https://github.com/sharelatex/sharelatex/pull/549 for more info.\ +`) + return callback() + }, + + checkMake(callback) { + if (callback == null) { + callback = function (error) {} + } + grunt.log.write('Checking make is installed... ') + return exec('make --version', function (error, stdout, stderr) { + if (error != null && error.message.match('not found')) { + grunt.log.error('FAIL.') + grunt.log.errorlns(`\ +Either make is not installed or is not in your path. + +On Ubuntu you can install make with: + + sudo apt-get install build-essential +\ +`) + return callback(error) + } else if (error != null) { + return callback(error) + } else { + grunt.log.write('OK.') + return callback() + } + }) + }, + checkMongoConnect(callback) { + if (callback == null) { + callback = function (error) {} + } + grunt.log.write('Checking can connect to mongo') + const mongojs = require('mongojs') + const db = mongojs(settings.mongo.url, ['tags']) + db.runCommand({ ping: 1 }, function (err, res) { + if (!err && res.ok) { + grunt.log.write('OK.') + } + return callback() + }) + return db.on('error', function (err) { + err = 'Can not connect to mongodb' + grunt.log.error('FAIL.') + grunt.log.errorlns(`\ +!!!!!!!!!!!!!! MONGO ERROR !!!!!!!!!!!!!! + +ShareLaTeX can not talk to the mongodb instance + +Check the mongodb instance is running and accessible on env var SHARELATEX_MONGO_URL + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\ +`) + throw new Error('Can not connect to Mongodb') + return callback(err) + }) + }, + + checkRedisConnect(callback) { + if (callback == null) { + callback = function (error) {} + } + grunt.log.write('Checking can connect to redis\n') + const rclient = require('redis').createClient(settings.redis.web) + + rclient.ping(function (err, res) { + if (err == null) { + grunt.log.write('OK.') + } else { + throw new Error('Can not connect to redis') + } + return callback() + }) + const errorHandler = _.once(function (err) { + err = 'Can not connect to redis' + grunt.log.error('FAIL.') + grunt.log.errorlns(`\ +!!!!!!!!!!!!!! REDIS ERROR !!!!!!!!!!!!!! + +ShareLaTeX can not talk to the redis instance + +Check the redis instance is running and accessible on env var SHARELATEX_REDIS_HOST + +!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\ +`) + throw new Error('Can not connect to redis') + return callback(err) + }) + return rclient.on('error', errorHandler) + }, + }) +} + +function __guard__(value, transform) { + return typeof value !== 'undefined' && value !== null + ? transform(value) + : undefined +} diff --git a/bin/compile-services b/bin/compile-services index 4045a49a4c..2ebde44826 100755 --- a/bin/compile-services +++ b/bin/compile-services @@ -2,19 +2,18 @@ set -e -grep 'name:' config/services.js | \ - sed 's/.*name: "\(.*\)",/\1/' | \ +node ./config/services.js | \ while read service do pushd $service echo "Compiling Service $service" - case $service in + case $service in web) npm run webpack:production ;; *) echo "$service doesn't require a compilation" ;; - esac + esac popd done diff --git a/bin/install-services b/bin/install-services index becf174cc1..591fb3354b 100755 --- a/bin/install-services +++ b/bin/install-services @@ -2,8 +2,7 @@ set -e -grep 'name:' config/services.js | \ - sed 's/.*name: "\(.*\)",/\1/' | \ +node ./config/services.js | \ while read service do pushd $service diff --git a/package-lock.json b/package-lock.json index 62038e3213..3331f87502 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4,18 +4,194 @@ "lockfileVersion": 1, "requires": true, "dependencies": { + "@babel/code-frame": { + "version": "7.12.11", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", + "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.10.4" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.5.tgz", + "integrity": "sha512-5lsetuxCLilmVGyiLEfoHBRX8UCFD+1m2x3Rj97WrW3V7H3u4RWRXA4evMjImCsin2J2YT0QaVDGf+z8ondbAg==", + "dev": true + }, + "@babel/highlight": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", + "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.14.5", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "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=" + } + } + }, + "@eslint/eslintrc": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-0.4.2.tgz", + "integrity": "sha512-8nmGq/4ycLpIwzvhI4tNDmQztZ8sp+hI7cyG8i1nQDhkAbRzHpXPidRAHlNvCZQpJTKw5ItIpMw9RSToGF00mg==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.1.1", + "espree": "^7.3.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz", + "integrity": "sha512-FagtKFz74XrTl7y6HCzQpwDfXP0yhxe9lHLD1UZxjvZIcbyRz8zTFF/yYNfSfzU414eDwZ1SrO0Qvtyf+wFMQg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.0", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.0.tgz", + "integrity": "sha512-wdppn25U8z/2yiaT6YGquE6X8sSv7hNMWSXYSSU1jGv/yd6XqjXgTDJ8KP4NgjTXfJ3GbRjeeb8RTV7a/VpM+w==", + "dev": true + }, + "@overleaf/settings": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@overleaf/settings/-/settings-2.1.1.tgz", + "integrity": "sha512-vcJwqCGFKmQxTP/syUqCeMaSRjHmBcQgKOACR9He2uJcErg2GZPa1go+nGvszMbkElM4HfRKm/MfxvqHhoN4TQ==" + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, - "ansi-styles": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.0.0.tgz", - "integrity": "sha1-yxAt8cVvUSPquLZ817mAJ6AnkXg=", + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", "dev": true }, + "acorn-jsx": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.1.tgz", + "integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==", + "dev": true + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", + "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, "argparse": { "version": "0.1.16", "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", @@ -40,6 +216,59 @@ } } }, + "array-differ": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", + "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" + }, + "array-includes": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.3.tgz", + "integrity": "sha512-gcem1KlBU7c9rB+Rq8/3PPKsK2kjqeEBa3bD5kkQo4nYlOHQCJqIJFqBXDEfwaRuYTT4E+FxA9xez7Gf/e3Q7A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.2", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.5" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "requires": { + "array-uniq": "^1.0.1" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" + }, + "array.prototype.flat": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.4.tgz", + "integrity": "sha512-4470Xi3GAPAjZqFcljX2xzckv1qeKPizoNkiS0+O4IoPR2ZNpcjE0pkhdihlDouK+x6QOast26B4Q/O9DJnwSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.0-next.1" + } + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true + }, "async": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz", @@ -49,15 +278,13 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -78,15 +305,30 @@ "mv": "~2" } }, - "chalk": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.4.0.tgz", - "integrity": "sha1-UZmj3c0MHv4jvAjBsCewYXbgxk8=", + "call-bind": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", + "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", "dev": true, "requires": { - "ansi-styles": "~1.0.0", - "has-color": "~0.1.0", - "strip-ansi": "~0.1.0" + "function-bind": "^1.1.1", + "get-intrinsic": "^1.0.2" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "supports-color": "^5.3.0" } }, "coffee-script": { @@ -94,18 +336,40 @@ "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.12.7.tgz", "integrity": "sha512-fLeEhqwymYat/MpTPUjSKHVYYl0ec2mOyALEMLmzr5i1isuG+6jfI2j2d5oBO3VIzgUXgBVIcOT9uH1TFxBckw==" }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, "colors": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", "dev": true }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "requires": { + "graceful-readlink": ">= 1.0.0" + } + }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -113,6 +377,48 @@ "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", "dev": true }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "cson": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/cson/-/cson-3.0.2.tgz", + "integrity": "sha1-g+6Qids8JUvsHpjkmNmqzxGtzFQ=", + "requires": { + "coffee-script": "^1.9.0", + "cson-parser": "^1.0.6", + "extract-opts": "^3.0.1", + "requirefresh": "^2.0.0", + "safefs": "^4.0.0" + } + }, + "cson-parser": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/cson-parser/-/cson-parser-1.3.5.tgz", + "integrity": "sha1-fsZ14DkUVTO/KmqFYHPxWZ2cLSQ=", + "requires": { + "coffee-script": "^1.10.0" + } + }, "dateformat": { "version": "1.0.2-1.2.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", @@ -125,6 +431,35 @@ "integrity": "sha1-BuHqgILCyxTjmAbiLi9vdX+Srzk=", "dev": true }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "double-ended-queue": { + "version": "2.1.0-0", + "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", + "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" + }, "dtrace-provider": { "version": "0.2.8", "resolved": "https://registry.npmjs.org/dtrace-provider/-/dtrace-provider-0.2.8.tgz", @@ -132,6 +467,20 @@ "dev": true, "optional": true }, + "each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/each-series/-/each-series-1.0.0.tgz", + "integrity": "sha1-+Ibmxm39sl7x/nNWQUbuXLR4r8s=" + }, + "eachr": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eachr/-/eachr-3.2.0.tgz", + "integrity": "sha1-LDXkPqCGUW95l8+At6pk1VpKRIQ=", + "requires": { + "editions": "^1.1.1", + "typechecker": "^4.3.0" + } + }, "east": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/east/-/east-0.5.7.tgz", @@ -143,35 +492,10 @@ "twostep": "0.4.2" }, "dependencies": { - "commander": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", - "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", - "requires": { - "graceful-readlink": ">= 1.0.0" - }, - "dependencies": { - "graceful-readlink": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", - "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" - } - } - }, - "expressionify": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/expressionify/-/expressionify-0.9.3.tgz", - "integrity": "sha1-/iJnx+hpRXfxP02oML/DyNgXf5I=" - }, "progress": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz", "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=" - }, - "twostep": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/twostep/-/twostep-0.4.2.tgz", - "integrity": "sha1-hLxQh6hxV00ev3vjB54D4SLUFbY=" } } }, @@ -180,12 +504,544 @@ "resolved": "https://registry.npmjs.org/east-mongo/-/east-mongo-0.3.3.tgz", "integrity": "sha1-WKtCdGaRy+ITtBweiG8EttyCq8A=" }, + "editions": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", + "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==" + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.3.tgz", + "integrity": "sha512-nQIr12dxV7SSxE6r6f1l3DtAeEYdsGpps13dR0TwJg1S8gyp4ZPgy3FZcHBgbiQqnoqSTb+oC+kO4UQ0C/J8vw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.3", + "is-string": "^1.0.6", + "object-inspect": "^1.10.3", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es6-promise": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", + "integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q=" + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint": { + "version": "7.30.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-7.30.0.tgz", + "integrity": "sha512-VLqz80i3as3NdloY44BQSJpFw534L9Oh+6zJOUaViV4JPd+DaHwutqP7tcpkW3YiXbK6s05RZl7yl7cQn+lijg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.12.11", + "@eslint/eslintrc": "^0.4.2", + "@humanwhocodes/config-array": "^0.5.0", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.0.1", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^2.1.0", + "eslint-visitor-keys": "^2.0.0", + "espree": "^7.3.1", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^5.1.2", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^3.13.1", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.1.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.0", + "strip-json-comments": "^3.1.0", + "table": "^6.0.9", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "chalk": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true + }, + "eslint-config-standard": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", + "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==", + "dev": true + }, + "eslint-import-resolver-node": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.4.tgz", + "integrity": "sha512-ogtf+5AB/O+nM6DIeBUNr2fuT7ot9Qg/1harBfBtaP13ekEWFQEEMP94BCB7zaNW3gyY+8SHYF00rnqYwXKWOA==", + "dev": true, + "requires": { + "debug": "^2.6.9", + "resolve": "^1.13.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.6.1.tgz", + "integrity": "sha512-ZXI9B8cxAJIH4nfkhTwcRTEAnrVfobYqwjWy/QMCZ8rHkZHFjf9yO4BzpiF9kCSfNlMG54eKigISHpX0+AaT4A==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "pkg-dir": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "eslint-plugin-chai-expect": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-chai-expect/-/eslint-plugin-chai-expect-2.2.0.tgz", + "integrity": "sha512-ExTJKhgeYMfY8wDj3UiZmgpMKJOUHGNHmWMlxT49JUDB1vTnw0sSNfXJSxnX+LcebyBD/gudXzjzD136WqPJrQ==", + "dev": true + }, + "eslint-plugin-chai-friendly": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-chai-friendly/-/eslint-plugin-chai-friendly-0.6.0.tgz", + "integrity": "sha512-Uvvv1gkbRGp/qfN15B0kQyQWg+oFA8buDSqrwmW3egNSk/FpqH2MjQqKOuKwmEL6w4QIQrIjDp+gg6kGGmD3oQ==", + "dev": true + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + } + }, + "eslint-plugin-import": { + "version": "2.23.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.23.4.tgz", + "integrity": "sha512-6/wP8zZRsnQFiR3iaPFgh5ImVRM1WN5NUWfTIRqwOdeiGJlBcSk82o1FEVq8yXmy4lkIzTo7YhHCIxlU/2HyEQ==", + "dev": true, + "requires": { + "array-includes": "^3.1.3", + "array.prototype.flat": "^1.2.4", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.4", + "eslint-module-utils": "^2.6.1", + "find-up": "^2.0.0", + "has": "^1.0.3", + "is-core-module": "^2.4.0", + "minimatch": "^3.0.4", + "object.values": "^1.1.3", + "pkg-up": "^2.0.0", + "read-pkg-up": "^3.0.0", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.9.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "eslint-plugin-mocha": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-mocha/-/eslint-plugin-mocha-8.2.0.tgz", + "integrity": "sha512-8oOR47Ejt+YJPNQzedbiklDqS1zurEaNrxXpRs+Uk4DMDPVmKNagShFeUaYsfvWP55AhI+P1non5QZAHV6K78A==", + "dev": true, + "requires": { + "eslint-utils": "^2.1.0", + "ramda": "^0.27.1" + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.8", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz", + "integrity": "sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw==", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-4.3.1.tgz", + "integrity": "sha512-bY2sGqyptzFBDLh/GMbAxfdJC+b0f23ME63FOE4+Jao0oZ3E1LEwFtWJX/1pGMJLiTtrSSern2CRM/g+dfc0eQ==", + "dev": true + }, + "eslint-plugin-standard": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-standard/-/eslint-plugin-standard-5.0.0.tgz", + "integrity": "sha512-eSIXPc9wBM4BrniMzJRBm2uoVuXz2EPa+NXPk2+itrVt+r5SbKFERx/IgrK/HmfjddyKVz2f+j+7gBRvu19xLg==", + "dev": true + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-7.3.1.tgz", + "integrity": "sha512-v3JCNCE64umkFpmkFGqzVKsOT0tN1Zr+ueqLZfpV1Ob8e+CEgPWa+OxCoGH3tnhimMKIaBm4m/vaRpJ/krRz2g==", + "dev": true, + "requires": { + "acorn": "^7.4.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^1.3.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, "esprima": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", "dev": true }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, "eventemitter2": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", @@ -198,6 +1054,57 @@ "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", "dev": true }, + "expressionify": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/expressionify/-/expressionify-0.9.3.tgz", + "integrity": "sha1-/iJnx+hpRXfxP02oML/DyNgXf5I=" + }, + "extract-opts": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/extract-opts/-/extract-opts-3.3.1.tgz", + "integrity": "sha1-WrvtyYwNUgLjJ4cn+Rktfghsa+E=", + "requires": { + "eachr": "^3.2.0", + "editions": "^1.1.1", + "typechecker": "^4.3.0" + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, "findup-sync": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", @@ -236,6 +1143,85 @@ } } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "flatted": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.0.tgz", + "integrity": "sha512-XprP7lDrVT+kE2c2YlfiV+IfS9zxukiIOvNamPNsImNhXadSsQEbosItdL9bUQlCZXR13SvPk20BjWSWLA7m4A==", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "get-intrinsic": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", + "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.1" + } + }, "getobject": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", @@ -261,12 +1247,35 @@ } } }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "globals": { + "version": "13.10.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.10.0.tgz", + "integrity": "sha512-piHC3blgLGFjvOuMmWZX60f+na1lXFDhQXBf1UYp2fXPXqvEUbOhNwi6BsQ0bQishwedgnjkwv1d9zKf+MWw3g==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, "graceful-fs": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", "dev": true }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=" + }, "grunt": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", @@ -374,40 +1383,6 @@ } } }, - "grunt-contrib-coffee": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-coffee/-/grunt-contrib-coffee-0.10.1.tgz", - "integrity": "sha1-7SLGgp9FiqjqR/hnaEM+mBMUAYY=", - "dev": true, - "requires": { - "chalk": "~0.4.0", - "coffee-script": "~1.7.0", - "lodash": "~2.4.1" - }, - "dependencies": { - "coffee-script": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.7.1.tgz", - "integrity": "sha1-YplqhheAx15tUGnROCJyO3NAS/w=", - "dev": true, - "requires": { - "mkdirp": "~0.3.5" - } - }, - "lodash": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", - "dev": true - }, - "mkdirp": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.5.tgz", - "integrity": "sha1-3j5fiWHIjHh+4TaN+EmsRBPsqNc=", - "dev": true - } - } - }, "grunt-execute": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/grunt-execute/-/grunt-execute-0.1.5.tgz", @@ -563,33 +1538,34 @@ "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" } } - }, - "npm-run-path": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-1.0.0.tgz", - "integrity": "sha1-9cMr9ZX+ga6Sfa7FLoL4sACsPI8=", - "requires": { - "path-key": "^1.0.0" - }, - "dependencies": { - "path-key": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz", - "integrity": "sha1-XVPVeAGWRsDWiADbThRua9wqx68=" - } - } - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" } } }, - "has-color": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/has-color/-/has-color-0.1.7.tgz", - "integrity": "sha1-ZxRKUmDDT8PMpnfQQdr1L+e3iy8=", + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", "dev": true }, "hooker": { @@ -598,18 +1574,45 @@ "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", "dev": true }, + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, "iconv-lite": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=", "dev": true }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", "dev": true, - "optional": true, "requires": { "once": "^1.3.0", "wrappy": "1" @@ -621,12 +1624,129 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-bigint": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.2.tgz", + "integrity": "sha512-0JV5+SOCQkIdzjBK9buARcV804Ddu7A0Qet6sHi3FimE9ne6m4BGQZfRn+NZiXbBk4F4XmHfDZIipLj9pX8dSA==", + "dev": true + }, + "is-boolean-object": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.1.tgz", + "integrity": "sha512-bXdQWkECBUIAcCkeH1unwJLIpZYaa5VvuygSyS/c2lf719mTKZDU5UdDRlpd01UjADgmW8RfqaP+mRaVPdr/Ng==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "dev": true + }, + "is-core-module": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz", + "integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-date-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.4.tgz", + "integrity": "sha512-/b4ZVsG7Z5XVtIxs/h9W8nvfLgSAyKYdtGWQLbqy6jA1icmgjf8WCoTKgeS4wy5tYaPePouzFMANbnj94c2Z+A==", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", + "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "dev": true + }, + "is-number-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.5.tgz", + "integrity": "sha512-RU0lI/n95pMoUKu9v1BZP5MBcZuNSVJkMkAG2dJqC4z2GlkGUNeH68SuHuBKBD/XFe+LHZ+f9BKkLET60Niedw==", + "dev": true + }, + "is-regex": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.3.tgz", + "integrity": "sha512-qSVXFz28HM7y+IWX6vLCsexdlvzT1PJNFSBuaQLQ5o0IEw8UDYW6/2+eCMVyIsbM8CNLX2a/QWmSpyxYEHY7CQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-symbols": "^1.0.2" + } + }, + "is-string": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.6.tgz", + "integrity": "sha512-2gdzbKUuqtQ3lYNrUTQYoClPhm7oQu4UdpSZMp1/DGgkHBT8E2Z1l0yMdb6D4zNAxwDiMv8MdulKROJGNl0Q0w==", + "dev": true + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", "dev": true }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "jit-grunt": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/jit-grunt/-/jit-grunt-0.10.0.tgz", + "integrity": "sha1-AIw6f+Hpa9DYTiYOofoXg0V/ecI=" + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, "js-yaml": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", @@ -637,6 +1757,33 @@ "esprima": "~ 1.0.2" } }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json5": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", + "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, "knox": { "version": "0.8.10", "resolved": "https://registry.npmjs.org/knox/-/knox-0.8.10.tgz", @@ -649,6 +1796,16 @@ "xml2js": "0.2.x" } }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "load-grunt-config": { "version": "0.19.2", "resolved": "https://registry.npmjs.org/load-grunt-config/-/load-grunt-config-0.19.2.tgz", @@ -662,98 +1819,6 @@ "lodash": "~3.10.1" }, "dependencies": { - "cson": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/cson/-/cson-3.0.2.tgz", - "integrity": "sha1-g+6Qids8JUvsHpjkmNmqzxGtzFQ=", - "requires": { - "coffee-script": "^1.9.0", - "cson-parser": "^1.0.6", - "extract-opts": "^3.0.1", - "requirefresh": "^2.0.0", - "safefs": "^4.0.0" - }, - "dependencies": { - "cson-parser": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/cson-parser/-/cson-parser-1.3.5.tgz", - "integrity": "sha1-fsZ14DkUVTO/KmqFYHPxWZ2cLSQ=", - "requires": { - "coffee-script": "^1.10.0" - } - }, - "extract-opts": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/extract-opts/-/extract-opts-3.3.1.tgz", - "integrity": "sha1-WrvtyYwNUgLjJ4cn+Rktfghsa+E=", - "requires": { - "eachr": "^3.2.0", - "editions": "^1.1.1", - "typechecker": "^4.3.0" - }, - "dependencies": { - "eachr": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/eachr/-/eachr-3.2.0.tgz", - "integrity": "sha1-LDXkPqCGUW95l8+At6pk1VpKRIQ=", - "requires": { - "editions": "^1.1.1", - "typechecker": "^4.3.0" - } - }, - "editions": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", - "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==" - }, - "typechecker": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/typechecker/-/typechecker-4.4.1.tgz", - "integrity": "sha1-+XuV9RsDhBchLWd9RaNz7nvO1+Y=", - "requires": { - "editions": "^1.3.3" - } - } - } - }, - "requirefresh": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/requirefresh/-/requirefresh-2.1.0.tgz", - "integrity": "sha1-dC3Mwg86lpGNZsbxWX3I/+vE9vU=", - "requires": { - "editions": "^1.1.1" - }, - "dependencies": { - "editions": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", - "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==" - } - } - }, - "safefs": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/safefs/-/safefs-4.1.0.tgz", - "integrity": "sha1-+CrrS9165R9lPrIPZyizBYyNZEU=", - "requires": { - "editions": "^1.1.1", - "graceful-fs": "^4.1.4" - }, - "dependencies": { - "editions": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/editions/-/editions-1.3.4.tgz", - "integrity": "sha512-gzao+mxnYDzIysXKMQi/+M1mjy/rjestjg6OPoYTtI+3Izp23oiGZitsl9lPDPiTGXbcSIk1iJWhliSaglxnUg==" - }, - "graceful-fs": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", - "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" - } - } - } - } - }, "glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", @@ -840,11 +1905,6 @@ } } }, - "jit-grunt": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/jit-grunt/-/jit-grunt-0.10.0.tgz", - "integrity": "sha1-AIw6f+Hpa9DYTiYOofoXg0V/ecI=" - }, "js-yaml": { "version": "3.4.6", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.6.tgz", @@ -881,125 +1941,56 @@ "integrity": "sha1-8WFLBshUToEo5CKchjR9tzrZeI0=" } } - }, - "load-grunt-tasks": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-3.3.0.tgz", - "integrity": "sha1-vliSkJRY2T3fdp60vGhRAggMYyE=", + } + } + }, + "load-grunt-tasks": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-3.3.0.tgz", + "integrity": "sha1-vliSkJRY2T3fdp60vGhRAggMYyE=", + "requires": { + "arrify": "^1.0.0", + "multimatch": "^2.0.0", + "pkg-up": "^1.0.0" + }, + "dependencies": { + "pkg-up": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", + "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", "requires": { - "arrify": "^1.0.0", - "multimatch": "^2.0.0", - "pkg-up": "^1.0.0" + "find-up": "^1.0.0" }, "dependencies": { - "arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=" - }, - "multimatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", - "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", "requires": { - "array-differ": "^1.0.0", - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "minimatch": "^3.0.0" + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" }, "dependencies": { - "array-differ": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz", - "integrity": "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE=" - }, - "array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", "requires": { - "array-uniq": "^1.0.1" - }, - "dependencies": { - "array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=" - } - } - }, - "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.7" - }, - "dependencies": { - "brace-expansion": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", - "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - }, - "dependencies": { - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - } - } - } - } - } - } - }, - "pkg-up": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-1.0.0.tgz", - "integrity": "sha1-Pgj7RhUlxEIWJKM7n35tCvWwWiY=", - "requires": { - "find-up": "^1.0.0" - }, - "dependencies": { - "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", - "requires": { - "path-exists": "^2.0.0", "pinkie-promise": "^2.0.0" + } + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "requires": { + "pinkie": "^2.0.0" }, "dependencies": { - "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "requires": { - "pinkie-promise": "^2.0.0" - } - }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "requires": { - "pinkie": "^2.0.0" - }, - "dependencies": { - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" - } - } + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=" } } } @@ -1009,11 +2000,59 @@ } } }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "graceful-fs": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", + "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", + "dev": true + } + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, "lodash": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=" }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", + "dev": true + }, "lpad": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/lpad/-/lpad-0.1.0.tgz", @@ -1046,8 +2085,7 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", - "dev": true, - "optional": true + "dev": true }, "mkdirp": { "version": "0.5.5", @@ -1069,43 +2107,6 @@ "readable-stream": "2.2.7" }, "dependencies": { - "es6-promise": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", - "integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q=" - }, - "mongodb-core": { - "version": "2.1.18", - "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.18.tgz", - "integrity": "sha1-TEYTm986HwMt7ZHbSfOO7AFlkFA=", - "requires": { - "bson": "~1.0.4", - "require_optional": "~1.0.0" - }, - "dependencies": { - "require_optional": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", - "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", - "requires": { - "resolve-from": "^2.0.0", - "semver": "^5.1.0" - }, - "dependencies": { - "resolve-from": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", - "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" - }, - "semver": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", - "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" - } - } - } - } - }, "readable-stream": { "version": "2.2.7", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", @@ -1169,6 +2170,15 @@ } } }, + "mongodb-core": { + "version": "2.1.18", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.18.tgz", + "integrity": "sha1-TEYTm986HwMt7ZHbSfOO7AFlkFA=", + "requires": { + "bson": "~1.0.4", + "require_optional": "~1.0.0" + } + }, "mongojs": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/mongojs/-/mongojs-2.4.0.tgz", @@ -1184,31 +2194,6 @@ "xtend": "^4.0.0" }, "dependencies": { - "each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/each-series/-/each-series-1.0.0.tgz", - "integrity": "sha1-+Ibmxm39sl7x/nNWQUbuXLR4r8s=" - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - }, - "dependencies": { - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - } - } - }, - "parse-mongo-url": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-mongo-url/-/parse-mongo-url-1.1.1.tgz", - "integrity": "sha1-ZiON9fjnwMjKTNlw1KtqE3PrdbU=" - }, "readable-stream": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", @@ -1262,21 +2247,56 @@ "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" } } - }, - "thunky": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz", - "integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=" - }, - "to-mongodb-core": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-mongodb-core/-/to-mongodb-core-2.0.0.tgz", - "integrity": "sha1-NZbsdhOsmtO5ioncua77pWnNJ+s=" - }, - "xtend": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", - "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + } + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "multimatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz", + "integrity": "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis=", + "requires": { + "array-differ": "^1.0.0", + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "minimatch": "^3.0.0" + }, + "dependencies": { + "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.7" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + }, + "dependencies": { + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + } + } + } + } } } }, @@ -1328,6 +2348,12 @@ } } }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "ncp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz", @@ -1344,22 +2370,250 @@ "abbrev": "1" } }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "npm-run-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-1.0.0.tgz", + "integrity": "sha1-9cMr9ZX+ga6Sfa7FLoL4sACsPI8=", + "requires": { + "path-key": "^1.0.0" + }, + "dependencies": { + "path-key": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-1.0.0.tgz", + "integrity": "sha1-XVPVeAGWRsDWiADbThRua9wqx68=" + } + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-inspect": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.10.3.tgz", + "integrity": "sha512-e5mCJlSH7poANfC8z8S9s9S2IN5/4Zb3aZ33f5s8YqoazCFzNLloLU8r5VCG+G7WoqLvAAZoVMcy3tp/3X0Plw==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "object.values": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.4.tgz", + "integrity": "sha512-TnGo7j4XSnKQoK3MfvkzqKCi0nVe/D9I9IjwTNYdb/fxYHpjrluHVOgw0AF6jrRFGMPHdfuidR09tIDiIvnaSg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.18.2" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "optional": true, "requires": { "wrappy": "1" } }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse-mongo-url": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-mongo-url/-/parse-mongo-url-1.1.1.tgz", + "integrity": "sha1-ZiON9fjnwMjKTNlw1KtqE3PrdbU=" + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, "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=", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", "dev": true, - "optional": true + "requires": { + "pify": "^3.0.0" + } + }, + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + }, + "pkg-dir": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-2.0.0.tgz", + "integrity": "sha1-9tXREJ4Z1j7fQo4L1X4Sd3YVM0s=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-2.0.0.tgz", + "integrity": "sha1-yBmscoBZpGHKscOImivjxJoATX8=", + "dev": true, + "requires": { + "find-up": "^2.1.0" + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.3.2.tgz", + "integrity": "sha512-lnJzDfJ66zkMy58OL5/NY5zp70S7Nz6KqcKkXYzn2tMVrNxvbqaBpg7H3qHaLxCJ5lNMsGuM8+ohS7cZrthdLQ==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "ramda": { + "version": "0.27.1", + "resolved": "https://registry.npmjs.org/ramda/-/ramda-0.27.1.tgz", + "integrity": "sha512-PgIdVpn5y5Yns8vqb8FzBUEYn98V3xcPgawAkkgj0YJ0qDsnHCiNmZYfOGMgOvoB0eWFLpYbhxUR3mxfDIMvpw==", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-3.0.0.tgz", + "integrity": "sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=", + "dev": true, + "requires": { + "find-up": "^2.0.0", + "read-pkg": "^3.0.0" + } }, "readable-stream": { "version": "1.0.34", @@ -1381,30 +2635,96 @@ "double-ended-queue": "^2.1.0-0", "redis-commands": "^1.2.0", "redis-parser": "^2.6.0" + } + }, + "redis-commands": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz", + "integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs=" + }, + "redis-parser": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", + "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" + }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "requires": { + "resolve-from": "^2.0.0", + "semver": "^5.1.0" }, "dependencies": { - "double-ended-queue": { - "version": "2.1.0-0", - "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz", - "integrity": "sha1-ED01J/0xUo9AGIEwyEHv3XgmTlw=" + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" }, - "redis-commands": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz", - "integrity": "sha1-gdgm9F+pyLIBH0zXoP5ZfSQdRCs=" - }, - "redis-parser": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.6.0.tgz", - "integrity": "sha1-Uu0J2srBCPGmMcB+m2mUHnoZUEs=" + "semver": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.5.0.tgz", + "integrity": "sha512-4SJ3dm0WAwWy/NVeioZh5AntkdJoWKxHxcmyP622fOkgHa4z3R0TdBJICINyaSDE6uNwVc8gZr+ZinwZAH4xIA==" } } }, + "requirefresh": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/requirefresh/-/requirefresh-2.1.0.tgz", + "integrity": "sha1-dC3Mwg86lpGNZsbxWX3I/+vE9vU=", + "requires": { + "editions": "^1.1.1" + } + }, + "resolve": { + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", + "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", + "dev": true, + "requires": { + "is-core-module": "^2.2.0", + "path-parse": "^1.0.6" + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, "rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=" }, + "safefs": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/safefs/-/safefs-4.1.0.tgz", + "integrity": "sha1-+CrrS9165R9lPrIPZyizBYyNZEU=", + "requires": { + "editions": "^1.1.1", + "graceful-fs": "^4.1.4" + }, + "dependencies": { + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=" + } + } + }, "sax": { "version": "0.5.8", "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz", @@ -1417,26 +2737,102 @@ "integrity": "sha1-eUEYKz/8xYC/8cF5QqzfeVHA0hM=", "dev": true }, - "settings-sharelatex": { - "version": "git+https://github.com/sharelatex/settings-sharelatex.git#b4fb8404c5de571d029bf4c29e96a60b21206f94", - "from": "git+https://github.com/sharelatex/settings-sharelatex.git", + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "requires": { - "coffee-script": "1.6.0" - }, - "dependencies": { - "coffee-script": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.6.0.tgz", - "integrity": "sha1-gIs5bhEPU9AhoZpO8fZb4OjjX6M=" - } + "shebang-regex": "^3.0.0" } }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, "sigmund": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", "dev": true }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.9.tgz", + "integrity": "sha512-Ki212dKK4ogX+xDo4CtOZBVIwhsKBEfsEEcwmJfLQzirgc2jIWdzg40Unxz/HzEUqM1WFzVlQSMF9kZZ2HboLQ==", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, "stream-counter": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/stream-counter/-/stream-counter-0.1.0.tgz", @@ -1446,6 +2842,37 @@ "readable-stream": "~1.0.2" } }, + "string-width": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz", + "integrity": "sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.0" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, "string_decoder": { "version": "0.10.31", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", @@ -1453,11 +2880,136 @@ "dev": true }, "strip-ansi": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.1.1.tgz", - "integrity": "sha1-OeipjQRNFQZgq+SmgIrPcLt7yZE=", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", + "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "table": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/table/-/table-6.7.1.tgz", + "integrity": "sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg==", + "dev": true, + "requires": { + "ajv": "^8.0.1", + "lodash.clonedeep": "^4.5.0", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.6.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.6.1.tgz", + "integrity": "sha512-42VLtQUOLefAvKFAQIxIZDaThq6om/PrfP0CYk3/vn+y4BMNkKnbli8ON2QCiHov4KkzOSJ/xSoBJdayiiYvVQ==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + } + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "thunky": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-0.1.0.tgz", + "integrity": "sha1-vzAUaCTituZ7Dy16Ssi+smkIaE4=" + }, + "to-mongodb-core": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-mongodb-core/-/to-mongodb-core-2.0.0.tgz", + "integrity": "sha1-NZbsdhOsmtO5ioncua77pWnNJ+s=" + }, + "tsconfig-paths": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.10.1.tgz", + "integrity": "sha512-rETidPDgCpltxF7MjBZlAFPUHv5aHH2MymyPvh+vEyWAED4Eb/WeMbsnD/JDr4OKPOA1TssDHgIcpTN5Kh0p6Q==", + "dev": true, + "requires": { + "json5": "^2.2.0", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + } + }, + "twostep": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/twostep/-/twostep-0.4.2.tgz", + "integrity": "sha1-hLxQh6hxV00ev3vjB54D4SLUFbY=" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, + "typechecker": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/typechecker/-/typechecker-4.4.1.tgz", + "integrity": "sha1-+XuV9RsDhBchLWd9RaNz7nvO1+Y=", + "requires": { + "editions": "^1.3.3" + } + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "underscore": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", @@ -1469,18 +3021,60 @@ "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=", "dev": true }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, "which": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", "dev": true }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true, - "optional": true + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" }, "xml2js": { "version": "0.2.8", @@ -1490,6 +3084,17 @@ "requires": { "sax": "0.5.x" } + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true } } } diff --git a/package.json b/package.json index 4b32165fcd..f7ef5fd095 100644 --- a/package.json +++ b/package.json @@ -2,10 +2,16 @@ "name": "sharelatex", "version": "0.0.1", "description": "An online collaborative LaTeX editor", + "scripts": { + "lint": "eslint --max-warnings 0 --format unix .", + "lint:fix": "eslint --fix .", + "format": "prettier --list-different $PWD/'**/*.js'", + "format:fix": "prettier --write $PWD/'**/*.js'" + }, "dependencies": { + "@overleaf/settings": "^2.1.1", "async": "^0.9.0", "bson": "^1.0.4", - "coffee-script": "^1.11.1", "east": "0.5.7", "east-mongo": "0.3.3", "grunt-shell": "^1.1.1", @@ -15,17 +21,26 @@ "mongojs": "2.4.0", "redis": "^2.6.2", "rimraf": "~2.2.6", - "settings-sharelatex": "git+https://github.com/sharelatex/settings-sharelatex.git", "underscore": "^1.7.0" }, "devDependencies": { "grunt": "~0.4.2", "bunyan": "~0.22.1", + "eslint": "^7.21.0", + "eslint-config-prettier": "^8.1.0", + "eslint-config-standard": "^16.0.2", + "eslint-plugin-chai-expect": "^2.2.0", + "eslint-plugin-chai-friendly": "^0.6.0", + "eslint-plugin-import": "^2.22.1", + "eslint-plugin-mocha": "^8.0.0", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^4.2.1", + "eslint-plugin-standard": "^5.0.0", "grunt-bunyan": "~0.5.0", "grunt-execute": "~0.1.5", "grunt-available-tasks": "~0.4.1", "grunt-concurrent": "~0.4.3", - "grunt-contrib-coffee": "~0.10.1", + "prettier": "^2.2.1", "semver": "~2.2.1", "knox": "~0.8.9" } diff --git a/runit/chat-sharelatex/run b/runit/chat-sharelatex/run index cc5f75057f..c000f7d80d 100755 --- a/runit/chat-sharelatex/run +++ b/runit/chat-sharelatex/run @@ -1,5 +1,4 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee NODE_PARAMS="" if [ "$DEBUG_NODE" == "true" ]; then diff --git a/runit/clsi-sharelatex/run b/runit/clsi-sharelatex/run index c1469b6cfe..e8e7bbaf4c 100755 --- a/runit/clsi-sharelatex/run +++ b/runit/clsi-sharelatex/run @@ -1,5 +1,4 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee NODE_PARAMS="" if [ "$DEBUG_NODE" == "true" ]; then diff --git a/runit/contacts-sharelatex/run b/runit/contacts-sharelatex/run index 4c01aa0985..8de491ac6a 100755 --- a/runit/contacts-sharelatex/run +++ b/runit/contacts-sharelatex/run @@ -1,5 +1,4 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee NODE_PARAMS="" if [ "$DEBUG_NODE" == "true" ]; then diff --git a/runit/docstore-sharelatex/run b/runit/docstore-sharelatex/run index 2a171f0968..f6b3285358 100755 --- a/runit/docstore-sharelatex/run +++ b/runit/docstore-sharelatex/run @@ -1,5 +1,4 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee NODE_PARAMS="" if [ "$DEBUG_NODE" == "true" ]; then diff --git a/runit/document-updater-sharelatex/run b/runit/document-updater-sharelatex/run index 51472b3d48..7d688a17de 100755 --- a/runit/document-updater-sharelatex/run +++ b/runit/document-updater-sharelatex/run @@ -1,5 +1,4 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee NODE_PARAMS="" if [ "$DEBUG_NODE" == "true" ]; then diff --git a/runit/filestore-sharelatex/run b/runit/filestore-sharelatex/run index 4237a38793..8baccbfe0b 100755 --- a/runit/filestore-sharelatex/run +++ b/runit/filestore-sharelatex/run @@ -1,3 +1,2 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee exec /sbin/setuser www-data /usr/bin/node /var/www/sharelatex/filestore/app.js >> /var/log/sharelatex/filestore.log 2>&1 diff --git a/runit/notifications-sharelatex/run b/runit/notifications-sharelatex/run index 89f8ad54f9..721b1cf1e9 100755 --- a/runit/notifications-sharelatex/run +++ b/runit/notifications-sharelatex/run @@ -1,5 +1,4 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee NODE_PARAMS="" if [ "$DEBUG_NODE" == "true" ]; then diff --git a/runit/real-time-sharelatex/run b/runit/real-time-sharelatex/run index ad005b624c..392c4525ef 100755 --- a/runit/real-time-sharelatex/run +++ b/runit/real-time-sharelatex/run @@ -1,3 +1,2 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee exec /sbin/setuser www-data /usr/bin/node /var/www/sharelatex/real-time/app.js >> /var/log/sharelatex/real-time.log 2>&1 diff --git a/runit/spelling-sharelatex/run b/runit/spelling-sharelatex/run index a9a73f8ae0..af7941a4b4 100755 --- a/runit/spelling-sharelatex/run +++ b/runit/spelling-sharelatex/run @@ -1,5 +1,4 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee NODE_PARAMS="" if [ "$DEBUG_NODE" == "true" ]; then diff --git a/runit/track-changes-sharelatex/run b/runit/track-changes-sharelatex/run index 45b3b77ebc..a137098588 100755 --- a/runit/track-changes-sharelatex/run +++ b/runit/track-changes-sharelatex/run @@ -1,5 +1,4 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee NODE_PARAMS="" if [ "$DEBUG_NODE" == "true" ]; then diff --git a/runit/web-sharelatex/run b/runit/web-sharelatex/run index c1371de0f4..15fba8f806 100755 --- a/runit/web-sharelatex/run +++ b/runit/web-sharelatex/run @@ -1,5 +1,4 @@ #!/bin/bash -export SHARELATEX_CONFIG=/etc/sharelatex/settings.coffee NODE_PARAMS="" if [ "$DEBUG_NODE" == "true" ]; then diff --git a/services.js b/services.js index 84fd7622f5..c47186a159 100644 --- a/services.js +++ b/services.js @@ -1,47 +1,63 @@ -module.exports = +module.exports = [ + { + name: 'web', + repo: 'https://github.com/sharelatex/web-sharelatex.git', + version: 'master', + }, + { + name: 'real-time', + repo: 'https://github.com/sharelatex/real-time-sharelatex.git', + version: 'master', + }, + { + name: 'document-updater', + repo: 'https://github.com/sharelatex/document-updater-sharelatex.git', + version: 'master', + }, + { + name: 'clsi', + repo: 'https://github.com/sharelatex/clsi-sharelatex.git', + version: 'master', + }, + { + name: 'filestore', + repo: 'https://github.com/sharelatex/filestore-sharelatex.git', + version: 'master', + }, + { + name: 'track-changes', + repo: 'https://github.com/sharelatex/track-changes-sharelatex.git', + version: 'master', + }, + { + name: 'docstore', + repo: 'https://github.com/sharelatex/docstore-sharelatex.git', + version: 'master', + }, + { + name: 'chat', + repo: 'https://github.com/sharelatex/chat-sharelatex.git', + version: 'master', + }, + { + name: 'spelling', + repo: 'https://github.com/sharelatex/spelling-sharelatex.git', + version: 'master', + }, + { + name: 'contacts', + repo: 'https://github.com/sharelatex/contacts-sharelatex.git', + version: 'master', + }, + { + name: 'notifications', + repo: 'https://github.com/sharelatex/notifications-sharelatex.git', + version: 'master', + }, +] -[{ - name: "web", - repo: "https://github.com/sharelatex/web-sharelatex.git", - version: "master" -}, { - name: "real-time", - repo: "https://github.com/sharelatex/real-time-sharelatex.git", - version: "master" -}, { - name: "document-updater", - repo: "https://github.com/sharelatex/document-updater-sharelatex.git", - version: "master" -}, { - name: "clsi", - repo: "https://github.com/sharelatex/clsi-sharelatex.git", - version: "master" -}, { - name: "filestore", - repo: "https://github.com/sharelatex/filestore-sharelatex.git", - version: "master" -}, { - name: "track-changes", - repo: "https://github.com/sharelatex/track-changes-sharelatex.git", - version: "master" -}, { - name: "docstore", - repo: "https://github.com/sharelatex/docstore-sharelatex.git", - version: "master" -}, { - name: "chat", - repo: "https://github.com/sharelatex/chat-sharelatex.git", - version: "master" -}, { - name: "spelling", - repo: "https://github.com/sharelatex/spelling-sharelatex.git", - version: "master" -}, { - name: "contacts", - repo: "https://github.com/sharelatex/contacts-sharelatex.git", - version: "master" -}, { - name: "notifications", - repo: "https://github.com/sharelatex/notifications-sharelatex.git", - version: "master" -}] +if (require.main === module) { + for (const service of module.exports) { + console.log(service.name) + } +} diff --git a/settings.coffee b/settings.coffee deleted file mode 100644 index 684bf18d53..0000000000 --- a/settings.coffee +++ /dev/null @@ -1,576 +0,0 @@ -Path = require('path') - -# These credentials are used for authenticating api requests -# between services that may need to go over public channels -httpAuthUser = "sharelatex" -httpAuthPass = process.env["WEB_API_PASSWORD"] -httpAuthUsers = {} -httpAuthUsers[httpAuthUser] = httpAuthPass - -parse = (option)-> - if option? - try - opt = JSON.parse(option) - return opt - catch err - throw new Error("problem parsing #{option}, invalid JSON") - -parseIntOrFail = (value)-> - parsedValue = parseInt(value, 10) - if isNaN(parsedValue) - throw new Error("'#{value}' is an invalid integer") - return parsedValue - -DATA_DIR = '/var/lib/sharelatex/data' -TMP_DIR = '/var/lib/sharelatex/tmp' - -settings = - - clsi: - optimiseInDocker: process.env['OPTIMISE_PDF'] == 'true' - - brandPrefix: "" - - allowAnonymousReadAndWriteSharing: - process.env['SHARELATEX_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING'] == 'true' - - # Databases - # --------- - - # ShareLaTeX's main persistent data store is MongoDB (http://www.mongodb.org/) - # Documentation about the URL connection string format can be found at: - # - # http://docs.mongodb.org/manual/reference/connection-string/ - # - # The following works out of the box with Mongo's default settings: - mongo: - url : process.env["SHARELATEX_MONGO_URL"] or 'mongodb://dockerhost/sharelatex' - - # Redis is used in ShareLaTeX for high volume queries, like real-time - # editing, and session management. - # - # The following config will work with Redis's default settings: - redis: - web: redisConfig = - host: process.env["SHARELATEX_REDIS_HOST"] or "dockerhost" - port: process.env["SHARELATEX_REDIS_PORT"] or "6379" - password: process.env["SHARELATEX_REDIS_PASS"] or undefined - key_schema: - # document-updater - blockingKey: ({doc_id}) -> "Blocking:#{doc_id}" - docLines: ({doc_id}) -> "doclines:#{doc_id}" - docOps: ({doc_id}) -> "DocOps:#{doc_id}" - docVersion: ({doc_id}) -> "DocVersion:#{doc_id}" - docHash: ({doc_id}) -> "DocHash:#{doc_id}" - projectKey: ({doc_id}) -> "ProjectId:#{doc_id}" - docsInProject: ({project_id}) -> "DocsIn:#{project_id}" - ranges: ({doc_id}) -> "Ranges:#{doc_id}" - # document-updater:realtime - pendingUpdates: ({doc_id}) -> "PendingUpdates:#{doc_id}" - # document-updater:history - uncompressedHistoryOps: ({doc_id}) -> "UncompressedHistoryOps:#{doc_id}" - docsWithHistoryOps: ({project_id}) -> "DocsWithHistoryOps:#{project_id}" - # document-updater:lock - blockingKey: ({doc_id}) -> "Blocking:#{doc_id}" - # track-changes:lock - historyLock: ({doc_id}) -> "HistoryLock:#{doc_id}" - historyIndexLock: ({project_id}) -> "HistoryIndexLock:#{project_id}" - # track-changes:history - uncompressedHistoryOps: ({doc_id}) -> "UncompressedHistoryOps:#{doc_id}" - docsWithHistoryOps: ({project_id}) -> "DocsWithHistoryOps:#{project_id}" - # realtime - clientsInProject: ({project_id}) -> "clients_in_project:#{project_id}" - connectedUser: ({project_id, client_id})-> "connected_user:#{project_id}:#{client_id}" - fairy: redisConfig - # track-changes and document-updater - realtime: redisConfig - documentupdater: redisConfig - lock: redisConfig - history: redisConfig - websessions: redisConfig - api: redisConfig - pubsub: redisConfig - project_history: redisConfig - - # The compile server (the clsi) uses a SQL database to cache files and - # meta-data. sqlite is the default, and the load is low enough that this will - # be fine in production (we use sqlite at sharelatex.com). - # - # If you want to configure a different database, see the Sequelize documentation - # for available options: - # - # https://github.com/sequelize/sequelize/wiki/API-Reference-Sequelize#example-usage - # - mysql: - clsi: - database: "clsi" - username: "clsi" - password: "" - dialect: "sqlite" - storage: Path.join(DATA_DIR, "db.sqlite") - - # File storage - # ------------ - - # ShareLaTeX can store binary files like images either locally or in Amazon - # S3. The default is locally: - filestore: - backend: "fs" - stores: - user_files: Path.join(DATA_DIR, "user_files") - template_files: Path.join(DATA_DIR, "template_files") - - # To use Amazon S3 as a storage backend, comment out the above config, and - # uncomment the following, filling in your key, secret, and bucket name: - # - # filestore: - # backend: "s3" - # stores: - # user_files: "BUCKET_NAME" - # s3: - # key: "AWS_KEY" - # secret: "AWS_SECRET" - # - - trackchanges: - continueOnError: true - - # Local disk caching - # ------------------ - path: - # If we ever need to write something to disk (e.g. incoming requests - # that need processing but may be too big for memory), then write - # them to disk here: - dumpFolder: Path.join(TMP_DIR, "dumpFolder") - # Where to write uploads before they are processed - uploadFolder: Path.join(TMP_DIR, "uploads") - # Where to write the project to disk before running LaTeX on it - compilesDir: Path.join(DATA_DIR, "compiles") - # Where to cache downloaded URLs for the CLSI - clsiCacheDir: Path.join(DATA_DIR, "cache") - # Where to write the output files to disk after running LaTeX - outputDir: Path.join(DATA_DIR, "output") - - # Server Config - # ------------- - - # Where your instance of ShareLaTeX can be found publicly. This is used - # when emails are sent out and in generated links: - siteUrl: siteUrl = process.env["SHARELATEX_SITE_URL"] or 'http://localhost' - - # The name this is used to describe your ShareLaTeX Installation - appName: process.env["SHARELATEX_APP_NAME"] or "ShareLaTeX (Community Edition)" - - restrictInvitesToExistingAccounts: process.env["SHARELATEX_RESTRICT_INVITES_TO_EXISTING_ACCOUNTS"] == 'true' - - nav: - title: process.env["SHARELATEX_NAV_TITLE"] or process.env["SHARELATEX_APP_NAME"] or "ShareLaTeX Community Edition" - - - # The email address which users will be directed to as the main point of - # contact for this installation of ShareLaTeX. - adminEmail: process.env["SHARELATEX_ADMIN_EMAIL"] or "placeholder@example.com" - - # If provided, a sessionSecret is used to sign cookies so that they cannot be - # spoofed. This is recommended. - security: - sessionSecret: process.env["SHARELATEX_SESSION_SECRET"] or process.env["CRYPTO_RANDOM"] - - # These credentials are used for authenticating api requests - # between services that may need to go over public channels - httpAuthUsers: httpAuthUsers - - # Should javascript assets be served minified or not. - useMinifiedJs: true - - # Should static assets be sent with a header to tell the browser to cache - # them. This should be false in development where changes are being made, - # but should be set to true in production. - cacheStaticAssets: true - - # If you are running ShareLaTeX over https, set this to true to send the - # cookie with a secure flag (recommended). - secureCookie: process.env["SHARELATEX_SECURE_COOKIE"]? - - # If you are running ShareLaTeX behind a proxy (like Apache, Nginx, etc) - # then set this to true to allow it to correctly detect the forwarded IP - # address and http/https protocol information. - - behindProxy: process.env["SHARELATEX_BEHIND_PROXY"] or false - - i18n: - subdomainLang: - www: {lngCode:process.env["SHARELATEX_SITE_LANGUAGE"] or "en", url: siteUrl} - defaultLng: process.env["SHARELATEX_SITE_LANGUAGE"] or "en" - - currentImageName: process.env["TEX_LIVE_DOCKER_IMAGE"] - - apis: - web: - url: "http://localhost:3000" - user: httpAuthUser - pass: httpAuthPass - project_history: - enabled: false - references:{} - notifications:undefined - - defaultFeatures: - collaborators: -1 - dropbox: true - versioning: true - compileTimeout: parseIntOrFail(process.env["COMPILE_TIMEOUT"] or 180) - compileGroup: "standard" - trackChanges: true - templates: true - references: true - -## OPTIONAL CONFIGURABLE SETTINGS - -if process.env["SHARELATEX_LEFT_FOOTER"]? - try - settings.nav.left_footer = JSON.parse(process.env["SHARELATEX_LEFT_FOOTER"]) - catch e - console.error("could not parse SHARELATEX_LEFT_FOOTER, not valid JSON") - -if process.env["SHARELATEX_RIGHT_FOOTER"]? - settings.nav.right_footer = process.env["SHARELATEX_RIGHT_FOOTER"] - try - settings.nav.right_footer = JSON.parse(process.env["SHARELATEX_RIGHT_FOOTER"]) - catch e - console.error("could not parse SHARELATEX_RIGHT_FOOTER, not valid JSON") - -if process.env["SHARELATEX_HEADER_IMAGE_URL"]? - settings.nav.custom_logo = process.env["SHARELATEX_HEADER_IMAGE_URL"] - -if process.env["SHARELATEX_HEADER_NAV_LINKS"]? - console.error """ -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# -# WARNING: SHARELATEX_HEADER_NAV_LINKS is no longer supported -# See https://github.com/sharelatex/sharelatex/wiki/Configuring-Headers,-Footers-&-Logo -# -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -""" - -if process.env["SHARELATEX_HEADER_EXTRAS"]? - try - settings.nav.header_extras = JSON.parse(process.env["SHARELATEX_HEADER_EXTRAS"]) - catch e - console.error("could not parse SHARELATEX_HEADER_EXTRAS, not valid JSON") - - - -# Sending Email -# ------------- -# -# You must configure a mail server to be able to send invite emails from -# ShareLaTeX. The config settings are passed to nodemailer. See the nodemailer -# documentation for available options: -# -# http://www.nodemailer.com/docs/transports - - -if process.env["SHARELATEX_EMAIL_FROM_ADDRESS"]? - - settings.email = - fromAddress: process.env["SHARELATEX_EMAIL_FROM_ADDRESS"] - replyTo: process.env["SHARELATEX_EMAIL_REPLY_TO"] or "" - driver: process.env["SHARELATEX_EMAIL_DRIVER"] - parameters: - #AWS Creds - AWSAccessKeyID: process.env["SHARELATEX_EMAIL_AWS_SES_ACCESS_KEY_ID"] - AWSSecretKey: process.env["SHARELATEX_EMAIL_AWS_SES_SECRET_KEY"] - - #SMTP Creds - host: process.env["SHARELATEX_EMAIL_SMTP_HOST"] - port: process.env["SHARELATEX_EMAIL_SMTP_PORT"], - secure: parse(process.env["SHARELATEX_EMAIL_SMTP_SECURE"]) - ignoreTLS: parse(process.env["SHARELATEX_EMAIL_SMTP_IGNORE_TLS"]) - name: process.env["SHARELATEX_EMAIL_SMTP_NAME"] - logger: process.env["SHARELATEX_EMAIL_SMTP_LOGGER"] == 'true' - - textEncoding: process.env["SHARELATEX_EMAIL_TEXT_ENCODING"] - template: - customFooter: process.env["SHARELATEX_CUSTOM_EMAIL_FOOTER"] - - if process.env["SHARELATEX_EMAIL_AWS_SES_REGION"]? - settings.email.parameters.region = process.env["SHARELATEX_EMAIL_AWS_SES_REGION"] - - if process.env["SHARELATEX_EMAIL_SMTP_USER"]? or process.env["SHARELATEX_EMAIL_SMTP_PASS"]? - settings.email.parameters.auth = - user: process.env["SHARELATEX_EMAIL_SMTP_USER"] - pass: process.env["SHARELATEX_EMAIL_SMTP_PASS"] - - if process.env["SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH"]? - settings.email.parameters.tls = - rejectUnauthorized: parse(process.env["SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH"]) - - -# i18n -if process.env["SHARELATEX_LANG_DOMAIN_MAPPING"]? - - settings.i18n.subdomainLang = parse(process.env["SHARELATEX_LANG_DOMAIN_MAPPING"]) - -# Password Settings -# ----------- -# These restrict the passwords users can use when registering -# opts are from http://antelle.github.io/passfield -if process.env["SHARELATEX_PASSWORD_VALIDATION_PATTERN"] or process.env["SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH"] or process.env["SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH"] - - settings.passwordStrengthOptions = - pattern: process.env["SHARELATEX_PASSWORD_VALIDATION_PATTERN"] or "aA$3" - length: {min:process.env["SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH"] or 8, max: process.env["SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH"] or 150} - - - - -####################### -# ShareLaTeX Server Pro -####################### - -if parse(process.env["SHARELATEX_IS_SERVER_PRO"]) == true - settings.bypassPercentageRollouts = true - settings.apis.references = - url: "http://localhost:3040" - - -# LDAP - SERVER PRO ONLY -# ---------- - -if process.env["SHARELATEX_LDAP_HOST"] - console.error """ -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -# -# WARNING: The LDAP configuration format has changed in version 0.5.1 -# See https://github.com/sharelatex/sharelatex/wiki/Server-Pro:-LDAP-Config -# -# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # -""" - -if process.env["SHARELATEX_LDAP_URL"] - settings.externalAuth = true - settings.ldap = - emailAtt: process.env["SHARELATEX_LDAP_EMAIL_ATT"] - nameAtt: process.env["SHARELATEX_LDAP_NAME_ATT"] - lastNameAtt: process.env["SHARELATEX_LDAP_LAST_NAME_ATT"] - updateUserDetailsOnLogin: process.env["SHARELATEX_LDAP_UPDATE_USER_DETAILS_ON_LOGIN"] == 'true' - placeholder: process.env["SHARELATEX_LDAP_PLACEHOLDER"] - server: - url: process.env["SHARELATEX_LDAP_URL"] - bindDn: process.env["SHARELATEX_LDAP_BIND_DN"] - bindCredentials: process.env["SHARELATEX_LDAP_BIND_CREDENTIALS"] - bindProperty: process.env["SHARELATEX_LDAP_BIND_PROPERTY"] - searchBase: process.env["SHARELATEX_LDAP_SEARCH_BASE"] - searchScope: process.env["SHARELATEX_LDAP_SEARCH_SCOPE"] - searchFilter: process.env["SHARELATEX_LDAP_SEARCH_FILTER"] - searchAttributes: ( - if _ldap_search_attribs = process.env["SHARELATEX_LDAP_SEARCH_ATTRIBUTES"] - try - JSON.parse(_ldap_search_attribs) - catch e - console.error "could not parse SHARELATEX_LDAP_SEARCH_ATTRIBUTES" - else - undefined - ) - groupDnProperty: process.env["SHARELATEX_LDAP_GROUP_DN_PROPERTY"] - groupSearchBase: process.env["SHARELATEX_LDAP_GROUP_SEARCH_BASE"] - groupSearchScope: process.env["SHARELATEX_LDAP_GROUP_SEARCH_SCOPE"] - groupSearchFilter: process.env["SHARELATEX_LDAP_GROUP_SEARCH_FILTER"] - groupSearchAttributes: ( - if _ldap_group_search_attribs = process.env["SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES"] - try - JSON.parse(_ldap_group_search_attribs) - catch e - console.error "could not parse SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES" - else - undefined - ) - cache: process.env["SHARELATEX_LDAP_CACHE"] == 'true' - timeout: ( - if _ldap_timeout = process.env["SHARELATEX_LDAP_TIMEOUT"] - try - parseIntOrFail(_ldap_timeout) - catch e - console.error "Cannot parse SHARELATEX_LDAP_TIMEOUT" - else - undefined - ) - connectTimeout: ( - if _ldap_connect_timeout = process.env["SHARELATEX_LDAP_CONNECT_TIMEOUT"] - try - parseIntOrFail(_ldap_connect_timeout) - catch e - console.error "Cannot parse SHARELATEX_LDAP_CONNECT_TIMEOUT" - else - undefined - ) - - if process.env["SHARELATEX_LDAP_TLS_OPTS_CA_PATH"] - try - ca = JSON.parse(process.env["SHARELATEX_LDAP_TLS_OPTS_CA_PATH"]) - catch e - console.error "could not parse SHARELATEX_LDAP_TLS_OPTS_CA_PATH, invalid JSON" - - if typeof(ca) == 'string' - ca_paths = [ca] - else if typeof(ca) == 'object' && ca?.length? - ca_paths = ca - else - console.error "problem parsing SHARELATEX_LDAP_TLS_OPTS_CA_PATH" - - settings.ldap.server.tlsOptions = - rejectUnauthorized: process.env["SHARELATEX_LDAP_TLS_OPTS_REJECT_UNAUTH"] == "true" - ca:ca_paths # e.g.'/etc/ldap/ca_certs.pem' - - - - - -if process.env["SHARELATEX_SAML_ENTRYPOINT"] - # NOTE: see https://github.com/node-saml/passport-saml/blob/master/README.md for docs of `server` options - settings.externalAuth = true - settings.saml = - updateUserDetailsOnLogin: process.env["SHARELATEX_SAML_UPDATE_USER_DETAILS_ON_LOGIN"] == 'true' - identityServiceName: process.env["SHARELATEX_SAML_IDENTITY_SERVICE_NAME"] - emailField: process.env["SHARELATEX_SAML_EMAIL_FIELD"] || process.env["SHARELATEX_SAML_EMAIL_FIELD_NAME"] - firstNameField: process.env["SHARELATEX_SAML_FIRST_NAME_FIELD"] - lastNameField: process.env["SHARELATEX_SAML_LAST_NAME_FIELD"] - server: - # strings - entryPoint: process.env["SHARELATEX_SAML_ENTRYPOINT"] - callbackUrl: process.env["SHARELATEX_SAML_CALLBACK_URL"] - issuer: process.env["SHARELATEX_SAML_ISSUER"] - decryptionPvk: process.env["SHARELATEX_SAML_DECRYPTION_PVK"] - decryptionCert: process.env["SHARELATEX_SAML_DECRYPTION_CERT"] - signatureAlgorithm: process.env["SHARELATEX_SAML_SIGNATURE_ALGORITHM"] - identifierFormat: process.env["SHARELATEX_SAML_IDENTIFIER_FORMAT"] - attributeConsumingServiceIndex: process.env["SHARELATEX_SAML_ATTRIBUTE_CONSUMING_SERVICE_INDEX"] - authnContext: process.env["SHARELATEX_SAML_AUTHN_CONTEXT"] - authnRequestBinding: process.env["SHARELATEX_SAML_AUTHN_REQUEST_BINDING"] - validateInResponseTo: process.env["SHARELATEX_SAML_VALIDATE_IN_RESPONSE_TO"] - cacheProvider: process.env["SHARELATEX_SAML_CACHE_PROVIDER"] - logoutUrl: process.env["SHARELATEX_SAML_LOGOUT_URL"] - logoutCallbackUrl: process.env["SHARELATEX_SAML_LOGOUT_CALLBACK_URL"] - disableRequestedAuthnContext: process.env["SHARELATEX_SAML_DISABLE_REQUESTED_AUTHN_CONTEXT"] == 'true' - forceAuthn: process.env["SHARELATEX_SAML_FORCE_AUTHN"] == 'true' - skipRequestCompression: process.env["SHARELATEX_SAML_SKIP_REQUEST_COMPRESSION"] == 'true' - acceptedClockSkewMs: ( - if _saml_skew = process.env["SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS"] - try - parseIntOrFail(_saml_skew) - catch e - console.error "Cannot parse SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS" - else - undefined - ) - requestIdExpirationPeriodMs: ( - if _saml_expiration = process.env["SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS"] - try - parseIntOrFail(_saml_expiration) - catch e - console.error "Cannot parse SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS" - else - undefined - ) - additionalParams: ( - if _saml_additionalParams = process.env["SHARELATEX_SAML_ADDITIONAL_PARAMS"] - try - JSON.parse(_saml_additionalParams) - catch e - console.error "Cannot parse SHARELATEX_SAML_ADDITIONAL_PARAMS" - else - undefined - ) - additionalAuthorizeParams: ( - if _saml_additionalAuthorizeParams = process.env["SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS"] - try - JSON.parse(_saml_additionalAuthorizeParams ) - catch e - console.error "Cannot parse SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS" - else - undefined - ) - additionalLogoutParams: ( - if _saml_additionalLogoutParams = process.env["SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS"] - try - JSON.parse(_saml_additionalLogoutParams ) - catch e - console.error "Cannot parse SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS" - else - undefined - ) - - # SHARELATEX_SAML_CERT cannot be empty - # https://github.com/node-saml/passport-saml/commit/f6b1c885c0717f1083c664345556b535f217c102 - if process.env["SHARELATEX_SAML_CERT"] - settings.saml.server.cert = process.env["SHARELATEX_SAML_CERT"] - settings.saml.server.privateCert = process.env["SHARELATEX_SAML_PRIVATE_CERT"] - -# Compiler -# -------- -if process.env["SANDBOXED_COMPILES"] == "true" - settings.clsi = - dockerRunner: true - docker: - image: process.env["TEX_LIVE_DOCKER_IMAGE"] - env: - HOME: "/tmp" - PATH: process.env["COMPILER_PATH"] or "/usr/local/texlive/2015/bin/x86_64-linux:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - user: "www-data" - - if !settings.path? - settings.path = {} - settings.path.synctexBaseDir = () -> "/compile" - if process.env['SANDBOXED_COMPILES_SIBLING_CONTAINERS'] == 'true' - console.log("Using sibling containers for sandboxed compiles") - if process.env['SANDBOXED_COMPILES_HOST_DIR'] - settings.path.sandboxedCompilesHostDir = process.env['SANDBOXED_COMPILES_HOST_DIR'] - else - console.error('Sibling containers, but SANDBOXED_COMPILES_HOST_DIR not set') - - -# Templates -# --------- -if process.env["SHARELATEX_TEMPLATES_USER_ID"] - settings.templates = - mountPointUrl: "/templates" - user_id: process.env["SHARELATEX_TEMPLATES_USER_ID"] - - settings.templateLinks = parse(process.env["SHARELATEX_NEW_PROJECT_TEMPLATE_LINKS"]) - - -# /Learn -# ------- -if process.env["SHARELATEX_PROXY_LEARN"]? - settings.proxyLearn = parse(process.env["SHARELATEX_PROXY_LEARN"]) - - -# /References -# ----------- -if process.env["SHARELATEX_ELASTICSEARCH_URL"]? - settings.references.elasticsearch = - host: process.env["SHARELATEX_ELASTICSEARCH_URL"] - -# TeX Live Images -# ----------- -if process.env["ALL_TEX_LIVE_DOCKER_IMAGES"]? - allTexLiveDockerImages = process.env["ALL_TEX_LIVE_DOCKER_IMAGES"].split(',') -if process.env["ALL_TEX_LIVE_DOCKER_IMAGE_NAMES"]? - allTexLiveDockerImageNames = process.env["ALL_TEX_LIVE_DOCKER_IMAGE_NAMES"].split(',') -if allTexLiveDockerImages? - settings.allowedImageNames = [] - for fullImageName, index in allTexLiveDockerImages - imageName = Path.basename(fullImageName) - imageDesc = if allTexLiveDockerImageNames? then allTexLiveDockerImageNames[index] else imageName - settings.allowedImageNames.push({ imageName, imageDesc }) - -# With lots of incoming and outgoing HTTP connections to different services, -# sometimes long running, it is a good idea to increase the default number -# of sockets that Node will hold open. -http = require('http') -http.globalAgent.maxSockets = 300 -https = require('https') -https.globalAgent.maxSockets = 300 - -module.exports = settings diff --git a/settings.js b/settings.js new file mode 100644 index 0000000000..25de871789 --- /dev/null +++ b/settings.js @@ -0,0 +1,778 @@ +/* eslint-disable + camelcase, + no-cond-assign, + no-dupe-keys, + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS205: Consider reworking code to avoid use of IIFEs + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ +let allTexLiveDockerImageNames, allTexLiveDockerImages, redisConfig, siteUrl +let e +const Path = require('path') + +// These credentials are used for authenticating api requests +// between services that may need to go over public channels +const httpAuthUser = 'sharelatex' +const httpAuthPass = process.env.WEB_API_PASSWORD +const httpAuthUsers = {} +httpAuthUsers[httpAuthUser] = httpAuthPass + +const parse = function (option) { + if (option != null) { + try { + const opt = JSON.parse(option) + return opt + } catch (err) { + throw new Error(`problem parsing ${option}, invalid JSON`) + } + } +} + +const parseIntOrFail = function (value) { + const parsedValue = parseInt(value, 10) + if (isNaN(parsedValue)) { + throw new Error(`'${value}' is an invalid integer`) + } + return parsedValue +} + +const DATA_DIR = '/var/lib/sharelatex/data' +const TMP_DIR = '/var/lib/sharelatex/tmp' + +const settings = { + clsi: { + optimiseInDocker: process.env.OPTIMISE_PDF === 'true', + }, + + brandPrefix: '', + + allowAnonymousReadAndWriteSharing: + process.env.SHARELATEX_ALLOW_ANONYMOUS_READ_AND_WRITE_SHARING === 'true', + + // Databases + // --------- + + // ShareLaTeX's main persistent data store is MongoDB (http://www.mongodb.org/) + // Documentation about the URL connection string format can be found at: + // + // http://docs.mongodb.org/manual/reference/connection-string/ + // + // The following works out of the box with Mongo's default settings: + mongo: { + url: process.env.SHARELATEX_MONGO_URL || 'mongodb://dockerhost/sharelatex', + }, + + // Redis is used in ShareLaTeX for high volume queries, like real-time + // editing, and session management. + // + // The following config will work with Redis's default settings: + redis: { + web: (redisConfig = { + host: process.env.SHARELATEX_REDIS_HOST || 'dockerhost', + port: process.env.SHARELATEX_REDIS_PORT || '6379', + password: process.env.SHARELATEX_REDIS_PASS || undefined, + key_schema: { + // document-updater + blockingKey({ doc_id }) { + return `Blocking:${doc_id}` + }, + docLines({ doc_id }) { + return `doclines:${doc_id}` + }, + docOps({ doc_id }) { + return `DocOps:${doc_id}` + }, + docVersion({ doc_id }) { + return `DocVersion:${doc_id}` + }, + docHash({ doc_id }) { + return `DocHash:${doc_id}` + }, + projectKey({ doc_id }) { + return `ProjectId:${doc_id}` + }, + docsInProject({ project_id }) { + return `DocsIn:${project_id}` + }, + ranges({ doc_id }) { + return `Ranges:${doc_id}` + }, + // document-updater:realtime + pendingUpdates({ doc_id }) { + return `PendingUpdates:${doc_id}` + }, + // document-updater:history + uncompressedHistoryOps({ doc_id }) { + return `UncompressedHistoryOps:${doc_id}` + }, + docsWithHistoryOps({ project_id }) { + return `DocsWithHistoryOps:${project_id}` + }, + // document-updater:lock + blockingKey({ doc_id }) { + return `Blocking:${doc_id}` + }, + // track-changes:lock + historyLock({ doc_id }) { + return `HistoryLock:${doc_id}` + }, + historyIndexLock({ project_id }) { + return `HistoryIndexLock:${project_id}` + }, + // track-changes:history + uncompressedHistoryOps({ doc_id }) { + return `UncompressedHistoryOps:${doc_id}` + }, + docsWithHistoryOps({ project_id }) { + return `DocsWithHistoryOps:${project_id}` + }, + // realtime + clientsInProject({ project_id }) { + return `clients_in_project:${project_id}` + }, + connectedUser({ project_id, client_id }) { + return `connected_user:${project_id}:${client_id}` + }, + }, + }), + fairy: redisConfig, + // track-changes and document-updater + realtime: redisConfig, + documentupdater: redisConfig, + lock: redisConfig, + history: redisConfig, + websessions: redisConfig, + api: redisConfig, + pubsub: redisConfig, + project_history: redisConfig, + }, + + // The compile server (the clsi) uses a SQL database to cache files and + // meta-data. sqlite is the default, and the load is low enough that this will + // be fine in production (we use sqlite at sharelatex.com). + // + // If you want to configure a different database, see the Sequelize documentation + // for available options: + // + // https://github.com/sequelize/sequelize/wiki/API-Reference-Sequelize#example-usage + // + mysql: { + clsi: { + database: 'clsi', + username: 'clsi', + password: '', + dialect: 'sqlite', + storage: Path.join(DATA_DIR, 'db.sqlite'), + }, + }, + + // File storage + // ------------ + + // ShareLaTeX can store binary files like images either locally or in Amazon + // S3. The default is locally: + filestore: { + backend: 'fs', + stores: { + user_files: Path.join(DATA_DIR, 'user_files'), + template_files: Path.join(DATA_DIR, 'template_files'), + }, + }, + + // To use Amazon S3 as a storage backend, comment out the above config, and + // uncomment the following, filling in your key, secret, and bucket name: + // + // filestore: + // backend: "s3" + // stores: + // user_files: "BUCKET_NAME" + // s3: + // key: "AWS_KEY" + // secret: "AWS_SECRET" + // + + trackchanges: { + continueOnError: true, + }, + + // Local disk caching + // ------------------ + path: { + // If we ever need to write something to disk (e.g. incoming requests + // that need processing but may be too big for memory), then write + // them to disk here: + dumpFolder: Path.join(TMP_DIR, 'dumpFolder'), + // Where to write uploads before they are processed + uploadFolder: Path.join(TMP_DIR, 'uploads'), + // Where to write the project to disk before running LaTeX on it + compilesDir: Path.join(DATA_DIR, 'compiles'), + // Where to cache downloaded URLs for the CLSI + clsiCacheDir: Path.join(DATA_DIR, 'cache'), + // Where to write the output files to disk after running LaTeX + outputDir: Path.join(DATA_DIR, 'output'), + }, + + // Server Config + // ------------- + + // Where your instance of ShareLaTeX can be found publicly. This is used + // when emails are sent out and in generated links: + siteUrl: (siteUrl = process.env.SHARELATEX_SITE_URL || 'http://localhost'), + + // The name this is used to describe your ShareLaTeX Installation + appName: process.env.SHARELATEX_APP_NAME || 'ShareLaTeX (Community Edition)', + + restrictInvitesToExistingAccounts: + process.env.SHARELATEX_RESTRICT_INVITES_TO_EXISTING_ACCOUNTS === 'true', + + nav: { + title: + process.env.SHARELATEX_NAV_TITLE || + process.env.SHARELATEX_APP_NAME || + 'ShareLaTeX Community Edition', + }, + + // The email address which users will be directed to as the main point of + // contact for this installation of ShareLaTeX. + adminEmail: process.env.SHARELATEX_ADMIN_EMAIL || 'placeholder@example.com', + + // If provided, a sessionSecret is used to sign cookies so that they cannot be + // spoofed. This is recommended. + security: { + sessionSecret: + process.env.SHARELATEX_SESSION_SECRET || process.env.CRYPTO_RANDOM, + }, + + // These credentials are used for authenticating api requests + // between services that may need to go over public channels + httpAuthUsers, + + // Should javascript assets be served minified or not. + useMinifiedJs: true, + + // Should static assets be sent with a header to tell the browser to cache + // them. This should be false in development where changes are being made, + // but should be set to true in production. + cacheStaticAssets: true, + + // If you are running ShareLaTeX over https, set this to true to send the + // cookie with a secure flag (recommended). + secureCookie: process.env.SHARELATEX_SECURE_COOKIE != null, + + // If you are running ShareLaTeX behind a proxy (like Apache, Nginx, etc) + // then set this to true to allow it to correctly detect the forwarded IP + // address and http/https protocol information. + + behindProxy: process.env.SHARELATEX_BEHIND_PROXY || false, + + i18n: { + subdomainLang: { + www: { + lngCode: process.env.SHARELATEX_SITE_LANGUAGE || 'en', + url: siteUrl, + }, + }, + defaultLng: process.env.SHARELATEX_SITE_LANGUAGE || 'en', + }, + + currentImageName: process.env.TEX_LIVE_DOCKER_IMAGE, + + apis: { + web: { + url: 'http://localhost:3000', + user: httpAuthUser, + pass: httpAuthPass, + }, + project_history: { + enabled: false, + }, + }, + references: {}, + notifications: undefined, + + defaultFeatures: { + collaborators: -1, + dropbox: true, + versioning: true, + compileTimeout: parseIntOrFail(process.env.COMPILE_TIMEOUT || 180), + compileGroup: 'standard', + trackChanges: true, + templates: true, + references: true, + }, +} + +// # OPTIONAL CONFIGURABLE SETTINGS + +if (process.env.SHARELATEX_LEFT_FOOTER != null) { + try { + settings.nav.left_footer = JSON.parse(process.env.SHARELATEX_LEFT_FOOTER) + } catch (error) { + e = error + console.error('could not parse SHARELATEX_LEFT_FOOTER, not valid JSON') + } +} + +if (process.env.SHARELATEX_RIGHT_FOOTER != null) { + settings.nav.right_footer = process.env.SHARELATEX_RIGHT_FOOTER + try { + settings.nav.right_footer = JSON.parse(process.env.SHARELATEX_RIGHT_FOOTER) + } catch (error1) { + e = error1 + console.error('could not parse SHARELATEX_RIGHT_FOOTER, not valid JSON') + } +} + +if (process.env.SHARELATEX_HEADER_IMAGE_URL != null) { + settings.nav.custom_logo = process.env.SHARELATEX_HEADER_IMAGE_URL +} + +if (process.env.SHARELATEX_HEADER_NAV_LINKS != null) { + console.error(`\ +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# +# WARNING: SHARELATEX_HEADER_NAV_LINKS is no longer supported +# See https://github.com/sharelatex/sharelatex/wiki/Configuring-Headers,-Footers-&-Logo +# +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\ +`) +} + +if (process.env.SHARELATEX_HEADER_EXTRAS != null) { + try { + settings.nav.header_extras = JSON.parse( + process.env.SHARELATEX_HEADER_EXTRAS + ) + } catch (error2) { + e = error2 + console.error('could not parse SHARELATEX_HEADER_EXTRAS, not valid JSON') + } +} + +// Sending Email +// ------------- +// +// You must configure a mail server to be able to send invite emails from +// ShareLaTeX. The config settings are passed to nodemailer. See the nodemailer +// documentation for available options: +// +// http://www.nodemailer.com/docs/transports + +if (process.env.SHARELATEX_EMAIL_FROM_ADDRESS != null) { + settings.email = { + fromAddress: process.env.SHARELATEX_EMAIL_FROM_ADDRESS, + replyTo: process.env.SHARELATEX_EMAIL_REPLY_TO || '', + driver: process.env.SHARELATEX_EMAIL_DRIVER, + parameters: { + // AWS Creds + AWSAccessKeyID: process.env.SHARELATEX_EMAIL_AWS_SES_ACCESS_KEY_ID, + AWSSecretKey: process.env.SHARELATEX_EMAIL_AWS_SES_SECRET_KEY, + + // SMTP Creds + host: process.env.SHARELATEX_EMAIL_SMTP_HOST, + port: process.env.SHARELATEX_EMAIL_SMTP_PORT, + secure: parse(process.env.SHARELATEX_EMAIL_SMTP_SECURE), + ignoreTLS: parse(process.env.SHARELATEX_EMAIL_SMTP_IGNORE_TLS), + name: process.env.SHARELATEX_EMAIL_SMTP_NAME, + logger: process.env.SHARELATEX_EMAIL_SMTP_LOGGER === 'true', + }, + + textEncoding: process.env.SHARELATEX_EMAIL_TEXT_ENCODING, + template: { + customFooter: process.env.SHARELATEX_CUSTOM_EMAIL_FOOTER, + }, + } + + if (process.env.SHARELATEX_EMAIL_AWS_SES_REGION != null) { + settings.email.parameters.region = + process.env.SHARELATEX_EMAIL_AWS_SES_REGION + } + + if ( + process.env.SHARELATEX_EMAIL_SMTP_USER != null || + process.env.SHARELATEX_EMAIL_SMTP_PASS != null + ) { + settings.email.parameters.auth = { + user: process.env.SHARELATEX_EMAIL_SMTP_USER, + pass: process.env.SHARELATEX_EMAIL_SMTP_PASS, + } + } + + if (process.env.SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH != null) { + settings.email.parameters.tls = { + rejectUnauthorized: parse( + process.env.SHARELATEX_EMAIL_SMTP_TLS_REJECT_UNAUTH + ), + } + } +} + +// i18n +if (process.env.SHARELATEX_LANG_DOMAIN_MAPPING != null) { + settings.i18n.subdomainLang = parse( + process.env.SHARELATEX_LANG_DOMAIN_MAPPING + ) +} + +// Password Settings +// ----------- +// These restrict the passwords users can use when registering +// opts are from http://antelle.github.io/passfield +if ( + process.env.SHARELATEX_PASSWORD_VALIDATION_PATTERN || + process.env.SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH || + process.env.SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH +) { + settings.passwordStrengthOptions = { + pattern: process.env.SHARELATEX_PASSWORD_VALIDATION_PATTERN || 'aA$3', + length: { + min: process.env.SHARELATEX_PASSWORD_VALIDATION_MIN_LENGTH || 8, + max: process.env.SHARELATEX_PASSWORD_VALIDATION_MAX_LENGTH || 150, + }, + } +} + +// ###################### +// ShareLaTeX Server Pro +// ###################### + +if (parse(process.env.SHARELATEX_IS_SERVER_PRO) === true) { + settings.bypassPercentageRollouts = true + settings.apis.references = { url: 'http://localhost:3040' } +} + +// LDAP - SERVER PRO ONLY +// ---------- + +if (process.env.SHARELATEX_LDAP_HOST) { + console.error(`\ +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # +# +# WARNING: The LDAP configuration format has changed in version 0.5.1 +# See https://github.com/sharelatex/sharelatex/wiki/Server-Pro:-LDAP-Config +# +# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #\ +`) +} + +if (process.env.SHARELATEX_LDAP_URL) { + let _ldap_connect_timeout, + _ldap_group_search_attribs, + _ldap_search_attribs, + _ldap_timeout + settings.externalAuth = true + settings.ldap = { + emailAtt: process.env.SHARELATEX_LDAP_EMAIL_ATT, + nameAtt: process.env.SHARELATEX_LDAP_NAME_ATT, + lastNameAtt: process.env.SHARELATEX_LDAP_LAST_NAME_ATT, + updateUserDetailsOnLogin: + process.env.SHARELATEX_LDAP_UPDATE_USER_DETAILS_ON_LOGIN === 'true', + placeholder: process.env.SHARELATEX_LDAP_PLACEHOLDER, + server: { + url: process.env.SHARELATEX_LDAP_URL, + bindDn: process.env.SHARELATEX_LDAP_BIND_DN, + bindCredentials: process.env.SHARELATEX_LDAP_BIND_CREDENTIALS, + bindProperty: process.env.SHARELATEX_LDAP_BIND_PROPERTY, + searchBase: process.env.SHARELATEX_LDAP_SEARCH_BASE, + searchScope: process.env.SHARELATEX_LDAP_SEARCH_SCOPE, + searchFilter: process.env.SHARELATEX_LDAP_SEARCH_FILTER, + searchAttributes: (_ldap_search_attribs = + process.env.SHARELATEX_LDAP_SEARCH_ATTRIBUTES) + ? (() => { + try { + return JSON.parse(_ldap_search_attribs) + } catch (error3) { + e = error3 + return console.error( + 'could not parse SHARELATEX_LDAP_SEARCH_ATTRIBUTES' + ) + } + })() + : undefined, + groupDnProperty: process.env.SHARELATEX_LDAP_GROUP_DN_PROPERTY, + groupSearchBase: process.env.SHARELATEX_LDAP_GROUP_SEARCH_BASE, + groupSearchScope: process.env.SHARELATEX_LDAP_GROUP_SEARCH_SCOPE, + groupSearchFilter: process.env.SHARELATEX_LDAP_GROUP_SEARCH_FILTER, + groupSearchAttributes: (_ldap_group_search_attribs = + process.env.SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES) + ? (() => { + try { + return JSON.parse(_ldap_group_search_attribs) + } catch (error4) { + e = error4 + return console.error( + 'could not parse SHARELATEX_LDAP_GROUP_SEARCH_ATTRIBUTES' + ) + } + })() + : undefined, + cache: process.env.SHARELATEX_LDAP_CACHE === 'true', + timeout: (_ldap_timeout = process.env.SHARELATEX_LDAP_TIMEOUT) + ? (() => { + try { + return parseIntOrFail(_ldap_timeout) + } catch (error5) { + e = error5 + return console.error('Cannot parse SHARELATEX_LDAP_TIMEOUT') + } + })() + : undefined, + connectTimeout: (_ldap_connect_timeout = + process.env.SHARELATEX_LDAP_CONNECT_TIMEOUT) + ? (() => { + try { + return parseIntOrFail(_ldap_connect_timeout) + } catch (error6) { + e = error6 + return console.error( + 'Cannot parse SHARELATEX_LDAP_CONNECT_TIMEOUT' + ) + } + })() + : undefined, + }, + } + + if (process.env.SHARELATEX_LDAP_TLS_OPTS_CA_PATH) { + let ca, ca_paths + try { + ca = JSON.parse(process.env.SHARELATEX_LDAP_TLS_OPTS_CA_PATH) + } catch (error7) { + e = error7 + console.error( + 'could not parse SHARELATEX_LDAP_TLS_OPTS_CA_PATH, invalid JSON' + ) + } + + if (typeof ca === 'string') { + ca_paths = [ca] + } else if ( + typeof ca === 'object' && + (ca != null ? ca.length : undefined) != null + ) { + ca_paths = ca + } else { + console.error('problem parsing SHARELATEX_LDAP_TLS_OPTS_CA_PATH') + } + + settings.ldap.server.tlsOptions = { + rejectUnauthorized: + process.env.SHARELATEX_LDAP_TLS_OPTS_REJECT_UNAUTH === 'true', + ca: ca_paths, // e.g.'/etc/ldap/ca_certs.pem' + } + } +} + +if (process.env.SHARELATEX_SAML_ENTRYPOINT) { + // NOTE: see https://github.com/node-saml/passport-saml/blob/master/README.md for docs of `server` options + let _saml_additionalAuthorizeParams, + _saml_additionalLogoutParams, + _saml_additionalParams, + _saml_expiration, + _saml_skew + settings.externalAuth = true + settings.saml = { + updateUserDetailsOnLogin: + process.env.SHARELATEX_SAML_UPDATE_USER_DETAILS_ON_LOGIN === 'true', + identityServiceName: process.env.SHARELATEX_SAML_IDENTITY_SERVICE_NAME, + emailField: + process.env.SHARELATEX_SAML_EMAIL_FIELD || + process.env.SHARELATEX_SAML_EMAIL_FIELD_NAME, + firstNameField: process.env.SHARELATEX_SAML_FIRST_NAME_FIELD, + lastNameField: process.env.SHARELATEX_SAML_LAST_NAME_FIELD, + server: { + // strings + entryPoint: process.env.SHARELATEX_SAML_ENTRYPOINT, + callbackUrl: process.env.SHARELATEX_SAML_CALLBACK_URL, + issuer: process.env.SHARELATEX_SAML_ISSUER, + decryptionPvk: process.env.SHARELATEX_SAML_DECRYPTION_PVK, + decryptionCert: process.env.SHARELATEX_SAML_DECRYPTION_CERT, + signatureAlgorithm: process.env.SHARELATEX_SAML_SIGNATURE_ALGORITHM, + identifierFormat: process.env.SHARELATEX_SAML_IDENTIFIER_FORMAT, + attributeConsumingServiceIndex: + process.env.SHARELATEX_SAML_ATTRIBUTE_CONSUMING_SERVICE_INDEX, + authnContext: process.env.SHARELATEX_SAML_AUTHN_CONTEXT, + authnRequestBinding: process.env.SHARELATEX_SAML_AUTHN_REQUEST_BINDING, + validateInResponseTo: process.env.SHARELATEX_SAML_VALIDATE_IN_RESPONSE_TO, + cacheProvider: process.env.SHARELATEX_SAML_CACHE_PROVIDER, + logoutUrl: process.env.SHARELATEX_SAML_LOGOUT_URL, + logoutCallbackUrl: process.env.SHARELATEX_SAML_LOGOUT_CALLBACK_URL, + disableRequestedAuthnContext: + process.env.SHARELATEX_SAML_DISABLE_REQUESTED_AUTHN_CONTEXT === 'true', + forceAuthn: process.env.SHARELATEX_SAML_FORCE_AUTHN === 'true', + skipRequestCompression: + process.env.SHARELATEX_SAML_SKIP_REQUEST_COMPRESSION === 'true', + acceptedClockSkewMs: (_saml_skew = + process.env.SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS) + ? (() => { + try { + return parseIntOrFail(_saml_skew) + } catch (error8) { + e = error8 + return console.error( + 'Cannot parse SHARELATEX_SAML_ACCEPTED_CLOCK_SKEW_MS' + ) + } + })() + : undefined, + requestIdExpirationPeriodMs: (_saml_expiration = + process.env.SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS) + ? (() => { + try { + return parseIntOrFail(_saml_expiration) + } catch (error9) { + e = error9 + return console.error( + 'Cannot parse SHARELATEX_SAML_REQUEST_ID_EXPIRATION_PERIOD_MS' + ) + } + })() + : undefined, + additionalParams: (_saml_additionalParams = + process.env.SHARELATEX_SAML_ADDITIONAL_PARAMS) + ? (() => { + try { + return JSON.parse(_saml_additionalParams) + } catch (error10) { + e = error10 + return console.error( + 'Cannot parse SHARELATEX_SAML_ADDITIONAL_PARAMS' + ) + } + })() + : undefined, + additionalAuthorizeParams: (_saml_additionalAuthorizeParams = + process.env.SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS) + ? (() => { + try { + return JSON.parse(_saml_additionalAuthorizeParams) + } catch (error11) { + e = error11 + return console.error( + 'Cannot parse SHARELATEX_SAML_ADDITIONAL_AUTHORIZE_PARAMS' + ) + } + })() + : undefined, + additionalLogoutParams: (_saml_additionalLogoutParams = + process.env.SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS) + ? (() => { + try { + return JSON.parse(_saml_additionalLogoutParams) + } catch (error12) { + e = error12 + return console.error( + 'Cannot parse SHARELATEX_SAML_ADDITIONAL_LOGOUT_PARAMS' + ) + } + })() + : undefined, + }, + } + + // SHARELATEX_SAML_CERT cannot be empty + // https://github.com/node-saml/passport-saml/commit/f6b1c885c0717f1083c664345556b535f217c102 + if (process.env.SHARELATEX_SAML_CERT) { + settings.saml.server.cert = process.env.SHARELATEX_SAML_CERT + settings.saml.server.privateCert = process.env.SHARELATEX_SAML_PRIVATE_CERT + } +} + +// Compiler +// -------- +if (process.env.SANDBOXED_COMPILES === 'true') { + settings.clsi = { + dockerRunner: true, + docker: { + image: process.env.TEX_LIVE_DOCKER_IMAGE, + env: { + HOME: '/tmp', + PATH: + process.env.COMPILER_PATH || + '/usr/local/texlive/2015/bin/x86_64-linux:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + }, + user: 'www-data', + }, + } + + if (settings.path == null) { + settings.path = {} + } + settings.path.synctexBaseDir = () => '/compile' + if (process.env.SANDBOXED_COMPILES_SIBLING_CONTAINERS === 'true') { + console.log('Using sibling containers for sandboxed compiles') + if (process.env.SANDBOXED_COMPILES_HOST_DIR) { + settings.path.sandboxedCompilesHostDir = + process.env.SANDBOXED_COMPILES_HOST_DIR + } else { + console.error( + 'Sibling containers, but SANDBOXED_COMPILES_HOST_DIR not set' + ) + } + } +} + +// Templates +// --------- +if (process.env.SHARELATEX_TEMPLATES_USER_ID) { + settings.templates = { + mountPointUrl: '/templates', + user_id: process.env.SHARELATEX_TEMPLATES_USER_ID, + } + + settings.templateLinks = parse( + process.env.SHARELATEX_NEW_PROJECT_TEMPLATE_LINKS + ) +} + +// /Learn +// ------- +if (process.env.SHARELATEX_PROXY_LEARN != null) { + settings.proxyLearn = parse(process.env.SHARELATEX_PROXY_LEARN) +} + +// /References +// ----------- +if (process.env.SHARELATEX_ELASTICSEARCH_URL != null) { + settings.references.elasticsearch = { + host: process.env.SHARELATEX_ELASTICSEARCH_URL, + } +} + +// TeX Live Images +// ----------- +if (process.env.ALL_TEX_LIVE_DOCKER_IMAGES != null) { + allTexLiveDockerImages = process.env.ALL_TEX_LIVE_DOCKER_IMAGES.split(',') +} +if (process.env.ALL_TEX_LIVE_DOCKER_IMAGE_NAMES != null) { + allTexLiveDockerImageNames = + process.env.ALL_TEX_LIVE_DOCKER_IMAGE_NAMES.split(',') +} +if (allTexLiveDockerImages != null) { + settings.allowedImageNames = [] + for (let index = 0; index < allTexLiveDockerImages.length; index++) { + const fullImageName = allTexLiveDockerImages[index] + const imageName = Path.basename(fullImageName) + const imageDesc = + allTexLiveDockerImageNames != null + ? allTexLiveDockerImageNames[index] + : imageName + settings.allowedImageNames.push({ imageName, imageDesc }) + } +} + +// With lots of incoming and outgoing HTTP connections to different services, +// sometimes long running, it is a good idea to increase the default number +// of sockets that Node will hold open. +const http = require('http') +http.globalAgent.maxSockets = 300 +const https = require('https') +https.globalAgent.maxSockets = 300 + +module.exports = settings diff --git a/tasks/CreateAndDestroyUsers.coffee b/tasks/CreateAndDestroyUsers.coffee deleted file mode 100644 index 79da259c67..0000000000 --- a/tasks/CreateAndDestroyUsers.coffee +++ /dev/null @@ -1,60 +0,0 @@ - -module.exports = (grunt) -> - - grunt.registerTask 'user:create-admin', "Create a user with the given email address and make them an admin. Update in place if the user already exists. Usage: grunt user:create-admin --email joe@example.com", () -> - done = @async() - email = grunt.option("email") - if !email? - console.error "Usage: grunt user:create-admin --email=joe@example.com" - process.exit(1) - - settings = require "settings-sharelatex" - mongodb = require "../web/app/src/infrastructure/mongodb" - UserRegistrationHandler = require "../web/app/src/Features/User/UserRegistrationHandler" - OneTimeTokenHandler = require "../web/app/src/Features/Security/OneTimeTokenHandler" - mongodb.waitForDb().then () -> - UserRegistrationHandler.registerNewUser { - email: email - password: require("crypto").randomBytes(32).toString("hex") - }, (error, user) -> - if error? and error?.message != "EmailAlreadyRegistered" - throw error - user.isAdmin = true - user.save (error) -> - throw error if error? - ONE_WEEK = 7 * 24 * 60 * 60 # seconds - OneTimeTokenHandler.getNewToken "password", { expiresIn: ONE_WEEK, email:user.email, user_id: user._id.toString() }, (err, token)-> - return next(err) if err? - - console.log "" - console.log """ - Successfully created #{email} as an admin user. - - Please visit the following URL to set a password for #{email} and log in: - - #{settings.siteUrl}/user/password/set?passwordResetToken=#{token} - - """ - done() - - grunt.registerTask 'user:delete', "deletes a user and all their data, Usage: grunt user:delete --email joe@example.com", () -> - done = @async() - email = grunt.option("email") - if !email? - console.error "Usage: grunt user:delete --email=joe@example.com" - process.exit(1) - settings = require "settings-sharelatex" - mongodb = require "../web/app/src/infrastructure/mongodb" - UserGetter = require "../web/app/src/Features/User/UserGetter" - UserDeleter = require "../web/app/src/Features/User/UserDeleter" - mongodb.waitForDb().then () -> - UserGetter.getUser email:email, (error, user) -> - if error? - throw error - if !user? - console.log("user #{email} not in database, potentially already deleted") - return done() - UserDeleter.deleteUser user._id, (err)-> - if err? - throw err - done() diff --git a/tasks/CreateAndDestroyUsers.js b/tasks/CreateAndDestroyUsers.js new file mode 100644 index 0000000000..b7d519cc6c --- /dev/null +++ b/tasks/CreateAndDestroyUsers.js @@ -0,0 +1,116 @@ +/* eslint-disable + no-undef, + no-unused-vars, +*/ +// TODO: This file was created by bulk-decaffeinate. +// Fix any style issues and re-enable lint. +/* + * decaffeinate suggestions: + * DS102: Remove unnecessary code created because of implicit returns + * DS207: Consider shorter variations of null checks + * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md + */ + +module.exports = function (grunt) { + grunt.registerTask( + 'user:create-admin', + 'Create a user with the given email address and make them an admin. Update in place if the user already exists. Usage: grunt user:create-admin --email joe@example.com', + function () { + const done = this.async() + const email = grunt.option('email') + if (email == null) { + console.error('Usage: grunt user:create-admin --email=joe@example.com') + process.exit(1) + } + + const settings = require('@overleaf/settings') + const mongodb = require('../web/app/src/infrastructure/mongodb') + const UserRegistrationHandler = require('../web/app/src/Features/User/UserRegistrationHandler') + const OneTimeTokenHandler = require('../web/app/src/Features/Security/OneTimeTokenHandler') + return mongodb.waitForDb().then(() => + UserRegistrationHandler.registerNewUser( + { + email, + password: require('crypto').randomBytes(32).toString('hex'), + }, + function (error, user) { + if ( + error != null && + (error != null ? error.message : undefined) !== + 'EmailAlreadyRegistered' + ) { + throw error + } + user.isAdmin = true + return user.save(function (error) { + if (error != null) { + throw error + } + const ONE_WEEK = 7 * 24 * 60 * 60 // seconds + return OneTimeTokenHandler.getNewToken( + 'password', + { + expiresIn: ONE_WEEK, + email: user.email, + user_id: user._id.toString(), + }, + function (err, token) { + if (err != null) { + return next(err) + } + + console.log('') + console.log(`\ +Successfully created ${email} as an admin user. + +Please visit the following URL to set a password for ${email} and log in: + +${settings.siteUrl}/user/password/set?passwordResetToken=${token} +\ +`) + return done() + } + ) + }) + } + ) + ) + } + ) + + return grunt.registerTask( + 'user:delete', + 'deletes a user and all their data, Usage: grunt user:delete --email joe@example.com', + function () { + const done = this.async() + const email = grunt.option('email') + if (email == null) { + console.error('Usage: grunt user:delete --email=joe@example.com') + process.exit(1) + } + const settings = require('@overleaf/settings') + const mongodb = require('../web/app/src/infrastructure/mongodb') + const UserGetter = require('../web/app/src/Features/User/UserGetter') + const UserDeleter = require('../web/app/src/Features/User/UserDeleter') + return mongodb.waitForDb().then(() => + UserGetter.getUser({ email }, function (error, user) { + if (error != null) { + throw error + } + if (user == null) { + console.log( + `user ${email} not in database, potentially already deleted` + ) + return done() + } + return UserDeleter.deleteUser(user._id, function (err) { + if (err != null) { + throw err + } + return done() + }) + }) + ) + } + ) +} diff --git a/tasks/ProjectSize.coffee b/tasks/ProjectSize.coffee deleted file mode 100644 index 1d02d33d26..0000000000 --- a/tasks/ProjectSize.coffee +++ /dev/null @@ -1,24 +0,0 @@ -# require("coffee-script") - -# fs = require("fs") -# _ = require("underscore") - -# if not process.argv[2] -# console.log "Usage: coffee project_size.coffee user_files_path" -# else -# dirPath = process.argv[2] -# if not fs.lstatSync(dirPath).isDirectory() -# console.log dirPath + " directory not exist" -# else -# fs.readdir dirPath, (err, files)-> -# projects = [] -# files.forEach (file)-> -# project_id = file.split("_")[0] -# if !projects[project_id] -# projects[project_id] = 0 -# projects[project_id] += fs.lstatSync(dirPath+"/"+file).size - -# ids = _.keys projects -# console.log "project \t size" -# ids.forEach (id)-> -# console.log id + "\t" + projects[id]