├── .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 |
--------------------------------------------------------------------------------