IoTcat 3 years ago
parent 66236e58a9
commit 8ae2dc83c9
  1. 13
      package.json
  2. 1
      src/.gitignore
  3. 59
      src/index.js
  4. 140
      src/modules/api.js
  5. 29
      src/modules/log.js
  6. 281
      src/modules/node.js
  7. 269
      src/modules/nodetable.js
  8. 74
      src/modules/ns.js
  9. 446
      yarn.lock

@ -0,0 +1,13 @@
{
"name": "wiot-director",
"version": "0.0.1",
"description": "Director for wIoT systems.",
"main": "index.js",
"repository": "https://wiot.js.org",
"author": "iotcat",
"license": "MIT",
"dependencies": {
"express": "^4.17.1",
"log4js": "^6.3.0"
}
}

1
src/.gitignore vendored

@ -0,0 +1 @@
data/

@ -0,0 +1,59 @@
const logger = require(__dirname + '/modules/log.js')();
const nodetable = require(__dirname + '/modules/nodetable.js')(logger);
const node = require(__dirname + '/modules/node.js')(logger, nodetable);
const ns = require(__dirname + '/modules/ns.js')(logger, node);
const api = require(__dirname + '/modules/api.js')(logger, node, ns);
let OnlineBoard = [];
setInterval(async ()=>{
//console.log(await node.good.restart());
//console.log('ddd')
//console.log(await node.good.refresh());
//console.log(await node.good.setNS('ccc', '192.168.3.253', 6789));
//console.log(await node.good.checkNS('ccc', '111.111.11.11', 6789));
//console.log(await node.good.setFunc('333Func', 'tmr.create():alarm(3000, tmr.ALARM_AUTO, function() print("hello") end)'));
/*l = await ns.get(['good', 'good3'], {
'good': {
'good3': {
port: 22,
ip: '111.222.333.44'
}
}
})*/
let online = [];
Object.keys(node).forEach(nid => {
if(node[nid].status){
online.push(nid);
}
});
if(online.some(nid => OnlineBoard.indexOf(nid) == -1)){
OnlineBoard = online;
await ns.set(await ns.get(online/*, {
'good': {
'good3': {
port: 22,
ip: '111.222.333.44'
}
},
'good3': {
'good': {
port: 22,
ip: '111.222.333.44'
}
},
}*/))
}
},15000)

@ -0,0 +1,140 @@
module.exports = (logger, node, ns) => {
const log = logger.getLogger('weblog');
const express = require('express');
const app = express()
const port = 3001;
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
log.info('API web server begin at ', port);
})
function isJson(str) {
try {
if (typeof JSON.parse(str) == "object") {
return true;
}
} catch(e) {
}
return false;
}
app.get('/status', (req, res) => {
if(!req.query.hasOwnProperty('query')){
res.status(500).send();
return;
}
if(!isJson(req.query.query)){
res.status(500).send();
return;
}
let query = JSON.parse(req.query.query);
let resData = {};
query.forEach(nid => {
if(node.hasOwnProperty(nid)){
resData[nid] = {};
resData[nid].status = node[nid].status;
resData[nid].funcID = node[nid].info.funcID;
resData[nid].port = node[nid].info.localport;
resData[nid].ip = node[nid].info.localip;
resData[nid].ns = node[nid].ns;
resData[nid].heap = node[nid].info.heap;
resData[nid].spiff = node[nid].info.spiff;
resData[nid].HeartbeatInterval = node[nid].info.HeartbeatInterval;
resData[nid].LastUpTime = node[nid].info.LastUpTime;
resData[nid].LastActiveTime = node[nid].info.LastActiveTime;
resData[nid].LastRefreshTime = node[nid].LastRefreshTime;
resData[nid].LastRestartTime = node[nid].LastRestartTime;
}
});
res.send(resData);
log.info('[status]', JSON.stringify(req.query.query));
})
app.get('/setFunc', async (req, res) => {
if(!req.query.hasOwnProperty('nid') || !req.query.hasOwnProperty('funcID') || !req.query.hasOwnProperty('func')){
res.status(500).send();
return;
}
let nid = req.query.nid,
funcID = req.query.funcID,
func = new Buffer(req.query.func, 'base64').toString()
if(!node.hasOwnProperty(nid)){
res.status(404).send();
return;
}
if(!node[nid].status){
res.status(503).send();
return;
}
let status = await node[nid].setFunc(funcID, func);
res.send({status: status});
log.info('[setFunc]', '<'+nid+'>', funcID, status);
})
app.get('/restart', async (req, res) => {
if(!req.query.hasOwnProperty('nid')){
res.status(500).send();
return;
}
let nid = req.query.nid;
if(!node.hasOwnProperty(nid)){
res.status(404).send();
return;
}
if(!node[nid].status){
res.status(503).send();
return;
}
let status = await node[nid].restart();
res.send({status: status});
log.info('[restart]', '<'+nid+'>', status);
})
app.get('/log', (req, res) => {
if(!req.query.hasOwnProperty('type') || !req.query.hasOwnProperty('start')){
res.status(500).send();
return;
}
res.send();
log.info('[log]', req.query.type);
})
return null;
}

