├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── config.js ├── docs ├── getting-started.md └── howitworks.md ├── examples ├── .gitignore ├── proxy-express.js └── proxy-ngineer.js ├── index.js ├── package.json ├── reload.js ├── reset.js ├── scaffold.js ├── scaffold ├── conf │ ├── mime.types │ └── nginx.conf └── html │ └── index.html ├── sections ├── base.js └── location.js ├── start.js ├── stop-on-exit.js ├── stop.js ├── test ├── helpers │ ├── nginx.js │ └── test-server.js └── integration │ ├── add-location.js │ ├── detect-online.js │ ├── mocha.opts │ ├── server │ ├── conf │ │ ├── mime.types │ │ └── nginx.conf │ ├── html │ │ └── index.html │ └── logs │ │ └── README.md │ └── start.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | npm-debug.log 4 | test/integration/*/logs/*.log 5 | test/integration/*/logs/*.pid 6 | test/integration/*/conf/locations -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 10 4 | - 11 5 | - 12 6 | - 13 7 | - 14 8 | 9 | addons: 10 | apt: 11 | packages: 12 | - nginx 13 | 14 | before_install: 15 | - sudo touch /var/log/nginx/error.log 16 | - sudo chmod a+rw /var/log/nginx/error.log 17 | - sudo chmod a+rw /var/lib/nginx 18 | 19 | notifications: 20 | email: 21 | - damon.oehlman@gmail.com 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Damon Oehlman 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ngineer 2 | 3 | ngineer is a node automation later for nginx that assists with the following: 4 | 5 | * scaffolding a new nginx configuration folder (i.e. `conf/`, `html/`, `logs/`) 6 | * starting and reloading nginx using targeted base path 7 | * adding location proxy directives 8 | 9 | [![NPM](https://nodei.co/npm/ngineer.png)](https://nodei.co/npm/ngineer/) 10 | 11 | [![unstable](https://img.shields.io/badge/stability-unstable-yellowgreen.svg)](https://github.com/dominictarr/stability#unstable) [![Build Status](https://api.travis-ci.org/DamonOehlman/ngineer.svg?branch=master)](https://travis-ci.org/DamonOehlman/ngineer) 12 | 13 | ## Getting Started 14 | 15 | The following example shows how the `ngineer` module can be used to scaffold and start nginx within an application. 16 | 17 | ```js 18 | const async = require('async'); 19 | const nginx = require('ngineer')(__dirname + '/nginx', { 20 | port: 8080 21 | }); 22 | 23 | async.series([ 24 | nginx.scaffold, 25 | nginx.start, 26 | nginx.location('/ngineer').proxy('https://github.com/DamonOehlman/ngineer') 27 | ], function(err) { 28 | if (err) { 29 | return console.error(err); 30 | } 31 | 32 | console.log('started nginx, pid: ' + nginx.pid); 33 | console.log('proxying google at http://localhost:8080/ngineer'); 34 | }); 35 | 36 | nginx.stopOnExit(); 37 | ``` 38 | 39 | The above example proxies a request from through to . A more practical example is shown below where we proxy a local [express](https://github.com/visionmedia/express) application through nginx. 40 | 41 | ```js 42 | const async = require('async'); 43 | const express = require('express'); 44 | 45 | const nginx = require('ngineer')(__dirname + '/nginx', { 46 | port: 8080 47 | }); 48 | 49 | // create our simple express app 50 | express() 51 | .get('/', function(req, res) { 52 | res.end('Hi there'); 53 | }) 54 | .listen(3000, function(err) { 55 | if (err) { 56 | return console.error('could not start bind express app to port 3000', err); 57 | } 58 | 59 | async.series([ 60 | nginx.scaffold, 61 | nginx.start, 62 | nginx.location('/express-test').proxy('http://localhost:3000/') 63 | ], function(err) { 64 | if (err) { 65 | return console.error(err); 66 | } 67 | 68 | console.log('started nginx, pid: ' + nginx.pid); 69 | console.log('express app available at http://localhost:8080/express-test'); 70 | }); 71 | }); 72 | 73 | nginx.stopOnExit(); 74 | ``` 75 | 76 | ## How it Works 77 | 78 | Ngineer expects that it will have a nginx configuration folder that it s responsible for managing (see the `-p` commandline argument). While ngineer doesn't require that it is reponsible for running the nginx process, it is happy to do this. If you do decide to use this option then ensure that you upstart (or similar) the node process running nginx. 79 | 80 | ### Expected Traffic Flow 81 | 82 | When using ngineer it's important to note that you are probably accepting a few levels of HTTP proxying to make the magic happen. In the case of new version of [steelmesh](https://github.com/steelmesh/steelmesh) that is under development, we are using an archictecture similar to what is displayed below: 83 | 84 | ``` 85 | +----------------+ +----------------+ +----------------+ 86 | | |+---->| |+---->| | 87 | | HAproxy | | nginx | | node | 88 | | |<----+| |<----+| | 89 | +----------------+ +----------------+ +----------------+ 90 | ``` 91 | 92 | ### Handling nginx restarts 93 | 94 | Ngineer communicates with the `nginx` process and sends the `HUP` [signal](http://wiki.nginx.org/CommandLine#Loading_a_New_Configuration_Using_Signals) 95 | to flag the the nginx configuration should be reloaded and nginx gracefully restarted. 96 | 97 | ## Why ngineer? 98 | 99 | Why do you want this? Well, because `nginx` does a kick arse job of serving 100 | static files and also proxying services so this provides you an option of using it 101 | over node based proxying solutions. 102 | 103 | ## Prior Art 104 | 105 | * [nginx-http-proxy](https://github.com/liamoehlman/nginx-http-proxy) 106 | 107 | ## Alternative Projects 108 | 109 | Before using `ngineer` you should consider also consider the following 110 | projects (in addition to those listed in Prior Art): 111 | 112 | * [nginx-vhosts](https://github.com/maxogden/nginx-vhosts) 113 | 114 | ## License(s) 115 | 116 | ### MIT 117 | 118 | Copyright (c) 2017 Damon Oehlman 119 | 120 | Permission is hereby granted, free of charge, to any person obtaining 121 | a copy of this software and associated documentation files (the 122 | 'Software'), to deal in the Software without restriction, including 123 | without limitation the rights to use, copy, modify, merge, publish, 124 | distribute, sublicense, and/or sell copies of the Software, and to 125 | permit persons to whom the Software is furnished to do so, subject to 126 | the following conditions: 127 | 128 | The above copyright notice and this permission notice shall be 129 | included in all copies or substantial portions of the Software. 130 | 131 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, 132 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 133 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 134 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 135 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 136 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 137 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 138 | -------------------------------------------------------------------------------- /config.js: -------------------------------------------------------------------------------- 1 | const async = require('async'); 2 | const fs = require('fs'); 3 | const path = require('path'); 4 | 5 | const possibleExecutables = exports.executables = [ 6 | path.resolve('nginx'), 7 | '/usr/sbin/nginx', 8 | '/usr/local/bin/nginx' 9 | ]; 10 | 11 | exports.command = function(basePath, callback) { 12 | const existingFiles = possibleExecutables.filter(fs.existsSync); 13 | 14 | async.map( 15 | existingFiles, 16 | (executable, cb) => fs.stat(executable, cb), 17 | findFirstFile 18 | ); 19 | 20 | function findFirstFile(err, results) { 21 | if (err) { 22 | return callback(err); 23 | } 24 | 25 | // find the first result that is a file 26 | results = results 27 | .map((stats, idx) => ({ 28 | stats: stats, 29 | executable: existingFiles[idx] 30 | })) 31 | .filter(data => data.stats.isFile()); 32 | 33 | if (results.length === 0) { 34 | return callback(new Error('No nginx executable found')); 35 | } 36 | 37 | callback(null, `${results[0].executable} -p ${basePath}/ -c conf/nginx.conf`); 38 | } 39 | }; 40 | -------------------------------------------------------------------------------- /docs/getting-started.md: -------------------------------------------------------------------------------- 1 | The following example shows how the `ngineer` module can be used to scaffold and start nginx within an application. 2 | 3 | <<< examples/proxy-ngineer.js 4 | 5 | The above example proxies a request from http://localhost:8080/ngineer through to https://github.com/DamonOehlman/ngineer. A more practical example is shown below where we proxy a local [express](https://github.com/visionmedia/express) application through nginx. 6 | 7 | <<< examples/proxy-express.js 8 | -------------------------------------------------------------------------------- /docs/howitworks.md: -------------------------------------------------------------------------------- 1 | Ngineer expects that it will have a nginx configuration folder that it s responsible for managing (see the `-p` commandline argument). While ngineer doesn't require that it is reponsible for running the nginx process, it is happy to do this. If you do decide to use this option then ensure that you upstart (or similar) the node process running nginx. 2 | 3 | ### Expected Traffic Flow 4 | 5 | When using ngineer it's important to note that you are probably accepting a few levels of HTTP proxying to make the magic happen. In the case of new version of [steelmesh](https://github.com/steelmesh/steelmesh) that is under development, we are using an archictecture similar to what is displayed below: 6 | 7 | ``` 8 | +----------------+ +----------------+ +----------------+ 9 | | |+---->| |+---->| | 10 | | HAproxy | | nginx | | node | 11 | | |<----+| |<----+| | 12 | +----------------+ +----------------+ +----------------+ 13 | ``` 14 | 15 | ### Handling nginx restarts 16 | 17 | Ngineer communicates with the `nginx` process and sends the `HUP` [signal](http://wiki.nginx.org/CommandLine#Loading_a_New_Configuration_Using_Signals) 18 | to flag the the nginx configuration should be reloaded and nginx gracefully restarted. 19 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | nginx/ 2 | -------------------------------------------------------------------------------- /examples/proxy-express.js: -------------------------------------------------------------------------------- 1 | const async = require('async'); 2 | const express = require('express'); 3 | 4 | const nginx = require('..')(__dirname + '/nginx', { 5 | port: 8080 6 | }); 7 | 8 | // create our simple express app 9 | express() 10 | .get('/', function(req, res) { 11 | res.end('Hi there'); 12 | }) 13 | .listen(3000, function(err) { 14 | if (err) { 15 | return console.error('could not start bind express app to port 3000', err); 16 | } 17 | 18 | async.series([ 19 | nginx.scaffold, 20 | nginx.start, 21 | nginx.location('/express-test').proxy('http://localhost:3000/') 22 | ], function(err) { 23 | if (err) { 24 | return console.error(err); 25 | } 26 | 27 | console.log('started nginx, pid: ' + nginx.pid); 28 | console.log('express app available at http://localhost:8080/express-test'); 29 | }); 30 | }); 31 | 32 | nginx.stopOnExit(); 33 | -------------------------------------------------------------------------------- /examples/proxy-ngineer.js: -------------------------------------------------------------------------------- 1 | const async = require('async'); 2 | const nginx = require('..')(__dirname + '/nginx', { 3 | port: 8080 4 | }); 5 | 6 | async.series([ 7 | nginx.scaffold, 8 | nginx.start, 9 | nginx.location('/ngineer').proxy('https://github.com/DamonOehlman/ngineer') 10 | ], function(err) { 11 | if (err) { 12 | return console.error(err); 13 | } 14 | 15 | console.log('started nginx, pid: ' + nginx.pid); 16 | console.log('proxying google at http://localhost:8080/ngineer'); 17 | }); 18 | 19 | nginx.stopOnExit(); 20 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const async = require('async'); 2 | const debug = require('debug')('ngineer'); 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const EventEmitter = require('events').EventEmitter; 6 | const util = require('util'); 7 | const procinfo = require('procinfo'); 8 | const exec = require('child_process').exec; 9 | 10 | const createLocation = require('./sections/location'); 11 | 12 | module.exports = function(basePath, opts) { 13 | const nginx = new EventEmitter(); 14 | const pidLocation = path.resolve(basePath, (opts || {}).pidFile || 'logs/nginx.pid'); 15 | let online = false; 16 | let pid; 17 | 18 | function monitorProcess(targetPid) { 19 | debug(`looking up process information for process: ${targetPid}`); 20 | procinfo(targetPid, function(err, processData) { 21 | pid = processData && processData.pids[0]; 22 | nginx.online = !err; 23 | 24 | if (pid) { 25 | setTimeout(function() { 26 | monitorProcess(targetPid) 27 | }, 500); 28 | } 29 | }); 30 | } 31 | 32 | function readPID() { 33 | // open the pid file 34 | debug(`looking for pid file: ${pidLocation}`); 35 | fs.readFile(pidLocation, 'utf8', function(err, data) { 36 | let watchTarget = pidLocation; 37 | 38 | // if we hit an error opening the file, then the pid file does not exist 39 | // therefore we will assume that nginx is not running 40 | if (err) { 41 | // if we are currently online, then flag then update the flag and trigger the offline event 42 | if (nginx.online) { 43 | nginx.online = false; 44 | } 45 | } else { 46 | const filePid = parseInt(data, 10); 47 | 48 | // file exists but pid is not yet valid 49 | if (isNaN(filePid)) { 50 | return process.nextTick(readPID); 51 | } 52 | 53 | // otherwise, read the file and check on the process status 54 | return monitorProcess(filePid); 55 | } 56 | 57 | // work up parent folders until we find a valid location 58 | while (!fs.existsSync(watchTarget)) { 59 | watchTarget = path.dirname(watchTarget); 60 | } 61 | 62 | // if the pid file has since been created read it again 63 | if (watchTarget === pidLocation) { 64 | return process.nextTick(readPID); 65 | } 66 | 67 | // check that we can read the file (avoid potential race condition with scaffolding) 68 | try { 69 | fs.accessSync(watchTarget, fs.constants.R_OK); 70 | } catch (e) { 71 | debug(`no read access to ${watchTarget}, sleeping 500ms`); 72 | setTimeout(readPID, 500); 73 | return; 74 | } 75 | 76 | // watch the appropriate location and trigger a reread when something changes 77 | debug(`watching: ${watchTarget}`); 78 | const watcher = fs.watch(watchTarget, { persistent: false }); 79 | watcher.once('change', () => { 80 | debug(`target "${watchTarget}" changed`); 81 | watcher.close(); 82 | readPID(); 83 | }); 84 | }); 85 | } 86 | 87 | /** 88 | #### location(pattern) => NginxLocation 89 | 90 | Create a new location directive for the nginx configuration 91 | 92 | **/ 93 | nginx.location = pattern => createLocation(nginx, basePath, { 94 | ...opts, 95 | pattern, 96 | }); 97 | 98 | /** 99 | #### reload() 100 | 101 | The reload method sends the reload configuration (HUP) signal to the nginx process. 102 | 103 | **/ 104 | nginx.reload = require('./reload')(nginx, basePath, opts); 105 | 106 | /** 107 | #### reset() 108 | 109 | The reset function cleans out the config directory and stops the nginx running if 110 | is running. 111 | **/ 112 | nginx.reset = require('./reset')(nginx, basePath, opts); 113 | 114 | /** 115 | #### scaffold(callback) 116 | 117 | Scaffold an nginx configuration directory based on a known default 118 | configuration. 119 | **/ 120 | nginx.scaffold = require('./scaffold')(nginx, basePath, opts); 121 | 122 | /** 123 | #### start(callback) 124 | 125 | Attempt to start nginx by using a few well known nginx binary locations. 126 | **/ 127 | nginx.start = require('./start')(nginx, basePath, opts); 128 | 129 | 130 | /** 131 | #### stop(callback) 132 | 133 | 134 | Stop the nginx process 135 | **/ 136 | nginx.stop = require('./stop')(nginx, basePath, opts); 137 | nginx.stopOnExit = require('./stop-on-exit')(nginx); 138 | 139 | Object.defineProperty(nginx, 'online', { 140 | get: function() { 141 | return online; 142 | }, 143 | 144 | set: function(value) { 145 | // only update if we are toggling the state 146 | if (value !== online) { 147 | online = value; 148 | nginx.emit(value ? 'online' : 'offline'); 149 | 150 | // if we have gone offline start looking for the pid again 151 | if (! value) { 152 | process.nextTick(readPID); 153 | } 154 | } 155 | } 156 | }); 157 | 158 | Object.defineProperty(nginx, 'pid', { 159 | get: function() { 160 | return pid; 161 | } 162 | }); 163 | 164 | nginx.basePath = basePath; 165 | readPID(); 166 | 167 | return nginx; 168 | }; 169 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngineer", 3 | "description": "Generate proxy routes for nginx", 4 | "author": "Damon Oehlman ", 5 | "version": "1.1.0", 6 | "stability": "unstable", 7 | "dependencies": { 8 | "async": "^3.2.0", 9 | "debug": "^4.1.1", 10 | "mkdirp": "^1.0.4", 11 | "procinfo": "~0.1", 12 | "replacestream": "^4.0.2" 13 | }, 14 | "devDependencies": { 15 | "embellish-readme": "^1.6.0", 16 | "express": "^4", 17 | "mocha": "^8.0.1", 18 | "rimraf": "^3.0.2", 19 | "supertest": "^4.0.2" 20 | }, 21 | "repository": { 22 | "type": "git", 23 | "url": "https://github.com/DamonOehlman/ngineer.git" 24 | }, 25 | "bugs": { 26 | "url": "https://github.com/DamonOehlman/ngineer/issues" 27 | }, 28 | "scripts": { 29 | "test": "mocha test/integration --reporter spec -t 10s", 30 | "gendocs": "embellish README.md" 31 | }, 32 | "main": "index.js", 33 | "directories": { 34 | "test": "test" 35 | }, 36 | "keywords": [ 37 | "nginx", 38 | "automation" 39 | ], 40 | "license": "MIT" 41 | } 42 | -------------------------------------------------------------------------------- /reload.js: -------------------------------------------------------------------------------- 1 | const debug = require('debug')('ngineer:reload'); 2 | const exec = require('child_process').exec; 3 | const config = require('./config'); 4 | 5 | module.exports = function(nginx, basePath, opts) { 6 | return function(callback) { 7 | config.command(basePath, function(err, command) { 8 | if (err) { 9 | return callback(err); 10 | } 11 | 12 | exec(command + ' -t', function(err) { 13 | if (err) { 14 | return callback(err); 15 | } 16 | 17 | debug('reloading nginx config: ' + command + ' -s reload'); 18 | exec(command + ' -s reload', function(err) { 19 | if (err) { 20 | return callback(err); 21 | } 22 | 23 | setTimeout(callback, (opts || {}).reloadDelay || 500); 24 | }); 25 | }); 26 | }); 27 | }; 28 | }; 29 | -------------------------------------------------------------------------------- /reset.js: -------------------------------------------------------------------------------- 1 | const async = require('async'); 2 | const debug = require('debug')('ngineer:reset'); 3 | const exec = require('child_process').exec; 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | const config = require('./config'); 7 | 8 | module.exports = function(ngineer, basePath, opts) { 9 | return function(callback) { 10 | const configPath = path.join(basePath, 'conf'); 11 | 12 | fs.readdir(configPath, function(err, files) { 13 | const filesToDelete = files.map(function(filename) { 14 | return path.join(configPath, filename); 15 | }); 16 | 17 | debug('deleting config files: ', files); 18 | async.forEach(filesToDelete || [], fs.unlink, function(err) { 19 | if (err) { 20 | debug('could not delete config files, aborting stop'); 21 | return callback(err); 22 | } 23 | 24 | debug('attempting to stop nginx'); 25 | ngineer.stop(callback); 26 | }); 27 | }); 28 | }; 29 | }; 30 | -------------------------------------------------------------------------------- /scaffold.js: -------------------------------------------------------------------------------- 1 | const async = require('async'); 2 | const debug = require('debug')('ngineer:scaffold'); 3 | const mkdirp = require('mkdirp'); 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | const replaceStream = require('replacestream'); 7 | const CONFIG_DIRS = [ 'conf', 'html', 'logs' ]; 8 | const REQUIRED_FILES = [ 9 | 'conf/mime.types', 10 | 'conf/nginx.conf', 11 | 'html/index.html' 12 | ]; 13 | 14 | const checkFileExists = (filename, callback) => fs.access(filename, err => callback(null, !err)); 15 | 16 | module.exports = function(ngineer, basePath, opts) { 17 | const scaffoldBase = path.resolve(__dirname, 'scaffold'); 18 | 19 | function scaffoldFile(target, callback) { 20 | const src = path.join(scaffoldBase, target.slice(basePath.length)); 21 | const writer = fs.createWriteStream(target); 22 | const reader = fs.createReadStream(src); 23 | 24 | debug('scaffolding file: ' + src); 25 | reader.on('error', callback); 26 | writer.on('error', callback).on('close', callback); 27 | 28 | reader 29 | .pipe(replaceStream('{{ port }}', (opts || {}).port || 8080)) 30 | .pipe(replaceStream('{{ worker_connections }}', (opts || {}).worker_connections || 1024 )) 31 | .pipe(writer); 32 | } 33 | 34 | return function(callback) { 35 | const configPaths = CONFIG_DIRS.map(function(subpath) { 36 | return path.join(basePath, subpath); 37 | }); 38 | 39 | const requiredFiles = REQUIRED_FILES.map(function(subpath) { 40 | return path.join(basePath, subpath); 41 | }); 42 | 43 | debug('ensuring required directories exist: ', configPaths); 44 | Promise.all(configPaths.map(requiredPath => mkdirp(requiredPath))) 45 | .then(() => { 46 | debug('required directories exist, checking for required files: ', requiredFiles); 47 | async.reject(requiredFiles, checkFileExists, function(err, results) { 48 | async.forEach(results, scaffoldFile, function(scaffoldErr) { 49 | debug('scaffolding complete'); 50 | callback(scaffoldErr); 51 | }); 52 | }); 53 | }) 54 | .catch(callback); 55 | }; 56 | }; 57 | -------------------------------------------------------------------------------- /scaffold/conf/mime.types: -------------------------------------------------------------------------------- 1 | types { 2 | text/html html htm shtml; 3 | text/css css; 4 | text/xml xml; 5 | image/gif gif; 6 | image/jpeg jpeg jpg; 7 | application/x-javascript js; 8 | application/atom+xml atom; 9 | application/rss+xml rss; 10 | 11 | text/mathml mml; 12 | text/plain txt; 13 | text/vnd.sun.j2me.app-descriptor jad; 14 | text/vnd.wap.wml wml; 15 | text/x-component htc; 16 | 17 | image/png png; 18 | image/tiff tif tiff; 19 | image/vnd.wap.wbmp wbmp; 20 | image/x-icon ico; 21 | image/x-jng jng; 22 | image/x-ms-bmp bmp; 23 | image/svg+xml svg svgz; 24 | image/webp webp; 25 | 26 | application/java-archive jar war ear; 27 | application/mac-binhex40 hqx; 28 | application/msword doc; 29 | application/pdf pdf; 30 | application/postscript ps eps ai; 31 | application/rtf rtf; 32 | application/vnd.ms-excel xls; 33 | application/vnd.ms-powerpoint ppt; 34 | application/vnd.wap.wmlc wmlc; 35 | application/vnd.google-earth.kml+xml kml; 36 | application/vnd.google-earth.kmz kmz; 37 | application/x-7z-compressed 7z; 38 | application/x-cocoa cco; 39 | application/x-java-archive-diff jardiff; 40 | application/x-java-jnlp-file jnlp; 41 | application/x-makeself run; 42 | application/x-perl pl pm; 43 | application/x-pilot prc pdb; 44 | application/x-rar-compressed rar; 45 | application/x-redhat-package-manager rpm; 46 | application/x-sea sea; 47 | application/x-shockwave-flash swf; 48 | application/x-stuffit sit; 49 | application/x-tcl tcl tk; 50 | application/x-x509-ca-cert der pem crt; 51 | application/x-xpinstall xpi; 52 | application/xhtml+xml xhtml; 53 | application/zip zip; 54 | 55 | application/octet-stream bin exe dll; 56 | application/octet-stream deb; 57 | application/octet-stream dmg; 58 | application/octet-stream eot; 59 | application/octet-stream iso img; 60 | application/octet-stream msi msp msm; 61 | 62 | audio/midi mid midi kar; 63 | audio/mpeg mp3; 64 | audio/ogg ogg; 65 | audio/x-m4a m4a; 66 | audio/x-realaudio ra; 67 | 68 | video/3gpp 3gpp 3gp; 69 | video/mp4 mp4; 70 | video/mpeg mpeg mpg; 71 | video/quicktime mov; 72 | video/webm webm; 73 | video/x-flv flv; 74 | video/x-m4v m4v; 75 | video/x-mng mng; 76 | video/x-ms-asf asx asf; 77 | video/x-ms-wmv wmv; 78 | video/x-msvideo avi; 79 | } 80 | -------------------------------------------------------------------------------- /scaffold/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections {{ worker_connections }}; 3 | } 4 | 5 | error_log logs/error.log debug; 6 | pid logs/nginx.pid; 7 | 8 | http { 9 | access_log logs/access.log combined; 10 | include mime.types; 11 | 12 | server { 13 | listen {{ port }}; 14 | server_name _; 15 | 16 | index index.html index.htm; 17 | root html; 18 | 19 | include locations/*; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /scaffold/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Scaffolded NGINX 4 | 5 | 6 | This file has been scaffolded by ngineer, you should replace it. 7 | 8 | 9 | -------------------------------------------------------------------------------- /sections/base.js: -------------------------------------------------------------------------------- 1 | const debug = require('debug')('ngineer:section:base'); 2 | const mkdirp = require('mkdirp'); 3 | const path = require('path'); 4 | const fs = require('fs'); 5 | 6 | module.exports = function(nginx, basePath, opts) { 7 | const directives = []; 8 | 9 | function section(callback) { 10 | debug(`initializing section for basepath = ${basePath}, filename = ${section.filename}`); 11 | const filename = path.join(basePath, 'conf', section.filename); 12 | 13 | // if the section doesn't have a filename, then do nothing 14 | if (! section.filename) { 15 | return callback(); 16 | } 17 | 18 | mkdirp(path.dirname(filename)) 19 | .then(() => { 20 | debug('writing section file: ' + filename); 21 | fs.writeFile(filename, section.output, 'utf8', function(err) { 22 | if (err) { 23 | return callback(err); 24 | } 25 | 26 | nginx.reload(callback); 27 | }); 28 | }) 29 | .catch(callback); 30 | } 31 | 32 | section.directive = function() { 33 | directives.push([].slice.call(arguments)); 34 | }; 35 | 36 | section.save = section; 37 | 38 | Object.defineProperty(section, 'directives', { 39 | get: function() { 40 | return [].concat(directives); 41 | } 42 | }); 43 | 44 | return section; 45 | }; 46 | -------------------------------------------------------------------------------- /sections/location.js: -------------------------------------------------------------------------------- 1 | const debug = require('debug')('ngineer:section:location'); 2 | const reStripChars = /(^\/|\s|\/$)/g; 3 | const reToUnderscore = /\//; 4 | const createSection = require('./base'); 5 | 6 | module.exports = function(nginx, basePath, { pattern, ...opts }) { 7 | debug(`creating location section, pattern: ${pattern}`) 8 | 9 | const section = createSection(nginx, basePath, opts); 10 | 11 | section.filename = `locations/${pattern.replace(reStripChars, '').replace(reToUnderscore, '_')}`; 12 | section.proxy = function(targetUrl, opts) { 13 | section.directive('proxy_pass', targetUrl); 14 | section.directive('proxy_http_version', (opts || {}).httpVersion || '1.1'); 15 | section.directive('proxy_set_header', 'Upgrade $http_upgrade'); 16 | section.directive('proxy_set_header', 'Connection "upgrade"'); 17 | 18 | return section; 19 | }; 20 | 21 | Object.defineProperty(section, 'output', { 22 | get: function() { 23 | const lines = section.directives.map(parts => ` ${parts.join(' ')};`); 24 | return `location ${pattern} {\n${lines.join('\n')}\n}\n`; 25 | } 26 | }); 27 | 28 | return section; 29 | }; 30 | -------------------------------------------------------------------------------- /start.js: -------------------------------------------------------------------------------- 1 | const async = require('async'); 2 | const debug = require('debug')('ngineer:start'); 3 | const exec = require('child_process').exec; 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | const config = require('./config'); 7 | 8 | module.exports = function(ngineer, basePath, opts) { 9 | function nginxStart(callback) { 10 | config.command(basePath, function(err, command) { 11 | if (err) { 12 | return callback(err); 13 | } 14 | 15 | debug('running: ' + command); 16 | exec(command, function(err) { 17 | debug('started: ', err); 18 | 19 | if (err) { 20 | return callback(err); 21 | } 22 | 23 | callback(); 24 | }); 25 | }); 26 | } 27 | 28 | return function(callback) { 29 | let startTimeout; 30 | 31 | function handleOnline() { 32 | debug('detected nginx online'); 33 | clearTimeout(startTimeout); 34 | callback(); 35 | } 36 | 37 | // if already online do nothing 38 | if (ngineer.online) { 39 | return callback(); 40 | } 41 | 42 | ngineer.once('online', handleOnline); 43 | 44 | startTimeout = setTimeout(function() { 45 | ngineer.removeListener('online', handleOnline); 46 | nginxStart(callback); 47 | }, 500); 48 | }; 49 | }; 50 | -------------------------------------------------------------------------------- /stop-on-exit.js: -------------------------------------------------------------------------------- 1 | const debug = require('debug')('ngineer:stop-on-exit'); 2 | 3 | module.exports = function(ngineer) { 4 | function stopNginxAndExit() { 5 | debug('terminate detected, stopping nginx and exiting process'); 6 | ngineer.stop(() => process.exit(0)); 7 | } 8 | 9 | return function() { 10 | process.on('exit', ngineer.stop); 11 | process.on('SIGINT', stopNginxAndExit); 12 | process.on('uncaughtException', stopNginxAndExit); 13 | }; 14 | }; 15 | -------------------------------------------------------------------------------- /stop.js: -------------------------------------------------------------------------------- 1 | const async = require('async'); 2 | const debug = require('debug')('ngineer:stop'); 3 | const exec = require('child_process').exec; 4 | const path = require('path'); 5 | const fs = require('fs'); 6 | const config = require('./config'); 7 | 8 | module.exports = function(ngineer, basePath, opts) { 9 | return function(callback) { 10 | config.command(basePath, function(err, command) { 11 | if (err) { 12 | return callback(err); 13 | } 14 | 15 | debug(`running: ${command} -s stop`); 16 | exec(`${command} -s stop`, function() { 17 | callback(); 18 | }); 19 | }); 20 | }; 21 | }; 22 | -------------------------------------------------------------------------------- /test/helpers/nginx.js: -------------------------------------------------------------------------------- 1 | const debug = require('debug')('ngineer:tests'); 2 | const path = require('path'); 3 | const fs = require('fs'); 4 | const { exec } = require('child_process'); 5 | 6 | const nginxExecutable = [ 7 | '/usr/sbin/nginx', 8 | '/usr/local/bin/nginx' 9 | ].filter(file => fs.existsSync(file))[0]; 10 | const serverPath = path.resolve(__dirname, '..', 'integration', 'server'); 11 | const nginxCommand = `${nginxExecutable} -p ${serverPath}/ -c conf/nginx.conf`; 12 | 13 | function nginx(command) { 14 | return function(callback) { 15 | callback = callback || function() {}; 16 | 17 | if (!nginxExecutable) { 18 | return callback(new Error('nginx not found on machine')); 19 | } 20 | 21 | debug('running: ' + command); 22 | exec(command, function(err) { 23 | debug('started: ', err); 24 | 25 | if (err) { 26 | return callback(err); 27 | } 28 | 29 | setTimeout(callback, 1000); 30 | }); 31 | }; 32 | } 33 | 34 | exports.path = serverPath; 35 | exports.start = nginx(nginxCommand); 36 | exports.stop = nginx(`${nginxCommand} -s stop`); 37 | exports.url = 'http://localhost:8886'; 38 | -------------------------------------------------------------------------------- /test/helpers/test-server.js: -------------------------------------------------------------------------------- 1 | const { createServer } = require('http'); 2 | 3 | exports.createTestServer = () => createServer((req, res) => { 4 | res.end('Test Server'); 5 | }); 6 | -------------------------------------------------------------------------------- /test/integration/add-location.js: -------------------------------------------------------------------------------- 1 | const debug = require('debug')('ngineer:test:add-location'); 2 | const ngineer = require('../../'); 3 | const path = require('path'); 4 | const assert = require('assert'); 5 | const exec = require('child_process').exec; 6 | const { createTestServer } = require('../helpers/test-server'); 7 | const nginx = require('../helpers/nginx'); 8 | const request = require('supertest'); 9 | const rimraf = require('rimraf'); 10 | 11 | describe('add location', function() { 12 | let instance; 13 | let testServer; 14 | 15 | before(nginx.start); 16 | before(() => { 17 | testServer = createTestServer(); 18 | }); 19 | 20 | after(nginx.stop); 21 | after(done => rimraf(path.join(nginx.path, 'conf', 'locations'), done)); 22 | after(() => { 23 | testServer.close(); 24 | }); 25 | 26 | it('should validate nginx is running', function(done) { 27 | request(nginx.url).get('/').expect(200, done); 28 | }); 29 | 30 | it('should be able to create an ngineer instance', function(done) { 31 | instance = ngineer(nginx.path).once('online', done); 32 | }); 33 | 34 | it('should be able to start the test node server', function(done) { 35 | testServer.listen(3000, done); 36 | }); 37 | 38 | it('should be able to validate the test server is running', function(done) { 39 | request(testServer) 40 | .get('/') 41 | .expect('Test Server') 42 | .expect(200, done); 43 | }); 44 | 45 | it('should be able to add a new location to the nginx server', function(done) { 46 | instance 47 | .location('/test') 48 | .proxy('http://localhost:3000/') 49 | .save(done); 50 | }); 51 | 52 | it('should be able to request the new location', function(done) { 53 | request(nginx.url).get('/test').expect(200, done); 54 | }); 55 | }) 56 | -------------------------------------------------------------------------------- /test/integration/detect-online.js: -------------------------------------------------------------------------------- 1 | const ngineer = require('../../'); 2 | const path = require('path'); 3 | const assert = require('assert'); 4 | const exec = require('child_process').exec; 5 | const nginx = require('../helpers/nginx'); 6 | const request = require('supertest'); 7 | 8 | describe('detect online', function() { 9 | let instance; 10 | 11 | before(nginx.start); 12 | after(nginx.stop); 13 | 14 | it('should validate nginx is running', function(done) { 15 | request(nginx.url).get('/').expect(200, done); 16 | }); 17 | 18 | it('should be able to create an ngineer instance and detect nginx online', function(done) { 19 | instance = ngineer(nginx.path).once('online', done); 20 | }); 21 | 22 | it('should be able to stop nginx and receive an offline event', function(done) { 23 | instance.once('offline', done); 24 | nginx.stop(); 25 | }); 26 | 27 | it('should be able to detect nginx starting again', function(done) { 28 | instance.once('online', done); 29 | nginx.start(); 30 | }); 31 | }) 32 | -------------------------------------------------------------------------------- /test/integration/mocha.opts: -------------------------------------------------------------------------------- 1 | --reporter spec --exit 2 | -------------------------------------------------------------------------------- /test/integration/server/conf/mime.types: -------------------------------------------------------------------------------- 1 | 2 | types { 3 | text/html html htm shtml; 4 | text/css css; 5 | text/xml xml; 6 | image/gif gif; 7 | image/jpeg jpeg jpg; 8 | application/x-javascript js; 9 | application/atom+xml atom; 10 | application/rss+xml rss; 11 | 12 | text/mathml mml; 13 | text/plain txt; 14 | text/vnd.sun.j2me.app-descriptor jad; 15 | text/vnd.wap.wml wml; 16 | text/x-component htc; 17 | 18 | image/png png; 19 | image/tiff tif tiff; 20 | image/vnd.wap.wbmp wbmp; 21 | image/x-icon ico; 22 | image/x-jng jng; 23 | image/x-ms-bmp bmp; 24 | image/svg+xml svg svgz; 25 | image/webp webp; 26 | 27 | application/java-archive jar war ear; 28 | application/mac-binhex40 hqx; 29 | application/msword doc; 30 | application/pdf pdf; 31 | application/postscript ps eps ai; 32 | application/rtf rtf; 33 | application/vnd.ms-excel xls; 34 | application/vnd.ms-powerpoint ppt; 35 | application/vnd.wap.wmlc wmlc; 36 | application/vnd.google-earth.kml+xml kml; 37 | application/vnd.google-earth.kmz kmz; 38 | application/x-7z-compressed 7z; 39 | application/x-cocoa cco; 40 | application/x-java-archive-diff jardiff; 41 | application/x-java-jnlp-file jnlp; 42 | application/x-makeself run; 43 | application/x-perl pl pm; 44 | application/x-pilot prc pdb; 45 | application/x-rar-compressed rar; 46 | application/x-redhat-package-manager rpm; 47 | application/x-sea sea; 48 | application/x-shockwave-flash swf; 49 | application/x-stuffit sit; 50 | application/x-tcl tcl tk; 51 | application/x-x509-ca-cert der pem crt; 52 | application/x-xpinstall xpi; 53 | application/xhtml+xml xhtml; 54 | application/zip zip; 55 | 56 | application/octet-stream bin exe dll; 57 | application/octet-stream deb; 58 | application/octet-stream dmg; 59 | application/octet-stream eot; 60 | application/octet-stream iso img; 61 | application/octet-stream msi msp msm; 62 | 63 | audio/midi mid midi kar; 64 | audio/mpeg mp3; 65 | audio/ogg ogg; 66 | audio/x-m4a m4a; 67 | audio/x-realaudio ra; 68 | 69 | video/3gpp 3gpp 3gp; 70 | video/mp4 mp4; 71 | video/mpeg mpeg mpg; 72 | video/quicktime mov; 73 | video/webm webm; 74 | video/x-flv flv; 75 | video/x-m4v m4v; 76 | video/x-mng mng; 77 | video/x-ms-asf asx asf; 78 | video/x-ms-wmv wmv; 79 | video/x-msvideo avi; 80 | } -------------------------------------------------------------------------------- /test/integration/server/conf/nginx.conf: -------------------------------------------------------------------------------- 1 | events { 2 | worker_connections 1024; 3 | } 4 | 5 | error_log logs/error.log debug; 6 | pid logs/nginx.pid; 7 | 8 | http { 9 | access_log logs/access.log combined; 10 | include mime.types; 11 | 12 | server { 13 | listen 8886; 14 | server_name _; 15 | 16 | index index.html index.htm; 17 | root html; 18 | 19 | include locations/*; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/integration/server/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | Hi 3 | -------------------------------------------------------------------------------- /test/integration/server/logs/README.md: -------------------------------------------------------------------------------- 1 | # nginx logs dir 2 | 3 | This file exists to ensure the log path gets created for nginx. It's a convenience. -------------------------------------------------------------------------------- /test/integration/start.js: -------------------------------------------------------------------------------- 1 | const ngineer = require('../../'); 2 | const { EventEmitter } = require('events'); 3 | const path = require('path'); 4 | const assert = require('assert'); 5 | const { exec } = require('child_process'); 6 | const nginx = require('../helpers/nginx'); 7 | const request = require('supertest'); 8 | const rimraf = require('rimraf'); 9 | 10 | describe('start nginx', function() { 11 | let instance; 12 | 13 | after(nginx.stop); 14 | 15 | it('should be able to create an ngineer instance', function() { 16 | instance = ngineer(nginx.path); 17 | assert(instance instanceof EventEmitter); 18 | }); 19 | 20 | it('should be able to start nginx', function(done) { 21 | instance.start(function(err) { 22 | assert.ifError(err); 23 | done(err); 24 | }); 25 | }); 26 | 27 | it('should validate nginx is running', function(done) { 28 | request(nginx.url).get('/').expect(200, done); 29 | }); 30 | }) 31 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | accepts@~1.3.7: 6 | version "1.3.7" 7 | resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" 8 | integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== 9 | dependencies: 10 | mime-types "~2.1.24" 11 | negotiator "0.6.2" 12 | 13 | ansi-colors@4.1.1: 14 | version "4.1.1" 15 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" 16 | integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== 17 | 18 | ansi-regex@^3.0.0: 19 | version "3.0.0" 20 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 21 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 22 | 23 | ansi-regex@^4.1.0: 24 | version "4.1.0" 25 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" 26 | integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== 27 | 28 | ansi-styles@^3.2.0, ansi-styles@^3.2.1: 29 | version "3.2.1" 30 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 31 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 32 | dependencies: 33 | color-convert "^1.9.0" 34 | 35 | anymatch@~3.1.1: 36 | version "3.1.1" 37 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" 38 | integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== 39 | dependencies: 40 | normalize-path "^3.0.0" 41 | picomatch "^2.0.4" 42 | 43 | argparse@^1.0.7: 44 | version "1.0.10" 45 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" 46 | integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== 47 | dependencies: 48 | sprintf-js "~1.0.2" 49 | 50 | array-flatten@1.1.1: 51 | version "1.1.1" 52 | resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" 53 | integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= 54 | 55 | array.prototype.map@^1.0.1: 56 | version "1.0.2" 57 | resolved "https://registry.yarnpkg.com/array.prototype.map/-/array.prototype.map-1.0.2.tgz#9a4159f416458a23e9483078de1106b2ef68f8ec" 58 | integrity sha512-Az3OYxgsa1g7xDYp86l0nnN4bcmuEITGe1rbdEBVkrqkzMgDcbdQ2R7r41pNzti+4NMces3H8gMmuioZUilLgw== 59 | dependencies: 60 | define-properties "^1.1.3" 61 | es-abstract "^1.17.0-next.1" 62 | es-array-method-boxes-properly "^1.0.0" 63 | is-string "^1.0.4" 64 | 65 | async@^3.2.0: 66 | version "3.2.0" 67 | resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" 68 | integrity sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw== 69 | 70 | asynckit@^0.4.0: 71 | version "0.4.0" 72 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 73 | integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= 74 | 75 | balanced-match@^1.0.0: 76 | version "1.0.0" 77 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 78 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 79 | 80 | binary-extensions@^2.0.0: 81 | version "2.0.0" 82 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" 83 | integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== 84 | 85 | body-parser@1.19.0: 86 | version "1.19.0" 87 | resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" 88 | integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== 89 | dependencies: 90 | bytes "3.1.0" 91 | content-type "~1.0.4" 92 | debug "2.6.9" 93 | depd "~1.1.2" 94 | http-errors "1.7.2" 95 | iconv-lite "0.4.24" 96 | on-finished "~2.3.0" 97 | qs "6.7.0" 98 | raw-body "2.4.0" 99 | type-is "~1.6.17" 100 | 101 | brace-expansion@^1.1.7: 102 | version "1.1.11" 103 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 104 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 105 | dependencies: 106 | balanced-match "^1.0.0" 107 | concat-map "0.0.1" 108 | 109 | braces@~3.0.2: 110 | version "3.0.2" 111 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 112 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 113 | dependencies: 114 | fill-range "^7.0.1" 115 | 116 | browser-stdout@1.3.1: 117 | version "1.3.1" 118 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 119 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 120 | 121 | bytes@3.1.0: 122 | version "3.1.0" 123 | resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" 124 | integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== 125 | 126 | camelcase@^5.0.0: 127 | version "5.3.1" 128 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 129 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 130 | 131 | caseless@^0.12.0: 132 | version "0.12.0" 133 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 134 | integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= 135 | 136 | chalk@^2.4.2: 137 | version "2.4.2" 138 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 139 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 140 | dependencies: 141 | ansi-styles "^3.2.1" 142 | escape-string-regexp "^1.0.5" 143 | supports-color "^5.3.0" 144 | 145 | chokidar@3.3.1: 146 | version "3.3.1" 147 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450" 148 | integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg== 149 | dependencies: 150 | anymatch "~3.1.1" 151 | braces "~3.0.2" 152 | glob-parent "~5.1.0" 153 | is-binary-path "~2.1.0" 154 | is-glob "~4.0.1" 155 | normalize-path "~3.0.0" 156 | readdirp "~3.3.0" 157 | optionalDependencies: 158 | fsevents "~2.1.2" 159 | 160 | cliui@^5.0.0: 161 | version "5.0.0" 162 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" 163 | integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== 164 | dependencies: 165 | string-width "^3.1.0" 166 | strip-ansi "^5.2.0" 167 | wrap-ansi "^5.1.0" 168 | 169 | color-convert@^1.9.0: 170 | version "1.9.3" 171 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 172 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 173 | dependencies: 174 | color-name "1.1.3" 175 | 176 | color-name@1.1.3: 177 | version "1.1.3" 178 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 179 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 180 | 181 | combined-stream@^1.0.6: 182 | version "1.0.8" 183 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 184 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 185 | dependencies: 186 | delayed-stream "~1.0.0" 187 | 188 | component-emitter@^1.2.0: 189 | version "1.3.0" 190 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" 191 | integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== 192 | 193 | concat-map@0.0.1: 194 | version "0.0.1" 195 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 196 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 197 | 198 | content-disposition@0.5.3: 199 | version "0.5.3" 200 | resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" 201 | integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== 202 | dependencies: 203 | safe-buffer "5.1.2" 204 | 205 | content-type@~1.0.4: 206 | version "1.0.4" 207 | resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" 208 | integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== 209 | 210 | cookie-signature@1.0.6: 211 | version "1.0.6" 212 | resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" 213 | integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= 214 | 215 | cookie@0.4.0: 216 | version "0.4.0" 217 | resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" 218 | integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== 219 | 220 | cookiejar@^2.1.0: 221 | version "2.1.2" 222 | resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.1.2.tgz#dd8a235530752f988f9a0844f3fc589e3111125c" 223 | integrity sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA== 224 | 225 | core-util-is@~1.0.0: 226 | version "1.0.2" 227 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 228 | integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= 229 | 230 | debug@2.6.9: 231 | version "2.6.9" 232 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 233 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 234 | dependencies: 235 | ms "2.0.0" 236 | 237 | debug@3.2.6, debug@^3.1.0: 238 | version "3.2.6" 239 | resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b" 240 | integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ== 241 | dependencies: 242 | ms "^2.1.1" 243 | 244 | debug@^4.1.1: 245 | version "4.1.1" 246 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791" 247 | integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw== 248 | dependencies: 249 | ms "^2.1.1" 250 | 251 | decamelize@^1.2.0: 252 | version "1.2.0" 253 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 254 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 255 | 256 | define-properties@^1.1.2, define-properties@^1.1.3: 257 | version "1.1.3" 258 | resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" 259 | integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== 260 | dependencies: 261 | object-keys "^1.0.12" 262 | 263 | delayed-stream@~1.0.0: 264 | version "1.0.0" 265 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 266 | integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= 267 | 268 | depd@~1.1.2: 269 | version "1.1.2" 270 | resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" 271 | integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= 272 | 273 | destroy@~1.0.4: 274 | version "1.0.4" 275 | resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" 276 | integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= 277 | 278 | diff@4.0.2: 279 | version "4.0.2" 280 | resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" 281 | integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== 282 | 283 | ee-first@1.1.1: 284 | version "1.1.1" 285 | resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" 286 | integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= 287 | 288 | embellish-readme@^1.6.0: 289 | version "1.6.0" 290 | resolved "https://registry.yarnpkg.com/embellish-readme/-/embellish-readme-1.6.0.tgz#b1d788b07eb66cc3a6bb3b66d4426d22bfc71f86" 291 | integrity sha512-IVv1UlzWFhqc4N80cdHB6PCpHrseAzfdBp8gJj9Q4O5jqnZKWSdKFRbf1uusa9f6bPmSiUErx52oLQ8f/Jpnlw== 292 | dependencies: 293 | debug "^4.1.1" 294 | formatter "^0.4.1" 295 | marked-ast "^0.3.0" 296 | marked-ast-markdown "^2.1.0" 297 | out "^1.1.0" 298 | r2 "^2.0.1" 299 | 300 | emoji-regex@^7.0.1: 301 | version "7.0.3" 302 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" 303 | integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== 304 | 305 | encodeurl@~1.0.2: 306 | version "1.0.2" 307 | resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" 308 | integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= 309 | 310 | entities@^2.0.2: 311 | version "2.0.3" 312 | resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.3.tgz#5c487e5742ab93c15abb5da22759b8590ec03b7f" 313 | integrity sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ== 314 | 315 | es-abstract@^1.17.0-next.1, es-abstract@^1.17.4, es-abstract@^1.17.5: 316 | version "1.17.5" 317 | resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" 318 | integrity sha512-BR9auzDbySxOcfog0tLECW8l28eRGpDpU3Dm3Hp4q/N+VtLTmyj4EUN088XZWQDW/hzj6sYRDXeOFsaAODKvpg== 319 | dependencies: 320 | es-to-primitive "^1.2.1" 321 | function-bind "^1.1.1" 322 | has "^1.0.3" 323 | has-symbols "^1.0.1" 324 | is-callable "^1.1.5" 325 | is-regex "^1.0.5" 326 | object-inspect "^1.7.0" 327 | object-keys "^1.1.1" 328 | object.assign "^4.1.0" 329 | string.prototype.trimleft "^2.1.1" 330 | string.prototype.trimright "^2.1.1" 331 | 332 | es-array-method-boxes-properly@^1.0.0: 333 | version "1.0.0" 334 | resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" 335 | integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== 336 | 337 | es-get-iterator@^1.0.2: 338 | version "1.1.0" 339 | resolved "https://registry.yarnpkg.com/es-get-iterator/-/es-get-iterator-1.1.0.tgz#bb98ad9d6d63b31aacdc8f89d5d0ee57bcb5b4c8" 340 | integrity sha512-UfrmHuWQlNMTs35e1ypnvikg6jCz3SK8v8ImvmDsh36fCVUR1MqoFDiyn0/k52C8NqO3YsO8Oe0azeesNuqSsQ== 341 | dependencies: 342 | es-abstract "^1.17.4" 343 | has-symbols "^1.0.1" 344 | is-arguments "^1.0.4" 345 | is-map "^2.0.1" 346 | is-set "^2.0.1" 347 | is-string "^1.0.5" 348 | isarray "^2.0.5" 349 | 350 | es-to-primitive@^1.2.1: 351 | version "1.2.1" 352 | resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" 353 | integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== 354 | dependencies: 355 | is-callable "^1.1.4" 356 | is-date-object "^1.0.1" 357 | is-symbol "^1.0.2" 358 | 359 | escape-html@~1.0.3: 360 | version "1.0.3" 361 | resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" 362 | integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= 363 | 364 | escape-string-regexp@1.0.5, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: 365 | version "1.0.5" 366 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 367 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 368 | 369 | esprima@^4.0.0: 370 | version "4.0.1" 371 | resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" 372 | integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== 373 | 374 | etag@~1.8.1: 375 | version "1.8.1" 376 | resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" 377 | integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= 378 | 379 | express@^4: 380 | version "4.17.1" 381 | resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" 382 | integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== 383 | dependencies: 384 | accepts "~1.3.7" 385 | array-flatten "1.1.1" 386 | body-parser "1.19.0" 387 | content-disposition "0.5.3" 388 | content-type "~1.0.4" 389 | cookie "0.4.0" 390 | cookie-signature "1.0.6" 391 | debug "2.6.9" 392 | depd "~1.1.2" 393 | encodeurl "~1.0.2" 394 | escape-html "~1.0.3" 395 | etag "~1.8.1" 396 | finalhandler "~1.1.2" 397 | fresh "0.5.2" 398 | merge-descriptors "1.0.1" 399 | methods "~1.1.2" 400 | on-finished "~2.3.0" 401 | parseurl "~1.3.3" 402 | path-to-regexp "0.1.7" 403 | proxy-addr "~2.0.5" 404 | qs "6.7.0" 405 | range-parser "~1.2.1" 406 | safe-buffer "5.1.2" 407 | send "0.17.1" 408 | serve-static "1.14.1" 409 | setprototypeof "1.1.1" 410 | statuses "~1.5.0" 411 | type-is "~1.6.18" 412 | utils-merge "1.0.1" 413 | vary "~1.1.2" 414 | 415 | extend@^3.0.0: 416 | version "3.0.2" 417 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" 418 | integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== 419 | 420 | fill-range@^7.0.1: 421 | version "7.0.1" 422 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 423 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 424 | dependencies: 425 | to-regex-range "^5.0.1" 426 | 427 | finalhandler@~1.1.2: 428 | version "1.1.2" 429 | resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" 430 | integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== 431 | dependencies: 432 | debug "2.6.9" 433 | encodeurl "~1.0.2" 434 | escape-html "~1.0.3" 435 | on-finished "~2.3.0" 436 | parseurl "~1.3.3" 437 | statuses "~1.5.0" 438 | unpipe "~1.0.0" 439 | 440 | find-up@4.1.0: 441 | version "4.1.0" 442 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" 443 | integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== 444 | dependencies: 445 | locate-path "^5.0.0" 446 | path-exists "^4.0.0" 447 | 448 | find-up@^3.0.0: 449 | version "3.0.0" 450 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" 451 | integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== 452 | dependencies: 453 | locate-path "^3.0.0" 454 | 455 | flat@^4.1.0: 456 | version "4.1.0" 457 | resolved "https://registry.yarnpkg.com/flat/-/flat-4.1.0.tgz#090bec8b05e39cba309747f1d588f04dbaf98db2" 458 | integrity sha512-Px/TiLIznH7gEDlPXcUD4KnBusa6kR6ayRUVcnEAbreRIuhkqow/mun59BuRXwoYk7ZQOLW1ZM05ilIvK38hFw== 459 | dependencies: 460 | is-buffer "~2.0.3" 461 | 462 | form-data@^2.3.1: 463 | version "2.5.1" 464 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" 465 | integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== 466 | dependencies: 467 | asynckit "^0.4.0" 468 | combined-stream "^1.0.6" 469 | mime-types "^2.1.12" 470 | 471 | formatter@^0.4.1: 472 | version "0.4.1" 473 | resolved "https://registry.yarnpkg.com/formatter/-/formatter-0.4.1.tgz#f43afedf8f2e7454ceae02ce45567a9fa3277fb8" 474 | integrity sha1-9Dr+348udFTOrgLORVZ6n6Mnf7g= 475 | 476 | formidable@^1.2.0: 477 | version "1.2.2" 478 | resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.2.2.tgz#bf69aea2972982675f00865342b982986f6b8dd9" 479 | integrity sha512-V8gLm+41I/8kguQ4/o1D3RIHRmhYFG4pnNyonvua+40rqcEmT4+V71yaZ3B457xbbgCsCfjSPi65u/W6vK1U5Q== 480 | 481 | forwarded@~0.1.2: 482 | version "0.1.2" 483 | resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" 484 | integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= 485 | 486 | fresh@0.5.2: 487 | version "0.5.2" 488 | resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" 489 | integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= 490 | 491 | fs.realpath@^1.0.0: 492 | version "1.0.0" 493 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 494 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 495 | 496 | fsevents@~2.1.2: 497 | version "2.1.3" 498 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.3.tgz#fb738703ae8d2f9fe900c33836ddebee8b97f23e" 499 | integrity sha512-Auw9a4AxqWpa9GUfj370BMPzzyncfBABW8Mab7BGWBYDj4Isgq+cDKtx0i6u9jcX9pQDnswsaaOTgTmA5pEjuQ== 500 | 501 | function-bind@^1.1.1: 502 | version "1.1.1" 503 | resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" 504 | integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== 505 | 506 | get-caller-file@^2.0.1: 507 | version "2.0.5" 508 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 509 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 510 | 511 | glob-parent@~5.1.0: 512 | version "5.1.1" 513 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" 514 | integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== 515 | dependencies: 516 | is-glob "^4.0.1" 517 | 518 | glob@7.1.6, glob@^7.1.3: 519 | version "7.1.6" 520 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 521 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 522 | dependencies: 523 | fs.realpath "^1.0.0" 524 | inflight "^1.0.4" 525 | inherits "2" 526 | minimatch "^3.0.4" 527 | once "^1.3.0" 528 | path-is-absolute "^1.0.0" 529 | 530 | growl@1.10.5: 531 | version "1.10.5" 532 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 533 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 534 | 535 | has-flag@^3.0.0: 536 | version "3.0.0" 537 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 538 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 539 | 540 | has-flag@^4.0.0: 541 | version "4.0.0" 542 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 543 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 544 | 545 | has-symbols@^1.0.0, has-symbols@^1.0.1: 546 | version "1.0.1" 547 | resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.1.tgz#9f5214758a44196c406d9bd76cebf81ec2dd31e8" 548 | integrity sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg== 549 | 550 | has@^1.0.3: 551 | version "1.0.3" 552 | resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" 553 | integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== 554 | dependencies: 555 | function-bind "^1.1.1" 556 | 557 | he@1.2.0: 558 | version "1.2.0" 559 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 560 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 561 | 562 | http-errors@1.7.2: 563 | version "1.7.2" 564 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" 565 | integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== 566 | dependencies: 567 | depd "~1.1.2" 568 | inherits "2.0.3" 569 | setprototypeof "1.1.1" 570 | statuses ">= 1.5.0 < 2" 571 | toidentifier "1.0.0" 572 | 573 | http-errors@~1.7.2: 574 | version "1.7.3" 575 | resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" 576 | integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== 577 | dependencies: 578 | depd "~1.1.2" 579 | inherits "2.0.4" 580 | setprototypeof "1.1.1" 581 | statuses ">= 1.5.0 < 2" 582 | toidentifier "1.0.0" 583 | 584 | iconv-lite@0.4.24: 585 | version "0.4.24" 586 | resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" 587 | integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== 588 | dependencies: 589 | safer-buffer ">= 2.1.2 < 3" 590 | 591 | inflight@^1.0.4: 592 | version "1.0.6" 593 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 594 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 595 | dependencies: 596 | once "^1.3.0" 597 | wrappy "1" 598 | 599 | inherits@2, inherits@2.0.4, inherits@~2.0.3: 600 | version "2.0.4" 601 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 602 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 603 | 604 | inherits@2.0.3: 605 | version "2.0.3" 606 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 607 | integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= 608 | 609 | ipaddr.js@1.9.1: 610 | version "1.9.1" 611 | resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3" 612 | integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== 613 | 614 | is-arguments@^1.0.4: 615 | version "1.0.4" 616 | resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.0.4.tgz#3faf966c7cba0ff437fb31f6250082fcf0448cf3" 617 | integrity sha512-xPh0Rmt8NE65sNzvyUmWgI1tz3mKq74lGA0mL8LYZcoIzKOzDh6HmrYm3d18k60nHerC8A9Km8kYu87zfSFnLA== 618 | 619 | is-binary-path@~2.1.0: 620 | version "2.1.0" 621 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 622 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 623 | dependencies: 624 | binary-extensions "^2.0.0" 625 | 626 | is-buffer@~2.0.3: 627 | version "2.0.4" 628 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-2.0.4.tgz#3e572f23c8411a5cfd9557c849e3665e0b290623" 629 | integrity sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A== 630 | 631 | is-callable@^1.1.4, is-callable@^1.1.5: 632 | version "1.2.0" 633 | resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.0.tgz#83336560b54a38e35e3a2df7afd0454d691468bb" 634 | integrity sha512-pyVD9AaGLxtg6srb2Ng6ynWJqkHU9bEM087AKck0w8QwDarTfNcpIYoU8x8Hv2Icm8u6kFJM18Dag8lyqGkviw== 635 | 636 | is-date-object@^1.0.1: 637 | version "1.0.2" 638 | resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.2.tgz#bda736f2cd8fd06d32844e7743bfa7494c3bfd7e" 639 | integrity sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g== 640 | 641 | is-extglob@^2.1.1: 642 | version "2.1.1" 643 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 644 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 645 | 646 | is-fullwidth-code-point@^2.0.0: 647 | version "2.0.0" 648 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 649 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 650 | 651 | is-glob@^4.0.1, is-glob@~4.0.1: 652 | version "4.0.1" 653 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 654 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== 655 | dependencies: 656 | is-extglob "^2.1.1" 657 | 658 | is-map@^2.0.1: 659 | version "2.0.1" 660 | resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.1.tgz#520dafc4307bb8ebc33b813de5ce7c9400d644a1" 661 | integrity sha512-T/S49scO8plUiAOA2DBTBG3JHpn1yiw0kRp6dgiZ0v2/6twi5eiB0rHtHFH9ZIrvlWc6+4O+m4zg5+Z833aXgw== 662 | 663 | is-number@^7.0.0: 664 | version "7.0.0" 665 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 666 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 667 | 668 | is-regex@^1.0.5: 669 | version "1.1.0" 670 | resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.0.tgz#ece38e389e490df0dc21caea2bd596f987f767ff" 671 | integrity sha512-iI97M8KTWID2la5uYXlkbSDQIg4F6o1sYboZKKTDpnDQMLtUL86zxhgDet3Q2SriaYsyGqZ6Mn2SjbRKeLHdqw== 672 | dependencies: 673 | has-symbols "^1.0.1" 674 | 675 | is-set@^2.0.1: 676 | version "2.0.1" 677 | resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.1.tgz#d1604afdab1724986d30091575f54945da7e5f43" 678 | integrity sha512-eJEzOtVyenDs1TMzSQ3kU3K+E0GUS9sno+F0OBT97xsgcJsF9nXMBtkT9/kut5JEpM7oL7X/0qxR17K3mcwIAA== 679 | 680 | is-string@^1.0.4, is-string@^1.0.5: 681 | version "1.0.5" 682 | resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.5.tgz#40493ed198ef3ff477b8c7f92f644ec82a5cd3a6" 683 | integrity sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ== 684 | 685 | is-symbol@^1.0.2: 686 | version "1.0.3" 687 | resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.3.tgz#38e1014b9e6329be0de9d24a414fd7441ec61937" 688 | integrity sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ== 689 | dependencies: 690 | has-symbols "^1.0.1" 691 | 692 | is-typedarray@^1.0.0: 693 | version "1.0.0" 694 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 695 | integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= 696 | 697 | isarray@^2.0.5: 698 | version "2.0.5" 699 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" 700 | integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== 701 | 702 | isarray@~1.0.0: 703 | version "1.0.0" 704 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 705 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 706 | 707 | isexe@^2.0.0: 708 | version "2.0.0" 709 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 710 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 711 | 712 | iterate-iterator@^1.0.1: 713 | version "1.0.1" 714 | resolved "https://registry.yarnpkg.com/iterate-iterator/-/iterate-iterator-1.0.1.tgz#1693a768c1ddd79c969051459453f082fe82e9f6" 715 | integrity sha512-3Q6tudGN05kbkDQDI4CqjaBf4qf85w6W6GnuZDtUVYwKgtC1q8yxYX7CZed7N+tLzQqS6roujWvszf13T+n9aw== 716 | 717 | iterate-value@^1.0.0: 718 | version "1.0.2" 719 | resolved "https://registry.yarnpkg.com/iterate-value/-/iterate-value-1.0.2.tgz#935115bd37d006a52046535ebc8d07e9c9337f57" 720 | integrity sha512-A6fMAio4D2ot2r/TYzr4yUWrmwNdsN5xL7+HUiyACE4DXm+q8HtPcnFTp+NnW3k4N05tZ7FVYFFb2CR13NxyHQ== 721 | dependencies: 722 | es-get-iterator "^1.0.2" 723 | iterate-iterator "^1.0.1" 724 | 725 | js-yaml@3.13.1: 726 | version "3.13.1" 727 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" 728 | integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== 729 | dependencies: 730 | argparse "^1.0.7" 731 | esprima "^4.0.0" 732 | 733 | locate-path@^3.0.0: 734 | version "3.0.0" 735 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" 736 | integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== 737 | dependencies: 738 | p-locate "^3.0.0" 739 | path-exists "^3.0.0" 740 | 741 | locate-path@^5.0.0: 742 | version "5.0.0" 743 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" 744 | integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== 745 | dependencies: 746 | p-locate "^4.1.0" 747 | 748 | lodash@^4.17.15: 749 | version "4.17.15" 750 | resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.15.tgz#b447f6670a0455bbfeedd11392eff330ea097548" 751 | integrity sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A== 752 | 753 | log-symbols@3.0.0: 754 | version "3.0.0" 755 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-3.0.0.tgz#f3a08516a5dea893336a7dee14d18a1cfdab77c4" 756 | integrity sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ== 757 | dependencies: 758 | chalk "^2.4.2" 759 | 760 | marked-ast-markdown@^2.1.0: 761 | version "2.1.0" 762 | resolved "https://registry.yarnpkg.com/marked-ast-markdown/-/marked-ast-markdown-2.1.0.tgz#1756e237e528c59a10bc04992b7d64bc445f9478" 763 | integrity sha512-vGC/NGGlvyu4I1Uox41a/ScpPbyYL74UWd7GsWjB9pmpmK1iMKqt0d5KdW+wShplefoDZvhm9kRwPlEYE85YGA== 764 | dependencies: 765 | entities "^2.0.2" 766 | whisk "^1.0.0" 767 | 768 | marked-ast@^0.3.0: 769 | version "0.3.0" 770 | resolved "https://registry.yarnpkg.com/marked-ast/-/marked-ast-0.3.0.tgz#dc119d9109fd0be98e915d1e643b9ea24606daec" 771 | integrity sha1-3BGdkQn9C+mOkV0eZDueokYG2uw= 772 | 773 | media-typer@0.3.0: 774 | version "0.3.0" 775 | resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" 776 | integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= 777 | 778 | merge-descriptors@1.0.1: 779 | version "1.0.1" 780 | resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" 781 | integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= 782 | 783 | methods@^1.1.1, methods@^1.1.2, methods@~1.1.2: 784 | version "1.1.2" 785 | resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" 786 | integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= 787 | 788 | mime-db@1.44.0: 789 | version "1.44.0" 790 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" 791 | integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== 792 | 793 | mime-types@^2.1.12, mime-types@~2.1.24: 794 | version "2.1.27" 795 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" 796 | integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== 797 | dependencies: 798 | mime-db "1.44.0" 799 | 800 | mime@1.6.0, mime@^1.4.1: 801 | version "1.6.0" 802 | resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" 803 | integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== 804 | 805 | minimatch@3.0.4, minimatch@^3.0.4: 806 | version "3.0.4" 807 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 808 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 809 | dependencies: 810 | brace-expansion "^1.1.7" 811 | 812 | mkdirp@^1.0.4: 813 | version "1.0.4" 814 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" 815 | integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== 816 | 817 | mocha@^8.0.1: 818 | version "8.0.1" 819 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.0.1.tgz#fe01f0530362df271aa8f99510447bc38b88d8ed" 820 | integrity sha512-vefaXfdYI8+Yo8nPZQQi0QO2o+5q9UIMX1jZ1XMmK3+4+CQjc7+B0hPdUeglXiTlr8IHMVRo63IhO9Mzt6fxOg== 821 | dependencies: 822 | ansi-colors "4.1.1" 823 | browser-stdout "1.3.1" 824 | chokidar "3.3.1" 825 | debug "3.2.6" 826 | diff "4.0.2" 827 | escape-string-regexp "1.0.5" 828 | find-up "4.1.0" 829 | glob "7.1.6" 830 | growl "1.10.5" 831 | he "1.2.0" 832 | js-yaml "3.13.1" 833 | log-symbols "3.0.0" 834 | minimatch "3.0.4" 835 | ms "2.1.2" 836 | object.assign "4.1.0" 837 | promise.allsettled "1.0.2" 838 | serialize-javascript "3.0.0" 839 | strip-json-comments "3.0.1" 840 | supports-color "7.1.0" 841 | which "2.0.2" 842 | wide-align "1.1.3" 843 | workerpool "6.0.0" 844 | yargs "13.3.2" 845 | yargs-parser "13.1.2" 846 | yargs-unparser "1.6.0" 847 | 848 | ms@2.0.0: 849 | version "2.0.0" 850 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 851 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 852 | 853 | ms@2.1.1: 854 | version "2.1.1" 855 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" 856 | integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== 857 | 858 | ms@2.1.2, ms@^2.1.1: 859 | version "2.1.2" 860 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 861 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 862 | 863 | negotiator@0.6.2: 864 | version "0.6.2" 865 | resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" 866 | integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== 867 | 868 | node-fetch@^2.0.0-alpha.8: 869 | version "2.6.0" 870 | resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.0.tgz#e633456386d4aa55863f676a7ab0daa8fdecb0fd" 871 | integrity sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA== 872 | 873 | normalize-path@^3.0.0, normalize-path@~3.0.0: 874 | version "3.0.0" 875 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 876 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 877 | 878 | object-assign@^4.0.1: 879 | version "4.1.1" 880 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 881 | integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= 882 | 883 | object-inspect@^1.7.0: 884 | version "1.7.0" 885 | resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.7.0.tgz#f4f6bd181ad77f006b5ece60bd0b6f398ff74a67" 886 | integrity sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw== 887 | 888 | object-keys@^1.0.11, object-keys@^1.0.12, object-keys@^1.1.1: 889 | version "1.1.1" 890 | resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" 891 | integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== 892 | 893 | object.assign@4.1.0, object.assign@^4.1.0: 894 | version "4.1.0" 895 | resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da" 896 | integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w== 897 | dependencies: 898 | define-properties "^1.1.2" 899 | function-bind "^1.1.1" 900 | has-symbols "^1.0.0" 901 | object-keys "^1.0.11" 902 | 903 | on-finished@~2.3.0: 904 | version "2.3.0" 905 | resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" 906 | integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= 907 | dependencies: 908 | ee-first "1.1.1" 909 | 910 | once@^1.3.0: 911 | version "1.4.0" 912 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 913 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 914 | dependencies: 915 | wrappy "1" 916 | 917 | out@^1.1.0: 918 | version "1.1.0" 919 | resolved "https://registry.yarnpkg.com/out/-/out-1.1.0.tgz#d607bd5315e3a1733ecddc29b475ddf0c98c672b" 920 | integrity sha512-TfynqaVK+Z42/Cn5zwmdQsCLSs+WGmH+QhPHXhpuYhyiRGlUw/8FKd1LKPAL6B4f1sjIl+zLDegOjDpv6FOfRQ== 921 | 922 | p-limit@^2.0.0, p-limit@^2.2.0: 923 | version "2.3.0" 924 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 925 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 926 | dependencies: 927 | p-try "^2.0.0" 928 | 929 | p-locate@^3.0.0: 930 | version "3.0.0" 931 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" 932 | integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== 933 | dependencies: 934 | p-limit "^2.0.0" 935 | 936 | p-locate@^4.1.0: 937 | version "4.1.0" 938 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" 939 | integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== 940 | dependencies: 941 | p-limit "^2.2.0" 942 | 943 | p-try@^2.0.0: 944 | version "2.2.0" 945 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 946 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 947 | 948 | parseurl@~1.3.3: 949 | version "1.3.3" 950 | resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" 951 | integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== 952 | 953 | path-exists@^3.0.0: 954 | version "3.0.0" 955 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 956 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 957 | 958 | path-exists@^4.0.0: 959 | version "4.0.0" 960 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 961 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 962 | 963 | path-is-absolute@^1.0.0: 964 | version "1.0.1" 965 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 966 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 967 | 968 | path-to-regexp@0.1.7: 969 | version "0.1.7" 970 | resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" 971 | integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= 972 | 973 | picomatch@^2.0.4, picomatch@^2.0.7: 974 | version "2.2.2" 975 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" 976 | integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== 977 | 978 | process-nextick-args@~2.0.0: 979 | version "2.0.1" 980 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" 981 | integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== 982 | 983 | procinfo@~0.1: 984 | version "0.1.4" 985 | resolved "https://registry.yarnpkg.com/procinfo/-/procinfo-0.1.4.tgz#532019126114aee41b80997ef888a108319df50f" 986 | integrity sha1-UyAZEmEUruQbgJl++IihCDGd9Q8= 987 | 988 | promise.allsettled@1.0.2: 989 | version "1.0.2" 990 | resolved "https://registry.yarnpkg.com/promise.allsettled/-/promise.allsettled-1.0.2.tgz#d66f78fbb600e83e863d893e98b3d4376a9c47c9" 991 | integrity sha512-UpcYW5S1RaNKT6pd+s9jp9K9rlQge1UXKskec0j6Mmuq7UJCvlS2J2/s/yuPN8ehftf9HXMxWlKiPbGGUzpoRg== 992 | dependencies: 993 | array.prototype.map "^1.0.1" 994 | define-properties "^1.1.3" 995 | es-abstract "^1.17.0-next.1" 996 | function-bind "^1.1.1" 997 | iterate-value "^1.0.0" 998 | 999 | proxy-addr@~2.0.5: 1000 | version "2.0.6" 1001 | resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf" 1002 | integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw== 1003 | dependencies: 1004 | forwarded "~0.1.2" 1005 | ipaddr.js "1.9.1" 1006 | 1007 | qs@6.7.0: 1008 | version "6.7.0" 1009 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" 1010 | integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== 1011 | 1012 | qs@^6.5.1: 1013 | version "6.9.4" 1014 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.4.tgz#9090b290d1f91728d3c22e54843ca44aea5ab687" 1015 | integrity sha512-A1kFqHekCTM7cz0udomYUoYNWjBebHm/5wzU/XqrBRBNWectVH0QIiN+NEcZ0Dte5hvzHwbr8+XQmguPhJ6WdQ== 1016 | 1017 | r2@^2.0.1: 1018 | version "2.0.1" 1019 | resolved "https://registry.yarnpkg.com/r2/-/r2-2.0.1.tgz#94cd802ecfce9a622549c8182032d8e4a2b2e612" 1020 | integrity sha512-EEmxoxYCe3LHzAUhRIRxdCKERpeRNmlLj6KLUSORqnK6dWl/K5ShmDGZqM2lRZQeqJgF+wyqk0s1M7SWUveNOQ== 1021 | dependencies: 1022 | caseless "^0.12.0" 1023 | node-fetch "^2.0.0-alpha.8" 1024 | typedarray-to-buffer "^3.1.2" 1025 | 1026 | range-parser@~1.2.1: 1027 | version "1.2.1" 1028 | resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" 1029 | integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== 1030 | 1031 | raw-body@2.4.0: 1032 | version "2.4.0" 1033 | resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" 1034 | integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== 1035 | dependencies: 1036 | bytes "3.1.0" 1037 | http-errors "1.7.2" 1038 | iconv-lite "0.4.24" 1039 | unpipe "1.0.0" 1040 | 1041 | readable-stream@^2.0.2, readable-stream@^2.3.5: 1042 | version "2.3.7" 1043 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" 1044 | integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== 1045 | dependencies: 1046 | core-util-is "~1.0.0" 1047 | inherits "~2.0.3" 1048 | isarray "~1.0.0" 1049 | process-nextick-args "~2.0.0" 1050 | safe-buffer "~5.1.1" 1051 | string_decoder "~1.1.1" 1052 | util-deprecate "~1.0.1" 1053 | 1054 | readdirp@~3.3.0: 1055 | version "3.3.0" 1056 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17" 1057 | integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ== 1058 | dependencies: 1059 | picomatch "^2.0.7" 1060 | 1061 | replacestream@^4.0.2: 1062 | version "4.0.3" 1063 | resolved "https://registry.yarnpkg.com/replacestream/-/replacestream-4.0.3.tgz#3ee5798092be364b1cdb1484308492cb3dff2f36" 1064 | integrity sha512-AC0FiLS352pBBiZhd4VXB1Ab/lh0lEgpP+GGvZqbQh8a5cmXVoTe5EX/YeTFArnp4SRGTHh1qCHu9lGs1qG8sA== 1065 | dependencies: 1066 | escape-string-regexp "^1.0.3" 1067 | object-assign "^4.0.1" 1068 | readable-stream "^2.0.2" 1069 | 1070 | require-directory@^2.1.1: 1071 | version "2.1.1" 1072 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 1073 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 1074 | 1075 | require-main-filename@^2.0.0: 1076 | version "2.0.0" 1077 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" 1078 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== 1079 | 1080 | rimraf@^3.0.2: 1081 | version "3.0.2" 1082 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 1083 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 1084 | dependencies: 1085 | glob "^7.1.3" 1086 | 1087 | safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: 1088 | version "5.1.2" 1089 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1090 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1091 | 1092 | "safer-buffer@>= 2.1.2 < 3": 1093 | version "2.1.2" 1094 | resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" 1095 | integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== 1096 | 1097 | send@0.17.1: 1098 | version "0.17.1" 1099 | resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" 1100 | integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== 1101 | dependencies: 1102 | debug "2.6.9" 1103 | depd "~1.1.2" 1104 | destroy "~1.0.4" 1105 | encodeurl "~1.0.2" 1106 | escape-html "~1.0.3" 1107 | etag "~1.8.1" 1108 | fresh "0.5.2" 1109 | http-errors "~1.7.2" 1110 | mime "1.6.0" 1111 | ms "2.1.1" 1112 | on-finished "~2.3.0" 1113 | range-parser "~1.2.1" 1114 | statuses "~1.5.0" 1115 | 1116 | serialize-javascript@3.0.0: 1117 | version "3.0.0" 1118 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.0.0.tgz#492e489a2d77b7b804ad391a5f5d97870952548e" 1119 | integrity sha512-skZcHYw2vEX4bw90nAr2iTTsz6x2SrHEnfxgKYmZlvJYBEZrvbKtobJWlQ20zczKb3bsHHXXTYt48zBA7ni9cw== 1120 | 1121 | serve-static@1.14.1: 1122 | version "1.14.1" 1123 | resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" 1124 | integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== 1125 | dependencies: 1126 | encodeurl "~1.0.2" 1127 | escape-html "~1.0.3" 1128 | parseurl "~1.3.3" 1129 | send "0.17.1" 1130 | 1131 | set-blocking@^2.0.0: 1132 | version "2.0.0" 1133 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1134 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 1135 | 1136 | setprototypeof@1.1.1: 1137 | version "1.1.1" 1138 | resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" 1139 | integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== 1140 | 1141 | sprintf-js@~1.0.2: 1142 | version "1.0.3" 1143 | resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" 1144 | integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= 1145 | 1146 | "statuses@>= 1.5.0 < 2", statuses@~1.5.0: 1147 | version "1.5.0" 1148 | resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" 1149 | integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= 1150 | 1151 | "string-width@^1.0.2 || 2": 1152 | version "2.1.1" 1153 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 1154 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 1155 | dependencies: 1156 | is-fullwidth-code-point "^2.0.0" 1157 | strip-ansi "^4.0.0" 1158 | 1159 | string-width@^3.0.0, string-width@^3.1.0: 1160 | version "3.1.0" 1161 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" 1162 | integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== 1163 | dependencies: 1164 | emoji-regex "^7.0.1" 1165 | is-fullwidth-code-point "^2.0.0" 1166 | strip-ansi "^5.1.0" 1167 | 1168 | string.prototype.trimend@^1.0.0: 1169 | version "1.0.1" 1170 | resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.1.tgz#85812a6b847ac002270f5808146064c995fb6913" 1171 | integrity sha512-LRPxFUaTtpqYsTeNKaFOw3R4bxIzWOnbQ837QfBylo8jIxtcbK/A/sMV7Q+OAV/vWo+7s25pOE10KYSjaSO06g== 1172 | dependencies: 1173 | define-properties "^1.1.3" 1174 | es-abstract "^1.17.5" 1175 | 1176 | string.prototype.trimleft@^2.1.1: 1177 | version "2.1.2" 1178 | resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.2.tgz#4408aa2e5d6ddd0c9a80739b087fbc067c03b3cc" 1179 | integrity sha512-gCA0tza1JBvqr3bfAIFJGqfdRTyPae82+KTnm3coDXkZN9wnuW3HjGgN386D7hfv5CHQYCI022/rJPVlqXyHSw== 1180 | dependencies: 1181 | define-properties "^1.1.3" 1182 | es-abstract "^1.17.5" 1183 | string.prototype.trimstart "^1.0.0" 1184 | 1185 | string.prototype.trimright@^2.1.1: 1186 | version "2.1.2" 1187 | resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.2.tgz#c76f1cef30f21bbad8afeb8db1511496cfb0f2a3" 1188 | integrity sha512-ZNRQ7sY3KroTaYjRS6EbNiiHrOkjihL9aQE/8gfQ4DtAC/aEBRHFJa44OmoWxGGqXuJlfKkZW4WcXErGr+9ZFg== 1189 | dependencies: 1190 | define-properties "^1.1.3" 1191 | es-abstract "^1.17.5" 1192 | string.prototype.trimend "^1.0.0" 1193 | 1194 | string.prototype.trimstart@^1.0.0: 1195 | version "1.0.1" 1196 | resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.1.tgz#14af6d9f34b053f7cfc89b72f8f2ee14b9039a54" 1197 | integrity sha512-XxZn+QpvrBI1FOcg6dIpxUPgWCPuNXvMD72aaRaUQv1eD4e/Qy8i/hFTe0BUmD60p/QA6bh1avmuPTfNjqVWRw== 1198 | dependencies: 1199 | define-properties "^1.1.3" 1200 | es-abstract "^1.17.5" 1201 | 1202 | string_decoder@~1.1.1: 1203 | version "1.1.1" 1204 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" 1205 | integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== 1206 | dependencies: 1207 | safe-buffer "~5.1.0" 1208 | 1209 | strip-ansi@^4.0.0: 1210 | version "4.0.0" 1211 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 1212 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 1213 | dependencies: 1214 | ansi-regex "^3.0.0" 1215 | 1216 | strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: 1217 | version "5.2.0" 1218 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" 1219 | integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== 1220 | dependencies: 1221 | ansi-regex "^4.1.0" 1222 | 1223 | strip-json-comments@3.0.1: 1224 | version "3.0.1" 1225 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.0.1.tgz#85713975a91fb87bf1b305cca77395e40d2a64a7" 1226 | integrity sha512-VTyMAUfdm047mwKl+u79WIdrZxtFtn+nBxHeb844XBQ9uMNTuTHdx2hc5RiAJYqwTj3wc/xe5HLSdJSkJ+WfZw== 1227 | 1228 | superagent@^3.8.3: 1229 | version "3.8.3" 1230 | resolved "https://registry.yarnpkg.com/superagent/-/superagent-3.8.3.tgz#460ea0dbdb7d5b11bc4f78deba565f86a178e128" 1231 | integrity sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA== 1232 | dependencies: 1233 | component-emitter "^1.2.0" 1234 | cookiejar "^2.1.0" 1235 | debug "^3.1.0" 1236 | extend "^3.0.0" 1237 | form-data "^2.3.1" 1238 | formidable "^1.2.0" 1239 | methods "^1.1.1" 1240 | mime "^1.4.1" 1241 | qs "^6.5.1" 1242 | readable-stream "^2.3.5" 1243 | 1244 | supertest@^4.0.2: 1245 | version "4.0.2" 1246 | resolved "https://registry.yarnpkg.com/supertest/-/supertest-4.0.2.tgz#c2234dbdd6dc79b6f15b99c8d6577b90e4ce3f36" 1247 | integrity sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ== 1248 | dependencies: 1249 | methods "^1.1.2" 1250 | superagent "^3.8.3" 1251 | 1252 | supports-color@7.1.0: 1253 | version "7.1.0" 1254 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" 1255 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== 1256 | dependencies: 1257 | has-flag "^4.0.0" 1258 | 1259 | supports-color@^5.3.0: 1260 | version "5.5.0" 1261 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1262 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1263 | dependencies: 1264 | has-flag "^3.0.0" 1265 | 1266 | to-regex-range@^5.0.1: 1267 | version "5.0.1" 1268 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 1269 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 1270 | dependencies: 1271 | is-number "^7.0.0" 1272 | 1273 | toidentifier@1.0.0: 1274 | version "1.0.0" 1275 | resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" 1276 | integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== 1277 | 1278 | type-is@~1.6.17, type-is@~1.6.18: 1279 | version "1.6.18" 1280 | resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" 1281 | integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== 1282 | dependencies: 1283 | media-typer "0.3.0" 1284 | mime-types "~2.1.24" 1285 | 1286 | typedarray-to-buffer@^3.1.2: 1287 | version "3.1.5" 1288 | resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" 1289 | integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== 1290 | dependencies: 1291 | is-typedarray "^1.0.0" 1292 | 1293 | unpipe@1.0.0, unpipe@~1.0.0: 1294 | version "1.0.0" 1295 | resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" 1296 | integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= 1297 | 1298 | util-deprecate@~1.0.1: 1299 | version "1.0.2" 1300 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 1301 | integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= 1302 | 1303 | utils-merge@1.0.1: 1304 | version "1.0.1" 1305 | resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" 1306 | integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= 1307 | 1308 | vary@~1.1.2: 1309 | version "1.1.2" 1310 | resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" 1311 | integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= 1312 | 1313 | which-module@^2.0.0: 1314 | version "2.0.0" 1315 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 1316 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= 1317 | 1318 | which@2.0.2: 1319 | version "2.0.2" 1320 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1321 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 1322 | dependencies: 1323 | isexe "^2.0.0" 1324 | 1325 | whisk@^1.0.0: 1326 | version "1.4.0" 1327 | resolved "https://registry.yarnpkg.com/whisk/-/whisk-1.4.0.tgz#c3fe50b0f585ba73d5915da477c6735c135e8811" 1328 | integrity sha512-uh4+hibHa+HxUTUwpP9iiAgyniVB4UBbI6QK2feiv1U9t6PSS32hl/xeAmf0RZhHKXVn3nnNQiju1RzBYVclCg== 1329 | 1330 | wide-align@1.1.3: 1331 | version "1.1.3" 1332 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 1333 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 1334 | dependencies: 1335 | string-width "^1.0.2 || 2" 1336 | 1337 | workerpool@6.0.0: 1338 | version "6.0.0" 1339 | resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.0.0.tgz#85aad67fa1a2c8ef9386a1b43539900f61d03d58" 1340 | integrity sha512-fU2OcNA/GVAJLLyKUoHkAgIhKb0JoCpSjLC/G2vYKxUjVmQwGbRVeoPJ1a8U4pnVofz4AQV5Y/NEw8oKqxEBtA== 1341 | 1342 | wrap-ansi@^5.1.0: 1343 | version "5.1.0" 1344 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" 1345 | integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== 1346 | dependencies: 1347 | ansi-styles "^3.2.0" 1348 | string-width "^3.0.0" 1349 | strip-ansi "^5.0.0" 1350 | 1351 | wrappy@1: 1352 | version "1.0.2" 1353 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1354 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1355 | 1356 | y18n@^4.0.0: 1357 | version "4.0.0" 1358 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" 1359 | integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== 1360 | 1361 | yargs-parser@13.1.2, yargs-parser@^13.1.2: 1362 | version "13.1.2" 1363 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.2.tgz#130f09702ebaeef2650d54ce6e3e5706f7a4fb38" 1364 | integrity sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg== 1365 | dependencies: 1366 | camelcase "^5.0.0" 1367 | decamelize "^1.2.0" 1368 | 1369 | yargs-unparser@1.6.0: 1370 | version "1.6.0" 1371 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-1.6.0.tgz#ef25c2c769ff6bd09e4b0f9d7c605fb27846ea9f" 1372 | integrity sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw== 1373 | dependencies: 1374 | flat "^4.1.0" 1375 | lodash "^4.17.15" 1376 | yargs "^13.3.0" 1377 | 1378 | yargs@13.3.2, yargs@^13.3.0: 1379 | version "13.3.2" 1380 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.3.2.tgz#ad7ffefec1aa59565ac915f82dccb38a9c31a2dd" 1381 | integrity sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw== 1382 | dependencies: 1383 | cliui "^5.0.0" 1384 | find-up "^3.0.0" 1385 | get-caller-file "^2.0.1" 1386 | require-directory "^2.1.1" 1387 | require-main-filename "^2.0.0" 1388 | set-blocking "^2.0.0" 1389 | string-width "^3.0.0" 1390 | which-module "^2.0.0" 1391 | y18n "^4.0.0" 1392 | yargs-parser "^13.1.2" 1393 | --------------------------------------------------------------------------------