├── .gitignore ├── README.md ├── daemon.js ├── game.js ├── highscores.js ├── index.js ├── menu.js ├── package.json ├── pieces.js ├── stats.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | scores.json 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |
5 |
6 | 7 | ## Play Online 8 | 9 | telnet kirjava.xyz 10 | 11 | ## Play Locally 12 | 13 | git clone https://github.com/kirjavascript/blessed-tetris.git 14 | cd blessed-tetris 15 | npm install 16 | npm start 17 | 18 | ## Controls 19 | 20 | WASD, HJKL and arrow keys are supported 21 | 22 | | Action | Keys | 23 | | ------------- |------------------| 24 | | rotate left | Z , | 25 | | rotate right | X . up | 26 | | move left | A H left | 27 | | move right | D L right | 28 | | hard drop | space C / W K | 29 | | soft drop | S J down | 30 | | hold | tab V M \ | 31 | | quit | escape C-c | 32 | -------------------------------------------------------------------------------- /daemon.js: -------------------------------------------------------------------------------- 1 | ~function() { 2 | 3 | const args = '--harmony index.js'.split` `; 4 | 5 | const reload = process.argv.includes('--reload'); 6 | 7 | const proc = require('child_process') 8 | .spawn('node', args, { 9 | stdio: 'inherit', 10 | }); 11 | 12 | const rip = () => { 13 | if (reload) { 14 | arguments.callee(); 15 | } 16 | else { 17 | process.exit(); 18 | } 19 | }; 20 | 21 | proc.on('exit', rip); 22 | 23 | require('chokidar') 24 | .watch('**/*', {ignored: [/[\/\\]\./, 'scores.json']}) 25 | .on('change', () => { 26 | proc.removeListener('exit', rip); 27 | proc.on('exit', arguments.callee); 28 | proc.kill('SIGINT'); 29 | }); 30 | 31 | } (); 32 | -------------------------------------------------------------------------------- /game.js: -------------------------------------------------------------------------------- 1 | const { Screen, Box, Button, Message } = require('blessed'); 2 | const { getRandom } = require('./pieces'); 3 | const { createStats } = require('./stats'); 4 | const { createMenu } = require('./menu'); 5 | const { checkHighscore } = require('./highscores'); 6 | 7 | module.exports = (client) => { 8 | 9 | const screen = new Screen({ 10 | fastCSR: true, 11 | dockBorders: true, 12 | input: client, 13 | output: client, 14 | terminal: 'xterm-256color' 15 | }); 16 | 17 | const width = 10; 18 | const height = 20; 19 | const zoom = 4; 20 | 21 | const display = new Box({ 22 | parent: screen, 23 | width: width*zoom+2, 24 | height: (height*zoom/2)+2, 25 | border: 'line', 26 | style: { 27 | border: { 28 | fg: '#06A', 29 | }, 30 | }, 31 | bottom: 0, 32 | left: 'center', 33 | }); 34 | 35 | const title = new Box({ 36 | parent: screen, 37 | width: 'shrink', 38 | height: 3, 39 | content: '', 40 | style: { 41 | fg: '#06A', 42 | }, 43 | content: '╔╦╗╔═╗╔╦╗╦═╗╦╔═╗\n ║ ║╣ ║ ╠╦╝║╚═╗\n ╩ ╚═╝ ╩ ╩╚═╩╚═╝', 44 | left: '50%-9', 45 | top: 0, 46 | }); 47 | 48 | const { 49 | restartMessage, 50 | menuBox, 51 | } = createMenu({ screen }); 52 | 53 | const { 54 | alertMessage, 55 | holdBox, 56 | nextBox, 57 | statsBox, 58 | } = createStats({ width, height, zoom, screen }); 59 | 60 | const board = Array.from({length: width*height}, (_, i) => { 61 | const point = Object.create(null); 62 | 63 | const color = void 0; 64 | const x = i % width; 65 | const y = (0| i / width); 66 | const element = new Box({ 67 | width: zoom, 68 | height: zoom/2, 69 | parent: display, 70 | left: x * zoom, 71 | top: y * zoom / 2, 72 | style: { bg: color }, 73 | }); 74 | 75 | return Object.assign(point, { 76 | color, 77 | x, y, 78 | element, 79 | }); 80 | }); 81 | 82 | 83 | let activePiece, pendingPiece, timer; 84 | let heldPiece, justHeld; 85 | 86 | const game = { 87 | score: 0, 88 | lines: 0, 89 | get level() { 90 | return (0|game.lines/10) + 1; 91 | }, 92 | board, 93 | display, 94 | width, 95 | height, 96 | zoom, 97 | running: false, 98 | startTime: 0, 99 | stopTime: 0, 100 | nextPiece() { 101 | justHeld = false; 102 | activePiece = pendingPiece; 103 | activePiece.startTimer(); 104 | pendingPiece = getRandom(game); 105 | if (activePiece.collides()) { 106 | game.stop(); 107 | } 108 | }, 109 | hold() { 110 | if (justHeld) { 111 | return; 112 | } 113 | activePiece.hold(); 114 | let toPlace = heldPiece; 115 | heldPiece = activePiece; 116 | if (!toPlace) { 117 | game.nextPiece(); 118 | } else { 119 | // should dedupe 120 | activePiece = toPlace; 121 | toPlace.startTimer(); 122 | if (activePiece.collides()) { 123 | game.stop(); 124 | } 125 | } 126 | justHeld = true; 127 | }, 128 | addScore(n) { 129 | game.score += n; 130 | }, 131 | addLines(n) { 132 | game.lines += n; 133 | alertMessage.display(screen, n == 4 ? 'Tetris!' : `${n} Lines!`); 134 | }, 135 | render() { 136 | activePiece.eachCell( 137 | (point) => { 138 | point.element.style.bg = activePiece.color; 139 | // point.element.style.fg = "#000"; 140 | // point.element.content = '╭──╮╰──╯' 141 | }, 142 | (point) => { 143 | point.element.style.bg = point.color; 144 | // point.element.content = ''; 145 | }, 146 | ); 147 | 148 | activePiece.eachGhost( 149 | (point) => { 150 | point.element.style.transparent = !point.element.style.bg; 151 | point.element.style.bg = activePiece.color; 152 | }, 153 | (point) => { 154 | point.element.style.transparent = false; 155 | point.element.style.bg = point.element.style.bg; 156 | }, 157 | ); 158 | let stats = { 159 | Score: game.score, 160 | Lines: game.lines, 161 | Level: game.level, 162 | LPM: game.linesPerMinute(), 163 | }; 164 | 165 | statsBox.setContent( 166 | Object 167 | .entries(stats) 168 | .map(([name, val]) => `${name}: {bold}${val}{/}`) 169 | .join`\n` 170 | ); 171 | 172 | nextBox.setContent(` Next\n\n${pendingPiece.viewShape()}`); 173 | 174 | holdBox.setContent(` Hold\n\n${heldPiece ? heldPiece.viewShape() : ''}`) 175 | 176 | screen.render(); 177 | }, 178 | linesPerMinute() { 179 | let minutesPlaying = Math.max(game.timePlaying(), 1) / 1000 / 60; 180 | return (game.lines / minutesPlaying).toFixed(2); 181 | }, 182 | timePlaying() { 183 | return (game.stopTime || Date.now()) - game.startTime 184 | }, 185 | start() { 186 | game.running = true; 187 | game.startTime = Date.now(); 188 | game.stopTime = 0; 189 | pendingPiece = getRandom(game); 190 | game.nextPiece(); 191 | game.render(); 192 | }, 193 | stop() { 194 | activePiece.stopTimer(); 195 | clearInterval(timer); 196 | game.stopTime = Date.now(); 197 | game.render(); 198 | game.running = false; 199 | checkHighscore({ game, screen }); 200 | restartMessage.show(); 201 | screen.render(); 202 | }, 203 | reset() { 204 | game.score = 0; 205 | game.lines = 0; 206 | board.forEach(point => { 207 | point.color = void 0; 208 | }); 209 | restartMessage.hide(); 210 | game.start(); 211 | }, 212 | }; 213 | 214 | // keyboard input 215 | 216 | screen.key(['escape', 'C-c'], () => { 217 | screen.destroy(); 218 | !client && process.exit(); 219 | }); 220 | 221 | screen.key('enter', () => { 222 | if (!game.running) { 223 | game.reset(); 224 | } 225 | }); 226 | 227 | const input = [ 228 | { 229 | keys: ['z',','], 230 | action: () => { 231 | activePiece.rotate(-1); 232 | }, 233 | }, 234 | { 235 | keys: ['x', '.', 'up'], 236 | action: () => { 237 | activePiece.rotate(1); 238 | }, 239 | }, 240 | { 241 | keys: ['a', 'h', 'left'], 242 | action: () => { 243 | activePiece.move(-1); 244 | }, 245 | }, 246 | { 247 | keys: ['d', 'l', 'right'], 248 | action: () => { 249 | activePiece.move(1); 250 | }, 251 | }, 252 | { 253 | keys: ['s', 'down', 'j'], 254 | action: () => { 255 | activePiece.advance(true); 256 | }, 257 | }, 258 | { 259 | keys: ['space', '/', 'c', 'k', 'w'], 260 | action: () => { 261 | activePiece.drop(); 262 | }, 263 | }, 264 | { 265 | keys: ['tab', 'v', 'm', '\\'], 266 | action: () => { 267 | game.hold(); 268 | }, 269 | }, 270 | ]; 271 | 272 | 273 | input.forEach(({keys, action}) => { 274 | screen.key(keys, () => { 275 | if (game.running) { 276 | action(); 277 | game.render(); 278 | } 279 | }); 280 | }); 281 | 282 | game.start(); 283 | 284 | return { 285 | screen, 286 | game, 287 | }; 288 | }; 289 | 290 | 291 | -------------------------------------------------------------------------------- /highscores.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs'); 2 | const { Box, Textbox, Button } = require('blessed'); 3 | const filePath = './scores.json'; 4 | 5 | let highscores = []; 6 | 7 | if (fs.existsSync(filePath)) { 8 | try { 9 | highscores = JSON.parse(fs.readFileSync(filePath)); 10 | } 11 | catch (e) { 12 | console.error(e); 13 | } 14 | } 15 | 16 | function checkHighscore({ game, screen }) { 17 | const lowestScore = highscores.reduce((a, b) => Math.min(a, b.score), Infinity); 18 | 19 | if (highscores.length < 10 || game.score > lowestScore) { 20 | const prompt = new Box({ 21 | parent: screen, 22 | width: 40, 23 | height: `shrink`, 24 | border: 'line', 25 | style: { 26 | border: { 27 | fg: '#06A', 28 | }, 29 | }, 30 | left: 'center', 31 | top: '50%', 32 | padding: 1, 33 | content: 'New highscore! Enter a name...', 34 | draggable: true, 35 | }); 36 | 37 | const input = new Textbox({ 38 | parent: prompt, 39 | height: 2, 40 | top: 2, 41 | left: 0, 42 | width: 30, 43 | style: { 44 | }, 45 | inputOnFocus: true, 46 | mouse: true, 47 | }); 48 | 49 | const save = new Button({ 50 | parent: prompt, 51 | width: 'shrink', 52 | height: 1, 53 | mouse: true, 54 | content: ' Save ', 55 | style: { 56 | bg: '#06A', 57 | fg: '#000', 58 | }, 59 | bottom: 0, 60 | right: 0, 61 | }); 62 | 63 | input.focus(); 64 | 65 | save.on('click', () => { 66 | if (input.value.trim()) { 67 | (highscores.length >= 10) && highscores.pop(); 68 | 69 | highscores.push({ 70 | name: input.value.trim(), 71 | score: game.score, 72 | lines: game.lines, 73 | LPM: game.linesPerMinute(), 74 | }); 75 | 76 | highscores.sort((a, b) => a.score < b.score); 77 | fs.writeFile(filePath, JSON.stringify(highscores), (err) => { 78 | err && console.error(err); 79 | }); 80 | 81 | save.destroy(); 82 | input.destroy(); 83 | prompt.destroy(); 84 | screen.render(); 85 | } 86 | }); 87 | 88 | 89 | } 90 | } 91 | 92 | function getHighscores() { 93 | return highscores; 94 | } 95 | 96 | module.exports = { 97 | checkHighscore, 98 | getHighscores, 99 | }; 100 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const telnet = require('telnet2'); 2 | const newGame = require('./game'); 3 | 4 | const serve = process.argv.includes('--serve'); 5 | const serveDev = process.argv.includes('--serve-dev'); 6 | 7 | if (serve || serveDev) { 8 | telnet({ tty: true }, function(client) { 9 | client.on('size', function(width, height) { 10 | client.columns = width; 11 | client.rows = height; 12 | client.emit('resize'); 13 | }); 14 | client.on('close', function() { 15 | if (!screen.destroyed) { 16 | screen.destroy(); 17 | } 18 | }); 19 | 20 | const { screen, game } = newGame(client); 21 | 22 | screen.on('destroy', function() { 23 | if (client.writable) { 24 | client.destroy(); 25 | } 26 | }); 27 | 28 | }).listen(serveDev ? 2300 : 23); 29 | } 30 | else { 31 | newGame(); 32 | } 33 | -------------------------------------------------------------------------------- /menu.js: -------------------------------------------------------------------------------- 1 | const { Box, Message, Button, ListTable } = require('blessed'); 2 | const { getHighscores } = require('./highscores'); 3 | 4 | const messageBase = { 5 | width: `shrink`, 6 | height: `shrink`, 7 | border: 'line', 8 | style: { 9 | border: { 10 | fg: '#06A', 11 | }, 12 | }, 13 | left: 'center', 14 | top: '50%', 15 | hidden: true, 16 | padding: 1, 17 | draggable: true, 18 | }; 19 | 20 | const buttonBase = { 21 | width: 'shrink', 22 | height: 1, 23 | tags: true, 24 | mouse: true, 25 | style: { 26 | bg: '#06A', 27 | fg: '#000', 28 | }, 29 | }; 30 | 31 | const createMenu = ({screen}) => { 32 | const menuBox = new Box({ 33 | parent: screen, 34 | width: 20, 35 | height: 1, 36 | top: 3, 37 | left: 'center', 38 | }); 39 | 40 | const restartMessage = new Box(Object.assign({}, 41 | messageBase, { 42 | parent: screen, 43 | content: 'Game Over!\n\n Press enter key to restart', 44 | width: 32, 45 | }) 46 | ); 47 | 48 | const aboutButton = new Button(Object.assign({}, 49 | buttonBase, { 50 | parent: menuBox, 51 | content: ' About ', 52 | left: 0, 53 | bottom: 0, 54 | }) 55 | ); 56 | 57 | const aboutMessage = new Message(Object.assign({}, 58 | messageBase, { 59 | parent: screen, 60 | tags: true, 61 | width: 52, 62 | }) 63 | ); 64 | 65 | const aboutMessageCloseButton = new Button(Object.assign({}, 66 | buttonBase, { 67 | parent: aboutMessage, 68 | content: ' X ', 69 | right: 0, 70 | top: 0, 71 | }) 72 | ); 73 | 74 | aboutMessageCloseButton.on('click', () => { 75 | aboutMessage.hide(); 76 | screen.render(); 77 | }); 78 | 79 | aboutButton.on('press', () => { 80 | aboutMessage.display([ 81 | '{yellow-fg}{bold}★{/} Controls / Source', 82 | 'https://github.com/kirjavascript/blessed-tetris', 83 | ].join`\n\n`, 0, () => { 84 | aboutMessage.focus(); 85 | }); 86 | }); 87 | 88 | const highscoreButton = new Button(Object.assign({}, 89 | buttonBase, { 90 | parent: menuBox, 91 | content: ' Highscores ', 92 | right: 0, 93 | }) 94 | ); 95 | 96 | const highscoreMessage = new Box(Object.assign({}, 97 | messageBase, { 98 | parent: screen, 99 | tags: true, 100 | width: 'shrink', 101 | content: '{bold}High Scores{/}', 102 | }) 103 | ); 104 | 105 | const highscoreTable = new ListTable({ 106 | parent: highscoreMessage, 107 | top: 2, 108 | left: 0, 109 | height: 10, 110 | tags: true, 111 | }); 112 | 113 | const highscoreMessageCloseButton = new Button(Object.assign({}, 114 | buttonBase, { 115 | parent: highscoreMessage, 116 | content: ' X ', 117 | right: 0, 118 | top: 0, 119 | }) 120 | ); 121 | 122 | highscoreMessageCloseButton.on('click', () => { 123 | highscoreMessage.hide(); 124 | screen.render(); 125 | }); 126 | 127 | highscoreButton.on('press', () => { 128 | highscoreMessage.show(); 129 | const highscores = getHighscores() 130 | .map(({ name, score, lines, LPM, }) => { 131 | return [name, lines, LPM, score].map(String); 132 | }); 133 | 134 | highscoreTable.setData([ 135 | [ 'Nick', 'Lines' , 'LPM', 'Score' ], 136 | ...highscores, 137 | ]); 138 | screen.render(); 139 | }); 140 | 141 | return { 142 | menuBox, 143 | restartMessage, 144 | }; 145 | }; 146 | 147 | module.exports = { 148 | createMenu, 149 | }; 150 | 151 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "blessed-tetris", 3 | "engines": { 4 | "node": ">=8" 5 | }, 6 | "scripts": { 7 | "start": "node index", 8 | "daemon": "node daemon", 9 | "reload": "node daemon --reload", 10 | "serve-dev": "node index --serve-dev", 11 | "serve": "pm2 start --name \"tetris\" index.js -- --serve" 12 | }, 13 | "dependencies": { 14 | "blessed": "^0.1.81", 15 | "telnet2": "^0.0.1" 16 | }, 17 | "devDependencies": { 18 | "chokidar": "^1.7.0" 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /pieces.js: -------------------------------------------------------------------------------- 1 | const pieces = [ 2 | { 3 | name: 'I', 4 | color: 'cyan', 5 | frames: [ 6 | [ 7 | 0,1,0,0, 8 | 0,1,0,0, 9 | 0,1,0,0, 10 | 0,1,0,0, 11 | ], 12 | [ 13 | 0,0,0,0, 14 | 0,0,0,0, 15 | 1,1,1,1, 16 | 0,0,0,0, 17 | ], 18 | [ 19 | 0,0,1,0, 20 | 0,0,1,0, 21 | 0,0,1,0, 22 | 0,0,1,0, 23 | ], 24 | [ 25 | 0,0,0,0, 26 | 0,0,0,0, 27 | 1,1,1,1, 28 | 0,0,0,0, 29 | ], 30 | ], 31 | }, 32 | { 33 | name: 'J', 34 | color: 'blue', 35 | frames: [ 36 | [ 37 | 0,1,0,0, 38 | 0,1,0,0, 39 | 1,1,0,0, 40 | 0,0,0,0, 41 | ], 42 | [ 43 | 0,0,0,0, 44 | 1,0,0,0, 45 | 1,1,1,0, 46 | 0,0,0,0, 47 | ], 48 | [ 49 | 0,1,1,0, 50 | 0,1,0,0, 51 | 0,1,0,0, 52 | 0,0,0,0, 53 | ], 54 | [ 55 | 0,0,0,0, 56 | 1,1,1,0, 57 | 0,0,1,0, 58 | 0,0,0,0, 59 | ], 60 | ], 61 | }, 62 | { 63 | name: 'L', 64 | color: '#FF4500', 65 | frames: [ 66 | [ 67 | 0,1,0,0, 68 | 0,1,0,0, 69 | 0,1,1,0, 70 | 0,0,0,0, 71 | ], 72 | [ 73 | 0,0,0,0, 74 | 1,1,1,0, 75 | 1,0,0,0, 76 | 0,0,0,0, 77 | ], 78 | [ 79 | 1,1,0,0, 80 | 0,1,0,0, 81 | 0,1,0,0, 82 | 0,0,0,0, 83 | ], 84 | [ 85 | 0,0,0,0, 86 | 0,0,1,0, 87 | 1,1,1,0, 88 | 0,0,0,0, 89 | ], 90 | ], 91 | }, 92 | { 93 | name: 'O', 94 | color: '#Fa0', 95 | frames: new Array(4) 96 | .fill([ 97 | 0,0,0,0, 98 | 0,1,1,0, 99 | 0,1,1,0, 100 | 0,0,0,0, 101 | ]), 102 | }, 103 | { 104 | name: 'S', 105 | color: 'green', 106 | frames: [ 107 | [ 108 | 0,0,0,0, 109 | 0,1,1,0, 110 | 1,1,0,0, 111 | 0,0,0,0, 112 | ], 113 | [ 114 | 0,1,0,0, 115 | 0,1,1,0, 116 | 0,0,1,0, 117 | 0,0,0,0, 118 | ], 119 | [ 120 | 0,0,0,0, 121 | 0,1,1,0, 122 | 1,1,0,0, 123 | 0,0,0,0, 124 | ], 125 | [ 126 | 0,1,0,0, 127 | 0,1,1,0, 128 | 0,0,1,0, 129 | 0,0,0,0, 130 | ], 131 | ], 132 | }, 133 | { 134 | name: 'T', 135 | color: '#551a8b', 136 | frames: [ 137 | [ 138 | 0,0,0,0, 139 | 1,1,1,0, 140 | 0,1,0,0, 141 | 0,0,0,0, 142 | ], 143 | [ 144 | 0,1,0,0, 145 | 1,1,0,0, 146 | 0,1,0,0, 147 | 0,0,0,0, 148 | ], 149 | [ 150 | 0,0,0,0, 151 | 0,1,0,0, 152 | 1,1,1,0, 153 | 0,0,0,0, 154 | ], 155 | [ 156 | 0,1,0,0, 157 | 0,1,1,0, 158 | 0,1,0,0, 159 | 0,0,0,0, 160 | ], 161 | ], 162 | }, 163 | { 164 | name: 'Z', 165 | color: 'red', 166 | frames: [ 167 | [ 168 | 0,0,0,0, 169 | 1,1,0,0, 170 | 0,1,1,0, 171 | 0,0,0,0, 172 | ], 173 | [ 174 | 0,0,1,0, 175 | 0,1,1,0, 176 | 0,1,0,0, 177 | 0,0,0,0, 178 | ], 179 | [ 180 | 0,0,0,0, 181 | 1,1,0,0, 182 | 0,1,1,0, 183 | 0,0,0,0, 184 | ], 185 | [ 186 | 0,0,1,0, 187 | 0,1,1,0, 188 | 0,1,0,0, 189 | 0,0,0,0, 190 | ], 191 | ], 192 | }, 193 | ]; 194 | 195 | 196 | let queue = []; 197 | 198 | const getRandom = (game) => { 199 | const {board, width, height } = game; 200 | 201 | if (queue.length == 0) { 202 | queue = shuffle(Array.from({length: pieces.length}, (_, i) => i)); 203 | } 204 | 205 | const nextIndex = queue.pop(); 206 | const initialState = { 207 | x: (width/2)-2, 208 | y: -2, 209 | rotation: 0|Math.random()*4, 210 | locking: false, 211 | // TODO: Consider liming extended moves (e.g. moves when touching the ground) 212 | // instead. 213 | floorKicksLeft: 3, 214 | }; 215 | 216 | const piece = Object.create({ 217 | rotate(order) { 218 | let transformsToTry = [ 219 | { rotation: order }, 220 | { rotation: order, x: 1 }, 221 | { rotation: order, x: -1 }, 222 | // A pattern matching detection system is too much work 223 | // and this feels accuate enough. 224 | { rotation: order, x: 0, y: -1 }, 225 | { rotation: order, x: 1, y: -1 }, 226 | { rotation: order, x: -1, y: -1 }, 227 | 228 | { rotation: order, x: 0, y: -2 }, 229 | { rotation: order, x: 1, y: -2 }, 230 | { rotation: order, x: -1, y: -2 }, 231 | ]; 232 | 233 | for (let transform of transformsToTry) { 234 | let isFloorKick = transform.y < 0; 235 | if (isFloorKick && piece.floorKicksLeft <= 0) { 236 | return; 237 | } 238 | if (piece.tryTransform(transform)) { 239 | if (isFloorKick) { 240 | --piece.floorKicksLeft; 241 | } 242 | if (!piece.collides({y: 1})) { 243 | piece.resumeNormalMotion(); 244 | } 245 | return; 246 | } 247 | } 248 | }, 249 | tryTransform({x = 0, y = 0, rotation = 0}) { 250 | if (piece.collides({x, y, rotation})) { 251 | return false; 252 | } 253 | piece.x += x; 254 | piece.y += y; 255 | piece.rotation = modulo(piece.rotation + rotation, 4); 256 | return true; 257 | }, 258 | move(dx) { 259 | if (piece.tryTransform({x: dx})) { 260 | if (!piece.collides({y: 1})) { 261 | piece.resumeNormalMotion(); 262 | } 263 | } 264 | }, 265 | collides({x = 0, y = 0, rotation = 0} = {}) { 266 | let doesCollide = false; 267 | piece.eachTransformed({x, y, rotation}, (x, y) => { 268 | if (doesCollide) { 269 | return; 270 | } 271 | if (y >= height) { 272 | doesCollide = true; 273 | } 274 | else if (board[x + (y*width)] && board[x + (y*width)].color) { 275 | doesCollide = true; 276 | } 277 | else if (x < 0) { 278 | doesCollide = true; 279 | } 280 | else if (x >= width) { 281 | doesCollide = true; 282 | } 283 | }); 284 | return doesCollide; 285 | }, 286 | advance(fromUserInput = false) { 287 | if (!piece.tryTransform({y: 1})) { 288 | if (!piece.locking) { 289 | piece.waitForLock(); 290 | } else if (fromUserInput) { 291 | piece.place(); 292 | } 293 | } 294 | }, 295 | waitForLock() { 296 | piece.stopTimer(); 297 | piece.locking = true; 298 | // even TGM3 isn't cruel enough to move lock delay below 250. 299 | let lockDelay = [500, 400, 300][Math.floor(game.level / 10)] || 250; 300 | piece.lockTimer = setTimeout(() => { 301 | piece.place(); 302 | }, lockDelay); 303 | }, 304 | resumeNormalMotion() { 305 | if (piece.locking) { 306 | clearTimeout(piece.lockTimer); 307 | piece.locking = false; 308 | piece.startTimer(); 309 | } 310 | }, 311 | place() { 312 | piece.locking = false; 313 | piece.eachCell((point) => { 314 | point.color = piece.color; 315 | }); 316 | 317 | // remove lines 318 | let lineQty = 0; 319 | 320 | for (let i = 0; i < height; i++) { 321 | let line = board.slice(i * width, (i*width) + width); 322 | if (line.filter(d => d.color).length == width) { 323 | for (let j = i; j > 0; j--) { 324 | for (let k = 0; k < width; k++) { 325 | board[(j*width)+k].color = board[((j-1)*width)+k].color; 326 | } 327 | } 328 | lineQty++; 329 | } 330 | } 331 | 332 | piece.stopTimer(); 333 | 334 | if (lineQty) { 335 | game.addLines(lineQty); 336 | game.addScore([40, 100, 300, 1200][lineQty-1] * game.level); 337 | } 338 | else { 339 | game.addScore(10); 340 | } 341 | game.nextPiece(); 342 | }, 343 | drop() { 344 | while (piece.tryTransform({y: 1})) { 345 | // intentionally empty 346 | } 347 | piece.place(); 348 | }, 349 | getShape() { 350 | return piece.frames[piece.rotation % 4]; 351 | }, 352 | viewShape() { 353 | return `{${piece.color}-fg}` + piece.getShape().join``.match(/..../g).join`\n`.replace(/0|1/g, m => { 354 | return m == '1' ? '██' : ' '; 355 | }) + '{/}'; 356 | }, 357 | each(callback) { 358 | piece.getShape().forEach((d, i) => { 359 | if (d) { 360 | const x = i%4; 361 | const y = 0|i/4; 362 | callback(x + piece.x, y + piece.y, i); 363 | } 364 | }); 365 | }, 366 | eachTransformed({x = 0, y = 0, rotation = 0}, callback) { 367 | let frame = piece.frames[modulo(piece.rotation + rotation, 4)] 368 | frame.forEach((d, i) => { 369 | if (d) { 370 | const ix = i%4; 371 | const iy = 0|i/4; 372 | callback(ix + piece.x + x, iy + piece.y + y, i); 373 | } 374 | }); 375 | }, 376 | eachGhost(on, off) { 377 | let y = 0; 378 | while (!piece.collides({y: y + 1})) { 379 | y += 1; 380 | } 381 | piece.eachCell(on, off, 0, y); 382 | }, 383 | // TODO: should this accept {x, y, rotation} transform as last arg? (atm not needed) 384 | eachCell(callbackOn, callbackOff, xOff = 0, yOff = 0) { 385 | board.forEach((point, i) => { 386 | 387 | const { element, color, x, y } = point; 388 | const pieceX = piece.x + xOff; 389 | const pieceY = piece.y + yOff; 390 | 391 | let drawColor = color; 392 | 393 | let [dx, dy] = [ 394 | x - pieceX, 395 | y - pieceY, 396 | ]; 397 | 398 | if (x >= pieceX && Math.abs(dx) < 4 && Math.abs(dy) < 4) { 399 | let shape = piece.getShape(); 400 | if (shape[dx + (dy*4)]) { 401 | drawColor = piece.color; 402 | return callbackOn && callbackOn(point); 403 | } 404 | } 405 | 406 | callbackOff && callbackOff(point); 407 | 408 | }); 409 | }, 410 | startTimer() { 411 | piece.timer = setInterval(() => { 412 | piece.advance(); 413 | game.render(); 414 | }, [500, 450, 400, 350, 300, 250, 200, 150, 100][game.level - 1] || 50); 415 | }, 416 | stopTimer() { 417 | clearInterval(piece.timer); 418 | clearTimeout(piece.lockTimer); 419 | }, 420 | clone() { 421 | let newObj = Object.create(piece); 422 | return Object.assign(newObj, piece); 423 | }, 424 | hold() { 425 | this.stopTimer(); 426 | Object.assign(this, initialState); 427 | } 428 | }); 429 | 430 | Object.assign(piece, pieces[nextIndex], initialState); 431 | 432 | return piece; 433 | }; 434 | 435 | 436 | const shuffle = (array) => { 437 | var m = array.length, t, i; 438 | while (m) { 439 | i = Math.floor(Math.random() * m--); 440 | t = array[m]; 441 | array[m] = array[i]; 442 | array[i] = t; 443 | } 444 | return array; 445 | } 446 | 447 | // % is actually remainder. this does the right thing for negative a 448 | const modulo = (a, b) => ((a % b) + b) % b; 449 | 450 | module.exports = { 451 | getRandom, 452 | }; 453 | -------------------------------------------------------------------------------- /stats.js: -------------------------------------------------------------------------------- 1 | const { Screen, Box, Message, Button } = require('blessed'); 2 | 3 | const createStats = ({width, height, zoom, screen}) => { 4 | 5 | const statsBox = new Box({ 6 | parent: screen, 7 | width: (width*zoom+2), 8 | height: `100%-${(height*(zoom/2))+2+4}`, 9 | border: 'line', 10 | style: { 11 | border: { 12 | fg: '#06A', 13 | }, 14 | }, 15 | left: 'center', 16 | top: 4, 17 | tags: true, 18 | padding: { 19 | left: 2, 20 | right: 2, 21 | top: 1, 22 | bottom: 1, 23 | }, 24 | }); 25 | 26 | const nextBox = new Box({ 27 | parent: statsBox, 28 | width: 'shrink', 29 | height: `shrink`, 30 | style: { 31 | }, 32 | top: 0, 33 | right: 0, 34 | tags: true, 35 | }); 36 | 37 | const holdBox = new Box({ 38 | parent: statsBox, 39 | width: 'shrink', 40 | height: `shrink`, 41 | style: { 42 | }, 43 | top: 0, 44 | right: 12, 45 | tags: true, 46 | }); 47 | 48 | const alertMessage = new Box({ 49 | parent: statsBox, 50 | width: 'shrink', 51 | left: 'center', 52 | top: 6, 53 | style: { 54 | }, 55 | tags: true, 56 | hidden: true, 57 | content: '(~˘▾˘)~', 58 | timer: void 0, 59 | }); 60 | 61 | alertMessage.display = (screen, msg) => { 62 | alertMessage.setContent(`{bold}${msg}{/}`); 63 | alertMessage.show(); 64 | alertMessage.timer && clearTimeout(alertMessage.timer); 65 | alertMessage.timer = setTimeout(() => { 66 | alertMessage.hide(); 67 | screen.render(); 68 | }, 2000) 69 | }; 70 | 71 | return { 72 | alertMessage, 73 | holdBox, 74 | nextBox, 75 | statsBox, 76 | }; 77 | 78 | }; 79 | 80 | module.exports = { 81 | createStats, 82 | }; 83 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | abbrev@1: 6 | version "1.1.0" 7 | resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" 8 | 9 | ajv@^4.9.1: 10 | version "4.11.8" 11 | resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" 12 | dependencies: 13 | co "^4.6.0" 14 | json-stable-stringify "^1.0.1" 15 | 16 | ansi-regex@^2.0.0: 17 | version "2.1.1" 18 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" 19 | 20 | anymatch@^1.3.0: 21 | version "1.3.0" 22 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" 23 | dependencies: 24 | arrify "^1.0.0" 25 | micromatch "^2.1.5" 26 | 27 | aproba@^1.0.3: 28 | version "1.1.2" 29 | resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.2.tgz#45c6629094de4e96f693ef7eab74ae079c240fc1" 30 | 31 | are-we-there-yet@~1.1.2: 32 | version "1.1.4" 33 | resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" 34 | dependencies: 35 | delegates "^1.0.0" 36 | readable-stream "^2.0.6" 37 | 38 | arr-diff@^2.0.0: 39 | version "2.0.0" 40 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" 41 | dependencies: 42 | arr-flatten "^1.0.1" 43 | 44 | arr-flatten@^1.0.1: 45 | version "1.0.3" 46 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" 47 | 48 | array-unique@^0.2.1: 49 | version "0.2.1" 50 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" 51 | 52 | arrify@^1.0.0: 53 | version "1.0.1" 54 | resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" 55 | 56 | asn1@~0.2.3: 57 | version "0.2.3" 58 | resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" 59 | 60 | assert-plus@1.0.0, assert-plus@^1.0.0: 61 | version "1.0.0" 62 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" 63 | 64 | assert-plus@^0.2.0: 65 | version "0.2.0" 66 | resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" 67 | 68 | async-each@^1.0.0: 69 | version "1.0.1" 70 | resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" 71 | 72 | asynckit@^0.4.0: 73 | version "0.4.0" 74 | resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 75 | 76 | aws-sign2@~0.6.0: 77 | version "0.6.0" 78 | resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" 79 | 80 | aws4@^1.2.1: 81 | version "1.6.0" 82 | resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" 83 | 84 | balanced-match@^1.0.0: 85 | version "1.0.0" 86 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 87 | 88 | bcrypt-pbkdf@^1.0.0: 89 | version "1.0.1" 90 | resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" 91 | dependencies: 92 | tweetnacl "^0.14.3" 93 | 94 | binary-extensions@^1.0.0: 95 | version "1.8.0" 96 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" 97 | 98 | blessed@^0.1.81: 99 | version "0.1.81" 100 | resolved "https://registry.yarnpkg.com/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129" 101 | 102 | block-stream@*: 103 | version "0.0.9" 104 | resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" 105 | dependencies: 106 | inherits "~2.0.0" 107 | 108 | boom@2.x.x: 109 | version "2.10.1" 110 | resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" 111 | dependencies: 112 | hoek "2.x.x" 113 | 114 | brace-expansion@^1.1.7: 115 | version "1.1.8" 116 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.8.tgz#c07b211c7c952ec1f8efd51a77ef0d1d3990a292" 117 | dependencies: 118 | balanced-match "^1.0.0" 119 | concat-map "0.0.1" 120 | 121 | braces@^1.8.2: 122 | version "1.8.5" 123 | resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" 124 | dependencies: 125 | expand-range "^1.8.1" 126 | preserve "^0.2.0" 127 | repeat-element "^1.1.2" 128 | 129 | caseless@~0.12.0: 130 | version "0.12.0" 131 | resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" 132 | 133 | chokidar@^1.7.0: 134 | version "1.7.0" 135 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" 136 | dependencies: 137 | anymatch "^1.3.0" 138 | async-each "^1.0.0" 139 | glob-parent "^2.0.0" 140 | inherits "^2.0.1" 141 | is-binary-path "^1.0.0" 142 | is-glob "^2.0.0" 143 | path-is-absolute "^1.0.0" 144 | readdirp "^2.0.0" 145 | optionalDependencies: 146 | fsevents "^1.0.0" 147 | 148 | co@^4.6.0: 149 | version "4.6.0" 150 | resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" 151 | 152 | code-point-at@^1.0.0: 153 | version "1.1.0" 154 | resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" 155 | 156 | combined-stream@^1.0.5, combined-stream@~1.0.5: 157 | version "1.0.5" 158 | resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" 159 | dependencies: 160 | delayed-stream "~1.0.0" 161 | 162 | concat-map@0.0.1: 163 | version "0.0.1" 164 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 165 | 166 | console-control-strings@^1.0.0, console-control-strings@~1.1.0: 167 | version "1.1.0" 168 | resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" 169 | 170 | core-util-is@~1.0.0: 171 | version "1.0.2" 172 | resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" 173 | 174 | cryptiles@2.x.x: 175 | version "2.0.5" 176 | resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" 177 | dependencies: 178 | boom "2.x.x" 179 | 180 | dashdash@^1.12.0: 181 | version "1.14.1" 182 | resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" 183 | dependencies: 184 | assert-plus "^1.0.0" 185 | 186 | debug@^2.2.0: 187 | version "2.6.8" 188 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" 189 | dependencies: 190 | ms "2.0.0" 191 | 192 | deep-extend@~0.4.0: 193 | version "0.4.2" 194 | resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" 195 | 196 | delayed-stream@~1.0.0: 197 | version "1.0.0" 198 | resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 199 | 200 | delegates@^1.0.0: 201 | version "1.0.0" 202 | resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" 203 | 204 | ecc-jsbn@~0.1.1: 205 | version "0.1.1" 206 | resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" 207 | dependencies: 208 | jsbn "~0.1.0" 209 | 210 | expand-brackets@^0.1.4: 211 | version "0.1.5" 212 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" 213 | dependencies: 214 | is-posix-bracket "^0.1.0" 215 | 216 | expand-range@^1.8.1: 217 | version "1.8.2" 218 | resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" 219 | dependencies: 220 | fill-range "^2.1.0" 221 | 222 | extend@~3.0.0: 223 | version "3.0.1" 224 | resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" 225 | 226 | extglob@^0.3.1: 227 | version "0.3.2" 228 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" 229 | dependencies: 230 | is-extglob "^1.0.0" 231 | 232 | extsprintf@1.0.2: 233 | version "1.0.2" 234 | resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" 235 | 236 | filename-regex@^2.0.0: 237 | version "2.0.1" 238 | resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" 239 | 240 | fill-range@^2.1.0: 241 | version "2.2.3" 242 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" 243 | dependencies: 244 | is-number "^2.1.0" 245 | isobject "^2.0.0" 246 | randomatic "^1.1.3" 247 | repeat-element "^1.1.2" 248 | repeat-string "^1.5.2" 249 | 250 | for-in@^1.0.1: 251 | version "1.0.2" 252 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 253 | 254 | for-own@^0.1.4: 255 | version "0.1.5" 256 | resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" 257 | dependencies: 258 | for-in "^1.0.1" 259 | 260 | forever-agent@~0.6.1: 261 | version "0.6.1" 262 | resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" 263 | 264 | form-data@~2.1.1: 265 | version "2.1.4" 266 | resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" 267 | dependencies: 268 | asynckit "^0.4.0" 269 | combined-stream "^1.0.5" 270 | mime-types "^2.1.12" 271 | 272 | fs.realpath@^1.0.0: 273 | version "1.0.0" 274 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 275 | 276 | fsevents@^1.0.0: 277 | version "1.1.2" 278 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.2.tgz#3282b713fb3ad80ede0e9fcf4611b5aa6fc033f4" 279 | dependencies: 280 | nan "^2.3.0" 281 | node-pre-gyp "^0.6.36" 282 | 283 | fstream-ignore@^1.0.5: 284 | version "1.0.5" 285 | resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" 286 | dependencies: 287 | fstream "^1.0.0" 288 | inherits "2" 289 | minimatch "^3.0.0" 290 | 291 | fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: 292 | version "1.0.11" 293 | resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" 294 | dependencies: 295 | graceful-fs "^4.1.2" 296 | inherits "~2.0.0" 297 | mkdirp ">=0.5 0" 298 | rimraf "2" 299 | 300 | gauge@~2.7.3: 301 | version "2.7.4" 302 | resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" 303 | dependencies: 304 | aproba "^1.0.3" 305 | console-control-strings "^1.0.0" 306 | has-unicode "^2.0.0" 307 | object-assign "^4.1.0" 308 | signal-exit "^3.0.0" 309 | string-width "^1.0.1" 310 | strip-ansi "^3.0.1" 311 | wide-align "^1.1.0" 312 | 313 | getpass@^0.1.1: 314 | version "0.1.7" 315 | resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" 316 | dependencies: 317 | assert-plus "^1.0.0" 318 | 319 | glob-base@^0.3.0: 320 | version "0.3.0" 321 | resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" 322 | dependencies: 323 | glob-parent "^2.0.0" 324 | is-glob "^2.0.0" 325 | 326 | glob-parent@^2.0.0: 327 | version "2.0.0" 328 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" 329 | dependencies: 330 | is-glob "^2.0.0" 331 | 332 | glob@^7.0.5: 333 | version "7.1.2" 334 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" 335 | dependencies: 336 | fs.realpath "^1.0.0" 337 | inflight "^1.0.4" 338 | inherits "2" 339 | minimatch "^3.0.4" 340 | once "^1.3.0" 341 | path-is-absolute "^1.0.0" 342 | 343 | graceful-fs@^4.1.2: 344 | version "4.1.11" 345 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" 346 | 347 | har-schema@^1.0.5: 348 | version "1.0.5" 349 | resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" 350 | 351 | har-validator@~4.2.1: 352 | version "4.2.1" 353 | resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" 354 | dependencies: 355 | ajv "^4.9.1" 356 | har-schema "^1.0.5" 357 | 358 | has-unicode@^2.0.0: 359 | version "2.0.1" 360 | resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" 361 | 362 | hawk@~3.1.3: 363 | version "3.1.3" 364 | resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" 365 | dependencies: 366 | boom "2.x.x" 367 | cryptiles "2.x.x" 368 | hoek "2.x.x" 369 | sntp "1.x.x" 370 | 371 | hoek@2.x.x: 372 | version "2.16.3" 373 | resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" 374 | 375 | http-signature@~1.1.0: 376 | version "1.1.1" 377 | resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" 378 | dependencies: 379 | assert-plus "^0.2.0" 380 | jsprim "^1.2.2" 381 | sshpk "^1.7.0" 382 | 383 | inflight@^1.0.4: 384 | version "1.0.6" 385 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 386 | dependencies: 387 | once "^1.3.0" 388 | wrappy "1" 389 | 390 | inherits@2, inherits@^2.0.1, inherits@~2.0.0, inherits@~2.0.3: 391 | version "2.0.3" 392 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" 393 | 394 | ini@~1.3.0: 395 | version "1.3.4" 396 | resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" 397 | 398 | is-binary-path@^1.0.0: 399 | version "1.0.1" 400 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" 401 | dependencies: 402 | binary-extensions "^1.0.0" 403 | 404 | is-buffer@^1.1.5: 405 | version "1.1.5" 406 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" 407 | 408 | is-dotfile@^1.0.0: 409 | version "1.0.3" 410 | resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" 411 | 412 | is-equal-shallow@^0.1.3: 413 | version "0.1.3" 414 | resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" 415 | dependencies: 416 | is-primitive "^2.0.0" 417 | 418 | is-extendable@^0.1.1: 419 | version "0.1.1" 420 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 421 | 422 | is-extglob@^1.0.0: 423 | version "1.0.0" 424 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" 425 | 426 | is-fullwidth-code-point@^1.0.0: 427 | version "1.0.0" 428 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" 429 | dependencies: 430 | number-is-nan "^1.0.0" 431 | 432 | is-glob@^2.0.0, is-glob@^2.0.1: 433 | version "2.0.1" 434 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" 435 | dependencies: 436 | is-extglob "^1.0.0" 437 | 438 | is-number@^2.1.0: 439 | version "2.1.0" 440 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" 441 | dependencies: 442 | kind-of "^3.0.2" 443 | 444 | is-number@^3.0.0: 445 | version "3.0.0" 446 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" 447 | dependencies: 448 | kind-of "^3.0.2" 449 | 450 | is-posix-bracket@^0.1.0: 451 | version "0.1.1" 452 | resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" 453 | 454 | is-primitive@^2.0.0: 455 | version "2.0.0" 456 | resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" 457 | 458 | is-typedarray@~1.0.0: 459 | version "1.0.0" 460 | resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" 461 | 462 | isarray@1.0.0, isarray@~1.0.0: 463 | version "1.0.0" 464 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 465 | 466 | isobject@^2.0.0: 467 | version "2.1.0" 468 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 469 | dependencies: 470 | isarray "1.0.0" 471 | 472 | isstream@~0.1.2: 473 | version "0.1.2" 474 | resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" 475 | 476 | jsbn@~0.1.0: 477 | version "0.1.1" 478 | resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" 479 | 480 | json-schema@0.2.3: 481 | version "0.2.3" 482 | resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" 483 | 484 | json-stable-stringify@^1.0.1: 485 | version "1.0.1" 486 | resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" 487 | dependencies: 488 | jsonify "~0.0.0" 489 | 490 | json-stringify-safe@~5.0.1: 491 | version "5.0.1" 492 | resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" 493 | 494 | jsonify@~0.0.0: 495 | version "0.0.0" 496 | resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" 497 | 498 | jsprim@^1.2.2: 499 | version "1.4.0" 500 | resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" 501 | dependencies: 502 | assert-plus "1.0.0" 503 | extsprintf "1.0.2" 504 | json-schema "0.2.3" 505 | verror "1.3.6" 506 | 507 | kind-of@^3.0.2: 508 | version "3.2.2" 509 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 510 | dependencies: 511 | is-buffer "^1.1.5" 512 | 513 | kind-of@^4.0.0: 514 | version "4.0.0" 515 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" 516 | dependencies: 517 | is-buffer "^1.1.5" 518 | 519 | micromatch@^2.1.5: 520 | version "2.3.11" 521 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" 522 | dependencies: 523 | arr-diff "^2.0.0" 524 | array-unique "^0.2.1" 525 | braces "^1.8.2" 526 | expand-brackets "^0.1.4" 527 | extglob "^0.3.1" 528 | filename-regex "^2.0.0" 529 | is-extglob "^1.0.0" 530 | is-glob "^2.0.1" 531 | kind-of "^3.0.2" 532 | normalize-path "^2.0.1" 533 | object.omit "^2.0.0" 534 | parse-glob "^3.0.4" 535 | regex-cache "^0.4.2" 536 | 537 | mime-db@~1.27.0: 538 | version "1.27.0" 539 | resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" 540 | 541 | mime-types@^2.1.12, mime-types@~2.1.7: 542 | version "2.1.15" 543 | resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" 544 | dependencies: 545 | mime-db "~1.27.0" 546 | 547 | minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.4: 548 | version "3.0.4" 549 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 550 | dependencies: 551 | brace-expansion "^1.1.7" 552 | 553 | minimist@0.0.8: 554 | version "0.0.8" 555 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" 556 | 557 | minimist@^1.2.0: 558 | version "1.2.0" 559 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" 560 | 561 | "mkdirp@>=0.5 0", mkdirp@^0.5.1: 562 | version "0.5.1" 563 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" 564 | dependencies: 565 | minimist "0.0.8" 566 | 567 | ms@2.0.0: 568 | version "2.0.0" 569 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 570 | 571 | nan@^2.3.0: 572 | version "2.6.2" 573 | resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" 574 | 575 | node-pre-gyp@^0.6.36: 576 | version "0.6.36" 577 | resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786" 578 | dependencies: 579 | mkdirp "^0.5.1" 580 | nopt "^4.0.1" 581 | npmlog "^4.0.2" 582 | rc "^1.1.7" 583 | request "^2.81.0" 584 | rimraf "^2.6.1" 585 | semver "^5.3.0" 586 | tar "^2.2.1" 587 | tar-pack "^3.4.0" 588 | 589 | nopt@^4.0.1: 590 | version "4.0.1" 591 | resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" 592 | dependencies: 593 | abbrev "1" 594 | osenv "^0.1.4" 595 | 596 | normalize-path@^2.0.1: 597 | version "2.1.1" 598 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" 599 | dependencies: 600 | remove-trailing-separator "^1.0.1" 601 | 602 | npmlog@^4.0.2: 603 | version "4.1.0" 604 | resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5" 605 | dependencies: 606 | are-we-there-yet "~1.1.2" 607 | console-control-strings "~1.1.0" 608 | gauge "~2.7.3" 609 | set-blocking "~2.0.0" 610 | 611 | number-is-nan@^1.0.0: 612 | version "1.0.1" 613 | resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" 614 | 615 | oauth-sign@~0.8.1: 616 | version "0.8.2" 617 | resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" 618 | 619 | object-assign@^4.1.0: 620 | version "4.1.1" 621 | resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" 622 | 623 | object.omit@^2.0.0: 624 | version "2.0.1" 625 | resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" 626 | dependencies: 627 | for-own "^0.1.4" 628 | is-extendable "^0.1.1" 629 | 630 | once@^1.3.0, once@^1.3.3: 631 | version "1.4.0" 632 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 633 | dependencies: 634 | wrappy "1" 635 | 636 | os-homedir@^1.0.0: 637 | version "1.0.2" 638 | resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" 639 | 640 | os-tmpdir@^1.0.0: 641 | version "1.0.2" 642 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 643 | 644 | osenv@^0.1.4: 645 | version "0.1.4" 646 | resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" 647 | dependencies: 648 | os-homedir "^1.0.0" 649 | os-tmpdir "^1.0.0" 650 | 651 | parse-glob@^3.0.4: 652 | version "3.0.4" 653 | resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" 654 | dependencies: 655 | glob-base "^0.3.0" 656 | is-dotfile "^1.0.0" 657 | is-extglob "^1.0.0" 658 | is-glob "^2.0.0" 659 | 660 | path-is-absolute@^1.0.0: 661 | version "1.0.1" 662 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 663 | 664 | performance-now@^0.2.0: 665 | version "0.2.0" 666 | resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" 667 | 668 | preserve@^0.2.0: 669 | version "0.2.0" 670 | resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" 671 | 672 | process-nextick-args@~1.0.6: 673 | version "1.0.7" 674 | resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" 675 | 676 | punycode@^1.4.1: 677 | version "1.4.1" 678 | resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" 679 | 680 | qs@~6.4.0: 681 | version "6.4.0" 682 | resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" 683 | 684 | randomatic@^1.1.3: 685 | version "1.1.7" 686 | resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.7.tgz#c7abe9cc8b87c0baa876b19fde83fd464797e38c" 687 | dependencies: 688 | is-number "^3.0.0" 689 | kind-of "^4.0.0" 690 | 691 | rc@^1.1.7: 692 | version "1.2.1" 693 | resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" 694 | dependencies: 695 | deep-extend "~0.4.0" 696 | ini "~1.3.0" 697 | minimist "^1.2.0" 698 | strip-json-comments "~2.0.1" 699 | 700 | readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.4: 701 | version "2.3.2" 702 | resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.2.tgz#5a04df05e4f57fe3f0dc68fdd11dc5c97c7e6f4d" 703 | dependencies: 704 | core-util-is "~1.0.0" 705 | inherits "~2.0.3" 706 | isarray "~1.0.0" 707 | process-nextick-args "~1.0.6" 708 | safe-buffer "~5.1.0" 709 | string_decoder "~1.0.0" 710 | util-deprecate "~1.0.1" 711 | 712 | readdirp@^2.0.0: 713 | version "2.1.0" 714 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" 715 | dependencies: 716 | graceful-fs "^4.1.2" 717 | minimatch "^3.0.2" 718 | readable-stream "^2.0.2" 719 | set-immediate-shim "^1.0.1" 720 | 721 | regex-cache@^0.4.2: 722 | version "0.4.3" 723 | resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" 724 | dependencies: 725 | is-equal-shallow "^0.1.3" 726 | is-primitive "^2.0.0" 727 | 728 | remove-trailing-separator@^1.0.1: 729 | version "1.0.2" 730 | resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz#69b062d978727ad14dc6b56ba4ab772fd8d70511" 731 | 732 | repeat-element@^1.1.2: 733 | version "1.1.2" 734 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" 735 | 736 | repeat-string@^1.5.2: 737 | version "1.6.1" 738 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 739 | 740 | request@^2.81.0: 741 | version "2.81.0" 742 | resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" 743 | dependencies: 744 | aws-sign2 "~0.6.0" 745 | aws4 "^1.2.1" 746 | caseless "~0.12.0" 747 | combined-stream "~1.0.5" 748 | extend "~3.0.0" 749 | forever-agent "~0.6.1" 750 | form-data "~2.1.1" 751 | har-validator "~4.2.1" 752 | hawk "~3.1.3" 753 | http-signature "~1.1.0" 754 | is-typedarray "~1.0.0" 755 | isstream "~0.1.2" 756 | json-stringify-safe "~5.0.1" 757 | mime-types "~2.1.7" 758 | oauth-sign "~0.8.1" 759 | performance-now "^0.2.0" 760 | qs "~6.4.0" 761 | safe-buffer "^5.0.1" 762 | stringstream "~0.0.4" 763 | tough-cookie "~2.3.0" 764 | tunnel-agent "^0.6.0" 765 | uuid "^3.0.0" 766 | 767 | rimraf@2, rimraf@^2.5.1, rimraf@^2.6.1: 768 | version "2.6.1" 769 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" 770 | dependencies: 771 | glob "^7.0.5" 772 | 773 | safe-buffer@^5.0.1, safe-buffer@~5.1.0: 774 | version "5.1.1" 775 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" 776 | 777 | semver@^5.3.0: 778 | version "5.3.0" 779 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" 780 | 781 | set-blocking@~2.0.0: 782 | version "2.0.0" 783 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 784 | 785 | set-immediate-shim@^1.0.1: 786 | version "1.0.1" 787 | resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" 788 | 789 | signal-exit@^3.0.0: 790 | version "3.0.2" 791 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" 792 | 793 | sntp@1.x.x: 794 | version "1.0.9" 795 | resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" 796 | dependencies: 797 | hoek "2.x.x" 798 | 799 | sshpk@^1.7.0: 800 | version "1.13.1" 801 | resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.1.tgz#512df6da6287144316dc4c18fe1cf1d940739be3" 802 | dependencies: 803 | asn1 "~0.2.3" 804 | assert-plus "^1.0.0" 805 | dashdash "^1.12.0" 806 | getpass "^0.1.1" 807 | optionalDependencies: 808 | bcrypt-pbkdf "^1.0.0" 809 | ecc-jsbn "~0.1.1" 810 | jsbn "~0.1.0" 811 | tweetnacl "~0.14.0" 812 | 813 | string-width@^1.0.1, string-width@^1.0.2: 814 | version "1.0.2" 815 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" 816 | dependencies: 817 | code-point-at "^1.0.0" 818 | is-fullwidth-code-point "^1.0.0" 819 | strip-ansi "^3.0.0" 820 | 821 | string_decoder@~1.0.0: 822 | version "1.0.3" 823 | resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.3.tgz#0fc67d7c141825de94282dd536bec6b9bce860ab" 824 | dependencies: 825 | safe-buffer "~5.1.0" 826 | 827 | stringstream@~0.0.4: 828 | version "0.0.5" 829 | resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" 830 | 831 | strip-ansi@^3.0.0, strip-ansi@^3.0.1: 832 | version "3.0.1" 833 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" 834 | dependencies: 835 | ansi-regex "^2.0.0" 836 | 837 | strip-json-comments@~2.0.1: 838 | version "2.0.1" 839 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" 840 | 841 | tar-pack@^3.4.0: 842 | version "3.4.0" 843 | resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" 844 | dependencies: 845 | debug "^2.2.0" 846 | fstream "^1.0.10" 847 | fstream-ignore "^1.0.5" 848 | once "^1.3.3" 849 | readable-stream "^2.1.4" 850 | rimraf "^2.5.1" 851 | tar "^2.2.1" 852 | uid-number "^0.0.6" 853 | 854 | tar@^2.2.1: 855 | version "2.2.1" 856 | resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" 857 | dependencies: 858 | block-stream "*" 859 | fstream "^1.0.2" 860 | inherits "2" 861 | 862 | telnet2@^0.0.1: 863 | version "0.0.1" 864 | resolved "https://registry.yarnpkg.com/telnet2/-/telnet2-0.0.1.tgz#4ecf8b113c33a7e077092c6293ee427df3332b0d" 865 | 866 | tough-cookie@~2.3.0: 867 | version "2.3.2" 868 | resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" 869 | dependencies: 870 | punycode "^1.4.1" 871 | 872 | tunnel-agent@^0.6.0: 873 | version "0.6.0" 874 | resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" 875 | dependencies: 876 | safe-buffer "^5.0.1" 877 | 878 | tweetnacl@^0.14.3, tweetnacl@~0.14.0: 879 | version "0.14.5" 880 | resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" 881 | 882 | uid-number@^0.0.6: 883 | version "0.0.6" 884 | resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" 885 | 886 | util-deprecate@~1.0.1: 887 | version "1.0.2" 888 | resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" 889 | 890 | uuid@^3.0.0: 891 | version "3.1.0" 892 | resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04" 893 | 894 | verror@1.3.6: 895 | version "1.3.6" 896 | resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" 897 | dependencies: 898 | extsprintf "1.0.2" 899 | 900 | wide-align@^1.1.0: 901 | version "1.1.2" 902 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" 903 | dependencies: 904 | string-width "^1.0.2" 905 | 906 | wrappy@1: 907 | version "1.0.2" 908 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 909 | --------------------------------------------------------------------------------