@ -0,0 +1,29 @@
module.exports = (node, nodetable) => {
const LOG_PATH = __dirname + '/../data/log/';
const log4js = require('log4js');
log4js.configure({
appenders: {
flow: {type: 'file', filename: LOG_PATH + 'flow.log'},
access: {type: 'file', filename: LOG_PATH + 'access.log'},
event: {type: 'file', filename: LOG_PATH + 'event.log'},
nslog: {type: 'file', filename: LOG_PATH + 'ns.log'},
weblog: {type: 'file', filename: LOG_PATH + 'web.log'},
console: { type: 'console' }
},
categories: {
flow: {appenders: [/*'flow',*/ 'console'], level: 'info' },
//access: { appenders: ['access'], level: 'info' },
event: {appenders: [/*'event', */'console'], level: 'info' },
nslog: {appenders: [/*'nslog',*/ 'console'], level: 'info' },
weblog: {appenders: [/*'weblog',*/ 'console'], level: 'info' },
default: { appenders: ['console'], level: 'info' }
}
});
return log4js;
}

@ -0,0 +1,281 @@
module.exports = (logger, nodetable) => {
let nodes = {}
const CMD_DELAY = 200;
let delay = (time_ms) => new Promise(resolve => {
setTimeout(()=>{
resolve();
}, time_ms);
});
const event = logger.getLogger('event');
nodetable.newNode((nid, info) => {
nodes[nid] = {
send: (name, body, isudp) => {
return nodetable.outgo(nid, {
to: nid,
from: "director",
name: name,
body: body
}, isudp);
},
triggers: {
income: [
function(name, body){
if(name == '__getInfo'){
nodes[nid].info.localport = body.port;
nodes[nid].info.localip = body.ip;
nodes[nid].info.funcID = body.funcID;
nodes[nid].info.HeartbeatInterval = body.HeartbeatInterval;
nodes[nid].ns = body.ns;
nodes[nid].LastRefreshTime = new Date().valueOf();
}
},
function(name, body){
if(name == '__checkNS'){
if(!nodes[nid].rns.hasOwnProperty(body.from) || nodes[nid].rns[body.from].ip != body.ip || nodes[nid].rns[body.from].port != body.port){
nodes[nid].rns[body.from] = body;
nodes[nid].rns[body.from].updated = true;
}
nodes[nid].rns[body.from].LastCheckTime = new Date().valueOf();
}
}
],
connect: [],
disconnect: [],
restart: [],
error: []
},
LastRefreshTime: 0,
LastRestartTime: 0,
ns: {},
rns: {},
on: (type, cb) => {
nodes[nid].triggers[type].push(cb);
},
restart: () => new Promise((resolve) => {
let restartTime = new Date().valueOf();
let counter = 100;
nodes[nid].send('__restart', '');
let timer = () => {
setTimeout(()=>{
if(nodes[nid].info.LastUpTime < restartTime){
if(counter){
if(nodes[nid].info.LastActiveTime > restartTime + 500){
nodes[nid].send('__restart', '');
restartTime = new Date().valueOf();
counter = 100;
}
timer();
counter --;
}else{
resolve(false);
return;
}
}else{
event.info('[CMD]', '<'+nid+'>', '__restart');
resolve(true);
return;
}
}, 300);
};
timer();
}),
refresh: () => new Promise((resolve) => {
let startTime = new Date().valueOf();
let counter = 100;
nodes[nid].send('__getInfo', '');
let timer = () => {
setTimeout(async ()=>{
if(nodes[nid].LastRefreshTime < startTime){
if(counter){
if(counter == 70 || counter == 40){
nodes[nid].send('__getInfo', '');
}
timer();
counter--;
}else{
resolve(false);
return;
}
}else{
await delay(CMD_DELAY)
event.info('[CMD]', '<'+nid+'>', '__refresh');
resolve(true);
return;
}
}, 300);
};
timer();
}),
setNS: (nsArr) => new Promise(async (resolve) => {
let checkLocalNS = () => Object.keys(nodes[nid].ns).every(id => {
if(nsArr.hasOwnProperty(id) && nodes[nid].ns[id].ip == nsArr[id].ip && nodes[nid].ns[id].port == nsArr[id].port){
return true;
}else{
return false;
}
}) && Object.keys(nsArr).every(id => {
if(nodes[nid].ns.hasOwnProperty(id) && nodes[nid].ns[id].ip == nsArr[id].ip && nodes[nid].ns[id].port == nsArr[id].port){
return true;
}else{
return false;
}
});
if(checkLocalNS()){
resolve(true);
return;
}
let body = {};
Object.keys(nsArr).forEach(id => {
body[id] = {
ip: nsArr[id].ip,
port: nsArr[id].port
}
});
nodes[nid].send('__setNS', body);
await delay(CMD_DELAY);
if(checkLocalNS()){
event.info('[CMD]', '<'+nid+'>', '__setNS', JSON.stringify(Object.keys(body)));
resolve(true);
}else{
resolve(false);
}
}),
checkNS: (id, ip, port) => new Promise(async (resolve) => {
nodes[nid].send('__checkNS', {
to: id,
from: nid,
ip: ip,
port: port
}, true);
await delay(CMD_DELAY);
nodes[nid].send('__checkNS', {
to: id,
from: nid,
ip: ip,
port: port
},true);
await delay(CMD_DELAY);
event.info('[CMD]', '<'+nid+'>', '__checkNS', id);
resolve();
}),
setFunc: (id, func) => new Promise(async resolve => {
let restartTime = new Date().valueOf();
let counter = 100;
if(nodes[nid].info.funcID == id) {
resolve(true);
return;
}
nodes[nid].send('__setFunc', {
func: {
id: id,
online: func
}
});
let timer = () => {
setTimeout(()=>{
if(nodes[nid].info.LastUpTime < restartTime || nodes[nid].info.funcID != id){
if(counter){
if(nodes[nid].info.LastActiveTime > restartTime + 500){
nodes[nid].send('__setFunc', {
func: {
id: id,
online: func
}
});
restartTime = new Date().valueOf();
//counter = 100;
}
timer();
counter --;
}else{
resolve(false);
return;
}
}else{
event.info('[CMD]', '<'+nid+'>', '__setFunc', id, func);
resolve(true);
return;
}
}, 300);
};
timer();
})
};
nodes[nid].info = info;
});
nodetable.connect((nid, info) => {
nodes[nid].status = true;
if(new Date().valueOf() < nodes[nid].info.LastUpTime + nodes[nid].info.HeartbeatInterval){
nodes[nid].triggers.restart.forEach(cb => {
cb();
});
nodes[nid].LastRestartTime = new Date().valueOf();
event.info('[RESTART]', '<'+nid+'>', '{'+info.funcID+'}');
}
nodes[nid].triggers.connect.forEach(cb => {
cb();
});
event.info('[CONNECT]', '<'+nid+'>', '{'+info.funcID+'}');
});
nodetable.disconnect((nid, info) => {
nodes[nid].status = false;
nodes[nid].triggers.disconnect.forEach(cb => {
cb();
});
event.info('[DISCONNECT]', '<'+nid+'>', '{'+info.funcID+'}');
});
nodetable.income((nid, info, data) => {
nodes[nid].status = true;
nodes[nid].triggers.income.forEach(cb => {
cb(data.name, data.body);
});
});
nodetable.error((nid, info) => {
nodes[nid].triggers.error.forEach(cb => {
cb(info.error);
});
event.error('[ERROR]', '<'+nid+'>', '{'+info.funcID+'}', info.error);
});
return nodes;
}

