1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-01-10 01:17:40 +03:00

M #~: fix code node (#77)

Signed-off-by: Jorge Lobo <jlobo@opennebula.io>
This commit is contained in:
Jorge Miguel Lobo Escalona 2020-07-03 15:24:29 +02:00 committed by GitHub
parent 1e237cb3a1
commit 823cbf43fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 744 additions and 25 deletions

8
.gitignore vendored
View File

@ -47,6 +47,14 @@ src/sunstone/public/locale/languages/*.js
src/sunstone/public/package-lock.json
.tx/config
src/fireedge/node_modules
src/fireedge/dist
src/fireedge/test
src/fireedge/.vscode/launch.json
src/fireedge/yarn-error.log
src/fireedge/.DS_Store
src/fireedge/cypress/screenshots
src/onedb/local/
src/onedb/shared/

View File

@ -35,16 +35,4 @@ OPENNEBULA_ZONES:
- ID: 1
RPC: http://localhost:2633/RPC2
ZEROMQ:
VNC:
# Presentation information system (Config information)
SYSTEM_DATA:
NO_AUTH:
- MODE
AUTH:
- MODE
- OPENNEBULA_ZONES:
- ID
- VNC
- ZEROMQ
VNC:

View File

@ -1 +1,8 @@
{}
{
"port": 3001,
"numTestsKeptInMemory": 20,
"env":{},
"video": false,
"viewportHeight": 720,
"viewportWidth": 1280
}

View File

@ -0,0 +1,34 @@
// / <reference types="Cypress" />
context('dashboard', () => {
beforeEach(() => {
cy.visit('https://localhost:3000');
});
it('!!!!See menu', () => {
// https://on.cypress.io/type
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
// .type() with special character sequences
.type('{leftarrow}{rightarrow}{uparrow}{downarrow}')
.type('{del}{selectall}{backspace}')
// .type() with key modifiers
.type('{alt}{option}') // these are equivalent
.type('{ctrl}{control}') // these are equivalent
.type('{meta}{command}{cmd}') // these are equivalent
.type('{shift}')
// Delay each keypress by 0.1 sec
.type('slow.typing@email.com', { delay: 100 })
.should('have.value', 'slow.typing@email.com');
cy.get('.action-disabled')
// Ignore error checking prior to type
// like whether the input is visible or disabled
.type('disabled error checking', { force: true })
.should('have.value', 'disabled error checking');
});
});

View File

@ -0,0 +1,296 @@
// / <reference types="Cypress" />
context('login', () => {
beforeEach(() => {
cy.visit('https://localhost:3000');
});
it('Login without 2FA', () => {
// https://on.cypress.io/type
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
// .type() with special character sequences
.type('{leftarrow}{rightarrow}{uparrow}{downarrow}')
.type('{del}{selectall}{backspace}')
// .type() with key modifiers
.type('{alt}{option}') // these are equivalent
.type('{ctrl}{control}') // these are equivalent
.type('{meta}{command}{cmd}') // these are equivalent
.type('{shift}')
// Delay each keypress by 0.1 sec
.type('slow.typing@email.com', { delay: 100 })
.should('have.value', 'slow.typing@email.com');
cy.get('.action-disabled')
// Ignore error checking prior to type
// like whether the input is visible or disabled
.type('disabled error checking', { force: true })
.should('have.value', 'disabled error checking');
});
it('.focus() - focus on a DOM element', () => {
// https://on.cypress.io/focus
cy.get('.action-focus')
.focus()
.should('have.class', 'focus')
.prev()
.should('have.attr', 'style', 'color: orange;');
});
it('.blur() - blur off a DOM element', () => {
// https://on.cypress.io/blur
cy.get('.action-blur')
.type('About to blur')
.blur()
.should('have.class', 'error')
.prev()
.should('have.attr', 'style', 'color: red;');
});
it('.clear() - clears an input or textarea element', () => {
// https://on.cypress.io/clear
cy.get('.action-clear')
.type('Clear this text')
.should('have.value', 'Clear this text')
.clear()
.should('have.value', '');
});
it('.submit() - submit a form', () => {
// https://on.cypress.io/submit
cy.get('.action-form')
.find('[type="text"]')
.type('HALFOFF');
cy.get('.action-form')
.submit()
.next()
.should('contain', 'Your form has been submitted!');
});
it('.click() - click on a DOM element', () => {
// https://on.cypress.io/click
cy.get('.action-btn').click();
// You can click on 9 specific positions of an element:
// -----------------------------------
// | topLeft top topRight |
// | |
// | |
// | |
// | left center right |
// | |
// | |
// | |
// | bottomLeft bottom bottomRight |
// -----------------------------------
// clicking in the center of the element is the default
cy.get('#action-canvas').click();
cy.get('#action-canvas').click('topLeft');
cy.get('#action-canvas').click('top');
cy.get('#action-canvas').click('topRight');
cy.get('#action-canvas').click('left');
cy.get('#action-canvas').click('right');
cy.get('#action-canvas').click('bottomLeft');
cy.get('#action-canvas').click('bottom');
cy.get('#action-canvas').click('bottomRight');
// .click() accepts an x and y coordinate
// that controls where the click occurs :)
cy.get('#action-canvas')
.click(80, 75) // click 80px on x coord and 75px on y coord
.click(170, 75)
.click(80, 165)
.click(100, 185)
.click(125, 190)
.click(150, 185)
.click(170, 165);
// click multiple elements by passing multiple: true
cy.get('.action-labels>.label').click({ multiple: true });
// Ignore error checking prior to clicking
cy.get('.action-opacity>.btn').click({ force: true });
});
it('.dblclick() - double click on a DOM element', () => {
// https://on.cypress.io/dblclick
// Our app has a listener on 'dblclick' event in our 'scripts.js'
// that hides the div and shows an input on double click
cy.get('.action-div')
.dblclick()
.should('not.be.visible');
cy.get('.action-input-hidden').should('be.visible');
});
it('.check() - check a checkbox or radio element', () => {
// https://on.cypress.io/check
// By default, .check() will check all
// matching checkbox or radio elements in succession, one after another
cy.get('.action-checkboxes [type="checkbox"]')
.not('[disabled]')
.check()
.should('be.checked');
cy.get('.action-radios [type="radio"]')
.not('[disabled]')
.check()
.should('be.checked');
// .check() accepts a value argument
cy.get('.action-radios [type="radio"]')
.check('radio1')
.should('be.checked');
// .check() accepts an array of values
cy.get('.action-multiple-checkboxes [type="checkbox"]')
.check(['checkbox1', 'checkbox2'])
.should('be.checked');
// Ignore error checking prior to checking
cy.get('.action-checkboxes [disabled]')
.check({ force: true })
.should('be.checked');
cy.get('.action-radios [type="radio"]')
.check('radio3', { force: true })
.should('be.checked');
});
it('.uncheck() - uncheck a checkbox element', () => {
// https://on.cypress.io/uncheck
// By default, .uncheck() will uncheck all matching
// checkbox elements in succession, one after another
cy.get('.action-check [type="checkbox"]')
.not('[disabled]')
.uncheck()
.should('not.be.checked');
// .uncheck() accepts a value argument
cy.get('.action-check [type="checkbox"]')
.check('checkbox1')
.uncheck('checkbox1')
.should('not.be.checked');
// .uncheck() accepts an array of values
cy.get('.action-check [type="checkbox"]')
.check(['checkbox1', 'checkbox3'])
.uncheck(['checkbox1', 'checkbox3'])
.should('not.be.checked');
// Ignore error checking prior to unchecking
cy.get('.action-check [disabled]')
.uncheck({ force: true })
.should('not.be.checked');
});
it('.select() - select an option in a <select> element', () => {
// https://on.cypress.io/select
// Select option(s) with matching text content
cy.get('.action-select').select('apples');
cy.get('.action-select-multiple').select(['apples', 'oranges', 'bananas']);
// Select option(s) with matching value
cy.get('.action-select').select('fr-bananas');
cy.get('.action-select-multiple').select([
'fr-apples',
'fr-oranges',
'fr-bananas'
]);
});
it('.scrollIntoView() - scroll an element into view', () => {
// https://on.cypress.io/scrollintoview
// normally all of these buttons are hidden,
// because they're not within
// the viewable area of their parent
// (we need to scroll to see them)
cy.get('#scroll-horizontal button').should('not.be.visible');
// scroll the button into view, as if the user had scrolled
cy.get('#scroll-horizontal button')
.scrollIntoView()
.should('be.visible');
cy.get('#scroll-vertical button').should('not.be.visible');
// Cypress handles the scroll direction needed
cy.get('#scroll-vertical button')
.scrollIntoView()
.should('be.visible');
cy.get('#scroll-both button').should('not.be.visible');
// Cypress knows to scroll to the right and down
cy.get('#scroll-both button')
.scrollIntoView()
.should('be.visible');
});
it('.trigger() - trigger an event on a DOM element', () => {
// https://on.cypress.io/trigger
// To interact with a range input (slider)
// we need to set its value & trigger the
// event to signal it changed
// Here, we invoke jQuery's val() method to set
// the value and trigger the 'change' event
cy.get('.trigger-input-range')
.invoke('val', 25)
.trigger('change')
.get('input[type=range]')
.siblings('p')
.should('have.text', '25');
});
it('cy.scrollTo() - scroll the window or element to a position', () => {
// https://on.cypress.io/scrollTo
// You can scroll to 9 specific positions of an element:
// -----------------------------------
// | topLeft top topRight |
// | |
// | |
// | |
// | left center right |
// | |
// | |
// | |
// | bottomLeft bottom bottomRight |
// -----------------------------------
// if you chain .scrollTo() off of cy, we will
// scroll the entire window
cy.scrollTo('bottom');
cy.get('#scrollable-horizontal').scrollTo('right');
// or you can scroll to a specific coordinate:
// (x axis, y axis) in pixels
cy.get('#scrollable-vertical').scrollTo(250, 250);
// or you can scroll to a specific percentage
// of the (width, height) of the element
cy.get('#scrollable-both').scrollTo('75%', '25%');
// control the easing of the scroll (default is 'swing')
cy.get('#scrollable-vertical').scrollTo('center', { easing: 'linear' });
// control the duration of the scroll (in ms)
cy.get('#scrollable-both').scrollTo('center', { duration: 2000 });
});
});

View File

@ -0,0 +1,17 @@
// ***********************************************************
// This example plugins/index.js can be used to load plugins
//
// You can change the location of this file or turn off loading
// the plugins file with the 'pluginsFile' configuration option.
//
// You can read more here:
// https://on.cypress.io/plugins-guide
// ***********************************************************
// This function is called when a project is opened or re-opened (e.g. due to
// the project's config changing)
module.exports = (on, config) => {
// `on` is used to hook into various events Cypress emits
// `config` is the resolved Cypress config
}

View File

@ -1,7 +1,7 @@
{
"name": "sunstone_react",
"name": "FireEdge",
"version": "1.0.0",
"description": "Backend",
"description": "Opennebula FireEdge",
"main": "dist/index.js",
"scripts": {
"build": "webpack --mode=production && concurrently \"npm run copy_static_assets\" \"npm run build:css\"",
@ -10,14 +10,16 @@
"build:css": "node-sass src/public/scss/main.scss dist/public/app.css --output-style compressed",
"dev": "webpack --mode=development && npm run copy_static_assets && concurrently \"webpack --watch\" \"npm run build:css\" \"nodemon --inspect dist\"",
"start": "node dist/index",
"cypress:open": "cypress open",
"cypress:run": "cypress run --headless --browser chromium --spec \"cypress/integration/**/*.spec.js\"",
"copy_static_assets": "node copyStaticAssets.js"
},
"keywords": [
"sunstone",
"vm",
"flow",
"vms",
"opennebula"
],
"author": "Jorge Lobo",
"author": "OpenNebula.io",
"license": "ISC",
"engines": {
"node": ">=12.18.2"
@ -82,13 +84,13 @@
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"css-loader": "^3.2.0",
"cypress": "^3.4.1",
"cypress": "^3.8.1",
"enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.10.0",
"eslint": "^6.1.0",
"jloboescalona-eslint-config": "^1.1.0",
"node-sass": "^4.12.0",
"nodemon": "^2.0.4",
"nodemon": "^1.18.10",
"react-addons-test-utils": "^15.6.2",
"style-loader": "^1.0.0",
"webpack": "^4.43.0",

View File

@ -0,0 +1,167 @@
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
const express = require('express');
const { Map } = require('immutable');
const { defaults, httpCodes, params } = require('../../utils/contants');
const { getConfig } = require('../../utils/yml');
const {
opennebulaConnect,
checkRouteFunction,
commandXML,
checkOpennebulaCommand,
validateRouteFunction,
responseOpennebula
} = require('../../utils');
const {
validateResource,
optionalParameters,
optionalQueries,
clearStates,
getParamsState,
getQueriesState,
getIdUserOpennebula,
getUserOpennebula,
getPassOpennebula
} = require('./middlewares');
const {
defaultOpennebulaZones,
defaultMessageInvalidZone,
defaultGetMethod,
httpMethod: httpMethods,
from: fromData
} = defaults;
const router = express.Router();
express();
// user config
const appConfig = getConfig();
const opennebulaZones = appConfig.OPENNEBULA_ZONES || defaultOpennebulaZones;
const paramsToRoutes = () =>
Object.keys(params).reduce(
(resources, param) => String(resources).concat(`/:${params[param]}?`),
'/:resource?'
);
const getDataZone = () => {
let rtn;
if (opennebulaZones && Array.isArray(opennebulaZones)) {
const { federation } = getParamsState();
rtn = opennebulaZones[0];
if (federation !== null) {
rtn = opennebulaZones.find(
zone => zone && zone.ID !== undefined && String(zone.ID) === federation
);
}
}
return rtn;
};
router.all(
paramsToRoutes(),
[validateResource, optionalParameters, optionalQueries],
(req, res, next) => {
const { internalServerError, ok, methodNotAllowed } = httpCodes;
const { method: httpMethod } = req;
res.locals.httpCode = Map(internalServerError).toObject();
const zone = getDataZone();
if (zone) {
const { RPC } = zone;
const connectOpennebula = (
user = getUserOpennebula(),
pass = getPassOpennebula()
) => opennebulaConnect(user, pass, RPC);
const { resource } = req.params;
const routeFunction = checkRouteFunction(resource);
res.locals.httpCode = Map(methodNotAllowed).toObject();
const dataSources = {
[fromData.resource]: getParamsState(),
[fromData.query]: getQueriesState(),
[fromData.postBody]: req.body
};
if (routeFunction) {
const valRouteFunction = validateRouteFunction(
routeFunction,
httpMethod
);
if (valRouteFunction) {
valRouteFunction(
dataSources,
res,
next,
connectOpennebula,
getIdUserOpennebula()
);
} else {
next();
}
} else {
const { method } = getParamsState();
const command = commandXML(
resource,
method,
httpMethod === httpMethods.GET && defaultGetMethod
);
const getOpennebulaMethod = checkOpennebulaCommand(command, httpMethod);
if (getOpennebulaMethod) {
const response = val => {
res.locals.httpCode = Map(ok).toObject();
res.locals.httpCode.data = val || {};
if (typeof val === 'string') {
res.locals.httpCode.data = {};
res.locals.httpCode.message = val;
}
next();
};
const updaterResponse = code => {
if ('id' in code && 'message' in code) {
res.locals.httpCode = code;
}
};
const connect = connectOpennebula(
getUserOpennebula(),
getPassOpennebula(),
RPC
);
connect(
command,
getOpennebulaMethod(dataSources),
(err, value) =>
responseOpennebula(updaterResponse, err, value, response, next)
);
} else {
next();
}
}
} else {
res.locals.httpCode.message += `: ${defaultMessageInvalidZone}`;
next();
}
},
(req, res) => {
clearStates();
const { httpCode } = res.locals;
res.status(httpCode.id).json(httpCode);
}
);
module.exports = router;

View File

@ -0,0 +1,142 @@
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
const { Map } = require('immutable');
const {
private: authenticated,
public: nonAuthenticated
} = require('../../../api');
const { httpCodes, params } = require('../../../../utils/contants');
const {
validateAuth,
getAllowedQueryParams,
createParamsState,
createQueriesState
} = require('../../../../utils');
const defaultParams = Map(createParamsState());
const defaultQueries = Map(createQueriesState());
let paramsState = defaultParams.toObject();
let queriesState = defaultQueries.toObject();
let idUserOpennebula = '';
let userOpennebula = '';
let passOpennebula = '';
const getParamsState = () => paramsState;
const getQueriesState = () => queriesState;
const getIdUserOpennebula = () => idUserOpennebula;
const getUserOpennebula = () => userOpennebula;
const getPassOpennebula = () => passOpennebula;
const validateResource = (req, res, next) => {
const { badRequest, unauthorized, serviceUnavailable } = httpCodes;
let status = badRequest;
if (req && req.params && req.params.resource) {
const resource = req.params.resource;
status = serviceUnavailable;
if (resource in authenticated) {
const session = validateAuth(req);
if (
session &&
'iss' in session &&
'aud' in session &&
'jti' in session &&
'iat' in session &&
'exp' in session
) {
idUserOpennebula = session.iss;
userOpennebula = session.aud;
passOpennebula = session.jti;
next();
return;
}
status = unauthorized;
}
if (resource in nonAuthenticated) {
next();
return;
}
}
res.status(status.id).json(status);
};
const optionalParameters = (req, res, next) => {
if (req && req.params) {
let start = true;
const keys = Object.keys(req.params);
keys.forEach(param => {
if (start) {
start = false;
return start;
}
if (req.params[param]) {
const matches = req.params[param].match(/(^[\w]*=)/gi);
if (matches && matches[0]) {
params.forEach(parameter => {
if (
matches[0].replace(/=/g, '').toLowerCase() ===
parameter.toLowerCase()
) {
const removeKey = new RegExp(`^${parameter}=`, 'i');
if (paramsState[parameter] === null) {
paramsState[parameter] = req.params[param].replace(
removeKey,
''
);
}
}
});
} else {
paramsState[param] = req.params[param];
}
}
return '';
});
}
next();
};
const optionalQueries = (req, res, next) => {
if (req && req.query) {
const keys = Object.keys(req.query);
const queries = getAllowedQueryParams();
keys.forEach(query => {
if (req.query[query] && queries.includes(query)) {
queriesState[query] = req.query[query];
}
});
}
next();
};
const clearStates = () => {
paramsState = defaultParams.toObject();
queriesState = defaultQueries.toObject();
idUserOpennebula = '';
userOpennebula = '';
passOpennebula = '';
};
module.exports = {
validateResource,
optionalParameters,
optionalQueries,
clearStates,
getParamsState,
getQueriesState,
getIdUserOpennebula,
getUserOpennebula,
getPassOpennebula
};

View File

@ -0,0 +1,37 @@
/* Copyright 2002-2019, OpenNebula Project, OpenNebula Systems */
/* */
/* Licensed under the Apache License, Version 2.0 (the "License"); you may */
/* not use this file except in compliance with the License. You may obtain */
/* a copy of the License at */
/* */
/* http://www.apache.org/licenses/LICENSE-2.0 */
/* */
/* Unless required by applicable law or agreed to in writing, software */
/* distributed under the License is distributed on an "AS IS" BASIS, */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */
/* See the License for the specific language governing permissions and */
/* limitations under the License. */
/* -------------------------------------------------------------------------- */
const {
validateResource,
optionalParameters,
optionalQueries,
clearStates,
getParamsState,
getQueriesState,
getIdUserOpennebula,
getUserOpennebula,
getPassOpennebula
} = require('./api');
module.exports = {
validateResource,
optionalParameters,
optionalQueries,
clearStates,
getParamsState,
getQueriesState,
getIdUserOpennebula,
getUserOpennebula,
getPassOpennebula
};

View File

@ -100,6 +100,7 @@ const validateRouteFunction = (routeFunction, httpMethod = '') => {
typeof routeFunction.action === 'function'
) {
rtn = routeFunction.action;
console.log("aca llama la ruta--->", rtn.toString())
}
return rtn;
};

