diff --git a/package.json b/package.json index e846a07..715fe41 100644 --- a/package.json +++ b/package.json @@ -17,6 +17,7 @@ "moment": "^2.22.2", "mongoose": "^5.2.17", "nabbit": "^0.0.2", + "sharp": "^0.21.3", "table": "^5.1.0", "vm2": "^3.6.3", "wumpfetch": "^0.0.5" diff --git a/src/_application.yml b/src/_application.yml index f19c4e4..e95ef37 100644 --- a/src/_application.yml +++ b/src/_application.yml @@ -37,8 +37,14 @@ discord : type : 1 # 0 - Playing / 1 - Streaming / 2 - Listening / 3 - Watching status: 'online' # online / idle / dnd / invisible + webhook: + token : '<--snip-->' + channel: '<--snip-->' events : ready : true + shardready : true + shardresume : true + sharddisconnect: true disconnect : true messagecreate: true messagedelete: true @@ -52,6 +58,7 @@ discord : # Category : INFORMATION stats : true guild : true + avatar : true commands : true # Category : IMAGE cat : true diff --git a/src/assets/config/colors.yml b/src/assets/config/colors.yml index 11f430e..5233d8e 100644 --- a/src/assets/config/colors.yml +++ b/src/assets/config/colors.yml @@ -15,6 +15,7 @@ util : info : stats : 0x02C2F33 # Dark but not black guild : 0x7289DA # Blurple + avatar : 0x02C2F33 # Dark but not black commands: 0x02C2F33 # Dark but not black image : diff --git a/src/assets/config/emotes.yml b/src/assets/config/emotes.yml index 37f73ec..884111f 100644 --- a/src/assets/config/emotes.yml +++ b/src/assets/config/emotes.yml @@ -1,6 +1,6 @@ -cooldown : <:sad:500719642403405824> # On cooldown -owner_only: <:sad:500719642403405824> # Only owners -guild_only: <:sad:500719642403405824> # Only guilds +cooldown : <:stopwatch:542477522147868672> # On cooldown +owner_only: <:exclamation:542368036255039509> # Only owners +guild_only: <:exclamation:542368036255039509> # Only guilds core : locale: @@ -14,6 +14,13 @@ core : 7 : <:sad:500719642403405824> # Invalid locale 8 : <:sad:500719642403405824> # Missing permissions (guild) +logs : + ready : '<:spacewump:542723940997529641>' + shard : + ready : '<:create_webhook:542716503674454016>' + resume : '<:update_webhook:542716504089690124>' + disconnect: '<:remove_webhook:542716503624253461>' + util : ping : 0 : <:bored:500719642164199425> # Pinging @@ -44,6 +51,7 @@ info: 13 : <:dnd:362670805676720128> # Total DnD members 14 : <:offline:362670805441708032> # Total offline members 15 : <:exclamation:542368036255039509> # Invalid query + avatar : <:blueberry:506201160382939141> # User's avatar commands : 0 : <:blueberry:506201160382939141> # Guild prefix 1 : <:spirit:332131321759399937> # More info diff --git a/src/assets/i18n/en_us/logs_simple.yml b/src/assets/i18n/en_us/logs_simple.yml new file mode 100644 index 0000000..8323573 --- /dev/null +++ b/src/assets/i18n/en_us/logs_simple.yml @@ -0,0 +1,6 @@ +connection: + ready : '`[$[date:now] / $[process:hash]]` $[emoji#0] Master client on Wump (`v$[wump:version]`) connected' + shard : + ready : '`[$[date:now] / $[process:hash]]` $[emoji#0] Shard `#$[shard:id]` connected to Wump (`v$[wump:version]`)' + resume : '`[$[date:now] / $[process:hash]]` $[emoji#0] Shard `#$[shard:id]` resumed to Wump (`v$[wump:version]`)' + disconnect: '`[$[date:now] / $[process:hash]]` $[emoji#0] Shard `#$[shard:id]` disconnected from Wump (`v$[wump:version]`)' \ No newline at end of file diff --git a/src/assets/i18n/en_us/strings.yml b/src/assets/i18n/en_us/strings.yml index b77ecad..d6e20ff 100644 --- a/src/assets/i18n/en_us/strings.yml +++ b/src/assets/i18n/en_us/strings.yml @@ -62,6 +62,7 @@ util : info : stats : fetching: '$[emoji#0] Fetching statistics, this may take some time...' + avatar : '$[emoji#0] Here''s **$[user:full]** avatar' commands: multi : - '$[emoji#0] The prefix for **$[guild:name]** is `$[guild:prefix]`' diff --git a/src/assets/i18n/nl/logs_simple.yml b/src/assets/i18n/nl/logs_simple.yml new file mode 100644 index 0000000..5008ced --- /dev/null +++ b/src/assets/i18n/nl/logs_simple.yml @@ -0,0 +1,6 @@ +connection: + ready : '`[$[date:now] / $[process:hash]]` $[emoji#0] Meester client op Wump (`v$[wump:version]`) is verbonden' + shard : + ready : '`[$[date:now] / $[process:hash]]` $[emoji#0] Shard `#$[shard:id]` is verbonden naar Wump (`v$[wump:version]`)' + resume : '`[$[date:now] / $[process:hash]]` $[emoji#0] Shard `#$[shard:id]` is hervat naar Wump (`v$[wump:version]`)' + disconnect: '`[$[date:now] / $[process:hash]]` $[emoji#0] Shard `#$[shard:id]` is losgekoppeld van Wump (`v$[wump:version]`)' \ No newline at end of file diff --git a/src/assets/i18n/nl/strings.yml b/src/assets/i18n/nl/strings.yml index 7021afd..4d74374 100644 --- a/src/assets/i18n/nl/strings.yml +++ b/src/assets/i18n/nl/strings.yml @@ -61,6 +61,7 @@ util : info : stats : fetching: '$[emoji#0] Statistieken aan het ophalen, dit kan enige tijd duren...' + avatar : '$[emoji#0] Hier is **$[user:full]** avatar' commands: multi : - '$[emoji#0] Het voorvoegsel voor **$[guild:name]** is `$[guild:prefix]`' diff --git a/src/assets/img/emoji/Audit logs/create_webhook.png b/src/assets/img/emoji/Audit logs/create_webhook.png new file mode 100644 index 0000000..e896a4f Binary files /dev/null and b/src/assets/img/emoji/Audit logs/create_webhook.png differ diff --git a/src/assets/img/emoji/Audit logs/remove_webhook.png b/src/assets/img/emoji/Audit logs/remove_webhook.png new file mode 100644 index 0000000..21407db Binary files /dev/null and b/src/assets/img/emoji/Audit logs/remove_webhook.png differ diff --git a/src/assets/img/emoji/Audit logs/update_webhook.png b/src/assets/img/emoji/Audit logs/update_webhook.png new file mode 100644 index 0000000..0460c88 Binary files /dev/null and b/src/assets/img/emoji/Audit logs/update_webhook.png differ diff --git a/src/assets/img/emoji/ok_hand.png b/src/assets/img/emoji/ok_hand.png new file mode 100644 index 0000000..41c20fb Binary files /dev/null and b/src/assets/img/emoji/ok_hand.png differ diff --git a/src/assets/img/logo/webhook.png b/src/assets/img/logo/webhook.png new file mode 100644 index 0000000..69dfdc6 Binary files /dev/null and b/src/assets/img/logo/webhook.png differ diff --git a/src/commands/Discord/Image/fox.js b/src/commands/Discord/Image/fox.js index 3d75d35..4a74849 100644 --- a/src/commands/Discord/Image/fox.js +++ b/src/commands/Discord/Image/fox.js @@ -2,7 +2,7 @@ const { DiscordCommand } = require('../../../core'); const w = require('wumpfetch'); -module.exports = class Cat extends DiscordCommand { +module.exports = class Fox extends DiscordCommand { constructor(bot) { super(bot, { name : 'fox', diff --git a/src/commands/Discord/Image/lizard.js b/src/commands/Discord/Image/lizard.js index ecfe714..08ba5e2 100644 --- a/src/commands/Discord/Image/lizard.js +++ b/src/commands/Discord/Image/lizard.js @@ -2,7 +2,7 @@ const { DiscordCommand } = require('../../../core'); const w = require('wumpfetch'); -module.exports = class Cat extends DiscordCommand { +module.exports = class Lizard extends DiscordCommand { constructor(bot) { super(bot, { name : 'lizard', diff --git a/src/commands/Discord/Image/penguin.js b/src/commands/Discord/Image/penguin.js index db221c0..cc3fd5e 100644 --- a/src/commands/Discord/Image/penguin.js +++ b/src/commands/Discord/Image/penguin.js @@ -2,7 +2,7 @@ const { DiscordCommand } = require('../../../core'); const w = require('wumpfetch'); -module.exports = class Cat extends DiscordCommand { +module.exports = class Penguin extends DiscordCommand { constructor(bot) { super(bot, { name : 'penguin', diff --git a/src/commands/Discord/Information/avatar.js b/src/commands/Discord/Information/avatar.js new file mode 100644 index 0000000..c61fc94 --- /dev/null +++ b/src/commands/Discord/Information/avatar.js @@ -0,0 +1,80 @@ +const { DiscordCommand } = require('../../../core'); + +const w = require('wumpfetch'); +const sizeOf = require('../../../util/sizeOf'); +const { extname } = require('path'); + +let s; +try { s = require('sharp'); } +catch (ex) { throw new Error('Sharp not found, not loading this command'); } + +module.exports = class Avatar extends DiscordCommand { + constructor(bot) { + super(bot, { + name : 'avatar', + syntax : 'avatar [...user:string] [--large] [--(nearest|linear)]', + aliases : [ 'avt', 'pfp' ], + argument : [ '[...user:string]', '[--large]', '[--(nearest|linear)]' ], + description: 'Get a user\'s avatar', + + hidden : false, + enabled : true, + cooldown : 5000, + category : 'Information', + ownerOnly : false, + guildOnly : false, + permissions: [ 'embedLinks' ] + }); + + this.regex = [/--large/i, /--(nearest|linear)/i, /--greyscale/i]; + } + + async execute(msg, args) { + const resize = + this.regex[1].test(args) && this.regex[1].exec(args)[0].toLowerCase() === '--nearest' ? 'NEAREST' : + this.regex[1].test(args) && this.regex[1].exec(args)[0].toLowerCase() === '--linear' ? 'LINEAR_A' : 'LINEAR_B'; + + const oldArgs = args; + args = args.join(' ').trim().replace(this.regex[0], '').replace(this.regex[1], '').replace(this.regex[2], '').split(' ').filter((v) => { return v !== ''; }); + let user = this.bot.REST.getUser(args[0] ? args.join(' ') : msg.author.id); + if (!user) user = this.bot.users.get(msg.author.id); + + let img, dim; + const avatarURL = (user.avatar ? user.avatarURL : user.defaultAvatarURL).split('?')[0]; + + if (this.regex[0].test(oldArgs.join(' '))) { + img = await w(avatarURL).send(); + img = img.body; + + dim = sizeOf(img); + img = await s(img) + .resize(dim.width * 2, dim.height * 2, { kernel: resize === 'LINEAR_B' ? s.kernel.linearB : resize === 'LINEAR_A' ? s.kernel.linearA : resize === 'NEAREST' ? s.kernel.nearest : s.kernel.linearA }) // { fit: 'inside' } + .toBuffer(); + if (this.regex[2].exec(args)) img = await s(img).greyscale().toBuffer(); + } else { + img = await w(avatarURL).send(); + img = img.body; + } + + if (this.regex[2].test(oldArgs)) img = await s(img).greyscale().toBuffer(); + + msg.channel.createMessage({ + embed: { + image: { url: `attachment://thumb${extname(avatarURL)}` }, + color: this.bot.col['info']['avatar'], + description: `${this.localize(msg.author.locale['info']['avatar'], { user: user })} (\`${this.regex[0].test(oldArgs.join(' ')) ? 'LARGE' : 'DEFAULT'} ${resize} ${this.regex[2].exec(oldArgs) ? 'GREYSCALE' : ''}\`)` + } + }, { + file: img, + name: `thumb${extname(avatarURL)}` + }); + } + + localize(msg, extData) { + if (!msg) return ''; + + return msg + .replace(/\$\[user:full]/g, `${extData.user.username}'${!extData.user.username.toLowerCase().endsWith('s') ? 's' : ''}`) + .replace(/\$\[emoji#0]/g, this.bot.emote('info', 'avatar')); + } +}; \ No newline at end of file diff --git a/src/commands/Discord/Information/guild.js b/src/commands/Discord/Information/guild.js index 4cff123..1b1ef60 100644 --- a/src/commands/Discord/Information/guild.js +++ b/src/commands/Discord/Information/guild.js @@ -2,7 +2,7 @@ const { DiscordCommand } = require('../../../core'); const moment = require('moment'); require('../../../util/moment/diff.js'); -module.exports = class name extends DiscordCommand { +module.exports = class Guild extends DiscordCommand { constructor(bot) { super(bot, { name : 'guild', diff --git a/src/core/clients/Discord.js b/src/core/clients/Discord.js index 66826fd..35c7040 100644 --- a/src/core/clients/Discord.js +++ b/src/core/clients/Discord.js @@ -39,11 +39,12 @@ module.exports = class WumpDiscord extends Eris { this.schema = Schema; this.Collection = Collection; - this.ua = options.ua ? options.ua : undefined; - this.pkg = options.pkg ? options.pkg : undefined; - this.col = options.colors ? options.colors : undefined; - this.ico = options.emojis ? options.emojis : undefined; - this.conf = options.config ? options.config : undefined; + this.ua = options.ua ? options.ua : undefined; + this.pkg = options.pkg ? options.pkg : undefined; + this.col = options.colors ? options.colors : undefined; + this.ico = options.emojis ? options.emojis : undefined; + this.conf = options.config ? options.config : undefined; + this.start = Date.now(); this.requestHandler.userAgent = this.ua ? this.ua : `Wump (https://github.com/PassTheWessel/wump, ${this.pkg.version})`; } diff --git a/src/core/clients/DiscordWebhook.js b/src/core/clients/DiscordWebhook.js index 373a486..bf87a44 100644 --- a/src/core/clients/DiscordWebhook.js +++ b/src/core/clients/DiscordWebhook.js @@ -1,4 +1,4 @@ -const fetch = require('wumpfetch'); +const w = require('wumpfetch'); const { randomBytes } = require('crypto'); module.exports = class DiscordWebhook { @@ -11,14 +11,16 @@ module.exports = class DiscordWebhook { (async() => { try { if (!this.extData.token || !this.extData.channel) return this.hook = undefined; - this.hook = await fetch(`${this.baseURL}/${this.extData.channel}/${this.extData.token}`, { method: 'GET' }).send(); + this.payloadURL = `${this.baseURL}/${this.extData.channel}/${this.extData.token}`; + this.hook = await w(this.payloadURL).send(); if (this.hook.statusCode !== 200) throw new SyntaxError( 'Failed to fetch webhook' ); } catch (ex) { throw ex; } })(); } - async send(data = {}) { + async send(payload = {}) { if (!this.hook) return true; - return await fetch(`${this.baseURL}/${this.extData.channel}/${this.extData.token}`, { method: 'POST', data: data }).send(); + const req = await w(this.payloadURL, { method: 'POST', data: payload, sendDataAs: 'json' }).send(); + return req; } }; \ No newline at end of file diff --git a/src/core/registry/Discord/Commands.js b/src/core/registry/Discord/Commands.js index 1586de7..659e4ed 100644 --- a/src/core/registry/Discord/Commands.js +++ b/src/core/registry/Discord/Commands.js @@ -105,6 +105,9 @@ module.exports = class CommandRegistry { cmd = this.bot.cmds.filter((v) => v.extData.name.toLowerCase() === cmd || v.extData.aliases.includes(cmd)); if (cmd.length > 0) { + if (!this.bot.cache.has('commands_ran')) this.bot.cache.set('commands_ran', 1); + else this.bot.cache.set('commands_ran', this.bot.cache.get('commands_ran') + 1); + user['entryAge'] = Date.now(); guild['entryAge'] = Date.now(); cmd = cmd[0]; @@ -141,7 +144,7 @@ module.exports = class CommandRegistry { return msg.channel.createMessage({ embed: { color : this.bot.col['cooldown'], - description: this.localize(msg.author.locale['cooldown'], { left: moment.duration(timeLeft).format('YYYY[y] M[M] DD[d] H[h] m[m] s[S] SS[ms]'), author: msg.author }) + description: this.localize(msg.author.locale['cooldown'], { left: moment.duration(timeLeft).format(`YYYY[y] M[M] DD[d] H[h] m[m] ${timeLeft > 1000 ? 's[.]SS[s]' : 's[s] SS[ms]'}`), author: msg.author }) } }); } diff --git a/src/events/Discord/ready.js b/src/events/Discord/ready.js index 076a265..fbf1f9c 100644 --- a/src/events/Discord/ready.js +++ b/src/events/Discord/ready.js @@ -1,10 +1,16 @@ const { DiscordEvent } = require('../../core'); +const moment = require('moment'); +const { safeLoad } = require('js-yaml'); const { green, cyan } = require('../../util/colors'); +const { join: pJoin } = require('path'); +const { readFileSync } = require('fs'); module.exports = class Ready extends DiscordEvent { constructor(bot) { super(bot, { name: 'ready' }); + + this.strings = safeLoad(readFileSync(pJoin(__dirname, '..', '..', 'assets', 'i18n', bot.conf['discord']['locale'], 'logs_simple.yml'), { encoding: 'utf8' })); } emit() { @@ -19,14 +25,26 @@ module.exports = class Ready extends DiscordEvent { }); } + this.bot.hook.send({ content: this.localize(this.strings['connection']['ready']) }); + // Cache flushing if entry isn't used within `flushTime` minutes const flushTime = 1800000; setInterval(() => { const uCache = this.bot.cache.get('users') || []; + const gCache = this.bot.cache.get('guilds') || []; - uCache.forEach((v, _) => (new Date(v.entryAge) <= new Date(new Date() - flushTime)) ? uCache.splice(_, 1) : undefined); gCache.forEach((v, _) => (new Date(v.entryAge) <= new Date(new Date() - flushTime)) ? gCache.splice(_, 1) : undefined); }, flushTime); } -}; \ No newline at end of file + + localize(msg) { + if (!msg) return ''; + return msg + .replace(/\$\[wump:version]/g, `${this.bot.pkg.version} ${this.bot.conf['nightly'] ? 'NIGHTLY' : 'DISTRIBUTIONs'}`) + .replace(/\$\[process:hash]/g, process.hash) + .replace(/\$\[date:now]/g, moment(Date.now()).format('HH[:]mm[:]ss')) + .replace(/\$\[emoji#0]/g, this.bot.emote('logs', 'ready')); + } +}; +// YYYY[y] M[M] DD[d] H[h] m[m] ${startTime > 1000 ? 's[.]SS[s]' : 's[s] SS[ms]'} \ No newline at end of file diff --git a/src/events/Discord/shardDisconnect.js b/src/events/Discord/shardDisconnect.js new file mode 100644 index 0000000..fda8bdf --- /dev/null +++ b/src/events/Discord/shardDisconnect.js @@ -0,0 +1,28 @@ +const { DiscordEvent } = require('../../core'); + +const moment = require('moment'); +const { safeLoad } = require('js-yaml'); +const { join: pJoin } = require('path'); +const { readFileSync } = require('fs'); + +module.exports = class shardDisconnect extends DiscordEvent { + constructor(bot) { + super(bot, { name: 'shardDisconnect' }); + + this.strings = safeLoad(readFileSync(pJoin(__dirname, '..', '..', 'assets', 'i18n', bot.conf['discord']['locale'], 'logs_simple.yml'), { encoding: 'utf8' })); + } + + emit(err, id) { + this.bot.hook.send({ content: this.localize(this.strings['connection']['shard']['disconnect'], { shard: id }) }); + } + + localize(msg, extData) { + if (!msg) return ''; + return msg + .replace(/\$\[shard:id]/g, extData.shard) + .replace(/\$\[wump:version]/g, `${this.bot.pkg.version} ${this.bot.conf['nightly'] ? 'NIGHTLY' : 'DISTRIBUTION'}`) + .replace(/\$\[process:hash]/g, process.hash) + .replace(/\$\[date:now]/g, moment(Date.now()).format('HH[:]mm[:]ss')) + .replace(/\$\[emoji#0]/g, this.bot.emote('logs', 'shard', 'disconnect')); + } +}; \ No newline at end of file diff --git a/src/events/Discord/shardReady.js b/src/events/Discord/shardReady.js new file mode 100644 index 0000000..8deff7f --- /dev/null +++ b/src/events/Discord/shardReady.js @@ -0,0 +1,28 @@ +const { DiscordEvent } = require('../../core'); + +const moment = require('moment'); +const { safeLoad } = require('js-yaml'); +const { join: pJoin } = require('path'); +const { readFileSync } = require('fs'); + +module.exports = class ShardReady extends DiscordEvent { + constructor(bot) { + super(bot, { name: 'shardReady' }); + + this.strings = safeLoad(readFileSync(pJoin(__dirname, '..', '..', 'assets', 'i18n', bot.conf['discord']['locale'], 'logs_simple.yml'), { encoding: 'utf8' })); + } + + emit(id) { + this.bot.hook.send({ content: this.localize(this.strings['connection']['shard']['ready'], { shard: id }) }); + } + + localize(msg, extData) { + if (!msg) return ''; + return msg + .replace(/\$\[shard:id]/g, extData.shard) + .replace(/\$\[wump:version]/g, `${this.bot.pkg.version} ${this.bot.conf['nightly'] ? 'NIGHTLY' : 'DISTRIBUTION'}`) + .replace(/\$\[process:hash]/g, process.hash) + .replace(/\$\[date:now]/g, moment(Date.now()).format('HH[:]mm[:]ss')) + .replace(/\$\[emoji#0]/g, this.bot.emote('logs', 'shard', 'ready')); + } +}; \ No newline at end of file diff --git a/src/events/Discord/shardResume.js b/src/events/Discord/shardResume.js new file mode 100644 index 0000000..dbd3e72 --- /dev/null +++ b/src/events/Discord/shardResume.js @@ -0,0 +1,28 @@ +const { DiscordEvent } = require('../../core'); + +const moment = require('moment'); +const { safeLoad } = require('js-yaml'); +const { join: pJoin } = require('path'); +const { readFileSync } = require('fs'); + +module.exports = class ShardResume extends DiscordEvent { + constructor(bot) { + super(bot, { name: 'shardResume' }); + + this.strings = safeLoad(readFileSync(pJoin(__dirname, '..', '..', 'assets', 'i18n', bot.conf['discord']['locale'], 'logs_simple.yml'), { encoding: 'utf8' })); + } + + emit(id) { + this.bot.hook.send({ content: this.localize(this.strings['connection']['shard']['resume'], { shard: id }) }); + } + + localize(msg, extData) { + if (!msg) return ''; + return msg + .replace(/\$\[shard:id]/g, extData.shard) + .replace(/\$\[wump:version]/g, `${this.bot.pkg.version} ${this.bot.conf['nightly'] ? 'NIGHTLY' : 'DISTRIBUTION'}`) + .replace(/\$\[process:hash]/g, process.hash) + .replace(/\$\[date:now]/g, moment(Date.now()).format('HH[:]mm[:]ss')) + .replace(/\$\[emoji#0]/g, this.bot.emote('logs', 'shard', 'resume')); + } +}; \ No newline at end of file diff --git a/src/main.js b/src/main.js index 3c7f2c4..216021d 100644 --- a/src/main.js +++ b/src/main.js @@ -22,7 +22,7 @@ globalize(); let Discord, Database; process.argv = require('larg')(process.argv.slice(2)); -process.hash = String.string(Math.floor(Math.random() * 5) + 3); +process.hash = String.string(8); process.handleError = (err, name, type, exit = false, custom = false) => { if (!custom) print(0, `${type ? type : green('Master')} !! ${name ? name : err.name ? err.name : 'Error'} -\n${red(`${err.message && err.stack ? `${err.message}\n${err.stack}` : err}`)}`); @@ -71,10 +71,14 @@ process.on('SIGINT', () => { print(2, `${yellow('Database')} >> ${green('Connected to database')}` ); })(); - if (conf['discord']['enabled']) { print(2, `${cyan('Discord')} >> Creating client...`); Discord = new DiscordClient(conf['discord']['token'], { + webhook :{ + token : conf['discord']['webhook']['token'] || undefined, + channel: conf['discord']['webhook']['channel'] || undefined + }, + clientOptions : { maxShards : 'auto', getAllUsers : false, diff --git a/src/util/sizeOf/detector.js b/src/util/sizeOf/detector.js new file mode 100644 index 0000000..5dd36b4 --- /dev/null +++ b/src/util/sizeOf/detector.js @@ -0,0 +1,13 @@ +'use strict'; + +var typeHandlers = require('./types'); + +module.exports = function (buffer, filepath) { + var type, result; + for (type in typeHandlers) { + result = typeHandlers[type].detect(buffer, filepath); + if (result) { + return type; + } + } +}; diff --git a/src/util/sizeOf/index.js b/src/util/sizeOf/index.js new file mode 100644 index 0000000..22dc8c2 --- /dev/null +++ b/src/util/sizeOf/index.js @@ -0,0 +1,126 @@ +'use strict'; + +var fs = require('fs'); +var path = require('path'); + +var typeHandlers = require('./types'); +var detector = require('./detector'); + +// Maximum buffer size, with a default of 512 kilobytes. +// TO-DO: make this adaptive based on the initial signature of the image +var MaxBufferSize = 512*1024; + +/** + * Return size information based on a buffer + * + * @param {Buffer} buffer + * @param {String} filepath + * @returns {Object} + */ +function lookup (buffer, filepath) { + // detect the file type.. don't rely on the extension + var type = detector(buffer, filepath); + + // find an appropriate handler for this file type + if (type in typeHandlers) { + var size = typeHandlers[type].calculate(buffer, filepath); + if (size !== false) { + size.type = type; + return size; + } + } + + // throw up, if we don't understand the file + throw new TypeError('unsupported file type: ' + type + ' (file: ' + filepath + ')'); +} + +/** + * Reads a file into a buffer. + * + * The callback will be called after the process has completed. The + * callback's first argument will be an error (or null). The second argument + * will be the Buffer, if the operation was successful. + * + * @param {String} filepath + * @param {Function} callback + */ +function asyncFileToBuffer (filepath, callback) { + // open the file in read only mode + fs.open(filepath, 'r', function (err, descriptor) { + if (err) { return callback(err); } + fs.fstat(descriptor, function (err, stats) { + if (err) { return callback(err); } + var size = stats.size; + if (size <= 0) { + return callback(new Error('File size is not greater than 0 —— ' + filepath)); + } + var bufferSize = Math.min(size, MaxBufferSize); + var buffer = Buffer.alloc(bufferSize); + // read first buffer block from the file, asynchronously + fs.read(descriptor, buffer, 0, bufferSize, 0, function (err) { + if (err) { return callback(err); } + // close the file, we are done + fs.close(descriptor, function (err) { + callback(err, buffer); + }); + }); + }); + }); +} + +/** + * Synchronously reads a file into a buffer, blocking the nodejs process. + * + * @param {String} filepath + * @returns {Buffer} + */ +function syncFileToBuffer (filepath) { + // read from the file, synchronously + var descriptor = fs.openSync(filepath, 'r'); + var size = fs.fstatSync(descriptor).size; + var bufferSize = Math.min(size, MaxBufferSize); + var buffer = Buffer.alloc(bufferSize); + fs.readSync(descriptor, buffer, 0, bufferSize, 0); + fs.closeSync(descriptor); + return buffer; +} + +/** + * @param {Buffer|string} input - buffer or relative/absolute path of the image file + * @param {Function} callback - optional function for async detection + */ +module.exports = function (input, callback) { + + // Handle buffer input + if (Buffer.isBuffer(input)) { + return lookup(input); + } + + // input should be a string at this point + if (typeof input !== 'string') { + throw new TypeError('invalid invocation'); + } + + // resolve the file path + var filepath = path.resolve(input); + + if (typeof callback === 'function') { + asyncFileToBuffer(filepath, function (err, buffer) { + if (err) { return callback(err); } + + // return the dimensions + var dimensions; + try { + dimensions = lookup(buffer, filepath); + } catch (e) { + err = e; + } + callback(err, dimensions); + }); + } else { + var buffer = syncFileToBuffer(filepath); + return lookup(buffer, filepath); + } +}; + +module.exports.types = Object.keys(typeHandlers); diff --git a/src/util/sizeOf/readUInt.js b/src/util/sizeOf/readUInt.js new file mode 100644 index 0000000..9bceff4 --- /dev/null +++ b/src/util/sizeOf/readUInt.js @@ -0,0 +1,11 @@ +'use strict'; + +// Abstract reading multi-byte unsigned integers +function readUInt (buffer, bits, offset, isBigEndian) { + offset = offset || 0; + var endian = isBigEndian ? 'BE' : 'LE'; + var method = buffer['readUInt' + bits + endian]; + return method.call(buffer, offset); +} + +module.exports = readUInt; diff --git a/src/util/sizeOf/types.js b/src/util/sizeOf/types.js new file mode 100644 index 0000000..b27da76 --- /dev/null +++ b/src/util/sizeOf/types.js @@ -0,0 +1,19 @@ +'use strict'; + +// load all available handlers for browserify support +var typeHandlers = { + bmp: require('./types/bmp'), + cur: require('./types/cur'), + dds: require('./types/dds'), + gif: require('./types/gif'), + icns: require('./types/icns'), + ico: require('./types/ico'), + jpg: require('./types/jpg'), + png: require('./types/png'), + psd: require('./types/psd'), + svg: require('./types/svg'), + tiff: require('./types/tiff'), + webp: require('./types/webp'), +}; + +module.exports = typeHandlers; diff --git a/src/util/sizeOf/types/bmp.js b/src/util/sizeOf/types/bmp.js new file mode 100644 index 0000000..ada0141 --- /dev/null +++ b/src/util/sizeOf/types/bmp.js @@ -0,0 +1,17 @@ +'use strict'; + +function isBMP (buffer) { + return ('BM' === buffer.toString('ascii', 0, 2)); +} + +function calculate (buffer) { + return { + 'width': buffer.readUInt32LE(18), + 'height': Math.abs(buffer.readInt32LE(22)) + }; +} + +module.exports = { + 'detect': isBMP, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/cur.js b/src/util/sizeOf/types/cur.js new file mode 100644 index 0000000..c4449b9 --- /dev/null +++ b/src/util/sizeOf/types/cur.js @@ -0,0 +1,17 @@ +'use strict'; + +var TYPE_CURSOR = 2; + +function isCUR (buffer) { + var type; + if (buffer.readUInt16LE(0) !== 0) { + return false; + } + type = buffer.readUInt16LE(2); + return type === TYPE_CURSOR; +} + +module.exports = { + 'detect': isCUR, + 'calculate': require('./ico').calculate +}; diff --git a/src/util/sizeOf/types/dds.js b/src/util/sizeOf/types/dds.js new file mode 100644 index 0000000..ae46447 --- /dev/null +++ b/src/util/sizeOf/types/dds.js @@ -0,0 +1,18 @@ +'use strict'; + +function isDDS(buffer){ + return buffer.readUInt32LE(0) === 0x20534444; +} + +function calculate(buffer){ + // read file resolution metadata + return { + 'height': buffer.readUInt32LE(12), + 'width': buffer.readUInt32LE(16) + }; +} + +module.exports = { + 'detect': isDDS, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/gif.js b/src/util/sizeOf/types/gif.js new file mode 100644 index 0000000..b497079 --- /dev/null +++ b/src/util/sizeOf/types/gif.js @@ -0,0 +1,19 @@ +'use strict'; + +var gifRegexp = /^GIF8[79]a/; +function isGIF (buffer) { + var signature = buffer.toString('ascii', 0, 6); + return (gifRegexp.test(signature)); +} + +function calculate(buffer) { + return { + 'width': buffer.readUInt16LE(6), + 'height': buffer.readUInt16LE(8) + }; +} + +module.exports = { + 'detect': isGIF, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/icns.js b/src/util/sizeOf/types/icns.js new file mode 100644 index 0000000..199b0e6 --- /dev/null +++ b/src/util/sizeOf/types/icns.js @@ -0,0 +1,122 @@ +'use strict'; + +/** + * ICNS Header + * + * | Offset | Size | Purpose | + * | 0 | 4 | Magic literal, must be "icns" (0x69, 0x63, 0x6e, 0x73) | + * | 4 | 4 | Length of file, in bytes, msb first. | + * + **/ +var SIZE_HEADER = 4 + 4; // 8 +var FILE_LENGTH_OFFSET = 4; // MSB => BIG ENDIAN + +/** + * Image Entry + * + * | Offset | Size | Purpose | + * | 0 | 4 | Icon type, see OSType below. | + * | 4 | 4 | Length of data, in bytes (including type and length), msb first. | + * | 8 | n | Icon data | + * + **/ +var ENTRY_LENGTH_OFFSET = 4; // MSB => BIG ENDIAN + +function isICNS (buffer) { + return ('icns' === buffer.toString('ascii', 0, 4)); +} + +var ICON_TYPE_SIZE = { + ICON: 32, + 'ICN#': 32, + // m => 16 x 16 + 'icm#': 16, + icm4: 16, + icm8: 16, + // s => 16 x 16 + 'ics#': 16, + ics4: 16, + ics8: 16, + is32: 16, + s8mk: 16, + icp4: 16, + // l => 32 x 32 + icl4: 32, + icl8: 32, + il32: 32, + l8mk: 32, + icp5: 32, + ic11: 32, + // h => 48 x 48 + ich4: 48, + ich8: 48, + ih32: 48, + h8mk: 48, + // . => 64 x 64 + icp6: 64, + ic12: 32, + // t => 128 x 128 + it32: 128, + t8mk: 128, + ic07: 128, + // . => 256 x 256 + ic08: 256, + ic13: 256, + // . => 512 x 512 + ic09: 512, + ic14: 512, + // . => 1024 x 1024 + ic10: 1024, +}; + +function readImageHeader(buffer, imageOffset) { + var imageLengthOffset = imageOffset + ENTRY_LENGTH_OFFSET; + // returns [type, length] + return [ + buffer.toString('ascii', imageOffset, imageLengthOffset), + buffer.readUInt32BE(imageLengthOffset) + ]; +} + +function getImageSize(type) { + var size = ICON_TYPE_SIZE[type]; + return { width: size, height: size, type: type }; +} + +function calculate (buffer) { + var + bufferLength = buffer.length, + imageOffset = SIZE_HEADER, + fileLength = buffer.readUInt32BE(FILE_LENGTH_OFFSET), + imageHeader, + imageSize, + result; + + imageHeader = readImageHeader(buffer, imageOffset); + imageSize = getImageSize(imageHeader[0]); + imageOffset += imageHeader[1]; + + if (imageOffset === fileLength) { + return imageSize; + } + + result = { + width: imageSize.width, + height: imageSize.height, + images: [imageSize] + }; + + while (imageOffset < fileLength && imageOffset < bufferLength) { + imageHeader = readImageHeader(buffer, imageOffset); + imageSize = getImageSize(imageHeader[0]); + imageOffset += imageHeader[1]; + result.images.push(imageSize); + } + + return result; +} + +module.exports = { + 'detect': isICNS, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/ico.js b/src/util/sizeOf/types/ico.js new file mode 100644 index 0000000..5a87cc7 --- /dev/null +++ b/src/util/sizeOf/types/ico.js @@ -0,0 +1,81 @@ +'use strict'; + +var TYPE_ICON = 1; + +/** + * ICON Header + * + * | Offset | Size | Purpose | + * | 0 | 2 | Reserved. Must always be 0. | + * | 2 | 2 | Image type: 1 for icon (.ICO) image, 2 for cursor (.CUR) image. Other values are invalid. | + * | 4 | 2 | Number of images in the file. | + * + **/ +var SIZE_HEADER = 2 + 2 + 2; // 6 + +/** + * Image Entry + * + * | Offset | Size | Purpose | + * | 0 | 1 | Image width in pixels. Can be any number between 0 and 255. Value 0 means width is 256 pixels. | + * | 1 | 1 | Image height in pixels. Can be any number between 0 and 255. Value 0 means height is 256 pixels. | + * | 2 | 1 | Number of colors in the color palette. Should be 0 if the image does not use a color palette. | + * | 3 | 1 | Reserved. Should be 0. | + * | 4 | 2 | ICO format: Color planes. Should be 0 or 1. | + * | | | CUR format: The horizontal coordinates of the hotspot in number of pixels from the left. | + * | 6 | 2 | ICO format: Bits per pixel. | + * | | | CUR format: The vertical coordinates of the hotspot in number of pixels from the top. | + * | 8 | 4 | The size of the image's data in bytes | + * | 12 | 4 | The offset of BMP or PNG data from the beginning of the ICO/CUR file | + * + **/ +var SIZE_IMAGE_ENTRY = 1 + 1 + 1 + 1 + 2 + 2 + 4 + 4; // 16 + +function isICO (buffer) { + var type; + if (buffer.readUInt16LE(0) !== 0) { + return false; + } + type = buffer.readUInt16LE(2); + return type === TYPE_ICON; +} + +function getSizeFromOffset(buffer, offset) { + var value = buffer.readUInt8(offset); + return value === 0 ? 256 : value; +} + +function getImageSize(buffer, imageIndex) { + var offset = SIZE_HEADER + (imageIndex * SIZE_IMAGE_ENTRY); + return { + 'width': getSizeFromOffset(buffer, offset), + 'height': getSizeFromOffset(buffer, offset + 1) + }; +} + +function calculate (buffer) { + var + nbImages = buffer.readUInt16LE(4), + result = getImageSize(buffer, 0), + imageIndex; + + if (nbImages === 1) { + return result; + } + + result.images = [{ + width: result.width, + height: result.height + }]; + + for (imageIndex = 1; imageIndex < nbImages; imageIndex += 1) { + result.images.push(getImageSize(buffer, imageIndex)); + } + + return result; +} + +module.exports = { + 'detect': isICO, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/jpg.js b/src/util/sizeOf/types/jpg.js new file mode 100644 index 0000000..68a2270 --- /dev/null +++ b/src/util/sizeOf/types/jpg.js @@ -0,0 +1,145 @@ +'use strict'; + +// NOTE: we only support baseline and progressive JPGs here +// due to the structure of the loader class, we only get a buffer +// with a maximum size of 4096 bytes. so if the SOF marker is outside +// if this range we can't detect the file size correctly. + +function isJPG (buffer) { //, filepath + var SOIMarker = buffer.toString('hex', 0, 2); + return ('ffd8' === SOIMarker); +} + +function isEXIF (buffer) { //, filepath + var exifMarker = buffer.toString('hex', 2, 6); + return (exifMarker === '45786966'); // 'Exif' +} + +function extractSize (buffer, i) { + return { + 'height' : buffer.readUInt16BE(i), + 'width' : buffer.readUInt16BE(i + 2) + }; +} + +var APP1_DATA_SIZE_BYTES = 2; +var EXIF_HEADER_BYTES = 6; +var TIFF_BYTE_ALIGN_BYTES = 2; +var MOTOROLA_BYTE_ALIGN = '4d4d'; + +// Each entry is exactly 12 bytes +var IDF_ENTRY_BYTES = 12; +var NUM_DIRECTORY_ENTRIES_BYTES = 2; + +function extractOrientation (buffer, i) { + // Skip APP1 Data Size + var exifBlock = buffer.slice(APP1_DATA_SIZE_BYTES, i); + + // TODO: support intel byte alignment + var byteAlign = exifBlock.toString('hex', EXIF_HEADER_BYTES, EXIF_HEADER_BYTES + TIFF_BYTE_ALIGN_BYTES); + if (byteAlign !== MOTOROLA_BYTE_ALIGN) { + return; + } + + // TODO: assert that this contains 0x002A + // var STATIC_MOTOROLA_TIFF_HEADER_BYTES = 2; + // var TIFF_IMAGE_FILE_DIRECTORY_BYTES = 4; + + // TODO: derive from TIFF_IMAGE_FILE_DIRECTORY_BYTES + var idfOffset = 8; + + // IDF osset works from right after the header bytes + // (so the offset includes the tiff byte align) + var offset = EXIF_HEADER_BYTES + idfOffset; + + var idfDirectoryEntries = exifBlock.readUInt16BE(offset); + + var start; + var end; + for (var directoryEntryNumber = 0; directoryEntryNumber < idfDirectoryEntries; directoryEntryNumber++) { + start = offset + NUM_DIRECTORY_ENTRIES_BYTES + (directoryEntryNumber * IDF_ENTRY_BYTES); + end = start + IDF_ENTRY_BYTES; + + var block = exifBlock.slice(start, end); + var tagNumber = block.readUInt16BE(0); + + // 0x0112 (decimal: 274) is the `orientation` tag ID + if (tagNumber === 274) { + var dataFormat = block.readUInt16BE(2); + if (dataFormat !== 3) { + return; + } + + // unsinged int has 2 bytes per component + // if there would more than 4 bytes in total it's a pointer + var numberOfComponents = block.readUInt32BE(4); + if (numberOfComponents !== 1) { + return; + } + + var orientation = block.readUInt16BE(8); + + return orientation; + } + } +} + +function validateBuffer (buffer, i) { + // index should be within buffer limits + if (i > buffer.length) { + throw new TypeError('Corrupt JPG, exceeded buffer limits'); + } + // Every JPEG block must begin with a 0xFF + if (buffer[i] !== 0xFF) { + throw new TypeError('Invalid JPG, marker table corrupted'); + } +} + +function calculate (buffer) { + // Skip 4 chars, they are for signature + buffer = buffer.slice(4); + + var orientation; + + var i, next; + while (buffer.length) { + // read length of the next block + i = buffer.readUInt16BE(0); + + + if (isEXIF(buffer)) { + orientation = extractOrientation(buffer, i); + } + + // ensure correct format + validateBuffer(buffer, i); + + // 0xFFC0 is baseline standard(SOF) + // 0xFFC1 is baseline optimized(SOF) + // 0xFFC2 is progressive(SOF2) + next = buffer[i + 1]; + if (next === 0xC0 || next === 0xC1 || next === 0xC2) { + var size = extractSize(buffer, i + 5); + + if (!orientation) { + return size; + } + + return { + width: size.width, + height: size.height, + orientation: orientation + }; + } + + // move to the next block + buffer = buffer.slice(i + 2); + } + + throw new TypeError('Invalid JPG, no size found'); +} + +module.exports = { + 'detect': isJPG, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/png.js b/src/util/sizeOf/types/png.js new file mode 100644 index 0000000..78b9535 --- /dev/null +++ b/src/util/sizeOf/types/png.js @@ -0,0 +1,38 @@ +'use strict'; + +var pngSignature = 'PNG\r\n\x1a\n'; +var pngImageHeaderChunkName = 'IHDR'; + +// Used to detect "fried" png's: http://www.jongware.com/pngdefry.html +var pngFriedChunkName = 'CgBI'; + +function isPNG (buffer) { + if (pngSignature === buffer.toString('ascii', 1, 8)) { + var chunkName = buffer.toString('ascii', 12, 16); + if (chunkName === pngFriedChunkName) { + chunkName = buffer.toString('ascii', 28, 32); + } + if (chunkName !== pngImageHeaderChunkName) { + throw new TypeError('invalid png'); + } + return true; + } +} + +function calculate (buffer) { + if (buffer.toString('ascii', 12, 16) === pngFriedChunkName) { + return { + 'width': buffer.readUInt32BE(32), + 'height': buffer.readUInt32BE(36) + }; + } + return { + 'width': buffer.readUInt32BE(16), + 'height': buffer.readUInt32BE(20) + }; +} + +module.exports = { + 'detect': isPNG, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/psd.js b/src/util/sizeOf/types/psd.js new file mode 100644 index 0000000..dec4304 --- /dev/null +++ b/src/util/sizeOf/types/psd.js @@ -0,0 +1,17 @@ +'use strict'; + +function isPSD (buffer) { + return ('8BPS' === buffer.toString('ascii', 0, 4)); +} + +function calculate (buffer) { + return { + 'width': buffer.readUInt32BE(18), + 'height': buffer.readUInt32BE(14) + }; +} + +module.exports = { + 'detect': isPSD, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/svg.js b/src/util/sizeOf/types/svg.js new file mode 100644 index 0000000..1b821f2 --- /dev/null +++ b/src/util/sizeOf/types/svg.js @@ -0,0 +1,78 @@ +'use strict'; + +var svgReg = /"']|"[^"]*"|'[^']*')*>/; +function isSVG (buffer) { + return svgReg.test(buffer); +} + +var extractorRegExps = { + 'root': svgReg, + 'width': /\bwidth=(['"])([^%]+?)\1/, + 'height': /\bheight=(['"])([^%]+?)\1/, + 'viewbox': /\bviewBox=(['"])(.+?)\1/ +}; + +function parseViewbox (viewbox) { + var bounds = viewbox.split(' '); + return { + 'width': parseInt(bounds[2], 10), + 'height': parseInt(bounds[3], 10) + }; +} + +function parseAttributes (root) { + var width = root.match(extractorRegExps.width); + var height = root.match(extractorRegExps.height); + var viewbox = root.match(extractorRegExps.viewbox); + return { + 'width': width && parseInt(width[2], 10), + 'height': height && parseInt(height[2], 10), + 'viewbox': viewbox && parseViewbox(viewbox[2]) + }; +} + +function calculateByDimensions (attrs) { + return { + 'width': attrs.width, + 'height': attrs.height + }; +} + +function calculateByViewbox (attrs) { + var ratio = attrs.viewbox.width / attrs.viewbox.height; + if (attrs.width) { + return { + 'width': attrs.width, + 'height': Math.floor(attrs.width / ratio) + }; + } + if (attrs.height) { + return { + 'width': Math.floor(attrs.height * ratio), + 'height': attrs.height + }; + } + return { + 'width': attrs.viewbox.width, + 'height': attrs.viewbox.height + }; +} + +function calculate (buffer) { + var root = buffer.toString('utf8').match(extractorRegExps.root); + if (root) { + var attrs = parseAttributes(root[0]); + if (attrs.width && attrs.height) { + return calculateByDimensions(attrs); + } + if (attrs.viewbox) { + return calculateByViewbox(attrs); + } + } + throw new TypeError('invalid svg'); +} + +module.exports = { + 'detect': isSVG, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/tiff.js b/src/util/sizeOf/types/tiff.js new file mode 100644 index 0000000..6f50c61 --- /dev/null +++ b/src/util/sizeOf/types/tiff.js @@ -0,0 +1,120 @@ +'use strict'; + +// based on http://www.compix.com/fileformattif.htm +// TO-DO: support big-endian as well + +var fs = require('fs'); +var readUInt = require('../readUInt'); + +function isTIFF (buffer) { + var hex4 = buffer.toString('hex', 0, 4); + return ('49492a00' === hex4 || '4d4d002a' === hex4); +} + +// Read IFD (image-file-directory) into a buffer +function readIFD (buffer, filepath, isBigEndian) { + + var ifdOffset = readUInt(buffer, 32, 4, isBigEndian); + + // read only till the end of the file + var bufferSize = 1024; + var fileSize = fs.statSync(filepath).size; + if (ifdOffset + bufferSize > fileSize) { + bufferSize = fileSize - ifdOffset - 10; + } + + // populate the buffer + var endBuffer = Buffer.alloc(bufferSize); + var descriptor = fs.openSync(filepath, 'r'); + fs.readSync(descriptor, endBuffer, 0, bufferSize, ifdOffset); + + // var ifdLength = readUInt(endBuffer, 16, 0, isBigEndian); + var ifdBuffer = endBuffer.slice(2); //, 2 + 12 * ifdLength); + return ifdBuffer; +} + +// TIFF values seem to be messed up on Big-Endian, this helps +function readValue (buffer, isBigEndian) { + var low = readUInt(buffer, 16, 8, isBigEndian); + var high = readUInt(buffer, 16, 10, isBigEndian); + return (high << 16) + low; +} + +// move to the next tag +function nextTag (buffer) { + if (buffer.length > 24) { + return buffer.slice(12); + } +} + +// Extract IFD tags from TIFF metadata +/* eslint-disable complexity */ +function extractTags (buffer, isBigEndian) { + var tags = {}; + var code, type, length; + + while (buffer && buffer.length) { + code = readUInt(buffer, 16, 0, isBigEndian); + type = readUInt(buffer, 16, 2, isBigEndian); + length = readUInt(buffer, 32, 4, isBigEndian); + + // 0 means end of IFD + if (code === 0) { + break; + } else { + // 256 is width, 257 is height + // if (code === 256 || code === 257) { + if (length === 1 && (type === 3 || type === 4)) { + tags[code] = readValue(buffer, isBigEndian); + } + + // move to the next tag + buffer = nextTag(buffer); + } + } + return tags; +} +/* eslint-enable complexity */ + +// Test if the TIFF is Big Endian or Little Endian +function determineEndianness (buffer) { + var signature = buffer.toString('ascii', 0, 2); + if ('II' === signature) { + return 'LE'; + } else if ('MM' === signature) { + return 'BE'; + } +} + +function calculate (buffer, filepath) { + + if (!filepath) { + throw new TypeError('Tiff doesn\'t support buffer'); + } + + // Determine BE/LE + var isBigEndian = determineEndianness(buffer) === 'BE'; + + // read the IFD + var ifdBuffer = readIFD(buffer, filepath, isBigEndian); + + // extract the tags from the IFD + var tags = extractTags(ifdBuffer, isBigEndian); + + var width = tags[256]; + var height = tags[257]; + + if (!width || !height) { + throw new TypeError('Invalid Tiff, missing tags'); + } + + return { + 'width': width, + 'height': height + }; +} + +module.exports = { + 'detect': isTIFF, + 'calculate': calculate +}; diff --git a/src/util/sizeOf/types/webp.js b/src/util/sizeOf/types/webp.js new file mode 100644 index 0000000..9f35c69 --- /dev/null +++ b/src/util/sizeOf/types/webp.js @@ -0,0 +1,71 @@ +'use strict'; + +// based on https://developers.google.com/speed/webp/docs/riff_container + +function isWebP (buffer) { + var riffHeader = 'RIFF' === buffer.toString('ascii', 0, 4); + var webpHeader = 'WEBP' === buffer.toString('ascii', 8, 12); + var vp8Header = 'VP8' === buffer.toString('ascii', 12, 15); + return (riffHeader && webpHeader && vp8Header); +} + +/* eslint-disable complexity */ +function calculate (buffer) { + var chunkHeader = buffer.toString('ascii', 12, 16); + buffer = buffer.slice(20, 30); + + // Extended webp stream signature + if (chunkHeader === 'VP8X') { + var extendedHeader = buffer[0]; + var validStart = (extendedHeader & 0xc0) === 0; + var validEnd = (extendedHeader & 0x01) === 0; + if (validStart && validEnd) { + return calculateExtended(buffer); + } else { + return false; + } + } + + // Lossless webp stream signature + if (chunkHeader === 'VP8 ' && buffer[0] !== 0x2f) { + return calculateLossy(buffer); + } + + // Lossy webp stream signature + var signature = buffer.toString('hex', 3, 6); + if (chunkHeader === 'VP8L' && signature !== '9d012a') { + return calculateLossless(buffer); + } + + return false; +} +/* eslint-enable complexity */ + +function calculateExtended (buffer) { + return { + 'width': 1 + buffer.readUIntLE(4, 3), + 'height': 1 + buffer.readUIntLE(7, 3) + }; +} + +function calculateLossless (buffer) { + return { + 'width': 1 + (((buffer[2] & 0x3F) << 8) | buffer[1]), + 'height': 1 + (((buffer[4] & 0xF) << 10) | (buffer[3] << 2) | + ((buffer[2] & 0xC0) >> 6)) + }; +} + +function calculateLossy (buffer) { + // `& 0x3fff` returns the last 14 bits + // TO-DO: include webp scaling in the calculations + return { + 'width': buffer.readInt16LE(6) & 0x3fff, + 'height': buffer.readInt16LE(8) & 0x3fff + }; +} + +module.exports = { + 'detect': isWebP, + 'calculate': calculate +}; diff --git a/yarn.lock b/yarn.lock index 3ce583c..7751c56 100644 --- a/yarn.lock +++ b/yarn.lock @@ -43,6 +43,11 @@ ansi-escapes@^3.2.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= + ansi-regex@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" @@ -60,6 +65,19 @@ ansi-styles@^3.2.0, ansi-styles@^3.2.1: dependencies: color-convert "^1.9.0" +aproba@^1.0.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== + +are-we-there-yet@~1.1.2: + version "1.1.5" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + argparse@^1.0.7: version "1.0.10" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" @@ -89,6 +107,21 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= +bindings@^1.3.1: + version "1.4.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.4.0.tgz#909efa49f2ebe07ecd3cb136778f665052040127" + integrity sha512-7znEVX22Djn+nYjxCWKDne0RRloa9XfYa84yk3s+HkE3LpDYZmhArYr9O9huBoHY3/oXispx5LorIX7Sl2CgSQ== + dependencies: + file-uri-to-path "1.0.0" + +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + bluebird@3.5.1: version "3.5.1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" @@ -107,6 +140,24 @@ bson@^1.1.0, bson@~1.1.0: resolved "https://registry.yarnpkg.com/bson/-/bson-1.1.0.tgz#bee57d1fb6a87713471af4e32bcae36de814b5b0" integrity sha512-9Aeai9TacfNtWXOYarkFJRW2CWo+dRon+fuLZYJmvLV3+MiUp0bEI6IAZfXEIg7/Pl/7IWlLaDnhzTsD81etQA== +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + callsites@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.0.0.tgz#fb7eb569b72ad7a45812f93fd9430a3e410b3dd3" @@ -126,6 +177,11 @@ chardet@^0.7.0: resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== +chownr@^1.0.1, chownr@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.1.tgz#54726b8b8fff4df053c42187e801fb4412df1494" + integrity sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g== + circular-json@^0.3.1: version "0.3.3" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66" @@ -143,7 +199,12 @@ cli-width@^2.0.0: resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk= -color-convert@^1.9.0: +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= + +color-convert@^1.9.0, color-convert@^1.9.1: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== @@ -155,6 +216,27 @@ color-name@1.1.3: resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= +color-name@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +color-string@^1.5.2: + version "1.5.3" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.5.3.tgz#c9bbc5f01b58b5492f3d6857459cb6590ce204cc" + integrity sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw== + dependencies: + color-name "^1.0.0" + simple-swizzle "^0.2.2" + +color@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/color/-/color-3.1.0.tgz#d8e9fb096732875774c84bf922815df0308d0ffc" + integrity sha512-CwyopLkuRYO5ei2EpzpIh6LqJMt6Mt+jZhO5VI5f/wJLZriXQE32/SSqzmrh+QB+AZT81Cj8yv+7zwToW8ahZg== + dependencies: + color-convert "^1.9.1" + color-string "^1.5.2" + complex.js@2.0.11: version "2.0.11" resolved "https://registry.yarnpkg.com/complex.js/-/complex.js-2.0.11.tgz#09a873fbf15ffd8c18c9c2201ccef425c32b8bf1" @@ -165,6 +247,16 @@ concat-map@0.0.1: resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= + cross-spawn@^6.0.5: version "6.0.5" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" @@ -195,11 +287,33 @@ decimal.js@10.0.2: resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.0.2.tgz#50fd0f9184139f543e5b84c97681534292deb640" integrity sha512-qL5tUTXAWjB5cSBfm0V2a4jO5FaDLumCfwc/0f7WaTOT3WU8pIeq2HHrd98eXHtbey4qFWlaPzfml1JWIoO9TQ== +decompress-response@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/decompress-response/-/decompress-response-3.3.0.tgz#80a4dd323748384bfa248083622aedec982adff3" + integrity sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M= + dependencies: + mimic-response "^1.0.0" + +deep-extend@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== + deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= + +detect-libc@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -207,6 +321,13 @@ doctrine@^2.1.0: dependencies: esutils "^2.0.2" +end-of-stream@^1.0.0, end-of-stream@^1.1.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43" + integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q== + dependencies: + once "^1.4.0" + eris@^0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/eris/-/eris-0.9.0.tgz#a2796839f7768cd40645c2c6b1bf0c86ba3147f3" @@ -325,6 +446,11 @@ esutils@^2.0.2: resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs= +expand-template@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/expand-template/-/expand-template-2.0.3.tgz#6e14b3fcee0f3a6340ecb57d2e8918692052a47c" + integrity sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg== + external-editor@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.0.3.tgz#5866db29a97826dbe4bf3afd24070ead9ea43a27" @@ -364,6 +490,11 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + flat-cache@^1.2.1: version "1.3.4" resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.3.4.tgz#2c2ef77525cc2929007dfffa1dd314aa9c9dee6f" @@ -379,6 +510,23 @@ fraction.js@4.0.12: resolved "https://registry.yarnpkg.com/fraction.js/-/fraction.js-4.0.12.tgz#0526d47c65a5fb4854df78bc77f7bec708d7b8c3" integrity sha512-8Z1K0VTG4hzYY7kA/1sj4/r1/RWLBD3xwReT/RCrUCbzPszjNQCCsy3ktkU/eaEqX3MYa4pY37a52eiBlPMlhA== +fs-constants@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== + +fs-copy-file-sync@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fs-copy-file-sync/-/fs-copy-file-sync-1.1.1.tgz#11bf32c096c10d126e5f6b36d06eece776062918" + integrity sha512-2QY5eeqVv4m2PfyMiEuy9adxNP+ajf+8AR05cEi+OAzPcOj90hvFImeZhTmKLBgSd9EvG33jsD7ZRxsx9dThkQ== + +fs-minipass@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d" + integrity sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ== + dependencies: + minipass "^2.2.1" + fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" @@ -389,6 +537,25 @@ functional-red-black-tree@^1.0.1: resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc= +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +github-from-package@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" + integrity sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4= + glob@^7.1.2, glob@^7.1.3: version "7.1.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.3.tgz#3960832d3f1574108342dafd3a67b332c0969df1" @@ -416,6 +583,11 @@ has-flag@^3.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= + iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -449,11 +621,16 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2: +inherits@2, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= +ini@~1.3.0: + version "1.3.5" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" + integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw== + inquirer@^6.1.0: version "6.2.2" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.2.2.tgz#46941176f65c9eb20804627149b743a218f25406" @@ -473,6 +650,18 @@ inquirer@^6.1.0: strip-ansi "^5.0.0" through "^2.3.6" +is-arrayish@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" + integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= + dependencies: + number-is-nan "^1.0.0" + is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" @@ -483,6 +672,11 @@ is-promise@^2.1.0: resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o= +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -563,6 +757,11 @@ mimic-fn@^1.0.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== +mimic-response@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-1.0.1.tgz#4923538878eef42063cb8a3e3b0798781487ab1b" + integrity sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ== + minimatch@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" @@ -575,7 +774,27 @@ minimist@0.0.8: resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= -mkdirp@^0.5.1: +minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ= + +minipass@^2.2.1, minipass@^2.3.4: + version "2.3.5" + resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848" + integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA== + dependencies: + safe-buffer "^5.1.2" + yallist "^3.0.0" + +minizlib@^1.1.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614" + integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA== + dependencies: + minipass "^2.2.1" + +mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= @@ -665,6 +884,16 @@ nabbit@^0.0.2: resolved "https://registry.yarnpkg.com/nabbit/-/nabbit-0.0.2.tgz#35722cbc9745016477449befc3db580d2e9306cb" integrity sha512-2baEoEz/ugzmqTtgzHz03Z3CmmBSgsEeONxnZp++x3QRo8IBfc4FTQsP7R4IFGchYIYlvuFqf02hBGNqXCmaWQ== +nan@^2.12.1: + version "2.12.1" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" + integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== + +napi-build-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/napi-build-utils/-/napi-build-utils-1.0.1.tgz#1381a0f92c39d66bf19852e7873432fc2123e508" + integrity sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -675,12 +904,39 @@ nice-try@^1.0.4: resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -object-assign@^4.0.1: +node-abi@^2.2.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-abi/-/node-abi-2.7.0.tgz#e2f814088ab97c85504ae2bacb8f93d5d77cbc2b" + integrity sha512-egTtvNoZLMjwxkL/5iiJKYKZgn2im0zP+G+PncMxICYGiD3aZtXUvEsDmu0pF8gpASvLZyD8v53qi1/ELaRZpg== + dependencies: + semver "^5.4.1" + +noop-logger@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/noop-logger/-/noop-logger-0.1.1.tgz#94a2b1633c4f1317553007d8966fd0e841b6a4c2" + integrity sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI= + +npmlog@^4.0.1, npmlog@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= + +object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= -once@^1.3.0: +once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= @@ -711,6 +967,11 @@ opusscript@^0.0.4: resolved "https://registry.yarnpkg.com/opusscript/-/opusscript-0.0.4.tgz#c718edcfdcd2a1f55fadb266dd07268d4a46afde" integrity sha512-bEPZFE2lhUJYQD5yfTFO4RhbRZ937x6hRwBC1YoGacT35bwDVwKFP1+amU8NYfZL/v4EU7ZTU3INTqzYAnuP7Q== +os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= + os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -738,21 +999,87 @@ path-key@^2.0.1: resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= +prebuild-install@^5.2.2: + version "5.2.3" + resolved "https://registry.yarnpkg.com/prebuild-install/-/prebuild-install-5.2.3.tgz#096f5116e63eeef57ae533a2ee460b13d7872704" + integrity sha512-sdijGV8EkK244XbYJLRhOLiHj9QZKUaYW6uDotEPpRGrC5FUXFr6mZhGHr9NjhU0MISI+JSqZ0geVZMs2kIDRQ== + dependencies: + detect-libc "^1.0.3" + expand-template "^2.0.3" + github-from-package "0.0.0" + minimist "^1.2.0" + mkdirp "^0.5.1" + napi-build-utils "^1.0.1" + node-abi "^2.2.0" + noop-logger "^0.1.1" + npmlog "^4.0.1" + os-homedir "^1.0.1" + pump "^2.0.1" + rc "^1.2.7" + simple-get "^2.7.0" + tar-fs "^1.13.0" + tunnel-agent "^0.6.0" + which-pm-runs "^1.0.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= +process-nextick-args@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.0.tgz#a37d732f4271b4ab1ad070d35508e8290788ffaa" + integrity sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw== + progress@^2.0.0: version "2.0.3" resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +pump@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + punycode@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +rc@^1.2.7: + version "1.2.8" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== + dependencies: + deep-extend "^0.6.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +readable-stream@^2.0.6, readable-stream@^2.3.0, readable-stream@^2.3.5: + version "2.3.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf" + integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + regexp-clone@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/regexp-clone/-/regexp-clone-0.0.1.tgz#a7c2e09891fdbf38fbb10d376fb73003e68ac589" @@ -810,7 +1137,7 @@ rxjs@^6.4.0: dependencies: tslib "^1.9.0" -safe-buffer@5.1.2, safe-buffer@^5.1.2: +safe-buffer@5.1.2, safe-buffer@^5.0.1, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== @@ -832,11 +1159,33 @@ seed-random@2.2.0: resolved "https://registry.yarnpkg.com/seed-random/-/seed-random-2.2.0.tgz#2a9b19e250a817099231a5b99a4daf80b7fbed54" integrity sha1-KpsZ4lCoFwmSMaW5mk2vgLf77VQ= -semver@^5.1.0, semver@^5.5.0, semver@^5.5.1: +semver@^5.1.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0: version "5.6.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= + +sharp@^0.21.3: + version "0.21.3" + resolved "https://registry.yarnpkg.com/sharp/-/sharp-0.21.3.tgz#381937de66c123687f2ac7186f85921c6bb19cdd" + integrity sha512-5qZk8r+YgfyztLEKkNez20Wynq/Uh1oNyP5T/3gTYwt2lBYGs9iDs5m0yVsZEPm8eVBbAJhS08J1wp/g+Ai1Qw== + dependencies: + bindings "^1.3.1" + color "^3.1.0" + detect-libc "^1.0.3" + fs-copy-file-sync "^1.1.1" + nan "^2.12.1" + npmlog "^4.1.2" + prebuild-install "^5.2.2" + semver "^5.6.0" + simple-get "^3.0.3" + tar "^4.4.8" + tunnel-agent "^0.6.0" + shebang-command@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" @@ -849,11 +1198,41 @@ shebang-regex@^1.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= -signal-exit@^3.0.2: +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0= +simple-concat@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/simple-concat/-/simple-concat-1.0.0.tgz#7344cbb8b6e26fb27d66b2fc86f9f6d5997521c6" + integrity sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY= + +simple-get@^2.7.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-2.8.1.tgz#0e22e91d4575d87620620bc91308d57a77f44b5d" + integrity sha512-lSSHRSw3mQNUGPAYRqo7xy9dhKmxFXIjLjp4KHpf99GEH2VH7C3AM+Qfx6du6jhfUi6Vm7XnbEVEf7Wb6N8jRw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-get@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/simple-get/-/simple-get-3.0.3.tgz#924528ac3f9d7718ce5e9ec1b1a69c0be4d62efa" + integrity sha512-Wvre/Jq5vgoz31Z9stYWPLn0PqRqmBDpFSdypAnHu5AvRVCYPRYGnvryNLiXu8GOBNDH82J2FRHUGMjjHUpXFw== + dependencies: + decompress-response "^3.3.0" + once "^1.3.1" + simple-concat "^1.0.0" + +simple-swizzle@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a" + integrity sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo= + dependencies: + is-arrayish "^0.3.1" + slice-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636" @@ -880,7 +1259,16 @@ sprintf-js@~1.0.2: resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= -string-width@^2.1.0, string-width@^2.1.1: +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +"string-width@^1.0.2 || 2", string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== @@ -888,6 +1276,20 @@ string-width@^2.1.0, string-width@^2.1.1: is-fullwidth-code-point "^2.0.0" strip-ansi "^4.0.0" +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= + dependencies: + ansi-regex "^2.0.0" + strip-ansi@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" @@ -902,7 +1304,7 @@ strip-ansi@^5.0.0: dependencies: ansi-regex "^4.0.0" -strip-json-comments@^2.0.1: +strip-json-comments@^2.0.1, strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= @@ -924,6 +1326,42 @@ table@^5.0.2, table@^5.1.0: slice-ansi "^2.0.0" string-width "^2.1.1" +tar-fs@^1.13.0: + version "1.16.3" + resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" + integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + +tar-stream@^1.1.2: + version "1.6.2" + resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + +tar@^4.4.8: + version "4.4.8" + resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d" + integrity sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ== + dependencies: + chownr "^1.1.1" + fs-minipass "^1.2.5" + minipass "^2.3.4" + minizlib "^1.1.1" + mkdirp "^0.5.0" + safe-buffer "^5.1.2" + yallist "^3.0.2" + text-table@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -946,11 +1384,23 @@ tmp@^0.0.33: dependencies: os-tmpdir "~1.0.2" +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" integrity sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ== +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= + dependencies: + safe-buffer "^5.0.1" + tweetnacl@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.1.tgz#2594d42da73cd036bd0d2a54683dd35a6b55ca17" @@ -975,11 +1425,21 @@ uri-js@^4.2.2: dependencies: punycode "^2.1.0" +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= + vm2@^3.6.3: version "3.6.10" resolved "https://registry.yarnpkg.com/vm2/-/vm2-3.6.10.tgz#a9066c3849ad8a3ea35b9c0cf79a6589ce6e3cbe" integrity sha512-p4LBl7theIhmKaWPdCn25kEIG0bfDDEDx1lexXH7gcCu9pHIT+PKFgofwLHVHUGhe39lKExeaYVEZtdbQhdl2g== +which-pm-runs@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" + integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= + which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" @@ -987,6 +1447,13 @@ which@^1.2.9: dependencies: isexe "^2.0.0" +wide-align@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== + dependencies: + string-width "^1.0.2 || 2" + wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -1015,3 +1482,13 @@ wumpfetch@^0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/wumpfetch/-/wumpfetch-0.0.5.tgz#c9afe264eb4190b9e4ecb5839c98e0a2c9ecf143" integrity sha512-FqLFJCPX7A61egdlGQ6yK9eTWkHP1+n2+BJoW6S+1foRzqiV9sr2b9Tdw+w/jnW7MqcqZ+j1SAmcKfVxSYsEgA== + +xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= + +yallist@^3.0.0, yallist@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9" + integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==