@ -0,0 +1,269 @@
module.exports = (logger, host = '0.0.0.0', port = 6789) => {
let cbArr = {
income: [],
outgo: [],
forward: [],
newNode: [],
connect: [],
disconnect: [],
error: []
};
let o = {
income: cb => { //cb(nid, info{funcID, error}, data)
cbArr.income.push(cb);
},
forward: cb => { //cb(nid, info{funcID, error}, data)
cbArr.forward.push(cb);
},
outgo: (nid, data, isudp) => {
if(!nidtable.hasOwnProperty(nid) || !nidtable[nid].socket || (!nidtable[nid].status && !isudp)){
flow.error('[OUTGOING]', '<nid lookup failure>', data.to+'<--'+data.from, data.name, data.body);
return false;
}
try{
let raw = JSON.stringify(data);
if(raw.length>1300){
let rawArr = [];
let flag = require('md5')(Math.random()).substring(0,1);
let n = 1300;
for (let i = 0; i < raw.length/n; i++) {
let prefix = '&';
if(i == 0){
prefix = '^';
}
if(i >= raw.length/n - 1){
prefix = '$';
}
setTimeout(()=>{
console.log(prefix + flag + raw.slice(n*i, n*(i+1)))
nidtable[nid].socket.write(prefix + flag + raw.slice(n*i, n*(i+1)));
}, i*2);
}
}else{
nidtable[nid].socket.write(raw);
}
if(!isudp) nidtable[nid].status = false;
}catch(e){
flow.error('[OUTGOING]', '<nid lookup failure>', data.to+'<--'+data.from, data.name, data.body);
}
cbArr.outgo.forEach(cb => {
cb(nid, nidtable[nid], data);
});
flow.log('[OUTGOING]', data.from + '-->' + data.to, data.name, data.body);
return true;
},
newNode: cb => {
cbArr.newNode.push(cb);
},
connect: cb => {
cbArr.connect.push(cb);
},
disconnect: cb => {
cbArr.disconnect.push(cb);
},
error: cb => {
cbArr.error.push(cb);
}
}
let nidtable = {}
function isJson(str) {
try {
if (typeof JSON.parse(str) == "object") {
return true;
}
} catch(e) {
}
return false;
}
const net = require('net');
const flow = logger.getLogger('flow');
const access = logger.getLogger('access');
const server = net.createServer((socket) => {
access.trace('Unspecified', socket.remoteAddress+':'+socket.remotePort, 'New TCP request.');
socket.setKeepAlive(true);
let nid = null;
socket.on('data', (data) => {
data = data.toString();
if(!isJson(data)){
access.error(nid, socket.remoteAddress+':'+socket.remotePort, 'Data is not JSON! Data::'+data);
return;
}
data = JSON.parse(data);
if(data.hasOwnProperty('nid') && data.hasOwnProperty('funcID') && data.hasOwnProperty('port') && data.hasOwnProperty('ip') && data.hasOwnProperty('HeartbeatInterval') && data.hasOwnProperty('uptime')){
nid = data.nid;
let isNew = false;
if(!nidtable.hasOwnProperty(nid)){
nidtable[nid] = {};
isNew = true;
}
if(nidtable[nid].socket){
nidtable[nid].socket.destroy();
nidtable[nid].socket = null;
nidtable[nid].ip = null;
nidtable[nid].port = null;
access.info(nid, socket.remoteAddress+':'+socket.remotePort, '[CLOSE]');
cbArr.disconnect.forEach(cb => {
cb(nid, nidtable[nid]);
});
}
nidtable[nid].status = true;
nidtable[nid].funcID = data.funcID;
nidtable[nid].localport = data.port;
nidtable[nid].localip = data.ip;
nidtable[nid].HeartbeatInterval = data.HeartbeatInterval;
nidtable[nid].LastUpTime = new Date().valueOf() - data.uptime*1000;
nidtable[nid].LastActiveTime = new Date().valueOf();
nidtable[nid].ip = socket.remoteAddress;
nidtable[nid].port = socket.remotePort;
nidtable[nid].socket = socket;
socket.setTimeout(2.2 * nidtable[nid].HeartbeatInterval);
if(isNew){
cbArr.newNode.forEach(cb => {
cb(nid, nidtable[nid]);
});
}
if(data.hasOwnProperty('error') && data.error){
nidtable[nid].error = data.error;
cbArr.error.forEach(cb => {
cb(nid, nidtable[nid]);
});
}
cbArr.connect.forEach(cb => {
cb(nid, nidtable[nid]);
});
access.info(nid, socket.remoteAddress+':'+socket.remotePort, 'New TCP connection. Data::', JSON.stringify(data));
return;
}
if(!nid){
access.error(nid, socket.remoteAddress+':'+socket.remotePort, 'No nid is specified. Data::', data);
return;
}
nidtable[nid].LastActiveTime = new Date().valueOf();
nidtable[nid].status = true;
if(data.hasOwnProperty('uptime') && data.hasOwnProperty('heap') && data.hasOwnProperty('spiff')){
nidtable[nid].LastUpTime = new Date().valueOf() - data.uptime*1000;
nidtable[nid].heap = data.heap;
nidtable[nid].spiff = data.spiff;
access.info(nid, socket.remoteAddress+':'+socket.remotePort, '[HEARTBEAT]', data);
return;
}
if(!data.hasOwnProperty('from') || !data.hasOwnProperty('to') || !data.hasOwnProperty('name') || !data.hasOwnProperty('body')){
access.error(nid, socket.remoteAddress+':'+socket.remotePort, 'Illegal package format. Data::', data);
return;
}
if(data.to != 'director'){
if(nidtable.hasOwnProperty(data.to)){
try{
nidtable[data.to].socket.write(JSON.stringify(data));
flow.log('[FORWARD]', data.to+'<--'+data.from, data.name, data.body);
}catch(e){console.error(e)}
}else{
flow.error('[FORWARD]', '<nid lookup failure>', data.to+'<--'+data.from, data.name, data.body);
}
cbArr.forward.forEach(cb => {
cb(nid, nidtable[nid], data);
});
return;
}
if(data.to == 'director'){
cbArr.income.forEach(cb => {
cb(nid, nidtable[nid], data);
});
flow.log('[INCOMING]', data.to+'<--'+data.from, data.name, data.body );
return;
}
});
socket.setTimeout(60 * 1000);
socket.on('timeout', () => {
access.info(nid, socket.remoteAddress+':'+socket.remotePort, '[TIMEOUT]', 'After', socket.timeout, 'ms');
try{
nidtable[nid].socket = null;
nidtable[nid].ip = null;
nidtable[nid].port = null;
nidtable[nid].status = false;
access.info(nid, socket.remoteAddress+':'+socket.remotePort, '[CLOSE]');
cbArr.disconnect.forEach(cb => {
cb(nid, nidtable[nid]);
});
}catch(e){
delete nidtable[nid];
}
socket.destroy();
});
socket.on('error', function(err){
access.error(nid, socket.remoteAddress+':'+socket.remotePort, '[ERROR]', 'Exist unsent package');
});
socket.on('close', function(err){
if(nid && nidtable[nid].socket === socket){
nidtable[nid].socket = null;
nidtable[nid].ip = null;
nidtable[nid].port = null;
nidtable[nid].status = false;
access.info(nid, socket.remoteAddress+':'+socket.remotePort, '[CLOSE]');
cbArr.disconnect.forEach(cb => {
cb(nid, nidtable[nid]);
});
}
})
}).on('error', (err) => {
access.error('[ERROR]', 'Exist unsent package');
});
// Grab an arbitrary unused port.
server.listen({
host: host,
port: port,
exclusive: true
}, () => {
access.info('TCP Server Begin at ', host + ':' + port);
});
return o;
}

