From 71be13075290bc1e072942a29517eeec38f91285 Mon Sep 17 00:00:00 2001 From: Dmitry Noranovich Date: Wed, 30 Nov 2016 16:32:57 -0500 Subject: [PATCH 1/4] Added all-your-base exercise to JavaScript track Added use strict statement to the code Renamed and moved test concerning missing inputs --- config.json | 9 +- exercises/all-your-base/all-your-base.spec.js | 141 ++++++++++++++++++ exercises/all-your-base/example.js | 59 ++++++++ 3 files changed, 208 insertions(+), 1 deletion(-) create mode 100644 exercises/all-your-base/all-your-base.spec.js create mode 100644 exercises/all-your-base/example.js diff --git a/config.json b/config.json index c60390db..b30f5090 100644 --- a/config.json +++ b/config.json @@ -70,7 +70,8 @@ "bracket-push", "two-bucket", "bowling", - "diamond" + "diamond", + "all-your-base" ], "exercises": [ { @@ -468,6 +469,12 @@ "difficulty": 1, "topics": [ ] + }, + { + "slug": "all-your-base", + "difficulty": 1, + "topics": [ + ] } ], "deprecated": [ diff --git a/exercises/all-your-base/all-your-base.spec.js b/exercises/all-your-base/all-your-base.spec.js new file mode 100644 index 00000000..34d28100 --- /dev/null +++ b/exercises/all-your-base/all-your-base.spec.js @@ -0,0 +1,141 @@ +'use strict'; + +const Converter = require('./all-your-base'); + +const converter = new Converter(); + +describe('Converter', function () { + + xit('single bit one to decimal', function () { + expect(converter.convert([1], 2, 10)).toEqual([1]); + }); + + xit('binary to single decimal', function () { + expect(converter.convert([1, 0, 1], 2, 10)).toEqual([5]); + }); + + xit('single decimal to binary', function () { + expect(converter.convert([5], 10, 2)).toEqual([1, 0, 1]); + }); + + xit('binary to multiple decimal', function () { + expect(converter.convert([1, 0, 1, 0, 1, 0], 2, 10)).toEqual([4, 2]); + }); + + xit('decimal to binary', function () { + expect(converter.convert([4, 2], 10, 2)).toEqual([1, 0, 1, 0, 1, 0]); + }); + + xit('trinary to hexadecimal', function () { + expect(converter.convert([1, 1, 2, 0], 3, 16)).toEqual([2, 10]); + }); + + xit('hexadecimal to trinary', function () { + expect(converter.convert([2, 10], 16, 3)).toEqual([1, 1, 2, 0]); + }); + + xit('15-bit integer', function () { + expect(converter.convert([3, 46, 60], 97, 73)).toEqual([6, 10, 45]); + }); + + xit('empty list', function () { + expect(function () { + converter.convert([], 2, 10); + }).toThrow(new Error('Input has wrong format')); + }); + + xit('single zero', function () { + expect(converter.convert([0], 10, 2)).toEqual([0]); + }); + + xit('multiple zeros', function () { + expect(function () { + converter.convert([0, 0, 0], 10, 2); + }).toThrow(new Error('Input has wrong format')); + }); + + xit('leading zeros', function () { + expect(function () { + converter.convert([0, 6, 0], 7, 10); + }).toThrow(new Error('Input has wrong format')); + }); + + xit('negative digit', function () { + expect(function () { + converter.convert([1, -1, 1, 0, 1, 0], 2, 10); + }).toThrow(new Error('Input has wrong format')); + }); + + xit('invalid positive digit', function () { + expect(function () { + converter.convert([1, 2, 1, 0, 1, 0], 2, 10); + }).toThrow(new Error('Input has wrong format')); + }); + + xit('first base is one', function () { + expect(function () { + converter.convert([], 1, 10); + }).toThrow(new Error('Wrong input base')); + }); + + xit('second base is one', function () { + expect(function () { + converter.convert([1, 0, 1, 0, 1, 0], 2, 1); + }).toThrow(new Error('Wrong output base')); + }); + + xit('first base is zero', function () { + expect(function () { + converter.convert([], 0, 10); + }).toThrow(new Error('Wrong input base')); + }); + + xit('second base is zero', function () { + expect(function () { + converter.convert([7], 10, 0); + }).toThrow(new Error('Wrong output base')); + }); + + xit('first base is negative', function () { + expect(function () { + converter.convert([1], -2, 10); + }).toThrow(new Error('Wrong input base')); + }); + + xit('second base is negative', function () { + expect(function () { + converter.convert([1], 2, -7); + }).toThrow(new Error('Wrong output base')); + }); + + xit('both bases are negative', function () { + expect(function () { + converter.convert([1], -2, -7); + }).toThrow(new Error('Wrong input base')); + }); + + it('missing input base throws an error', function () { + expect(function () { + converter.convert([0]); + }).toThrow(new Error('Wrong input base')); + }); + + xit('wrong input_base base not integer', function () { + expect(function () { + converter.convert([0], 2.5); + }).toThrow(new Error('Wrong input base')); + }); + + xit('missing output base throws an error', function () { + expect(function () { + converter.convert([0], 2); + }).toThrow(new Error('Wrong output base')); + }); + + xit('wrong output_base base not integer', function () { + expect(function () { + converter.convert([0], 3, 2.5); + }).toThrow(new Error('Wrong output base')); + }); + +}); diff --git a/exercises/all-your-base/example.js b/exercises/all-your-base/example.js new file mode 100644 index 00000000..7dae83cc --- /dev/null +++ b/exercises/all-your-base/example.js @@ -0,0 +1,59 @@ +'use strict'; + +const Converter = function () { }; + +const isValidBase = function (base) { + return !base || base < 2 || Math.floor(base) !== base; +}; + +const isInputValid = function (array, base) { + if (!array || !array.length) { + return false; + } + const val = base - 1; + for (let i = 0, n = array.length; i < n; i++) { + const tmp = array[i]; + if (tmp > val || tmp < 0) { + return false; + } + } + return true; +}; + +const convertFromDecimalToBase = function (num, outputBase) { + let tmp = num; + const result = []; + while (tmp) { + result.unshift(tmp % outputBase); + tmp = Math.floor(tmp / outputBase); + } + return result; +}; + +Converter.prototype.convert = function (array, inputBase, outputBase) { + if (isValidBase(inputBase)) { + throw new Error('Wrong input base'); + } + if (isValidBase(outputBase)) { + throw new Error('Wrong output base'); + } + const regexp = new RegExp('^0.', 'g'); + const str = array.join(''); + if (str.match(regexp) + || !isInputValid(array, inputBase)) { + throw new Error('Input has wrong format'); + } + if (str === '0') { + return [0]; + } + if (str === '1') { + return [1]; + } + const decimalValue = array + .reduce((accumulator, value) => { + return accumulator * inputBase + value; + }, 0); + return convertFromDecimalToBase(decimalValue, outputBase); +}; + +module.exports = Converter; From c94bd0d1ea22432557b264401e830115334cd410 Mon Sep 17 00:00:00 2001 From: ldwoolley Date: Sun, 4 Dec 2016 16:36:32 -0800 Subject: [PATCH 2/4] Update word-count in xjavascript to match the x-common reference. The test now checks for the elimination of punctuation. --- exercises/word-count/example.js | 10 ++++---- exercises/word-count/word-count.spec.js | 31 ++++++++++++++++++------- 2 files changed, 28 insertions(+), 13 deletions(-) diff --git a/exercises/word-count/example.js b/exercises/word-count/example.js index 02aa1d9e..2a357994 100644 --- a/exercises/word-count/example.js +++ b/exercises/word-count/example.js @@ -4,15 +4,15 @@ function Words() {} Words.prototype.count = function (input) { var counts = {}; - var words = input.match(/\S+/g); + var words = input.toLowerCase() + .replace(/[,."\/!&@$%\^\*;:{}()¡¿?]/g, ' ') + .replace(/\s'(\w+)'\s/, ' '+'$1'+' ') + .match(/\S+/g); words.forEach(function (word) { - var lcWord = word.toLowerCase(); - counts[lcWord] = counts.hasOwnProperty(lcWord) ? counts[lcWord] + 1 : 1; + counts[word] = counts.hasOwnProperty(word) ? counts[word] + 1 : 1; }); - return counts; }; module.exports = Words; - diff --git a/exercises/word-count/word-count.spec.js b/exercises/word-count/word-count.spec.js index ab503dda..8b34faf0 100644 --- a/exercises/word-count/word-count.spec.js +++ b/exercises/word-count/word-count.spec.js @@ -8,19 +8,24 @@ describe('count()', function() { expect(words.count('word')).toEqual(expectedCounts); }); - xit('counts one of each', function() { + xit('counts one of each word', function() { var expectedCounts = { one: 1, of: 1, each: 1 }; expect(words.count('one of each')).toEqual(expectedCounts); }); - xit('counts multiple occurrences', function() { + xit('counts multiple occurrences of a word', function() { var expectedCounts = { one: 1, fish: 4, two: 1, red: 1, blue: 1 }; expect(words.count('one fish two fish red fish blue fish')).toEqual(expectedCounts); }); - xit('includes punctuation', function() { - var expectedCounts = { car: 1, ':': 2, carpet: 1, as: 1, java: 1, 'javascript!!&@$%^&': 1 }; - expect(words.count('car : carpet as java : javascript!!&@$%^&')).toEqual(expectedCounts); + xit('handles cramped lists', function() { + var expectedCounts = { one: 1, two: 1, three: 1 }; + expect(words.count('one,two,three')).toEqual(expectedCounts); + }); + + xit('ignores punctuation', function() { + var expectedCounts = { car: 1, carpet: 1, as: 1, java: 1, javascript: 1 }; + expect(words.count('car : carpet as java: javascript!!&@$%^&')).toEqual(expectedCounts); }); xit('includes numbers', function() { @@ -33,8 +38,18 @@ describe('count()', function() { expect(words.count('go Go GO')).toEqual(expectedCounts); }); + xit('counts words with apostrophes', function() { + var expectedCounts = { 'first': 1, 'don\'t': 2, 'laugh': 1, 'then': 1, 'cry': 1 }; + expect(words.count('First: don\'t laugh. Then: don\'t cry.')).toEqual(expectedCounts); + }); + + xit('counts words with quotations', function() { + var expectedCounts = { 'joe': 1, 'can\'t': 1, 'tell': 1, 'between': 1, 'large': 2, 'and': 1 }; + expect(words.count('Joe can\'t tell between \'large\' and large.')).toEqual(expectedCounts); + }); + xit('counts properly international characters', function() { - var expectedCounts = { '¡hola!': 1, '¿qué': 1, 'tal?': 1, 'привет!': 1 }; + var expectedCounts = { 'hola': 1, 'qué': 1, 'tal': 1, 'привет': 1 }; expect(words.count('¡Hola! ¿Qué tal? Привет!')).toEqual(expectedCounts); }); @@ -43,7 +58,7 @@ describe('count()', function() { expect(words.count('hello\nworld')).toEqual(expectedCounts); }); - xit('counts tabs', function() { + xit('counts tabs as white space', function() { var expectedCounts = { hello: 1, world: 1 }; expect(words.count('hello\tworld')).toEqual(expectedCounts); }); @@ -59,7 +74,7 @@ describe('count()', function() { }); xit('handles properties that exist on Object’s prototype', function() { - var expectedCounts = { reserved: 1, words: 1, like: 1, constructor: 1, and: 1, tostring: 1, 'ok?': 1 }; + var expectedCounts = { reserved: 1, words: 1, like: 1, constructor: 1, and: 1, tostring: 1, ok: 1 }; expect(words.count('reserved words like constructor and toString ok?')).toEqual(expectedCounts); }); }); From 375d3316057422a5fc7f6e7d431718b6370a1fef Mon Sep 17 00:00:00 2001 From: ldwoolley Date: Sun, 4 Dec 2016 23:06:11 -0800 Subject: [PATCH 3/4] Update bowling test Adjusted test order and add tests to align with x-common reference, and set the file to the test start position. --- exercises/bowling/bowling.spec.js | 146 +++++++++++++++++------------- 1 file changed, 83 insertions(+), 63 deletions(-) diff --git a/exercises/bowling/bowling.spec.js b/exercises/bowling/bowling.spec.js index 309555c0..2804ee5a 100644 --- a/exercises/bowling/bowling.spec.js +++ b/exercises/bowling/bowling.spec.js @@ -2,39 +2,44 @@ var Bowling = require('./bowling'); describe('Bowling', function() { describe('Check game can be scored correctly.', function() { - it('should be able to score open frame', function() { - var rolls = [3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(7); + it('should be able to score a game with all gutterballs', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + expect(new Bowling(rolls).score()).toEqual(0); }); - xit('should be able to score multiple frames', function() { - var rolls = [3, 4, 2, 3, 5, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(19); + xit('should be able to score a game with all open frames', function() { + var rolls = [3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6]; + expect(new Bowling(rolls).score()).toEqual(90); }); - xit('should be able to score a game with all gutterballs', function() { - var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(0); + xit('a spare followed by zeros is worth ten points', function() { + var rolls = [6, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + expect(new Bowling(rolls).score()).toEqual(10); }); - xit('should be able to score a game with all single pin rolls', function() { - var rolls = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]; - expect(new Bowling(rolls).score()).toEqual(20); + xit('points scored in the roll after a spare are counted twice', function() { + var rolls = [6, 4, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + expect(new Bowling(rolls).score()).toEqual(16); }); - xit('should be able to score a game with all open frames', function() { - var rolls = [3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6, 3, 6]; - expect(new Bowling(rolls).score()).toEqual(90); + xit('consecutive spares each get a one roll bonus', function() { + var rolls = [5, 5, 3, 7, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + expect(new Bowling(rolls).score()).toEqual(31); }); - xit('should be able to score a strike not in the last frame', function() { - var rolls = [10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(26); + xit('should allow fill ball when the last frame is a spare', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 7]; + expect(new Bowling(rolls).score()).toEqual(17); }); - xit('should be able to score a spare not in the last frame', function() { - var rolls = [5, 5, 3, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(20); + xit('a strike earns ten points in a frame with a single roll', function() { + var rolls = [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + expect(new Bowling(rolls).score()).toEqual(10); + }); + + xit('points scored in the two rolls after a strike are counted twice as a bonus', function() { + var rolls = [10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + expect(new Bowling(rolls).score()).toEqual(26); }); xit('should be able to score multiple strikes in a row', function() { @@ -42,26 +47,26 @@ describe('Bowling', function() { expect(new Bowling(rolls).score()).toEqual(81); }); - xit('should be able to score multiple spares in a row', function() { - var rolls = [5, 5, 3, 7, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(32); - }); - xit('should allow fill balls when the last frame is a strike', function() { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 1]; expect(new Bowling(rolls).score()).toEqual(18); }); - xit('should allow fill ball when the last frame is a spare', function() { - var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 1, 7]; - expect(new Bowling(rolls).score()).toEqual(17); + xit('rolling a spare with the two roll bonus does not get a bonus roll', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 7, 3]; + expect(new Bowling(rolls).score()).toEqual(20); }); - xit('should allow fill balls to be a strike', function() { + xit('strikes with the two roll bonus do not get bonus rolls', function() { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10]; expect(new Bowling(rolls).score()).toEqual(30); }); + xit('a strike with the one roll bonus after a spare in the last frame does not get a bonus', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 10]; + expect(new Bowling(rolls).score()).toEqual(20); + }); + xit('should be able to score a perfect game', function() { var rolls = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10]; expect(new Bowling(rolls).score()).toEqual(300); @@ -69,60 +74,75 @@ describe('Bowling', function() { }); describe('Check game rules.', function() { - xit('should not allow rolls with negative pins', function() { - var rolls = [-1]; + xit('rolls can not score negative points', function() { + var rolls = [-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; expect(function() { new Bowling(rolls).score(); }).toThrow( - new Error('Pins must have a value from 0 to 10') - ); - }); + new Error('Pins must have a value from 0 to 10')); + }); - xit('should not allow rolls better than strike', function() { - var rolls = [11]; + xit('a roll can not score more than 10 points', function() { + var rolls = [11, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; expect(function() { new Bowling(rolls).score(); }).toThrow( - new Error('Pins must have a value from 0 to 10') - ); - }); + new Error('Pins must have a value from 0 to 10')); + }); - xit('should not allow two normal rolls better than strike', function() { - var rolls = [5, 6]; + xit('two rolls in a frame can not score more than 10 points', function() { + var rolls = [5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; expect(function() { new Bowling(rolls).score(); }).toThrow( - new Error('Pin count exceeds pins on the lane') - ); + new Error('Pin count exceeds pins on the lane')); + }); + + xit('two bonus rolls after a strike in the last frame can not score more than 10 points', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 5, 6]; + expect(function() { new Bowling(rolls).score(); }).toThrow( + new Error('Pin count exceeds pins on the lane')); + }); + + xit('two bonus rolls after a strike in the last frame can score more than 10 points if one is a strike', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 6]; + expect(new Bowling(rolls).score()).toEqual(26); }); - xit('should not allow two normal rolls better than strike in last frame', function() { - var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6]; + xit('the second bonus rolls after a strike in the last frame can not be a strike if the first one is not a strike', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 6, 10]; expect(function() { new Bowling(rolls).score(); }).toThrow( - new Error('Pin count exceeds pins on the lane') - ); + new Error('Pin count exceeds pins on the lane')); }); - xit('should not allow to take score at the beginning of the game', function() { + xit('an unstarted game can not be scored', function() { var rolls = []; expect(function() { new Bowling(rolls).score(); }).toThrow( - new Error('Score cannot be taken until the end of the game') - ); + new Error('Score cannot be taken until the end of the game')); }); - xit('should not allow to take score before the game has ended', function() { - var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + xit('an incomplete game can not be scored', function() { + var rolls = [0, 0]; expect(function() { new Bowling(rolls).score(); }).toThrow( - new Error('Score cannot be taken until the end of the game') - ); + new Error('Score cannot be taken until the end of the game')); }); - xit('should not allow rolls after the tenth frame', function() { + xit('a game with more than ten frames and no last frame spare or strike can not be scored', function() { var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; expect(function() { new Bowling(rolls).score(); }).toThrow( - new Error('Should not be able to roll after game is over') - ); + new Error('Should not be able to roll after game is over')); + }); + + xit('bonus rolls for a strike in the last frame must be rolled before score can be calculated', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10]; + expect(function() { new Bowling(rolls).score(); }).toThrow( + new Error('Score cannot be taken until the end of the game')); + }); + + xit('both bonus rolls for a strike in the last frame must be rolled before score can be calculated', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10]; + expect(function() { new Bowling(rolls).score(); }).toThrow( + new Error('Score cannot be taken until the end of the game')); }); - xit('should not calculate score before fill balls have been played', function() { - var rolls = [10, 10, 10, 10, 10, 10, 10, 10, 10, 10]; + xit('bonus roll for a spare in the last frame must be rolled before score can be calculated', function() { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3]; expect(function() { new Bowling(rolls).score(); }).toThrow( - new Error('Score cannot be taken until the end of the game') - ); + new Error('Score cannot be taken until the end of the game')); }); }); -}); +}); \ No newline at end of file From be106b90b0fc85954f00bf59b348bdb8de00999d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rub=C3=A9n=20Chavarr=C3=ADa?= Date: Mon, 19 Dec 2016 22:37:54 +0100 Subject: [PATCH 4/4] Fix typo: missing `t` --- docs/INSTALLATION.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 5e12e440..802b696b 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -6,7 +6,7 @@ There are at least two common options to run JavaScript code: the browsers and [ **Mac OS X users**: same as Windows users, you will find official installers on [Node.js downloads](https://nodejs.org/en/download/). Choose the LTS version. It will install Node.js and `npm` on your machine. -**Linux users**: there are binaries for `node` and `npm` tools on the Node.js downloads page, but the recommended way to install them on a Linux machine is via a package manager. As of writing this, the recommended version of Node.js to install is 4.x. To install it on a Debian or Ubuntu Linux distribuion just execute these commands: +**Linux users**: there are binaries for `node` and `npm` tools on the Node.js downloads page, but the recommended way to install them on a Linux machine is via a package manager. As of writing this, the recommended version of Node.js to install is 4.x. To install it on a Debian or Ubuntu Linux distribution just execute these commands: curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash - sudo apt-get install -y nodejs