View File

@ -0,0 +1,2 @@
system_config --- toda la configuración del oned.conf
one.zonepool.info -- info de todas las zonas

View File

@ -1075,6 +1075,11 @@
"@types/prop-types" "*"
csstype "^2.2.0"
"@types/sizzle@2.3.2":
version "2.3.2"
resolved "https://registry.yarnpkg.com/@types/sizzle/-/sizzle-2.3.2.tgz#a811b8c18e2babab7d542b3365887ae2e4d9de47"
integrity sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==
"@types/styled-jsx@^2.2.8":
version "2.2.8"
resolved "https://registry.yarnpkg.com/@types/styled-jsx/-/styled-jsx-2.2.8.tgz#b50d13d8a3c34036282d65194554cf186bab7234"
@ -2512,13 +2517,14 @@ cyclist@^1.0.1:
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9"
integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=
cypress@^3.4.1:
version "3.4.1"
resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.4.1.tgz#ca2e4e9864679da686c6a6189603efd409664c30"
integrity sha512-1HBS7t9XXzkt6QHbwfirWYty8vzxNMawGj1yI+Fu6C3/VZJ8UtUngMW6layqwYZzLTZV8tiDpdCNBypn78V4Dg==
cypress@^3.8.1:
version "3.8.3"
resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.8.3.tgz#e921f5482f1cbe5814891c878f26e704bbffd8f4"
integrity sha512-I9L/d+ilTPPA4vq3NC1OPKmw7jJIpMKNdyfR8t1EXYzYCjyqbc59migOm1YSse/VRbISLJ+QGb5k4Y3bz2lkYw==
dependencies:
"@cypress/listr-verbose-renderer" "0.4.1"
"@cypress/xvfb" "1.2.4"
"@types/sizzle" "2.3.2"
arch "2.1.1"
bluebird "3.5.0"
cachedir "1.3.0"
@ -2527,6 +2533,7 @@ cypress@^3.4.1:
commander "2.15.1"
common-tags "1.8.0"
debug "3.2.6"
eventemitter2 "4.1.2"
execa "0.10.0"
executable "4.1.1"
extract-zip "1.6.7"
@ -2545,6 +2552,7 @@ cypress@^3.4.1:
request-progress "3.0.0"
supports-color "5.5.0"
tmp "0.1.0"
untildify "3.0.3"
url "0.11.0"
yauzl "2.10.0"
@ -3257,6 +3265,11 @@ etag@~1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
eventemitter2@4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-4.1.2.tgz#0e1a8477af821a6ef3995b311bf74c23a5247f15"
integrity sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU=
events@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
@ -8137,6 +8150,11 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
untildify@3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9"
integrity sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA==
unzip-response@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/unzip-response/-/unzip-response-2.0.1.tgz#d2f0f737d16b0615e72a6935ed04214572d56f97"