@ -0,0 +1,74 @@
module.exports = (logger, node, nodetable) => {
const log = logger.getLogger('nslog');
const NS_DELAY = 2000;
let delay = (time_ms) => new Promise(resolve => {
setTimeout(()=>{
resolve();
}, time_ms);
});
let o = {
get: (nodeArr, refer) => new Promise(async resolve => {
let list = [];
nodeArr.forEach(nid => {
if(node.hasOwnProperty(nid)){
list.push(nid);
}
});
let nsList = {};
let beginTime = new Date().valueOf();
for(nid1 of list){
for(nid2 of list){
if(nid1 != nid2){
log.info('[CHECK]', nid2, '-->', nid1);
await node[nid2].checkNS(nid1, refer && refer[nid2] && refer[nid2][nid1] && refer[nid2][nid1].ip || node[nid1].info.localip, refer && refer[nid2] && refer[nid2][nid1] && refer[nid2][nid1].port || node[nid1].info.localport)
}
}
};
await delay(NS_DELAY);
list.forEach(nid => {
Object.keys(node[nid].rns).forEach(nid2 => {
let rns = node[nid].rns[nid2];
if(rns.LastCheckTime > beginTime){
log.info('[VERIFIED]', nid2, '-->', nid);
if(!nsList.hasOwnProperty(nid2)){
nsList[nid2] = {};
}
nsList[nid2][nid] = {
ip: rns.ip,
port: rns.port
}
}
});
});
resolve(nsList);
}),
set: (nsList) => new Promise(async resolve => {
let status = true;
Object.keys(nsList).forEach(async nidf => {
log.info('[SET]', nidf, '::', JSON.stringify(nsList[nidf]));
status = status && await node[nidf].setNS(nsList[nidf]);
});
resolve(status);
})
}
return o;
}

