diff --git a/neutrino-custom/base.js b/neutrino-custom/base.js index a061401dd..95de55537 100644 --- a/neutrino-custom/base.js +++ b/neutrino-custom/base.js @@ -36,8 +36,7 @@ module.exports = neutrino => { 'angular', 'angular-cookies', 'angular-local-storage', 'angular-resource', 'angular-route', 'angular-sanitize', 'angular-toarrayfilter', 'angular-ui-bootstrap', 'angular-ui-router', 'bootstrap/dist/js/bootstrap', 'hawk', 'jquery', 'jquery.scrollto', - 'js-yaml', 'mousetrap', 'react', 'react-dom', 'taskcluster-client', 'numeral' - ]; + 'js-yaml', 'mousetrap', 'react', 'react-dom', 'taskcluster-client', 'numeral', 'metrics-graphics']; jsDeps.map(dep => neutrino.config.entry('vendor').add(dep) ); diff --git a/neutrino-custom/lint.js b/neutrino-custom/lint.js index c5f99d52b..13cd23a7e 100644 --- a/neutrino-custom/lint.js +++ b/neutrino-custom/lint.js @@ -93,7 +93,8 @@ module.exports = neutrino => { globals: ['angular', '$', '_', 'treeherder', 'perf', 'treeherderApp', 'failureViewerApp', 'logViewerApp', 'userguideApp', 'admin', 'Mousetrap', 'jQuery', 'React', - 'hawk', 'jsonSchemaDefaults', 'SERVICE_DOMAIN', 'numeral' + 'hawk', 'jsonSchemaDefaults', 'SERVICE_DOMAIN', 'numeral', + 'metrics-graphics' ] } })); diff --git a/package.json b/package.json index 217d6f4c9..d98cef70b 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "angular-ui-bootstrap": "1.3.3", "angular-ui-router": "0.4.2", "bootstrap": "3.3.7", + "d3": "^4.9.1", "deepmerge": "1.3.2", "font-awesome": "4.7.0", "hawk": "6.0.1", @@ -29,6 +30,7 @@ "json-e": "^2.1.1", "json-schema-defaults": "0.3.0", "lodash": "4.17.4", + "metrics-graphics": "^2.11.0", "mousetrap": "1.6.1", "neutrino": "4.3.1", "neutrino-lint-base": "4.3.1", diff --git a/ui/css/perf.css b/ui/css/perf.css index aa96992f0..917861ac7 100644 --- a/ui/css/perf.css +++ b/ui/css/perf.css @@ -471,3 +471,17 @@ td.alert-confidence { width: 200px; border: 1px solid white; } + +.replicate-graph .mg-header { + font-family: "Helvetica"; + font-size: 15px; + font-weight: bold; +} + +.replicate-graph .mg-x-axis text { + font-size: 0px; +} + +.replicate-graph .mg-category-guides line { + stroke: #ffffff; +} diff --git a/ui/entry-perf.js b/ui/entry-perf.js index 44f5f8f7d..a4843ccd4 100644 --- a/ui/entry-perf.js +++ b/ui/entry-perf.js @@ -10,6 +10,7 @@ require('font-awesome/css/font-awesome.css'); require('./css/treeherder-navbar.css'); require('./css/perf.css'); require('./css/treeherder-loading-overlay.css'); +require('metrics-graphics/dist/metricsgraphics.css'); // Vendor JS require('angular'); @@ -22,6 +23,7 @@ require('mousetrap'); require('bootstrap/dist/js/bootstrap'); require('angular-ui-bootstrap'); require('numeral'); +require('metrics-graphics'); require('./vendor/angular-clipboard.js'); // The jquery flot package does not seem to be updated on npm, so we use a local version: require('./vendor/jquery.flot.js'); diff --git a/ui/js/controllers/perf/compare.js b/ui/js/controllers/perf/compare.js index f3d9712e1..dc2cb1b7c 100644 --- a/ui/js/controllers/perf/compare.js +++ b/ui/js/controllers/perf/compare.js @@ -511,12 +511,13 @@ perf.controller('CompareSubtestResultsCtrl', [ '$state', '$stateParams', '$scope', '$rootScope', '$location', 'thServiceDomain', 'ThRepositoryModel', 'ThResultSetModel', '$http', '$q', '$timeout', 'PhSeries', 'math', - 'PhCompare', 'phTimeRanges', 'compareBaseLineDefaultTimeRange', + 'PhCompare', 'phTimeRanges', 'compareBaseLineDefaultTimeRange', '$httpParamSerializer', function CompareSubtestResultsCtrl($state, $stateParams, $scope, $rootScope, $location, thServiceDomain, ThRepositoryModel, ThResultSetModel, $http, $q, $timeout, PhSeries, math, - PhCompare, phTimeRanges, compareBaseLineDefaultTimeRange) { + PhCompare, phTimeRanges, compareBaseLineDefaultTimeRange, + $httpParamSerializer) { //TODO: duplicated from comparectrl function verifyRevision(project, revision, rsid) { return ThResultSetModel.getResultSetsFromRevision(project.name, revision).then( @@ -588,6 +589,20 @@ perf.controller('CompareSubtestResultsCtrl', [ }; }), [$scope.originalResultSet, $scope.newResultSet]) }]; + //replicate distribution is added only for talos + if ($scope.filterOptions.framework === '1') { + cmap.links.push({ + title: 'replicate', + href: 'perf.html#/comparesubtestdistribution?' + $httpParamSerializer({ + originalProject: $scope.originalProject.name, + newProject: $scope.newProject.name, + originalRevision: $scope.originalRevision, + newRevision: $scope.newRevision, + originalSubtestSignature: oldSig, + newSubtestSignature: newSig + }) + }); + } } else { @@ -605,7 +620,6 @@ perf.controller('CompareSubtestResultsCtrl', [ }), [$scope.newResultSet], $scope.selectedTimeRange.value) }]; } - $scope.compareResults[testName].push(cmap); }); } @@ -853,3 +867,113 @@ perf.controller('CompareSubtestResultsCtrl', [ }); }); }]); + +perf.controller('CompareSubtestDistributionCtrl', ['$scope', '$stateParams', '$q', 'ThRepositoryModel', + 'PhSeries', 'ThResultSetModel', 'metricsgraphics', + function CompareSubtestDistributionCtrl($scope, $stateParams, $q, ThRepositoryModel, + PhSeries, ThResultSetModel, metricsgraphics) { + $scope.originalRevision = $stateParams.originalRevision; + $scope.newRevision = $stateParams.newRevision; + $scope.originalSubtestSignature = $stateParams.originalSubtestSignature; + $scope.newSubtestSignature = $stateParams.newSubtestSignature; + $scope.dataLoading = true; + let loadRepositories = ThRepositoryModel.load(); + const fetchAndDrawReplicateGraph = function (project, revision, subtestSignature, target) { + let replicateData = {}; + return ThResultSetModel.getResultSetsFromRevision(project, revision).then( + (revisionData) => { + replicateData.resultSet = revisionData[0]; + return PhSeries.getSeriesData(project, { + signatures: subtestSignature, + push_id: replicateData.resultSet.id + }); + }).then((perfDatumList) => { + if (!perfDatumList[subtestSignature]) { + replicateData.replicateDataError = true; + return; + } + const numRuns = perfDatumList[subtestSignature].length; + let replicatePromises = perfDatumList[subtestSignature].map( + (value) => {return PhSeries.getReplicateData({job_id: value.job_id}); + }); + return $q.all(replicatePromises).then((replicateData) => { + let replicateValues = replicateData.concat.apply([], + replicateData.map((data) => { + let testSuite = data.suites.find((suite) => { + return suite.name === $scope.testSuite; + }); + let subtest = testSuite.subtests.find((subtest) =>{ + return subtest.name === $scope.subtest; + }); + return subtest.replicates; + }) + ); + //metrics-graphics doesn't accept "0" as x_accesor + replicateValues = replicateValues.map((value, index) => ({ + "replicate": (index + 1).toString(), + "value": value + })); + metricsgraphics.data_graphic({ + title: `${target} Replicates over ${numRuns} run${(numRuns > 1) ? 's' : ''}`, + chart_type: "bar", + data: replicateValues, + y_accessor: "value", + x_accessor: "replicate", + height: 275, + width: 1000, + target: `#${target}` + }); + }, + () =>{ + replicateData.replicateDataError = true; + }); + }).then(() =>{ + if (replicateData.replicateDataError) { + metricsgraphics.data_graphic({ + title: `${target} Replicates`, + chart_type: 'missing-data', + missing_text: 'No Data Found', + target: `#${target}`, + width: 1000, + height: 275 + }); + } + return replicateData; + }); + }; + + $q.all([loadRepositories]).then(() => { + $scope.originalProject = ThRepositoryModel.getRepo( + $stateParams.originalProject); + $scope.newProject = ThRepositoryModel.getRepo( + $stateParams.newProject); + PhSeries.getSeriesList($scope.originalProject.name, {signature: $scope.originalSubtestSignature}).then( + (seriesData) => { + $scope.testSuite = seriesData[0].suite; + $scope.subtest = seriesData[0].test; + $scope.testName = seriesData[0].name; + $scope.platform = seriesData[0].platform; + return fetchAndDrawReplicateGraph($scope.originalProject.name, + $scope.originalRevision, + $scope.originalSubtestSignature, + 'Base'); + }).then((result) => { + $scope.originalResultSet = result.resultSet; + $scope.originalReplicateError = result.replicateDataError; + if ($scope.originalReplicateError) + $scope.noResult = "base"; + return fetchAndDrawReplicateGraph($scope.newProject.name, + $scope.newRevision, + $scope.newSubtestSignature, + 'New'); + }).then((result) => { + $scope.newResultSet = result.resultSet; + $scope.newReplicateError = result.replicateDataError; + if ($scope.newReplicateError) + $scope.noResult = "new"; + window.document.title = `${$scope.platform}: ${$scope.testName}`; + $scope.dataLoading = false; + }); + }); + } +]); diff --git a/ui/js/models/perf/series.js b/ui/js/models/perf/series.js index 83f056234..050ecfa3d 100644 --- a/ui/js/models/perf/series.js +++ b/ui/js/models/perf/series.js @@ -81,12 +81,26 @@ treeherder.factory('PhSeries', ['$http', 'thServiceDomain', 'ThOptionCollectionM }, getSeriesData: function (projectName, params) { return $http.get(thServiceDomain + '/api/project/' + projectName + '/performance/data/', - { params: params }).then(function (response) { + {params: params}).then(function (response) { if (response.data) { return response.data; } return $q.reject("No series data found"); }); + }, + getReplicateData: function (params) { + params.value = 'perfherder-data.json'; + return $http.get(thServiceDomain + '/api/jobdetail/' + , {params: params}).then( + function (response) { + if (response.data.results[0]) { + let url = response.data.results[0].url; + return $http.get(url).then(function (response) { + return response.data; + }); + } + return $q.reject("No replicate data found"); + }); } }; }]); diff --git a/ui/js/perfapp.js b/ui/js/perfapp.js index aa72dcc44..2790261e4 100644 --- a/ui/js/perfapp.js +++ b/ui/js/perfapp.js @@ -55,6 +55,11 @@ perf.config(['$compileProvider', '$httpProvider', '$stateProvider', '$urlRouterP templateUrl: 'partials/perf/dashboardsubtest.html', url: '/dashboardsubtest?topic&filter&showOnlyImportant&showOnlyConfident&baseSignature&variantSignature&repo&timerange&revision', controller: 'dashSubtestCtrl' + }).state('comparesubtestdistribution', { + title: 'Compare Subtest Distribution', + templateUrl: 'partials/perf/comparesubtestdistribution.html', + url: '/comparesubtestdistribution?originalProject&newProject&originalRevision&newRevision&originalSubtestSignature?newSubtestSignature', + controller: 'CompareSubtestDistributionCtrl' }); $urlRouterProvider.otherwise('/graphs'); }]).run(['$rootScope', '$state', '$stateParams', function ($rootScope, $state, $stateParams) { diff --git a/ui/js/services/main.js b/ui/js/services/main.js index b5e3b8a80..327dd476d 100755 --- a/ui/js/services/main.js +++ b/ui/js/services/main.js @@ -218,3 +218,8 @@ treeherder.factory('numeral', [ function () { return require('numeral'); }]); + +treeherder.factory('metricsgraphics', [ + function () { + return require('metrics-graphics'); + }]); diff --git a/ui/partials/perf/comparesubtestdistribution.html b/ui/partials/perf/comparesubtestdistribution.html new file mode 100644 index 000000000..98f532532 --- /dev/null +++ b/ui/partials/perf/comparesubtestdistribution.html @@ -0,0 +1,16 @@ +
+
+ Loading all results, please wait a minute... + +
+
+

{{platform}}: {{testName}} replicate distribution

+ +    +
+
+
+
+
+

No results to show for these two revisions.

+
diff --git a/yarn.lock b/yarn.lock index 24d5db3ae..e8e773216 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1501,7 +1501,7 @@ combined-stream@~0.0.4: dependencies: delayed-stream "0.0.5" -commander@2.9.0, commander@2.9.x: +commander@2, commander@2.9.0, commander@2.9.x: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" dependencies: @@ -1804,6 +1804,216 @@ custom-event@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/custom-event/-/custom-event-1.0.1.tgz#5d02a46850adf1b4a317946a3928fccb5bfd0425" +d3-array@1, d3-array@1.2.0, d3-array@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.0.tgz#147d269720e174c4057a7f42be8b0f3f2ba53108" + +d3-axis@1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.7.tgz#048433d307061f62d1d248e2930c01d7b6738cd8" + +d3-brush@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.0.4.tgz#00c2f238019f24f6c0a194a26d41a1530ffe7bc4" + dependencies: + d3-dispatch "1" + d3-drag "1" + d3-interpolate "1" + d3-selection "1" + d3-transition "1" + +d3-chord@1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-1.0.4.tgz#7dec4f0ba886f713fe111c45f763414f6f74ca2c" + dependencies: + d3-array "1" + d3-path "1" + +d3-collection@1, d3-collection@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-collection/-/d3-collection-1.0.3.tgz#00bdea94fbc1628d435abbae2f4dc2164e37dd34" + +d3-color@1, d3-color@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.0.3.tgz#bc7643fca8e53a8347e2fbdaffa236796b58509b" + +d3-dispatch@1, d3-dispatch@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.3.tgz#46e1491eaa9b58c358fce5be4e8bed626e7871f8" + +d3-drag@1, d3-drag@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.1.0.tgz#4a49b4d77a42e9e3d5a0ef3b492b14aaa2e5a733" + dependencies: + d3-dispatch "1" + d3-selection "1" + +d3-dsv@1, d3-dsv@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-1.0.5.tgz#419f7db47f628789fc3fdb636e678449d0821136" + dependencies: + commander "2" + iconv-lite "0.4" + rw "1" + +d3-ease@1, d3-ease@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.3.tgz#68bfbc349338a380c44d8acc4fbc3304aa2d8c0e" + +d3-force@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/d3-force/-/d3-force-1.0.6.tgz#ea7e1b7730e2664cd314f594d6718c57cc132b79" + dependencies: + d3-collection "1" + d3-dispatch "1" + d3-quadtree "1" + d3-timer "1" + +d3-format@1, d3-format@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.2.0.tgz#6b480baa886885d4651dc248a8f4ac9da16db07a" + +d3-geo@1.6.4: + version "1.6.4" + resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.6.4.tgz#f20e1e461cb1845f5a8be55ab6f876542a7e3199" + dependencies: + d3-array "1" + +d3-hierarchy@1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/d3-hierarchy/-/d3-hierarchy-1.1.4.tgz#96c3942f3f21cf997a11b4edf00dde2a77b4c6d0" + +d3-interpolate@1, d3-interpolate@1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-1.1.5.tgz#69e099ff39214716e563c9aec3ea9d1ea4b8a79f" + dependencies: + d3-color "1" + +d3-path@1, d3-path@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.5.tgz#241eb1849bd9e9e8021c0d0a799f8a0e8e441764" + +d3-polygon@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.3.tgz#16888e9026460933f2b179652ad378224d382c62" + +d3-quadtree@1, d3-quadtree@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/d3-quadtree/-/d3-quadtree-1.0.3.tgz#ac7987e3e23fe805a990f28e1b50d38fcb822438" + +d3-queue@3.0.7: + version "3.0.7" + resolved "https://registry.yarnpkg.com/d3-queue/-/d3-queue-3.0.7.tgz#c93a2e54b417c0959129d7d73f6cf7d4292e7618" + +d3-random@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/d3-random/-/d3-random-1.1.0.tgz#6642e506c6fa3a648595d2b2469788a8d12529d3" + +d3-request@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/d3-request/-/d3-request-1.0.5.tgz#4daae946d1dd0d57dfe01f022956354958d51f23" + dependencies: + d3-collection "1" + d3-dispatch "1" + d3-dsv "1" + xmlhttprequest "1" + +d3-scale@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-1.0.6.tgz#bce19da80d3a0cf422c9543ae3322086220b34ed" + dependencies: + d3-array "^1.2.0" + d3-collection "1" + d3-color "1" + d3-format "1" + d3-interpolate "1" + d3-time "1" + d3-time-format "2" + +d3-selection@1, d3-selection@1.1.0, d3-selection@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.1.0.tgz#1998684896488f839ca0372123da34f1d318809c" + +d3-shape@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.1.1.tgz#50a1037e48a79f5b8fd9d58cde52799aeb1f7723" + dependencies: + d3-path "1" + +d3-time-format@2, d3-time-format@2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.0.5.tgz#9d7780204f7c9119c9170b1a56db4de9a8af972e" + dependencies: + d3-time "1" + +d3-time@1, d3-time@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.0.6.tgz#a55b13d7d15d3a160ae91708232e0835f1d5e945" + +d3-timer@1, d3-timer@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.5.tgz#b266d476c71b0d269e7ac5f352b410a3b6fe6ef0" + +d3-transition@1, d3-transition@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.1.0.tgz#cfc85c74e5239324290546623572990560c3966f" + dependencies: + d3-color "1" + d3-dispatch "1" + d3-ease "1" + d3-interpolate "1" + d3-selection "^1.1.0" + d3-timer "1" + +d3-voronoi@1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.2.tgz#1687667e8f13a2d158c80c1480c5a29cb0d8973c" + +d3-zoom@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.2.0.tgz#b3231f4f9386241475defe1c557bfd3fde1065fb" + dependencies: + d3-dispatch "1" + d3-drag "1" + d3-interpolate "1" + d3-selection "1" + d3-transition "1" + +d3@^4, d3@^4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/d3/-/d3-4.9.1.tgz#f860be9252261a3c14eea64b1d2590d14f4db838" + dependencies: + d3-array "1.2.0" + d3-axis "1.0.7" + d3-brush "1.0.4" + d3-chord "1.0.4" + d3-collection "1.0.3" + d3-color "1.0.3" + d3-dispatch "1.0.3" + d3-drag "1.1.0" + d3-dsv "1.0.5" + d3-ease "1.0.3" + d3-force "1.0.6" + d3-format "1.2.0" + d3-geo "1.6.4" + d3-hierarchy "1.1.4" + d3-interpolate "1.1.5" + d3-path "1.0.5" + d3-polygon "1.0.3" + d3-quadtree "1.0.3" + d3-queue "3.0.7" + d3-random "1.1.0" + d3-request "1.0.5" + d3-scale "1.0.6" + d3-selection "1.1.0" + d3-shape "1.1.1" + d3-time "1.0.6" + d3-time-format "2.0.5" + d3-timer "1.0.5" + d3-transition "1.1.0" + d3-voronoi "1.1.2" + d3-zoom "1.2.0" + d@1: version "1.0.0" resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" @@ -3104,7 +3314,7 @@ https-browserify@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" -iconv-lite@0.4.15, iconv-lite@~0.4.13: +iconv-lite@0.4, iconv-lite@0.4.15, iconv-lite@~0.4.13: version "0.4.15" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" @@ -3979,6 +4189,12 @@ methods@~1.1.1, methods@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" +metrics-graphics@^2.11.0: + version "2.11.0" + resolved "https://registry.yarnpkg.com/metrics-graphics/-/metrics-graphics-2.11.0.tgz#1585eb483a0b494f417a65c35a0ade8ece904a72" + dependencies: + d3 "^4" + micromatch@^2.1.5, micromatch@^2.3.11: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" @@ -5393,6 +5609,10 @@ run-async@^0.1.0: dependencies: once "^1.3.0" +rw@1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" + rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" @@ -6313,6 +6533,10 @@ xmlhttprequest-ssl@1.5.3: version "1.5.3" resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d" +xmlhttprequest@1: + version "1.8.0" + resolved "https://registry.yarnpkg.com/xmlhttprequest/-/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc" + xtend@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"