Refactor SplatNet data updaters

This also changes the output paths for SplatNet images to make them follow the original paths (rather than just using the original filenames).
This commit is contained in:
Unknown 2017-11-12 13:22:25 -08:00 committed by Matt Isenhower
parent 5fa3c1110d
commit 8bcb4a35fc
7 changed files with 386 additions and 214 deletions

View File

@ -32,6 +32,7 @@
"html-loader": "^0.5.0",
"html-webpack-plugin": "^2.30.1",
"json-stable-stringify": "^1.0.1",
"jsonpath": "^1.0.0",
"make-runnable": "^1.3.6",
"mkdirp": "^0.5.1",
"moment-timezone": "^0.5.13",

View File

@ -54,7 +54,7 @@ export default {
},
largeImage() {
if (this.stageDetails)
return Vue.filter('localSplatNetImageUrl')(this.stageDetails.largeImage || this.stageDetails.image);
return this.stageDetails.largeImage || Vue.filter('localSplatNetImageUrl')(this.stageDetails.image);
},
style() {
return {

View File

@ -2,15 +2,9 @@ import Vue from 'vue';
// Local hosting of SplatNet images
Vue.filter('localSplatNetImageUrl', function(value) {
if (value) {
// Quick hack to detect whether this is a bundled image or a SplatNet image
if (value.indexOf('assets/img/') === 0)
return value;
// This is a SplatNet image, so let's adjust the URL
let filename = value.replace(/^.*[\\\/]/, '');
return `assets/img/splatnet/${filename}`;
}
// Have to use a relative path here for the screenshot generator.
// May need to change this in the future.
return 'assets/splatnet' + value;
});
// Short date format (e.g., 8/15 or 15/8)

View File

@ -1,218 +1,92 @@
require('./bootstrap');
const path = require('path');
const fs = require('fs');
const mkdirp = require('mkdirp');
const splatnet = require('./splatnet');
const raven = require('raven');
const dataPath = path.resolve('public/data');
const splatnetImagePath = path.resolve('public/assets/img/splatnet');
const Updater = require('./updaters/Updater');
const OriginalGearImageUpdater = require('./updaters/OriginalGearImageUpdater');
/**
* Updaters
*/
const updaters = [
// Original gear images
new OriginalGearImageUpdater(),
async function updateSchedules() {
let data = await handleRequest({
title: 'map schedules',
filename: `${dataPath}/schedules.json`,
request: splatnet.getSchedules(),
});
// Schedules
new Updater({
name: 'Schedules',
filename: 'schedules.json',
request: () => splatnet.getSchedules(),
imagePaths: [
'$..stage_a.image',
'$..stage_b.image',
],
}),
// Download stage images
if (data) {
for (let type of ['regular', 'gachi', 'league']) {
if (data[type]) {
for (let schedule of data[type]) {
await maybeDownloadImage(schedule.stage_a.image);
await maybeDownloadImage(schedule.stage_b.image);
}
}
}
}
}
// Co-op Schedules
new Updater({
name: 'Co-op Schedules',
filename: 'coop-schedules.json',
request: () => splatnet.getCoopSchedules(),
imagePaths: [
'$..stage.image',
'$..weapons[*].image',
],
}),
async function updateCoopSchedules() {
let data = await handleRequest({
title: 'co-op schedules',
filename: `${dataPath}/coop-schedules.json`,
request: splatnet.getCoopSchedules(),
});
// Timeline
new Updater({
name: 'Timeline',
filename: 'timeline.json',
request: () => splatnet.getTimeline(),
rootKeys: ['coop', 'weapon_availability'],
imagePaths: [
'$.coop..gear.image',
'$.coop..gear.brand.image',
'$.weapon_availability..weapon.image',
'$.weapon_availability..weapon.special.image_a',
'$.weapon_availability..weapon.sub.image_a',
],
}),
// Download images
if (data) {
for (let schedule of data.details) {
await maybeDownloadImage(schedule.stage.image);
for (let weapon of schedule.weapons) {
// Mystery weapons are null, so we have to make sure we don't attempt to download their images
if (weapon)
await maybeDownloadImage(weapon.image);
}
}
}
}
async function updateTimeline() {
let data = await handleRequest({
title: 'timeline',
filename: `${dataPath}/timeline.json`,
request: splatnet.getTimeline(),
transformer: responseData => {
// Filter out everything but the data we need
let data = { coop: null, weapon_availability: null };
if (responseData.coop && responseData.coop.importance > -1)
data.coop = responseData.coop;
if (responseData.weapon_availability && responseData.weapon_availability.importance > -1)
data.weapon_availability = responseData.weapon_availability;
return data;
},
});
// Download images
if (data) {
if (data.coop && data.coop.reward_gear) {
await maybeDownloadImage(data.coop.reward_gear.gear.image);
await maybeDownloadImage(data.coop.reward_gear.gear.brand.image);
}
if (data.weapon_availability && data.weapon_availability.availabilities) {
for (let availability of data.weapon_availability.availabilities) {
let weapon = availability.weapon;
await maybeDownloadImage(weapon.image);
await maybeDownloadImage(weapon.special.image_a);
await maybeDownloadImage(weapon.sub.image_a);
}
}
}
}
async function updateFestivals() {
let data = await handleRequest({
title: 'festivals',
filename: `${dataPath}/festivals.json`,
request: async function() {
// Festivals
new Updater({
name: 'Festivals',
filename: 'festivals.json',
async request() {
return {
na: await splatnet.getCombinedFestivals('NA'),
eu: await splatnet.getCombinedFestivals('EU'),
jp: await splatnet.getCombinedFestivals('JP'),
};
}(),
});
// Download banner/stage images
if (data) {
for (let region of ['na', 'eu', 'jp']) {
for (let festival of data[region].festivals) {
await maybeDownloadImage(festival.images.alpha);
await maybeDownloadImage(festival.images.bravo);
await maybeDownloadImage(festival.images.panel);
await maybeDownloadImage(festival.special_stage.image);
}
}
}
}
async function updateMerchandises() {
let data = await handleRequest({
title: 'merchandises',
filename: `${dataPath}/merchandises.json`,
request: splatnet.getMerchandises(),
transformer: responseData => {
// Filter out everything but the data we need
let data = { merchandises: null };
if (responseData.merchandises)
data.merchandises = responseData.merchandises;
return data;
},
});
imagePaths: [
'$..images.alpha',
'$..images.bravo',
'$..images.panel',
'$..special_stage.image',
],
}),
// Download merchandise/skill images
if (data && data.merchandises) {
for (let merchandise of data.merchandises) {
await maybeDownloadImage(merchandise.gear.image);
await maybeDownloadImage(merchandise.gear.brand.image);
await maybeDownloadImage(merchandise.gear.brand.frequent_skill.image);
await maybeDownloadImage(merchandise.skill.image);
}
}
}
// Merchandises
new Updater({
name: 'Merchandises',
filename: 'merchandises.json',
request: () => splatnet.getMerchandises(),
rootKeys: ['merchandises'],
imagePaths: [
'$..gear.image',
'$..gear.brand.image',
'$..gear.brand.frequent_skill.image',
'$..skill.image',
],
}),
];
async function updateAll() {
await updateSchedules();
await updateCoopSchedules();
await updateTimeline();
await updateFestivals();
await updateMerchandises();
return 'Done.';
}
for (let updater of updaters)
await updater.update();
/**
* Utility functions
*/
function writeFile(filename, data) {
mkdirp(path.dirname(filename));
fs.writeFileSync(filename, data);
}
async function handleRequest(options) {
options = Object.assign({ isJson: true }, options);
console.info(`Updating ${options.title}...`);
try {
// Get the response data
let data = await options.request;
// If we have a data transformer, use it
if (options.transformer)
data = options.transformer(data);
let fileData = (options.isJson) ? JSON.stringify(data) : data;
// Write the data
writeFile(options.filename, fileData);
console.info(`Updated ${options.title}.`);
return data;
} catch (e) {
raven.captureException(e);
console.error(`Couldn\'t update ${options.title}.`);
console.error(e);
}
}
function maybeDownloadImage(imagePath) {
if (!imagePath)
return;
// Quick hack to detect whether this is our own hosted image
if (imagePath.indexOf('assets/img/') === 0)
return;
let filename = path.basename(imagePath);
let localPath = `${splatnetImagePath}/${filename}`;
// If we've already downloaded the image, we don't need to do anything
if (fs.existsSync(localPath))
return;
// Otherwise, download the image
return handleRequest({
title: `image ${filename}`,
filename: localPath,
request: splatnet.getImage(imagePath),
isJson: false,
});
return 'Done';
}
module.exports = {
updateSchedules,
updateCoopSchedules,
updateTimeline,
updateFestivals,
updateMerchandises,
updateAll,
}

View File

@ -0,0 +1,23 @@
const Updater = require('./Updater');
const path = require('path');
const fs = require('fs');
const dataPath = path.resolve('src/js/data');
class OriginalGearImageUpdater extends Updater {
constructor() {
super({
name: 'Original Gear',
imagePaths: ['$..image'],
});
}
async update() {
// Get the list of skills
let data = JSON.parse(fs.readFileSync(`${dataPath}/skills.json`));
// Retrieve skill images
await this.downloadImages(data);
}
}
module.exports = OriginalGearImageUpdater;

View File

@ -0,0 +1,138 @@
const path = require('path');
const fs = require('fs');
const mkdirp = require('mkdirp');
const jsonpath = require('jsonpath');
const splatnet = require('../splatnet');
const raven = require('raven');
const dataPath = path.resolve('public/data');
const splatnetAssetPath = path.resolve('public/assets/splatnet');
class Updater {
constructor(options = {}) {
this.options = options;
}
async update() {
this.info('Updating data...');
// Retrieve the data
let data = await this.handleRequest(this.getData());
// Filter the root keys if necessary
data = this.filterRootKeys(data);
// Convert the data to a JSON string
let dataString = JSON.stringify(data);
// Write the data to disk
let localPath = `${dataPath}/${this.options.filename}`;
this.writeFile(localPath, dataString);
// Download images if necessary
await this.downloadImages(data);
this.info('Done.');
}
getData() {
return this.options.request();
}
async handleRequest(request) {
try {
return await request;
}
catch (e) {
// Send the error to Sentry
raven.captureException(e);
// Log the message to the console
this.error(`Couldn't handle request: ${e.toString()}`);
// Re-throw
throw e;
}
}
filterRootKeys(data) {
if (this.options.rootKeys) {
let result = {};
for (let key of this.options.rootKeys) {
let value = data[key];
result[key] = (this.shouldIncludeRootValue(value)) ? value : null;
}
return result;
}
return data;
}
shouldIncludeRootValue(value) {
if (!value)
return false;
// Remove timeline items with an importance of -1
if (value.hasOwnProperty('importance'))
return value.importance > -1;
return true;
}
writeFile(filename, data) {
mkdirp(path.dirname(filename));
fs.writeFileSync(filename, data);
}
async downloadImages(data) {
if (this.options.imagePaths) {
for (let expression of this.options.imagePaths) {
let splatnetImages = jsonpath.query(data, expression);
for (let splatnetImage of splatnetImages)
await this.maybeDownloadImage(splatnetImage);
}
}
}
async maybeDownloadImage(imagePath) {
if (!imagePath)
return;
let localPath = splatnetAssetPath + imagePath;
// Check whether the image has already been downloaded
if (fs.existsSync(localPath))
return;
// Otherwise, download the image
try {
this.info(`Downloading image: ${imagePath}`);
let image = await this.handleRequest(splatnet.getImage(imagePath));
this.writeFile(localPath, image);
} catch (e) { }
}
/**
* Log helpers
*/
formatLogMessage(message) {
return `[Updater] [${this.options.name}] ${message}`;
}
log(message) {
console.log(this.formatLogMessage(message));
}
info(message) {
console.info(this.formatLogMessage(message));
}
error(message) {
console.error(this.formatLogMessage(message));
}
}
module.exports = Updater;

162
yarn.lock
View File

@ -2,6 +2,10 @@
# yarn lockfile v1
JSONSelect@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/JSONSelect/-/JSONSelect-0.4.0.tgz#a08edcc67eb3fcbe99ed630855344a0cf282bb8d"
abbrev@1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
@ -1130,6 +1134,10 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
inherits "^2.0.1"
safe-buffer "^5.0.1"
cjson@~0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/cjson/-/cjson-0.2.1.tgz#73cd8aad65d9e1505f9af1744d3b79c1527682a5"
clap@^1.0.9:
version "1.2.3"
resolved "https://registry.yarnpkg.com/clap/-/clap-1.2.3.tgz#4f36745b32008492557f46412d66d50cb99bce51"
@ -1223,6 +1231,10 @@ colormin@^1.0.5:
css-color-names "0.0.4"
has "^1.0.1"
colors@0.5.x:
version "0.5.1"
resolved "https://registry.yarnpkg.com/colors/-/colors-0.5.1.tgz#7d0023eaeb154e8ee9fce75dcb923d0ed1667774"
colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
@ -1597,6 +1609,10 @@ deep-extend@~0.4.0:
version "0.4.2"
resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f"
deep-is@~0.1.3:
version "0.1.3"
resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
define-properties@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94"
@ -1731,6 +1747,10 @@ dotenv@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-4.0.0.tgz#864ef1379aced55ce6f95debecdce179f7a0cd1d"
ebnf-parser@~0.1.9:
version "0.1.10"
resolved "https://registry.yarnpkg.com/ebnf-parser/-/ebnf-parser-0.1.10.tgz#cd1f6ba477c5638c40c97ed9b572db5bab5d8331"
ecc-jsbn@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505"
@ -1885,6 +1905,26 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
escodegen@0.0.21:
version "0.0.21"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-0.0.21.tgz#53d652cfa1030388279458a5266c5ffc709c63c3"
dependencies:
esprima "~1.0.2"
estraverse "~0.0.4"
optionalDependencies:
source-map ">= 0.1.2"
escodegen@^1.8.1:
version "1.9.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.0.tgz#9811a2f265dc1cd3894420ee3717064b632b8852"
dependencies:
esprima "^3.1.3"
estraverse "^4.2.0"
esutils "^2.0.2"
optionator "^0.8.1"
optionalDependencies:
source-map "~0.5.6"
escope@^3.6.0:
version "3.6.0"
resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3"
@ -1894,18 +1934,26 @@ escope@^3.6.0:
esrecurse "^4.1.0"
estraverse "^4.1.1"
esprima@1.0.x, esprima@~1.0.2:
version "1.0.4"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad"
esprima@1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.2.tgz#76a0fd66fcfe154fd292667dc264019750b1657b"
esprima@^2.6.0:
version "2.7.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581"
esprima@^3.1.3, esprima@~3.1.0:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
esprima@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
esprima@~3.1.0:
version "3.1.3"
resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
esrecurse@^4.1.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163"
@ -1913,10 +1961,14 @@ esrecurse@^4.1.0:
estraverse "^4.1.0"
object-assign "^4.0.1"
estraverse@^4.1.0, estraverse@^4.1.1:
estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
estraverse@~0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-0.0.4.tgz#01a0932dfee574684a598af5a67c3bf9b6428db2"
esutils@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
@ -2048,6 +2100,10 @@ fast-deep-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff"
fast-levenshtein@~2.0.4:
version "2.0.6"
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
fastparse@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8"
@ -2834,6 +2890,26 @@ isstream@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
jison-lex@0.2.x:
version "0.2.1"
resolved "https://registry.yarnpkg.com/jison-lex/-/jison-lex-0.2.1.tgz#ac4b815e8cce5132eb12b5dfcfe8d707b8844dfe"
dependencies:
lex-parser "0.1.x"
nomnom "1.5.2"
jison@0.4.13:
version "0.4.13"
resolved "https://registry.yarnpkg.com/jison/-/jison-0.4.13.tgz#9041707d62241367f58834532b9f19c2c36fac78"
dependencies:
JSONSelect "0.4.0"
cjson "~0.2.1"
ebnf-parser "~0.1.9"
escodegen "0.0.21"
esprima "1.0.x"
jison-lex "0.2.x"
lex-parser "~0.1.3"
nomnom "1.5.2"
js-base64@^2.1.8, js-base64@^2.1.9:
version "2.3.2"
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.3.2.tgz#a79a923666372b580f8e27f51845c6f7e8fbfbaf"
@ -2908,6 +2984,15 @@ jsonify@~0.0.0:
version "0.0.0"
resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73"
jsonpath@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/jsonpath/-/jsonpath-1.0.0.tgz#45cd9d4c4d0d6825d90bd7e40f83f1182b13dd07"
dependencies:
esprima "1.2.2"
jison "0.4.13"
static-eval "2.0.0"
underscore "1.7.0"
jsprim@^1.2.2:
version "1.4.1"
resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
@ -2949,6 +3034,17 @@ lcid@^1.0.0:
dependencies:
invert-kv "^1.0.0"
levn@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
dependencies:
prelude-ls "~1.1.2"
type-check "~0.3.2"
lex-parser@0.1.x, lex-parser@~0.1.3:
version "0.1.4"
resolved "https://registry.yarnpkg.com/lex-parser/-/lex-parser-0.1.4.tgz#64c4f025f17fd53bfb45763faeb16f015a747550"
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@ -3367,6 +3463,13 @@ node-sass@^4.5.3:
sass-graph "^2.1.1"
stdout-stream "^1.4.0"
nomnom@1.5.2:
version "1.5.2"
resolved "https://registry.yarnpkg.com/nomnom/-/nomnom-1.5.2.tgz#f4345448a853cfbd5c0d26320f2477ab0526fe2f"
dependencies:
colors "0.5.x"
underscore "1.1.x"
"nopt@2 || 3":
version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
@ -3482,6 +3585,17 @@ opn@^5.1.0:
dependencies:
is-wsl "^1.1.0"
optionator@^0.8.1:
version "0.8.2"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
dependencies:
deep-is "~0.1.3"
fast-levenshtein "~2.0.4"
levn "~0.3.0"
prelude-ls "~1.1.2"
type-check "~0.3.2"
wordwrap "~1.0.0"
original@>=0.0.5:
version "1.0.0"
resolved "https://registry.yarnpkg.com/original/-/original-1.0.0.tgz#9147f93fa1696d04be61e01bd50baeaca656bd3b"
@ -3962,6 +4076,10 @@ postcss@^6.0.1, postcss@^6.0.13, postcss@^6.0.2, postcss@^6.0.6:
source-map "^0.6.1"
supports-color "^4.4.0"
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
prepend-http@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
@ -4638,10 +4756,14 @@ source-map-url@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.3.0.tgz#7ecaf13b57bcd09da8a40c5d269db33799d4aaf9"
source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3:
source-map@0.5.x, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.3, source-map@~0.5.6:
version "0.5.7"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
"source-map@>= 0.1.2", source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
source-map@^0.1.38:
version "0.1.43"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346"
@ -4654,10 +4776,6 @@ source-map@^0.4.2:
dependencies:
amdefine ">=0.0.4"
source-map@^0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
spdx-correct@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40"
@ -4717,6 +4835,12 @@ stack-trace@0.0.9:
version "0.0.9"
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695"
static-eval@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-2.0.0.tgz#0e821f8926847def7b4b50cda5d55c04a9b13864"
dependencies:
escodegen "^1.8.1"
"statuses@>= 1.3.1 < 2", statuses@~1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e"
@ -4942,6 +5066,12 @@ twitter@^1.7.1:
deep-extend "^0.5.0"
request "^2.72.0"
type-check@~0.3.2:
version "0.3.2"
resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
dependencies:
prelude-ls "~1.1.2"
type-is@~1.6.15:
version "1.6.15"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410"
@ -4989,6 +5119,14 @@ ultron@~1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864"
underscore@1.1.x:
version "1.1.7"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.1.7.tgz#40bab84bad19d230096e8d6ef628bff055d83db0"
underscore@1.7.0:
version "1.7.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209"
uniq@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
@ -5296,6 +5434,10 @@ wordwrap@0.0.2:
version "0.0.2"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
wordwrap@~1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
wrap-ansi@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"