@ -0,0 +1,446 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
accepts@~1.3.7:
version "1.3.7"
resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
dependencies:
mime-types "~2.1.24"
negotiator "0.6.2"
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
body-parser@1.19.0:
version "1.19.0"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
dependencies:
bytes "3.1.0"
content-type "~1.0.4"
debug "2.6.9"
depd "~1.1.2"
http-errors "1.7.2"
iconv-lite "0.4.24"
on-finished "~2.3.0"
qs "6.7.0"
raw-body "2.4.0"
type-is "~1.6.17"
bytes@3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
content-disposition@0.5.3:
version "0.5.3"
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
dependencies:
safe-buffer "5.1.2"
content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
cookie-signature@1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
cookie@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
date-format@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/date-format/-/date-format-2.1.0.tgz#31d5b5ea211cf5fd764cd38baf9d033df7e125cf"
integrity sha512-bYQuGLeFxhkxNOF3rcMtiZxvCBAquGzZm6oWA1oZ0g2THUzivaRhv8uOhdr19LmoobSOLoIAxeUK2RdbM8IFTA==
date-format@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/date-format/-/date-format-3.0.0.tgz#eb8780365c7d2b1511078fb491e6479780f3ad95"
integrity sha512-eyTcpKOcamdhWJXj56DpQMo1ylSQpcGtGKXcU0Tb97+K56/CF5amAqqqNj0+KvA0iw2ynxtHWFsPDSClCxe48w==
debug@2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
dependencies:
ms "2.0.0"
debug@^4.1.1:
version "4.3.1"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
dependencies:
ms "2.1.2"
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
ee-first@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
encodeurl@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
escape-html@~1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
etag@~1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
express@^4.17.1:
version "4.17.1"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
dependencies:
accepts "~1.3.7"
array-flatten "1.1.1"
body-parser "1.19.0"
content-disposition "0.5.3"
content-type "~1.0.4"
cookie "0.4.0"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~1.1.2"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
finalhandler "~1.1.2"
fresh "0.5.2"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
parseurl "~1.3.3"
path-to-regexp "0.1.7"
proxy-addr "~2.0.5"
qs "6.7.0"
range-parser "~1.2.1"
safe-buffer "5.1.2"
send "0.17.1"
serve-static "1.14.1"
setprototypeof "1.1.1"
statuses "~1.5.0"
type-is "~1.6.18"
utils-merge "1.0.1"
vary "~1.1.2"
finalhandler@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
dependencies:
debug "2.6.9"
encodeurl "~1.0.2"
escape-html "~1.0.3"
on-finished "~2.3.0"
parseurl "~1.3.3"
statuses "~1.5.0"
unpipe "~1.0.0"
flatted@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.2.tgz#4575b21e2bcee7434aa9be662f4b7b5f9c2b5138"
integrity sha512-r5wGx7YeOwNWNlCA0wQ86zKyDLMQr+/RB8xy74M4hTphfmjlijTSSXGuH8rnvKZnfT9i+75zmd8jcKdMR4O6jA==
forwarded@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
fresh@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
fs-extra@^8.1.0:
version "8.1.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
dependencies:
graceful-fs "^4.2.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
graceful-fs@^4.1.6, graceful-fs@^4.2.0:
version "4.2.6"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
http-errors@1.7.2:
version "1.7.2"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
dependencies:
depd "~1.1.2"
inherits "2.0.3"
setprototypeof "1.1.1"
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
http-errors@~1.7.2:
version "1.7.3"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
dependencies:
depd "~1.1.2"
inherits "2.0.4"
setprototypeof "1.1.1"
statuses ">= 1.5.0 < 2"
toidentifier "1.0.0"
iconv-lite@0.4.24:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
dependencies:
safer-buffer ">= 2.1.2 < 3"
inherits@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
inherits@2.0.4:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
ipaddr.js@1.9.1:
version "1.9.1"
resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.1.tgz#bff38543eeb8984825079ff3a2a8e6cbd46781b3"
integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==
jsonfile@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb"
integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=
optionalDependencies:
graceful-fs "^4.1.6"
log4js@^6.3.0:
version "6.3.0"
resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.3.0.tgz#10dfafbb434351a3e30277a00b9879446f715bcb"
integrity sha512-Mc8jNuSFImQUIateBFwdOQcmC6Q5maU0VVvdC2R6XMb66/VnT+7WS4D/0EeNMZu1YODmJe5NIn2XftCzEocUgw==
dependencies:
date-format "^3.0.0"
debug "^4.1.1"
flatted "^2.0.1"
rfdc "^1.1.4"
streamroller "^2.2.4"
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
merge-descriptors@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
mime-db@1.46.0:
version "1.46.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee"
integrity sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==
mime-types@~2.1.24:
version "2.1.29"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.29.tgz#1d4ab77da64b91f5f72489df29236563754bb1b2"
integrity sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==
dependencies:
mime-db "1.46.0"
mime@1.6.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
ms@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
ms@2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
ms@2.1.2:
version "2.1.2"
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
negotiator@0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
dependencies:
ee-first "1.1.1"
parseurl@~1.3.3:
version "1.3.3"
resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
proxy-addr@~2.0.5:
version "2.0.6"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.6.tgz#fdc2336505447d3f2f2c638ed272caf614bbb2bf"
integrity sha512-dh/frvCBVmSsDYzw6n926jv974gddhkFPfiN8hPOi30Wax25QZyZEGveluCgliBnqmuM+UJmBErbAUFIoDbjOw==
dependencies:
forwarded "~0.1.2"
ipaddr.js "1.9.1"
qs@6.7.0:
version "6.7.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
range-parser@~1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
raw-body@2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
dependencies:
bytes "3.1.0"
http-errors "1.7.2"
iconv-lite "0.4.24"
unpipe "1.0.0"
rfdc@^1.1.4:
version "1.3.0"
resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b"
integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==
safe-buffer@5.1.2:
version "5.1.2"
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
"safer-buffer@>= 2.1.2 < 3":
version "2.1.2"
resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
send@0.17.1:
version "0.17.1"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
dependencies:
debug "2.6.9"
depd "~1.1.2"
destroy "~1.0.4"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
http-errors "~1.7.2"
mime "1.6.0"
ms "2.1.1"
on-finished "~2.3.0"
range-parser "~1.2.1"
statuses "~1.5.0"
serve-static@1.14.1:
version "1.14.1"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
dependencies:
encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.3"
send "0.17.1"
setprototypeof@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
streamroller@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-2.2.4.tgz#c198ced42db94086a6193608187ce80a5f2b0e53"
integrity sha512-OG79qm3AujAM9ImoqgWEY1xG4HX+Lw+yY6qZj9R1K2mhF5bEmQ849wvrb+4vt4jLMLzwXttJlQbOdPOQVRv7DQ==
dependencies:
date-format "^2.1.0"
debug "^4.1.1"
fs-extra "^8.1.0"
toidentifier@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
type-is@~1.6.17, type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
dependencies:
media-typer "0.3.0"
mime-types "~2.1.24"
universalify@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
unpipe@1.0.0, unpipe@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
utils-merge@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
vary@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
Loading…
Cancel
Save