diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..03223202 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +big-integer.js +exercises/grains/big-integer.js +exercises/grains/big-integer.spec.js diff --git a/.gitignore b/.gitignore index ee83fc8c..7af8849c 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ tmp bin/configlet bin/configlet.exe .idea + +*.js~ diff --git a/.travis.yml b/.travis.yml index e287b590..45fde31c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,12 +3,13 @@ language: node_js sudo: false node_js: - - 5.7 + - "lts/*" install: - - "npm install -g jasmine" + - "npm install" script: - "make test" - "./bin/fetch-configlet" - "./bin/configlet lint ." + - "npm run lint" diff --git a/README.md b/README.md index c724b208..4f5bffa2 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,3 @@ -# xJavaScript [![Build Status](https://travis-ci.org/exercism/xjavascript.svg?branch=master)](https://travis-ci.org/exercism/xjavascript) - -Exercism exercises in JavaScript - -## Installing - -To run the tests, you'll need NodeJS and Jasmine. For information about how to install these tools, see the [Javascript](http://exercism.io/languages/javascript/about) page. - -## Running Unit Test Suite - -The following commands assume that you are in the 'xjavascript' directory: - -### All Assignments - - % make test - -### Single Assignment - - % make test-assignment ASSIGNMENT=wordy - -## Contributing Guide - -Please see the [contributing guide](https://github.com/exercism/x-api/blob/master/CONTRIBUTING.md#the-exercise-data) - +# DEPRECATION NOTICE +This track is deprecated. Please see the https://github.com/exercism/javascript track. diff --git a/big-integer.js b/big-integer.js index 286518df..6f21af28 100644 --- a/big-integer.js +++ b/big-integer.js @@ -1 +1 @@ -var bigInt=function(e){"use strict";function o(e,t){this.value=e,this.sign=t,this.isSmall=!1}function u(e){this.value=e,this.sign=e<0,this.isSmall=!0}function a(e){return-r0?Math.floor(e):Math.ceil(e)}function d(e,n){var r=e.length,i=n.length,s=new Array(r),o=0,u=t,a,f;for(f=0;f=u?1:0,s[f]=a-o*u;while(f0&&s.push(o),s}function v(e,t){return e.length>=t.length?d(e,t):d(t,e)}function m(e,n){var r=e.length,i=new Array(r),s=t,o,u;for(u=0;u0)i[u++]=n%s,n=Math.floor(n/s);return i}function g(e,n){var r=e.length,i=n.length,s=new Array(r),o=0,u=t,a,f;for(a=0;a=0?r=g(e,t):(r=g(t,e),n=!n),r=l(r),typeof r=="number"?(n&&(r=-r),new u(r)):new o(r,n)}function b(e,n,r){var i=e.length,s=new Array(i),a=-n,f=t,c,h;for(c=0;c0)i[a++]=o%s,o=Math.floor(o/s);return i}function S(e,t){var n=[];while(t-->0)n.push(0);return n.concat(e)}function x(e,t){var n=Math.max(e.length,t.length);if(n<=400)return w(e,t);n=Math.ceil(n/2);var r=e.slice(n),i=e.slice(0,n),s=t.slice(n),o=t.slice(0,n),u=x(i,o),a=x(r,s),f=x(v(i,r),v(o,s));return v(v(u,S(g(g(f,u),a),n)),S(a,2*n))}function T(e){var n=e.length,r=h(n+n),i=t,s,o,u,a,f;for(u=0;u=0;d--){p=s-1,p=Math.floor((f[d+i]*s+f[d+i-1])/u),v=0,m=0,y=c.length;for(g=0;gi&&(c=(c+1)*u),a=Math.ceil(c/h);do{p=E(n,a);if(A(p,o)<=0)break;a--}while(a);s.push(a),o=g(o,p)}return s.reverse(),[l(s),l(o)]}function k(e,n){var r=e.length,i=h(r),s=t,o,u,a,f;a=0;for(o=r-1;o>=0;--o)f=a*s+e[o],u=p(f/n),a=f-u*n,i[o]=u|0;return[i,a|0]}function L(e,n){var r,i=z(n),s=e.value,a=i.value,c;if(a===0)throw new Error("Cannot divide by zero");if(e.isSmall)return i.isSmall?[new u(p(s/a)),new u(s%a)]:[W[0],e];if(i.isSmall){if(a===1)return[e,W[0]];if(a==-1)return[e.negate(),W[0]];var h=Math.abs(a);if(ht.length?1:-1;for(var n=e.length-1;n>=0;n--)if(e[n]!==t[n])return e[n]>t[n]?1:-1;return 0}function D(e){return(typeof e=="number"||typeof e=="string")&&+Math.abs(e)<=t||e instanceof o&&e.value.length<=1}function P(e,t,n){t=z(t);var r=e.isNegative(),i=t.isNegative(),s=r?e.not():e,o=i?t.not():t,u=[],a=[],f=!1,l=!1;while(!f||!l)s.isZero()?(f=!0,u.push(r?1:0)):r?u.push(s.isEven()?1:0):u.push(s.isEven()?0:1),o.isZero()?(l=!0,a.push(i?1:0)):i?a.push(o.isEven()?1:0):a.push(o.isEven()?0:1),s=s.over(2),o=o.over(2);var c=[];for(var h=0;h=0;c--){var h=f?s.value[c]:t,d=p(Math.random()*h);a.unshift(d),d"}function U(e,t){t=bigInt(t);if(t.isZero()){if(e.isZero())return"0";throw new Error("Cannot convert nonzero numbers to base 0.")}if(t.equals(-1))return e.isZero()?"0":e.isNegative()?(new Array(1-e)).join("10"):"1"+(new Array(+e)).join("01");var n="";e.isNegative()&&t.isPositive()&&(n="-",e=e.abs());if(t.equals(1))return e.isZero()?"0":n+(new Array(+e+1)).join(1);var r=[],i=e,s;while(i.isNegative()||i.compareAbs(t)>=0){s=i.divmod(t),i=s.quotient;var o=s.remainder;o.isNegative()&&(o=t.minus(o).abs(),i=i.next()),r.push(R(o))}return r.push(R(i)),n+r.reverse().join("")}function z(e){if(e instanceof o||e instanceof u)return e;if(typeof e=="number"){if(a(e))return new u(e);e=String(e)}if(typeof e=="string"){if(a(+e)){var t=+e;if(t===p(t))return new u(t);throw"Invalid integer: "+e}var r=e[0]==="-";r&&(e=e.slice(1));var i=e.split(/e/i);if(i.length>2)throw new Error("Invalid integer: "+f.join("e"));if(i.length===2){var s=i[1];s[0]==="+"&&(s=s.slice(1)),s=+s;if(s!==p(s)||!a(s))throw new Error("Invalid integer: "+s+" is not a valid exponent.");var f=i[0],l=f.indexOf(".");l>=0&&(s-=f.length-l,f=f.slice(0,l)+f.slice(l+1));if(s<0)throw new Error("Cannot include negative exponent part for integers");f+=(new Array(s+1)).join("0"),e=f}var h=/^([0-9][0-9]*)$/.test(e);if(!h)throw new Error("Invalid integer: "+e);var d=[],v=e.length,m=n,g=v-m;while(v>0)d.push(+e.slice(g,v)),g-=m,g<0&&(g=0),v-=m;return c(d),new o(d,r)}}var t=1e7,n=7,r=9007199254740992,i=f(r),s=Math.log(r);o.prototype.add=function(e){var t,n=z(e);if(this.sign!==n.sign)return this.subtract(n.negate());var r=this.value,i=n.value;return n.isSmall?new o(m(r,Math.abs(i)),this.sign):new o(v(r,i),this.sign)},o.prototype.plus=o.prototype.add,u.prototype.add=function(e){var t=z(e),n=this.value;if(n<0!==t.sign)return this.subtract(t.negate());var r=t.value;if(t.isSmall){if(a(n+r))return new u(n+r);r=f(Math.abs(r))}return new o(m(r,Math.abs(n)),n<0)},u.prototype.plus=u.prototype.add,o.prototype.subtract=function(e){var t=z(e);if(this.sign!==t.sign)return this.add(t.negate());var n=this.value,r=t.value;return t.isSmall?b(n,Math.abs(r),this.sign):y(n,r,this.sign)},o.prototype.minus=o.prototype.subtract,u.prototype.subtract=function(e){var t=z(e),n=this.value;if(n<0!==t.sign)return this.add(t.negate());var r=t.value;return t.isSmall?new u(n-r):b(r,Math.abs(n),n>=0)},u.prototype.minus=u.prototype.subtract,o.prototype.negate=function(){return new o(this.value,!this.sign)},u.prototype.negate=function(){var e=this.sign,t=new u(-this.value);return t.sign=!e,t},o.prototype.abs=function(){return new o(this.value,!1)},u.prototype.abs=function(){return new u(Math.abs(this.value))},o.prototype.multiply=function(e){var n,r=z(e),i=this.value,s=r.value,u=this.sign!==r.sign,a;if(r.isSmall){if(s===0)return W[0];if(s===1)return this;if(s===-1)return this.negate();a=Math.abs(s);if(a4e3?new o(x(i,s),u):new o(w(i,s),u)},o.prototype.times=o.prototype.multiply,u.prototype.multiply=function(e){var n=z(e),r=this.value,i=n.value;if(r===0)return W[0];if(r===1)return n;if(r===-1)return n.negate();if(n.isSmall){if(a(r*i))return new u(r*i);i=f(Math.abs(i))}var s=Math.abs(r);return sr?1:-1):-1},o.prototype.compare=function(e){var t=z(e),n=this.value,r=t.value;return this.sign!==t.sign?t.sign?1:-1:t.isSmall?this.sign?-1:1:A(n,r)*(this.sign?-1:1)},o.prototype.compareTo=o.prototype.compare,u.prototype.compare=function(e){var t=z(e),n=this.value,r=t.value;return t.isSmall?n==r?0:n>r?1:-1:n<0!==t.sign?n<0?-1:1:n<0?1:-1},u.prototype.compareTo=u.prototype.compare,o.prototype.equals=function(e){return this.compare(e)===0},u.prototype.eq=u.prototype.equals=o.prototype.eq=o.prototype.equals,o.prototype.notEquals=function(e){return this.compare(e)!==0},u.prototype.neq=u.prototype.notEquals=o.prototype.neq=o.prototype.notEquals,o.prototype.greater=function(e){return this.compare(e)>0},u.prototype.gt=u.prototype.greater=o.prototype.gt=o.prototype.greater,o.prototype.lesser=function(e){return this.compare(e)<0},u.prototype.lt=u.prototype.lesser=o.prototype.lt=o.prototype.lesser,o.prototype.greaterOrEquals=function(e){return this.compare(e)>=0},u.prototype.geq=u.prototype.greaterOrEquals=o.prototype.geq=o.prototype.greaterOrEquals,o.prototype.lesserOrEquals=function(e){return this.compare(e)<=0},u.prototype.leq=u.prototype.lesserOrEquals=o.prototype.leq=o.prototype.lesserOrEquals,o.prototype.isEven=function(){return(this.value[0]&1)===0},u.prototype.isEven=function(){return(this.value&1)===0},o.prototype.isOdd=function(){return(this.value[0]&1)===1},u.prototype.isOdd=function(){return(this.value&1)===1},o.prototype.isPositive=function(){return!this.sign},u.prototype.isPositive=function(){return this.value>0},o.prototype.isNegative=function(){return this.sign},u.prototype.isNegative=function(){return this.value<0},o.prototype.isUnit=function(){return!1},u.prototype.isUnit=function(){return Math.abs(this.value)===1},o.prototype.isZero=function(){return!1},u.prototype.isZero=function(){return this.value===0},o.prototype.isDivisibleBy=function(e){var t=z(e),n=t.value;return n===0?!1:n===1?!0:n===2?this.isEven():this.mod(t).equals(W[0])},u.prototype.isDivisibleBy=o.prototype.isDivisibleBy,o.prototype.isPrime=function(){var e=this.abs(),t=e.prev();if(e.isUnit())return!1;if(e.equals(2)||e.equals(3)||e.equals(5))return!0;if(e.isEven()||e.isDivisibleBy(3)||e.isDivisibleBy(5))return!1;if(e.lesser(25))return!0;var n=[2,3,5,7,11,13,17,19],r=t,i,s,o,u;while(r.isEven())r=r.divide(2);for(o=0;o-r?new u(e-1):new o(i,!0)};var O=[1];while(O[O.length-1]<=t)O.push(2*O[O.length-1]);var M=O.length,_=O[M-1];o.prototype.shiftLeft=function(e){if(!D(e))return e.isNegative()?this.shiftRight(e.abs()):this.times(W[2].pow(e));e=+e;if(e<0)return this.shiftRight(-e);var t=this;while(e>=M)t=t.multiply(_),e-=M-1;return t.multiply(O[e])},u.prototype.shiftLeft=o.prototype.shiftLeft,o.prototype.shiftRight=function(e){var t;if(!D(e))return e.isNegative()?this.shiftLeft(e.abs()):(t=this.divmod(W[2].pow(e)),t.remainder.isNegative()?t.quotient.prev():t.quotient);e=+e;if(e<0)return this.shiftLeft(-e);var n=this;while(e>=M){if(n.isZero())return n;t=L(n,_),n=t[1].isNegative()?t[0].prev():t[0],e-=M-1}return t=L(n,O[e]),t[1].isNegative()?t[0].prev():t[0]},u.prototype.shiftRight=o.prototype.shiftRight,o.prototype.not=function(){return this.negate().prev()},u.prototype.not=o.prototype.not,o.prototype.and=function(e){return P(this,e,function(e,t){return e&t})},u.prototype.and=o.prototype.and,o.prototype.or=function(e){return P(this,e,function(e,t){return e|t})},u.prototype.or=o.prototype.or,o.prototype.xor=function(e){return P(this,e,function(e,t){return e^t})},u.prototype.xor=o.prototype.xor;var q=function(e,t){var n=W[0],r=W[1],i=e.length;if(2<=t&&t<=36&&i<=s/Math.log(t))return new u(parseInt(e,t));t=z(t);var o=[],a,f=e[0]==="-";for(a=f?1:0;a");o.push(z(e.slice(h+1,a)))}}o.reverse();for(a=0;a=0)o=String(n[r]),i+=s.slice(o.length)+o;var u=this.sign?"-":"";return u+i},u.prototype.toString=function(t){return t===e&&(t=10),t!=10?U(this,t):String(this.value)},o.prototype.valueOf=function(){return+this.toString()},o.prototype.toJSNumber=o.prototype.valueOf,u.prototype.valueOf=function(){return this.value},u.prototype.toJSNumber=u.prototype.valueOf;var W=function(e,t){return typeof e=="undefined"?W[0]:typeof t!="undefined"?+t===10?z(e):q(e,t):z(e)};for(var X=0;X<1e3;X++)W[X]=new u(X),X>0&&(W[-X]=new u(-X));return W.one=W[1],W.zero=W[0],W.minusOne=W[-1],W.max=H,W.min=B,W.gcd=j,W.lcm=F,W.isInstance=function(e){return e instanceof o||e instanceof u},W.randBetween=I,W}();typeof module!="undefined"&&module.hasOwnProperty("exports")&&(module.exports=bigInt); \ No newline at end of file +var bigInt = (function (e) {'use strict'; function o(e, t) {this.value = e, this.sign = t, this.isSmall = !1;} function u(e) {this.value = e, this.sign = e < 0, this.isSmall = !0;} function a(e) {return -r < e && e < r;} function f(e) {return e < 1e7 ? [e] : e < 1e14 ? [e % 1e7, Math.floor(e / 1e7)] : [e % 1e7, Math.floor(e / 1e7) % 1e7, Math.floor(e / 1e14)];} function l(e) {c(e); var n = e.length; if (n < 4 && A(e, i) < 0) switch (n) {case 0:return 0; case 1:return e[0]; case 2:return e[0] + e[1] * t; default:return e[0] + (e[1] + e[2] * t) * t;} return e;} function c(e) {var t = e.length; while (e[--t] === 0);e.length = t + 1;} function h(e) {var t = new Array(e), n = -1; while (++n < e)t[n] = 0; return t;} function p(e) {return e > 0 ? Math.floor(e) : Math.ceil(e);} function d(e, n) {var r = e.length, i = n.length, s = new Array(r), o = 0, u = t, a, f; for (f = 0; f < i; f++)a = e[f] + n[f] + o, o = a >= u ? 1 : 0, s[f] = a - o * u; while (f < r)a = e[f] + o, o = a === u ? 1 : 0, s[f++] = a - o * u; return o > 0 && s.push(o), s;} function v(e, t) {return e.length >= t.length ? d(e, t) : d(t, e);} function m(e, n) {var r = e.length, i = new Array(r), s = t, o, u; for (u = 0; u < r; u++)o = e[u] - s + n, n = Math.floor(o / s), i[u] = o - n * s, n += 1; while (n > 0)i[u++] = n % s, n = Math.floor(n / s); return i;} function g(e, n) {var r = e.length, i = n.length, s = new Array(r), o = 0, u = t, a, f; for (a = 0; a < i; a++)f = e[a] - o - n[a], f < 0 ? (f += u, o = 1) : o = 0, s[a] = f; for (a = i; a < r; a++) {f = e[a] - o; if (!(f < 0)) {s[a++] = f; break;}f += u, s[a] = f;} for (;a < r; a++)s[a] = e[a]; return c(s), s;} function y(e, t, n) {var r, i; return A(e, t) >= 0 ? r = g(e, t) : (r = g(t, e), n = !n), r = l(r), typeof r === 'number' ? (n && (r = -r), new u(r)) : new o(r, n);} function b(e, n, r) {var i = e.length, s = new Array(i), a = -n, f = t, c, h; for (c = 0; c < i; c++)h = e[c] + a, a = Math.floor(h / f), s[c] = h < 0 ? h % f + f : h; return s = l(s), typeof s === 'number' ? (r && (s = -s), new u(s)) : new o(s, r);} function w(e, n) {var r = e.length, i = n.length, s = r + i, o = h(s), u = t, a, f, l, p, d; for (l = 0; l < r; ++l) {p = e[l]; for (var v = 0; v < i; ++v)d = n[v], a = p * d + o[l + v], f = Math.floor(a / u), o[l + v] = a - f * u, o[l + v + 1] += f;} return c(o), o;} function E(e, n) {var r = e.length, i = new Array(r), s = t, o = 0, u, a; for (a = 0; a < r; a++)u = e[a] * n + o, o = Math.floor(u / s), i[a] = u - o * s; while (o > 0)i[a++] = o % s, o = Math.floor(o / s); return i;} function S(e, t) {var n = []; while (t-- > 0)n.push(0); return n.concat(e);} function x(e, t) {var n = Math.max(e.length, t.length); if (n <= 400) return w(e, t); n = Math.ceil(n / 2); var r = e.slice(n), i = e.slice(0, n), s = t.slice(n), o = t.slice(0, n), u = x(i, o), a = x(r, s), f = x(v(i, r), v(o, s)); return v(v(u, S(g(g(f, u), a), n)), S(a, 2 * n));} function T(e) {var n = e.length, r = h(n + n), i = t, s, o, u, a, f; for (u = 0; u < n; u++) {a = e[u]; for (var l = 0; l < n; l++)f = e[l], s = a * f + r[u + l], o = Math.floor(s / i), r[u + l] = s - o * i, r[u + l + 1] += o;} return c(r), r;} function N(e, n) {var r = e.length, i = n.length, s = t, o = h(n.length), u = n[i - 1], a = Math.ceil(s / (2 * u)), f = E(e, a), c = E(n, a), p, d, v, m, g, y, b; f.length <= r && f.push(0), c.push(0), u = c[i - 1]; for (d = r - i; d >= 0; d--) {p = s - 1, p = Math.floor((f[d + i] * s + f[d + i - 1]) / u), v = 0, m = 0, y = c.length; for (g = 0; g < y; g++)v += p * c[g], b = Math.floor(v / s), m += f[d + g] - (v - b * s), v = b, m < 0 ? (f[d + g] = m + s, m = -1) : (f[d + g] = m, m = 0); while (m !== 0) {p -= 1, v = 0; for (g = 0; g < y; g++)v += f[d + g] - s + c[g], v < 0 ? (f[d + g] = v + s, v = 0) : (f[d + g] = v, v = 1); m += v;}o[d] = p;} return f = k(f, a)[0], [l(o), l(f)];} function C(e, n) {var r = e.length, i = n.length, s = [], o = [], u = t, a, f, c, h, p; while (r) {o.unshift(e[--r]); if (A(o, n) < 0) {s.push(0); continue;}f = o.length, c = o[f - 1] * u + o[f - 2], h = n[i - 1] * u + n[i - 2], f > i && (c = (c + 1) * u), a = Math.ceil(c / h); do {p = E(n, a); if (A(p, o) <= 0) break; a--;} while (a);s.push(a), o = g(o, p);} return s.reverse(), [l(s), l(o)];} function k(e, n) {var r = e.length, i = h(r), s = t, o, u, a, f; a = 0; for (o = r - 1; o >= 0; --o)f = a * s + e[o], u = p(f / n), a = f - u * n, i[o] = u | 0; return [i, a | 0];} function L(e, n) {var r, i = z(n), s = e.value, a = i.value, c; if (a === 0) throw new Error('Cannot divide by zero'); if (e.isSmall) return i.isSmall ? [new u(p(s / a)), new u(s % a)] : [W[0], e]; if (i.isSmall) {if (a === 1) return [e, W[0]]; if (a == -1) return [e.negate(), W[0]]; var h = Math.abs(a); if (h < t) {r = k(s, h), c = l(r[0]); var d = r[1]; return e.sign && (d = -d), typeof c === 'number' ? (e.sign !== i.sign && (c = -c), [new u(c), new u(d)]) : [new o(c, e.sign !== i.sign), new u(d)];}a = f(h);} var v = A(s, a); if (v === -1) return [W[0], e]; if (v === 0) return [W[e.sign === i.sign ? 1 : -1], W[0]]; s.length + a.length <= 200 ? r = N(s, a) : r = C(s, a), c = r[0]; var m = e.sign !== i.sign, g = r[1], y = e.sign; return typeof c === 'number' ? (m && (c = -c), c = new u(c)) : c = new o(c, m), typeof g === 'number' ? (y && (g = -g), g = new u(g)) : g = new o(g, y), [c, g];} function A(e, t) {if (e.length !== t.length) return e.length > t.length ? 1 : -1; for (var n = e.length - 1; n >= 0; n--) if (e[n] !== t[n]) return e[n] > t[n] ? 1 : -1; return 0;} function D(e) {return (typeof e === 'number' || typeof e === 'string') && +Math.abs(e) <= t || e instanceof o && e.value.length <= 1;} function P(e, t, n) {t = z(t); var r = e.isNegative(), i = t.isNegative(), s = r ? e.not() : e, o = i ? t.not() : t, u = [], a = [], f = !1, l = !1; while (!f || !l)s.isZero() ? (f = !0, u.push(r ? 1 : 0)) : r ? u.push(s.isEven() ? 1 : 0) : u.push(s.isEven() ? 0 : 1), o.isZero() ? (l = !0, a.push(i ? 1 : 0)) : i ? a.push(o.isEven() ? 1 : 0) : a.push(o.isEven() ? 0 : 1), s = s.over(2), o = o.over(2); var c = []; for (var h = 0; h < u.length; h++)c.push(n(u[h], a[h])); var p = bigInt(c.pop()).negate().times(bigInt(2).pow(c.length)); while (c.length)p = p.add(bigInt(c.pop()).times(bigInt(2).pow(c.length))); return p;} function H(e, t) {return e = z(e), t = z(t), e.greater(t) ? e : t;} function B(e, t) {return e = z(e), t = z(t), e.lesser(t) ? e : t;} function j(e, t) {return e = z(e).abs(), t = z(t).abs(), e.equals(t) ? e : e.isZero() ? t : t.isZero() ? e : e.isEven() ? t.isOdd() ? j(e.divide(2), t) : j(e.divide(2), t.divide(2)).multiply(2) : t.isEven() ? j(e, t.divide(2)) : e.greater(t) ? j(e.subtract(t).divide(2), t) : j(t.subtract(e).divide(2), e);} function F(e, t) {return e = z(e).abs(), t = z(t).abs(), e.multiply(t).divide(j(e, t));} function I(e, n) {e = z(e), n = z(n); var r = B(e, n), i = H(e, n), s = i.subtract(r); if (s.isSmall) return r.add(Math.random() * s); var u = s.value.length - 1, a = [], f = !0; for (var c = u; c >= 0; c--) {var h = f ? s.value[c] : t, d = p(Math.random() * h); a.unshift(d), d < h && (f = !1);} return a = l(a), r.add(new o(a, !1, typeof a === 'number'));} function R(e) {var t = e.value; return typeof t === 'number' && (t = [t]), t.length === 1 && t[0] <= 36 ? '0123456789abcdefghijklmnopqrstuvwxyz'.charAt(t[0]) : '<' + t + '>';} function U(e, t) {t = bigInt(t); if (t.isZero()) {if (e.isZero()) return '0'; throw new Error('Cannot convert nonzero numbers to base 0.');} if (t.equals(-1)) return e.isZero() ? '0' : e.isNegative() ? (new Array(1 - e)).join('10') : '1' + (new Array(+e)).join('01'); var n = ''; e.isNegative() && t.isPositive() && (n = '-', e = e.abs()); if (t.equals(1)) return e.isZero() ? '0' : n + (new Array(+e + 1)).join(1); var r = [], i = e, s; while (i.isNegative() || i.compareAbs(t) >= 0) {s = i.divmod(t), i = s.quotient; var o = s.remainder; o.isNegative() && (o = t.minus(o).abs(), i = i.next()), r.push(R(o));} return r.push(R(i)), n + r.reverse().join('');} function z(e) {if (e instanceof o || e instanceof u) return e; if (typeof e === 'number') {if (a(e)) return new u(e); e = String(e);} if (typeof e === 'string') {if (a(+e)) {var t = +e; if (t === p(t)) return new u(t); throw 'Invalid integer: ' + e;} var r = e[0] === '-'; r && (e = e.slice(1)); var i = e.split(/e/i); if (i.length > 2) throw new Error('Invalid integer: ' + f.join('e')); if (i.length === 2) {var s = i[1]; s[0] === '+' && (s = s.slice(1)), s = +s; if (s !== p(s) || !a(s)) throw new Error('Invalid integer: ' + s + ' is not a valid exponent.'); var f = i[0], l = f.indexOf('.'); l >= 0 && (s -= f.length - l, f = f.slice(0, l) + f.slice(l + 1)); if (s < 0) throw new Error('Cannot include negative exponent part for integers'); f += (new Array(s + 1)).join('0'), e = f;} var h = /^([0-9][0-9]*)$/.test(e); if (!h) throw new Error('Invalid integer: ' + e); var d = [], v = e.length, m = n, g = v - m; while (v > 0)d.push(+e.slice(g, v)), g -= m, g < 0 && (g = 0), v -= m; return c(d), new o(d, r);}} var t = 1e7, n = 7, r = 9007199254740992, i = f(r), s = Math.log(r); o.prototype.add = function (e) {var t, n = z(e); if (this.sign !== n.sign) return this.subtract(n.negate()); var r = this.value, i = n.value; return n.isSmall ? new o(m(r, Math.abs(i)), this.sign) : new o(v(r, i), this.sign);}, o.prototype.plus = o.prototype.add, u.prototype.add = function (e) {var t = z(e), n = this.value; if (n < 0 !== t.sign) return this.subtract(t.negate()); var r = t.value; if (t.isSmall) {if (a(n + r)) return new u(n + r); r = f(Math.abs(r));} return new o(m(r, Math.abs(n)), n < 0);}, u.prototype.plus = u.prototype.add, o.prototype.subtract = function (e) {var t = z(e); if (this.sign !== t.sign) return this.add(t.negate()); var n = this.value, r = t.value; return t.isSmall ? b(n, Math.abs(r), this.sign) : y(n, r, this.sign);}, o.prototype.minus = o.prototype.subtract, u.prototype.subtract = function (e) {var t = z(e), n = this.value; if (n < 0 !== t.sign) return this.add(t.negate()); var r = t.value; return t.isSmall ? new u(n - r) : b(r, Math.abs(n), n >= 0);}, u.prototype.minus = u.prototype.subtract, o.prototype.negate = function () {return new o(this.value, !this.sign);}, u.prototype.negate = function () {var e = this.sign, t = new u(-this.value); return t.sign = !e, t;}, o.prototype.abs = function () {return new o(this.value, !1);}, u.prototype.abs = function () {return new u(Math.abs(this.value));}, o.prototype.multiply = function (e) {var n, r = z(e), i = this.value, s = r.value, u = this.sign !== r.sign, a; if (r.isSmall) {if (s === 0) return W[0]; if (s === 1) return this; if (s === -1) return this.negate(); a = Math.abs(s); if (a < t) return new o(E(i, a), u); s = f(a);} return i.length + s.length > 4e3 ? new o(x(i, s), u) : new o(w(i, s), u);}, o.prototype.times = o.prototype.multiply, u.prototype.multiply = function (e) {var n = z(e), r = this.value, i = n.value; if (r === 0) return W[0]; if (r === 1) return n; if (r === -1) return n.negate(); if (n.isSmall) {if (a(r * i)) return new u(r * i); i = f(Math.abs(i));} var s = Math.abs(r); return s < t ? new o(E(i, s), this.sign !== n.sign) : new o(w(i, f(s)), this.sign !== n.sign);}, u.prototype.times = u.prototype.multiply, o.prototype.square = function () {return new o(T(this.value), !1);}, u.prototype.square = function () {var e = this.value * this.value; return a(e) ? new u(e) : new o(T(f(Math.abs(this.value))), !1);}, o.prototype.divmod = function (e) {var t = L(this, e); return {quotient: t[0], remainder: t[1]};}, u.prototype.divmod = o.prototype.divmod, o.prototype.divide = function (e) {return L(this, e)[0];}, u.prototype.over = u.prototype.divide = o.prototype.over = o.prototype.divide, o.prototype.mod = function (e) {return L(this, e)[1];}, u.prototype.remainder = u.prototype.mod = o.prototype.remainder = o.prototype.mod, o.prototype.pow = function (e) {var t = z(e), n = this.value, r = t.value, i, s, o; if (r === 0) return W[1]; if (n === 0) return W[0]; if (n === 1) return W[1]; if (n === -1) return t.isEven() ? W[1] : W[-1]; if (t.sign) return W[0]; if (!t.isSmall) throw new Error('The exponent ' + t.toString() + ' is too large.'); if (this.isSmall && a(i = Math.pow(n, r))) return new u(p(i)); s = this, o = W[1]; for (;;) {r & !0 && (o = o.times(s), --r); if (r === 0) break; r /= 2, s = s.square();} return o;}, u.prototype.pow = o.prototype.pow, o.prototype.modPow = function (e, t) {e = z(e), t = z(t); if (t.isZero()) throw new Error('Cannot take modPow with modulus 0'); var n = W[1], r = this.mod(t); if (r.isZero()) return W[0]; while (e.isPositive())e.isOdd() && (n = n.multiply(r).mod(t)), e = e.divide(2), r = r.square().mod(t); return n;}, u.prototype.modPow = o.prototype.modPow, o.prototype.compareAbs = function (e) {var t = z(e), n = this.value, r = t.value; return t.isSmall ? 1 : A(n, r);}, u.prototype.compareAbs = function (e) {var t = z(e), n = Math.abs(this.value), r = t.value; return t.isSmall ? (r = Math.abs(r), n === r ? 0 : n > r ? 1 : -1) : -1;}, o.prototype.compare = function (e) {var t = z(e), n = this.value, r = t.value; return this.sign !== t.sign ? t.sign ? 1 : -1 : t.isSmall ? this.sign ? -1 : 1 : A(n, r) * (this.sign ? -1 : 1);}, o.prototype.compareTo = o.prototype.compare, u.prototype.compare = function (e) {var t = z(e), n = this.value, r = t.value; return t.isSmall ? n == r ? 0 : n > r ? 1 : -1 : n < 0 !== t.sign ? n < 0 ? -1 : 1 : n < 0 ? 1 : -1;}, u.prototype.compareTo = u.prototype.compare, o.prototype.equals = function (e) {return this.compare(e) === 0;}, u.prototype.eq = u.prototype.equals = o.prototype.eq = o.prototype.equals, o.prototype.notEquals = function (e) {return this.compare(e) !== 0;}, u.prototype.neq = u.prototype.notEquals = o.prototype.neq = o.prototype.notEquals, o.prototype.greater = function (e) {return this.compare(e) > 0;}, u.prototype.gt = u.prototype.greater = o.prototype.gt = o.prototype.greater, o.prototype.lesser = function (e) {return this.compare(e) < 0;}, u.prototype.lt = u.prototype.lesser = o.prototype.lt = o.prototype.lesser, o.prototype.greaterOrEquals = function (e) {return this.compare(e) >= 0;}, u.prototype.geq = u.prototype.greaterOrEquals = o.prototype.geq = o.prototype.greaterOrEquals, o.prototype.lesserOrEquals = function (e) {return this.compare(e) <= 0;}, u.prototype.leq = u.prototype.lesserOrEquals = o.prototype.leq = o.prototype.lesserOrEquals, o.prototype.isEven = function () {return (this.value[0] & 1) === 0;}, u.prototype.isEven = function () {return (this.value & 1) === 0;}, o.prototype.isOdd = function () {return (this.value[0] & 1) === 1;}, u.prototype.isOdd = function () {return (this.value & 1) === 1;}, o.prototype.isPositive = function () {return !this.sign;}, u.prototype.isPositive = function () {return this.value > 0;}, o.prototype.isNegative = function () {return this.sign;}, u.prototype.isNegative = function () {return this.value < 0;}, o.prototype.isUnit = function () {return !1;}, u.prototype.isUnit = function () {return Math.abs(this.value) === 1;}, o.prototype.isZero = function () {return !1;}, u.prototype.isZero = function () {return this.value === 0;}, o.prototype.isDivisibleBy = function (e) {var t = z(e), n = t.value; return n === 0 ? !1 : n === 1 ? !0 : n === 2 ? this.isEven() : this.mod(t).equals(W[0]);}, u.prototype.isDivisibleBy = o.prototype.isDivisibleBy, o.prototype.isPrime = function () {var e = this.abs(), t = e.prev(); if (e.isUnit()) return !1; if (e.equals(2) || e.equals(3) || e.equals(5)) return !0; if (e.isEven() || e.isDivisibleBy(3) || e.isDivisibleBy(5)) return !1; if (e.lesser(25)) return !0; var n = [2, 3, 5, 7, 11, 13, 17, 19], r = t, i, s, o, u; while (r.isEven())r = r.divide(2); for (o = 0; o < n.length; o++) {u = bigInt(n[o]).modPow(r, e); if (u.equals(W[1]) || u.equals(t)) continue; for (s = !0, i = r; s && i.lesser(t); i = i.multiply(2))u = u.square().mod(e), u.equals(t) && (s = !1); if (s) return !1;} return !0;}, u.prototype.isPrime = o.prototype.isPrime, o.prototype.next = function () {var e = this.value; return this.sign ? b(e, 1, this.sign) : new o(m(e, 1), this.sign);}, u.prototype.next = function () {var e = this.value; return e + 1 < r ? new u(e + 1) : new o(i, !1);}, o.prototype.prev = function () {var e = this.value; return this.sign ? new o(m(e, 1), !0) : b(e, 1, this.sign);}, u.prototype.prev = function () {var e = this.value; return e - 1 > -r ? new u(e - 1) : new o(i, !0);}; var O = [1]; while (O[O.length - 1] <= t)O.push(2 * O[O.length - 1]); var M = O.length, _ = O[M - 1]; o.prototype.shiftLeft = function (e) {if (!D(e)) return e.isNegative() ? this.shiftRight(e.abs()) : this.times(W[2].pow(e)); e = +e; if (e < 0) return this.shiftRight(-e); var t = this; while (e >= M)t = t.multiply(_), e -= M - 1; return t.multiply(O[e]);}, u.prototype.shiftLeft = o.prototype.shiftLeft, o.prototype.shiftRight = function (e) {var t; if (!D(e)) return e.isNegative() ? this.shiftLeft(e.abs()) : (t = this.divmod(W[2].pow(e)), t.remainder.isNegative() ? t.quotient.prev() : t.quotient); e = +e; if (e < 0) return this.shiftLeft(-e); var n = this; while (e >= M) {if (n.isZero()) return n; t = L(n, _), n = t[1].isNegative() ? t[0].prev() : t[0], e -= M - 1;} return t = L(n, O[e]), t[1].isNegative() ? t[0].prev() : t[0];}, u.prototype.shiftRight = o.prototype.shiftRight, o.prototype.not = function () {return this.negate().prev();}, u.prototype.not = o.prototype.not, o.prototype.and = function (e) {return P(this, e, function (e, t) {return e & t;});}, u.prototype.and = o.prototype.and, o.prototype.or = function (e) {return P(this, e, function (e, t) {return e | t;});}, u.prototype.or = o.prototype.or, o.prototype.xor = function (e) {return P(this, e, function (e, t) {return e ^ t;});}, u.prototype.xor = o.prototype.xor; var q = function (e, t) {var n = W[0], r = W[1], i = e.length; if (t >= 2 && t <= 36 && i <= s / Math.log(t)) return new u(parseInt(e, t)); t = z(t); var o = [], a, f = e[0] === '-'; for (a = f ? 1 : 0; a < e.length; a++) {var l = e[a].toLowerCase(), c = l.charCodeAt(0); if (c >= 48 && c <= 57)o.push(z(l)); else if (c >= 97 && c <= 122)o.push(z(l.charCodeAt(0) - 87)); else {if (l !== '<') throw new Error(l + ' is not a valid character'); var h = a; do a++; while (e[a] !== '>');o.push(z(e.slice(h + 1, a)));}}o.reverse(); for (a = 0; a < o.length; a++)n = n.add(o[a].times(r)), r = r.times(t); return f ? n.negate() : n;}; o.prototype.toString = function (t) {t === e && (t = 10); if (t !== 10) return U(this, t); var n = this.value, r = n.length, i = String(n[--r]), s = '0000000', o; while (--r >= 0)o = String(n[r]), i += s.slice(o.length) + o; var u = this.sign ? '-' : ''; return u + i;}, u.prototype.toString = function (t) {return t === e && (t = 10), t != 10 ? U(this, t) : String(this.value);}, o.prototype.valueOf = function () {return +this.toString();}, o.prototype.toJSNumber = o.prototype.valueOf, u.prototype.valueOf = function () {return this.value;}, u.prototype.toJSNumber = u.prototype.valueOf; var W = function (e, t) {return typeof e === 'undefined' ? W[0] : typeof t !== 'undefined' ? +t === 10 ? z(e) : q(e, t) : z(e);}; for (var X = 0; X < 1e3; X++)W[X] = new u(X), X > 0 && (W[-X] = new u(-X)); return W.one = W[1], W.zero = W[0], W.minusOne = W[-1], W.max = H, W.min = B, W.gcd = j, W.lcm = F, W.isInstance = function (e) {return e instanceof o || e instanceof u;}, W.randBetween = I, W;}()); typeof module !== 'undefined' && module.hasOwnProperty('exports') && (module.exports = bigInt); diff --git a/config.json b/config.json index 429f6697..e11dd1f6 100644 --- a/config.json +++ b/config.json @@ -1,1048 +1,1288 @@ { - "language": "JavaScript", - "active": true, + "language": "JavaScript (Legacy)", + "active": false, + "blurb": "JavaScript is a scripting language, primarily used for creating dynamic websites and programming web servers. It's a very popular language, and supports a variety of programming paradigms.", "test_pattern": ".*[.]spec[.]js$", "exercises": [ { - "uuid": "4756cfc9-7509-4783-8be7-60e3376b8256", "slug": "hello-world", + "uuid": "4756cfc9-7509-4783-8be7-60e3376b8256", "core": true, + "unlocked_by": null, "difficulty": 1, "topics": [ - "Control-flow (conditionals)", - "Optional values", - "Strings", - "Text formatting" + "control_flow_conditionals", + "optional_values", + "strings", + "text_formatting" + ] + }, + { + "slug": "two-fer", + "uuid": "5f3d1326-f0c5-44a6-b90a-6af3b7d455f1", + "core": false, + "unlocked_by": "hello-world", + "difficulty": 1, + "topics": [ + "control_flow_conditionals", + "strings" ] }, { - "uuid": "0c231a1c-55f7-47b6-8a54-ccae4ab0c65b", "slug": "leap", + "uuid": "0c231a1c-55f7-47b6-8a54-ccae4ab0c65b", "core": true, + "unlocked_by": null, "difficulty": 1, "topics": [ - "Booleans", - "Integers", - "Logic" + "booleans", + "integers", + "logic" + ] + }, + { + "slug": "reverse-string", + "uuid": "553a6be7-eecb-45dc-9cea-05126c525f1b", + "core": false, + "unlocked_by": "leap", + "difficulty": 2, + "topics": [ + "for", + "loops", + "strings" ] }, { - "uuid": "d7f57ab9-2edb-44cb-a04e-c575c0f4be4c", "slug": "rna-transcription", + "uuid": "d7f57ab9-2edb-44cb-a04e-c575c0f4be4c", "core": true, + "unlocked_by": null, "difficulty": 1, "topics": [ - "Strings", - "Transforming" + "strings", + "transforming" ] }, { - "uuid": "fff57c49-cde9-4a0c-b70b-2903cef212af", "slug": "simple-cipher", + "uuid": "fff57c49-cde9-4a0c-b70b-2903cef212af", "core": true, + "unlocked_by": null, "difficulty": 1, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Algorithms", - "Mathematics", - "Strings", - "Randomness", - "Text formatting", - "Transforming" + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "mathematics", + "randomness", + "strings", + "text_formatting", + "transforming" ] }, { - "uuid": "c57bf909-130f-46e6-97ca-aeed58df1a15", "slug": "pangram", + "uuid": "c57bf909-130f-46e6-97ca-aeed58df1a15", "core": true, + "unlocked_by": null, "difficulty": 2, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Lists", - "Strings", - "Maps", - "Algorithms", - "Searching" + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "lists", + "maps", + "searching", + "strings" ] }, { - "uuid": "246be5d9-b361-4893-9707-f218ede2bed6", "slug": "bob", + "uuid": "246be5d9-b361-4893-9707-f218ede2bed6", "core": true, + "unlocked_by": null, "difficulty": 2, "topics": [ - "Control flow (conditionals)", - "Polymorfism", - "Strings", - "Unicode", - "Pattern recognition", - "Regular expressions" + "control_flow_conditionals", + "pattern_recognition", + "polymorfism", + "regular_expressions", + "strings", + "unicode" ] }, { - "uuid": "49e4874b-d7e2-4305-a9bc-627fab4ada44", "slug": "gigasecond", + "uuid": "49e4874b-d7e2-4305-a9bc-627fab4ada44", "core": true, + "unlocked_by": null, "difficulty": 2, "topics": [ - "Time" + "time" ] }, { - "uuid": "b668e11a-a8ce-4e94-ba68-3a1f0fa3f6c8", "slug": "space-age", + "uuid": "b668e11a-a8ce-4e94-ba68-3a1f0fa3f6c8", "core": true, + "unlocked_by": null, "difficulty": 3, "topics": [ - "Classes", - "Floating-point numbers", - "Mathematics" + "classes", + "floating_point_numbers", + "mathematics" ] }, { - "uuid": "c3035180-ff4c-4afe-8019-f8364158b74e", "slug": "binary", + "uuid": "c3035180-ff4c-4afe-8019-f8364158b74e", "core": true, + "unlocked_by": null, "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Integers", - "Strings", - "Regular expressions", - "Exception handling" + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "integers", + "mathematics", + "regular_expressions", + "strings" ] }, { - "uuid": "73ecd6c2-e59b-4354-b305-64e28a60433f", "slug": "prime-factors", + "uuid": "73ecd6c2-e59b-4354-b305-64e28a60433f", "core": true, + "unlocked_by": null, "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Algorithms", - "Integers" + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics" ] }, { - "uuid": "fbfe6032-c209-40bd-b485-8b2881638166", "slug": "matrix", + "uuid": "fbfe6032-c209-40bd-b485-8b2881638166", "core": true, + "unlocked_by": null, "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Data structures", - "Arrays", - "Matrices", - "Text formatting" + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "data_structures", + "matrices", + "text_formatting" ] }, { - "uuid": "ecc41237-f629-458f-873e-2cc51ba1a385", "slug": "linked-list", + "uuid": "ecc41237-f629-458f-873e-2cc51ba1a385", "core": true, + "unlocked_by": null, "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Algorithms", - "Data structures", - "Arrays", - "Lists", - "Optional values" + "algorithms", + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "data_structures", + "lists", + "optional_values" ] }, { - "uuid": "a96ab45d-10a0-42cf-a754-c2466037ceaf", "slug": "pascals-triangle", + "uuid": "a96ab45d-10a0-42cf-a754-c2466037ceaf", "core": true, + "unlocked_by": null, "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Strings", - "Text formatting" + "control_flow_conditionals", + "control_flow_loops", + "mathematics", + "strings", + "text_formatting" ] }, { - "uuid": "0a3a452c-f734-47eb-8e65-34c8ae710ef0", "slug": "secret-handshake", + "uuid": "0a3a452c-f734-47eb-8e65-34c8ae710ef0", "core": true, + "unlocked_by": null, "difficulty": 6, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Algorithms", - "Games", - "Bitwise operations", - "Arrays" + "algorithms", + "arrays", + "bitwise_operations", + "control_flow_conditionals", + "control_flow_loops", + "games" + ] + }, + { + "slug": "rotational-cipher", + "uuid": "7078b1a4-ef73-4c02-809d-b2de62e9af11", + "core": false, + "unlocked_by": "secret-handshake", + "difficulty": 6, + "topics": [ + "cryptography", + "integers", + "strings" ] }, { - "uuid": "029bc3ed-772d-439b-bd0a-1ba1196a79ec", "slug": "grade-school", + "uuid": "029bc3ed-772d-439b-bd0a-1ba1196a79ec", "core": true, + "unlocked_by": null, "difficulty": 6, "topics": [ - "Arrays", - "Maps", - "Sorting" + "arrays", + "maps", + "sorting" ] }, { - "uuid": "3005340b-a8d6-46ac-9075-125f9adccc2a", "slug": "robot-name", + "uuid": "3005340b-a8d6-46ac-9075-125f9adccc2a", "core": true, + "unlocked_by": null, "difficulty": 6, "topics": [ - "Control flow (conditionals)", - "Exception handling", - "Sets", - "Randomness", - "Regular expressions" + "control_flow_conditionals", + "exception_handling", + "randomness", + "regular_expressions", + "sets" ] }, { - "uuid": "bb54bf08-24ba-45e1-bdf7-08db161e5843", "slug": "wordy", + "uuid": "bb54bf08-24ba-45e1-bdf7-08db161e5843", "core": true, + "unlocked_by": null, "difficulty": 7, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Regular expressions", - "Exception handling", - "Strings", - "Pattern recognition", - "Parsing" + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "parsing", + "pattern_recognition", + "regular_expressions", + "strings" ] }, { - "uuid": "e70defe4-5944-4392-956c-63cb92e7fd9c", "slug": "list-ops", + "uuid": "e70defe4-5944-4392-956c-63cb92e7fd9c", "core": true, + "unlocked_by": null, "difficulty": 8, "topics": [ - "Data structures", - "Lists", - "Recursion" + "data_structures", + "lists", + "recursion" + ] + }, + { + "slug": "rational-numbers", + "uuid": "2de5677e-5759-4a21-93c7-39a3d88242e8", + "core": false, + "unlocked_by": "pascals-triangle", + "difficulty": 5, + "topics": [ + "algorithms", + "floating_point_numbers", + "mathematics" ] }, { - "uuid": "3e1358c8-2bea-41f9-bc9e-8277f354a4e0", "slug": "hamming", + "uuid": "3e1358c8-2bea-41f9-bc9e-8277f354a4e0", "core": false, "unlocked_by": "rna-transcription", "difficulty": 2, "topics": [ - "Control-flow (loops)", - "Control-flow (conditionals)", - "Equality", - "Strings" + "control_flow_conditionals", + "control_flow_loops", + "equality", + "strings" ] }, { - "uuid": "d66c2b56-b465-4922-af35-ae78944c0aac", "slug": "run-length-encoding", + "uuid": "d66c2b56-b465-4922-af35-ae78944c0aac", "core": false, "unlocked_by": null, "difficulty": 2, "topics": [ - "Control flow (conditionals)", - "Exception handling", - "Parsing", - "Text formatting", - "Regular expressions", - "Pattern recognition", - "Strings" + "control_flow_conditionals", + "exception_handling", + "parsing", + "pattern_recognition", + "regular_expressions", + "strings", + "text_formatting" ] }, { - "uuid": "35821375-5c94-4d4b-aa56-e3b079a45ca0", "slug": "isogram", + "uuid": "35821375-5c94-4d4b-aa56-e3b079a45ca0", "core": false, "unlocked_by": "pangram", "difficulty": 2, "topics": [ - "Strings", - "Filtering" + "filtering", + "strings" ] }, { - "uuid": "6f315fc3-095a-4387-aefb-cc5fee97110a", "slug": "beer-song", + "uuid": "6f315fc3-095a-4387-aefb-cc5fee97110a", "core": false, "unlocked_by": "bob", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Strings" + "control_flow_conditionals", + "control_flow_loops", + "strings" ] }, { - "uuid": "347f9f54-a0d9-469d-babf-b3edb34d9d70", "slug": "phone-number", + "uuid": "347f9f54-a0d9-469d-babf-b3edb34d9d70", "core": false, "unlocked_by": "pangram", "difficulty": 3, "topics": [ - "Parsing", - "Transforming" + "parsing", + "transforming" ] }, { - "uuid": "432ec2ce-c919-4142-aea2-389b67503252", "slug": "anagram", + "uuid": "432ec2ce-c919-4142-aea2-389b67503252", "core": false, "unlocked_by": "pangram", "difficulty": 1, "topics": [ - "Strings", - "Filtering" + "filtering", + "strings" ] }, { - "uuid": "a717745f-da00-4a5f-8bf3-6876e20cdf17", "slug": "food-chain", + "uuid": "a717745f-da00-4a5f-8bf3-6876e20cdf17", "core": false, "unlocked_by": "bob", "difficulty": 4, "topics": [ - "Text formatting", - "Algorithms" + "algorithms", + "text_formatting" ] }, { - "uuid": "a2a19f61-62ba-447a-8f57-537c8baa2e7a", "slug": "etl", + "uuid": "a2a19f61-62ba-447a-8f57-537c8baa2e7a", "core": false, "unlocked_by": "rna-transcription", "difficulty": 2, "topics": [ - "Control flow (loops)", - "Transforming", - "Maps", - "Integers" + "control_flow_loops", + "integers", + "maps", + "transforming" ] }, { - "uuid": "4a83a72c-db0a-45b6-b77c-1949cb24fbae", "slug": "sublist", - "difficulty": 4, + "uuid": "4a83a72c-db0a-45b6-b77c-1949cb24fbae", "core": false, "unlocked_by": "linked-list", + "difficulty": 4, "topics": [ - "Lists", - "Arrays" + "arrays", + "lists" ] }, { - "uuid": "c5be6908-f45c-4278-ba99-3701024f4eda", "slug": "grains", + "uuid": "c5be6908-f45c-4278-ba99-3701024f4eda", "core": false, "unlocked_by": "space-age", "difficulty": 5, "topics": [ - "Control flow (loops)", - "Integers", - "Mathematics" + "control_flow_loops", + "integers", + "mathematics" ] }, { - "uuid": "fde792fa-84e9-4b86-8ecb-8466ad92a99d", "slug": "triangle", + "uuid": "fde792fa-84e9-4b86-8ecb-8466ad92a99d", "core": false, "unlocked_by": "leap", "difficulty": 3, "topics": [ - "Control flow (loops)", - "Control flow (conditionals)", - "Exception handling", - "Integers", - "Mathematics" + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "integers", + "mathematics" ] }, { - "uuid": "1ff85150-6c51-4758-af02-4484cf35658e", "slug": "clock", + "uuid": "1ff85150-6c51-4758-af02-4484cf35658e", "core": false, "unlocked_by": "gigasecond", "difficulty": 5, "topics": [ - "Dates", - "Time", - "Globalization" + "dates", + "globalization", + "time" ] }, { - "uuid": "51aa5429-b2db-43ad-83cf-84e2ead22cb6", "slug": "perfect-numbers", + "uuid": "51aa5429-b2db-43ad-83cf-84e2ead22cb6", "core": false, "unlocked_by": "space-age", "difficulty": 3, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Arrays", - "Integers", - "Mathematics" + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics" ] }, { - "uuid": "9a4ea3da-ad43-4850-bdf3-2c578c5de838", "slug": "word-count", + "uuid": "9a4ea3da-ad43-4850-bdf3-2c578c5de838", "core": false, "unlocked_by": "pangram", "difficulty": 1, "topics": [ - "Control flow (loops)", - "Lists", - "Strings", - "Unicode", - "Regular expressions" + "control_flow_loops", + "lists", + "regular_expressions", + "strings", + "unicode" ] }, { - "uuid": "0c1c4788-0372-42e7-81c1-b090bb7ebc8b", "slug": "acronym", + "uuid": "0c1c4788-0372-42e7-81c1-b090bb7ebc8b", "core": false, "unlocked_by": "pangram", "difficulty": 2, "topics": [ - "Strings", - "Control flow (loops)", - "Regular expressions", - "Transforming" + "control_flow_loops", + "regular_expressions", + "strings", + "transforming" ] }, { - "uuid": "a6bd8126-3879-4593-8380-39ebfa87801b", "slug": "scrabble-score", + "uuid": "a6bd8126-3879-4593-8380-39ebfa87801b", "core": false, "unlocked_by": "rna-transcription", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Maps", - "Strings" + "control_flow_conditionals", + "control_flow_loops", + "maps", + "strings" ] }, { - "uuid": "4226e3c6-99d4-406d-998a-bcf11845b211", "slug": "roman-numerals", + "uuid": "4226e3c6-99d4-406d-998a-bcf11845b211", "core": false, "unlocked_by": null, "difficulty": 3, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Pattern recognition", - "Transforming" + "control_flow_conditionals", + "control_flow_loops", + "mathematics", + "pattern_recognition", + "transforming" ] }, { - "uuid": "f1943e87-182a-44f5-a885-3d68a0c0a0dc", "slug": "circular-buffer", + "uuid": "f1943e87-182a-44f5-a885-3d68a0c0a0dc", "core": false, "unlocked_by": "linked-list", "difficulty": 8, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Data structures", - "Lists", - "Arrays", - "Exception handling" + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "data_structures", + "exception_handling", + "lists" ] }, { - "uuid": "86b1acf1-9e2d-4b04-b8b0-e9ae6beb5f3d", "slug": "raindrops", + "uuid": "86b1acf1-9e2d-4b04-b8b0-e9ae6beb5f3d", "core": false, "unlocked_by": "rna-transcription", "difficulty": 2, "topics": [ - "Control flow (conditionals)", - "Strings", - "Integers", - "Transforming" + "control_flow_conditionals", + "integers", + "strings", + "transforming" ] }, { - "uuid": "23210e9e-81f6-4279-a776-00459c7ccd02", "slug": "allergies", + "uuid": "23210e9e-81f6-4279-a776-00459c7ccd02", "core": false, "unlocked_by": "rna-transcription", "difficulty": 6, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Bitwise operations", - "Arrays" + "arrays", + "bitwise_operations", + "control_flow_conditionals", + "control_flow_loops" ] }, { - "uuid": "e61f3d54-55d2-4d32-9d2a-e7d6af3a3247", "slug": "strain", + "uuid": "e61f3d54-55d2-4d32-9d2a-e7d6af3a3247", "core": false, "unlocked_by": "list-ops", "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Algorithms", - "Lists", - "Arrays", - "Callbacks", - "Filtering" + "algorithms", + "arrays", + "callbacks", + "control_flow_conditionals", + "control_flow_loops", + "filtering", + "lists" ] }, { - "uuid": "99974454-0736-4cc0-b88f-ed5701397a97", "slug": "atbash-cipher", + "uuid": "99974454-0736-4cc0-b88f-ed5701397a97", "core": false, "unlocked_by": "simple-cipher", "difficulty": 7, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Algorithms", - "Arrays", - "Regular expressions", - "Text formatting" + "algorithms", + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "regular_expressions", + "text_formatting" ] }, { - "uuid": "dc9b2598-9757-4b20-82f9-8049ad081ac9", "slug": "accumulate", + "uuid": "dc9b2598-9757-4b20-82f9-8049ad081ac9", "core": false, "unlocked_by": "list-ops", "difficulty": 5, "topics": [ - "Control flow (loops)", - "Algorithms", - "Lists", - "Callbacks" + "algorithms", + "callbacks", + "control_flow_loops", + "lists" ] }, { - "uuid": "a98e3593-d5b4-4c2b-8569-ae3ae7e07dad", "slug": "crypto-square", + "uuid": "a98e3593-d5b4-4c2b-8569-ae3ae7e07dad", "core": false, - "unlocked_by": "atbash-cipher", + "unlocked_by": "simple-cipher", "difficulty": 9, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Algorithms", - "Arrays", - "Sorting", - "Text formatting", - "Regular expressions", - "Transforming" + "algorithms", + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "regular_expressions", + "sorting", + "text_formatting", + "transforming" ] }, { - "uuid": "f317721d-e1f5-4e68-9fdc-f9bc7b6b004d", "slug": "trinary", + "uuid": "f317721d-e1f5-4e68-9fdc-f9bc7b6b004d", "core": false, "unlocked_by": "binary", "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Integers", - "Strings", - "Regular expressions" + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics", + "regular_expressions", + "strings" ] }, { - "uuid": "4cad8ee8-40be-4d4d-8c14-45d8c6e29a32", "slug": "sieve", + "uuid": "4cad8ee8-40be-4d4d-8c14-45d8c6e29a32", "core": false, "unlocked_by": "prime-factors", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Integers", - "Recursion" + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics", + "recursion" ] }, { - "uuid": "9892d47d-97a0-4a2f-8284-6f84c86559e8", "slug": "octal", + "uuid": "9892d47d-97a0-4a2f-8284-6f84c86559e8", "core": false, "unlocked_by": "binary", "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Integers", - "Strings", - "Regular expressions" + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics", + "regular_expressions", + "strings" ] }, { - "uuid": "bb46e832-8c37-45ee-9ee7-5037015b965c", "slug": "luhn", + "uuid": "bb46e832-8c37-45ee-9ee7-5037015b965c", "core": false, "unlocked_by": "space-age", "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Integers", - "Strings" + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics", + "strings" ] }, { - "uuid": "9a515ad0-34c7-4191-8784-5c4cd6385b38", "slug": "pig-latin", + "uuid": "9a515ad0-34c7-4191-8784-5c4cd6385b38", "core": false, "unlocked_by": "bob", "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Strings", - "Games", - "Regular expressions", - "Transforming" + "control_flow_conditionals", + "control_flow_loops", + "games", + "regular_expressions", + "strings", + "transforming" ] }, { - "uuid": "26a973dd-d72e-40fb-abeb-0ba306356ed6", "slug": "pythagorean-triplet", + "uuid": "26a973dd-d72e-40fb-abeb-0ba306356ed6", "core": false, "unlocked_by": "space-age", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Algorithms", - "Mathematics", - "Integers" + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics" ] }, { - "uuid": "06afdb06-8d2a-4cb0-baf1-48ae997cf1f5", "slug": "series", + "uuid": "06afdb06-8d2a-4cb0-baf1-48ae997cf1f5", "core": false, "unlocked_by": "pangram", "difficulty": 3, "topics": [ - "Control flow (loops)", - "Exception handling", - "Strings", - "Text formatting" + "control_flow_loops", + "exception_handling", + "strings", + "text_formatting" ] }, { - "uuid": "07110dd5-b879-40b9-9485-685cb0963d8f", "slug": "difference-of-squares", + "uuid": "07110dd5-b879-40b9-9485-685cb0963d8f", "core": false, "unlocked_by": "space-age", "difficulty": 3, "topics": [ - "Control flow (loops)", - "Algorithms", - "Mathematics", - "Integers" + "algorithms", + "control_flow_loops", + "integers", + "mathematics" ] }, { - "uuid": "8786d591-077b-49bc-be8d-d014dc9dc308", "slug": "proverb", + "uuid": "8786d591-077b-49bc-be8d-d014dc9dc308", "core": false, "unlocked_by": "bob", "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Arrays", - "Strings", - "Text formatting", - "Optional values" + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "optional_values", + "strings", + "text_formatting" ] }, { - "uuid": "32a0a5fa-c7de-470c-beff-118b448b3916", "slug": "flatten-array", + "uuid": "32a0a5fa-c7de-470c-beff-118b448b3916", "core": false, "unlocked_by": "list-ops", "difficulty": 1, "topics": [ - "Arrays", - "Recursion" + "arrays", + "recursion" ] }, { - "uuid": "33b8f4c0-3210-478a-9225-5c30ad6df870", "slug": "hexadecimal", + "uuid": "33b8f4c0-3210-478a-9225-5c30ad6df870", "core": false, "unlocked_by": "binary", "difficulty": 4, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Integers", - "Strings", - "Regular expressions" + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics", + "regular_expressions", + "strings" ] }, { - "uuid": "44bd02a7-0e3a-4441-ab76-524e36d4661c", "slug": "largest-series-product", + "uuid": "44bd02a7-0e3a-4441-ab76-524e36d4661c", "core": false, "unlocked_by": "pangram", "difficulty": 7, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Integers", - "Strings", - "Exception handling", - "Regular expressions" + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "integers", + "mathematics", + "regular_expressions", + "strings" ] }, { - "uuid": "2702ac90-0be2-43a2-91b6-7256a25fec87", "slug": "kindergarten-garden", + "uuid": "2702ac90-0be2-43a2-91b6-7256a25fec87", "core": false, "unlocked_by": "wordy", "difficulty": 7, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Strings", - "Arrays", - "Text formatting" + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "strings", + "text_formatting" ] }, { - "uuid": "5991c379-f033-4b46-9702-6b7fd03640e8", "slug": "binary-search", + "uuid": "5991c379-f033-4b46-9702-6b7fd03640e8", "core": false, "unlocked_by": "linked-list", "difficulty": 7, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Recursion", - "Arrays", - "Algorithms" + "algorithms", + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "recursion" ] }, { - "uuid": "865806e0-950f-49a5-a6e5-26472b90ab85", "slug": "binary-search-tree", + "uuid": "865806e0-950f-49a5-a6e5-26472b90ab85", "core": false, - "unlocked_by": "binary-search", + "unlocked_by": "linked-list", "difficulty": 6, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Recursion", - "Algorithms" + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "recursion" ] }, { - "uuid": "00002977-ea1e-45e2-b66e-09d793b5c1ad", "slug": "robot-simulator", + "uuid": "00002977-ea1e-45e2-b66e-09d793b5c1ad", "core": false, "unlocked_by": "wordy", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Exception handling", - "Strings", - "Games", - "Parsing" + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "games", + "parsing", + "strings" ] }, { - "uuid": "8fa51380-ec2c-4806-8833-cf543579de17", "slug": "nth-prime", + "uuid": "8fa51380-ec2c-4806-8833-cf543579de17", "core": false, "unlocked_by": "prime-factors", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Exception handling", - "Algorithms", - "Mathematics", - "Integers" + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "integers", + "mathematics" ] }, { - "uuid": "fde83f66-d927-48f8-a599-efb98927f0b1", "slug": "palindrome-products", + "uuid": "fde83f66-d927-48f8-a599-efb98927f0b1", "core": false, "unlocked_by": "prime-factors", "difficulty": 7, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Exception handling", - "Algorithms", - "Mathematics", - "Integers" + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "integers", + "mathematics" ] }, { - "uuid": "01d286f6-5f29-4d4b-a4de-e217a4833bfa", "slug": "say", + "uuid": "01d286f6-5f29-4d4b-a4de-e217a4833bfa", "core": false, "unlocked_by": "bob", "difficulty": 6, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Mathematics", - "Integers", - "Exception handling", - "Strings", - "Text formatting" + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "integers", + "mathematics", + "strings", + "text_formatting" ] }, { - "uuid": "d4ec15c4-2742-493b-97fe-9d5121f0b659", "slug": "custom-set", + "uuid": "d4ec15c4-2742-493b-97fe-9d5121f0b659", "core": false, "unlocked_by": "linked-list", "difficulty": 6, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Data structures", - "Arrays", - "Lists", - "Sets", - "Equality", - "Recursion" + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "data_structures", + "equality", + "lists", + "recursion", + "sets" ] }, { - "uuid": "f30463c4-9d8c-4238-a691-e594291b4425", "slug": "sum-of-multiples", + "uuid": "f30463c4-9d8c-4238-a691-e594291b4425", "core": false, "unlocked_by": "prime-factors", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Lists", - "Integers" + "control_flow_conditionals", + "control_flow_loops", + "integers", + "lists" ] }, { - "uuid": "fefcfeba-59ec-4c63-a562-374201ee39a7", "slug": "queen-attack", + "uuid": "fefcfeba-59ec-4c63-a562-374201ee39a7", "core": false, "unlocked_by": null, "difficulty": 8, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Optional values", - "Exception handling", - "Equality", - "Text formatting", - "Parsing" + "control_flow_conditionals", + "control_flow_loops", + "equality", + "exception_handling", + "optional_values", + "parsing", + "text_formatting" ] }, { - "uuid": "98cbae4f-78b6-4745-b922-39e8db9a12bb", "slug": "saddle-points", + "uuid": "98cbae4f-78b6-4745-b922-39e8db9a12bb", "core": false, "unlocked_by": "matrix", "difficulty": 6, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Optional values", - "Exception handling", - "Equality", - "Parsing", - "Integers", - "Matrices", - "Mathematics" + "control_flow_conditionals", + "control_flow_loops", + "equality", + "exception_handling", + "integers", + "mathematics", + "matrices", + "optional_values", + "parsing" ] }, { - "uuid": "759618b1-7ccc-46cd-889d-aea58ec88756", "slug": "ocr-numbers", + "uuid": "759618b1-7ccc-46cd-889d-aea58ec88756", "core": false, "unlocked_by": "matrix", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Exception handling", - "Equality", - "Parsing", - "Integers", - "Text formatting" + "control_flow_conditionals", + "control_flow_loops", + "equality", + "exception_handling", + "integers", + "parsing", + "text_formatting" ] }, { - "uuid": "86b1b6ba-c1fe-492d-a7ec-c22c525b4da8", "slug": "meetup", + "uuid": "86b1b6ba-c1fe-492d-a7ec-c22c525b4da8", "core": false, "unlocked_by": "gigasecond", "difficulty": 7, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Exception handling", - "Equality", - "Time", - "Dates" + "control_flow_conditionals", + "control_flow_loops", + "dates", + "equality", + "exception_handling", + "time" ] }, { - "uuid": "25099f87-5c3b-4a8a-b648-4639d1e9fa84", "slug": "bracket-push", + "uuid": "25099f87-5c3b-4a8a-b648-4639d1e9fa84", "core": false, "unlocked_by": "pangram", "difficulty": 3, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Strings", - "Parsing", - "Exception handling" + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "parsing", + "strings" ] }, { - "uuid": "4c857b17-33b0-47fa-b981-6b2fe4e394a1", "slug": "two-bucket", + "uuid": "4c857b17-33b0-47fa-b981-6b2fe4e394a1", "core": false, "unlocked_by": "grade-school", "difficulty": 6, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Arrays", - "Parsing", - "Algorithms", - "Games", - "Exception handling" + "algorithms", + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "games", + "parsing" ] }, { - "uuid": "c168fe1f-f84e-46e6-91fc-7553d048a4e9", "slug": "bowling", + "uuid": "c168fe1f-f84e-46e6-91fc-7553d048a4e9", "core": false, "unlocked_by": "grade-school", "difficulty": 8, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Arrays", - "Parsing", - "Games", - "Exception handling", - "Text formatting" + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "games", + "parsing", + "text_formatting" ] }, { - "uuid": "04a4ef78-5b61-454f-8c37-798875fb4956", "slug": "diamond", + "uuid": "04a4ef78-5b61-454f-8c37-798875fb4956", "core": false, "unlocked_by": "pascals-triangle", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Arrays", - "Parsing", - "Games", - "Exception handling", - "Text formatting" + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "games", + "parsing", + "text_formatting" ] }, { - "uuid": "cdfcec62-f2f3-4408-ad2c-8b5e1e56e791", "slug": "all-your-base", + "uuid": "cdfcec62-f2f3-4408-ad2c-8b5e1e56e791", "core": false, "unlocked_by": "binary", "difficulty": 5, "topics": [ - "Control flow (conditionals)", - "Control flow (loops)", - "Exception handling", - "Parsing", - "Mathematics", - "Integers" + "control_flow_conditionals", + "control_flow_loops", + "exception_handling", + "integers", + "mathematics", + "parsing" ] }, { - "uuid": "22fa5ab4-935b-44cc-b055-9803214ae5f3", "slug": "minesweeper", + "uuid": "22fa5ab4-935b-44cc-b055-9803214ae5f3", "core": false, "unlocked_by": null, "difficulty": 7, "topics": [ - "Games", - "Arrays", - "Algorithms" + "algorithms", + "arrays", + "games" ] }, { - "uuid": "42a7fd83-4508-403c-8b5e-f0a3126fac8a", "slug": "alphametics", + "uuid": "42a7fd83-4508-403c-8b5e-f0a3126fac8a", "core": false, "unlocked_by": "grade-school", "difficulty": 7, "topics": [ - "Games", - "Algorithms" + "algorithms", + "games" ] }, { - "uuid": "c21ab6e8-b845-49d0-a2f6-1c89c7a07626", "slug": "simple-linked-list", + "uuid": "c21ab6e8-b845-49d0-a2f6-1c89c7a07626", "core": false, "unlocked_by": "linked-list", "difficulty": 8, "topics": [ - "Arrays", - "Data structures", - "Lists" + "arrays", + "data_structures", + "lists" + ] + }, + { + "slug": "diffie-hellman", + "uuid": "833bd7c7-d3d8-45fd-a218-12dea646065d", + "core": false, + "unlocked_by": "simple-cipher", + "difficulty": 3, + "topics": [ + "algorithms", + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "exception_handling" + ] + }, + { + "slug": "change", + "uuid": "910fe904-7e3c-11e7-bb31-be2e44b06b34", + "core": false, + "unlocked_by": "prime-factors", + "difficulty": 8, + "topics": [ + "algorithms", + "mathematics", + "performance", + "searching" + ] + }, + { + "slug": "connect", + "uuid": "3b779cb8-9544-4e0d-a306-e5478d741be7", + "core": false, + "unlocked_by": "grade-school", + "difficulty": 7, + "topics": [ + "arrays", + "control_flow_conditionals", + "control_flow_loops", + "games", + "maps", + "parsing" + ] + }, + { + "slug": "collatz-conjecture", + "uuid": "fd435dad-311a-4c40-9868-70863455831e", + "core": false, + "unlocked_by": null, + "difficulty": 1, + "topics": [ + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "integers", + "mathematics", + "recursion" ] }, { - "uuid": "1b53340d-ea40-44ee-bf2e-42e516704e7c", "slug": "nucleotide-count", + "uuid": "1b53340d-ea40-44ee-bf2e-42e516704e7c", + "core": false, + "unlocked_by": null, + "difficulty": 0, + "topics": null, "deprecated": true }, { - "uuid": "e9a6b2ea-a67d-4b75-800d-7b46240094ec", "slug": "point-mutations", + "uuid": "e9a6b2ea-a67d-4b75-800d-7b46240094ec", + "core": false, + "unlocked_by": null, + "difficulty": 0, + "topics": null, "deprecated": true + }, + { + "slug": "twelve-days", + "uuid": "09e10522-9853-11e7-abc4-cec278b6b50a", + "core": false, + "unlocked_by": "bob", + "difficulty": 4, + "topics": [ + "control_flow_conditionals", + "control_flow_loops", + "pattern_recognition", + "strings" + ] + }, + { + "slug": "transpose", + "uuid": "7c024853-0540-473d-b2d9-cad84953c00f", + "core": false, + "unlocked_by": "matrix", + "difficulty": 1, + "topics": [ + "arrays", + "lists", + "loops", + "matrices", + "strings", + "text_formatting" + ] + }, + { + "slug": "protein-translation", + "uuid": "52c775a4-7ddb-4cba-8a78-8544220bd1b6", + "core": false, + "unlocked_by": null, + "difficulty": 1, + "topics": [ + "algorithms", + "control_flow_conditionals", + "control_flow_loops", + "strings" + ] + }, + { + "slug": "zipper", + "uuid": "f4a3d66a-04a8-3e80-6c9a-8a573ccb26fd9ed1d5c", + "core": false, + "unlocked_by": null, + "difficulty": 8, + "topics": [ + "recursion", + "searching", + "trees" + ] + }, + { + "slug": "isbn-verifier", + "uuid": "8740af44-002c-4716-a759-a68ae4c68737", + "core": false, + "unlocked_by": "bob", + "difficulty": 4, + "topics": [ + "conditionals", + "loops", + "pattern_matching", + "strings" + ] + }, + { + "slug": "forth", + "uuid": "b3dbc935-536e-4910-994d-4a519b511b6a", + "core": false, + "unlocked_by": "matrix", + "difficulty": 8, + "topics": [ + "domain_specific_languages", + "parsing", + "stacks" + ] + }, + { + "slug": "variable-length-quantity", + "uuid": "f82e470d-0bcc-4eba-b9b0-8a0c50a6fd19", + "core": false, + "unlocked_by": "grade-school", + "difficulty": 5, + "topics": [ + "bitwise_operations", + "transforming" + ] + }, + { + "slug": "rectangles", + "uuid": "cb09212c-f2ae-4acf-9177-6c7f42594c1d", + "core": false, + "unlocked_by": "grade-school", + "difficulty": 6, + "topics": [ + "parsing", + "pattern_recognition", + "searching" + ] + }, + { + "slug": "armstrong-numbers", + "uuid": "0e4b628c-870d-446b-a400-3cc72457f2bc", + "core": false, + "unlocked_by": null, + "difficulty": 2, + "topics": [ + "algorithms", + "mathematics" + ] } - ], - "foregone": [ - ] } diff --git a/config/exercise_readme.go.tmpl b/config/exercise_readme.go.tmpl index 2b26f494..730bb47c 100644 --- a/config/exercise_readme.go.tmpl +++ b/config/exercise_readme.go.tmpl @@ -4,10 +4,32 @@ {{- with .Hints }} {{ . }} {{ end }} -{{- with .TrackInsert }} -{{ . }} -{{ end }} -{{- with .Spec.Credits -}} +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine {{ .Spec.Slug }}.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. +{{ with .Spec.Credits }} ## Source {{ . }} diff --git a/config/maintainers.json b/config/maintainers.json index 15965d38..48b19c6a 100644 --- a/config/maintainers.json +++ b/config/maintainers.json @@ -1,85 +1,5 @@ { + "docs_url": "https://github.com/exercism/docs/blob/master/maintaining-a-track/maintainer-configuration.md", "maintainers": [ - { - "github_username": "ireddick", - "show_on_website": false, - "alumnus": false, - "name": null, - "bio": null, - "link_text": null, - "link_url": null, - "avatar_url": null - }, - { - "github_username": "rchavarria", - "show_on_website": false, - "alumnus": false, - "name": null, - "bio": null, - "link_text": null, - "link_url": null, - "avatar_url": null - }, - { - "github_username": "joelwallis", - "show_on_website": false, - "alumnus": false, - "name": null, - "bio": null, - "link_text": null, - "link_url": null, - "avatar_url": null - }, - { - "github_username": "drueck", - "show_on_website": false, - "alumnus": false, - "name": null, - "bio": null, - "link_text": null, - "link_url": null, - "avatar_url": null - }, - { - "github_username": "tejasbubane", - "show_on_website": false, - "alumnus": false, - "name": null, - "bio": null, - "link_text": null, - "link_url": null, - "avatar_url": null - }, - { - "github_username": "matthewmorgan", - "show_on_website": false, - "alumnus": false, - "name": null, - "bio": null, - "link_text": null, - "link_url": null, - "avatar_url": null - }, - { - "github_username": "mixolidia", - "show_on_website": false, - "alumnus": false, - "name": null, - "bio": null, - "link_text": null, - "link_url": null, - "avatar_url": null - }, - { - "github_username": "ZacharyRSmith", - "show_on_website": false, - "alumnus": false, - "name": null, - "bio": null, - "link_text": null, - "link_url": null, - "avatar_url": null - } - ], - "docs_url": "https://github.com/exercism/docs/blob/master/maintaining-a-track/maintainer-configuration.md" + ] } diff --git a/docs/ABOUT.md b/docs/ABOUT.md index b325e92b..94a463da 100644 --- a/docs/ABOUT.md +++ b/docs/ABOUT.md @@ -1,22 +1,29 @@ -Javascript is a scripting language used to provide dynamic and interactive content on webpages. Also, server side JS allows the use of the same language on the server and client. Besides being fast, JavaScript provides benefits like: +JavaScript is a scripting language used to provide dynamic and interactive content on webpages. +Also, server side JS allows the use of the same language on the server and client. + +Besides being fast, JavaScript provides benefits like: * Reducing server traffic by validating user input in the browser before it is sent to the server. -* Providing immediate feedback to the site visitors so that they don't have to reload pages just to get error messages on form validations. +* Providing immediate feedback to the site's visitors so that they don't have to reload pages just to get error messages on form validations. * Allowing richer user interfaces with content changes on mouse hover, drag and drop gestures, and animations. -Client-side JavaScript is interpreted in the browser without requiring compilation. This allows interactive content to be included in HTML pages which would otherwise be static. +Client-side JavaScript is interpreted in the browser without requiring compilation. +This allows interactive content to be included in HTML pages which would otherwise be static. -Server-Side JavaScript as run in NodeJS enables back-end access to databases, file systems, and servers. NodeJS is built on Google Chrome's JavaScript V8 Engine. NodeJS uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. Node can be a great solution for applications requiring I/O bound operations, data streaming etc. More details can be found [here](https://nodejs.org/en/about/). +Server-Side JavaScript as run in NodeJS enables back-end access to databases, file systems, and servers. +NodeJS is built on Google Chrome's JavaScript V8 Engine. +NodeJS uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. +Node can be a great solution for applications requiring I/O bound operations, data streaming etc. +More details can be found [here](https://nodejs.org/en/about/). You should learn JavaScript because: * It's easy to learn. -* It's versatile in the sense that it's multi-paradigm supporting procedural, event based, object oriented and functional programming. -* It can be used for the frontend and backend. +* It's versatile in the sense that it's multi-paradigm - supporting procedural, event based, object oriented and functional programming. +* It can be used for the front-end and back-end. * It's Open Source. * JavaScript programming skills are in high demand. ---- - -_This track is intended for widely supported JavaScript, for code that could be executed in almost all existing browsers. If you're looking for experimenting with newer features of the language try the [ECMAScript](http://exercism.io/languages/ecmascript) track._ +_This track is intended for widely supported JavaScript, for code that could be executed in almost all existing browsers. +If you're looking to experiment with newer features of the language, try the [ECMAScript](http://exercism.io/languages/ecmascript) track._ diff --git a/docs/EXERCISE_README_INSERT.md b/docs/EXERCISE_README_INSERT.md deleted file mode 100644 index 00fd308e..00000000 --- a/docs/EXERCISE_README_INSERT.md +++ /dev/null @@ -1,22 +0,0 @@ -## Setup - -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript - -## Making the Test Suite Pass - -Execute the tests with: - - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: - - jasmine hello-world.spec.js - -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. diff --git a/docs/LEARNING.md b/docs/LEARNING.md index 0e0322cb..462c8cb2 100644 --- a/docs/LEARNING.md +++ b/docs/LEARNING.md @@ -1,4 +1,4 @@ -* [Eloquent JavaScript: A Modern Introduction to Programming (2nd Ed.)](http://eloquentjavascript.net) +* [Eloquent JavaScript: A Modern Introduction to Programming](http://eloquentjavascript.net) * [JavaScript: The Good Parts](http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742) * [Crockford on JavaScript](http://javascript.crockford.com/) * [idiomatic.js: Principles of Writing Consistent, Idiomatic JavaScript](https://github.com/rwaldron/idiomatic.js) diff --git a/docs/SNIPPET.txt b/docs/SNIPPET.txt new file mode 100644 index 00000000..0cb40c8b --- /dev/null +++ b/docs/SNIPPET.txt @@ -0,0 +1,10 @@ +'use strict'; + +var HelloWorld = function() {}; + +HelloWorld.prototype.hello = function(name) { + name = name || 'World'; + return 'Hello, ' + name + '!'; +}; + +module.exports = HelloWorld; diff --git a/docs/TESTS.md b/docs/TESTS.md index 9a353ef3..62985f52 100644 --- a/docs/TESTS.md +++ b/docs/TESTS.md @@ -1,7 +1,7 @@ With the first few exercises, you will get a skeleton file with the exported modules. For later ones, you can find more information about modules in the [node documentation](http://nodejs.org/api/modules.html#modules_module_exports). -For running tests, install `jasmine` as described in the [Installing Javascript section](http://exercism.io/languages/javascript/installing). +For running tests, install `jasmine` as described in the [Installing Javascript section](http://exercism.io/languages/javascript/installation). Move to the folder where that exercise's files are located (a path similar to {EXERCISM_HOME_DIR}/javascript/{EXERCISE}). cd ~/exercism/javascript/bob @@ -26,7 +26,7 @@ To get started, you can download a Visual Studio solution that is already set up 1. Download the [Exercism.io Visual Studio Template](https://github.com/rprouse/Exercism.VisualStudio) from GitHub by clicking the Download Zip button on the page. 2. Unzip the template into your exercises directory, for example `C:\src\exercises` -2. Install the [Exercism CLI](http://exercism.io/cli) +2. Install the [Exercism CLI](http://exercism.io/clients/cli) 3. Open a command prompt to your exercise directory 4. Add your API key to exercism `exercism configure --key=YOUR_API_KEY` 5. Configure your source directory in exercism `exercism configure --dir=C:\src\exercises` diff --git a/exercises/accumulate/README.md b/exercises/accumulate/README.md index 1f8e999f..0588b985 100644 --- a/exercises/accumulate/README.md +++ b/exercises/accumulate/README.md @@ -25,31 +25,31 @@ Keep your hands off that collect/map/fmap/whatchamacallit functionality provided by your standard library! Solve this one yourself using other basic tools instead. -Lisp specific: it's perfectly fine to use `MAPCAR` or the equivalent, -as this is idiomatic Lisp, not a library function. - ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine accumulate.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/accumulate/accumulate.spec.js b/exercises/accumulate/accumulate.spec.js index 4effd86e..2f0c7c65 100644 --- a/exercises/accumulate/accumulate.spec.js +++ b/exercises/accumulate/accumulate.spec.js @@ -1,14 +1,13 @@ var accumulate = require('./accumulate'); -describe('accumulate()', function() { - - it('accumulation empty', function() { - var accumulator = function(e) { return e * e; }; +describe('accumulate()', function () { + it('accumulation empty', function () { + var accumulator = function (e) { return e * e; }; expect(accumulate([], accumulator)).toEqual([]); }); - xit('accumulate squares', function() { - var accumulator = function(number) { + xit('accumulate squares', function () { + var accumulator = function (number) { return number * number; }; @@ -17,8 +16,8 @@ describe('accumulate()', function() { expect(result).toEqual([1, 4, 9]); }); - xit('accumulate upcases', function() { - var accumulator = function(word) { + xit('accumulate upcases', function () { + var accumulator = function (word) { return word.toUpperCase(); }; @@ -27,8 +26,8 @@ describe('accumulate()', function() { expect(result).toEqual(['HELLO', 'WORLD']); }); - xit('accumulate reversed strings', function() { - var accumulator = function(word) { + xit('accumulate reversed strings', function () { + var accumulator = function (word) { return word.split('').reverse().join(''); }; @@ -37,14 +36,13 @@ describe('accumulate()', function() { expect(result).toEqual(['eht', 'kciuq', 'nworb', 'xof', 'cte']); }); - xit('accumulate recursively', function() { - var result = accumulate('a b c'.split(/\s/), function(char) { - return accumulate('1 2 3'.split(/\s/), function(digit) { + xit('accumulate recursively', function () { + var result = accumulate('a b c'.split(/\s/), function (char) { + return accumulate('1 2 3'.split(/\s/), function (digit) { return char + digit; }); }); expect(result).toEqual([['a1', 'a2', 'a3'], ['b1', 'b2', 'b3'], ['c1', 'c2', 'c3']]); }); - }); diff --git a/exercises/accumulate/example.js b/exercises/accumulate/example.js index 18274805..e36fb748 100644 --- a/exercises/accumulate/example.js +++ b/exercises/accumulate/example.js @@ -1,4 +1,4 @@ -var accumulate = module.exports = function (list, accumulator) { +module.exports = function (list, accumulator) { var out = []; var idx = -1; var end = Array.isArray(list) ? list.length : 0; @@ -9,4 +9,3 @@ var accumulate = module.exports = function (list, accumulator) { return out; }; - diff --git a/exercises/acronym/README.md b/exercises/acronym/README.md index 3cc46d74..8fefa5b9 100644 --- a/exercises/acronym/README.md +++ b/exercises/acronym/README.md @@ -7,29 +7,31 @@ Techies love their TLA (Three Letter Acronyms)! Help generate some jargon by writing a program that converts a long name like Portable Network Graphics to its acronym (PNG). - ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine acronym.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/acronym/acronym.spec.js b/exercises/acronym/acronym.spec.js index ec5f60c2..e5619576 100644 --- a/exercises/acronym/acronym.spec.js +++ b/exercises/acronym/acronym.spec.js @@ -1,27 +1,27 @@ var Acronyms = require('./acronym'); -describe('Acronyms are produced from', function(){ - it('title cased phrases', function() { +describe('Acronyms are produced from', function () { + it('title cased phrases', function () { expect(Acronyms.parse('Portable Network Graphics')).toEqual('PNG'); }); - it('other title cased phrases', function(){ + it('other title cased phrases', function () { expect(Acronyms.parse('Ruby on Rails')).toEqual('ROR'); }); - it('inconsistently cased phrases', function(){ + it('inconsistently cased phrases', function () { expect(Acronyms.parse('HyperText Markup Language')).toEqual('HTML'); }); - it('phrases with punctuation', function() { + it('phrases with punctuation', function () { expect(Acronyms.parse('First In, First Out')).toEqual('FIFO'); }); - it('other phrases with punctuation', function() { + it('other phrases with punctuation', function () { expect(Acronyms.parse('PHP: Hypertext Preprocessor')).toEqual('PHP'); }); - it('phrases with punctuation and sentence casing', function() { + it('phrases with punctuation and sentence casing', function () { expect(Acronyms.parse('Complementary metal-oxide semiconductor')).toEqual('CMOS'); }); }); diff --git a/exercises/acronym/example.js b/exercises/acronym/example.js index ac8d5636..1618d203 100644 --- a/exercises/acronym/example.js +++ b/exercises/acronym/example.js @@ -2,7 +2,8 @@ module.exports = { parse: function (phrase) { return phrase.match(/[A-Z]+[a-z]*|[a-z]+/g) .reduce(function (acronym, word) { - return acronym += word[0].toUpperCase() + var returnAcronym = acronym + word[0].toUpperCase(); + return returnAcronym; }, ''); } }; diff --git a/exercises/all-your-base/README.md b/exercises/all-your-base/README.md index 5971b557..d18b0258 100644 --- a/exercises/all-your-base/README.md +++ b/exercises/all-your-base/README.md @@ -6,6 +6,7 @@ Implement general base conversion. Given a number in base **a**, represented as a sequence of digits, convert it to base **b**. ## Note + - Try to implement the conversion yourself. Do not use something else to perform the conversion for you. @@ -28,32 +29,33 @@ The number 1120, *in base 3*, means: I think you got the idea! - *Yes. Those three numbers above are exactly the same. Congratulations!* ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript - -## Making the Test Suite Pass +Go through the setup instructions for JavaScript to install the + necessary dependencies: -Execute the tests with: +http://exercism.io/languages/javascript/installation - jasmine .spec.js +## Running the test suite -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine hello-world.spec.js +```sh +npm install -g jasmine +``` -In many test suites all but the first test have been skipped. +Run the test suite from the exercise directory with: -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +```sh +jasmine all-your-base.spec.js +``` +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Submitting Incomplete Solutions It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/all-your-base/all-your-base.spec.js b/exercises/all-your-base/all-your-base.spec.js index 34d28100..eb490913 100644 --- a/exercises/all-your-base/all-your-base.spec.js +++ b/exercises/all-your-base/all-your-base.spec.js @@ -5,7 +5,6 @@ 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]); }); @@ -137,5 +136,4 @@ describe('Converter', function () { converter.convert([0], 3, 2.5); }).toThrow(new Error('Wrong output base')); }); - }); diff --git a/exercises/allergies/README.md b/exercises/allergies/README.md index af0072d6..179a7f58 100644 --- a/exercises/allergies/README.md +++ b/exercises/allergies/README.md @@ -29,29 +29,31 @@ allergens that score 256, 512, 1024, etc.). Your program should ignore those components of the score. For example, if the allergy score is 257, your program should only report the eggs (1) allergy. - ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine allergies.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/allergies/allergies.spec.js b/exercises/allergies/allergies.spec.js index 40bcf72a..efce5cf9 100644 --- a/exercises/allergies/allergies.spec.js +++ b/exercises/allergies/allergies.spec.js @@ -1,66 +1,65 @@ var Allergies = require('./allergies'); -describe('Allergies',function() { - - it('no allergies at all', function() { +describe('Allergies', function () { + it('no allergies at all', function () { var allergies = new Allergies(0); expect(allergies.list()).toEqual([]); }); - xit('allergies to eggs', function() { + xit('allergies to eggs', function () { var allergies = new Allergies(1); expect(allergies.list()).toEqual([ 'eggs' ]); }); - xit('allergies to peanuts', function() { + xit('allergies to peanuts', function () { var allergies = new Allergies(2); expect(allergies.list()).toEqual([ 'peanuts' ]); }); - xit('allergies to strawberries', function() { + xit('allergies to strawberries', function () { var allergies = new Allergies(8); expect(allergies.list()).toEqual([ 'strawberries' ]); }); - xit('allergies to eggs and peanuts', function() { + xit('allergies to eggs and peanuts', function () { var allergies = new Allergies(3); expect(allergies.list()).toEqual([ 'eggs', 'peanuts' ]); }); - xit('allergies to more than eggs but not peanuts', function() { + xit('allergies to more than eggs but not peanuts', function () { var allergies = new Allergies(5); expect(allergies.list()).toEqual([ 'eggs', 'shellfish' ]); }); - xit('allergic to lots of stuff', function() { + xit('allergic to lots of stuff', function () { var allergies = new Allergies(248); expect(allergies.list()).toEqual(['strawberries', 'tomatoes', 'chocolate', 'pollen', 'cats']); }); - xit('allergic to everything', function() { + xit('allergic to everything', function () { var allergies = new Allergies(255); expect(allergies.list()).toEqual(['eggs', 'peanuts', 'shellfish', 'strawberries', 'tomatoes', 'chocolate', 'pollen', 'cats']); }); - xit('no allergic means not allergic', function() { + xit('no allergic means not allergic', function () { var allergies = new Allergies(0); expect(allergies.allergicTo('peanuts')).toEqual(false); expect(allergies.allergicTo('cats')).toEqual(false); expect(allergies.allergicTo('strawberries')).toEqual(false); }); - xit('allergic to eggs', function() { + xit('allergic to eggs', function () { var allergies = new Allergies(1); expect(allergies.allergicTo('eggs')).toEqual(true); }); - xit('allergic to eggs and other things', function() { + xit('allergic to eggs and other things', function () { var allergies = new Allergies(5); expect(allergies.allergicTo('eggs')).toEqual(true); }); - xit('ignore non allergen score parts', function() { + xit('ignore non allergen score parts', function () { var allergies = new Allergies(509); expect(allergies.list()).toEqual(['eggs', 'shellfish', 'strawberries', 'tomatoes', 'chocolate', 'pollen', 'cats']); }); -}); \ No newline at end of file +}); diff --git a/exercises/allergies/example.js b/exercises/allergies/example.js index 3ffe16b9..3fd62fe7 100644 --- a/exercises/allergies/example.js +++ b/exercises/allergies/example.js @@ -5,23 +5,23 @@ function Allergies(allergenIndex) { } Allergies.possibleAllergies = [ 'eggs', 'peanuts', 'shellfish', 'strawberries', - 'tomatoes', 'chocolate', 'pollen', 'cats']; + 'tomatoes', 'chocolate', 'pollen', 'cats']; Allergies.prototype = { - list: function() { + list: function () { var possibleAllergies = Allergies.possibleAllergies; var allergicTo = []; for (var i = 0; i < possibleAllergies.length; i++) { var allergy = possibleAllergies[i]; - if (this.allergenIndex & Math.pow(2,i)) { + if (this.allergenIndex & Math.pow(2, i)) { allergicTo.push(allergy); } } return allergicTo; }, - allergicTo: function(food) { + allergicTo: function (food) { var isAllergic = false; var allergyList = this.list(); @@ -36,4 +36,4 @@ Allergies.prototype = { } }; -module.exports = Allergies; \ No newline at end of file +module.exports = Allergies; diff --git a/exercises/alphametics/README.md b/exercises/alphametics/README.md index d96936f2..bc3ff2ec 100644 --- a/exercises/alphametics/README.md +++ b/exercises/alphametics/README.md @@ -7,7 +7,7 @@ letters in words are replaced with numbers. For example `SEND + MORE = MONEY`: -``` +```text S E N D M O R E + ----------- @@ -16,7 +16,7 @@ M O N E Y Replacing these with valid numbers gives: -``` +```text 9 5 6 7 1 0 8 5 + ----------- @@ -33,27 +33,29 @@ Write a function to solve alphametics puzzles. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: - - jasmine hello-world.spec.js +```sh +npm install -g jasmine +``` -In many test suites all but the first test have been skipped. +Run the test suite from the exercise directory with: -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +```sh +jasmine alphametics.spec.js +``` +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Submitting Incomplete Solutions It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/alphametics/alphametics.spec.js b/exercises/alphametics/alphametics.spec.js index 4db54f1a..d175f6f9 100644 --- a/exercises/alphametics/alphametics.spec.js +++ b/exercises/alphametics/alphametics.spec.js @@ -1,95 +1,93 @@ var solve = require('./alphametics'); -describe("Solve the alphametics puzzle", function() { - - it("puzzle with three letters", function() { - var puzzle = "I + BB == ILL"; +describe('Solve the alphametics puzzle', function () { + it('puzzle with three letters', function () { + var puzzle = 'I + BB == ILL'; var expected = { - "I": 1, - "B": 9, - "L": 0 + 'I': 1, + 'B': 9, + 'L': 0 }; expect(solve(puzzle)).toEqual(expected); }); - xit("solution must have unique value for each letter", function() { - var puzzle = "A == B"; + xit('solution must have unique value for each letter', function () { + var puzzle = 'A == B'; expect(solve(puzzle)).toBeNull(); }); - xit("leading zero solution is invalid", function() { - var puzzle = "ACA + DD == BD"; + xit('leading zero solution is invalid', function () { + var puzzle = 'ACA + DD == BD'; expect(solve(puzzle)).toBeNull(); }); - xit("puzzle with four letters", function() { - var puzzle = "AS + A == MOM"; + xit('puzzle with four letters', function () { + var puzzle = 'AS + A == MOM'; var expected = { - "A": 9, - "S": 2, - "M": 1, - "O": 0 + 'A': 9, + 'S': 2, + 'M': 1, + 'O': 0 }; expect(solve(puzzle)).toEqual(expected); }); - xit("puzzle with six letters", function() { - var puzzle = "NO + NO + TOO == LATE"; + xit('puzzle with six letters', function () { + var puzzle = 'NO + NO + TOO == LATE'; var expected = { - "N": 7, - "O": 4, - "T": 9, - "L": 1, - "A": 0, - "E": 2 + 'N': 7, + 'O': 4, + 'T': 9, + 'L': 1, + 'A': 0, + 'E': 2 }; expect(solve(puzzle)).toEqual(expected); }); - xit("puzzle with seven letters", function() { - var puzzle = "HE + SEES + THE == LIGHT"; + xit('puzzle with seven letters', function () { + var puzzle = 'HE + SEES + THE == LIGHT'; var expected = { - "E": 4, - "G": 2, - "H": 5, - "I": 0, - "L": 1, - "S": 9, - "T": 7 + 'E': 4, + 'G': 2, + 'H': 5, + 'I': 0, + 'L': 1, + 'S': 9, + 'T': 7 }; expect(solve(puzzle)).toEqual(expected); }); - xit("puzzle with eight letters", function() { - var puzzle = "SEND + MORE == MONEY"; + xit('puzzle with eight letters', function () { + var puzzle = 'SEND + MORE == MONEY'; var expected = { - "S": 9, - "E": 5, - "N": 6, - "D": 7, - "M": 1, - "O": 0, - "R": 8, - "Y": 2 + 'S': 9, + 'E': 5, + 'N': 6, + 'D': 7, + 'M': 1, + 'O': 0, + 'R': 8, + 'Y': 2 }; expect(solve(puzzle)).toEqual(expected); }); - xit("puzzle with ten letters", function() { - var puzzle = "AND + A + STRONG + OFFENSE + AS + A + GOOD == DEFENSE"; + xit('puzzle with ten letters', function () { + var puzzle = 'AND + A + STRONG + OFFENSE + AS + A + GOOD == DEFENSE'; var expected = { - "A": 5, - "D": 3, - "E": 4, - "F": 7, - "G": 8, - "N": 0, - "O": 2, - "R": 1, - "S": 6, - "T": 9 + 'A': 5, + 'D': 3, + 'E': 4, + 'F': 7, + 'G': 8, + 'N': 0, + 'O': 2, + 'R': 1, + 'S': 6, + 'T': 9 }; expect(solve(puzzle)).toEqual(expected); - }); - + }); }); diff --git a/exercises/alphametics/example.js b/exercises/alphametics/example.js index 3dc16042..0c4a8f7f 100644 --- a/exercises/alphametics/example.js +++ b/exercises/alphametics/example.js @@ -1,24 +1,24 @@ function solve(puzzle) { var parts = puzzle .split(/[+|==]/g) - .map(function(o) { return o.trim(); }) - .filter(function(o) { return o !== ""; }); + .map(function (o) { return o.trim(); }) + .filter(function (o) { return o !== ''; }); - if(parts.length < 3) { + if (parts.length < 3) { return null; } var uniqueLetters = getUniqueLetters(parts.join('')); var firstLetters = getFirstLetters(parts); - var numberCombinations = getNumberCombinations([0,1,2,3,4,5,6,7,8,9], uniqueLetters.length); - var permutations = getPermutations(Array(uniqueLetters.length).fill().map(function(_, i) {return i; })); + var numberCombinations = getNumberCombinations([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], uniqueLetters.length); + var permutations = getPermutations(Array(uniqueLetters.length).fill().map(function (_, i) {return i; })); - while(numberCombinations.length) { + while (numberCombinations.length) { var numberCombination = numberCombinations.pop(); - for(var k = 0; k < permutations.length; k++) { + for (var k = 0; k < permutations.length; k++) { var newNumbers = assignNumbers(numberCombination, uniqueLetters, permutations[k]); - if(testNumbers(newNumbers, parts, firstLetters)) { + if (testNumbers(newNumbers, parts, firstLetters)) { return newNumbers; } } @@ -28,13 +28,13 @@ function solve(puzzle) { function getFirstLetters(words) { return words - .map(function(word) { return word[0]; }) + .map(function (word) { return word[0]; }) .filter(function (val, i, arr) { return arr.indexOf(val) === i; }); } function assignNumbers(numbers, letters, orders) { var output = {}; - for(var i = 0; i < letters.length; i++) { + for (var i = 0; i < letters.length; i++) { output[letters[i]] = numbers[orders[i]]; } return output; @@ -46,28 +46,28 @@ function getUniqueLetters(string) { function testNumbers(numbers, puzzleParts, firstLetters) { var keys = Object.keys(numbers); - for(var i = 0; i < keys.length; i++) { - if(numbers[keys[i]] === 0 && firstLetters.indexOf(keys[i]) !== -1) { + for (var i = 0; i < keys.length; i++) { + if (numbers[keys[i]] === 0 && firstLetters.indexOf(keys[i]) !== -1) { return false; } } var replaceRegex = new RegExp('[' + keys.join('') + ']', 'g'); - puzzleParts = puzzleParts.join(',') - .replace(replaceRegex, function(input) { return numbers[input]; }) + var puzzlePartsJoined = puzzleParts.join(',') + .replace(replaceRegex, function (input) { return numbers[input]; }) .split(',') - .map(function(t) {return parseInt(t);}); + .map(function (t) {return parseInt(t, 10);}); - var total = puzzleParts.slice(puzzleParts.length-1)[0]; - return total === puzzleParts - .slice(0,puzzleParts.length-1) - .reduce(function(acc, val) { return acc + val; },0); + var total = puzzlePartsJoined.slice(puzzlePartsJoined.length - 1)[0]; + return total === puzzlePartsJoined + .slice(0, puzzlePartsJoined.length - 1) + .reduce(function (acc, val) { return acc + val; }, 0); } function getPermutations(inputArr) { var results = []; function permute(arr, memo) { - var cur, memo = memo || []; + var cur = memo; for (var i = 0; i < arr.length; i++) { cur = arr.splice(i, 1); if (arr.length === 0) { @@ -78,11 +78,15 @@ function getPermutations(inputArr) { } return results; } - return permute(inputArr); + return permute(inputArr, []); } function getNumberCombinations(set, k) { - var i, j, combs, head, tailcombs; + var i; + var j; + var combs; + var head; + var tailcombs; if (k > set.length || k <= 0) { return []; } @@ -104,4 +108,4 @@ function getNumberCombinations(set, k) { return combs; } -module.exports = solve; \ No newline at end of file +module.exports = solve; diff --git a/exercises/anagram/README.md b/exercises/anagram/README.md index f9b4bf5c..9473855e 100644 --- a/exercises/anagram/README.md +++ b/exercises/anagram/README.md @@ -8,26 +8,29 @@ Given `"listen"` and a list of candidates like `"enlists" "google" ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine anagram.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/anagram/anagram.spec.js b/exercises/anagram/anagram.spec.js index ca71bd97..db03ac95 100644 --- a/exercises/anagram/anagram.spec.js +++ b/exercises/anagram/anagram.spec.js @@ -1,78 +1,77 @@ var Anagram = require('./anagram'); -describe('Anagram', function() { - - it('no matches',function() { +describe('Anagram', function () { + it('no matches', function () { var subject = new Anagram('diaper'); var matches = subject.matches([ 'hello', 'world', 'zombies', 'pants']); expect(matches).toEqual([]); }); - xit('detects simple anagram',function() { + xit('detects simple anagram', function () { var subject = new Anagram('ant'); var matches = subject.matches(['tan', 'stand', 'at']); expect(matches).toEqual(['tan']); }); - xit('does not detect false positives',function() { + xit('does not detect false positives', function () { var subject = new Anagram('galea'); var matches = subject.matches(['eagle']); expect(matches).toEqual([]); }); - xit('detects multiple anagrams',function() { + xit('detects multiple anagrams', function () { var subject = new Anagram('master'); var matches = subject.matches(['stream', 'pigeon', 'maters']); expect(matches).toEqual(['stream', 'maters']); }); - xit('does not detect anagram subsets',function() { + xit('does not detect anagram subsets', function () { var subject = new Anagram('good'); var matches = subject.matches(['dog', 'goody']); expect(matches).toEqual([]); }); - xit('detects anagram',function() { + xit('detects anagram', function () { var subject = new Anagram('listen'); var matches = subject.matches(['enlists', 'google', 'inlets', 'banana']); expect(matches).toEqual(['inlets']); }); - xit('detects multiple anagrams',function() { + xit('detects multiple anagrams', function () { var subject = new Anagram('allergy'); var matches = subject.matches(['gallery', 'ballerina', 'regally', 'clergy', 'largely', 'leading']); expect(matches).toEqual(['gallery', 'regally', 'largely']); }); - xit('detects anagrams case-insensitively',function() { + xit('detects anagrams case-insensitively', function () { var subject = new Anagram('Orchestra'); var matches = subject.matches(['cashregister', 'Carthorse', 'radishes']); expect(matches).toEqual(['Carthorse']); }); - xit('does not detect a word as its own anagram',function() { + xit('does not detect a word as its own anagram', function () { var subject = new Anagram('banana'); var matches = subject.matches(['Banana']); expect(matches).toEqual([]); }); - xit('matches() accepts string arguments',function() { + xit('matches() accepts string arguments', function () { var subject = new Anagram('ant'); var matches = subject.matches('stand', 'tan', 'at'); expect(matches).toEqual(['tan']); }); - xit('matches() accepts single string argument',function() { + xit('matches() accepts single string argument', function () { var subject = new Anagram('ant'); var matches = subject.matches('tan'); diff --git a/exercises/anagram/example.js b/exercises/anagram/example.js index daddd20c..2e1cee2e 100644 --- a/exercises/anagram/example.js +++ b/exercises/anagram/example.js @@ -4,13 +4,13 @@ function Anagram(word) { this.word = word; } -Anagram.prototype.matches = function (words) { - words = Array.isArray(words) ? words : [].slice.call(arguments, 0); +Anagram.prototype.matches = function (wordList) { + var words = Array.isArray(wordList) ? wordList : [].slice.call(arguments, 0); return words.filter(function (candidate) { return !sameWord(this.word, candidate) && isAnagram(this.word, candidate); }, this); -} +}; function sameWord(word, candidate) { return word.toLowerCase() === candidate.toLowerCase(); diff --git a/exercises/armstrong-numbers/README.md b/exercises/armstrong-numbers/README.md new file mode 100644 index 00000000..f0714aa7 --- /dev/null +++ b/exercises/armstrong-numbers/README.md @@ -0,0 +1,46 @@ +# Armstrong Numbers + +An [Armstrong number](https://en.wikipedia.org/wiki/Narcissistic_number) is a number that is the sum of its own digits each raised to the power of the number of digits. + +For example: + +- 9 is an Armstrong number, because `9 = 9^1 = 9` +- 10 is *not* an Armstrong number, because `10 != 1^2 + 0^2 = 2` +- 153 is an Armstrong number, because: `153 = 1^3 + 5^3 + 3^3 = 1 + 125 + 27 = 153` +- 154 is *not* an Armstrong number, because: `154 != 1^3 + 5^3 + 4^3 = 1 + 125 + 64 = 190` + +Write some code to determine whether a number is an Armstrong number. + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine armstrong-numbers.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Wikipedia [Narcissistic number](https://en.wikipedia.org/wiki/Narcissistic_number) + +## Submitting Incomplete Solutions + +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/armstrong-numbers/armstrong-numbers.spec.js b/exercises/armstrong-numbers/armstrong-numbers.spec.js new file mode 100644 index 00000000..9f250fac --- /dev/null +++ b/exercises/armstrong-numbers/armstrong-numbers.spec.js @@ -0,0 +1,43 @@ +var ArmstrongNumber = require('./armstrong-numbers'); + +describe('ArmstrongNumber', function () { + it('Single digit numbers are Armstrong numbers', function () { + var input = 5; + expect(ArmstrongNumber.validate(input)).toBe(true); + }); + + xit('There are no 2 digit Armstrong numbers', function () { + var input = 10; + expect(ArmstrongNumber.validate(input)).toBe(false); + }); + + xit('Three digit number that is an Armstrong number', function () { + var input = 153; + expect(ArmstrongNumber.validate(input)).toBe(true); + }); + + xit('Three digit number that is not an Armstrong number', function () { + var input = 100; + expect(ArmstrongNumber.validate(input)).toBe(false); + }); + + xit('Four digit number that is an Armstrong number', function () { + var input = 9474; + expect(ArmstrongNumber.validate(input)).toBe(true); + }); + + xit('Four digit number that is not an Armstrong number', function () { + var input = 9475; + expect(ArmstrongNumber.validate(input)).toBe(false); + }); + + xit('Seven digit number that is an Armstrong number', function () { + var input = 9926315; + expect(ArmstrongNumber.validate(input)).toBe(true); + }); + + xit('Seven digit number that is not an Armstrong number', function () { + var input = 9926314; + expect(ArmstrongNumber.validate(input)).toBe(false); + }); +}); diff --git a/exercises/armstrong-numbers/example.js b/exercises/armstrong-numbers/example.js new file mode 100644 index 00000000..c0652924 --- /dev/null +++ b/exercises/armstrong-numbers/example.js @@ -0,0 +1,11 @@ +'use strict'; + +module.exports = { + validate: function (input) { + var digits = String(input).split(''); + var sum = digits.reduce(function (total, current) { + return total + Math.pow(current, digits.length); + }, 0); + return sum === input; + } +}; diff --git a/exercises/atbash-cipher/README.md b/exercises/atbash-cipher/README.md index 57634176..a34b50ab 100644 --- a/exercises/atbash-cipher/README.md +++ b/exercises/atbash-cipher/README.md @@ -9,7 +9,7 @@ letter, the second with the second-last, and so on. An Atbash cipher for the Latin alphabet would be as follows: -```plain +```text Plain: abcdefghijklmnopqrstuvwxyz Cipher: zyxwvutsrqponmlkjihgfedcba ``` @@ -23,32 +23,36 @@ being 5 letters, and punctuation is excluded. This is to make it harder to guess things based on word boundaries. ## Examples + - Encoding `test` gives `gvhg` - Decoding `gvhg` gives `test` - Decoding `gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt` gives `thequickbrownfoxjumpsoverthelazydog` ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine atbash-cipher.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/atbash-cipher/atbash-cipher.spec.js b/exercises/atbash-cipher/atbash-cipher.spec.js index 73f73e07..07c9f554 100644 --- a/exercises/atbash-cipher/atbash-cipher.spec.js +++ b/exercises/atbash-cipher/atbash-cipher.spec.js @@ -1,39 +1,37 @@ var atbash = require('./atbash-cipher'); -describe('encode', function() { - - it('encodes no', function() { +describe('encode', function () { + it('encodes no', function () { expect(atbash.encode('no')).toEqual('ml'); }); - xit('encodes yes', function() { + xit('encodes yes', function () { expect(atbash.encode('yes')).toEqual('bvh'); }); - xit('encodes OMG', function() { + xit('encodes OMG', function () { expect(atbash.encode('OMG')).toEqual('lnt'); }); - xit('encodes O M G', function() { + xit('encodes O M G', function () { expect(atbash.encode('O M G')).toEqual('lnt'); }); - xit('encodes long words', function() { + xit('encodes long words', function () { expect(atbash.encode('mindblowingly')).toEqual('nrmwy oldrm tob'); }); - xit('encodes numbers', function() { + xit('encodes numbers', function () { expect(atbash.encode('Testing, 1 2 3, testing.')) .toEqual('gvhgr mt123 gvhgr mt'); }); - xit('encodes sentences', function() { + xit('encodes sentences', function () { expect(atbash.encode('Truth is fiction.')).toEqual('gifgs rhurx grlm'); }); - xit('encodes all the things', function() { + xit('encodes all the things', function () { expect(atbash.encode('The quick brown fox jumps over the lazy dog.')) .toEqual('gsvjf rxpyi ldmul cqfnk hlevi gsvoz abwlt'); }); - }); diff --git a/exercises/atbash-cipher/example.js b/exercises/atbash-cipher/example.js index 6c301bfe..c93608fa 100644 --- a/exercises/atbash-cipher/example.js +++ b/exercises/atbash-cipher/example.js @@ -9,7 +9,7 @@ function insertSpacing(s, interval) { } function invert(character) { - /*jshint validthis: true */ + /* jshint validthis: true */ if (character.match(/\d/)) { this.push(character); } else { @@ -25,4 +25,4 @@ module.exports = { encoded = insertSpacing(characters.join(''), 5); return encoded; } -}; \ No newline at end of file +}; diff --git a/exercises/beer-song/README.md b/exercises/beer-song/README.md index 57089d1d..ffd71e31 100644 --- a/exercises/beer-song/README.md +++ b/exercises/beer-song/README.md @@ -1,10 +1,10 @@ # Beer Song -Produce the lyrics to that beloved classic, that field-trip favorite: 99 Bottles of Beer on the Wall. +Recite the lyrics to that beloved classic, that field-trip favorite: 99 Bottles of Beer on the Wall. Note that not all verses are identical. -```plain +```text 99 bottles of beer on the wall, 99 bottles of beer. Take one down and pass it around, 98 bottles of beer on the wall. @@ -322,26 +322,29 @@ experiment make the code better? Worse? Did you learn anything from it? ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine beer-song.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/beer-song/beer-song.spec.js b/exercises/beer-song/beer-song.spec.js index d77d7e2d..b83908a1 100644 --- a/exercises/beer-song/beer-song.spec.js +++ b/exercises/beer-song/beer-song.spec.js @@ -1,34 +1,34 @@ var BeerSong = require('./beer-song'); -describe('BeerSong', function() { +describe('BeerSong', function () { var song = new BeerSong(); - it('prints an arbitrary verse', function() { + it('prints an arbitrary verse', function () { var expected = '8 bottles of beer on the wall, 8 bottles of beer.\nTake one down and pass it around, 7 bottles of beer on the wall.\n'; expect(song.verse(8)).toEqual(expected); }); - xit('handles 2 bottles', function() { + xit('handles 2 bottles', function () { var expected = '2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n'; expect(song.verse(2)).toEqual(expected); }); - xit('handles 1 bottle', function() { + xit('handles 1 bottle', function () { var expected = '1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n'; expect(song.verse(1)).toEqual(expected); }); - xit('handles 0 bottles', function() { + xit('handles 0 bottles', function () { var expected = 'No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n'; expect(song.verse(0)).toEqual(expected); }); - xit('sings several verses', function() { + xit('sings several verses', function () { var expected = '8 bottles of beer on the wall, 8 bottles of beer.\nTake one down and pass it around, 7 bottles of beer on the wall.\n\n7 bottles of beer on the wall, 7 bottles of beer.\nTake one down and pass it around, 6 bottles of beer on the wall.\n\n6 bottles of beer on the wall, 6 bottles of beer.\nTake one down and pass it around, 5 bottles of beer on the wall.\n'; expect(song.sing(8, 6)).toEqual(expected); }); - xit('sings the rest of the verses', function() { + xit('sings the rest of the verses', function () { var expected = '3 bottles of beer on the wall, 3 bottles of beer.\nTake one down and pass it around, 2 bottles of beer on the wall.\n\n2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n\n1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n\nNo more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n'; expect(song.sing(3)).toEqual(expected); }); diff --git a/exercises/beer-song/example.js b/exercises/beer-song/example.js index 26e7299d..89f31811 100644 --- a/exercises/beer-song/example.js +++ b/exercises/beer-song/example.js @@ -1,4 +1,4 @@ -(function() { +(function () { 'use strict'; function bottles(number) { @@ -15,50 +15,54 @@ return str; } - function action(current_verse) { - var sbj, str = ''; + function action(currentVerse) { + var sbj; + var str = ''; - if (current_verse === 0) { + if (currentVerse === 0) { str = 'Go to the store and buy some more, '; } else { - sbj = (current_verse === 1 ? 'it' : 'one'); + sbj = (currentVerse === 1 ? 'it' : 'one'); str = 'Take ' + sbj + ' down and pass it around, '; } return str; } - function next_bottle(current_verse) { - return bottles(next_verse(current_verse)).toLowerCase() + ' of beer on the wall.\n'; + function nextBottle(currentVerse) { + return bottles(nextVerse(currentVerse)).toLowerCase() + ' of beer on the wall.\n'; } - function next_verse(current_verse) { - return current_verse === 0 ? 99 : (current_verse - 1); + function nextVerse(currentVerse) { + return currentVerse === 0 ? 99 : (currentVerse - 1); } function BeerSong() {} - BeerSong.prototype.sing = function(first, last) { - if (typeof(first) === 'undefined') { - first = 99; + BeerSong.prototype.sing = function (first, last) { + var firstVerseBottleCount = first; + var lastVerseBottleCount = last; + + if (typeof (firstVerseBottleCount) === 'undefined') { + firstVerseBottleCount = 99; } - if (typeof(last) === 'undefined') { - last = 0; + if (typeof (lastVerseBottleCount) === 'undefined') { + lastVerseBottleCount = 0; } var verses = []; - for (var i = first; i >= last; i--) { + for (var i = firstVerseBottleCount; i >= lastVerseBottleCount; i--) { verses.push(this.verse(i)); } return verses.join('\n'); }; - BeerSong.prototype.verse = function(number) { + BeerSong.prototype.verse = function (number) { var line1 = bottles(number) + ' of beer on the wall, '; var line2 = bottles(number).toLowerCase() + ' of beer.\n'; var line3 = action(number); - var line4 = next_bottle(number); + var line4 = nextBottle(number); return [line1, line2, line3, line4].join(''); }; diff --git a/exercises/binary-search-tree/README.md b/exercises/binary-search-tree/README.md index 5b864ebc..798ea8f2 100644 --- a/exercises/binary-search-tree/README.md +++ b/exercises/binary-search-tree/README.md @@ -55,26 +55,29 @@ And if we then added 1, 5, and 7, it would look like this ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine binary-search-tree.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/binary-search-tree/binary-search-tree.spec.js b/exercises/binary-search-tree/binary-search-tree.spec.js index 16f3c307..e2a2ba2d 100644 --- a/exercises/binary-search-tree/binary-search-tree.spec.js +++ b/exercises/binary-search-tree/binary-search-tree.spec.js @@ -8,13 +8,12 @@ function recordAllData(bst) { return out; } -describe('BinarySearchTree', function() { - - it('data is retained', function() { +describe('BinarySearchTree', function () { + it('data is retained', function () { expect(new Bst(4).data).toEqual(4); }); - xit('inserting less', function() { + xit('inserting less', function () { var four; four = new Bst(4); @@ -24,7 +23,7 @@ describe('BinarySearchTree', function() { expect(four.left.data).toEqual(2); }); - xit('inserting same', function() { + xit('inserting same', function () { var four; four = new Bst(4); @@ -34,7 +33,7 @@ describe('BinarySearchTree', function() { expect(four.left.data).toEqual(4); }); - xit('inserting right', function() { + xit('inserting right', function () { var four; four = new Bst(4); @@ -44,7 +43,7 @@ describe('BinarySearchTree', function() { expect(four.right.data).toEqual(5); }); - xit('complex tree', function() { + xit('complex tree', function () { var four; four = new Bst(4); @@ -64,11 +63,11 @@ describe('BinarySearchTree', function() { expect(four.right.right.data).toEqual(7); }); - xit('iterating one element', function() { + xit('iterating one element', function () { expect(recordAllData(new Bst(4))).toEqual([4]); }); - xit('iterating over smaller element', function() { + xit('iterating over smaller element', function () { var four; four = new Bst(4); @@ -77,7 +76,7 @@ describe('BinarySearchTree', function() { expect(recordAllData(four)).toEqual([2, 4]); }); - xit('iterating over larger element', function() { + xit('iterating over larger element', function () { var four; four = new Bst(4); @@ -86,7 +85,7 @@ describe('BinarySearchTree', function() { expect(recordAllData(four)).toEqual([4, 5]); }); - xit('iterating over complex tree', function() { + xit('iterating over complex tree', function () { var four; four = new Bst(4); @@ -99,5 +98,4 @@ describe('BinarySearchTree', function() { expect(recordAllData(four)).toEqual([1, 2, 3, 4, 5, 6, 7]); }); - }); diff --git a/exercises/binary-search-tree/example.js b/exercises/binary-search-tree/example.js index 7d6f1670..edc3af96 100644 --- a/exercises/binary-search-tree/example.js +++ b/exercises/binary-search-tree/example.js @@ -2,11 +2,11 @@ function BinarySearchTree(data) { this.data = data; - this.left = undefined; - this.right = undefined; + this.left = null; + this.right = null; } -BinarySearchTree.prototype.insert = function(value) { +BinarySearchTree.prototype.insert = function (value) { if (value <= this.data) { this.insertLeft(value); } else { @@ -16,7 +16,7 @@ BinarySearchTree.prototype.insert = function(value) { return this; }; -BinarySearchTree.prototype.insertLeft = function(value) { +BinarySearchTree.prototype.insertLeft = function (value) { if (!this.left) { this.left = new BinarySearchTree(value); } else { @@ -26,7 +26,7 @@ BinarySearchTree.prototype.insertLeft = function(value) { return this; }; -BinarySearchTree.prototype.insertRight = function(value) { +BinarySearchTree.prototype.insertRight = function (value) { if (!this.right) { this.right = new BinarySearchTree(value); } else { @@ -36,7 +36,7 @@ BinarySearchTree.prototype.insertRight = function(value) { return this; }; -BinarySearchTree.prototype.each = function(fn) { +BinarySearchTree.prototype.each = function (fn) { if (this.left) { this.left.each(fn); } fn.call(this, this.data); if (this.right) { this.right.each(fn); } diff --git a/exercises/binary-search/README.md b/exercises/binary-search/README.md index 2aa09ad1..c3f4cb4c 100644 --- a/exercises/binary-search/README.md +++ b/exercises/binary-search/README.md @@ -36,26 +36,29 @@ A binary search is a dichotomic divide and conquer search algorithm. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine binary-search.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/binary-search/binary-search.spec.js b/exercises/binary-search/binary-search.spec.js index 773b22f3..12efc126 100644 --- a/exercises/binary-search/binary-search.spec.js +++ b/exercises/binary-search/binary-search.spec.js @@ -1,12 +1,11 @@ var BinarySearch = require('./binary-search'); -describe('BinarySearch', function() { - +describe('BinarySearch', function () { var sortedArray = [1, 2, 3, 4, 5, 6]; var sortedArrayOfOddLength = [0, 1, 2, 2, 3, 10, 12]; var unsortedArray = [10, 2, 5, 1]; - it ('should require a sorted array', function() { + it('should require a sorted array', function () { var invalidBinarySearch = new BinarySearch(unsortedArray); var validBinarySearch = new BinarySearch(sortedArray); @@ -14,23 +13,23 @@ describe('BinarySearch', function() { expect(Array.isArray(validBinarySearch.array)).toEqual(true); }); - xit('should find the correct index of an included value in the middle of the array', function() { + xit('should find the correct index of an included value in the middle of the array', function () { expect(new BinarySearch(sortedArray).indexOf(3)).toEqual(2); }); - xit('should find the correct index of an included value at the beginning of the array', function() { + xit('should find the correct index of an included value at the beginning of the array', function () { expect(new BinarySearch(sortedArray).indexOf(1)).toEqual(0); }); - xit('should find the correct index of an included value at the end of the array', function() { + xit('should find the correct index of an included value at the end of the array', function () { expect(new BinarySearch(sortedArray).indexOf(6)).toEqual(5); }); - xit('should search the middle of the array', function() { + xit('should search the middle of the array', function () { expect(new BinarySearch(sortedArrayOfOddLength).indexOf(2)).toEqual(3); }); - xit('should return -1 for a value not in the array', function() { + xit('should return -1 for a value not in the array', function () { expect(new BinarySearch(sortedArray).indexOf(10)).toEqual(-1); }); }); diff --git a/exercises/binary-search/example.js b/exercises/binary-search/example.js index 00ad0eab..a1fd178f 100644 --- a/exercises/binary-search/example.js +++ b/exercises/binary-search/example.js @@ -1,25 +1,24 @@ 'use strict'; function BinarySearch(array) { - - //check if array is sorted + // check if array is sorted var arrayIsSorted = true; for (var i = 1; i < array.length; i++) { if (array[i] < array[i - 1]) arrayIsSorted = false; } - //instantiate the array if sorted + // instantiate the array if sorted if (arrayIsSorted) this.array = array; - //use binary search for indexOf - this.indexOf = function(value) { + // use binary search for indexOf + this.indexOf = function (value) { return recursiveSearch(this.array, value, 0, this.array.length); }; } function recursiveSearch(array, value, start, end) { - if (start == end) return -1; + if (start === end) return -1; var mid = Math.floor((start + end) / 2); @@ -32,4 +31,4 @@ function recursiveSearch(array, value, start, end) { return mid; } -module.exports = BinarySearch; \ No newline at end of file +module.exports = BinarySearch; diff --git a/exercises/binary/README.md b/exercises/binary/README.md index c41024b0..363c47bd 100644 --- a/exercises/binary/README.md +++ b/exercises/binary/README.md @@ -7,10 +7,12 @@ string, your program should produce a decimal output. The program should handle invalid inputs. ## Note + - Implement the conversion yourself. Do not use something else to perform the conversion for you. ## About Binary (Base-2) + Decimal is a base-10 system. A number 23 in base 10 notation can be understood @@ -30,26 +32,29 @@ So: `101 => 1*2^2 + 0*2^1 + 1*2^0 => 1*4 + 0*2 + 1*1 => 4 + 1 => 5 base 10`. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine binary.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/binary/binary.spec.js b/exercises/binary/binary.spec.js index b90f7d0e..a7fe1c35 100644 --- a/exercises/binary/binary.spec.js +++ b/exercises/binary/binary.spec.js @@ -1,48 +1,47 @@ var Binary = require('./binary'); -describe('binary', function() { - it('0 is decimal 0', function() { +describe('binary', function () { + it('0 is decimal 0', function () { expect(new Binary('0').toDecimal()).toEqual(0); }); - xit('1 is decimal 1', function() { + xit('1 is decimal 1', function () { expect(new Binary('1').toDecimal()).toEqual(1); }); - xit('10 is decimal 2', function() { + xit('10 is decimal 2', function () { expect(new Binary('10').toDecimal()).toEqual(2); }); - xit('11 is decimal 3', function() { + xit('11 is decimal 3', function () { expect(new Binary('11').toDecimal()).toEqual(3); }); - xit('100 is decimal 4', function() { + xit('100 is decimal 4', function () { expect(new Binary('100').toDecimal()).toEqual(4); }); - xit('1001 is decimal 9', function() { + xit('1001 is decimal 9', function () { expect(new Binary('1001').toDecimal()).toEqual(9); }); - xit('11010 is decimal 26', function() { + xit('11010 is decimal 26', function () { expect(new Binary('11010').toDecimal()).toEqual(26); }); - xit('10001101000 is decimal 1128', function() { + xit('10001101000 is decimal 1128', function () { expect(new Binary('10001101000').toDecimal()).toEqual(1128); }); - xit('00011111 is decimal 31', function() { + xit('00011111 is decimal 31', function () { expect(new Binary('00011111').toDecimal()).toEqual(31); }); - xit('invalid inputs are decimal 0', function() { + xit('invalid inputs are decimal 0', function () { expect(new Binary('carrot').toDecimal()).toEqual(0); expect(new Binary('012').toDecimal()).toEqual(0); expect(new Binary('10nope').toDecimal()).toEqual(0); expect(new Binary('nope10').toDecimal()).toEqual(0); expect(new Binary('10nope10').toDecimal()).toEqual(0); }); - }); diff --git a/exercises/bob/README.md b/exercises/bob/README.md index b53ec785..ee9c8adb 100644 --- a/exercises/bob/README.md +++ b/exercises/bob/README.md @@ -6,6 +6,8 @@ Bob answers 'Sure.' if you ask him a question. He answers 'Whoa, chill out!' if you yell at him. +He answers 'Calm down, I know what I'm doing!' if you yell a question at him. + He says 'Fine. Be that way!' if you address him without actually saying anything. @@ -13,26 +15,29 @@ He answers 'Whatever.' to anything else. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine bob.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/bob/bob.spec.js b/exercises/bob/bob.spec.js index 5a008481..fc017cd1 100644 --- a/exercises/bob/bob.spec.js +++ b/exercises/bob/bob.spec.js @@ -45,7 +45,7 @@ describe('Bob', function () { xit('forceful questions', function () { var result = bob.hey('WHAT THE HELL WERE YOU THINKING?'); - expect(result).toEqual('Whoa, chill out!'); + expect(result).toEqual("Calm down, I know what I'm doing!"); }); xit('shouting numbers', function () { @@ -122,5 +122,4 @@ describe('Bob', function () { var result = bob.hey('This is a statement ending with whitespace '); expect(result).toEqual('Whatever.'); }); - }); diff --git a/exercises/bob/example.js b/exercises/bob/example.js index 6526bd7a..b7fa2913 100644 --- a/exercises/bob/example.js +++ b/exercises/bob/example.js @@ -13,17 +13,19 @@ function Bob() { return message[message.length - 1] === '?'; } - this.hey = function(input) { + this.hey = function (input) { var message = input.trim(); if (isSilence(message)) { return 'Fine. Be that way!'; } else if (isShouting(message)) { + if (isAQuestion(message)) { + return "Calm down, I know what I'm doing!"; + } return 'Whoa, chill out!'; } else if (isAQuestion(message)) { return 'Sure.'; - } else { - return 'Whatever.'; } + return 'Whatever.'; }; } diff --git a/exercises/bowling/README.md b/exercises/bowling/README.md index b8342c33..d1d52f8d 100644 --- a/exercises/bowling/README.md +++ b/exercises/bowling/README.md @@ -2,19 +2,29 @@ Score a bowling game. -Bowling is game where players roll a heavy ball to knock down pins +Bowling is a game where players roll a heavy ball to knock down pins arranged in a triangle. Write code to keep track of the score of a game of bowling. ## Scoring Bowling -The game consists of 10 frames. A frame is composed of one or two ball throws with 10 pins standing at frame initialization. There are three cases for the tabulation of a frame. +The game consists of 10 frames. A frame is composed of one or two ball +throws with 10 pins standing at frame initialization. There are three +cases for the tabulation of a frame. -* An open frame is where a score of less than 10 is recorded for the frame. In this case the score for the frame is the number of pins knocked down. +* An open frame is where a score of less than 10 is recorded for the + frame. In this case the score for the frame is the number of pins + knocked down. -* A spare is where all ten pins are knocked down after the second throw. The total value of a spare is 10 plus the number of pins knocked down in their next throw. +* A spare is where all ten pins are knocked down by the second + throw. The total value of a spare is 10 plus the number of pins + knocked down in their next throw. -* A strike is where all ten pins are knocked down after the first throw. The total value of a strike is 10 plus the number of pins knocked down in their next two throws. If a strike is immediately followed by a second strike, then we can not total the value of first strike until they throw the ball one more time. +* A strike is where all ten pins are knocked down by the first + throw. The total value of a strike is 10 plus the number of pins + knocked down in the next two throws. If a strike is immediately + followed by a second strike, then the value of the first strike + cannot be determined until the ball is thrown one more time. Here is a three frame example: @@ -30,7 +40,11 @@ Frame 3 is (9 + 0) = 9 This means the current running total is 48. -The tenth frame in the game is a special case. If someone throws a strike or a spare then they get a fill ball. Fill balls exist to calculate the total of the 10th frame. Scoring a strike or spare on the fill ball does not give the player more fill balls. The total value of the 10th frame is the total number of pins knocked down. +The tenth frame in the game is a special case. If someone throws a +strike or a spare then they get a fill ball. Fill balls exist to +calculate the total of the 10th frame. Scoring a strike or spare on +the fill ball does not give the player more fill balls. The total +value of the 10th frame is the total number of pins knocked down. For a tenth frame of X1/ (strike and a spare), the total value is 20. @@ -48,26 +62,29 @@ support two operations: ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine bowling.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/bowling/bowling.spec.js b/exercises/bowling/bowling.spec.js index 2804ee5a..c78b2f9d 100644 --- a/exercises/bowling/bowling.spec.js +++ b/exercises/bowling/bowling.spec.js @@ -1,148 +1,228 @@ var Bowling = require('./bowling'); -describe('Bowling', function() { - describe('Check game can be scored correctly.', function() { - it('should be able to score a game with all gutterballs', function() { +describe('Bowling', function () { + function previousRolls(bowling, rolls) { + for (var i = 0; i < rolls.length; i++) { + bowling.roll(rolls[i]); + } + } + describe('Check game can be scored correctly.', function () { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(0); }); - xit('should be able to score a game with all open frames', function() { + xit('should be able to score a game with no strikes or spares', 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(90); }); - xit('a spare followed by zeros is worth ten points', function() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(10); }); - xit('points scored in the roll after a spare are counted twice', function() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(16); }); - xit('consecutive spares each get a one roll bonus', function() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(31); }); - xit('should allow fill ball when the last frame is a spare', function() { + xit('should allow fill ball 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(17); }); - xit('a strike earns ten points in a frame with a single roll', function() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(10); }); - xit('points scored in the two rolls after a strike are counted twice as a bonus', function() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(26); }); - xit('should be able to score multiple strikes in a row', function() { + xit('should be able to score multiple strikes in a row', function () { var rolls = [10, 10, 10, 5, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - expect(new Bowling(rolls).score()).toEqual(81); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(81); }); - xit('should allow fill balls when the last frame is a strike', function() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(18); }); - xit('rolling a spare with the two roll bonus does not get a bonus roll', function() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(20); }); - xit('strikes with the two roll bonus do not get bonus rolls', 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(30); }); - xit('a strike with the one roll bonus after a spare in the last frame does not get a bonus', function() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(20); }); - xit('should be able to score a perfect game', function() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(300); }); }); - describe('Check game rules.', function() { - 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')); - }); - - 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')); - }); - - 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( + describe('Check game rules.', function () { + xit('rolls cannot score negative points', function () { + var bowling = new Bowling(); + expect(function () {bowling.roll(-1);}).toThrow(new Error('Negative roll is invalid')); + }); + + xit('a roll cannot score more than 10 points', function () { + var bowling = new Bowling(); + expect(function () {bowling.roll(11);}).toThrow( new Error('Pin count exceeds pins on the lane')); + }); + + xit('two rolls in a frame cannot score more than 10 points', function () { + var bowling = new Bowling(); + bowling.roll(5); + expect(function () {bowling.roll(6);}).toThrow( new Error('Pin count exceeds pins on the lane')); + }); + + xit('bonus roll after a strike in the last frame cannot 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]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(11); }).toThrow( 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 cannot 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]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () {bowling.roll(6);}).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() { + 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); + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(bowling.score()).toEqual(26); }); - 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')); + xit('the second bonus roll after a strike in the last frame cannot 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]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(10); }).toThrow( + new Error('Pin count exceeds pins on the lane')); }); - xit('an unstarted game can not be scored', function() { + xit('the second bonus roll after a strike in the last frame cannot 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, 10]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(11); }).toThrow( + new Error('Pin count exceeds pins on the lane')); + }); + + xit('an unstarted game cannot be scored', function () { var rolls = []; - expect(function() { new Bowling(rolls).score(); }).toThrow( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); - xit('an incomplete game can not be scored', function() { + xit('an incomplete game cannot be scored', function () { var rolls = [0, 0]; - expect(function() { new Bowling(rolls).score(); }).toThrow( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); - 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')); + xit('cannot roll if game already has 10 frames', function () { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(0); }).toThrow( + new Error('Cannot roll after game is over')); }); - xit('bonus rolls for a strike in the last frame must be rolled before score can be calculated', function() { + 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( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.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() { + 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( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () {bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); - xit('bonus roll for a spare in the last frame must be rolled before score can be calculated', function() { + 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( + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.score(); }).toThrow( new Error('Score cannot be taken until the end of the game')); }); + + xit('cannot roll after bonus roll for a spare', function () { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 3, 2]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(2); }).toThrow( + new Error('Cannot roll after game is over')); + }); + + xit('cannot roll after bonus rolls for a strike', function () { + var rolls = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 3, 2]; + var bowling = new Bowling(); + previousRolls(bowling, rolls); + expect(function () { bowling.roll(2); }).toThrow( + new Error('Cannot roll after game is over')); + }); }); -}); \ No newline at end of file +}); diff --git a/exercises/bowling/example.js b/exercises/bowling/example.js index 69b71027..ea2a29b1 100644 --- a/exercises/bowling/example.js +++ b/exercises/bowling/example.js @@ -1,69 +1,135 @@ 'use strict'; -function Bowling(rolls) { - this.rolls = rolls; -} +function Bowling() { + var maxPins = 10; + var maxFrames = 10; + var frames = []; + var frameScores = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; -Bowling.prototype.score = function() { - var initialState = { - frameNumber: 1, - rollNumber: 1, - pinsRemaining: 10, - spareLastFrame: false, - strikeLastFrame: false, - twoStrikesInARow: false, - fillBall: false, - score: 0 - }; + var currentFrame = 0; + var frameRoll = 1; + var remainingPins = maxPins; - var finalState = this.rolls.reduce(function(state, roll) { - if (roll < 0 || roll > 10) { - throw new Error('Pins must have a value from 0 to 10'); - } + initializeFrame(); - if (roll > state.pinsRemaining) { - throw new Error('Pin count exceeds pins on the lane'); + function initializeFrame() { + frameRoll = 1; + remainingPins = maxPins; + currentFrame++; + } + + function incrementScore(pins) { + if (currentFrame > maxFrames) return; + frameScores[currentFrame - 1] += pins; + } + + function scoreStrike() { + frames[currentFrame - 1] = 'X'; + applyStrikeBonus(maxPins); + applySpareBonus(maxPins); + frameRoll++; + } + + function scoreFirstRoll(pins) { + remainingPins = remainingPins - pins; + applySpareBonus(pins); + applyStrikeBonus(pins); + frameRoll++; + } + + function scoreSpare(pins) { + frames[currentFrame - 1] = 'S'; + applyStrikeBonus(pins); + frameRoll++; + } + + function scoreOpenFrame(pins) { + frames[currentFrame - 1] = (maxPins - remainingPins) + pins; + applyStrikeBonus(pins); + frameRoll++; + } + + function applySpareBonus(pins) { + // pins on the first roll after a spare are counted twice (on the frame of spare) + if (frames[currentFrame - 2] === 'S' ) { + frameScores[currentFrame - 2] += pins; } + } - if (state.frameNumber > 10) { - throw new Error('Should not be able to roll after game is over') + function applyStrikeBonus(pins) { + // on the two rolls after a strike are counted twice (on the frame of the strike) + if (frames[currentFrame - 3] === 'X' && frames[currentFrame - 2] === 'X' && + frameRoll === 1 && currentFrame <= (maxFrames + 2)) { + frameScores[currentFrame - 3] += pins; } + if (frames[currentFrame - 2] === 'X' && currentFrame <= (maxFrames + 1)) { + frameScores[currentFrame - 2] += pins; + } + } - var finalFrame = state.frameNumber === 10; - var strike = state.rollNumber === 1 && roll === 10; - var spare = state.rollNumber === 2 && roll === state.pinsRemaining; - var frameOver = finalFrame - ? (!state.fillBall && !spare && state.rollNumber === 2) || state.rollNumber === 3 - : strike || spare || state.rollNumber === 2; + function isGameOver() { + if (currentFrame <= maxFrames) return false; - var score = state.score + roll; + if (frames[maxFrames - 1] !== 'X' && frames[maxFrames - 1] !== 'S') return true; - if (state.strikeLastFrame && state.rollNumber < 3) { score += roll; } - if (state.spareLastFrame && state.rollNumber === 1) { score += roll; } - if (state.twoStrikesInARow && state.rollNumber === 1) { score += roll; } + // spare in the last frame gets no more than bonus roll + if (frames[maxFrames - 1] === 'S' && frameRoll > 1) return true; - var next = {}; + // bonus roll after the spare in the last frame may get a strike but then the games ends without another roll + if (frames[maxFrames - 1] === 'S' && frames[maxFrames] === 'X') return true; - next.frameNumber = frameOver ? state.frameNumber + 1 : state.frameNumber; - next.rollNumber = frameOver ? 1 : state.rollNumber + 1; - next.pinsRemaining = finalFrame - ? ((strike || spare) ? 10 : state.pinsRemaining - roll) - : (frameOver ? 10 : state.pinsRemaining - roll); - next.spareLastFrame = frameOver ? spare : state.spareLastFrame; - next.strikeLastFrame = frameOver ? strike : state.strikeLastFrame; - next.twoStrikesInARow = frameOver ? strike && state.strikeLastFrame : state.twoStrikesInARow; - next.fillBall = next.fillBall || (finalFrame && (strike || spare)); - next.score = score; + if (frames[maxFrames - 1] === 'X') { + // if the first bonus roll is not a strike then finish the bonus frame + if (frames[maxFrames] !== 'X' && currentFrame > maxFrames + 1) return true; - return next; + if (frames[maxFrames] === 'X') { + // if the second bonus roll is a strike, but was still used, the game is over + if (frames[maxFrames + 1] !== 'X' && frameRoll > 1) return true; + // if the second bonus roll is a strike the game is over + if (frames[maxFrames + 1] === 'X') return true; + } + } + return false; + } - }, initialState); + this.roll = function (pins) { + if (pins < 0) { + throw new Error( 'Negative roll is invalid'); + } - if (finalState.frameNumber !== 11) { - throw new Error('Score cannot be taken until the end of the game'); - } + if (pins > remainingPins) { + throw new Error('Pin count exceeds pins on the lane'); + } - return finalState.score; -}; + if (isGameOver()) { + throw new Error('Cannot roll after game is over'); + } + + incrementScore(pins); + + if (frameRoll === 1) { + if (pins === maxPins) { + scoreStrike(); + initializeFrame(); + } else { + scoreFirstRoll(pins); + } + } else { + if (pins === remainingPins) { + scoreSpare(pins); + } else { + scoreOpenFrame(pins); + } + initializeFrame(); + } + }; + + this.score = function () { + if (!isGameOver()) { + throw new Error('Score cannot be taken until the end of the game'); + } + return frameScores.reduce(function (total, num) {return total + num;}); + }; +} module.exports = Bowling; diff --git a/exercises/bracket-push/README.md b/exercises/bracket-push/README.md index 0496d2f1..66c336ef 100644 --- a/exercises/bracket-push/README.md +++ b/exercises/bracket-push/README.md @@ -5,26 +5,29 @@ verify that all the pairs are matched and nested correctly. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine bracket-push.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/bracket-push/bracket-push.spec.js b/exercises/bracket-push/bracket-push.spec.js index 2896d0f0..fb6ed2c5 100644 --- a/exercises/bracket-push/bracket-push.spec.js +++ b/exercises/bracket-push/bracket-push.spec.js @@ -1,35 +1,35 @@ var bracket = require('./bracket-push'); -describe('bracket push', function() { - it('checks for appropriate bracketing in a set of brackets', function() { +describe('bracket push', function () { + it('checks for appropriate bracketing in a set of brackets', function () { expect(bracket('{}')).toEqual(true); }); - xit('returns false for unclosed brackets', function() { + xit('returns false for unclosed brackets', function () { expect(bracket('{{')).toEqual(false); }); - xit('returns false if brackets are out of order', function() { + xit('returns false if brackets are out of order', function () { expect(bracket('}{')).toEqual(false); }); - xit('checks bracketing in more than one pair of brackets', function() { + xit('checks bracketing in more than one pair of brackets', function () { expect(bracket('{}[]')).toEqual(true); }); - xit('checks bracketing in nested brackets', function() { + xit('checks bracketing in nested brackets', function () { expect(bracket('{[]}')).toEqual(true); }); - xit('rejects brackets that are properly balanced but improperly nested', function() { + xit('rejects brackets that are properly balanced but improperly nested', function () { expect(bracket('{[}]')).toEqual(false); }); - xit('checks bracket closure with deeper nesting', function() { + xit('checks bracket closure with deeper nesting', function () { expect(bracket('{[)][]}')).toEqual(false); }); - xit('checks bracket closure in a long string of brackets', function() { + xit('checks bracket closure in a long string of brackets', function () { expect(bracket('{[]([()])}')).toEqual(true); }); }); diff --git a/exercises/bracket-push/example.js b/exercises/bracket-push/example.js index 2d97c0ee..ace16508 100644 --- a/exercises/bracket-push/example.js +++ b/exercises/bracket-push/example.js @@ -1,6 +1,6 @@ 'use strict'; -var bracketPush = module.exports = function(input) { +var bracketPush = module.exports = function (input) { if (input.length === 0) { return true; } @@ -28,7 +28,7 @@ var bracketPush = module.exports = function(input) { for (var k = 0; k < 3; k++) { if (bracketArray[topNumber] === openArray[k]) { - if (typeof bracketArray[(topNumber + 1)] !== undefined) { + if (typeof bracketArray[(topNumber + 1)] !== 'undefined') { if (bracketArray[(topNumber + 1)] === closeArray[k]) { bracketArray.splice(topNumber, 2); return bracketPush(bracketArray); diff --git a/exercises/change/README.md b/exercises/change/README.md new file mode 100644 index 00000000..282186fe --- /dev/null +++ b/exercises/change/README.md @@ -0,0 +1,50 @@ +# Change + +Correctly determine the fewest number of coins to be given to a customer such +that the sum of the coins' value would equal the correct amount of change. + +## For example + +- An input of 15 with [1, 5, 10, 25, 100] should return one nickel (5) + and one dime (10) or [0, 1, 1, 0, 0] +- An input of 40 with [1, 5, 10, 25, 100] should return one nickel (5) + and one dime (10) and one quarter (25) or [0, 1, 1, 1, 0] + +## Edge cases + +- Does your algorithm work for any given set of coins? +- Can you ask for negative change? +- Can you ask for a change value smaller than the smallest coin value? + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine change.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Software Craftsmanship - Coin Change Kata [https://web.archive.org/web/20130115115225/http://craftsmanship.sv.cmu.edu:80/exercises/coin-change-kata](https://web.archive.org/web/20130115115225/http://craftsmanship.sv.cmu.edu:80/exercises/coin-change-kata) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/change/change.spec.js b/exercises/change/change.spec.js new file mode 100644 index 00000000..25b86012 --- /dev/null +++ b/exercises/change/change.spec.js @@ -0,0 +1,70 @@ + + +var Change = require('./change'); + +describe('Change', function () { + it('change for 1 cent', function () { + var change = new Change(); + var result = change.calculate([1, 5, 10, 25], 1); + expect(result).toEqual([1]); + }); + + xit('return a single coin', function () { + var change = new Change(); + var result = change.calculate([1, 5, 10, 25, 100], 25); + expect(result).toEqual([25]); + }); + + xit('multiple coins coin', function () { + var change = new Change(); + var result = change.calculate([1, 5, 10, 25, 100], 15); + expect(result).toEqual([5, 10]); + }); + + xit('test with Lillipution Currency where a greedy algorithm fails', function () { + // https://en.wikipedia.org/wiki/Change-making_problem#Greedy_method + var change = new Change(); + var result = change.calculate([1, 4, 15, 20, 50], 23); + expect(result).toEqual([4, 4, 15]); + }); + + xit('test with lower Elbonian Currency where a greedy algorithm fails', function () { + // https://en.wikipedia.org/wiki/Change-making_problem#Greedy_method + var change = new Change(); + var result = change.calculate([1, 5, 10, 21, 25], 63); + expect(result).toEqual([21, 21, 21]); + }); + + xit('test large amount of change', function () { + var change = new Change(); + var result = change.calculate([1, 2, 5, 10, 20, 50, 100], 999); + expect(result).toEqual([2, 2, 5, 20, 20, 50, 100, 100, 100, 100, 100, 100, 100, 100, 100]); + }); + + xit('test zero change', function () { + var change = new Change(); + var result = change.calculate([1, 5, 10, 21, 25], 0); + expect(result).toEqual([]); + }); + + xit('test less than the smallest currency represented', function () { + var change = new Change(); + var message = 'The total 3 cannot be represented in the given currency.'; + var test = function () {return change.calculate([5, 10], 3);}; + expect(test).toThrowError(Error, message); + }); + + xit('test a large value that the currency cannot represent', function () { + var change = new Change(); + var message = 'The total 94 cannot be represented in the given currency.'; + var test = function () {return change.calculate([5, 10], 94);}; + expect(test).toThrowError(Error, message); + }); + + xit('negative change is rejected', function () { + var change = new Change(); + var message = 'Negative totals are not allowed.'; + var test = function () {return change.calculate([1, 2, 5], -5);}; + expect(test).toThrowError(Error, message); + }); +}); diff --git a/exercises/change/example.js b/exercises/change/example.js new file mode 100644 index 00000000..89d3cd2a --- /dev/null +++ b/exercises/change/example.js @@ -0,0 +1,146 @@ +'use strict'; + + +var Change = function () { + + +}; + +module.exports = Change; + + +// data structure to hold each candidate solution that is generated +var Candidate = function () { + var searched = false; + var coins = []; + + this.searched = function () { + searched = true; + }; + + this.isSearched = function () { + return searched; + }; + + this.getCoins = function () { + return coins; + }; + + this.addCoin = function (coin) { + function sortNum(a, b) { + return a - b; + } + + coins.push(coin); + coins.sort(sortNum); + }; + + this.getCoinCount = function () { + return coins.length; + }; + + this.getSum = function () { + function getSum(total, num) {return total + num;} + return coins.reduce(getSum); + }; +}; + +Change.prototype.calculate = function (coinArray, target) { + var candidates = []; + // fill the array with 0 to start + candidates[target] = 0; + candidates.fill(0); + + // validation checks up front + if (target === 0) return []; + + if (target < 0) { + throw new Error( 'Negative totals are not allowed.'); + } + + if (target < Math.min.apply(null, coinArray)) { + throw new Error('The total ' + target + ' cannot be represented in the given currency.'); + } + + + initialize(); + + // process the arrange until everything is searched + while (isDone() === false) { + let candidate = getNext(); + branch(candidate); + candidate.searched(); + } + + // print the result + if (typeof (candidates[target]) !== 'number') {return candidates[target].getCoins();} + throw new Error('The total ' + target + ' cannot be represented in the given currency.'); + + // initialize the candidate array with the given coins only + function initialize() { + for (let j = 0; j < coinArray.length; j++) { + let temp = coinArray[j]; + let candidate = new Candidate(); + candidate.addCoin(temp); + saveCandidate(candidate); + } + } + + // is everthing searched? + function isDone() { + let done = true; + for (let i = 0; i < candidates.length; i++) { + let temp = candidates[i]; + if (typeof (temp) !== 'number') { + if (temp.isSearched() === false) { + done = false; + break; + } + } + } + return done; + } + + // get the next unsearched member of the candidate array + function getNext() { + for (let i = 0; i < candidates.length; i++) { + let temp = candidates[i]; + if (typeof (temp) !== 'number' && + temp.isSearched() === false) return temp; + } + return null; + } + + // save a new candidate to the candidate array + function saveCandidate(candidate) { + let sum = candidate.getSum(); + + if ( candidate.getSum() <= target && + typeof (candidates[sum]) !== 'number' && + candidates[sum].getCoinCount() > candidate.getCoinCount()) { + candidates[sum] = candidate; + } + + if (candidate.getSum() <= target && + typeof (candidates[sum]) === 'number') { + candidates[sum] = candidate; + } + } + + + // for the candidate, generate another candate for each of the possible coins + function branch(current) { + for (let j = 0; j < coinArray.length; j++) { + // make a new Candidate for coin type + let candidate = new Candidate(); + + // copy the curent coins into it and add the new coin type + for (var i = 0; i < current.getCoins().length; i++)candidate.addCoin(current.getCoins()[i]); + + candidate.addCoin(coinArray[j]); + + saveCandidate(candidate); + } + } +}; + diff --git a/exercises/circular-buffer/README.md b/exercises/circular-buffer/README.md index 14f497e5..85243a97 100644 --- a/exercises/circular-buffer/README.md +++ b/exercises/circular-buffer/README.md @@ -31,40 +31,50 @@ If the buffer has 7 elements then it is completely full: When the buffer is full an error will be raised, alerting the client that further writes are blocked until a slot becomes free. -The client can opt to overwrite the oldest data with a forced write. In -this case, two more elements — A & B — are added and they overwrite the -3 & 4: +When the buffer is full, the client can opt to overwrite the oldest +data with a forced write. In this case, two more elements — A & B — +are added and they overwrite the 3 & 4: [6][7][8][9][A][B][5] -Finally, if two elements are now removed then what would be returned is -not 3 & 4 but 5 & 6 because A & B overwrote the 3 & the 4 yielding the -buffer with: +3 & 4 have been replaced by A & B making 5 now the oldest data in the +buffer. Finally, if two elements are removed then what would be +returned is 5 & 6 yielding the buffer: [ ][7][8][9][A][B][ ] -## Setup +Because there is space available, if the client again uses overwrite +to store C & D then the space where 5 & 6 were stored previously will +be used not the location of 7 & 8. 7 is still the oldest element and +the buffer is once again full. + + [D][7][8][9][A][B][C] -Go through the setup instructions for JavaScript to -install the necessary dependencies: +## Setup -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine circular-buffer.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/circular-buffer/circular-buffer.spec.js b/exercises/circular-buffer/circular-buffer.spec.js index 5ae5e358..36b73491 100644 --- a/exercises/circular-buffer/circular-buffer.spec.js +++ b/exercises/circular-buffer/circular-buffer.spec.js @@ -2,21 +2,20 @@ var circularBuffer = require('./circular-buffer').circularBuffer; var bufferEmptyException = require('./circular-buffer').bufferEmptyException; var bufferFullException = require('./circular-buffer').bufferFullException; -describe('CircularBuffer', function() { - - it('reading an empty buffer throws a BufferEmptyException', function() { +describe('CircularBuffer', function () { + it('reading an empty buffer throws a BufferEmptyException', function () { var buffer = circularBuffer(1); expect(buffer.read).toThrow(bufferEmptyException()); }); - xit('write and read back one item', function() { + xit('write and read back one item', function () { var buffer = circularBuffer(1); buffer.write('1'); expect(buffer.read()).toBe('1'); expect(buffer.read).toThrow(bufferEmptyException()); }); - xit('write and read back multiple items', function() { + xit('write and read back multiple items', function () { var buffer = circularBuffer(2); buffer.write('1'); buffer.write('2'); @@ -25,7 +24,7 @@ describe('CircularBuffer', function() { expect(buffer.read).toThrow(bufferEmptyException()); }); - xit('clearing a buffer', function() { + xit('clearing a buffer', function () { var buffer = circularBuffer(2); buffer.write('1'); buffer.write('2'); @@ -37,7 +36,7 @@ describe('CircularBuffer', function() { expect(buffer.read()).toBe('4'); }); - xit('alternate write and read', function() { + xit('alternate write and read', function () { var buffer = circularBuffer(2); buffer.write('1'); expect(buffer.read()).toBe('1'); @@ -45,7 +44,7 @@ describe('CircularBuffer', function() { expect(buffer.read()).toBe('2'); }); - xit('reads back oldest item', function() { + xit('reads back oldest item', function () { var buffer = circularBuffer(3); buffer.write('1'); buffer.write('2'); @@ -55,24 +54,24 @@ describe('CircularBuffer', function() { expect(buffer.read()).toBe('3'); }); - xit('writes of undefined or null don\'t occupy buffer', function() { + xit('writes of undefined or null don\'t occupy buffer', function () { var buffer = circularBuffer(3); buffer.write(null); - buffer.write(undefined); - [1,2,3].map(function(i) { buffer.write(i.toString()); }); + buffer.write(undefined); // eslint-disable-line no-undefined + [1, 2, 3].map(function (i) { buffer.write(i.toString()); }); expect(buffer.read()).toBe('1'); }); - xit('writing to a full buffer throws a BufferFullException', function() { + xit('writing to a full buffer throws a BufferFullException', function () { var buffer = circularBuffer(2); buffer.write('1'); buffer.write('2'); - expect(function() { + expect(function () { buffer.write('A'); }).toThrow(bufferFullException()); }); - xit('forced writes over write oldest item in a full buffer', function() { + xit('forced writes over write oldest item in a full buffer', function () { var buffer = circularBuffer(2); buffer.write('1'); buffer.write('2'); @@ -82,7 +81,7 @@ describe('CircularBuffer', function() { expect(buffer.read).toThrow(bufferEmptyException()); }); - xit('forced writes act like write in a non-full buffer', function() { + xit('forced writes act like write in a non-full buffer', function () { var buffer = circularBuffer(2); buffer.write('1'); buffer.forceWrite('2'); @@ -91,14 +90,14 @@ describe('CircularBuffer', function() { expect(buffer.read).toThrow(bufferEmptyException()); }); - xit('alternate force write and read into full buffer', function() { + xit('alternate force write and read into full buffer', function () { var buffer = circularBuffer(5); - [1,2,3].map(function(i) { buffer.write(i.toString()); }); + [1, 2, 3].map(function (i) { buffer.write(i.toString()); }); buffer.read(); buffer.read(); buffer.write('4'); buffer.read(); - [5,6,7,8].map(function(i) { buffer.write(i.toString()); }); + [5, 6, 7, 8].map(function (i) { buffer.write(i.toString()); }); buffer.forceWrite('A'); buffer.forceWrite('B'); expect(buffer.read()).toBe('6'); @@ -109,12 +108,11 @@ describe('CircularBuffer', function() { expect(buffer.read).toThrow(bufferEmptyException()); }); - xit('multiple buffers don\'t interfere with each other', function() { + xit('multiple buffers don\'t interfere with each other', function () { var buffer1 = circularBuffer(1); var buffer2 = circularBuffer(1); buffer1.write('1'); expect(buffer2.read).toThrow(bufferEmptyException()); expect(buffer1.read()).toBe('1'); }); - }); diff --git a/exercises/circular-buffer/example.js b/exercises/circular-buffer/example.js index c289472d..e636d4a0 100644 --- a/exercises/circular-buffer/example.js +++ b/exercises/circular-buffer/example.js @@ -1,99 +1,97 @@ function CircularBuffer(capacity) { - var readPoint = 0; var writePoint = 0; var buffer = new Array(capacity); return { - read: function() { - if (isBufferEmpty()) { throw new BufferEmptyException(); } - var data = buffer[readPoint]; - buffer[readPoint] = null; - updateReadPoint(); - return data; - }, - - write: function(data) { - updateBuffer(data, function() { - if (isBufferFull()) { throw new BufferFullException(); } - buffer[writePoint] = data; - }); - }, - - forceWrite: function(data) { - updateBuffer(data, function(){ - if (isBufferFull()) { updateReadPoint(); } - buffer[writePoint] = data; - }); - }, - - clear: function() { - readPoint = 0; - writePoint = 0; - buffer = new Array(capacity); - }, - - isFull: function() { - return isBufferFull(); - }, - - isEmpty: function() { - return isBufferEmpty(); - } + read: function () { + if (isBufferEmpty()) { throw new BufferEmptyException(); } + var data = buffer[readPoint]; + buffer[readPoint] = null; + updateReadPoint(); + return data; + }, + + write: function (data) { + updateBuffer(data, function () { + if (isBufferFull()) { throw new BufferFullException(); } + buffer[writePoint] = data; + }); + }, + + forceWrite: function (data) { + updateBuffer(data, function () { + if (isBufferFull()) { updateReadPoint(); } + buffer[writePoint] = data; + }); + }, + + clear: function () { + readPoint = 0; + writePoint = 0; + buffer = new Array(capacity); + }, + + isFull: function () { + return isBufferFull(); + }, + + isEmpty: function () { + return isBufferEmpty(); + } }; function isBufferEmpty() { return buffer.every(isEmpty); - }; + } function isBufferFull() { return buffer.filter(isFull).length === capacity; - }; + } function updateBuffer(data, callback) { if (isEmpty(data)) { return; } callback(); updateWritePoint(); - }; + } function updateWritePoint() { writePoint = (writePoint + 1) % capacity; - }; + } function updateReadPoint() { readPoint = (readPoint + 1) % capacity; - }; + } function isFull(data) { return !isEmpty(data); - }; + } function isEmpty(data) { - return data === null || data === undefined; - }; - -}; + return !data; + } +} function BufferEmptyException() { this.name = 'BufferEmptyException'; this.message = 'Buffer is empty.'; -}; +} function BufferFullException() { this.name = 'BufferFullException'; this.message = 'Buffer is full.'; -}; +} module.exports = { - circularBuffer: function(capacity) { + circularBuffer: function (capacity) { return new CircularBuffer(capacity); }, - bufferEmptyException: function() { + bufferEmptyException: function () { return new BufferEmptyException(); }, - bufferFullException: function() { + bufferFullException: function () { return new BufferFullException(); } }; diff --git a/exercises/clock/README.md b/exercises/clock/README.md index 0427655d..9fdc3811 100644 --- a/exercises/clock/README.md +++ b/exercises/clock/README.md @@ -8,26 +8,29 @@ Two clocks that represent the same time should be equal to each other. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine clock.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/clock/clock.spec.js b/exercises/clock/clock.spec.js index 0fa74872..5849b0d8 100644 --- a/exercises/clock/clock.spec.js +++ b/exercises/clock/clock.spec.js @@ -1,9 +1,7 @@ var at = require('./clock').at; describe('Clock', function () { - describe('Creating a new clock with an initial time', function () { - it('on the hour', function () { expect(at(8).toString()).toEqual('08:00'); }); @@ -81,7 +79,6 @@ describe('Clock', function () { }); describe('Adding and subtracting minutes', function () { - xit('add minutes', function () { expect(at(10, 0).plus(3).toString()).toEqual('10:03'); }); @@ -145,11 +142,9 @@ describe('Clock', function () { xit('subtract more than two days', function () { expect(at(2, 20).minus(3000).toString()).toEqual('00:20'); }); - }); describe('Construct two separate clocks, set times, test if they are equal', function () { - it('clocks with same time', function () { expect(at(15, 37).equals(at(15, 37))).toBeTruthy(); }); @@ -209,9 +204,6 @@ describe('Clock', function () { xit('clocks with negative hours and minutes that wrap', function () { expect(at(18, 7).equals(at(-54, -11513))).toBeTruthy(); }); - }); - }); - }); diff --git a/exercises/clock/example.js b/exercises/clock/example.js index 857d2511..dc69700a 100644 --- a/exercises/clock/example.js +++ b/exercises/clock/example.js @@ -8,15 +8,12 @@ var MILLIS_IN_AN_HOUR = MINUTES_IN_AN_HOUR * MILLIS_IN_A_MINUTE; var MILLIS_IN_A_DAY = HOURS_IN_A_DAY * MILLIS_IN_AN_HOUR; function makePositive(time, maxValue) { - time %= maxValue; - time += maxValue; - return time; + return time % maxValue + maxValue; } -function at(hours, minutes) { - minutes = minutes || 0; - hours = makePositive(hours, HOURS_IN_A_DAY); - minutes = makePositive(minutes, MINUTES_IN_A_DAY); +function at(inputHours, inputMinutes) { + var minutes = makePositive(inputMinutes || 0, MINUTES_IN_A_DAY); + var hours = makePositive(inputHours, HOURS_IN_A_DAY); var clock = {}; var value = (hours * MILLIS_IN_AN_HOUR) + (minutes * MILLIS_IN_A_MINUTE); @@ -31,13 +28,13 @@ function at(hours, minutes) { return time[0] + ':' + time[1]; }; - clock.plus = function (minutes) { - value += minutes * MILLIS_IN_A_MINUTE; + clock.plus = function (addMinutes) { + value += addMinutes * MILLIS_IN_A_MINUTE; return clock; }; - clock.minus = function (minutes) { - value -= minutes * MILLIS_IN_A_MINUTE; + clock.minus = function (subMinutes) { + value -= subMinutes * MILLIS_IN_A_MINUTE; return clock; }; @@ -46,4 +43,4 @@ function at(hours, minutes) { }; return Object.create(clock); -}; +} diff --git a/exercises/collatz-conjecture/README.md b/exercises/collatz-conjecture/README.md new file mode 100644 index 00000000..f4dcfa8e --- /dev/null +++ b/exercises/collatz-conjecture/README.md @@ -0,0 +1,60 @@ +# Collatz Conjecture + +The Collatz Conjecture or 3x+1 problem can be summarized as follows: + +Take any positive integer n. If n is even, divide n by 2 to get n / 2. If n is +odd, multiply n by 3 and add 1 to get 3n + 1. Repeat the process indefinitely. +The conjecture states that no matter which number you start with, you will +always reach 1 eventually. + +Given a number n, return the number of steps required to reach 1. + +## Examples + +Starting with n = 12, the steps would be as follows: + +0. 12 +1. 6 +2. 3 +3. 10 +4. 5 +5. 16 +6. 8 +7. 4 +8. 2 +9. 1 + +Resulting in 9 steps. So for input n = 12, the return value would be 9. + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine collatz-conjecture.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +An unsolved problem in mathematics named after mathematician Lothar Collatz [https://en.wikipedia.org/wiki/3x_%2B_1_problem](https://en.wikipedia.org/wiki/3x_%2B_1_problem) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/collatz-conjecture/collatz-conjecture.spec.js b/exercises/collatz-conjecture/collatz-conjecture.spec.js new file mode 100644 index 00000000..90a29015 --- /dev/null +++ b/exercises/collatz-conjecture/collatz-conjecture.spec.js @@ -0,0 +1,37 @@ +var CollatzConjecture = require('./collatz-conjecture'); + +describe('CollatzConjecture', function () { + var collatz = new CollatzConjecture(); + + it('test zero steps for one', function () { + var expected = 0; + expect(collatz.steps(1)).toEqual(expected); + }); + + xit('test divide if even steps', function () { + var expected = 4; + expect(collatz.steps(16)).toEqual(expected); + }); + + xit('test even and odd steps', function () { + var expected = 9; + expect(collatz.steps(12)).toEqual(expected); + }); + + xit('test large number of even and odd steps', function () { + var expected = 152; + expect(collatz.steps(1000000)).toEqual(expected); + }); + + xit('test zero is an error', function () { + expect(function () { + collatz.steps(0); + }).toThrow(new Error('Only positive numbers are allowed')); + }); + + xit('test negative value is an error', function () { + expect(function () { + collatz.steps(-1); + }).toThrow(new Error('Only positive numbers are allowed')); + }); +}); diff --git a/exercises/collatz-conjecture/example.js b/exercises/collatz-conjecture/example.js new file mode 100644 index 00000000..2f51ac50 --- /dev/null +++ b/exercises/collatz-conjecture/example.js @@ -0,0 +1,20 @@ +'use strict'; + +function CollatzConjecture() {} + +CollatzConjecture.prototype.steps = function (number) { + var count = 0; + if (number < 1) { + throw new Error('Only positive numbers are allowed'); + } + getStepsCount(number); + function getStepsCount(n) { + if (n === 1) return 0; + var nextNumber = ( n % 2 === 0 ? n / 2 : 3 * n + 1); + count++; + return getStepsCount(nextNumber); + } + return count; +}; + +module.exports = CollatzConjecture; diff --git a/exercises/connect/README.md b/exercises/connect/README.md new file mode 100644 index 00000000..8e711f2b --- /dev/null +++ b/exercises/connect/README.md @@ -0,0 +1,60 @@ +# Connect + +Compute the result for a game of Hex / Polygon. + +The abstract boardgame known as +[Hex](https://en.wikipedia.org/wiki/Hex_%28board_game%29) / Polygon / +CON-TAC-TIX is quite simple in rules, though complex in practice. Two players +place stones on a rhombus with hexagonal fields. The player to connect his/her +stones to the opposite side first wins. The four sides of the rhombus are +divided between the two players (i.e. one player gets assigned a side and the +side directly opposite it and the other player gets assigned the two other +sides). + +Your goal is to build a program that given a simple representation of a board +computes the winner (or lack thereof). Note that all games need not be "fair". +(For example, players may have mismatched piece counts.) + +The boards look like this (with spaces added for readability, which won't be in +the representation passed to your code): + +```text +. O . X . + . X X O . + O O O X . + . X O X O + X O O O X +``` + +"Player `O`" plays from top to bottom, "Player `X`" plays from left to right. In +the above example `O` has made a connection from left to right but nobody has +won since `O` didn't connect top and bottom. + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine connect.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/connect/connect.spec.js b/exercises/connect/connect.spec.js new file mode 100644 index 00000000..1b926346 --- /dev/null +++ b/exercises/connect/connect.spec.js @@ -0,0 +1,108 @@ +var Board = require('./connect'); + +describe('Judging a game of connect', function () { + it('an empty board has no winner', function () { + var board = [ + '. . . . .', + ' . . . . .', + ' . . . . .', + ' . . . . .', + ' . . . . .' + ]; + expect(new Board(board).winner()).toEqual(''); + }); + + xit('X can win on a 1x1 board', function () { + var board = [ + 'X' + ]; + expect(new Board(board).winner()).toEqual('X'); + }); + + xit('O can win on a 1x1 board', function () { + var board = [ + 'O' + ]; + expect(new Board(board).winner()).toEqual('O'); + }); + + xit('only edges does not make a winner', function () { + var board = [ + 'O O O X', + ' X . . X', + ' X . . X', + ' X O O O' + ]; + expect(new Board(board).winner()).toEqual(''); + }); + + xit('illegal diagonal does not make a winner', function () { + var board = [ + 'X O . .', + ' O X X X', + ' O X O .', + ' . O X .', + ' X X O O' + ]; + expect(new Board(board).winner()).toEqual(''); + }); + + xit('nobody wins crossing adjacent angles', function () { + var board = [ + 'X . . .', + ' . X O .', + ' O . X O', + ' . O . X', + ' . . O .' + ]; + expect(new Board(board).winner()).toEqual(''); + }); + + xit('X wins crossing from left to right', function () { + var board = [ + '. O . .', + ' O X X X', + ' O X O .', + ' X X O X', + ' . O X .' + ]; + expect(new Board(board).winner()).toEqual('X'); + }); + + xit('O wins crossing from top to bottom', function () { + var board = [ + '. O . .', + ' O X X X', + ' O O O .', + ' X X O X', + ' . O X .' + ]; + expect(new Board(board).winner()).toEqual('O'); + }); + + xit('X wins using a convoluted path', function () { + var board = [ + '. X X . .', + ' X . X . X', + ' . X . X .', + ' . X X . .', + ' O O O O O' + ]; + expect(new Board(board).winner()).toEqual('X'); + }); + + xit('X wins using a spiral path', function () { + var board = [ + 'O X X X X X X X X', + ' O X O O O O O O O', + ' O X O X X X X X O', + ' O X O X O O O X O', + ' O X O X X X O X O', + ' O X O O O X O X O', + ' O X X X X X O X O', + ' O O O O O O O X O', + ' X X X X X X X X O' + ]; + expect(new Board(board).winner()).toEqual('X'); + }); +}); diff --git a/exercises/connect/example.js b/exercises/connect/example.js new file mode 100644 index 00000000..9c709a1b --- /dev/null +++ b/exercises/connect/example.js @@ -0,0 +1,105 @@ +/** + * "Player O" plays from top to bottom, "Player X" plays from left to right. + * @param {string[]} initBoard - The starting state of the board + * @returns {Object} - The board business object + */ +var Board = function (initBoard) { + this.board = initBoard.slice(); +}; + +Board.prototype.winner = function () { + var players = ['X', 'O']; + for (var i = 0; i < players.length; i++) { + if (this.checkWin(players[i])) { + return players[i]; + } + } + return ''; +}; + +Board.prototype.checkWin = function (player) { + var positions = this.startPositions(player); + for (var i = 0; i < positions.length; i++) { + if (this.search(positions[i], player, [])) { + return true; + } + } + return false; +}; + +Board.prototype.search = function (pos, XorO, isChecked) { + var self = this; + if (!this.containsPiece(pos, XorO)) { + return false; + } + if (this.winningSpot(pos, XorO)) { + return true; + } + var checked = isChecked.slice(0); + checked.push(pos); + + var matches = this.neighbors(pos) + .filter(function (cell) { + return self.containsPiece(cell, XorO) && + checked.filter( + function (spot) { + return locationMatch(spot, cell); + } + ).length === 0; + }); + + function locationMatch(spot, cell) { + return spot.x === cell.x && spot.y === cell.y; + } + + if (matches.length === 0) { + return false; + } + + return matches + .filter( + function (spot) { + return self.search(spot, XorO, checked); + } + ).length > 0; +}; + +Board.prototype.neighbors = function (cell) { + return [ + {x: cell.x, y: cell.y + 2}, + {x: cell.x, y: cell.y - 2}, + + {x: cell.x + 1, y: cell.y + 1}, + {x: cell.x - 1, y: cell.y + 1}, + + {x: cell.x + 1, y: cell.y - 1}, + {x: cell.x - 1, y: cell.y - 1} + ]; +}; + +Board.prototype.startPositions = function (XorO) { + var self = this; + return XorO === 'X' ? + this.board + .map(function (pos, i) { + return {x: i, y: i}; + }) : + Array.prototype + .map + .call(self.board[0], function (pos, i) { + return {x: 0, y: i}; + }); +}; + +Board.prototype.winningSpot = function (cell, XorO) { + return XorO === 'X' ? + cell.y === this.board[0].length - 1 + cell.x : + cell.x === this.board.length - 1; +}; + +Board.prototype.containsPiece = function (cell, XorO) { + return this.board[cell.x] && this.board[cell.x][cell.y] === XorO; +}; + + +module.exports = Board; diff --git a/exercises/crypto-square/README.md b/exercises/crypto-square/README.md index 515f68f2..9fbbe98f 100644 --- a/exercises/crypto-square/README.md +++ b/exercises/crypto-square/README.md @@ -26,7 +26,7 @@ and `r` is the number of rows. Our normalized text is 54 characters long, dictating a rectangle with `c = 8` and `r = 7`: -```plain +```text ifmanwas meanttos tayonthe @@ -41,22 +41,24 @@ right. The message above is coded as: -```plain +```text imtgdvsfearwermayoogoanouuiontnnlvtwttddesaohghnsseoau ``` -Output the encoded text in chunks. Phrases that fill perfect squares -`(r X r)` should be output in `r`-length chunks separated by spaces. -Imperfect squares will have `n` empty spaces. Those spaces should be distributed evenly across the last `n` rows. +Output the encoded text in chunks. Phrases that fill perfect rectangles +`(r X c)` should be output `c` chunks of `r` length, separated by spaces. +Phrases that do not fill perfect rectangles will have `n` empty spaces. +Those spaces should be distributed evenly, added to the end of the last +`n` chunks. -```plain -imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau +```text +imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau ``` Notice that were we to stack these, we could visually decode the cyphertext back in to the original message: -```plain +```text imtgdvs fearwer mayoogo @@ -69,26 +71,29 @@ sseoau ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine crypto-square.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/crypto-square/crypto-square.spec.js b/exercises/crypto-square/crypto-square.spec.js index 2682339a..76f52a6d 100644 --- a/exercises/crypto-square/crypto-square.spec.js +++ b/exercises/crypto-square/crypto-square.spec.js @@ -1,52 +1,52 @@ var Crypto = require('./crypto-square'); -describe('Crypto',function() { - it('normalize strange characters',function() { +describe('Crypto', function () { + it('normalize strange characters', function () { var crypto = new Crypto('s#$%^&plunk'); expect(crypto.normalizePlaintext()).toEqual('splunk'); }); - xit('normalize numbers',function() { + xit('normalize numbers', function () { var crypto = new Crypto('1, 2, 3 GO!'); expect(crypto.normalizePlaintext()).toEqual('123go'); }); - xit('size of small square',function() { + xit('size of small square', function () { var crypto = new Crypto('1234'); expect(crypto.size()).toEqual(2); }); - xit('size of small square with additional non-nuber chars',function() { + xit('size of small square with additional non-nuber chars', function () { var crypto = new Crypto('1 2 3 4'); expect(crypto.size()).toEqual(2); }); - xit('size of slightly larger square',function() { + xit('size of slightly larger square', function () { var crypto = new Crypto('123456789'); expect(crypto.size()).toEqual(3); }); - xit('size of non-perfect square',function() { + xit('size of non-perfect square', function () { var crypto = new Crypto('123456789abc'); expect(crypto.size()).toEqual(4); }); - xit('plain text segments',function() { + xit('plain text segments', function () { var crypto = new Crypto('Never vex thine heart with idle woes'); expect(crypto.plaintextSegments()).toEqual(['neverv', 'exthin', 'eheart', 'withid', 'lewoes']); }); - xit('plain text segments',function() { + xit('plain text segments', function () { var crypto = new Crypto('ZOMG! ZOMBIES!!!'); expect(crypto.plaintextSegments()).toEqual(['zomg', 'zomb', 'ies']); }); - xit('cipher text',function() { + xit('cipher text', function () { var crypto = new Crypto('Time is an illusion. Lunchtime doubly so.'); expect(crypto.ciphertext()).toEqual('tasneyinicdsmiohooelntuillibsuuml'); }); - xit('cipher text',function() { + xit('cipher text', function () { var crypto = new Crypto('We all know interspecies romance is weird.'); expect(crypto.ciphertext()).toEqual('wneiaweoreneawssciliprerlneoidktcms'); }); diff --git a/exercises/crypto-square/example.js b/exercises/crypto-square/example.js index 7a914a55..44589d5b 100644 --- a/exercises/crypto-square/example.js +++ b/exercises/crypto-square/example.js @@ -1,28 +1,29 @@ 'use strict'; -module.exports = function(input) { +module.exports = function (input) { this.input = input; - this.normalizePlaintext = function() { - return input.toLowerCase().replace(/[^a-zA-Z0-9]/g,''); + this.normalizePlaintext = function () { + return input.toLowerCase().replace(/[^a-zA-Z0-9]/g, ''); }; - this.size = function() { + this.size = function () { var realLength = Math.sqrt(this.normalizePlaintext().length); return Math.ceil(realLength); }; - this.plaintextSegments = function() { + this.plaintextSegments = function () { var plainText = this.normalizePlaintext(); var chunkSize = this.size(); - var splitRegex = new RegExp('.{1,' + chunkSize + '}','g'); + var splitRegex = new RegExp('.{1,' + chunkSize + '}', 'g'); return plainText.match(splitRegex); }; - this.ciphertext = function() { + this.ciphertext = function () { var textSegments = this.plaintextSegments(); - var i, j; + var i; + var j; var columns = []; var currentSegment; var currentLetter; @@ -47,9 +48,9 @@ module.exports = function(input) { return columns.join(''); }; - this.normalizeCiphertext = function() { + this.normalizeCiphertext = function () { var chunkSize = this.size(); - var splitRegex = new RegExp('.{1,' + chunkSize + '}','g'); + var splitRegex = new RegExp('.{1,' + chunkSize + '}', 'g'); return this.ciphertext().match(splitRegex).join(' '); }; }; diff --git a/exercises/custom-set/README.md b/exercises/custom-set/README.md index 765ce0be..9635f1e0 100644 --- a/exercises/custom-set/README.md +++ b/exercises/custom-set/README.md @@ -9,27 +9,29 @@ unique elements. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js - -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +```sh +jasmine custom-set.spec.js +``` +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Submitting Incomplete Solutions It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/custom-set/custom-set.spec.js b/exercises/custom-set/custom-set.spec.js index d5615c94..1e0bf8c0 100644 --- a/exercises/custom-set/custom-set.spec.js +++ b/exercises/custom-set/custom-set.spec.js @@ -1,209 +1,208 @@ var CustomSet = require('./custom-set'); -describe('CustomSet', function() { - - it('sets with no elements are empty', function() { +describe('CustomSet', function () { + it('sets with no elements are empty', function () { var actual = new CustomSet().empty(); expect(actual).toBe(true); }); - xit('sets with elements are not empty', function() { + xit('sets with elements are not empty', function () { var actual = new CustomSet([1]).empty(); expect(actual).toBe(false); }); - xit('nothing is contained in an empty set', function() { + xit('nothing is contained in an empty set', function () { var actual = new CustomSet().contains(1); expect(actual).toBe(false); }); - xit('when the element is in the set', function() { + xit('when the element is in the set', function () { var actual = new CustomSet([1, 2, 3]).contains(1); expect(actual).toBe(true); }); - xit('when the element is not in the set', function() { + xit('when the element is not in the set', function () { var actual = new CustomSet([1, 2, 3]).contains(4); expect(actual).toBe(false); }); - xit('empty set is a subset of another empty set', function() { + xit('empty set is a subset of another empty set', function () { var actual = new CustomSet().subset(new CustomSet()); expect(actual).toBe(true); }); - xit('empty set is a subset of non-empty set', function() { + xit('empty set is a subset of non-empty set', function () { var actual = new CustomSet([1]).subset(new CustomSet()); expect(actual).toBe(true); }); - xit('non-empty set is not a subset of empty set', function() { + xit('non-empty set is not a subset of empty set', function () { var actual = new CustomSet().subset(new CustomSet([1])); expect(actual).toBe(false); }); - xit('set is a subset of set with exact same elements', function() { + xit('set is a subset of set with exact same elements', function () { var actual = new CustomSet([1, 2, 3]).subset(new CustomSet([1, 2, 3])); expect(actual).toBe(true); }); - xit('set is a subset of larger set with same elements', function() { + xit('set is a subset of larger set with same elements', function () { var actual = new CustomSet([4, 1, 2, 3]).subset(new CustomSet([1, 2, 3])); expect(actual).toBe(true); }); - xit('set is not a subset of set that does not contain its elements', function() { + xit('set is not a subset of set that does not contain its elements', function () { var actual = new CustomSet([4, 1, 3]).subset(new CustomSet([1, 2, 3])); expect(actual).toBe(false); }); - xit('the empty set is disjoint with itself', function() { + xit('the empty set is disjoint with itself', function () { var actual = new CustomSet().disjoint(new CustomSet()); expect(actual).toBe(true); }); - xit('empty set is disjoint with non-empty set', function() { + xit('empty set is disjoint with non-empty set', function () { var actual = new CustomSet().disjoint(new CustomSet([1])); expect(actual).toBe(true); }); - xit('non-empty set is disjoint with empty set', function() { + xit('non-empty set is disjoint with empty set', function () { var actual = new CustomSet([1]).disjoint(new CustomSet()); expect(actual).toBe(true); }); - xit('sets are not disjoint if they share an element', function() { + xit('sets are not disjoint if they share an element', function () { var actual = new CustomSet([1, 2]).disjoint(new CustomSet([2, 3])); expect(actual).toBe(false); }); - xit('sets are disjoint if they share no elements', function() { + xit('sets are disjoint if they share no elements', function () { var actual = new CustomSet([1, 2]).disjoint(new CustomSet([3, 4])); expect(actual).toBe(true); }); - xit('empty sets are equal', function() { + xit('empty sets are equal', function () { var actual = new CustomSet().eql(new CustomSet()); expect(actual).toBe(true); }); - xit('empty set is not equal to non-empty set', function() { + xit('empty set is not equal to non-empty set', function () { var actual = new CustomSet().eql(new CustomSet([1, 2, 3])); expect(actual).toBe(false); }); - xit('non-empty set is not equal to empty set', function() { + xit('non-empty set is not equal to empty set', function () { var actual = new CustomSet([1, 2, 3]).eql(new CustomSet()); expect(actual).toBe(false); }); - xit('sets with the same elements are equal', function() { + xit('sets with the same elements are equal', function () { var actual = new CustomSet([1, 2]).eql(new CustomSet([2, 1])); expect(actual).toBe(true); }); - xit('sets with different elements are not equal', function() { + xit('sets with different elements are not equal', function () { var actual = new CustomSet([1, 2, 3]).eql(new CustomSet([1, 2, 4])); expect(actual).toBe(false); }); - xit('add to empty set', function() { + xit('add to empty set', function () { var actual = new CustomSet().add(3); var expected = new CustomSet([3]); expect(actual.eql(expected)).toBe(true); }); - xit('add to non-empty set', function() { + xit('add to non-empty set', function () { var actual = new CustomSet([1, 2, 4]).add(3); var expected = new CustomSet([1, 2, 3, 4]); expect(actual.eql(expected)).toBe(true); }); - xit('adding an existing element does not change the set', function() { + xit('adding an existing element does not change the set', function () { var actual = new CustomSet([1, 2, 3]).add(3); var expected = new CustomSet([1, 2, 3]); expect(actual.eql(expected)).toBe(true); }); - xit('intersection of two empty sets is an empty set', function() { + xit('intersection of two empty sets is an empty set', function () { var actual = new CustomSet().intersection(new CustomSet()); var expected = new CustomSet(); expect(actual.eql(expected)).toBe(true); }); - xit('intersection of an empty set and non-empty set is an empty set', function() { + xit('intersection of an empty set and non-empty set is an empty set', function () { var actual = new CustomSet().intersection(new CustomSet([3, 2, 5])); var expected = new CustomSet(); expect(actual.eql(expected)).toBe(true); }); - xit('intersection of a non-empty set and an empty set is an empty set', function() { + xit('intersection of a non-empty set and an empty set is an empty set', function () { var actual = new CustomSet([1, 2, 3, 4]).intersection(new CustomSet()); var expected = new CustomSet(); expect(actual.eql(expected)).toBe(true); }); - xit('intersection of two sets with no shared elements is an empty set', function() { + xit('intersection of two sets with no shared elements is an empty set', function () { var actual = new CustomSet([1, 2, 3]).intersection(new CustomSet([4, 5, 6])); var expected = new CustomSet(); expect(actual.eql(expected)).toBe(true); }); - xit('intersection of two sets with shared elements is a set of the shared elements', function() { + xit('intersection of two sets with shared elements is a set of the shared elements', function () { var actual = new CustomSet([1, 2, 3, 4]).intersection(new CustomSet([3, 2, 5])); var expected = new CustomSet([2, 3]); expect(actual.eql(expected)).toBe(true); }); - xit('difference of two empty sets is an empty set', function() { + xit('difference of two empty sets is an empty set', function () { var actual = new CustomSet().difference(new CustomSet()); var expected = new CustomSet(); expect(actual.eql(expected)).toBe(true); }); - xit('difference of empty set and non-empty set is an empty set', function() { + xit('difference of empty set and non-empty set is an empty set', function () { var actual = new CustomSet().difference(new CustomSet([3, 2, 5])); var expected = new CustomSet(); expect(actual.eql(expected)).toBe(true); }); - xit('difference of a non-empty set and an empty set is the non-empty set', function() { + xit('difference of a non-empty set and an empty set is the non-empty set', function () { var actual = new CustomSet([1, 2, 3, 4]).difference(new CustomSet()); var expected = new CustomSet([1, 2, 3, 4]); expect(actual.eql(expected)).toBe(true); }); - xit('difference of two non-empty sets is a set of elements that are only in the first set', function() { + xit('difference of two non-empty sets is a set of elements that are only in the first set', function () { var actual = new CustomSet([3, 2, 1]).difference(new CustomSet([2, 4])); var expected = new CustomSet([1, 3]); expect(actual.eql(expected)).toBe(true); }); - xit('union of empty sets is an empty set', function() { + xit('union of empty sets is an empty set', function () { var actual = new CustomSet().union(new CustomSet()); var expected = new CustomSet(); expect(actual.eql(expected)).toBe(true); }); - xit('union of an empty set and non-empty set is the non-empty set', function() { + xit('union of an empty set and non-empty set is the non-empty set', function () { var actual = new CustomSet().union(new CustomSet([2])); var expected = new CustomSet([2]); expect(actual.eql(expected)).toBe(true); }); - xit('union of a non-empty set and empty set is the non-empty set', function() { + xit('union of a non-empty set and empty set is the non-empty set', function () { var actual = new CustomSet([1, 3]).union(new CustomSet()); var expected = new CustomSet([1, 3]); expect(actual.eql(expected)).toBe(true); }); - xit('union of non-empty sets contains all unique elements', function() { + xit('union of non-empty sets contains all unique elements', function () { var actual = new CustomSet([1, 3]).union(new CustomSet([2, 3])); var expected = new CustomSet([3, 2, 1]); expect(actual.eql(expected)).toBe(true); }); - xit('can be emptied', function() { + xit('can be emptied', function () { var actual = new CustomSet([1, 2]).clear(); var expected = new CustomSet(); expect(actual.eql(expected)).toBe(true); @@ -212,7 +211,7 @@ describe('CustomSet', function() { expect(actual2.eql(expected2)).toBe(true); }); - xit('knows its size', function() { + xit('knows its size', function () { var actual = new CustomSet().size(); expect(actual).toBe(0); var actual2 = new CustomSet([1, 2, 3]).size(); @@ -221,7 +220,7 @@ describe('CustomSet', function() { expect(actual3).toBe(3); }); - xit('can give back a list', function() { + xit('can give back a list', function () { var actual = new CustomSet().toList(); var expected = []; expect(actual.sort()).toEqual(expected); @@ -232,5 +231,4 @@ describe('CustomSet', function() { var expected3 = [1, 2, 3]; expect(actual3.sort()).toEqual(expected3); }); - }); diff --git a/exercises/custom-set/example-gen.js b/exercises/custom-set/example-gen.js index 0170a3da..f27732f6 100644 --- a/exercises/custom-set/example-gen.js +++ b/exercises/custom-set/example-gen.js @@ -28,62 +28,62 @@ var SPEC_FILE_NAME = 'custom-set.spec.js'; var TEST_BODY_TEMPLATES = { empty: function ({set, expected}) { return ( - `var actual = new CustomSet(${array(set)}).empty(); + `var actual = new CustomSet(${array(set)}).empty(); expect(actual).toBe(${expected});`); }, contains: function ({set, element, expected}) { return ( - `var actual = new CustomSet(${array(set)}).contains(${element}); + `var actual = new CustomSet(${array(set)}).contains(${element}); expect(actual).toBe(${expected});`); }, subset: function ({set1, set2, expected}) { return ( - `var actual = new CustomSet(${array(set2)}).subset(new CustomSet(${array(set1)})); + `var actual = new CustomSet(${array(set2)}).subset(new CustomSet(${array(set1)})); expect(actual).toBe(${expected});`); }, disjoint: function ({set1, set2, expected}) { return ( - `var actual = new CustomSet(${array(set1)}).disjoint(new CustomSet(${array(set2)})); + `var actual = new CustomSet(${array(set1)}).disjoint(new CustomSet(${array(set2)})); expect(actual).toBe(${expected});`); }, equal: function ({set1, set2, expected}) { return ( - `var actual = new CustomSet(${array(set1)}).eql(new CustomSet(${array(set2)})); + `var actual = new CustomSet(${array(set1)}).eql(new CustomSet(${array(set2)})); expect(actual).toBe(${expected});`); }, add: function ({set, element, expected}) { return ( - `var actual = new CustomSet(${array(set)}).add(${element}); + `var actual = new CustomSet(${array(set)}).add(${element}); var expected = new CustomSet(${array(expected)}); expect(actual.eql(expected)).toBe(true);`); }, intersection: function ({set1, set2, expected}) { return ( - `var actual = new CustomSet(${array(set1)}).intersection(new CustomSet(${array(set2)})); + `var actual = new CustomSet(${array(set1)}).intersection(new CustomSet(${array(set2)})); var expected = new CustomSet(${array(expected)}); expect(actual.eql(expected)).toBe(true);`); }, difference: function ({set1, set2, expected}) { return ( - `var actual = new CustomSet(${array(set1)}).difference(new CustomSet(${array(set2)})); + `var actual = new CustomSet(${array(set1)}).difference(new CustomSet(${array(set2)})); var expected = new CustomSet(${array(expected)}); expect(actual.eql(expected)).toBe(true);`); }, union: function ({set1, set2, expected}) { return ( - `var actual = new CustomSet(${array(set1)}).union(new CustomSet(${array(set2)})); + `var actual = new CustomSet(${array(set1)}).union(new CustomSet(${array(set2)})); var expected = new CustomSet(${array(expected)}); expect(actual.eql(expected)).toBe(true);`); } -} +}; var NON_CANONICAL_TESTS = ` xit('can be emptied', function() { @@ -115,16 +115,16 @@ var NON_CANONICAL_TESTS = ` var expected3 = [1, 2, 3]; expect(actual3.sort()).toEqual(expected3); }); -` +`; -function render ({suiteData, testBodyTemplates, extraTests, suiteTemplate}) { +function render({suiteData, testBodyTemplates, extraTests, suiteTemplate}) { var testCases = extractTestCases(suiteData, testBodyTemplates); var tests = renderTests(testCases); return renderSuite(tests, extraTests, suiteTemplate); } -function extractTestCases (suiteData, testBodyTemplates) { +function extractTestCases(suiteData, testBodyTemplates) { var testCases = []; Object.keys(suiteData) @@ -132,37 +132,37 @@ function extractTestCases (suiteData, testBodyTemplates) { return key !== METADATA_COMMENT_KEY; }) .forEach(function (sectionName) { - suiteData[sectionName]['cases'] + suiteData[sectionName].cases .forEach(function (caseData) { testCases.push(new TestCase(caseData, testBodyTemplates[sectionName])); - }) - }) + }); + }); return testCases; } -function TestCase (caseData, bodyTemplate) { +function TestCase(caseData, bodyTemplate) { this.caseData = caseData; this.bodyTemplate = bodyTemplate; } TestCase.prototype.render = function (isEnabled) { return testTemplate(isEnabled, this.caseData.description, this.bodyTemplate(this.caseData)); -} +}; -function renderTests (testCases) { +function renderTests(testCases) { return testCases.reduce(function (output, testCase, index) { return output + testCase.render(index === 0); - }, '') + }, ''); } -function renderSuite (tests, otherTests, suiteTemplate) { +function renderSuite(tests, otherTests, suiteTemplate) { return suiteTemplate(tests.concat(otherTests)); } -function suiteTemplate (tests) { +function suiteTemplateFn(tests) { return ( -`var CustomSet = require('./custom-set'); + `var CustomSet = require('./custom-set'); describe('CustomSet', function() { ${tests} @@ -170,20 +170,20 @@ ${tests} `); } -function testTemplate (isEnabled, description, body) { +function testTemplate(isEnabled, description, body) { return ( -` + ` ${isEnabled ? 'it' : 'xit'}('${description}', function() { ${body} }); `); } -function array (array) { - return array.length === 0 ? '' : `[${array.join(', ')}]`; +function array(arr) { + return arr.length === 0 ? '' : `[${arr.join(', ')}]`; } -function generate () { +function generate() { var exerciseFilePath = path.join(EXERCISE_METADATA_ROOT, EXERCISE_DIR_NAME, METADATA_FILE_NAME); var suiteData = JSON.parse(fs.readFileSync(exerciseFilePath)); @@ -193,7 +193,7 @@ function generate () { suiteData: suiteData, testBodyTemplates: TEST_BODY_TEMPLATES, extraTests: NON_CANONICAL_TESTS, - suiteTemplate: suiteTemplate + suiteTemplate: suiteTemplateFn })); } diff --git a/exercises/custom-set/example.js b/exercises/custom-set/example.js index a4ba69d3..edd1f5ac 100644 --- a/exercises/custom-set/example.js +++ b/exercises/custom-set/example.js @@ -1,16 +1,15 @@ -(function() { - +(function () { 'use strict'; - var CustomSet = function(inputData) { + var CustomSet = function (inputData) { this.data = inputData || []; }; - CustomSet.prototype.empty = function() { + CustomSet.prototype.empty = function () { return this.data.length === 0; }; - CustomSet.prototype.delete = function(element) { + CustomSet.prototype.delete = function (element) { var index = this.data.indexOf(element); if (index !== -1) { this.data.splice(index, 1); @@ -18,11 +17,11 @@ return this; }; - CustomSet.prototype.difference = function(other) { + CustomSet.prototype.difference = function (other) { var thisData = this.data.sort(); var thatData = other.data.sort(); var result = []; - for (var i=0; i < thisData.length; i++) { + for (var i = 0; i < thisData.length; i++) { if (thatData.indexOf(thisData[i]) === -1) { result.push(thisData[i]); } @@ -30,8 +29,8 @@ return new CustomSet(result); }; - CustomSet.prototype.disjoint = function(other) { - if (this.data.length === 0) { return true; }; + CustomSet.prototype.disjoint = function (other) { + if (this.data.length === 0) { return true; } for (var i = 0; i < this.data.length; i++) { if (other.data.indexOf(this.data[i]) !== -1) { return false; @@ -40,15 +39,15 @@ return true; }; - CustomSet.prototype.clear = function() { + CustomSet.prototype.clear = function () { return new CustomSet([]); }; - CustomSet.prototype.intersection = function(other) { + CustomSet.prototype.intersection = function (other) { var thisData = this.data.sort(); var thatData = other.data.sort(); var result = []; - for (var i=0; i < thisData.length; i++) { + for (var i = 0; i < thisData.length; i++) { if (thatData.indexOf(thisData[i]) !== -1) { result.push(thisData[i]); } @@ -56,23 +55,23 @@ return new CustomSet(result); }; - CustomSet.prototype.contains = function(datum) { + CustomSet.prototype.contains = function (datum) { return this.data.indexOf(datum) !== -1; }; - CustomSet.prototype.add = function(datum) { + CustomSet.prototype.add = function (datum) { if (this.data.indexOf(datum) === -1) { this.data.push(datum); } return this; }; - CustomSet.prototype.size = function() { + CustomSet.prototype.size = function () { return arrayUnique(this.data).length; }; - CustomSet.prototype.subset = function(other) { - for (var i=0; i < other.data.length; i++) { + CustomSet.prototype.subset = function (other) { + for (var i = 0; i < other.data.length; i++) { if (this.data.indexOf(other.data[i]) === -1) { return false; } @@ -80,24 +79,24 @@ return true; }; - CustomSet.prototype.toList = function() { + CustomSet.prototype.toList = function () { return arrayUnique(this.data); }; - CustomSet.prototype.union = function(other) { + CustomSet.prototype.union = function (other) { var result = []; - for (var i=0; i < this.data.length; i++) { + for (var i = 0; i < this.data.length; i++) { result.push(this.data[i]); } - for (var j=0; j < other.data.length; j++) { + for (var j = 0; j < other.data.length; j++) { result.push(other.data[j]); } return new CustomSet(arrayUnique(result)); }; - CustomSet.prototype.eql = function(other) { + CustomSet.prototype.eql = function (other) { var thisData = this.data.sort(); var thatData = other.data.sort(); @@ -113,10 +112,10 @@ return true; }; - var arrayUnique = function(a) { - return a.reduce(function(p, c) { - if (p.indexOf(c) < 0) p.push(c); - return p; + var arrayUnique = function (a) { + return a.reduce(function (p, c) { + if (p.indexOf(c) < 0) p.push(c); + return p; }, []); }; diff --git a/exercises/diamond/README.md b/exercises/diamond/README.md index 6dab43a6..7ba94abd 100644 --- a/exercises/diamond/README.md +++ b/exercises/diamond/README.md @@ -1,7 +1,7 @@ # Diamond -The diamond kata takes as its input a letter, and outputs it in a diamond -shape. Given a letter, it prints a diamond starting with 'A', with the +The diamond kata takes as its input a letter, and outputs it in a diamond +shape. Given a letter, it prints a diamond starting with 'A', with the supplied letter at the widest point. ## Requirements @@ -15,7 +15,7 @@ supplied letter at the widest point. * The diamond has a square shape (width equals height). * The letters form a diamond shape. * The top half has the letters in ascending order. -* The bottom half has the letters in descending order. +* The bottom half has the letters in descending order. * The four corners (containing the spaces) are triangles. ## Examples @@ -24,13 +24,13 @@ In the following examples, spaces are indicated by `·` characters. Diamond for letter 'A': -```plain +```text A ``` Diamond for letter 'C': -```plain +```text ··A·· ·B·B· C···C @@ -40,7 +40,7 @@ C···C Diamond for letter 'E': -```plain +```text ····A···· ···B·B··· ··C···C·· @@ -54,26 +54,29 @@ E·······E ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine diamond.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/diamond/diamond.spec.js b/exercises/diamond/diamond.spec.js index 8bf43564..5e52b952 100644 --- a/exercises/diamond/diamond.spec.js +++ b/exercises/diamond/diamond.spec.js @@ -1,32 +1,32 @@ var Diamond = require('./diamond'); -describe('Diamond', function() { +describe('Diamond', function () { var diamond = new Diamond(); - it('test letter A', function() { - result = "A\n"; + it('test letter A', function () { + var result = 'A\n'; expect(diamond.makeDiamond('A')).toEqual(result); }); - it('test letter C', function() { - result = [" A ", - " B B ", - "C C", - " B B ", - " A "].join("\n") + "\n"; + it('test letter C', function () { + var result = [' A ', + ' B B ', + 'C C', + ' B B ', + ' A '].join('\n') + '\n'; expect(diamond.makeDiamond('C')).toEqual(result); }); - it('test letter E', function() { - result = [" A ", - " B B ", - " C C ", - " D D ", - "E E", - " D D ", - " C C ", - " B B ", - " A "].join("\n") + "\n"; + it('test letter E', function () { + var result = [' A ', + ' B B ', + ' C C ', + ' D D ', + 'E E', + ' D D ', + ' C C ', + ' B B ', + ' A '].join('\n') + '\n'; expect(diamond.makeDiamond('E')).toEqual(result); }); }); diff --git a/exercises/diamond/example.js b/exercises/diamond/example.js index 7107827d..d535e64e 100644 --- a/exercises/diamond/example.js +++ b/exercises/diamond/example.js @@ -1,35 +1,33 @@ -var Diamond = function() { - this.makeDiamond = function(input){ +var Diamond = function () { + this.makeDiamond = function (input) { var inputIndex = input.charCodeAt() - 65; - var output = ""; - for(var i = 0; i <= inputIndex; i++){ + var output = ''; + for (var i = 0; i <= inputIndex; i++) { output += getLine(inputIndex, i); } - for(var i = inputIndex - 1; i >= 0; i--){ - output += getLine(inputIndex, i); + for (var j = inputIndex - 1; j >= 0; j--) { + output += getLine(inputIndex, j); } - return output; - } + return output; + }; - var getLine = function(inputIndex, index){ + var getLine = function (inputIndex, index) { var difference = inputIndex - index; - return spaceTimes(difference) + printAlphabets(index) + spaceTimes(difference) + "\n"; - } + return spaceTimes(difference) + printAlphabets(index) + spaceTimes(difference) + '\n'; + }; - var printAlphabets = function(index){ + var printAlphabets = function (index) { var character = 65 + index; - if(index === 0){ - return "A"; - } - else { - return String.fromCharCode(character) + spaceTimes(((index - 1) * 2) + 1) + String.fromCharCode(character); + if (index === 0) { + return 'A'; } - } + return String.fromCharCode(character) + spaceTimes(((index - 1) * 2) + 1) + String.fromCharCode(character); + }; - var spaceTimes = function(times){ - return " ".repeat(times); - } + var spaceTimes = function (times) { + return ' '.repeat(times); + }; }; module.exports = Diamond; diff --git a/exercises/difference-of-squares/README.md b/exercises/difference-of-squares/README.md index 5d05e84a..5c181acf 100644 --- a/exercises/difference-of-squares/README.md +++ b/exercises/difference-of-squares/README.md @@ -14,26 +14,29 @@ natural numbers is 3025 - 385 = 2640. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine difference-of-squares.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/difference-of-squares/difference-of-squares.spec.js b/exercises/difference-of-squares/difference-of-squares.spec.js index 99a188f8..4be426e0 100644 --- a/exercises/difference-of-squares/difference-of-squares.spec.js +++ b/exercises/difference-of-squares/difference-of-squares.spec.js @@ -1,7 +1,6 @@ var Squares = require('./difference-of-squares'); describe('Squares', function () { - describe('up to 5', function () { var squares = new Squares(5); @@ -16,7 +15,6 @@ describe('Squares', function () { xit('gets the difference', function () { expect(squares.difference).toBe(170); }); - }); describe('up to 10', function () { @@ -33,7 +31,6 @@ describe('Squares', function () { xit('gets the difference', function () { expect(squares.difference).toBe(2640); }); - }); describe('up to 100', function () { @@ -50,7 +47,5 @@ describe('Squares', function () { xit('gets the difference', function () { expect(squares.difference).toBe(25164150); }); - }); - }); diff --git a/exercises/difference-of-squares/example.js b/exercises/difference-of-squares/example.js index 686e4a8c..4b96fc3e 100644 --- a/exercises/difference-of-squares/example.js +++ b/exercises/difference-of-squares/example.js @@ -7,12 +7,12 @@ module.exports = function Squares(max) { for (var x = 1; x <= max; x++) { sum += x; } - return sum*sum; + return sum * sum; }, get sumOfSquares() { var sum = 0; for (var x = 1; x <= max; x++) { - sum += x*x; + sum += x * x; } return sum; }, @@ -20,4 +20,4 @@ module.exports = function Squares(max) { return this.squareOfSums - this.sumOfSquares; } }; -}; \ No newline at end of file +}; diff --git a/exercises/diffie-hellman/README.md b/exercises/diffie-hellman/README.md new file mode 100644 index 00000000..f04f3c27 --- /dev/null +++ b/exercises/diffie-hellman/README.md @@ -0,0 +1,71 @@ +# Diffie Hellman + +Diffie-Hellman key exchange. + +Alice and Bob use Diffie-Hellman key exchange to share secrets. They +start with prime numbers, pick private keys, generate and share public +keys, and then generate a shared secret key. + +## Step 0 + +The test program supplies prime numbers p and g. + +## Step 1 + +Alice picks a private key, a, greater than 1 and less than p. Bob does +the same to pick a private key b. + +## Step 2 + +Alice calculates a public key A. + + A = g**a mod p + +Using the same p and g, Bob similarly calculates a public key B from his +private key b. + +## Step 3 + +Alice and Bob exchange public keys. Alice calculates secret key s. + + s = B**a mod p + +Bob calculates + + s = A**b mod p + +The calculations produce the same result! Alice and Bob now share +secret s. + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine diffie-hellman.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Wikipedia, 1024 bit key from www.cryptopp.com/wiki. [http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange](http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/diffie-hellman/diffie-hellman.spec.js b/exercises/diffie-hellman/diffie-hellman.spec.js new file mode 100644 index 00000000..47b4faae --- /dev/null +++ b/exercises/diffie-hellman/diffie-hellman.spec.js @@ -0,0 +1,73 @@ +var DiffieHellman = require('./diffie-hellman'); + +describe('diffie-hellman', function () { + var p = 23; + var g = 5; + var diffieHellman = new DiffieHellman(p, g); + + var alicePrivateKey = 6; + var alicePublicKey = 8; + + var bobPrivateKey = 15; + var bobPublicKey = 19; + + it('throws an error if the constructor arguments are out of range', function () { + expect(function () { + return new DiffieHellman(0, 9999); + }).toThrow(); + }); + + xit('throws an error if the constructor arguments are not prime', function () { + expect(function () { + return new DiffieHellman(10, 13); + }).toThrow(); + }); + + xit('throws an error if private key is negative', function () { + expect(function () { + diffieHellman.getPublicKeyFromPrivateKey(-1); + }).toThrow(); + }); + + xit('throws an error if private key is zero', function () { + expect(function () { + diffieHellman.getPublicKeyFromPrivateKey(0); + }).toThrow(); + }); + + xit('throws an error if private key is one', function () { + expect(function () { + diffieHellman.getPublicKeyFromPrivateKey(1); + }).toThrow(); + }); + + xit('throws an error if private key equals the modulus parameter p', function () { + expect(function () { + diffieHellman.getPublicKeyFromPrivateKey(p); + }).toThrow(); + }); + + xit('throws an error if private key is greater than the modulus parameter p', function () { + expect(function () { + diffieHellman.getPublicKeyFromPrivateKey(p + 1); + }).toThrow(); + }); + + xit('when given a private key, returns the correct public one', function () { + expect(diffieHellman.getPublicKeyFromPrivateKey(alicePrivateKey)).toEqual(alicePublicKey); + }); + + xit('when given a different private key, returns the correct public one', function () { + expect(diffieHellman.getPublicKeyFromPrivateKey(bobPrivateKey)).toEqual(bobPublicKey); + }); + + xit('can generate a shared secret from our private key and their public key', function () { + var sharedSecret = 2; + + expect(diffieHellman.getSharedSecret(alicePrivateKey, bobPublicKey)) + .toEqual(sharedSecret); + + expect(diffieHellman.getSharedSecret(bobPrivateKey, alicePublicKey)) + .toEqual(sharedSecret); + }); +}); diff --git a/exercises/diffie-hellman/example.js b/exercises/diffie-hellman/example.js new file mode 100644 index 00000000..ce6c9141 --- /dev/null +++ b/exercises/diffie-hellman/example.js @@ -0,0 +1,48 @@ + +var DiffieHellman = function (p, g) { + this.p = p; + this.g = g; + + // array of first 1000 primes. + this.PRIMES = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997, 1009, 1013, 1019, 1021, 1031, 1033, 1039, 1049, 1051, 1061, 1063, 1069, 1087, 1091, 1093, 1097, 1103, 1109, 1117, 1123, 1129, 1151, 1153, 1163, 1171, 1181, 1187, 1193, 1201, 1213, 1217, 1223, 1229, 1231, 1237, 1249, 1259, 1277, 1279, 1283, 1289, 1291, 1297, 1301, 1303, 1307, 1319, 1321, 1327, 1361, 1367, 1373, 1381, 1399, 1409, 1423, 1427, 1429, 1433, 1439, 1447, 1451, 1453, 1459, 1471, 1481, 1483, 1487, 1489, 1493, 1499, 1511, 1523, 1531, 1543, 1549, 1553, 1559, 1567, 1571, 1579, 1583, 1597, 1601, 1607, 1609, 1613, 1619, 1621, 1627, 1637, 1657, 1663, 1667, 1669, 1693, 1697, 1699, 1709, 1721, 1723, 1733, 1741, 1747, 1753, 1759, 1777, 1783, 1787, 1789, 1801, 1811, 1823, 1831, 1847, 1861, 1867, 1871, 1873, 1877, 1879, 1889, 1901, 1907, 1913, 1931, 1933, 1949, 1951, 1973, 1979, 1987, 1993, 1997, 1999, 2003, 2011, 2017, 2027, 2029, 2039, 2053, 2063, 2069, 2081, 2083, 2087, 2089, 2099, 2111, 2113, 2129, 2131, 2137, 2141, 2143, 2153, 2161, 2179, 2203, 2207, 2213, 2221, 2237, 2239, 2243, 2251, 2267, 2269, 2273, 2281, 2287, 2293, 2297, 2309, 2311, 2333, 2339, 2341, 2347, 2351, 2357, 2371, 2377, 2381, 2383, 2389, 2393, 2399, 2411, 2417, 2423, 2437, 2441, 2447, 2459, 2467, 2473, 2477, 2503, 2521, 2531, 2539, 2543, 2549, 2551, 2557, 2579, 2591, 2593, 2609, 2617, 2621, 2633, 2647, 2657, 2659, 2663, 2671, 2677, 2683, 2687, 2689, 2693, 2699, 2707, 2711, 2713, 2719, 2729, 2731, 2741, 2749, 2753, 2767, 2777, 2789, 2791, 2797, 2801, 2803, 2819, 2833, 2837, 2843, 2851, 2857, 2861, 2879, 2887, 2897, 2903, 2909, 2917, 2927, 2939, 2953, 2957, 2963, 2969, 2971, 2999, 3001, 3011, 3019, 3023, 3037, 3041, 3049, 3061, 3067, 3079, 3083, 3089, 3109, 3119, 3121, 3137, 3163, 3167, 3169, 3181, 3187, 3191, 3203, 3209, 3217, 3221, 3229, 3251, 3253, 3257, 3259, 3271, 3299, 3301, 3307, 3313, 3319, 3323, 3329, 3331, 3343, 3347, 3359, 3361, 3371, 3373, 3389, 3391, 3407, 3413, 3433, 3449, 3457, 3461, 3463, 3467, 3469, 3491, 3499, 3511, 3517, 3527, 3529, 3533, 3539, 3541, 3547, 3557, 3559, 3571, 3581, 3583, 3593, 3607, 3613, 3617, 3623, 3631, 3637, 3643, 3659, 3671, 3673, 3677, 3691, 3697, 3701, 3709, 3719, 3727, 3733, 3739, 3761, 3767, 3769, 3779, 3793, 3797, 3803, 3821, 3823, 3833, 3847, 3851, 3853, 3863, 3877, 3881, 3889, 3907, 3911, 3917, 3919, 3923, 3929, 3931, 3943, 3947, 3967, 3989, 4001, 4003, 4007, 4013, 4019, 4021, 4027, 4049, 4051, 4057, 4073, 4079, 4091, 4093, 4099, 4111, 4127, 4129, 4133, 4139, 4153, 4157, 4159, 4177, 4201, 4211, 4217, 4219, 4229, 4231, 4241, 4243, 4253, 4259, 4261, 4271, 4273, 4283, 4289, 4297, 4327, 4337, 4339, 4349, 4357, 4363, 4373, 4391, 4397, 4409, 4421, 4423, 4441, 4447, 4451, 4457, 4463, 4481, 4483, 4493, 4507, 4513, 4517, 4519, 4523, 4547, 4549, 4561, 4567, 4583, 4591, 4597, 4603, 4621, 4637, 4639, 4643, 4649, 4651, 4657, 4663, 4673, 4679, 4691, 4703, 4721, 4723, 4729, 4733, 4751, 4759, 4783, 4787, 4789, 4793, 4799, 4801, 4813, 4817, 4831, 4861, 4871, 4877, 4889, 4903, 4909, 4919, 4931, 4933, 4937, 4943, 4951, 4957, 4967, 4969, 4973, 4987, 4993, 4999, 5003, 5009, 5011, 5021, 5023, 5039, 5051, 5059, 5077, 5081, 5087, 5099, 5101, 5107, 5113, 5119, 5147, 5153, 5167, 5171, 5179, 5189, 5197, 5209, 5227, 5231, 5233, 5237, 5261, 5273, 5279, 5281, 5297, 5303, 5309, 5323, 5333, 5347, 5351, 5381, 5387, 5393, 5399, 5407, 5413, 5417, 5419, 5431, 5437, 5441, 5443, 5449, 5471, 5477, 5479, 5483, 5501, 5503, 5507, 5519, 5521, 5527, 5531, 5557, 5563, 5569, 5573, 5581, 5591, 5623, 5639, 5641, 5647, 5651, 5653, 5657, 5659, 5669, 5683, 5689, 5693, 5701, 5711, 5717, 5737, 5741, 5743, 5749, 5779, 5783, 5791, 5801, 5807, 5813, 5821, 5827, 5839, 5843, 5849, 5851, 5857, 5861, 5867, 5869, 5879, 5881, 5897, 5903, 5923, 5927, 5939, 5953, 5981, 5987, 6007, 6011, 6029, 6037, 6043, 6047, 6053, 6067, 6073, 6079, 6089, 6091, 6101, 6113, 6121, 6131, 6133, 6143, 6151, 6163, 6173, 6197, 6199, 6203, 6211, 6217, 6221, 6229, 6247, 6257, 6263, 6269, 6271, 6277, 6287, 6299, 6301, 6311, 6317, 6323, 6329, 6337, 6343, 6353, 6359, 6361, 6367, 6373, 6379, 6389, 6397, 6421, 6427, 6449, 6451, 6469, 6473, 6481, 6491, 6521, 6529, 6547, 6551, 6553, 6563, 6569, 6571, 6577, 6581, 6599, 6607, 6619, 6637, 6653, 6659, 6661, 6673, 6679, 6689, 6691, 6701, 6703, 6709, 6719, 6733, 6737, 6761, 6763, 6779, 6781, 6791, 6793, 6803, 6823, 6827, 6829, 6833, 6841, 6857, 6863, 6869, 6871, 6883, 6899, 6907, 6911, 6917, 6947, 6949, 6959, 6961, 6967, 6971, 6977, 6983, 6991, 6997, 7001, 7013, 7019, 7027, 7039, 7043, 7057, 7069, 7079, 7103, 7109, 7121, 7127, 7129, 7151, 7159, 7177, 7187, 7193, 7207, 7211, 7213, 7219, 7229, 7237, 7243, 7247, 7253, 7283, 7297, 7307, 7309, 7321, 7331, 7333, 7349, 7351, 7369, 7393, 7411, 7417, 7433, 7451, 7457, 7459, 7477, 7481, 7487, 7489, 7499, 7507, 7517, 7523, 7529, 7537, 7541, 7547, 7549, 7559, 7561, 7573, 7577, 7583, 7589, 7591, 7603, 7607, 7621, 7639, 7643, 7649, 7669, 7673, 7681, 7687, 7691, 7699, 7703, 7717, 7723, 7727, 7741, 7753, 7757, 7759, 7789, 7793, 7817, 7823, 7829, 7841, 7853, 7867, 7873, 7877, 7879, 7883, 7901, 7907, 7919 + ]; + + this.getPublicKeyFromPrivateKey = function (privateKey) { + if (privateKey <= 1 || privateKey > this.p - 1) { + throw Error('Private key must be greater than one but less than modulus parameter p!'); + } + return Math.pow(this.g, privateKey) % this.p; + }; + + this.getSharedSecret = function (ourPrivateKey, theirPublicKey) { + return Math.pow(theirPublicKey, ourPrivateKey) % this.p; + }; + + this.validateInitialArguments = function (primeModulus, generator) { + var BIGGEST_PRIME = this.PRIMES[this.PRIMES.length - 1]; + return primeModulus >= 2 + && generator >= 2 + && primeModulus <= BIGGEST_PRIME + && generator <= BIGGEST_PRIME + && arrIncludes(this.PRIMES, primeModulus) + && arrIncludes(this.PRIMES, generator); + }; + + function arrIncludes(arr, a) { + for (var i = 0; i < arr.length; i++) { + if (arr[i] === a) { + return true; + } + } + return false; + } + + + if (!this.validateInitialArguments(p, g)) { + throw Error('Constructor arguments are out of range or non-prime!'); + } +}; + + +module.exports = DiffieHellman; diff --git a/exercises/etl/README.md b/exercises/etl/README.md index 3cbb4ed5..fad82d79 100644 --- a/exercises/etl/README.md +++ b/exercises/etl/README.md @@ -1,8 +1,9 @@ -# Etl +# ETL We are going to do the `Transform` step of an Extract-Transform-Load. ### ETL + Extract-Transform-Load (ETL) is a fancy way of saying, "We have some crufty, legacy data over in this system, and now we need it in this shiny new system over here, so we're going to migrate this." @@ -11,6 +12,7 @@ once." That's then typically followed by much forehead slapping and moaning about how stupid we could possibly be.) ### The goal + We're going to extract some scrabble scores from a legacy system. The old system stored a list of letters per score: @@ -46,26 +48,29 @@ game while being scored at 4 in the Hawaiian-language version. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine etl.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/etl/etl.spec.js b/exercises/etl/etl.spec.js index f2132843..23076ecf 100644 --- a/exercises/etl/etl.spec.js +++ b/exercises/etl/etl.spec.js @@ -1,30 +1,30 @@ var ETL = require('./etl'); -describe('Transform', function() { +describe('Transform', function () { var etl = new ETL(); - it('transforms one value', function() { + it('transforms one value', function () { var old = { 1: ['A'] }; var expected = { a: 1 }; expect(etl.transform(old)).toEqual(expected); }); - xit('transforms more values', function() { + xit('transforms more values', function () { var old = { 1: ['A', 'E', 'I', 'O', 'U'] }; var expected = { a: 1, e: 1, i: 1, o: 1, u: 1 }; expect(etl.transform(old)).toEqual(expected); }); - xit('transforms more keys', function() { + xit('transforms more keys', function () { var old = { 1: ['A', 'E'], 2: ['D', 'G'] }; var expected = { a: 1, e: 1, d: 2, g: 2 }; expect(etl.transform(old)).toEqual(expected); }); - xit('transforms a full dataset', function() { + xit('transforms a full dataset', function () { var old = { 1: [ 'A', 'E', 'I', 'O', 'U', 'L', 'N', 'R', 'S', 'T' ], 2: [ 'D', 'G' ], @@ -45,5 +45,4 @@ describe('Transform', function() { expect(etl.transform(old)).toEqual(expected); }); - }); diff --git a/exercises/etl/example.js b/exercises/etl/example.js index e0a51bf6..cd8df0ce 100644 --- a/exercises/etl/example.js +++ b/exercises/etl/example.js @@ -2,7 +2,7 @@ function ETL() {} -ETL.prototype.transform = function(input) { +ETL.prototype.transform = function (input) { var output = {}; var object = Object.keys(input); diff --git a/exercises/flatten-array/README.md b/exercises/flatten-array/README.md index bdb7ff67..2a98a300 100644 --- a/exercises/flatten-array/README.md +++ b/exercises/flatten-array/README.md @@ -3,36 +3,38 @@ Take a nested list and return a single flattened list with all values except nil/null. The challenge is to write a function that accepts an arbitrarily-deep nested list-like structure and returns a flattened structure without any nil/null values. - + For Example input: [1,[2,3,null,4],[null],5] output: [1,2,3,4,5] - ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine flatten-array.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/flatten-array/example.js b/exercises/flatten-array/example.js index fcaa8444..658eb26e 100644 --- a/exercises/flatten-array/example.js +++ b/exercises/flatten-array/example.js @@ -1,15 +1,16 @@ -var Flattener = function(){}; +var Flattener = function () { }; -Flattener.prototype.flatten = function(unflattenedArray, flattenedArray){ - var self = this, flattenedArray = flattenedArray || []; - unflattenedArray.forEach(function(element){ - if(Array.isArray(element)){ - return self.flatten(element, flattenedArray); - }else if( element !== null){ - flattenedArray.push(element); - } - }); - return flattenedArray; -} +Flattener.prototype.flatten = function (unflattenedArray, inputFlattenedArray) { + var self = this; + var flattenedArray = inputFlattenedArray || []; + unflattenedArray.forEach(function (element) { + if (Array.isArray(element)) { + self.flatten(element, flattenedArray); + } else if (element !== null) { + flattenedArray.push(element); + } + }); + return flattenedArray; +}; -module.exports = Flattener; \ No newline at end of file +module.exports = Flattener; diff --git a/exercises/flatten-array/flatten-array.spec.js b/exercises/flatten-array/flatten-array.spec.js index 5009a257..4c5be05f 100644 --- a/exercises/flatten-array/flatten-array.spec.js +++ b/exercises/flatten-array/flatten-array.spec.js @@ -1,26 +1,26 @@ -var Flattener = require("./flatten-array.js"); +var Flattener = require('./flatten-array.js'); -describe("FlattenArray", function() { +describe('FlattenArray', function () { var flattener = new Flattener(); - it('flattens a nested list', function(){ - expect(flattener.flatten([[]])).toEqual([]); - }); - xit('flattens a 2 level nested list', function(){ - expect(flattener.flatten([1,[2,3,4],5])).toEqual([1, 2, 3, 4, 5]); - }); - xit('flattens a 3 level nested list', function(){ - expect(flattener.flatten([1,[2,3,4],5,[6,[7,8]]])).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); - }); - xit('flattens a 5 level nested list', function(){ - expect(flattener.flatten([0, 2, [[2, 3], 8, 100, 4,[[[50]]]], -2])).toEqual([0, 2, 2, 3, 8, 100, 4, 50, -2]); - }); - xit('flattens a 6 level nest list', function(){ - expect(flattener.flatten([1,[2,[[3]],[4,[[5]]],6,7],8])).toEqual([1,2,3,4,5,6,7,8]); - }); - xit('flattens a 6 level nest list with null values', function(){ - expect(flattener.flatten([0, 2, [[2, 3], 8, [[100]], null, [[null]]], -2])).toEqual([0,2,2,3,8,100,-2]); - }); - xit('returns an empty list if all values in nested list are null', function(){ - expect(flattener.flatten([null,[[[null]]],null,null,[[null,null],null],null])).toEqual([]); - }); + it('flattens a nested list', function () { + expect(flattener.flatten([[]])).toEqual([]); + }); + xit('flattens a 2 level nested list', function () { + expect(flattener.flatten([1, [2, 3, 4], 5])).toEqual([1, 2, 3, 4, 5]); + }); + xit('flattens a 3 level nested list', function () { + expect(flattener.flatten([1, [2, 3, 4], 5, [6, [7, 8]]])).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); + }); + xit('flattens a 5 level nested list', function () { + expect(flattener.flatten([0, 2, [[2, 3], 8, 100, 4, [[[50]]]], -2])).toEqual([0, 2, 2, 3, 8, 100, 4, 50, -2]); + }); + xit('flattens a 6 level nest list', function () { + expect(flattener.flatten([1, [2, [[3]], [4, [[5]]], 6, 7], 8])).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); + }); + xit('flattens a 6 level nest list with null values', function () { + expect(flattener.flatten([0, 2, [[2, 3], 8, [[100]], null, [[null]]], -2])).toEqual([0, 2, 2, 3, 8, 100, -2]); + }); + xit('returns an empty list if all values in nested list are null', function () { + expect(flattener.flatten([null, [[[null]]], null, null, [[null, null], null], null])).toEqual([]); + }); }); diff --git a/exercises/food-chain/README.md b/exercises/food-chain/README.md index 9386f059..1f1cf16a 100644 --- a/exercises/food-chain/README.md +++ b/exercises/food-chain/README.md @@ -10,7 +10,7 @@ This is a [cumulative song](http://en.wikipedia.org/wiki/Cumulative_song) of unk This is one of many common variants. -```plain +```text I know an old lady who swallowed a fly. I don't know why she swallowed the fly. Perhaps she'll die. @@ -65,26 +65,29 @@ She's dead, of course! ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine food-chain.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/food-chain/example.js b/exercises/food-chain/example.js index ab719fce..f3b567b2 100644 --- a/exercises/food-chain/example.js +++ b/exercises/food-chain/example.js @@ -29,51 +29,64 @@ FoodChain.prototype.verses = function (first, last) { /** * Return song verse by number. * - * @param {Number} verse + * @param {Number} number * verse number * * @return {String} * song verse */ FoodChain.prototype.verse = function (number) { + var verse; + switch (number) { - case 1: return '' + - 'I know an old lady who swallowed a fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; - - case 2: return '' + - 'I know an old lady who swallowed a spider.\n' + 'It wriggled and jiggled and tickled inside her.\n' + - 'She swallowed the spider to catch the fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; - - case 3: return '' + - 'I know an old lady who swallowed a bird.\n' + 'How absurd to swallow a bird!\n' + - 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + - 'She swallowed the spider to catch the fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; - - case 4: return '' + - 'I know an old lady who swallowed a cat.\n' + 'Imagine that, to swallow a cat!\n' + 'She swallowed the cat to catch the bird.\n' + - 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + 'She swallowed the spider to catch the fly.\n' + - 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; - - case 5: return '' + - 'I know an old lady who swallowed a dog.\n' + 'What a hog, to swallow a dog!\n' + 'She swallowed the dog to catch the cat.\n' + - 'She swallowed the cat to catch the bird.\n' + 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + - 'She swallowed the spider to catch the fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; - - case 6: return '' + - 'I know an old lady who swallowed a goat.\n' + 'Just opened her throat and swallowed a goat!\n' + 'She swallowed the goat to catch the dog.\n' + - 'She swallowed the dog to catch the cat.\n' + 'She swallowed the cat to catch the bird.\n' + - 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + - 'She swallowed the spider to catch the fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; - - case 7: return '' + - 'I know an old lady who swallowed a cow.\n' + 'I don\'t know how she swallowed a cow!\n' + 'She swallowed the cow to catch the goat.\n' + - 'She swallowed the goat to catch the dog.\n' + 'She swallowed the dog to catch the cat.\n' + 'She swallowed the cat to catch the bird.\n' + - 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + 'She swallowed the spider to catch the fly.\n' + - 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; - - case 8: return '' + - 'I know an old lady who swallowed a horse.\n' + 'She\'s dead, of course!\n'; - }; + case 1: + verse = 'I know an old lady who swallowed a fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; + break; + + case 2: + verse = 'I know an old lady who swallowed a spider.\n' + 'It wriggled and jiggled and tickled inside her.\n' + + 'She swallowed the spider to catch the fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; + break; + + case 3: + verse = 'I know an old lady who swallowed a bird.\n' + 'How absurd to swallow a bird!\n' + + 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + + 'She swallowed the spider to catch the fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; + break; + + case 4: + verse = 'I know an old lady who swallowed a cat.\n' + 'Imagine that, to swallow a cat!\n' + 'She swallowed the cat to catch the bird.\n' + + 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + 'She swallowed the spider to catch the fly.\n' + + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; + break; + + case 5: + verse = 'I know an old lady who swallowed a dog.\n' + 'What a hog, to swallow a dog!\n' + 'She swallowed the dog to catch the cat.\n' + + 'She swallowed the cat to catch the bird.\n' + 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + + 'She swallowed the spider to catch the fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; + break; + + case 6: + verse = 'I know an old lady who swallowed a goat.\n' + 'Just opened her throat and swallowed a goat!\n' + 'She swallowed the goat to catch the dog.\n' + + 'She swallowed the dog to catch the cat.\n' + 'She swallowed the cat to catch the bird.\n' + + 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + + 'She swallowed the spider to catch the fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; + break; + + case 7: + verse = 'I know an old lady who swallowed a cow.\n' + 'I don\'t know how she swallowed a cow!\n' + 'She swallowed the cow to catch the goat.\n' + + 'She swallowed the goat to catch the dog.\n' + 'She swallowed the dog to catch the cat.\n' + 'She swallowed the cat to catch the bird.\n' + + 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + 'She swallowed the spider to catch the fly.\n' + + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n'; + break; + + case 8: verse = 'I know an old lady who swallowed a horse.\n' + 'She\'s dead, of course!\n'; + break; + + default: verse = ''; + } + + return verse; }; FoodChain.prototype.sing = FoodChain.prototype.verses.bind(null, 1, 8); diff --git a/exercises/food-chain/food-chain.spec.js b/exercises/food-chain/food-chain.spec.js index 382e26b9..6287146e 100644 --- a/exercises/food-chain/food-chain.spec.js +++ b/exercises/food-chain/food-chain.spec.js @@ -109,7 +109,7 @@ describe('Food Chain', function () { 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + 'She swallowed the spider to catch the fly.\n' + 'I don\'t know why she swallowed the fly. Perhaps she\'ll die.\n\n'; - expected += 'I know an old lady who swallowed a cat.\n' + + expected += 'I know an old lady who swallowed a cat.\n' + 'Imagine that, to swallow a cat!\n' + 'She swallowed the cat to catch the bird.\n' + 'She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.\n' + @@ -147,6 +147,5 @@ describe('Food Chain', function () { expect(song.verses(1, 8)).toEqual(expected); }); - }); diff --git a/exercises/forth/README.md b/exercises/forth/README.md new file mode 100644 index 00000000..2c42e805 --- /dev/null +++ b/exercises/forth/README.md @@ -0,0 +1,55 @@ +# Forth + +Implement an evaluator for a very simple subset of Forth. + +[Forth](https://en.wikipedia.org/wiki/Forth_%28programming_language%29) +is a stack-based programming language. Implement a very basic evaluator +for a small subset of Forth. + +Your evaluator has to support the following words: + +- `+`, `-`, `*`, `/` (integer arithmetic) +- `DUP`, `DROP`, `SWAP`, `OVER` (stack manipulation) + +Your evaluator also has to support defining new words using the +customary syntax: `: word-name definition ;`. + +To keep things simple the only data type you need to support is signed +integers of at least 16 bits size. + +You should use the following rules for the syntax: a number is a +sequence of one or more (ASCII) digits, a word is a sequence of one or +more letters, digits, symbols or punctuation that is not a number. +(Forth probably uses slightly different rules, but this is close +enough.) + +Words are case-insensitive. + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine forth.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/forth/example.js b/exercises/forth/example.js new file mode 100644 index 00000000..e1bfa34b --- /dev/null +++ b/exercises/forth/example.js @@ -0,0 +1,66 @@ +var Forth = function () { + this.stack = []; + this.commands = Forth.basicCommands(); +}; + +Forth.prototype.evaluate = function (program) { + var words = program.toLowerCase().split(' '); + + for (var t = 0; t < words.length; t++) { + var word = words[t]; + + if (/^-?\d+$/.test(word)) { + // numbers + this.stack.push(Number(word)); + } else if (word === ':') { + // word definition + var semicolon = words.indexOf(';', t); + if (semicolon === -1) throw new Error('Unterminated definition'); + this.defineCommand(words[t + 1], words.slice(t + 2, semicolon).join(' ')); + t = semicolon; + } else { + // commands + var command = this.commands[word]; + if (!command) throw new Error('Unknown command'); + this.performCommand(command); + } + } +}; + +Forth.prototype.defineCommand = function (word, subprogram) { + if (Forth.isKeyword(word)) throw new Error('Invalid definition'); + this.commands[word] = { + arity: 0, // handled inside the call + execute: this.evaluate.bind(this, subprogram) + }; +}; + +Forth.prototype.performCommand = function (command) { + if (command.arity > this.stack.length) throw new Error('Stack empty'); + + var args = this.stack.splice(this.stack.length - command.arity); + var vals = command.execute.apply(this, args); + this.stack.push.apply(this.stack, vals); +}; + +Forth.isKeyword = function (word) { + return word === ':' || word === ';' || /^-?\d+$/.test(word); +}; + +Forth.basicCommands = function () { + return { + '+': { arity: 2, execute: function (a, b) { return [a + b]; } }, + '-': { arity: 2, execute: function (a, b) { return [a - b]; } }, + '*': { arity: 2, execute: function (a, b) { return [a * b]; } }, + '/': { arity: 2, execute: function (a, b) { + if (b === 0) throw new Error('Division by zero'); + return [Math.floor(a / b)]; + } }, + dup: { arity: 1, execute: function (a) { return [a, a]; } }, + drop: { arity: 1, execute: function () {} }, + swap: { arity: 2, execute: function (a, b) { return [b, a]; } }, + over: { arity: 2, execute: function (a, b) { return [a, b, a]; } } + }; +}; + +module.exports = Forth; diff --git a/exercises/forth/forth.spec.js b/exercises/forth/forth.spec.js new file mode 100644 index 00000000..43bcd72a --- /dev/null +++ b/exercises/forth/forth.spec.js @@ -0,0 +1,259 @@ +var Forth = require('./forth'); + +describe('Forth', function () { + var forth; + + beforeEach(function () { + forth = new Forth(); + }); + + describe('parsing and numbers', function () { + it('just pushes numbers onto the stack', function () { + forth.evaluate('1 2 3 4 5'); + expect(forth.stack).toEqual([1, 2, 3, 4, 5]); + }); + xit('pushes negative numbers onto the stack', function () { + forth.evaluate('-1 -2 -3 -4 -5'); + expect(forth.stack).toEqual([-1, -2, -3, -4, -5]); + }); + }); + + describe('addition', function () { + xit('can add two numbers', function () { + forth.evaluate('1 2 +'); + expect(forth.stack).toEqual([3]); + }); + xit('errors if there is only one value on the stack', function () { + expect(function () { + forth.evaluate('1 +'); + }).toThrow(new Error('Stack empty')); + }); + xit('errors if there is nothing on the stack', function () { + expect(function () { + forth.evaluate('+'); + }).toThrow(new Error('Stack empty')); + }); + }); + + describe('subtraction', function () { + xit('can subtract two numbers', function () { + forth.evaluate('3 4 -'); + expect(forth.stack).toEqual([-1]); + }); + xit('errors if there is only one value on the stack', function () { + expect(function () { + forth.evaluate('1 -'); + }).toThrow(new Error('Stack empty')); + }); + xit('errors if there is nothing on the stack', function () { + expect(function () { + forth.evaluate('-'); + }).toThrow(new Error('Stack empty')); + }); + }); + + describe('multiplication', function () { + xit('can multiply two numbers', function () { + forth.evaluate('2 4 *'); + expect(forth.stack).toEqual([8]); + }); + xit('errors if there is only one value on the stack', function () { + expect(function () { + forth.evaluate('1 *'); + }).toThrow(new Error('Stack empty')); + }); + xit('errors if there is nothing on the stack', function () { + expect(function () { + forth.evaluate('*'); + }).toThrow(new Error('Stack empty')); + }); + }); + + describe('division', function () { + xit('can divide two numbers', function () { + forth.evaluate('12 3 /'); + expect(forth.stack).toEqual([4]); + }); + xit('performs integer division', function () { + forth.evaluate('8 3 /'); + expect(forth.stack).toEqual([2]); + }); + xit('errors if dividing by zero', function () { + expect(function () { + forth.evaluate('4 0 /'); + }).toThrow(new Error('Division by zero')); + }); + xit('errors if there is only one value on the stack', function () { + expect(function () { + forth.evaluate('1 /'); + }).toThrow(new Error('Stack empty')); + }); + xit('errors if there is nothing on the stack', function () { + expect(function () { + forth.evaluate('/'); + }).toThrow(new Error('Stack empty')); + }); + }); + + describe('combined arithmetic', function () { + xit('performs addition and subtraction', function () { + forth.evaluate('1 2 + 4 -'); + expect(forth.stack).toEqual([-1]); + }); + xit('performs multiplication and division', function () { + forth.evaluate('2 4 * 3 /'); + expect(forth.stack).toEqual([2]); + }); + }); + + describe('dup', function () { + xit('copies a value on the stack', function () { + forth.evaluate('1 dup'); + expect(forth.stack).toEqual([1, 1]); + }); + xit('copies the top value on the stack', function () { + forth.evaluate('1 2 dup'); + expect(forth.stack).toEqual([1, 2, 2]); + }); + xit('errors if there is nothing on the stack', function () { + expect(function () { + forth.evaluate('dup'); + }).toThrow(new Error('Stack empty')); + }); + }); + + describe('drop', function () { + xit('removes the top value on the stack if it is the only one', function () { + forth.evaluate('1 drop'); + expect(forth.stack).toEqual([]); + }); + xit('removes the top value on the stack if it is not the only one', function () { + forth.evaluate('1 2 drop'); + expect(forth.stack).toEqual([1]); + }); + xit('errors if there is nothing on the stack', function () { + expect(function () { + forth.evaluate('drop'); + }).toThrow(new Error('Stack empty')); + }); + }); + + describe('swap', function () { + xit('swaps the top two values on the stack if they are the only ones', function () { + forth.evaluate('1 2 swap'); + expect(forth.stack).toEqual([2, 1]); + }); + xit('swaps the top two values on the stack if they are not the only ones', function () { + forth.evaluate('1 2 3 swap'); + expect(forth.stack).toEqual([1, 3, 2]); + }); + xit('errors if there is only one value on the stack', function () { + expect(function () { + forth.evaluate('1 swap'); + }).toThrow(new Error('Stack empty')); + }); + xit('errors if there is nothing on the stack', function () { + expect(function () { + forth.evaluate('swap'); + }).toThrow(new Error('Stack empty')); + }); + }); + + describe('over', function () { + xit('copies the second element if there are only two', function () { + forth.evaluate('1 2 over'); + expect(forth.stack).toEqual([1, 2, 1]); + }); + xit('copies the second element if there are more than two', function () { + forth.evaluate('1 2 3 over'); + expect(forth.stack).toEqual([1, 2, 3, 2]); + }); + xit('errors if there is only one value on the stack', function () { + expect(function () { + forth.evaluate('1 over'); + }).toThrow(new Error('Stack empty')); + }); + xit('errors if there is nothing on the stack', function () { + expect(function () { + forth.evaluate('over'); + }).toThrow(new Error('Stack empty')); + }); + }); + + describe('user-defined words', function () { + xit('can consist of built-in words', function () { + forth.evaluate(': dup-twice dup dup ;'); + forth.evaluate('1 dup-twice'); + expect(forth.stack).toEqual([1, 1, 1]); + }); + xit('execute in the right order', function () { + forth.evaluate(': countup 1 2 3 ;'); + forth.evaluate('countup'); + expect(forth.stack).toEqual([1, 2, 3]); + }); + xit('can override other user-defined words', function () { + forth.evaluate(': foo dup ;'); + forth.evaluate(': foo dup dup ;'); + forth.evaluate( '1 foo'); + expect(forth.stack).toEqual([1, 1, 1]); + }); + xit('can override built-in words', function () { + forth.evaluate(': swap dup ;'); + forth.evaluate('1 swap'); + expect(forth.stack).toEqual([1, 1]); + }); + xit('can override built-in operators', function () { + forth.evaluate(': + * ;'); + forth.evaluate('3 4 +'); + expect(forth.stack).toEqual([12]); + }); + xit('cannot redefine numbers', function () { + expect(function () { + forth.evaluate(': 1 2 ;'); + }).toThrow(new Error('Invalid definition')); + }); + xit('errors if executing a non-existent word', function () { + expect(function () { + forth.evaluate('foo'); + }).toThrow(new Error('Unknown command')); + }); + xit('only defines words for current instance', function () { + var first = new Forth(); + var second = new Forth(); + first.evaluate(': + - ;'); + first.evaluate('1 1 +'); + second.evaluate('1 1 +'); + expect(first.stack).toEqual([0]); + expect(second.stack).toEqual([2]); + }); + }); + + describe('case-insensitivity', function () { + xit('DUP is case-insensitive', function () { + forth.evaluate('1 DUP Dup dup'); + expect(forth.stack).toEqual([1, 1, 1, 1]); + }); + xit('DROP is case-insensitive', function () { + forth.evaluate('1 2 3 4 DROP Drop drop'); + expect(forth.stack).toEqual([1]); + }); + xit('SWAP is case-insensitive', function () { + forth.evaluate('1 2 SWAP 3 Swap 4 swap'); + expect(forth.stack).toEqual([2, 3, 4, 1]); + }); + xit('OVER is case-insensitive', function () { + forth.evaluate('1 2 OVER Over over'); + expect(forth.stack).toEqual([1, 2, 1, 2, 1]); + }); + xit('user-defined words are case-insensitive', function () { + forth.evaluate(': foo dup ;'); + forth.evaluate('1 FOO Foo foo'); + expect(forth.stack).toEqual([1, 1, 1, 1]); + }); + xit('definitions are case-insensitive', function () { + forth.evaluate(': SWAP DUP Dup dup ;'); + forth.evaluate('1 swap'); + expect(forth.stack).toEqual([1, 1, 1, 1]); + }); + }); +}); diff --git a/exercises/gigasecond/README.md b/exercises/gigasecond/README.md index 4c73cb89..0bcf1777 100644 --- a/exercises/gigasecond/README.md +++ b/exercises/gigasecond/README.md @@ -6,26 +6,29 @@ A gigasecond is 10^9 (1,000,000,000) seconds. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine gigasecond.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/gigasecond/example.js b/exercises/gigasecond/example.js index f36189f8..420fb0dc 100644 --- a/exercises/gigasecond/example.js +++ b/exercises/gigasecond/example.js @@ -3,7 +3,7 @@ function Gigasecond(dateOfBirth) { this.dateOfBirth = dateOfBirth; - this.date = function() { + this.date = function () { var gigasecondDate = new Date(this.dateOfBirth.getTime() + 1000000000000); return gigasecondDate; }; diff --git a/exercises/gigasecond/gigasecond.spec.js b/exercises/gigasecond/gigasecond.spec.js index 5cf3384c..0fbe7c22 100644 --- a/exercises/gigasecond/gigasecond.spec.js +++ b/exercises/gigasecond/gigasecond.spec.js @@ -1,26 +1,25 @@ var Gigasecond = require('./gigasecond'); -describe('Gigasecond', function() { - - it('tells a gigasecond anniversary since midnight', function() { +describe('Gigasecond', function () { + it('tells a gigasecond anniversary since midnight', function () { var gs = new Gigasecond(new Date(Date.UTC(2015, 8, 14))); var expectedDate = new Date(Date.UTC(2047, 4, 23, 1, 46, 40)); expect(gs.date()).toEqual(expectedDate); }); - xit('tells the anniversary is next day when you are born at night', function() { + xit('tells the anniversary is next day when you are born at night', function () { var gs = new Gigasecond(new Date(Date.UTC(2015, 8, 14, 23, 59, 59))); var expectedDate = new Date(Date.UTC(2047, 4, 24, 1, 46, 39)); expect(gs.date()).toEqual(expectedDate); }); - xit('even works before 1970 (beginning of Unix epoch)', function() { + xit('even works before 1970 (beginning of Unix epoch)', function () { var gs = new Gigasecond(new Date(Date.UTC(1959, 6, 19, 5, 13, 45))); var expectedDate = new Date(Date.UTC(1991, 2, 27, 7, 0, 25)); expect(gs.date()).toEqual(expectedDate); }); - xit('make sure calling "date" doesn\'t mutate value', function() { + xit('make sure calling "date" doesn\'t mutate value', function () { var gs = new Gigasecond(new Date(Date.UTC(1959, 6, 19, 5, 13, 45))); var expectedDate = new Date(Date.UTC(1991, 2, 27, 7, 0, 25)); gs.date(); diff --git a/exercises/grade-school/README.md b/exercises/grade-school/README.md index 9a34bb7e..e9d6156a 100644 --- a/exercises/grade-school/README.md +++ b/exercises/grade-school/README.md @@ -21,7 +21,6 @@ In the end, you should be able to: Note that all our students only have one name. (It's a small town, what do you want?) - ## For bonus points Did you get the tests passing and the code clean? If you want to, these @@ -37,26 +36,29 @@ experiment make the code better? Worse? Did you learn anything from it? ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine grade-school.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/grade-school/example.js b/exercises/grade-school/example.js index 34be7f87..2e81015c 100644 --- a/exercises/grade-school/example.js +++ b/exercises/grade-school/example.js @@ -1,12 +1,11 @@ module.exports = function School() { - var db = {}; - function add(student, grade) { - if(db[grade]) { - db[grade].push(student); + function add(student, gradeLevel) { + if (db[gradeLevel]) { + db[gradeLevel].push(student); } else { - db[grade] = [student]; + db[gradeLevel] = [student]; } } @@ -15,8 +14,8 @@ module.exports = function School() { } function roster() { - return sortedGrades().reduce(function(sorted, grade) { - sorted[grade] = clone(db[grade]).sort(); + return sortedGrades().reduce(function (sorted, gradeLevel) { + sorted[gradeLevel] = clone(db[gradeLevel]).sort(); return sorted; }, {}); } @@ -30,7 +29,6 @@ module.exports = function School() { add: add, grade: grade }; - }; function clone(array) { diff --git a/exercises/grade-school/grade-school.spec.js b/exercises/grade-school/grade-school.spec.js index 9a58167c..2a30c810 100644 --- a/exercises/grade-school/grade-school.spec.js +++ b/exercises/grade-school/grade-school.spec.js @@ -1,60 +1,59 @@ var School = require('./grade-school'); -describe('School', function() { +describe('School', function () { var school; - beforeEach(function() { + beforeEach(function () { school = new School(); }); - it('a new school has an empty roster', function() { + it('a new school has an empty roster', function () { expect(school.roster()).toEqual({}); }); - xit('adding a student adds them to the roster for the given grade', function() { + xit('adding a student adds them to the roster for the given grade', function () { school.add('Aimee', 2); - var expectedDb = { 2 : [ 'Aimee' ] }; + var expectedDb = { 2: [ 'Aimee' ] }; expect(school.roster()).toEqual(expectedDb); }); - xit('adding more students to the same grade adds them to the roster', function() { - school.add('Blair',2); - school.add('James',2); - school.add('Paul',2); - var expectedDb = { 2 : [ 'Blair', 'James', 'Paul' ] }; + xit('adding more students to the same grade adds them to the roster', function () { + school.add('Blair', 2); + school.add('James', 2); + school.add('Paul', 2); + var expectedDb = { 2: [ 'Blair', 'James', 'Paul' ] }; expect(school.roster()).toEqual(expectedDb); }); - xit('adding students to different grades adds them to the roster', function() { - school.add('Chelsea',3); - school.add('Logan',7); - var expectedDb = { 3 : [ 'Chelsea' ], 7 : [ 'Logan' ] }; + xit('adding students to different grades adds them to the roster', function () { + school.add('Chelsea', 3); + school.add('Logan', 7); + var expectedDb = { 3: [ 'Chelsea' ], 7: [ 'Logan' ] }; expect(school.roster()).toEqual(expectedDb); }); - xit('grade returns the students in that grade in alphabetical order', function() { - school.add('Franklin',5); - school.add('Bradley',5); - school.add('Jeff',1); + xit('grade returns the students in that grade in alphabetical order', function () { + school.add('Franklin', 5); + school.add('Bradley', 5); + school.add('Jeff', 1); var expectedStudents = [ 'Bradley', 'Franklin' ]; expect(school.grade(5)).toEqual(expectedStudents); }); - xit('grade returns an empty array if there are no students in that grade', function() { + xit('grade returns an empty array if there are no students in that grade', function () { expect(school.grade(1)).toEqual([]); }); - xit('the students names in each grade in the roster are sorted', function() { + xit('the students names in each grade in the roster are sorted', function () { school.add('Jennifer', 4); school.add('Kareem', 6); school.add('Christopher', 4); school.add('Kyle', 3); var sorted = { - 3 : [ 'Kyle' ], - 4 : [ 'Christopher', 'Jennifer' ], - 6 : [ 'Kareem' ] + 3: [ 'Kyle' ], + 4: [ 'Christopher', 'Jennifer' ], + 6: [ 'Kareem' ] }; expect(school.roster()).toEqual(sorted); }); - }); diff --git a/exercises/grains/README.md b/exercises/grains/README.md index bac15508..f5600499 100644 --- a/exercises/grains/README.md +++ b/exercises/grains/README.md @@ -15,7 +15,6 @@ Write code that shows: - how many grains were on each square, and - the total number of grains - ## For bonus points Did you get the tests passing and the code clean? If you want to, these @@ -29,26 +28,29 @@ experiment make the code better? Worse? Did you learn anything from it? ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine grains.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/grains/big-integer.js b/exercises/grains/big-integer.js index 78a4338f..6f21af28 100644 --- a/exercises/grains/big-integer.js +++ b/exercises/grains/big-integer.js @@ -1 +1 @@ -var bigInt=function(e){'use strict';function o(e,t){this.value=e,this.sign=t,this.isSmall=!1;}function u(e){this.value=e,this.sign=e<0,this.isSmall=!0;}function a(e){return-r0?Math.floor(e):Math.ceil(e);}function d(e,n){var r=e.length,i=n.length,s=new Array(r),o=0,u=t,a,f;for(f=0;f=u?1:0,s[f]=a-o*u;while(f0&&s.push(o),s;}function v(e,t){return e.length>=t.length?d(e,t):d(t,e);}function m(e,n){var r=e.length,i=new Array(r),s=t,o,u;for(u=0;u0)i[u++]=n%s,n=Math.floor(n/s);return i;}function g(e,n){var r=e.length,i=n.length,s=new Array(r),o=0,u=t,a,f;for(a=0;a=0?r=g(e,t):(r=g(t,e),n=!n),r=l(r),typeof r=='number'?(n&&(r=-r),new u(r)):new o(r,n);}function b(e,n,r){var i=e.length,s=new Array(i),a=-n,f=t,c,h;for(c=0;c0)i[a++]=o%s,o=Math.floor(o/s);return i;}function S(e,t){var n=[];while(t-->0)n.push(0);return n.concat(e);}function x(e,t){var n=Math.max(e.length,t.length);if(n<=400)return w(e,t);n=Math.ceil(n/2);var r=e.slice(n),i=e.slice(0,n),s=t.slice(n),o=t.slice(0,n),u=x(i,o),a=x(r,s),f=x(v(i,r),v(o,s));return v(v(u,S(g(g(f,u),a),n)),S(a,2*n));}function T(e){var n=e.length,r=h(n+n),i=t,s,o,u,a,f;for(u=0;u=0;d--){p=s-1,p=Math.floor((f[d+i]*s+f[d+i-1])/u),v=0,m=0,y=c.length;for(g=0;gi&&(c=(c+1)*u),a=Math.ceil(c/h);do{p=E(n,a);if(A(p,o)<=0)break;a--;}while(a);s.push(a),o=g(o,p);}return s.reverse(),[l(s),l(o)];}function k(e,n){var r=e.length,i=h(r),s=t,o,u,a,f;a=0;for(o=r-1;o>=0;--o)f=a*s+e[o],u=p(f/n),a=f-u*n,i[o]=u|0;return[i,a|0];}function L(e,n){var r,i=z(n),s=e.value,a=i.value,c;if(a===0)throw new Error('Cannot divide by zero');if(e.isSmall)return i.isSmall?[new u(p(s/a)),new u(s%a)]:[W[0],e];if(i.isSmall){if(a===1)return[e,W[0]];if(a==-1)return[e.negate(),W[0]];var h=Math.abs(a);if(ht.length?1:-1;for(var n=e.length-1;n>=0;n--)if(e[n]!==t[n])return e[n]>t[n]?1:-1;return 0;}function D(e){return(typeof e=='number'||typeof e=='string')&&+Math.abs(e)<=t||e instanceof o&&e.value.length<=1;}function P(e,t,n){t=z(t);var r=e.isNegative(),i=t.isNegative(),s=r?e.not():e,o=i?t.not():t,u=[],a=[],f=!1,l=!1;while(!f||!l)s.isZero()?(f=!0,u.push(r?1:0)):r?u.push(s.isEven()?1:0):u.push(s.isEven()?0:1),o.isZero()?(l=!0,a.push(i?1:0)):i?a.push(o.isEven()?1:0):a.push(o.isEven()?0:1),s=s.over(2),o=o.over(2);var c=[];for(var h=0;h=0;c--){var h=f?s.value[c]:t,d=p(Math.random()*h);a.unshift(d),d';}function U(e,t){t=bigInt(t);if(t.isZero()){if(e.isZero())return'0';throw new Error('Cannot convert nonzero numbers to base 0.');}if(t.equals(-1))return e.isZero()?'0':e.isNegative()?(new Array(1-e)).join('10'):'1'+(new Array(+e)).join('01');var n='';e.isNegative()&&t.isPositive()&&(n='-',e=e.abs());if(t.equals(1))return e.isZero()?'0':n+(new Array(+e+1)).join(1);var r=[],i=e,s;while(i.isNegative()||i.compareAbs(t)>=0){s=i.divmod(t),i=s.quotient;var o=s.remainder;o.isNegative()&&(o=t.minus(o).abs(),i=i.next()),r.push(R(o));}return r.push(R(i)),n+r.reverse().join('');}function z(e){if(e instanceof o||e instanceof u)return e;if(typeof e=='number'){if(a(e))return new u(e);e=String(e);}if(typeof e=='string'){if(a(+e)){var t=+e;if(t===p(t))return new u(t);throw'Invalid integer: '+e;}var r=e[0]==='-';r&&(e=e.slice(1));var i=e.split(/e/i);if(i.length>2)throw new Error('Invalid integer: '+f.join('e'));if(i.length===2){var s=i[1];s[0]==='+'&&(s=s.slice(1)),s=+s;if(s!==p(s)||!a(s))throw new Error('Invalid integer: '+s+' is not a valid exponent.');var f=i[0],l=f.indexOf('.');l>=0&&(s-=f.length-l,f=f.slice(0,l)+f.slice(l+1));if(s<0)throw new Error('Cannot include negative exponent part for integers');f+=(new Array(s+1)).join('0'),e=f;}var h=/^([0-9][0-9]*)$/.test(e);if(!h)throw new Error('Invalid integer: '+e);var d=[],v=e.length,m=n,g=v-m;while(v>0)d.push(+e.slice(g,v)),g-=m,g<0&&(g=0),v-=m;return c(d),new o(d,r);}}var t=1e7,n=7,r=9007199254740992,i=f(r),s=Math.log(r);o.prototype.add=function(e){var t,n=z(e);if(this.sign!==n.sign)return this.subtract(n.negate());var r=this.value,i=n.value;return n.isSmall?new o(m(r,Math.abs(i)),this.sign):new o(v(r,i),this.sign);},o.prototype.plus=o.prototype.add,u.prototype.add=function(e){var t=z(e),n=this.value;if(n<0!==t.sign)return this.subtract(t.negate());var r=t.value;if(t.isSmall){if(a(n+r))return new u(n+r);r=f(Math.abs(r));}return new o(m(r,Math.abs(n)),n<0);},u.prototype.plus=u.prototype.add,o.prototype.subtract=function(e){var t=z(e);if(this.sign!==t.sign)return this.add(t.negate());var n=this.value,r=t.value;return t.isSmall?b(n,Math.abs(r),this.sign):y(n,r,this.sign);},o.prototype.minus=o.prototype.subtract,u.prototype.subtract=function(e){var t=z(e),n=this.value;if(n<0!==t.sign)return this.add(t.negate());var r=t.value;return t.isSmall?new u(n-r):b(r,Math.abs(n),n>=0);},u.prototype.minus=u.prototype.subtract,o.prototype.negate=function(){return new o(this.value,!this.sign);},u.prototype.negate=function(){var e=this.sign,t=new u(-this.value);return t.sign=!e,t;},o.prototype.abs=function(){return new o(this.value,!1);},u.prototype.abs=function(){return new u(Math.abs(this.value));},o.prototype.multiply=function(e){var n,r=z(e),i=this.value,s=r.value,u=this.sign!==r.sign,a;if(r.isSmall){if(s===0)return W[0];if(s===1)return this;if(s===-1)return this.negate();a=Math.abs(s);if(a4e3?new o(x(i,s),u):new o(w(i,s),u);},o.prototype.times=o.prototype.multiply,u.prototype.multiply=function(e){var n=z(e),r=this.value,i=n.value;if(r===0)return W[0];if(r===1)return n;if(r===-1)return n.negate();if(n.isSmall){if(a(r*i))return new u(r*i);i=f(Math.abs(i));}var s=Math.abs(r);return sr?1:-1):-1;},o.prototype.compare=function(e){var t=z(e),n=this.value,r=t.value;return this.sign!==t.sign?t.sign?1:-1:t.isSmall?this.sign?-1:1:A(n,r)*(this.sign?-1:1);},o.prototype.compareTo=o.prototype.compare,u.prototype.compare=function(e){var t=z(e),n=this.value,r=t.value;return t.isSmall?n==r?0:n>r?1:-1:n<0!==t.sign?n<0?-1:1:n<0?1:-1;},u.prototype.compareTo=u.prototype.compare,o.prototype.equals=function(e){return this.compare(e)===0;},u.prototype.eq=u.prototype.equals=o.prototype.eq=o.prototype.equals,o.prototype.notEquals=function(e){return this.compare(e)!==0;},u.prototype.neq=u.prototype.notEquals=o.prototype.neq=o.prototype.notEquals,o.prototype.greater=function(e){return this.compare(e)>0;},u.prototype.gt=u.prototype.greater=o.prototype.gt=o.prototype.greater,o.prototype.lesser=function(e){return this.compare(e)<0;},u.prototype.lt=u.prototype.lesser=o.prototype.lt=o.prototype.lesser,o.prototype.greaterOrEquals=function(e){return this.compare(e)>=0;},u.prototype.geq=u.prototype.greaterOrEquals=o.prototype.geq=o.prototype.greaterOrEquals,o.prototype.lesserOrEquals=function(e){return this.compare(e)<=0;},u.prototype.leq=u.prototype.lesserOrEquals=o.prototype.leq=o.prototype.lesserOrEquals,o.prototype.isEven=function(){return(this.value[0]&1)===0;},u.prototype.isEven=function(){return(this.value&1)===0;},o.prototype.isOdd=function(){return(this.value[0]&1)===1;},u.prototype.isOdd=function(){return(this.value&1)===1;},o.prototype.isPositive=function(){return!this.sign;},u.prototype.isPositive=function(){return this.value>0;},o.prototype.isNegative=function(){return this.sign;},u.prototype.isNegative=function(){return this.value<0;},o.prototype.isUnit=function(){return!1;},u.prototype.isUnit=function(){return Math.abs(this.value)===1;},o.prototype.isZero=function(){return!1;},u.prototype.isZero=function(){return this.value===0;},o.prototype.isDivisibleBy=function(e){var t=z(e),n=t.value;return n===0?!1:n===1?!0:n===2?this.isEven():this.mod(t).equals(W[0]);},u.prototype.isDivisibleBy=o.prototype.isDivisibleBy,o.prototype.isPrime=function(){var e=this.abs(),t=e.prev();if(e.isUnit())return!1;if(e.equals(2)||e.equals(3)||e.equals(5))return!0;if(e.isEven()||e.isDivisibleBy(3)||e.isDivisibleBy(5))return!1;if(e.lesser(25))return!0;var n=[2,3,5,7,11,13,17,19],r=t,i,s,o,u;while(r.isEven())r=r.divide(2);for(o=0;o-r?new u(e-1):new o(i,!0);};var O=[1];while(O[O.length-1]<=t)O.push(2*O[O.length-1]);var M=O.length,_=O[M-1];o.prototype.shiftLeft=function(e){if(!D(e))return e.isNegative()?this.shiftRight(e.abs()):this.times(W[2].pow(e));e=+e;if(e<0)return this.shiftRight(-e);var t=this;while(e>=M)t=t.multiply(_),e-=M-1;return t.multiply(O[e]);},u.prototype.shiftLeft=o.prototype.shiftLeft,o.prototype.shiftRight=function(e){var t;if(!D(e))return e.isNegative()?this.shiftLeft(e.abs()):(t=this.divmod(W[2].pow(e)),t.remainder.isNegative()?t.quotient.prev():t.quotient);e=+e;if(e<0)return this.shiftLeft(-e);var n=this;while(e>=M){if(n.isZero())return n;t=L(n,_),n=t[1].isNegative()?t[0].prev():t[0],e-=M-1;}return t=L(n,O[e]),t[1].isNegative()?t[0].prev():t[0];},u.prototype.shiftRight=o.prototype.shiftRight,o.prototype.not=function(){return this.negate().prev();},u.prototype.not=o.prototype.not,o.prototype.and=function(e){return P(this,e,function(e,t){return e&t;});},u.prototype.and=o.prototype.and,o.prototype.or=function(e){return P(this,e,function(e,t){return e|t;});},u.prototype.or=o.prototype.or,o.prototype.xor=function(e){return P(this,e,function(e,t){return e^t;});},u.prototype.xor=o.prototype.xor;var q=function(e,t){var n=W[0],r=W[1],i=e.length;if(2<=t&&t<=36&&i<=s/Math.log(t))return new u(parseInt(e,t));t=z(t);var o=[],a,f=e[0]==='-';for(a=f?1:0;a');o.push(z(e.slice(h+1,a)));}}o.reverse();for(a=0;a=0)o=String(n[r]),i+=s.slice(o.length)+o;var u=this.sign?'-':'';return u+i;},u.prototype.toString=function(t){return t===e&&(t=10),t!=10?U(this,t):String(this.value);},o.prototype.valueOf=function(){return+this.toString();},o.prototype.toJSNumber=o.prototype.valueOf,u.prototype.valueOf=function(){return this.value;},u.prototype.toJSNumber=u.prototype.valueOf;var W=function(e,t){return typeof e=='undefined'?W[0]:typeof t!='undefined'?+t===10?z(e):q(e,t):z(e);};for(var X=0;X<1e3;X++)W[X]=new u(X),X>0&&(W[-X]=new u(-X));return W.one=W[1],W.zero=W[0],W.minusOne=W[-1],W.max=H,W.min=B,W.gcd=j,W.lcm=F,W.isInstance=function(e){return e instanceof o||e instanceof u;},W.randBetween=I,W;}();typeof module!='undefined'&&module.hasOwnProperty('exports')&&(module.exports=bigInt); \ No newline at end of file +var bigInt = (function (e) {'use strict'; function o(e, t) {this.value = e, this.sign = t, this.isSmall = !1;} function u(e) {this.value = e, this.sign = e < 0, this.isSmall = !0;} function a(e) {return -r < e && e < r;} function f(e) {return e < 1e7 ? [e] : e < 1e14 ? [e % 1e7, Math.floor(e / 1e7)] : [e % 1e7, Math.floor(e / 1e7) % 1e7, Math.floor(e / 1e14)];} function l(e) {c(e); var n = e.length; if (n < 4 && A(e, i) < 0) switch (n) {case 0:return 0; case 1:return e[0]; case 2:return e[0] + e[1] * t; default:return e[0] + (e[1] + e[2] * t) * t;} return e;} function c(e) {var t = e.length; while (e[--t] === 0);e.length = t + 1;} function h(e) {var t = new Array(e), n = -1; while (++n < e)t[n] = 0; return t;} function p(e) {return e > 0 ? Math.floor(e) : Math.ceil(e);} function d(e, n) {var r = e.length, i = n.length, s = new Array(r), o = 0, u = t, a, f; for (f = 0; f < i; f++)a = e[f] + n[f] + o, o = a >= u ? 1 : 0, s[f] = a - o * u; while (f < r)a = e[f] + o, o = a === u ? 1 : 0, s[f++] = a - o * u; return o > 0 && s.push(o), s;} function v(e, t) {return e.length >= t.length ? d(e, t) : d(t, e);} function m(e, n) {var r = e.length, i = new Array(r), s = t, o, u; for (u = 0; u < r; u++)o = e[u] - s + n, n = Math.floor(o / s), i[u] = o - n * s, n += 1; while (n > 0)i[u++] = n % s, n = Math.floor(n / s); return i;} function g(e, n) {var r = e.length, i = n.length, s = new Array(r), o = 0, u = t, a, f; for (a = 0; a < i; a++)f = e[a] - o - n[a], f < 0 ? (f += u, o = 1) : o = 0, s[a] = f; for (a = i; a < r; a++) {f = e[a] - o; if (!(f < 0)) {s[a++] = f; break;}f += u, s[a] = f;} for (;a < r; a++)s[a] = e[a]; return c(s), s;} function y(e, t, n) {var r, i; return A(e, t) >= 0 ? r = g(e, t) : (r = g(t, e), n = !n), r = l(r), typeof r === 'number' ? (n && (r = -r), new u(r)) : new o(r, n);} function b(e, n, r) {var i = e.length, s = new Array(i), a = -n, f = t, c, h; for (c = 0; c < i; c++)h = e[c] + a, a = Math.floor(h / f), s[c] = h < 0 ? h % f + f : h; return s = l(s), typeof s === 'number' ? (r && (s = -s), new u(s)) : new o(s, r);} function w(e, n) {var r = e.length, i = n.length, s = r + i, o = h(s), u = t, a, f, l, p, d; for (l = 0; l < r; ++l) {p = e[l]; for (var v = 0; v < i; ++v)d = n[v], a = p * d + o[l + v], f = Math.floor(a / u), o[l + v] = a - f * u, o[l + v + 1] += f;} return c(o), o;} function E(e, n) {var r = e.length, i = new Array(r), s = t, o = 0, u, a; for (a = 0; a < r; a++)u = e[a] * n + o, o = Math.floor(u / s), i[a] = u - o * s; while (o > 0)i[a++] = o % s, o = Math.floor(o / s); return i;} function S(e, t) {var n = []; while (t-- > 0)n.push(0); return n.concat(e);} function x(e, t) {var n = Math.max(e.length, t.length); if (n <= 400) return w(e, t); n = Math.ceil(n / 2); var r = e.slice(n), i = e.slice(0, n), s = t.slice(n), o = t.slice(0, n), u = x(i, o), a = x(r, s), f = x(v(i, r), v(o, s)); return v(v(u, S(g(g(f, u), a), n)), S(a, 2 * n));} function T(e) {var n = e.length, r = h(n + n), i = t, s, o, u, a, f; for (u = 0; u < n; u++) {a = e[u]; for (var l = 0; l < n; l++)f = e[l], s = a * f + r[u + l], o = Math.floor(s / i), r[u + l] = s - o * i, r[u + l + 1] += o;} return c(r), r;} function N(e, n) {var r = e.length, i = n.length, s = t, o = h(n.length), u = n[i - 1], a = Math.ceil(s / (2 * u)), f = E(e, a), c = E(n, a), p, d, v, m, g, y, b; f.length <= r && f.push(0), c.push(0), u = c[i - 1]; for (d = r - i; d >= 0; d--) {p = s - 1, p = Math.floor((f[d + i] * s + f[d + i - 1]) / u), v = 0, m = 0, y = c.length; for (g = 0; g < y; g++)v += p * c[g], b = Math.floor(v / s), m += f[d + g] - (v - b * s), v = b, m < 0 ? (f[d + g] = m + s, m = -1) : (f[d + g] = m, m = 0); while (m !== 0) {p -= 1, v = 0; for (g = 0; g < y; g++)v += f[d + g] - s + c[g], v < 0 ? (f[d + g] = v + s, v = 0) : (f[d + g] = v, v = 1); m += v;}o[d] = p;} return f = k(f, a)[0], [l(o), l(f)];} function C(e, n) {var r = e.length, i = n.length, s = [], o = [], u = t, a, f, c, h, p; while (r) {o.unshift(e[--r]); if (A(o, n) < 0) {s.push(0); continue;}f = o.length, c = o[f - 1] * u + o[f - 2], h = n[i - 1] * u + n[i - 2], f > i && (c = (c + 1) * u), a = Math.ceil(c / h); do {p = E(n, a); if (A(p, o) <= 0) break; a--;} while (a);s.push(a), o = g(o, p);} return s.reverse(), [l(s), l(o)];} function k(e, n) {var r = e.length, i = h(r), s = t, o, u, a, f; a = 0; for (o = r - 1; o >= 0; --o)f = a * s + e[o], u = p(f / n), a = f - u * n, i[o] = u | 0; return [i, a | 0];} function L(e, n) {var r, i = z(n), s = e.value, a = i.value, c; if (a === 0) throw new Error('Cannot divide by zero'); if (e.isSmall) return i.isSmall ? [new u(p(s / a)), new u(s % a)] : [W[0], e]; if (i.isSmall) {if (a === 1) return [e, W[0]]; if (a == -1) return [e.negate(), W[0]]; var h = Math.abs(a); if (h < t) {r = k(s, h), c = l(r[0]); var d = r[1]; return e.sign && (d = -d), typeof c === 'number' ? (e.sign !== i.sign && (c = -c), [new u(c), new u(d)]) : [new o(c, e.sign !== i.sign), new u(d)];}a = f(h);} var v = A(s, a); if (v === -1) return [W[0], e]; if (v === 0) return [W[e.sign === i.sign ? 1 : -1], W[0]]; s.length + a.length <= 200 ? r = N(s, a) : r = C(s, a), c = r[0]; var m = e.sign !== i.sign, g = r[1], y = e.sign; return typeof c === 'number' ? (m && (c = -c), c = new u(c)) : c = new o(c, m), typeof g === 'number' ? (y && (g = -g), g = new u(g)) : g = new o(g, y), [c, g];} function A(e, t) {if (e.length !== t.length) return e.length > t.length ? 1 : -1; for (var n = e.length - 1; n >= 0; n--) if (e[n] !== t[n]) return e[n] > t[n] ? 1 : -1; return 0;} function D(e) {return (typeof e === 'number' || typeof e === 'string') && +Math.abs(e) <= t || e instanceof o && e.value.length <= 1;} function P(e, t, n) {t = z(t); var r = e.isNegative(), i = t.isNegative(), s = r ? e.not() : e, o = i ? t.not() : t, u = [], a = [], f = !1, l = !1; while (!f || !l)s.isZero() ? (f = !0, u.push(r ? 1 : 0)) : r ? u.push(s.isEven() ? 1 : 0) : u.push(s.isEven() ? 0 : 1), o.isZero() ? (l = !0, a.push(i ? 1 : 0)) : i ? a.push(o.isEven() ? 1 : 0) : a.push(o.isEven() ? 0 : 1), s = s.over(2), o = o.over(2); var c = []; for (var h = 0; h < u.length; h++)c.push(n(u[h], a[h])); var p = bigInt(c.pop()).negate().times(bigInt(2).pow(c.length)); while (c.length)p = p.add(bigInt(c.pop()).times(bigInt(2).pow(c.length))); return p;} function H(e, t) {return e = z(e), t = z(t), e.greater(t) ? e : t;} function B(e, t) {return e = z(e), t = z(t), e.lesser(t) ? e : t;} function j(e, t) {return e = z(e).abs(), t = z(t).abs(), e.equals(t) ? e : e.isZero() ? t : t.isZero() ? e : e.isEven() ? t.isOdd() ? j(e.divide(2), t) : j(e.divide(2), t.divide(2)).multiply(2) : t.isEven() ? j(e, t.divide(2)) : e.greater(t) ? j(e.subtract(t).divide(2), t) : j(t.subtract(e).divide(2), e);} function F(e, t) {return e = z(e).abs(), t = z(t).abs(), e.multiply(t).divide(j(e, t));} function I(e, n) {e = z(e), n = z(n); var r = B(e, n), i = H(e, n), s = i.subtract(r); if (s.isSmall) return r.add(Math.random() * s); var u = s.value.length - 1, a = [], f = !0; for (var c = u; c >= 0; c--) {var h = f ? s.value[c] : t, d = p(Math.random() * h); a.unshift(d), d < h && (f = !1);} return a = l(a), r.add(new o(a, !1, typeof a === 'number'));} function R(e) {var t = e.value; return typeof t === 'number' && (t = [t]), t.length === 1 && t[0] <= 36 ? '0123456789abcdefghijklmnopqrstuvwxyz'.charAt(t[0]) : '<' + t + '>';} function U(e, t) {t = bigInt(t); if (t.isZero()) {if (e.isZero()) return '0'; throw new Error('Cannot convert nonzero numbers to base 0.');} if (t.equals(-1)) return e.isZero() ? '0' : e.isNegative() ? (new Array(1 - e)).join('10') : '1' + (new Array(+e)).join('01'); var n = ''; e.isNegative() && t.isPositive() && (n = '-', e = e.abs()); if (t.equals(1)) return e.isZero() ? '0' : n + (new Array(+e + 1)).join(1); var r = [], i = e, s; while (i.isNegative() || i.compareAbs(t) >= 0) {s = i.divmod(t), i = s.quotient; var o = s.remainder; o.isNegative() && (o = t.minus(o).abs(), i = i.next()), r.push(R(o));} return r.push(R(i)), n + r.reverse().join('');} function z(e) {if (e instanceof o || e instanceof u) return e; if (typeof e === 'number') {if (a(e)) return new u(e); e = String(e);} if (typeof e === 'string') {if (a(+e)) {var t = +e; if (t === p(t)) return new u(t); throw 'Invalid integer: ' + e;} var r = e[0] === '-'; r && (e = e.slice(1)); var i = e.split(/e/i); if (i.length > 2) throw new Error('Invalid integer: ' + f.join('e')); if (i.length === 2) {var s = i[1]; s[0] === '+' && (s = s.slice(1)), s = +s; if (s !== p(s) || !a(s)) throw new Error('Invalid integer: ' + s + ' is not a valid exponent.'); var f = i[0], l = f.indexOf('.'); l >= 0 && (s -= f.length - l, f = f.slice(0, l) + f.slice(l + 1)); if (s < 0) throw new Error('Cannot include negative exponent part for integers'); f += (new Array(s + 1)).join('0'), e = f;} var h = /^([0-9][0-9]*)$/.test(e); if (!h) throw new Error('Invalid integer: ' + e); var d = [], v = e.length, m = n, g = v - m; while (v > 0)d.push(+e.slice(g, v)), g -= m, g < 0 && (g = 0), v -= m; return c(d), new o(d, r);}} var t = 1e7, n = 7, r = 9007199254740992, i = f(r), s = Math.log(r); o.prototype.add = function (e) {var t, n = z(e); if (this.sign !== n.sign) return this.subtract(n.negate()); var r = this.value, i = n.value; return n.isSmall ? new o(m(r, Math.abs(i)), this.sign) : new o(v(r, i), this.sign);}, o.prototype.plus = o.prototype.add, u.prototype.add = function (e) {var t = z(e), n = this.value; if (n < 0 !== t.sign) return this.subtract(t.negate()); var r = t.value; if (t.isSmall) {if (a(n + r)) return new u(n + r); r = f(Math.abs(r));} return new o(m(r, Math.abs(n)), n < 0);}, u.prototype.plus = u.prototype.add, o.prototype.subtract = function (e) {var t = z(e); if (this.sign !== t.sign) return this.add(t.negate()); var n = this.value, r = t.value; return t.isSmall ? b(n, Math.abs(r), this.sign) : y(n, r, this.sign);}, o.prototype.minus = o.prototype.subtract, u.prototype.subtract = function (e) {var t = z(e), n = this.value; if (n < 0 !== t.sign) return this.add(t.negate()); var r = t.value; return t.isSmall ? new u(n - r) : b(r, Math.abs(n), n >= 0);}, u.prototype.minus = u.prototype.subtract, o.prototype.negate = function () {return new o(this.value, !this.sign);}, u.prototype.negate = function () {var e = this.sign, t = new u(-this.value); return t.sign = !e, t;}, o.prototype.abs = function () {return new o(this.value, !1);}, u.prototype.abs = function () {return new u(Math.abs(this.value));}, o.prototype.multiply = function (e) {var n, r = z(e), i = this.value, s = r.value, u = this.sign !== r.sign, a; if (r.isSmall) {if (s === 0) return W[0]; if (s === 1) return this; if (s === -1) return this.negate(); a = Math.abs(s); if (a < t) return new o(E(i, a), u); s = f(a);} return i.length + s.length > 4e3 ? new o(x(i, s), u) : new o(w(i, s), u);}, o.prototype.times = o.prototype.multiply, u.prototype.multiply = function (e) {var n = z(e), r = this.value, i = n.value; if (r === 0) return W[0]; if (r === 1) return n; if (r === -1) return n.negate(); if (n.isSmall) {if (a(r * i)) return new u(r * i); i = f(Math.abs(i));} var s = Math.abs(r); return s < t ? new o(E(i, s), this.sign !== n.sign) : new o(w(i, f(s)), this.sign !== n.sign);}, u.prototype.times = u.prototype.multiply, o.prototype.square = function () {return new o(T(this.value), !1);}, u.prototype.square = function () {var e = this.value * this.value; return a(e) ? new u(e) : new o(T(f(Math.abs(this.value))), !1);}, o.prototype.divmod = function (e) {var t = L(this, e); return {quotient: t[0], remainder: t[1]};}, u.prototype.divmod = o.prototype.divmod, o.prototype.divide = function (e) {return L(this, e)[0];}, u.prototype.over = u.prototype.divide = o.prototype.over = o.prototype.divide, o.prototype.mod = function (e) {return L(this, e)[1];}, u.prototype.remainder = u.prototype.mod = o.prototype.remainder = o.prototype.mod, o.prototype.pow = function (e) {var t = z(e), n = this.value, r = t.value, i, s, o; if (r === 0) return W[1]; if (n === 0) return W[0]; if (n === 1) return W[1]; if (n === -1) return t.isEven() ? W[1] : W[-1]; if (t.sign) return W[0]; if (!t.isSmall) throw new Error('The exponent ' + t.toString() + ' is too large.'); if (this.isSmall && a(i = Math.pow(n, r))) return new u(p(i)); s = this, o = W[1]; for (;;) {r & !0 && (o = o.times(s), --r); if (r === 0) break; r /= 2, s = s.square();} return o;}, u.prototype.pow = o.prototype.pow, o.prototype.modPow = function (e, t) {e = z(e), t = z(t); if (t.isZero()) throw new Error('Cannot take modPow with modulus 0'); var n = W[1], r = this.mod(t); if (r.isZero()) return W[0]; while (e.isPositive())e.isOdd() && (n = n.multiply(r).mod(t)), e = e.divide(2), r = r.square().mod(t); return n;}, u.prototype.modPow = o.prototype.modPow, o.prototype.compareAbs = function (e) {var t = z(e), n = this.value, r = t.value; return t.isSmall ? 1 : A(n, r);}, u.prototype.compareAbs = function (e) {var t = z(e), n = Math.abs(this.value), r = t.value; return t.isSmall ? (r = Math.abs(r), n === r ? 0 : n > r ? 1 : -1) : -1;}, o.prototype.compare = function (e) {var t = z(e), n = this.value, r = t.value; return this.sign !== t.sign ? t.sign ? 1 : -1 : t.isSmall ? this.sign ? -1 : 1 : A(n, r) * (this.sign ? -1 : 1);}, o.prototype.compareTo = o.prototype.compare, u.prototype.compare = function (e) {var t = z(e), n = this.value, r = t.value; return t.isSmall ? n == r ? 0 : n > r ? 1 : -1 : n < 0 !== t.sign ? n < 0 ? -1 : 1 : n < 0 ? 1 : -1;}, u.prototype.compareTo = u.prototype.compare, o.prototype.equals = function (e) {return this.compare(e) === 0;}, u.prototype.eq = u.prototype.equals = o.prototype.eq = o.prototype.equals, o.prototype.notEquals = function (e) {return this.compare(e) !== 0;}, u.prototype.neq = u.prototype.notEquals = o.prototype.neq = o.prototype.notEquals, o.prototype.greater = function (e) {return this.compare(e) > 0;}, u.prototype.gt = u.prototype.greater = o.prototype.gt = o.prototype.greater, o.prototype.lesser = function (e) {return this.compare(e) < 0;}, u.prototype.lt = u.prototype.lesser = o.prototype.lt = o.prototype.lesser, o.prototype.greaterOrEquals = function (e) {return this.compare(e) >= 0;}, u.prototype.geq = u.prototype.greaterOrEquals = o.prototype.geq = o.prototype.greaterOrEquals, o.prototype.lesserOrEquals = function (e) {return this.compare(e) <= 0;}, u.prototype.leq = u.prototype.lesserOrEquals = o.prototype.leq = o.prototype.lesserOrEquals, o.prototype.isEven = function () {return (this.value[0] & 1) === 0;}, u.prototype.isEven = function () {return (this.value & 1) === 0;}, o.prototype.isOdd = function () {return (this.value[0] & 1) === 1;}, u.prototype.isOdd = function () {return (this.value & 1) === 1;}, o.prototype.isPositive = function () {return !this.sign;}, u.prototype.isPositive = function () {return this.value > 0;}, o.prototype.isNegative = function () {return this.sign;}, u.prototype.isNegative = function () {return this.value < 0;}, o.prototype.isUnit = function () {return !1;}, u.prototype.isUnit = function () {return Math.abs(this.value) === 1;}, o.prototype.isZero = function () {return !1;}, u.prototype.isZero = function () {return this.value === 0;}, o.prototype.isDivisibleBy = function (e) {var t = z(e), n = t.value; return n === 0 ? !1 : n === 1 ? !0 : n === 2 ? this.isEven() : this.mod(t).equals(W[0]);}, u.prototype.isDivisibleBy = o.prototype.isDivisibleBy, o.prototype.isPrime = function () {var e = this.abs(), t = e.prev(); if (e.isUnit()) return !1; if (e.equals(2) || e.equals(3) || e.equals(5)) return !0; if (e.isEven() || e.isDivisibleBy(3) || e.isDivisibleBy(5)) return !1; if (e.lesser(25)) return !0; var n = [2, 3, 5, 7, 11, 13, 17, 19], r = t, i, s, o, u; while (r.isEven())r = r.divide(2); for (o = 0; o < n.length; o++) {u = bigInt(n[o]).modPow(r, e); if (u.equals(W[1]) || u.equals(t)) continue; for (s = !0, i = r; s && i.lesser(t); i = i.multiply(2))u = u.square().mod(e), u.equals(t) && (s = !1); if (s) return !1;} return !0;}, u.prototype.isPrime = o.prototype.isPrime, o.prototype.next = function () {var e = this.value; return this.sign ? b(e, 1, this.sign) : new o(m(e, 1), this.sign);}, u.prototype.next = function () {var e = this.value; return e + 1 < r ? new u(e + 1) : new o(i, !1);}, o.prototype.prev = function () {var e = this.value; return this.sign ? new o(m(e, 1), !0) : b(e, 1, this.sign);}, u.prototype.prev = function () {var e = this.value; return e - 1 > -r ? new u(e - 1) : new o(i, !0);}; var O = [1]; while (O[O.length - 1] <= t)O.push(2 * O[O.length - 1]); var M = O.length, _ = O[M - 1]; o.prototype.shiftLeft = function (e) {if (!D(e)) return e.isNegative() ? this.shiftRight(e.abs()) : this.times(W[2].pow(e)); e = +e; if (e < 0) return this.shiftRight(-e); var t = this; while (e >= M)t = t.multiply(_), e -= M - 1; return t.multiply(O[e]);}, u.prototype.shiftLeft = o.prototype.shiftLeft, o.prototype.shiftRight = function (e) {var t; if (!D(e)) return e.isNegative() ? this.shiftLeft(e.abs()) : (t = this.divmod(W[2].pow(e)), t.remainder.isNegative() ? t.quotient.prev() : t.quotient); e = +e; if (e < 0) return this.shiftLeft(-e); var n = this; while (e >= M) {if (n.isZero()) return n; t = L(n, _), n = t[1].isNegative() ? t[0].prev() : t[0], e -= M - 1;} return t = L(n, O[e]), t[1].isNegative() ? t[0].prev() : t[0];}, u.prototype.shiftRight = o.prototype.shiftRight, o.prototype.not = function () {return this.negate().prev();}, u.prototype.not = o.prototype.not, o.prototype.and = function (e) {return P(this, e, function (e, t) {return e & t;});}, u.prototype.and = o.prototype.and, o.prototype.or = function (e) {return P(this, e, function (e, t) {return e | t;});}, u.prototype.or = o.prototype.or, o.prototype.xor = function (e) {return P(this, e, function (e, t) {return e ^ t;});}, u.prototype.xor = o.prototype.xor; var q = function (e, t) {var n = W[0], r = W[1], i = e.length; if (t >= 2 && t <= 36 && i <= s / Math.log(t)) return new u(parseInt(e, t)); t = z(t); var o = [], a, f = e[0] === '-'; for (a = f ? 1 : 0; a < e.length; a++) {var l = e[a].toLowerCase(), c = l.charCodeAt(0); if (c >= 48 && c <= 57)o.push(z(l)); else if (c >= 97 && c <= 122)o.push(z(l.charCodeAt(0) - 87)); else {if (l !== '<') throw new Error(l + ' is not a valid character'); var h = a; do a++; while (e[a] !== '>');o.push(z(e.slice(h + 1, a)));}}o.reverse(); for (a = 0; a < o.length; a++)n = n.add(o[a].times(r)), r = r.times(t); return f ? n.negate() : n;}; o.prototype.toString = function (t) {t === e && (t = 10); if (t !== 10) return U(this, t); var n = this.value, r = n.length, i = String(n[--r]), s = '0000000', o; while (--r >= 0)o = String(n[r]), i += s.slice(o.length) + o; var u = this.sign ? '-' : ''; return u + i;}, u.prototype.toString = function (t) {return t === e && (t = 10), t != 10 ? U(this, t) : String(this.value);}, o.prototype.valueOf = function () {return +this.toString();}, o.prototype.toJSNumber = o.prototype.valueOf, u.prototype.valueOf = function () {return this.value;}, u.prototype.toJSNumber = u.prototype.valueOf; var W = function (e, t) {return typeof e === 'undefined' ? W[0] : typeof t !== 'undefined' ? +t === 10 ? z(e) : q(e, t) : z(e);}; for (var X = 0; X < 1e3; X++)W[X] = new u(X), X > 0 && (W[-X] = new u(-X)); return W.one = W[1], W.zero = W[0], W.minusOne = W[-1], W.max = H, W.min = B, W.gcd = j, W.lcm = F, W.isInstance = function (e) {return e instanceof o || e instanceof u;}, W.randBetween = I, W;}()); typeof module !== 'undefined' && module.hasOwnProperty('exports') && (module.exports = bigInt); diff --git a/exercises/grains/big-integer.spec.js b/exercises/grains/big-integer.spec.js index 26bea91f..865a66ae 100644 --- a/exercises/grains/big-integer.spec.js +++ b/exercises/grains/big-integer.spec.js @@ -4,11 +4,11 @@ var BigInt = require('./big-integer'); describe('The big-integer module\'s returned object', function () { var bigI; - beforeEach(function() { + beforeEach(function () { bigI = BigInt(42); }); - afterEach(function() { + afterEach(function () { bigI = null; }); @@ -19,20 +19,19 @@ describe('The big-integer module\'s returned object', function () { }); it('can be compared to a stringified number by calling \'.toString()\'', - function () { - - expect(bigI).not.toBe(42); - expect(bigI).not.toBe('42'); - expect(bigI.toString()).toBe('42'); - // NOTE: - // The '==' operator calls '.toString()' here in order to compare. - expect(bigI == '42').toBe(true); + function () { + expect(bigI).not.toBe(42); + expect(bigI).not.toBe('42'); + expect(bigI.toString()).toBe('42'); + // NOTE: + // The '==' operator calls '.toString()' here in order to compare. + expect(bigI == '42').toBe(true); // While the line above is easier to write and read, we will use the // 'expect(bigI.toString()).toBe(expected)' way so that test failure // messages will be more informative. Eg, // "Expected '84' to be '42'." instead of // "Expected false to be true." - }); + }); it('is immutable', function () { bigI.add(10); diff --git a/exercises/grains/example.js b/exercises/grains/example.js index 2e91b663..e8831fd2 100644 --- a/exercises/grains/example.js +++ b/exercises/grains/example.js @@ -4,7 +4,7 @@ var BigInt = require('./big-integer'); * @author github.com/nonsensery * @class Grains * - * Computes the number of grains on the squares of a + * @classdesc Computes the number of grains on the squares of a * chess board, starting with one grain on the first * square, and doubling with each successive square. */ @@ -14,16 +14,19 @@ function Grains() { /** * Gets the number of grains on the nth square. + * @param {number} num - the value to square + * @return {number} the square of num */ -Grains.prototype.square = function(num) { - return BigInt(2).pow(num - 1).toString(); +Grains.prototype.square = function (num) { + return new BigInt(2).pow(num - 1).toString(); }; /** * Gets the total number of grains on all squares. + * @return {string} the total */ Grains.prototype.total = function () { - var total = BigInt(0); + var total = new BigInt(0); for (var squareNum = 1; squareNum <= 64; ++squareNum) { total = total.add(this.square(squareNum)); diff --git a/exercises/hamming/README.md b/exercises/hamming/README.md index f44a9feb..dcfd4d5b 100644 --- a/exercises/hamming/README.md +++ b/exercises/hamming/README.md @@ -37,26 +37,29 @@ of equal length differently. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine hamming.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/hamming/hamming.spec.js b/exercises/hamming/hamming.spec.js index 0a8ad582..db0a31ef 100644 --- a/exercises/hamming/hamming.spec.js +++ b/exercises/hamming/hamming.spec.js @@ -8,15 +8,15 @@ describe('Hamming', function () { }); xit('complete hamming distance for single nucleotide strand', function () { - expect(hamming.compute('A','G')).toEqual(1); + expect(hamming.compute('A', 'G')).toEqual(1); }); xit('complete hamming distance for small strand', function () { - expect(hamming.compute('AG','CT')).toEqual(2); + expect(hamming.compute('AG', 'CT')).toEqual(2); }); xit('small hamming distance', function () { - expect(hamming.compute('AT','CT')).toEqual(1); + expect(hamming.compute('AT', 'CT')).toEqual(1); }); xit('small hamming distance in longer strand', function () { @@ -31,10 +31,9 @@ describe('Hamming', function () { expect(hamming.compute('GGACGGATTCTG', 'AGGACGGATTCT')).toEqual(9); }); - xit('throws error when strands are not equal length', function() { - expect(function() { hamming.compute('GGACGGATTCTG', 'AGGAC'); }).toThrow( + xit('throws error when strands are not equal length', function () { + expect(function () { hamming.compute('GGACGGATTCTG', 'AGGAC'); }).toThrow( new Error('DNA strands must be of equal length.') ); }); - }); diff --git a/exercises/hello-world/HINTS.md b/exercises/hello-world/.meta/hints.md similarity index 100% rename from exercises/hello-world/HINTS.md rename to exercises/hello-world/.meta/hints.md diff --git a/exercises/hello-world/README.md b/exercises/hello-world/README.md index 7e71e8a7..3a36a6bd 100644 --- a/exercises/hello-world/README.md +++ b/exercises/hello-world/README.md @@ -103,26 +103,29 @@ When you are done, submit your solution to exercism: ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js - -In many test suites all but the first test have been skipped. +```sh +jasmine hello-world.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/hello-world/example.js b/exercises/hello-world/example.js index 0cb40c8b..51eadcf3 100644 --- a/exercises/hello-world/example.js +++ b/exercises/hello-world/example.js @@ -1,10 +1,9 @@ 'use strict'; -var HelloWorld = function() {}; +var HelloWorld = function () {}; -HelloWorld.prototype.hello = function(name) { - name = name || 'World'; - return 'Hello, ' + name + '!'; +HelloWorld.prototype.hello = function () { + return 'Hello, World!'; }; module.exports = HelloWorld; diff --git a/exercises/hello-world/hello-world.js b/exercises/hello-world/hello-world.js index 4f38bdbe..000d959a 100644 --- a/exercises/hello-world/hello-world.js +++ b/exercises/hello-world/hello-world.js @@ -4,9 +4,9 @@ // Make sure to look at hello-world.spec.js--that should give you some hints about what is // expected here. -var HelloWorld = function() {}; +var HelloWorld = function () {}; -HelloWorld.prototype.hello = function() { +HelloWorld.prototype.hello = function () { // // YOUR CODE GOES HERE // diff --git a/exercises/hello-world/hello-world.spec.js b/exercises/hello-world/hello-world.spec.js index e397a6c4..2d1a8200 100644 --- a/exercises/hello-world/hello-world.spec.js +++ b/exercises/hello-world/hello-world.spec.js @@ -1,9 +1,9 @@ var HelloWorld = require('./hello-world'); -describe('Hello World', function() { +describe('Hello World', function () { var helloWorld = new HelloWorld(); - it('says hello world', function() { + it('says hello world', function () { expect(helloWorld.hello()).toEqual('Hello, World!'); }); }); diff --git a/exercises/hexadecimal/README.md b/exercises/hexadecimal/README.md index 022fe2bf..06e409dd 100644 --- a/exercises/hexadecimal/README.md +++ b/exercises/hexadecimal/README.md @@ -9,26 +9,29 @@ The program should handle invalid hexadecimal strings. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine hexadecimal.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/hexadecimal/example.js b/exercises/hexadecimal/example.js index c8a49785..9e19e38c 100644 --- a/exercises/hexadecimal/example.js +++ b/exercises/hexadecimal/example.js @@ -3,15 +3,15 @@ function Hexadecimal(hex) { this.hex = hex; - this.toDecimal = function() { + this.toDecimal = function () { var hexCharacters = this.hex.split(''); for (var i = 0; i < hexCharacters.length; i++) { if (/[^0-9a-fA-F]/.exec(hexCharacters[i])) { return 0; } } - return parseInt(this.hex,16); + return parseInt(this.hex, 16); }; } -module.exports = Hexadecimal; \ No newline at end of file +module.exports = Hexadecimal; diff --git a/exercises/hexadecimal/hexadecimal.spec.js b/exercises/hexadecimal/hexadecimal.spec.js index 5b2f49f3..dabb38d6 100644 --- a/exercises/hexadecimal/hexadecimal.spec.js +++ b/exercises/hexadecimal/hexadecimal.spec.js @@ -1,55 +1,53 @@ var Hexadecimal = require('./hexadecimal'); -describe('Hexadecimal', function() { - - it('hex 1 is decimal 1', function() { +describe('Hexadecimal', function () { + it('hex 1 is decimal 1', function () { var hex = new Hexadecimal('1'); expect(hex.toDecimal()).toEqual(1); }); - xit('hex c is decimal 12', function() { + xit('hex c is decimal 12', function () { var hex = new Hexadecimal('c'); expect(hex.toDecimal()).toEqual(12); }); - xit('hex 10 is decimal 16', function() { + xit('hex 10 is decimal 16', function () { var hex = new Hexadecimal('10'); expect(hex.toDecimal()).toEqual(16); }); - xit('hex af is decimal 175', function() { + xit('hex af is decimal 175', function () { var hex = new Hexadecimal('af'); expect(hex.toDecimal()).toEqual(175); }); - xit('hex 100 is decimal 256', function() { + xit('hex 100 is decimal 256', function () { var hex = new Hexadecimal('100'); expect(hex.toDecimal()).toEqual(256); }); - xit('hex 19ace is decimal 105166', function() { + xit('hex 19ace is decimal 105166', function () { var hex = new Hexadecimal('19ace'); expect(hex.toDecimal()).toEqual(105166); }); - xit('invalid hex is decimal 0', function() { + xit('invalid hex is decimal 0', function () { var hex = new Hexadecimal('carrot'); expect(hex.toDecimal()).toEqual(0); }); - xit('black', function() { + xit('black', function () { var hex = new Hexadecimal('000000'); expect(hex.toDecimal()).toEqual(0); }); - xit('white', function() { + xit('white', function () { var hex = new Hexadecimal('ffffff'); expect(hex.toDecimal()).toEqual(16777215); }); - xit('yellow', function() { + xit('yellow', function () { var hex = new Hexadecimal('ffff00'); expect(hex.toDecimal()).toEqual(16776960); }); - -}); \ No newline at end of file +}); diff --git a/exercises/isbn-verifier/README.md b/exercises/isbn-verifier/README.md new file mode 100644 index 00000000..da1dbccf --- /dev/null +++ b/exercises/isbn-verifier/README.md @@ -0,0 +1,74 @@ +# Isbn Verifier + +The [ISBN-10 verification process](https://en.wikipedia.org/wiki/International_Standard_Book_Number) is used to validate book identification +numbers. These normally contain dashes and look like: `3-598-21508-8` + +## ISBN + +The ISBN-10 format is 9 digits (0 to 9) plus one check character (either a digit or an X only). In the case the check character is an X, this represents the value '10'. These may be communicated with or without hyphens, and can be checked for their validity by the following formula: + +``` +(x1 * 10 + x2 * 9 + x3 * 8 + x4 * 7 + x5 * 6 + x6 * 5 + x7 * 4 + x8 * 3 + x9 * 2 + x10 * 1) mod 11 == 0 +``` + +If the result is 0, then it is a valid ISBN-10, otherwise it is invalid. + +## Example + +Let's take the ISBN-10 `3-598-21508-8`. We plug it in to the formula, and get: +``` +(3 * 10 + 5 * 9 + 9 * 8 + 8 * 7 + 2 * 6 + 1 * 5 + 5 * 4 + 0 * 3 + 8 * 2 + 8 * 1) mod 11 == 0 +``` + +Since the result is 0, this proves that our ISBN is valid. + +## Task + +Given a string the program should check if the provided string is a valid ISBN-10. +Putting this into place requires some thinking about preprocessing/parsing of the string prior to calculating the check digit for the ISBN. + +The program should be able to verify ISBN-10 both with and without separating dashes. + + +## Caveats + +Converting from strings to numbers can be tricky in certain languages. +Now, it's even trickier since the check digit of an ISBN-10 may be 'X' (representing '10'). For instance `3-598-21507-X` is a valid ISBN-10. + +## Bonus tasks + +* Generate a valid ISBN-13 from the input ISBN-10 (and maybe verify it again with a derived verifier). + +* Generate valid ISBN, maybe even from a given starting ISBN. +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine isbn-verifier.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Converting a string into a number and some basic processing utilizing a relatable real world example. [https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation](https://en.wikipedia.org/wiki/International_Standard_Book_Number#ISBN-10_check_digit_calculation) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/isbn-verifier/example.js b/exercises/isbn-verifier/example.js new file mode 100644 index 00000000..90ba4d31 --- /dev/null +++ b/exercises/isbn-verifier/example.js @@ -0,0 +1,24 @@ +'use strict'; + +function ISBN(isbn) { + this.isbn = isbn.replace(/-/g, ''); + + this.isValid = function () { + if (!this.isbn.match(/^(\d{9}[\dX])$/)) { + return false; + } + + var digits = this.isbn.split(''); + if (digits[9] === 'X') { + digits[9] = 10; + } + + var sum = digits.reduce(function (total, current, index) { + return total + ((10 - index) * parseInt(current, 10)); + }, 0); + + return sum % 11 === 0; + }; +} + +module.exports = ISBN; diff --git a/exercises/isbn-verifier/isbn-verifier.spec.js b/exercises/isbn-verifier/isbn-verifier.spec.js new file mode 100644 index 00000000..c6c4ff91 --- /dev/null +++ b/exercises/isbn-verifier/isbn-verifier.spec.js @@ -0,0 +1,68 @@ +var ISBN = require('./isbn-verifier'); + +describe('ISBN', function () { + it('valid isbn number', function () { + var isbn = new ISBN('3-598-21508-8'); + expect(isbn.isValid()).toBe(true); + }); + + it('invalid isbn check digit', function () { + var isbn = new ISBN('3-598-21508-9'); + expect(isbn.isValid()).toBe(false); + }); + + it('valid isbn number with a check digit of 10', function () { + var isbn = new ISBN('3-598-21507-X'); + expect(isbn.isValid()).toBe(true); + }); + + it('check digit is a character other than X', function () { + var isbn = new ISBN('3-598-21507-A'); + expect(isbn.isValid()).toBe(false); + }); + + it('invalid character in isbn', function () { + var isbn = new ISBN('3-598-2K507-0'); + expect(isbn.isValid()).toBe(false); + }); + + it('X is only valid as a check digit', function () { + var isbn = new ISBN('3-598-2X507-0'); + expect(isbn.isValid()).toBe(false); + }); + + it('valid isbn without separating dashes', function () { + var isbn = new ISBN('3598215088'); + expect(isbn.isValid()).toBe(true); + }); + + it('isbn without separating dashes and X as check digit', function () { + var isbn = new ISBN('359821507X'); + expect(isbn.isValid()).toBe(true); + }); + + it('isbn without check digit and dashes', function () { + var isbn = new ISBN('359821507'); + expect(isbn.isValid()).toBe(false); + }); + + it('too long isbn and no dashes', function () { + var isbn = new ISBN('3598215078X'); + expect(isbn.isValid()).toBe(false); + }); + + it('isbn without check digit', function () { + var isbn = new ISBN('3-598-21507'); + expect(isbn.isValid()).toBe(false); + }); + + it('too long isbn', function () { + var isbn = new ISBN('3-598-21507-XA'); + expect(isbn.isValid()).toBe(false); + }); + + it('check digit of X should not be used for 0', function () { + var isbn = new ISBN('3-598-21515-X'); + expect(isbn.isValid()).toBe(false); + }); +}); diff --git a/exercises/isogram/README.md b/exercises/isogram/README.md index 369373af..0b5ef9eb 100644 --- a/exercises/isogram/README.md +++ b/exercises/isogram/README.md @@ -2,38 +2,42 @@ Determine if a word or phrase is an isogram. -An isogram (also known as a "nonpattern word") is a word or phrase without a repeating letter. +An isogram (also known as a "nonpattern word") is a word or phrase without a repeating letter, however spaces and hyphens are allowed to appear multiple times. Examples of isograms: - lumberjacks - background - downstream +- six-year-old The word *isograms*, however, is not an isogram, because the s repeats. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine isogram.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/isogram/example.js b/exercises/isogram/example.js index 531a9248..1c2f911e 100644 --- a/exercises/isogram/example.js +++ b/exercises/isogram/example.js @@ -7,5 +7,5 @@ module.exports = function (word) { }); return unique.length === this.word.length; - } -} + }; +}; diff --git a/exercises/isogram/isogram.spec.js b/exercises/isogram/isogram.spec.js index f5f28b73..f4851551 100644 --- a/exercises/isogram/isogram.spec.js +++ b/exercises/isogram/isogram.spec.js @@ -60,11 +60,10 @@ describe('Isogram Test Suite', function () { expect(word.isIsogram()).toEqual(false); }); - + xit('Àcrobàt', function () { var word = new Isogram('Àcrobàt'); expect(word.isIsogram()).toEqual(false); }); - }); diff --git a/exercises/kindergarten-garden/README.md b/exercises/kindergarten-garden/README.md index 15e4187d..515ef3af 100644 --- a/exercises/kindergarten-garden/README.md +++ b/exercises/kindergarten-garden/README.md @@ -3,19 +3,19 @@ Given a diagram, determine which plants each child in the kindergarten class is responsible for. -The kindergarten class is learning about growing plants. The teachers +The kindergarten class is learning about growing plants. The teacher thought it would be a good idea to give them actual seeds, plant them in actual dirt, and grow actual plants. They've chosen to grow grass, clover, radishes, and violets. -To this end, they've put little styrofoam cups along the window sills, -and planted one type of plant in each cup, choosing randomly from the -available types of seeds. +To this end, the children have put little cups along the window sills, and +planted one type of plant in each cup, choosing randomly from the available +types of seeds. -```plain +```text [window][window][window] -........................ # each dot represents a styrofoam cup +........................ # each dot represents a cup ........................ ``` @@ -25,27 +25,27 @@ There are 12 children in the class: - Eve, Fred, Ginny, Harriet, - Ileana, Joseph, Kincaid, and Larry. -Each child gets 4 cups, two on each row. The children are assigned to -cups in alphabetical order. +Each child gets 4 cups, two on each row. Their teacher assigns cups to +the children alphabetically by their names. The following diagram represents Alice's plants: -```plain +```text [window][window][window] VR...................... RG...................... ``` -So in the row nearest the window, she has a violet and a radish; in the -row behind that, she has a radish and some grass. +In the first row, nearest the windows, she has a violet and a radish. In the +second row she has a radish and some grass. Your program will be given the plants from left-to-right starting with the row nearest the windows. From this, it should be able to determine -which plants belong to which students. +which plants belong to each student. For example, if it's told that the garden looks like so: -```plain +```text [window][window][window] VRCGVVRVCGGCCGVRGCVCGCGV VRCCCGCRRGVCGCRVVCVGCGCV @@ -61,26 +61,29 @@ While asking for Bob's plants would yield: ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine kindergarten-garden.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/kindergarten-garden/example.js b/exercises/kindergarten-garden/example.js index 1194e1b5..0fc7f6c4 100644 --- a/exercises/kindergarten-garden/example.js +++ b/exercises/kindergarten-garden/example.js @@ -23,13 +23,13 @@ var plants = { }; function getPlants(pots, index) { - var plants = []; - var position = 2*index; - plants.push(pots[0][position]); - plants.push(pots[0][position+1]); - plants.push(pots[1][position]); - plants.push(pots[1][position+1]); - return plants; + var plantsArr = []; + var position = 2 * index; + plantsArr.push(pots[0][position]); + plantsArr.push(pots[0][position + 1]); + plantsArr.push(pots[1][position]); + plantsArr.push(pots[1][position + 1]); + return plantsArr; } function parse(diagram) { @@ -42,10 +42,10 @@ function parse(diagram) { function Garden(diagram, students) { var instance = {}; - students = students || defaultChildren; - students.sort(); - - students.forEach(function (student, index) { + var kids = students || defaultChildren; + kids.sort(); + + kids.forEach(function (student, index) { instance[student.toLowerCase()] = getPlants(parse(diagram), index); }); diff --git a/exercises/kindergarten-garden/kindergarten-garden.spec.js b/exercises/kindergarten-garden/kindergarten-garden.spec.js index dcc9c7cf..4e978ae6 100644 --- a/exercises/kindergarten-garden/kindergarten-garden.spec.js +++ b/exercises/kindergarten-garden/kindergarten-garden.spec.js @@ -1,7 +1,6 @@ var Garden = require('./kindergarten-garden'); describe('Garden', function () { - it('for Alice', function () { expect(new Garden('RC\nGG').alice) .toEqual(['radishes', 'clover', 'grass', 'grass']); @@ -22,7 +21,6 @@ describe('Garden', function () { expect(garden.bob).toEqual(['clover', 'clover', 'clover', 'clover']); expect(garden.charlie).toEqual(['grass', 'grass', 'grass', 'grass']); }); - }); describe('Full garden', function () { @@ -88,7 +86,6 @@ describe('Full garden', function () { expect(garden.larry) .toEqual(['grass', 'violets', 'clover', 'violets']); }); - }); describe('Disordered class', function () { @@ -115,7 +112,6 @@ describe('Disordered class', function () { expect(garden.xander) .toEqual(['radishes', 'grass', 'clover', 'violets']); }); - }); describe('Two gardens, different students', function () { @@ -133,5 +129,4 @@ describe('Two gardens, different students', function () { expect(garden2.charlie) .toEqual(['radishes', 'radishes', 'grass', 'clover']); }); - }); diff --git a/exercises/largest-series-product/README.md b/exercises/largest-series-product/README.md index 1d56a017..80ef954b 100644 --- a/exercises/largest-series-product/README.md +++ b/exercises/largest-series-product/README.md @@ -15,26 +15,29 @@ the largest product for a series of 6 digits is 23520. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine largest-series-product.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/largest-series-product/example.js b/exercises/largest-series-product/example.js index 1fb9a41f..fa5e5272 100644 --- a/exercises/largest-series-product/example.js +++ b/exercises/largest-series-product/example.js @@ -1,7 +1,7 @@ 'use strict'; function Series(numberString) { - if(numberString.match('[^0-9]')) throw new Error('Invalid input.'); + if (numberString.match('[^0-9]')) throw new Error('Invalid input.'); this.numberString = numberString; this.digits = this.getDigits(); } @@ -14,10 +14,11 @@ Series.prototype.getDigits = function () { Series.prototype.largestProduct = function (size) { if (size < 0) throw new Error('Invalid input.'); - var product, max = 0; + var product; + var max = 0; this.slices(size).forEach(function (slice) { - product = slice.reduce(function(a, b) { - return a*b; + product = slice.reduce(function (a, b) { + return a * b; }, 1); if (product > max) { max = product; } }); @@ -34,7 +35,7 @@ Series.prototype.slices = function (sliceSize) { for (var i = 0; i < this.digits.length - sliceSize + 1; i++) { for (var j = 0; j < sliceSize; j++) { - slice.push(this.digits[i+j]); + slice.push(this.digits[i + j]); } result.push(slice); slice = []; diff --git a/exercises/largest-series-product/largest-series-product.spec.js b/exercises/largest-series-product/largest-series-product.spec.js index 8c7e181c..130fa5c9 100644 --- a/exercises/largest-series-product/largest-series-product.spec.js +++ b/exercises/largest-series-product/largest-series-product.spec.js @@ -1,7 +1,6 @@ var Series = require('./largest-series-product'); describe('Series', function () { - it('can get the largest product of 2', function () { expect(new Series('0123456789').largestProduct(2)).toBe(72); }); @@ -37,13 +36,13 @@ describe('Series', function () { xit('rejects invalid character in input', ()=> { expect(function () { - new Series('1234a5').largestProduct('2') + new Series('1234a5').largestProduct('2'); }).toThrow(new Error('Invalid input.')); }); xit('rejects negative span', function () { expect(() => { - new Series('12345').largestProduct(-1) + new Series('12345').largestProduct(-1); }).toThrow(new Error('Invalid input.')); }); @@ -66,5 +65,4 @@ describe('Series', function () { new Series('').largestProduct(1); }).toThrow(new Error('Slice size is too big.')); }); - }); diff --git a/exercises/leap/README.md b/exercises/leap/README.md index 8f87cfcb..1797b780 100644 --- a/exercises/leap/README.md +++ b/exercises/leap/README.md @@ -4,7 +4,7 @@ Given a year, report if it is a leap year. The tricky thing here is that a leap year in the Gregorian calendar occurs: -```plain +```text on every year that is evenly divisible by 4 except every year that is evenly divisible by 100 unless the year is also evenly divisible by 400 @@ -28,26 +28,29 @@ phenomenon, go watch [this youtube video][video]. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine leap.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/leap/example.js b/exercises/leap/example.js index ad2eba7f..653dbe45 100644 --- a/exercises/leap/example.js +++ b/exercises/leap/example.js @@ -3,9 +3,11 @@ /** * Represents a year to check whether is leap or not * - * @param {number} year + * @param {number} year + * * Numeric year. */ + function Year(year) { this.year = year; } @@ -13,12 +15,14 @@ function Year(year) { /** * Whether given year is a leap year. * - * @return {boolean} + * @returns {boolean} + * * Whether given year is a leap year. */ + Year.prototype.isLeap = function () { - return (this.year % 400 == 0) || ((this.year % 4 == 0) && (this.year % 100 != 0)); -} + return (this.year % 400 === 0) || ((this.year % 4 === 0) && (this.year % 100 !== 0)); +}; module.exports = Year; diff --git a/exercises/leap/leap.js b/exercises/leap/leap.js index e3795c57..5329bf2d 100644 --- a/exercises/leap/leap.js +++ b/exercises/leap/leap.js @@ -3,13 +3,13 @@ // convenience to get you started writing code faster. // -var Year = function(input) { +var Year = function () { // // YOUR CODE GOES HERE -// +// }; -Year.prototype.isLeap = function() { +Year.prototype.isLeap = function () { // // YOUR CODE GOES HERE // diff --git a/exercises/leap/leap.spec.js b/exercises/leap/leap.spec.js index 604d1f61..852801a4 100644 --- a/exercises/leap/leap.spec.js +++ b/exercises/leap/leap.spec.js @@ -1,30 +1,28 @@ var Year = require('./leap'); -describe('Leap year', function() { - - it('is not very common', function() { +describe('Leap year', function () { + it('is not very common', function () { var year = new Year(2015); expect(year.isLeap()).toBe(false); }); - xit('is introduced every 4 years to adjust about a day', function() { + xit('is introduced every 4 years to adjust about a day', function () { var year = new Year(2016); expect(year.isLeap()).toBe(true); }); - xit('is skipped every 100 years to remove an extra day', function() { + xit('is skipped every 100 years to remove an extra day', function () { var year = new Year(1900); expect(year.isLeap()).toBe(false); }); - xit('is reintroduced every 400 years to adjust another day', function() { + xit('is reintroduced every 400 years to adjust another day', function () { var year = new Year(2000); expect(year.isLeap()).toBe(true); }); // Feel free to enable the following tests to check some more examples xdescribe('Additional example of a leap year that', function () { - it('is not a leap year', function () { var year = new Year(1978); expect(year.isLeap()).toBe(false); @@ -44,7 +42,5 @@ describe('Leap year', function() { var year = new Year(2400); expect(year.isLeap()).toBe(true); }); - }); - }); diff --git a/exercises/linked-list/README.md b/exercises/linked-list/README.md index d719f252..e7b5e704 100644 --- a/exercises/linked-list/README.md +++ b/exercises/linked-list/README.md @@ -2,18 +2,18 @@ Implement a doubly linked list. -Like an array, a linked list is a simple linear data structure. Several -common data types can be implemented using linked lists, like queues, +Like an array, a linked list is a simple linear data structure. Several +common data types can be implemented using linked lists, like queues, stacks, and associative arrays. -A linked list is a collection of data elements called *nodes*. In a -*singly linked list* each node holds a value and a link to the next node. -In a *doubly linked list* each node also holds a link to the previous +A linked list is a collection of data elements called *nodes*. In a +*singly linked list* each node holds a value and a link to the next node. +In a *doubly linked list* each node also holds a link to the previous node. -You will write an implementation of a doubly linked list. Implement a -Node to hold a value and pointers to the next and previous nodes. Then -implement a List which holds references to the first and last node and +You will write an implementation of a doubly linked list. Implement a +Node to hold a value and pointers to the next and previous nodes. Then +implement a List which holds references to the first and last node and offers an array-like interface for adding and removing items: * `push` (*insert value at back*); @@ -21,34 +21,37 @@ offers an array-like interface for adding and removing items: * `shift` (*remove value at front*). * `unshift` (*insert value at front*); -To keep your implementation simple, the tests will not cover error -conditions. Specifically: `pop` or `shift` will never be called on an +To keep your implementation simple, the tests will not cover error +conditions. Specifically: `pop` or `shift` will never be called on an empty list. If you want to know more about linked lists, check [Wikipedia](https://en.wikipedia.org/wiki/Linked_list). ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine linked-list.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/linked-list/example.js b/exercises/linked-list/example.js index 627df0c7..672dff0c 100644 --- a/exercises/linked-list/example.js +++ b/exercises/linked-list/example.js @@ -10,7 +10,7 @@ function LinkedList() { this._front = null; } -LinkedList.prototype.push = function LinkedList_push(value) { +LinkedList.prototype.push = function (value) { if (this._front === null) { this._front = new Node(value); } else { @@ -21,18 +21,18 @@ LinkedList.prototype.push = function LinkedList_push(value) { } }; -LinkedList.prototype.unshift = function LinkedList_unshift(value) { +LinkedList.prototype.unshift = function (value) { this.push(value); this._front = this._front.prev; }; -LinkedList.prototype.pop = function LinkedList_pop() { - if (this._front === null) {return undefined;}; +LinkedList.prototype.pop = function () { + if (this._front === null) {return null;} this._front = this._front.prev; return this.shift(); }; -LinkedList.prototype.shift = function LinkedList_shift() { +LinkedList.prototype.shift = function () { var value = this._front.value; var front = this._front.next; var back = this._front.prev; @@ -46,25 +46,24 @@ LinkedList.prototype.shift = function LinkedList_shift() { return value; }; -LinkedList.prototype.count = function() { +LinkedList.prototype.count = function () { if (this._front === null) { return 0; } else if (this._front.next === this._front) { return 1; - } else { - this._front.next = this._front.next.next; - return this.count() + 1; } + this._front.next = this._front.next.next; + return this.count() + 1; }; -LinkedList.prototype.delete = function(match) { +LinkedList.prototype.delete = function (match) { if (this._front.next === this._front && this._front.value === match) { this._front = null; } else if (this._front.next.value === match) { this._front.next = this._front.next.next; } else { this._front = this._front.next; - return this.delete(match); + this.delete(match); } }; diff --git a/exercises/linked-list/linked-list.spec.js b/exercises/linked-list/linked-list.spec.js index a7322c73..2ce5d68d 100644 --- a/exercises/linked-list/linked-list.spec.js +++ b/exercises/linked-list/linked-list.spec.js @@ -60,7 +60,7 @@ describe('LinkedList', function () { expect(list.pop()).toBe(30); expect(list.shift()).toBe(10); }); - xit('deletes the only element', function() { + xit('deletes the only element', function () { var list = new LinkedList(); list.push(10); list.delete(10); diff --git a/exercises/list-ops/README.md b/exercises/list-ops/README.md index cfbf36e6..44da25f4 100644 --- a/exercises/list-ops/README.md +++ b/exercises/list-ops/README.md @@ -8,27 +8,29 @@ without using existing functions. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js - -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +```sh +jasmine list-ops.spec.js +``` +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Submitting Incomplete Solutions It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/list-ops/example.js b/exercises/list-ops/example.js index a1d2788a..f47d84b9 100644 --- a/exercises/list-ops/example.js +++ b/exercises/list-ops/example.js @@ -21,7 +21,7 @@ List.prototype = { cons: function (item, arr) { var x = new List([item]); - var xs = new List(arr) + var xs = new List(arr); return x.append(xs).values; }, @@ -56,10 +56,10 @@ List.prototype = { return new List(this.foldl(this.cons, [])); }, - map: function (func, arr) { + map: function (func) { var applyFuncThenCons = function (x, acc) { return this.cons(func(x), acc); - } + }; return new List(this.foldr(applyFuncThenCons.bind(this), [])); }, @@ -71,6 +71,6 @@ List.prototype = { return new List(this.foldr(consIfPred.bind(this), [])); } -} +}; module.exports = List; diff --git a/exercises/list-ops/list-ops.spec.js b/exercises/list-ops/list-ops.spec.js index 19ce09a2..7da15220 100644 --- a/exercises/list-ops/list-ops.spec.js +++ b/exercises/list-ops/list-ops.spec.js @@ -4,7 +4,7 @@ describe('List', function () { // predicates to filter by & functions to map var isOdd = function (x) { return x % 2 === 1; - } + }; var plusOne = function (x) { return x + 1; diff --git a/exercises/luhn/README.md b/exercises/luhn/README.md index 217faccc..e11e1bf3 100644 --- a/exercises/luhn/README.md +++ b/exercises/luhn/README.md @@ -18,27 +18,27 @@ are disallowed. ## Example 1: valid credit card number -``` +```text 4539 1488 0343 6467 ``` The first step of the Luhn algorithm is to double every second digit, starting from the right. We will be doubling -``` +```text 4_3_ 1_8_ 0_4_ 6_6_ ``` If doubling the number results in a number greater than 9 then subtract 9 from the product. The results of our doubling: -``` +```text 8569 2478 0383 3437 ``` Then sum all of the digits: -``` +```text 8+5+6+9+2+4+7+8+0+3+8+3+3+4+3+7 = 80 ``` @@ -46,19 +46,19 @@ If the sum is evenly divisible by 10, then the number is valid. This number is v ## Example 2: invalid credit card number -``` +```text 8273 1232 7352 0569 ``` Double the second digits, starting from the right -``` +```text 7253 2262 5312 0539 ``` Sum the digits -``` +```text 7+2+5+3+2+2+6+2+5+3+1+2+0+5+3+9 = 57 ``` @@ -66,26 +66,29 @@ Sum the digits ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine luhn.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/luhn/example.js b/exercises/luhn/example.js index b311427f..cc38e98f 100644 --- a/exercises/luhn/example.js +++ b/exercises/luhn/example.js @@ -1,8 +1,8 @@ 'use strict'; function isValid(number) { - number = number.replace(/\s/g, ''); - const digits = [...number]; + var numbers = number.replace(/\s/g, ''); + const digits = [...numbers]; const sum = digits // convert to integers diff --git a/exercises/luhn/luhn.spec.js b/exercises/luhn/luhn.spec.js index e6e4b8ef..058cd00a 100644 --- a/exercises/luhn/luhn.spec.js +++ b/exercises/luhn/luhn.spec.js @@ -1,7 +1,6 @@ var Luhn = require('./luhn'); -describe('Luhn',function() { - +describe('Luhn', function () { it('single digit strings can not be valid', function () { const luhn = new Luhn('1'); expect(luhn.valid).toEqual(false); @@ -31,5 +30,4 @@ describe('Luhn',function() { const luhn = new Luhn('046a 454 286'); expect(luhn.valid).toEqual(false); }); - }); diff --git a/exercises/matrix/README.md b/exercises/matrix/README.md index 3b427e26..dd2504ef 100644 --- a/exercises/matrix/README.md +++ b/exercises/matrix/README.md @@ -5,13 +5,15 @@ that matrix. So given a string with embedded newlines like: -> 9 8 7 -> 5 3 2 -> 6 6 7 +```text +9 8 7 +5 3 2 +6 6 7 +``` representing this matrix: -```plain +```text 0 1 2 |--------- 0 | 9 8 7 @@ -40,26 +42,29 @@ And its columns: ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine matrix.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/matrix/example.js b/exercises/matrix/example.js index bfeb6996..544bb026 100644 --- a/exercises/matrix/example.js +++ b/exercises/matrix/example.js @@ -24,4 +24,4 @@ function Matrix(description) { this.columns = columnsFromRows(this.rows); } -module.exports = Matrix; \ No newline at end of file +module.exports = Matrix; diff --git a/exercises/matrix/matrix.spec.js b/exercises/matrix/matrix.spec.js index 4c17bdf2..815f870c 100644 --- a/exercises/matrix/matrix.spec.js +++ b/exercises/matrix/matrix.spec.js @@ -1,7 +1,6 @@ var Matrix = require('./matrix'); describe('Matrix', function () { - it('can extract a row', function () { expect(new Matrix('1 2\n10 20').rows[0]).toEqual([1, 2]); }); @@ -14,5 +13,4 @@ describe('Matrix', function () { expect(new Matrix('89 1903 3\n18 3 1\n9 4 800').columns[1]) .toEqual([1903, 3, 4]); }); - -}); \ No newline at end of file +}); diff --git a/exercises/meetup/README.md b/exercises/meetup/README.md index fb20f112..95f902ee 100644 --- a/exercises/meetup/README.md +++ b/exercises/meetup/README.md @@ -2,49 +2,55 @@ Calculate the date of meetups. -Typically meetups happen on the same day of the week. In this exercise, you will take -a description of a meetup date, and return the actual meetup date. +Typically meetups happen on the same day of the week. In this exercise, you +will take a description of a meetup date, and return the actual meetup date. Examples of general descriptions are: -- the first Monday of January 2017 -- the third Tuesday of January 2017 -- the Wednesteenth of January 2017 -- the last Thursday of January 2017 +- The first Monday of January 2017 +- The third Tuesday of January 2017 +- The wednesteenth of January 2017 +- The last Thursday of January 2017 -Note that "Monteenth", "Tuesteenth", etc are all made up words. There -was a meetup whose members realized that there are exactly 7 numbered days in a month that -end in '-teenth'. Therefore, one is guaranteed that each day of the week +The descriptors you are expected to parse are: +first, second, third, fourth, fifth, last, monteenth, tuesteenth, wednesteenth, +thursteenth, friteenth, saturteenth, sunteenth + +Note that "monteenth", "tuesteenth", etc are all made up words. There was a +meetup whose members realized that there are exactly 7 numbered days in a month +that end in '-teenth'. Therefore, one is guaranteed that each day of the week (Monday, Tuesday, ...) will have exactly one date that is named with '-teenth' in every month. -Given examples of a meetup dates, each containing a month, day, year, and descriptor -(first, second, teenth, etc), calculate the date of the actual meetup. -For example, if given "First Monday of January 2017", the correct meetup date is 2017/1/2 - +Given examples of a meetup dates, each containing a month, day, year, and +descriptor calculate the date of the actual meetup. For example, if given +"The first Monday of January 2017", the correct meetup date is 2017/1/2. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine meetup.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/meetup/example.js b/exercises/meetup/example.js index 9e76cf3a..2024d218 100644 --- a/exercises/meetup/example.js +++ b/exercises/meetup/example.js @@ -1,45 +1,40 @@ +'use strict'; + function MeetupDayException(message) { this.message = message; this.name = 'MeetupDayException'; } -function meetupDay (year, month, day_of_week, which) { - 'use strict'; - - var candidates = _getCandidates(year, month, day_of_week), - d, - i, - res; - which = which.toLowerCase(); +function meetupDay(year, month, dayOfWeek, which) { + var candidates = _getCandidates(year, month, dayOfWeek); + var res; + var day; - if (which === 'teenth') { - res = _find(candidates, function (d) { - return 13 <= d.getDate() && d.getDate() <= 19; - }); - } - else if (which === 'last') { + day = which.toLowerCase(); + if (day === 'teenth') { + res = _find(candidates, function (d) {return d.getDate() >= 13 && d.getDate() <= 19; }); + } else if (day === 'last') { res = candidates.pop(); - } - else { - which = parseInt(which) - 1; - res = candidates.slice(which, which + 1).pop(); + } else { + day = parseInt(day, 10) - 1; + res = candidates.slice(day, day + 1).pop(); } - if (!res) { throw new MeetupDayException('Day not found! ;_;'); } + if (!res) { throw new MeetupDayException('Day not found!'); } return res; } -function _getCandidates (year, month, day_of_week) { - var d, - i, - numDaysInMonth = new Date(year, month + 1, 0).getDate(), - res = []; +function _getCandidates(year, month, dayOfWeek) { + var d; + var i; + var numDaysInMonth = new Date(year, month + 1, 0).getDate(); + var res = []; for (i = 0; i < numDaysInMonth; i++) { d = new Date(year, month, i + 1); - if (d.getDay() === _getDayIndex(day_of_week)) { + if (d.getDay() === _getDayIndex(dayOfWeek)) { res.push(d); } } @@ -47,7 +42,7 @@ function _getCandidates (year, month, day_of_week) { return res; } -function _getDayIndex (day) { +function _getDayIndex(day) { var daysInd = { 'sunday': 0, 'monday': 1, @@ -57,16 +52,16 @@ function _getDayIndex (day) { 'friday': 5, 'saturday': 6 }; - - day = day.toLowerCase(); - - return daysInd[day]; + return daysInd[day.toLowerCase()]; } function _find(ary, callback) { + var foundDay; for (var i = 0; i < ary.length; i++) { - if (callback(ary[i], i, ary)) { return ary[i]; } + if (callback(ary[i], i, ary)) foundDay = ary[i]; } + return foundDay; } -module.exports = meetupDay; \ No newline at end of file +module.exports = meetupDay; + diff --git a/exercises/meetup/meetup.spec.js b/exercises/meetup/meetup.spec.js index f4ad9ee6..aa4b7a5b 100644 --- a/exercises/meetup/meetup.spec.js +++ b/exercises/meetup/meetup.spec.js @@ -1,61 +1,55 @@ var meetupDay = require('./meetup'); - -function MeetupDayException(message) { - this.message = message; - this.name = 'MeetupDayException'; -} - -describe('meetupDay()', function() { - it('monteenth of may 2013', function() { +describe('meetupDay()', function () { + it('monteenth of may 2013', function () { expect(meetupDay(2013, 4, 'Monday', 'teenth')).toEqual(new Date(2013, 4, 13)); }); - xit('saturteenth of february 2013', function() { + xit('saturteenth of february 2013', function () { expect(meetupDay(2013, 1, 'Saturday', 'teenth')).toEqual(new Date(2013, 1, 16)); }); - xit('first tuesday of may 2013', function() { + xit('first tuesday of may 2013', function () { expect(meetupDay(2013, 4, 'Tuesday', '1st')).toEqual(new Date(2013, 4, 7)); }); - xit('second monday of april 2013', function() { + xit('second monday of april 2013', function () { expect(meetupDay(2013, 3, 'Monday', '2nd')).toEqual(new Date(2013, 3, 8)); }); - xit('third thursday of september 2013', function() { + xit('third thursday of september 2013', function () { expect(meetupDay(2013, 8, 'Thursday', '3rd')).toEqual(new Date(2013, 8, 19)); }); - xit('fourth sunday of march 2013', function() { + xit('fourth sunday of march 2013', function () { expect(meetupDay(2013, 2, 'Sunday', '4th')).toEqual(new Date(2013, 2, 24)); }); - xit('last thursday of october 2013', function() { + xit('last thursday of october 2013', function () { expect(meetupDay(2013, 9, 'Thursday', 'last')).toEqual(new Date(2013, 9, 31)); }); - xit('last wednesday of february 2012', function() { + xit('last wednesday of february 2012', function () { expect(meetupDay(2012, 1, 'Wednesday', 'last')).toEqual(new Date(2012, 1, 29)); }); - xit('last wednesday of december 2014', function() { + xit('last wednesday of december 2014', function () { expect(meetupDay(2014, 11, 'Wednesday', 'last')).toEqual(new Date(2014, 11, 31)); }); - xit('last sunday of only four week february 2015', function() { + xit('last sunday of only four week february 2015', function () { expect(meetupDay(2015, 1, 'Sunday', 'last')).toEqual(new Date(2015, 1, 22)); }); - xit('first friday of december 2012', function() { + xit('first friday of december 2012', function () { expect(meetupDay(2012, 11, 'Friday', '1st')).toEqual(new Date(2012, 11, 7)); }); - xit('fifth monday of march 2015', function() { + xit('fifth monday of march 2015', function () { expect(meetupDay(2015, 2, 'Monday', '5th')).toEqual(new Date(2015, 2, 30)); }); - xit('nonexistent fifth monday of february 2015', function() { + xit('nonexistent fifth monday of february 2015', function () { expect(function () { meetupDay(2015, 1, 'Monday', '5th'); }).toThrow(); }); }); diff --git a/exercises/minesweeper/README.md b/exercises/minesweeper/README.md index 6b0e55de..f3890756 100644 --- a/exercises/minesweeper/README.md +++ b/exercises/minesweeper/README.md @@ -28,27 +28,29 @@ into this: ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js - -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +```sh +jasmine minesweeper.spec.js +``` +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Submitting Incomplete Solutions It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/minesweeper/example.js b/exercises/minesweeper/example.js index 7bb5dbd0..a366884e 100644 --- a/exercises/minesweeper/example.js +++ b/exercises/minesweeper/example.js @@ -1,47 +1,47 @@ -var Minesweeper = function() { +var Minesweeper = function () { this.distanceXdistanceYs = [ - [-1,-1], - [-1,0], - [-1,1], + [-1, -1], + [-1, 0], + [-1, 1], - [1,1], - [1,0], - [1,-1], + [1, 1], + [1, 0], + [1, -1], - [0,1], - [0,-1] + [0, 1], + [0, -1] - ] + ]; }; -Minesweeper.prototype.annotate = function(rows) { +Minesweeper.prototype.annotate = function (rows) { if (rows.length === 0 || rows[0].length === 0) { return rows; } - var board = rows.map(function(row) { return row.split(""); }); + var board = rows.map(function (row) { return row.split(''); }); var outBoard = []; - for (var x = 0; x < board.length; x++) { + board.forEach(function (memberX, x) { outBoard[x] = []; - for (var y = 0; y < board[x].length; y++) { - var spot = board[x][y]; - if (spot === "*") { + memberX.forEach(function (memberXY, y) { + var spot = memberXY; + if (spot === '*') { outBoard[x][y] = spot; - continue; + } else { + var bombCount = this.distanceXdistanceYs.map(function (dxdy) { + if (typeof board[x + dxdy[0]] === 'undefined') { + return 0; + } + return board[x + dxdy[0]][y + dxdy[1]] === '*' ? 1 : 0; + }).reduce(function (total, num) { + return total + num; + }); + outBoard[x][y] = bombCount > 0 ? bombCount : ' '; } - var bombCount = this.distanceXdistanceYs.map(function(dxdy) { - if (board[x + dxdy[0]] === undefined) { - return 0; - } - return board[x + dxdy[0]][y + dxdy[1]] === "*" ? 1 : 0; - }).reduce(function(total, num) { - return total + num; - }); - outBoard[x][y] = bombCount > 0 ? bombCount : " "; - } - } - return outBoard.map(function(row) { - return row.join(""); + }, this); + }, this); + return outBoard.map(function (row) { + return row.join(''); }); }; diff --git a/exercises/minesweeper/minesweeper.spec.js b/exercises/minesweeper/minesweeper.spec.js index 75ffe741..836ccae1 100644 --- a/exercises/minesweeper/minesweeper.spec.js +++ b/exercises/minesweeper/minesweeper.spec.js @@ -1,182 +1,180 @@ var Minesweeper = require('./minesweeper'); -describe('Minesweeper()', function() { - - it('handles no rows', function() { +describe('Minesweeper()', function () { + it('handles no rows', function () { var minesweeper = new Minesweeper(); expect(minesweeper.annotate([])).toEqual([]); }); - xit('handles no columns', function() { + xit('handles no columns', function () { var minesweeper = new Minesweeper(); - expect(minesweeper.annotate([""])).toEqual([""]); + expect(minesweeper.annotate([''])).toEqual(['']); }); - xit('handles no mines', function() { + xit('handles no mines', function () { var minesweeper = new Minesweeper(); var input = [ - " ", - " ", - " " + ' ', + ' ', + ' ' ]; var expected = [ - " ", - " ", - " " - ]; + ' ', + ' ', + ' ' + ]; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles board with only mines', function() { + xit('handles board with only mines', function () { var minesweeper = new Minesweeper(); var input = [ - "***", - "***", - "***" + '***', + '***', + '***' ]; var expected = [ - "***", - "***", - "***" + '***', + '***', + '***' ]; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles mine surrounded by spaces', function() { + xit('handles mine surrounded by spaces', function () { var minesweeper = new Minesweeper(); var input = [ - " ", - " * ", - " " + ' ', + ' * ', + ' ' ]; var expected = [ - "111", - "1*1", - "111" - ]; + '111', + '1*1', + '111' + ]; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles space surrounded by mines', function() { + xit('handles space surrounded by mines', function () { var minesweeper = new Minesweeper(); var input = [ - "***", - "* *", - "***" - ]; + '***', + '* *', + '***' + ]; var expected = [ - "***", - "*8*", - "***" - ]; + '***', + '*8*', + '***' + ]; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles space surrounded by mines', function() { + xit('handles space surrounded by mines', function () { var minesweeper = new Minesweeper(); var input = [ - "***", - "* *", - "***" - ]; + '***', + '* *', + '***' + ]; var expected = [ - "***", - "*8*", - "***" - ]; + '***', + '*8*', + '***' + ]; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles horizontal line', function() { + xit('handles horizontal line', function () { var minesweeper = new Minesweeper(); - var input = [" * * "]; - var expected = ["1*2*1"]; + var input = [' * * ']; + var expected = ['1*2*1']; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles horizontal line, mines at edges',function() { + xit('handles horizontal line, mines at edges', function () { var minesweeper = new Minesweeper(); - var input = ["* *"]; - var expected = ["*1 1*"]; + var input = ['* *']; + var expected = ['*1 1*']; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles vertical line', function() { + xit('handles vertical line', function () { var minesweeper = new Minesweeper(); var input = [ - " ", - "*", - " ", - "*", - " " - ]; + ' ', + '*', + ' ', + '*', + ' ' + ]; var expected = [ - "1", - "*", - "2", - "*", - "1" - ]; + '1', + '*', + '2', + '*', + '1' + ]; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles vertical line, mines at edges', function() { + xit('handles vertical line, mines at edges', function () { var minesweeper = new Minesweeper(); var input = [ - "*", - " ", - " ", - " ", - "*" - ]; + '*', + ' ', + ' ', + ' ', + '*' + ]; var expected = [ - "*", - "1", - " ", - "1", - "*" - ]; + '*', + '1', + ' ', + '1', + '*' + ]; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles cross', function() { + xit('handles cross', function () { var minesweeper = new Minesweeper(); var input = [ - " * ", - " * ", - "*****", - " * ", - " * " + ' * ', + ' * ', + '*****', + ' * ', + ' * ' ]; var expected = [ - " 2*2 ", - "25*52", - "*****", - "25*52", - " 2*2 " - ]; + ' 2*2 ', + '25*52', + '*****', + '25*52', + ' 2*2 ' + ]; expect(minesweeper.annotate(input)).toEqual(expected); }); - xit('handles large board', function() { + xit('handles large board', function () { var minesweeper = new Minesweeper(); var input = [ - " * * ", - " * ", - " * ", - " * *", - " * * ", - " " + ' * * ', + ' * ', + ' * ', + ' * *', + ' * * ', + ' ' ]; var expected = [ - "1*22*1", - "12*322", - " 123*2", - "112*4*", - "1*22*2", - "111111" - ]; + '1*22*1', + '12*322', + ' 123*2', + '112*4*', + '1*22*2', + '111111' + ]; expect(minesweeper.annotate(input)).toEqual(expected); - }); - + }); }); diff --git a/exercises/nth-prime/README.md b/exercises/nth-prime/README.md index 84bae01d..621e625a 100644 --- a/exercises/nth-prime/README.md +++ b/exercises/nth-prime/README.md @@ -10,26 +10,29 @@ numbers, pretend they don't exist and implement them yourself. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine nth-prime.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/nth-prime/example.js b/exercises/nth-prime/example.js index eff9a61b..5deed40c 100644 --- a/exercises/nth-prime/example.js +++ b/exercises/nth-prime/example.js @@ -1,18 +1,23 @@ 'use strict'; module.exports = { - nth: function(nthPrime) { + nth: function (nthPrime) { if (nthPrime === 0) { throw new Error('Prime is not possible'); } - this.generatePrimes(200000); + + // Using prime number theory to approximate the prime + // See https://en.wikipedia.org/wiki/Prime_number_theorem#Approximations_for_the_nth_prime_number + var upperBound = (nthPrime + 2) * Math.log((nthPrime + 2) * Math.log((nthPrime + 2))); + this.generatePrimes(upperBound); return this.realPrimes[nthPrime - 1]; }, - generatePrimes: function(uptoNumber) { - var i, j, currentPrime, primeCount, possiblePrimes = []; - - if (this.realPrimes) { return this.realPrimes; } + generatePrimes: function (uptoNumber) { + var i; + var j; + var currentPrime; + var possiblePrimes = []; for (i = 2; i <= uptoNumber; i++) { - possiblePrimes.push({ number: i, prime: true}); + possiblePrimes.push({ number: i, prime: true }); } for (i = 2; i < Math.sqrt(possiblePrimes.length); i++) { @@ -24,8 +29,6 @@ module.exports = { } } - primeCount = 0; - this.realPrimes = []; for (i = 0; i < possiblePrimes.length; i++) { @@ -34,6 +37,7 @@ module.exports = { this.realPrimes.push(currentPrime.number); } } + return this.realPrimes; } }; diff --git a/exercises/nth-prime/nth-prime.spec.js b/exercises/nth-prime/nth-prime.spec.js index 840d5b85..70a326d8 100644 --- a/exercises/nth-prime/nth-prime.spec.js +++ b/exercises/nth-prime/nth-prime.spec.js @@ -1,27 +1,33 @@ -var prime = require ('./nth-prime'); +var prime = require('./nth-prime'); -describe('Prime',function() { - - it('first',function(){ +describe('Prime', function () { + it('first', function () { expect(prime.nth(1)).toEqual(2); }); - xit('second',function(){ + xit('second', function () { expect(prime.nth(2)).toEqual(3); }); - xit('sixth',function(){ + xit('sixth', function () { expect(prime.nth(6)).toEqual(13); }); - xit('big prime',function(){ + xit('big prime', function () { expect(prime.nth(10001)).toEqual(104743); }); - xit('weird case',function() { + xit('massive prime', function () { + expect(prime.nth(20000)).toEqual(224737); + }); + + xit('extreme prime', function () { + expect(prime.nth(30000)).toEqual(350377); + }); + + xit('weird case', function () { expect( function () { prime.nth(0); }).toThrow(new Error('Prime is not possible')); }); - }); diff --git a/exercises/nucleotide-count/README.md b/exercises/nucleotide-count/README.md index 8f0622dc..607c27c5 100644 --- a/exercises/nucleotide-count/README.md +++ b/exercises/nucleotide-count/README.md @@ -1,53 +1,42 @@ # Nucleotide Count -Given a DNA string, compute how many times each nucleotide occurs in the string. +Given a single stranded DNA string, compute how many times each nucleotide occurs in the string. -DNA is represented by an alphabet of the following symbols: 'A', 'C', -'G', and 'T'. - -Each symbol represents a nucleotide, which is a fancy name for the -particular molecules that happen to make up a large part of DNA. - -Shortest intro to biochemistry EVAR: +The genetic language of every living thing on the planet is DNA. +DNA is a large molecule that is built from an extremely long sequence of individual elements called nucleotides. +4 types exist in DNA and these differ only slightly and can be represented as the following symbols: 'A' for adenine, 'C' for cytosine, 'G' for guanine, and 'T' thymine. +Here is an analogy: - twigs are to birds nests as -- nucleotides are to DNA and RNA as -- amino acids are to proteins as -- sugar is to starch as -- oh crap lipids - -I'm not going to talk about lipids because they're crazy complex. - -So back to nucleotides. - -DNA contains four types of them: adenine (`A`), cytosine (`C`), guanine -(`G`), and thymine (`T`). - -RNA contains a slightly different set of nucleotides, but we don't care -about that for now. +- nucleotides are to DNA as +- legos are to lego houses as +- words are to sentences as... ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine nucleotide-count.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/nucleotide-count/nucleotide-count.spec.js b/exercises/nucleotide-count/nucleotide-count.spec.js index 961d2bda..25c35ff2 100644 --- a/exercises/nucleotide-count/nucleotide-count.spec.js +++ b/exercises/nucleotide-count/nucleotide-count.spec.js @@ -1,44 +1,42 @@ var dna = require('./nucleotide-count'); -describe('DNA', function() { - - it('Empty DNA strand has no adenosine', function() { +describe('DNA', function () { + it('Empty DNA strand has no adenosine', function () { expect(dna().count('A')).toEqual(0); }); - xit('Repetitive cytidine gets counted', function() { + xit('Repetitive cytidine gets counted', function () { expect(dna('CCCCC').count('C')).toEqual(5); }); - xit('Counts only thymidine', function() { + xit('Counts only thymidine', function () { expect(dna('GGGGGTAACCCGG').count('T')).toEqual(1); }); - xit('Counts a nucleotide only once', function() { + xit('Counts a nucleotide only once', function () { var acid = dna('CGATTGGG'); acid.count('T'); acid.count('T'); expect(acid.count('T')).toEqual(2); }); - xit('Empty DNS strand has no nucleotides', function() { + xit('Empty DNA strand has no nucleotides', function () { var expected = {A: 0, T: 0, C: 0, G: 0}; expect(dna().histogram()).toEqual(expected); }); - xit('Repetitive sequence has only guanosine', function() { + xit('Repetitive sequence has only guanosine', function () { var expected = {A: 0, T: 0, C: 0, G: 8}; expect(dna('GGGGGGGG').histogram()).toEqual(expected); }); - xit('Counts all nucleotides', function() { + xit('Counts all nucleotides', function () { var strand = 'AGCTTTTCATTCTGACTGCAACGGGCAATATGTCTCTGTGTGGATTAAAAAAAGAGTGTCTGATAGCAGC'; var expected = {A: 20, T: 21, C: 12, G: 17}; expect(dna(strand).histogram()).toEqual(expected); }); - xit('Validates DNA', function() { + xit('Validates DNA', function () { expect(dna.bind(null, 'JOHNNYAPPLESEED')).toThrow(); }); - }); diff --git a/exercises/ocr-numbers/README.md b/exercises/ocr-numbers/README.md index 0a7e5338..5444b695 100644 --- a/exercises/ocr-numbers/README.md +++ b/exercises/ocr-numbers/README.md @@ -1,4 +1,4 @@ -# Ocr Numbers +# OCR Numbers Given a 3 x 4 grid of pipes, underscores, and spaces, determine which number is represented, or whether it is garbled. @@ -9,7 +9,7 @@ To begin with, convert a simple binary font to a string containing 0 or 1. The binary font uses pipes and underscores, four rows high and three columns wide. -``` +```text _ # | | # zero. |_| # @@ -18,7 +18,7 @@ The binary font uses pipes and underscores, four rows high and three columns wid Is converted to "0" -``` +```text # | # one. | # @@ -39,7 +39,7 @@ Update your program to recognize multi-character binary strings, replacing garbl Update your program to recognize all numbers 0 through 9, both individually and as part of a larger string. -``` +```text _ _| |_ @@ -48,7 +48,7 @@ Update your program to recognize all numbers 0 through 9, both individually and Is converted to "2" -``` +```text _ _ _ _ _ _ _ _ # | _| _||_||_ |_ ||_||_|| | # decimal numbers. ||_ _| | _||_| ||_| _||_| # @@ -61,7 +61,7 @@ Is converted to "1234567890" Update your program to handle multiple numbers, one per line. When converting several lines, join the lines with commas. -``` +```text _ _ | _| _| ||_ _| @@ -80,26 +80,29 @@ Is converted to "123,456,789" ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine ocr-numbers.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/ocr-numbers/example.js b/exercises/ocr-numbers/example.js index 2058207d..3da59585 100644 --- a/exercises/ocr-numbers/example.js +++ b/exercises/ocr-numbers/example.js @@ -2,45 +2,45 @@ var PATTERNS = { 0: [' _ ', - '| |', - '|_|', - ' '], + '| |', + '|_|', + ' '], 1: [' ', - ' |', - ' |', - ' '], + ' |', + ' |', + ' '], 2: [' _ ', - ' _|', - '|_ ', - ' '], + ' _|', + '|_ ', + ' '], 3: [' _ ', - ' _|', - ' _|', - ' '], + ' _|', + ' _|', + ' '], 4: [' ', - '|_|', - ' |', - ' '], + '|_|', + ' |', + ' '], 5: [' _ ', - '|_ ', - ' _|', - ' '], + '|_ ', + ' _|', + ' '], 6: [' _ ', - '|_ ', - '|_|', - ' '], + '|_ ', + '|_|', + ' '], 7: [' _ ', - ' |', - ' |', - ' '], + ' |', + ' |', + ' '], 8: [' _ ', - '|_|', - '|_|', - ' '], + '|_|', + '|_|', + ' '], 9: [' _ ', - '|_|', - ' _|', - ' '] + '|_|', + ' _|', + ' '] }; function getDigit(text) { @@ -88,4 +88,4 @@ function valuesInRow(row) { exports.convert = function (text) { var rows = splitIntoRows(text); return rows.map(valuesInRow).join(','); -}; \ No newline at end of file +}; diff --git a/exercises/ocr-numbers/ocr-numbers.spec.js b/exercises/ocr-numbers/ocr-numbers.spec.js index 2acc9458..a59ec428 100644 --- a/exercises/ocr-numbers/ocr-numbers.spec.js +++ b/exercises/ocr-numbers/ocr-numbers.spec.js @@ -1,7 +1,6 @@ var ocr = require('./ocr-numbers'); describe('ocr', function () { - it('recognizes zero', function () { expect(ocr.convert( ' _ \n' + @@ -153,5 +152,4 @@ describe('ocr', function () { ' ' )).toBe('123,456,789'); }); - }); diff --git a/exercises/octal/README.md b/exercises/octal/README.md index a791ac8d..1e906436 100644 --- a/exercises/octal/README.md +++ b/exercises/octal/README.md @@ -8,11 +8,13 @@ Implement octal to decimal conversion. Given an octal input string, your program should produce a decimal output. ## Note + - Implement the conversion yourself. Do not use something else to perform the conversion for you. - Treat invalid input as octal 0. ## About Octal (Base-8) + Decimal is a base-10 system. A number 233 in base 10 notation can be understood @@ -25,7 +27,8 @@ as a linear combination of powers of 10: - All these values are summed. So: -``` + +```text 233 # decimal = 2*10^2 + 3*10^1 + 3*10^0 = 2*100 + 3*10 + 3*1 @@ -34,7 +37,8 @@ So: Octal is similar, but uses powers of 8 rather than powers of 10. So: -``` + +```text 233 # octal = 2*8^2 + 3*8^1 + 3*8^0 = 2*64 + 3*8 + 3*1 @@ -44,26 +48,29 @@ So: ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine octal.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/octal/example.js b/exercises/octal/example.js index 6aec6caa..535d0556 100644 --- a/exercises/octal/example.js +++ b/exercises/octal/example.js @@ -6,18 +6,18 @@ function Octal(octal) { this.digits = octal.split('').reverse().map(this.digitValue); } -Octal.prototype.toDecimal = function() { +Octal.prototype.toDecimal = function () { var decimal = this.digits.reduce(this.accumulator, 0); return isNaN(decimal) ? 0 : decimal; }; -Octal.prototype.digitValue = function(value) { +Octal.prototype.digitValue = function (value) { var result = Number(value); - return (result < BASE)? result : Number.NaN; + return (result < BASE) ? result : Number.NaN; }; -Octal.prototype.accumulator = function(decimal, digit, index) { - return decimal += digit * Math.pow(BASE, index); +Octal.prototype.accumulator = function (decimal, digit, index) { + return decimal + digit * Math.pow(BASE, index); }; module.exports = Octal; diff --git a/exercises/octal/octal.spec.js b/exercises/octal/octal.spec.js index d29f7011..b3ee50e9 100644 --- a/exercises/octal/octal.spec.js +++ b/exercises/octal/octal.spec.js @@ -1,45 +1,43 @@ var Octal = require('./octal'); -describe('octal', function() { - - it('1 is decimal 1', function() { +describe('octal', function () { + it('1 is decimal 1', function () { expect(new Octal('1').toDecimal()).toEqual(1); }); - xit('10 is decimal 8', function() { + xit('10 is decimal 8', function () { expect(new Octal('10').toDecimal()).toEqual(8); }); - xit('17 is decimal 15', function() { + xit('17 is decimal 15', function () { expect(new Octal('17').toDecimal()).toEqual(15); }); - xit('11 is decimal 9', function() { + xit('11 is decimal 9', function () { expect(new Octal('11').toDecimal()).toEqual(9); }); - xit('130 is decimal 88', function() { + xit('130 is decimal 88', function () { expect(new Octal('130').toDecimal()).toEqual(88); }); - xit('2047 is decimal 1063', function() { + xit('2047 is decimal 1063', function () { expect(new Octal('2047').toDecimal()).toEqual(1063); }); - xit('7777 is decimal 4095', function() { + xit('7777 is decimal 4095', function () { expect(new Octal('7777').toDecimal()).toEqual(4095); }); - xit('1234567 is decimal 342391', function() { + xit('1234567 is decimal 342391', function () { expect(new Octal('1234567').toDecimal()).toEqual(342391); }); - xit('invalid is decimal 0', function() { + xit('invalid is decimal 0', function () { expect(new Octal('carrot').toDecimal()).toEqual(0); }); - xit('considers the digit 8 as invalid', function() { + xit('considers the digit 8 as invalid', function () { expect(new Octal('12345678').toDecimal()).toEqual(0); }); - }); diff --git a/exercises/palindrome-products/README.md b/exercises/palindrome-products/README.md index 9d4d6d61..29c8035b 100644 --- a/exercises/palindrome-products/README.md +++ b/exercises/palindrome-products/README.md @@ -5,56 +5,58 @@ Detect palindrome products in a given range. A palindromic number is a number that remains the same when its digits are reversed. For example, `121` is a palindromic number but `112` is not. -Given the definition of a palindromic number, we define a palindrome _product_ -to be the product `c`, such that `a * b = c`, where `c` is a palindromic number and - `a` and `b` are integers (possibly, but _not_ necessarily palindromic numbers). +Given a range of numbers, find the largest and smallest palindromes which +are products of numbers within that range. -For example, the palindromic number 9009 can be written as the palindrome -product: `91 * 99 = 9009`. - -It's possible (and indeed common) for a palindrome product to be the product -of multiple combinations of numbers. For example, the palindrome product `9` has -the factors `(1, 9)`, `(3, 3)`, and `(9, 1)`. - -Write a program that given a range of integers, returns the smallest and largest -palindromic product within that range, along with all of it's factors. +Your solution should return the largest and smallest palindromes, along with the +factors of each within the range. If the largest or smallest palindrome has more +than one pair of factors within the range, then return all the pairs. ## Example 1 Given the range `[1, 9]` (both inclusive)... -The smallest product is `1`. It's factors are `(1, 1)`. -The largest product is `9`. It's factors are `(1, 9)`, `(3, 3)`, and `(9, 1)`. +And given the list of all possible products within this range: +`[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 16, 18, 15, 21, 24, 27, 20, 28, 32, 36, 25, 30, 35, 40, 45, 42, 48, 54, 49, 56, 63, 64, 72, 81]` + +The palindrome products are all single digit numbers (in this case): +`[1, 2, 3, 4, 5, 6, 7, 8, 9]` + +The smallest palindrome product is `1`. Its factors are `(1, 1)`. +The largest palindrome product is `9`. Its factors are `(1, 9)` and `(3, 3)`. ## Example 2 Given the range `[10, 99]` (both inclusive)... -The smallest palindrome product is `121`. It's factors are `(11, 11)`. -The largest palindrome product is `9009`. It's factors are `(91, 99)` and `(99, 91)`. +The smallest palindrome product is `121`. Its factors are `(11, 11)`. +The largest palindrome product is `9009`. Its factors are `(91, 99)`. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine palindrome-products.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/palindrome-products/example.js b/exercises/palindrome-products/example.js index b9fbf4f1..ab242849 100644 --- a/exercises/palindrome-products/example.js +++ b/exercises/palindrome-products/example.js @@ -4,7 +4,7 @@ module.exports = function Palindromes(options) { this.maxFactor = options.maxFactor; this.minFactor = options.minFactor || 1; - this.generate = function() { + this.generate = function () { var minFactor = this.minFactor; var maxFactor = this.maxFactor; @@ -13,18 +13,17 @@ module.exports = function Palindromes(options) { for (var i = minFactor; i <= maxFactor; i++) { for (var j = minFactor; j <= maxFactor; j++) { - var result = i * j; - if ( ! this.isPalindrome(result) ) { continue; } + if (!this.isPalindrome(result)) { continue; } - var newFactor = [i,j].sort(); + var newFactor = [i, j].sort(); - if (palindromes[result] === undefined) { + if (!Array.isArray(palindromes[result])) { palindromes[result] = []; palindromeIndexes.push(result); } - if ( ! arrayContainsArray(palindromes[result],newFactor) ) { + if (!arrayContainsArray(palindromes[result], newFactor)) { palindromes[result].push(newFactor); } } @@ -34,26 +33,26 @@ module.exports = function Palindromes(options) { this.palindromeIndexes = palindromeIndexes; }; - this.largest = function() { - var largestPalindrome = Math.max.apply(null,this.palindromeIndexes); + this.largest = function () { + var largestPalindrome = Math.max.apply(null, this.palindromeIndexes); var factors = this.palindromes[largestPalindrome]; return { value: largestPalindrome, factors: factors }; }; - this.smallest = function() { - var smallestPalindrome = Math.min.apply(null,this.palindromeIndexes); + this.smallest = function () { + var smallestPalindrome = Math.min.apply(null, this.palindromeIndexes); var factors = this.palindromes[smallestPalindrome]; return { value: smallestPalindrome, factors: factors }; }; - this.isPalindrome = function(number) { + this.isPalindrome = function (number) { var numberAsString = number.toString(); var reversedString = numberAsString.split('').reverse().join(''); return (numberAsString === reversedString); }; }; -function arrayContainsArray(array,element) { +function arrayContainsArray(array, element) { var containsArray = false; for (var i = 0; i < array.length; i++) { diff --git a/exercises/palindrome-products/palindrome-products.spec.js b/exercises/palindrome-products/palindrome-products.spec.js index 9f02104b..36936f29 100644 --- a/exercises/palindrome-products/palindrome-products.spec.js +++ b/exercises/palindrome-products/palindrome-products.spec.js @@ -1,21 +1,20 @@ 'use strict'; var Palindromes = require('./palindrome-products'); -describe('Palindrome', function() { - - it('largest palindrome from single digit factors', function() { +describe('Palindrome', function () { + it('largest palindrome from single digit factors', function () { var palindromes = new Palindromes({maxFactor: 9}); palindromes.generate(); var largest = palindromes.largest(); expect(largest.value).toEqual(9); var orderedLargestFactors = largest.factors.sort( - function(a, b) { return a[0] > b[0]; } + function (a, b) { return a[0] > b[0]; } ); expect(orderedLargestFactors).toEqual([[1, 9], [3, 3]]); }); - xit('largest palindrome from double digit factors', function() { + xit('largest palindrome from double digit factors', function () { var palindromes = new Palindromes({ maxFactor: 99, minFactor: 10 }); palindromes.generate(); @@ -24,7 +23,7 @@ describe('Palindrome', function() { expect(largest.factors).toEqual([[91, 99]]); }); - xit('smallest palindrome from double digit factors', function() { + xit('smallest palindrome from double digit factors', function () { var palindromes = new Palindromes({ maxFactor: 99, minFactor: 10 }); palindromes.generate(); @@ -33,7 +32,7 @@ describe('Palindrome', function() { expect(smallest.factors).toEqual([[11, 11]]); }); - xit('largest palindrome from triple digit factors', function() { + xit('largest palindrome from triple digit factors', function () { var palindromes = new Palindromes({ maxFactor: 999, minFactor: 100 }); palindromes.generate(); @@ -42,7 +41,7 @@ describe('Palindrome', function() { expect(largest.factors).toEqual([[913, 993]]); }); - xit('smallest palindrome from triple digit factors', function() { + xit('smallest palindrome from triple digit factors', function () { var palindromes = new Palindromes({ maxFactor: 999, minFactor: 100 }); palindromes.generate(); @@ -50,5 +49,4 @@ describe('Palindrome', function() { expect(smallest.value).toEqual(10201); expect(smallest.factors).toEqual([[101, 101]]); }); - }); diff --git a/exercises/pangram/README.md b/exercises/pangram/README.md index 9fceecd9..d94827f5 100644 --- a/exercises/pangram/README.md +++ b/exercises/pangram/README.md @@ -2,7 +2,7 @@ Determine if a sentence is a pangram. A pangram (Greek: παν γράμμα, pan gramma, "every letter") is a sentence using every letter of the alphabet at least once. -The best known English pangram is: +The best known English pangram is: > The quick brown fox jumps over the lazy dog. The alphabet used consists of ASCII letters `a` to `z`, inclusive, and is case @@ -10,26 +10,29 @@ insensitive. Input will not contain non-ASCII symbols. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine pangram.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/pangram/example.js b/exercises/pangram/example.js index c61cfdb9..86922be7 100644 --- a/exercises/pangram/example.js +++ b/exercises/pangram/example.js @@ -1,9 +1,10 @@ -var notAlpha = /[^a-z]+/gi, - ALPHA_LENGTH = 26, - cleaned, - unique; -var Pangram = function(candidate) { +var Pangram = function (candidate) { + var notAlpha = /[^a-z]+/gi; + var ALPHA_LENGTH = 26; + var cleaned; + var unique; + unique = {}; cleaned = (candidate.replace(notAlpha, '')).toLowerCase(); cleaned.split('').forEach(function (el) { diff --git a/exercises/pangram/pangram.spec.js b/exercises/pangram/pangram.spec.js index d7feee37..b2bae495 100644 --- a/exercises/pangram/pangram.spec.js +++ b/exercises/pangram/pangram.spec.js @@ -1,50 +1,53 @@ var Pangram = require('./pangram'); -describe('Pangram()', function() { - - it('empty sentence', function() { +describe('Pangram()', function () { + it('sentence empty', function () { var pangram = new Pangram(''); expect(pangram.isPangram()).toBe(false); }); - xit('pangram with only lower case', function() { - var pangram = new Pangram("the quick brown fox jumps over the lazy dog"); + xit('recognizes a perfect lower case pangram', function () { + var pangram = new Pangram('abcdefghijklmnopqrstuvwxyz'); + expect(pangram.isPangram()).toBe(true); + }); + + xit('pangram with only lower case', function () { + var pangram = new Pangram('the quick brown fox jumps over the lazy dog'); expect(pangram.isPangram()).toBe(true); }); - xit("missing character 'x'", function() { - var pangram = new Pangram("a quick movement of the enemy will jeopardize five gunboats"); + xit("missing character 'x'", function () { + var pangram = new Pangram('a quick movement of the enemy will jeopardize five gunboats'); expect(pangram.isPangram()).toBe(false); }); - xit("another missing character 'x'", function() { - var pangram = new Pangram("the quick brown fish jumps over the lazy dog"); + xit("another missing character, e.g. 'h'", function () { + var pangram = new Pangram('five boxing wizards jump quickly at it'); expect(pangram.isPangram()).toBe(false); }); - xit("pangram with underscores", function() { - var pangram = new Pangram("the_quick_brown_fox_jumps_over_the_lazy_dog"); + xit('pangram with underscores', function () { + var pangram = new Pangram('the_quick_brown_fox_jumps_over_the_lazy_dog'); expect(pangram.isPangram()).toBe(true); }); - xit("pangram with numbers", function() { - var pangram = new Pangram("the 1 quick brown fox jumps over the 2 lazy dogs"); + xit('pangram with numbers', function () { + var pangram = new Pangram('the 1 quick brown fox jumps over the 2 lazy dog'); expect(pangram.isPangram()).toBe(true); }); - xit('missing letters replaced by numbers', function() { - var pangram = new Pangram("7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog"); + xit('missing letters replaced by numbers', function () { + var pangram = new Pangram('7h3 qu1ck brown fox jumps ov3r 7h3 lazy dog'); expect(pangram.isPangram()).toBe(false); }); - xit('pangram with mixed case and punctuation', function() { - var pangram = new Pangram("\"Five quacking Zephyrs jolt my wax bed.\""); + xit('pangram with mixed case and punctuation', function () { + var pangram = new Pangram('\"Five quacking Zephyrs jolt my wax bed.\"'); expect(pangram.isPangram()).toBe(true); }); - xit('pangram with non-ascii characters', function() { - var pangram = new Pangram("Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich."); - expect(pangram.isPangram()).toBe(true); + xit('upper and lower case versions of the same character should not be counted separately', function () { + var pangram = new Pangram('the quick brown fox jumps over with lazy FX'); + expect(pangram.isPangram()).toBe(false); }); - }); diff --git a/exercises/pascals-triangle/README.md b/exercises/pascals-triangle/README.md index cf72686d..4011ad75 100644 --- a/exercises/pascals-triangle/README.md +++ b/exercises/pascals-triangle/README.md @@ -1,11 +1,11 @@ -# Pascals Triangle +# Pascal's Triangle Compute Pascal's triangle up to a given number of rows. In Pascal's Triangle each number is computed by adding the numbers to the right and left of the current position in the previous row. -```plain +```text 1 1 1 1 2 1 @@ -16,26 +16,29 @@ the right and left of the current position in the previous row. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine pascals-triangle.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/pascals-triangle/example.js b/exercises/pascals-triangle/example.js index 2962c0f3..7140f98b 100644 --- a/exercises/pascals-triangle/example.js +++ b/exercises/pascals-triangle/example.js @@ -1,15 +1,15 @@ 'use strict'; function sumElements(element, index, array) { - /*jshint validthis:true */ - this.push(element + (array[index+1] || 0)); + /* jshint validthis:true */ + this.push(element + (array[index + 1] || 0)); } function fillRows(rows) { var result = [[1]]; for (var x = 1; x < rows; x++) { var newRow = [1]; - result[x-1].forEach(sumElements, newRow); + result[x - 1].forEach(sumElements, newRow); result.push(newRow); } return result; @@ -20,4 +20,4 @@ function Triangle(rows) { this.lastRow = this.rows[this.rows.length - 1]; } -module.exports = Triangle; \ No newline at end of file +module.exports = Triangle; diff --git a/exercises/pascals-triangle/pascals-triangle.spec.js b/exercises/pascals-triangle/pascals-triangle.spec.js index 79c4aab2..eb4009ba 100644 --- a/exercises/pascals-triangle/pascals-triangle.spec.js +++ b/exercises/pascals-triangle/pascals-triangle.spec.js @@ -1,7 +1,6 @@ var Triangle = require('./pascals-triangle'); describe('Triangle', function () { - it('with one row', function () { expect(new Triangle(1).rows).toEqual([[1]]); }); @@ -19,7 +18,7 @@ describe('Triangle', function () { }); xit('fifth row', function () { - expect(new Triangle(5).lastRow).toEqual([1, 4, 6, 4 ,1]); + expect(new Triangle(5).lastRow).toEqual([1, 4, 6, 4, 1]); }); xit('twentieth row', function () { @@ -27,5 +26,4 @@ describe('Triangle', function () { expect(new Triangle(20).lastRow) .toEqual(twentieth); }); - }); diff --git a/exercises/perfect-numbers/README.md b/exercises/perfect-numbers/README.md index 4e343f53..4f9eaabe 100644 --- a/exercises/perfect-numbers/README.md +++ b/exercises/perfect-numbers/README.md @@ -5,7 +5,7 @@ Nicomachus' (60 - 120 CE) classification scheme for natural numbers. The Greek mathematician [Nicomachus](https://en.wikipedia.org/wiki/Nicomachus) devised a classification scheme for natural numbers, identifying each as belonging uniquely to the categories of **perfect**, **abundant**, or **deficient** based on their [aliquot sum](https://en.wikipedia.org/wiki/Aliquot_sum). The aliquot sum is defined as the sum of the factors of a number not including the number itself. For example, the aliquot sum of 15 is (1 + 3 + 5) = 9 -- **Perfect**: aliquot sum = number +- **Perfect**: aliquot sum = number - 6 is a perfect number because (1 + 2 + 3) = 6 - 28 is a perfect number because (1 + 2 + 4 + 7 + 14) = 28 - **Abundant**: aliquot sum > number @@ -14,31 +14,34 @@ The Greek mathematician [Nicomachus](https://en.wikipedia.org/wiki/Nicomachus) d - **Deficient**: aliquot sum < number - 8 is a deficient number because (1 + 2 + 4) = 7 - Prime numbers are deficient - + Implement a way to determine whether a given number is **perfect**. Depending on your language track, you may also need to implement a way to determine whether a given number is **abundant** or **deficient**. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine perfect-numbers.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/perfect-numbers/example.js b/exercises/perfect-numbers/example.js index 5e98da18..ad7c1c6e 100644 --- a/exercises/perfect-numbers/example.js +++ b/exercises/perfect-numbers/example.js @@ -1,40 +1,41 @@ 'use strict'; -var PerfectNumbers = function() { +var PerfectNumbers = function () { }; /** * Calculate all the divisors for a given number and return them as an array. * Note: the actual number is not include in the returned array. + * @param {number} number - a number input. + * @returns {array} - the array of divisors */ -PerfectNumbers.prototype.getDivisors = function(number) { - +PerfectNumbers.prototype.getDivisors = function (number) { var i; - var divs = new Array(); + var divs = []; // Accepts only natura numbers greater than 1. if (number <= 1) { return divs; - } + } // 1 always divides everyone! divs.push(1); // Calculate the divisors up the the half of the number + 1 for (i = 2; i <= number / 2; i++) { - if (number % i === 0) { divs.push(i); - } + } } return divs; }; -PerfectNumbers.prototype.classify = function(number) { - - var i, sum, result; +PerfectNumbers.prototype.classify = function (number) { + var i; + var sum; + var result; // Check if the input is valid if (number <= 0) { @@ -53,11 +54,9 @@ PerfectNumbers.prototype.classify = function(number) { // Check if the number is perfect. if (sum === number) { result = 'perfect'; - } - else if (sum > number) { + } else if (sum > number) { result = 'abundant'; - } - else { + } else { result = 'deficient'; } diff --git a/exercises/perfect-numbers/perfect-numbers.spec.js b/exercises/perfect-numbers/perfect-numbers.spec.js index 4a9fe9d7..8fba8f1d 100644 --- a/exercises/perfect-numbers/perfect-numbers.spec.js +++ b/exercises/perfect-numbers/perfect-numbers.spec.js @@ -1,79 +1,69 @@ var PerfectNumbers = require('./perfect-numbers'); -describe('Exercise - Perfect Numbers', function() { - +describe('Exercise - Perfect Numbers', function () { var perfectNumbers; beforeEach(function () { perfectNumbers = new PerfectNumbers(); }); - describe('Perfect Numbers', function() { - - it('Smallest perfect number is classified correctly', function() { + describe('Perfect Numbers', function () { + it('Smallest perfect number is classified correctly', function () { expect(perfectNumbers.classify(6)).toEqual('perfect'); }); - it('Medium perfect number is classified correctly', function() { + it('Medium perfect number is classified correctly', function () { expect(perfectNumbers.classify(28)).toEqual('perfect'); }); - it('Large perfect number is classified correctly', function() { + it('Large perfect number is classified correctly', function () { expect(perfectNumbers.classify(33550336)).toEqual('perfect'); }); - }); - describe('Abundant Numbers', function() { - - it('Smallest abundant number is classified correctly', function() { + describe('Abundant Numbers', function () { + it('Smallest abundant number is classified correctly', function () { expect(perfectNumbers.classify(12)).toEqual('abundant'); }); - it('Medium abundant number is classified correctly', function() { + it('Medium abundant number is classified correctly', function () { expect(perfectNumbers.classify(30)).toEqual('abundant'); }); - it('Large abundant number is classified correctly', function() { + it('Large abundant number is classified correctly', function () { expect(perfectNumbers.classify(33550335)).toEqual('abundant'); }); - }); - describe('Deficient Numbers', function() { - - it('Smallest prime deficient number is classified correctly', function() { + describe('Deficient Numbers', function () { + it('Smallest prime deficient number is classified correctly', function () { expect(perfectNumbers.classify(2)).toEqual('deficient'); }); - it('Smallest non-prime deficient number is classified correctly', function() { + it('Smallest non-prime deficient number is classified correctly', function () { expect(perfectNumbers.classify(4)).toEqual('deficient'); }); - it('Medium deficient number is classified correctly', function() { + it('Medium deficient number is classified correctly', function () { expect(perfectNumbers.classify(32)).toEqual('deficient'); }); - it('Large deficient number is classified correctly', function() { + it('Large deficient number is classified correctly', function () { expect(perfectNumbers.classify(33550337)).toEqual('deficient'); }); - it('Edge case (no factors other than itself) is classified correctly', function() { + it('Edge case (no factors other than itself) is classified correctly', function () { expect(perfectNumbers.classify(1)).toEqual('deficient'); }); - }); - describe('Invalid Inputs', function() { - - it('Zero is rejected (not a natural number)', function() { + describe('Invalid Inputs', function () { + it('Zero is rejected (not a natural number)', function () { expect(perfectNumbers.classify(0)).toEqual('Classification is only possible for natural numbers.'); }); - it('Negative integer is rejected (not a natural number)', function() { + it('Negative integer is rejected (not a natural number)', function () { expect(perfectNumbers.classify(-1)).toEqual('Classification is only possible for natural numbers.'); }); - }); - }); diff --git a/exercises/phone-number/README.md b/exercises/phone-number/README.md index c0428ad7..12968e23 100644 --- a/exercises/phone-number/README.md +++ b/exercises/phone-number/README.md @@ -6,14 +6,15 @@ The **North American Numbering Plan (NANP)** is a telephone numbering system use NANP numbers are ten-digit numbers consisting of a three-digit Numbering Plan Area code, commonly known as *area code*, followed by a seven-digit local number. The first three digits of the local number represent the *exchange code*, followed by the unique four-digit number which is the *subscriber number*. - The format is usually represented as -``` + +```text (NXX)-NXX-XXXX ``` + where `N` is any digit from 2 through 9 and `X` is any digit from 0 through 9. -Your task is to clean up differently formated telephone numbers by removing punctuation and the country code (1) if present. +Your task is to clean up differently formatted telephone numbers by removing punctuation and the country code (1) if present. For example, the inputs - `+1 (613)-995-0253` @@ -29,26 +30,29 @@ should all produce the output ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine phone-number.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/phone-number/example.js b/exercises/phone-number/example.js index 5278ad40..e9da676e 100644 --- a/exercises/phone-number/example.js +++ b/exercises/phone-number/example.js @@ -5,35 +5,34 @@ var Phone = module.exports = function Phone(number) { this.cleanedNumber = this.cleanNumber(number); }; -Phone.prototype.cleanNumber = function(number) { - var num = number.replace(/\D/g,''); +Phone.prototype.cleanNumber = function (number) { + var num = number.replace(/\D/g, ''); - if (num.length === 10 && num[0]>=2&& num[3]>=2) { + if (num.length === 10 && num[0] >= 2 && num[3] >= 2) { return num; } else if (num.length === 11 && num[0] === '1') { - return num.substr(1,num.length); - } else { - return null; + return num.substr(1, num.length); } + return null; }; -Phone.prototype.number = function() { +Phone.prototype.number = function () { return this.cleanedNumber; }; -Phone.prototype.areaCode = function() { - return this.number().substr(0,3); +Phone.prototype.areaCode = function () { + return this.number().substr(0, 3); }; -Phone.prototype.exchangeCode = function() { - return this.number().substr(3,3); +Phone.prototype.exchangeCode = function () { + return this.number().substr(3, 3); }; -Phone.prototype.subscriberNumber = function() { - return this.number().substr(6,4); +Phone.prototype.subscriberNumber = function () { + return this.number().substr(6, 4); }; -Phone.prototype.toString = function() { +Phone.prototype.toString = function () { return '(' + this.areaCode() + ') ' + this.exchangeCode() + '-' + this.subscriberNumber(); }; diff --git a/exercises/phone-number/phone-number.spec.js b/exercises/phone-number/phone-number.spec.js index 257ddf15..fa272bfc 100644 --- a/exercises/phone-number/phone-number.spec.js +++ b/exercises/phone-number/phone-number.spec.js @@ -1,63 +1,63 @@ var PhoneNumber = require('./phone-number'); -describe('PhoneNumber()', function() { - it('cleans the number', function() { +describe('PhoneNumber()', function () { + it('cleans the number', function () { var phone = new PhoneNumber('(223) 456-7890'); expect(phone.number()).toEqual('2234567890'); }); - xit('cleans numbers with dots', function() { + xit('cleans numbers with dots', function () { var phone = new PhoneNumber('223.456.7890'); expect(phone.number()).toEqual('2234567890'); }); - xit('cleans numbers with multiple spaces', function() { + xit('cleans numbers with multiple spaces', function () { var phone = new PhoneNumber('223 456 7890 '); expect(phone.number()).toEqual('2234567890'); }); - - xit('invalid when 9 digits', function() { + + xit('invalid when 9 digits', function () { var phone = new PhoneNumber('123456789'); expect(phone.number()).toEqual(null); }); - - xit('invalid when 11 digits does not start with a 1', function(){ - var phone = new PhoneNumber('22234567890'); - expect(phone.number()).toEqual(null); - }); - - xit('valid when 11 digits and starting with 1', function(){ - var phone = new PhoneNumber('12234567890'); - expect(phone.number()).toEqual('2234567890'); - }); - - xit('valid when 11 digits and starting with 1 even with punctuation', function(){ - var phone = new PhoneNumber('+1 (223) 456-7890'); - expect(phone.number()).toEqual('2234567890'); - }); - - xit('invalid when more than 11 digits', function(){ - var phone = new PhoneNumber('321234567890'); - expect(phone.number()).toEqual(null); - }); - - xit('invalid with letters', function(){ - var phone = new PhoneNumber('123-abc-7890'); - expect(phone.number()).toEqual(null); - }); - - xit('invalid with punctuations', function(){ - var phone = new PhoneNumber('123-@:!-7890'); - expect(phone.number()).toEqual(null); - }); - - xit('invalid if area code does not start with 2-9', function(){ - var phone = new PhoneNumber('(123) 456-7890'); - expect(phone.number()).toEqual(null); - }); - - xit('invalid if exchange code does not start with 2-9', function(){ - var phone = new PhoneNumber('(223) 056-7890'); - expect(phone.number()).toEqual(null); - }); + + xit('invalid when 11 digits does not start with a 1', function () { + var phone = new PhoneNumber('22234567890'); + expect(phone.number()).toEqual(null); + }); + + xit('valid when 11 digits and starting with 1', function () { + var phone = new PhoneNumber('12234567890'); + expect(phone.number()).toEqual('2234567890'); + }); + + xit('valid when 11 digits and starting with 1 even with punctuation', function () { + var phone = new PhoneNumber('+1 (223) 456-7890'); + expect(phone.number()).toEqual('2234567890'); + }); + + xit('invalid when more than 11 digits', function () { + var phone = new PhoneNumber('321234567890'); + expect(phone.number()).toEqual(null); + }); + + xit('invalid with letters', function () { + var phone = new PhoneNumber('123-abc-7890'); + expect(phone.number()).toEqual(null); + }); + + xit('invalid with punctuations', function () { + var phone = new PhoneNumber('123-@:!-7890'); + expect(phone.number()).toEqual(null); + }); + + xit('invalid if area code does not start with 2-9', function () { + var phone = new PhoneNumber('(123) 456-7890'); + expect(phone.number()).toEqual(null); + }); + + xit('invalid if exchange code does not start with 2-9', function () { + var phone = new PhoneNumber('(223) 056-7890'); + expect(phone.number()).toEqual(null); + }); }); diff --git a/exercises/pig-latin/README.md b/exercises/pig-latin/README.md index cfd1f0e9..4a1cc7da 100644 --- a/exercises/pig-latin/README.md +++ b/exercises/pig-latin/README.md @@ -19,26 +19,29 @@ See for more details. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine pig-latin.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/pig-latin/example.js b/exercises/pig-latin/example.js index 7906cbbf..de800f58 100644 --- a/exercises/pig-latin/example.js +++ b/exercises/pig-latin/example.js @@ -20,4 +20,4 @@ module.exports = { words.forEach( translateWord ); return translated.join(' '); } -}; \ No newline at end of file +}; diff --git a/exercises/pig-latin/pig-latin.spec.js b/exercises/pig-latin/pig-latin.spec.js index da0c8391..0e619db0 100644 --- a/exercises/pig-latin/pig-latin.spec.js +++ b/exercises/pig-latin/pig-latin.spec.js @@ -1,7 +1,6 @@ var pigLatin = require('./pig-latin'); describe('pigLatin', function () { - it('translates a word beginning with a', function () { expect(pigLatin.translate('apple')).toEqual('appleay'); }); @@ -46,5 +45,4 @@ describe('pigLatin', function () { expect(pigLatin.translate('quick fast run')) .toEqual('ickquay astfay unray'); }); - }); diff --git a/exercises/point-mutations/README.md b/exercises/point-mutations/README.md index b479abc5..a7136a5c 100644 --- a/exercises/point-mutations/README.md +++ b/exercises/point-mutations/README.md @@ -36,26 +36,29 @@ distance function. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine point-mutations.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/point-mutations/example.js b/exercises/point-mutations/example.js index 0258f742..3b0a9af2 100644 --- a/exercises/point-mutations/example.js +++ b/exercises/point-mutations/example.js @@ -4,7 +4,7 @@ var DNA = module.exports = function DNA(nucleotides) { this.nucleotides = nucleotides; }; -DNA.prototype.hammingDistance = function(comparison) { +DNA.prototype.hammingDistance = function (comparison) { var distance = 0; var calculationDistance = Math.min(this.nucleotides.length, comparison.length); diff --git a/exercises/point-mutations/point-mutations.spec.js b/exercises/point-mutations/point-mutations.spec.js index b92ed05a..90ee18f4 100644 --- a/exercises/point-mutations/point-mutations.spec.js +++ b/exercises/point-mutations/point-mutations.spec.js @@ -1,45 +1,43 @@ var DNA = require('./point-mutations'); -describe('DNA', function() { - - it('no difference between empty strands', function() { +describe('DNA', function () { + it('no difference between empty strands', function () { var dna = new DNA(''); expect(dna.hammingDistance('')).toEqual(0); }); - xit('no difference between identical strands', function() { + xit('no difference between identical strands', function () { var dna = new DNA('GGACTGA'); expect(dna.hammingDistance('GGACTGA')).toEqual(0); }); - xit('complete hamming distance in small strand', function() { + xit('complete hamming distance in small strand', function () { var dna = new DNA('ACT'); expect(dna.hammingDistance('GGA')).toEqual(3); }); - xit('hamming distance in off by one strand', function() { + xit('hamming distance in off by one strand', function () { var dna = new DNA('GGACGGATTCTGACCTGGACTAATTTTGGGG'); expect(dna.hammingDistance('AGGACGGATTCTGACCTGGACTAATTTTGGGG')).toEqual(19); }); - xit('small hamming distance in middle somewhere', function() { + xit('small hamming distance in middle somewhere', function () { var dna = new DNA('GGACG'); expect(dna.hammingDistance('GGTCG')).toEqual(1); }); - xit('larger distance', function() { + xit('larger distance', function () { var dna = new DNA('ACCAGGG'); expect(dna.hammingDistance('ACTATGG')).toEqual(2); }); - xit('shortens other strand when longer', function() { + xit('shortens other strand when longer', function () { var dna = new DNA('AAACTAGGGG'); expect(dna.hammingDistance('AGGCTAGCGGTAGGAC')).toEqual(3); }); - xit('shortens original strand when longer', function() { + xit('shortens original strand when longer', function () { var dna = new DNA('GACTACGGACAGGGTAGGGAAT'); expect(dna.hammingDistance('GACATCGCACACC')).toEqual(5); }); - }); diff --git a/exercises/prime-factors/README.md b/exercises/prime-factors/README.md index eefc5599..ed083464 100644 --- a/exercises/prime-factors/README.md +++ b/exercises/prime-factors/README.md @@ -31,26 +31,29 @@ You can check this yourself: ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine prime-factors.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/prime-factors/example.js b/exercises/prime-factors/example.js index 44622035..74f2c150 100644 --- a/exercises/prime-factors/example.js +++ b/exercises/prime-factors/example.js @@ -1,15 +1,16 @@ 'use strict'; exports.for = function (n) { - var prime_factors = []; - var possible_factor = 2; - while (possible_factor * possible_factor <= n) { - while (n % possible_factor === 0) { - prime_factors.push(possible_factor); - n /= possible_factor; + var primeFactors = []; + var possibleFactor = 2; + var number = n; + while (possibleFactor * possibleFactor <= number) { + while (number % possibleFactor === 0) { + primeFactors.push(possibleFactor); + number /= possibleFactor; } - possible_factor += 1; + possibleFactor += 1; } - if (n > 1) { prime_factors.push(n); } - return prime_factors; -}; \ No newline at end of file + if (number > 1) { primeFactors.push(number); } + return primeFactors; +}; diff --git a/exercises/prime-factors/prime-factors.spec.js b/exercises/prime-factors/prime-factors.spec.js index 62e26cdd..a0f3d6b5 100644 --- a/exercises/prime-factors/prime-factors.spec.js +++ b/exercises/prime-factors/prime-factors.spec.js @@ -1,49 +1,47 @@ var primeFactors = require('./prime-factors'); -describe('primeFactors', function() { - - it('returns an empty array for 1', function() { +describe('primeFactors', function () { + it('returns an empty array for 1', function () { expect(primeFactors.for(1)).toEqual([]); }); - xit('factors 2', function() { + xit('factors 2', function () { expect(primeFactors.for(2)).toEqual([2]); }); - xit('factors 3', function() { + xit('factors 3', function () { expect(primeFactors.for(3)).toEqual([3]); }); - xit('factors 4', function() { + xit('factors 4', function () { expect(primeFactors.for(4)).toEqual([2, 2]); }); - xit('factors 6', function() { + xit('factors 6', function () { expect(primeFactors.for(6)).toEqual([2, 3]); }); - xit('factors 8', function() { + xit('factors 8', function () { expect(primeFactors.for(8)).toEqual([2, 2, 2]); }); - xit('factors 9', function() { + xit('factors 9', function () { expect(primeFactors.for(9)).toEqual([3, 3]); }); - xit('factors 27', function() { + xit('factors 27', function () { expect(primeFactors.for(27)).toEqual([3, 3, 3]); }); - xit('factors 625', function() { + xit('factors 625', function () { expect(primeFactors.for(625)).toEqual([5, 5, 5, 5]); }); - xit('factors 901255', function() { + xit('factors 901255', function () { expect(primeFactors.for(901255)).toEqual([5, 17, 23, 461]); }); - xit('factors 93819012551', function() { + xit('factors 93819012551', function () { expect(primeFactors.for(93819012551)).toEqual([11, 9539, 894119]); }); - }); diff --git a/exercises/protein-translation/README.md b/exercises/protein-translation/README.md new file mode 100644 index 00000000..96e516e5 --- /dev/null +++ b/exercises/protein-translation/README.md @@ -0,0 +1,75 @@ +# Protein Translation + +Translate RNA sequences into proteins. + +RNA can be broken into three nucleotide sequences called codons, and then translated to a polypeptide like so: + +RNA: `"AUGUUUUCU"` => translates to + +Codons: `"AUG", "UUU", "UCU"` +=> which become a polypeptide with the following sequence => + +Protein: `"Methionine", "Phenylalanine", "Serine"` + +There are 64 codons which in turn correspond to 20 amino acids; however, all of the codon sequences and resulting amino acids are not important in this exercise. If it works for one codon, the program should work for all of them. +However, feel free to expand the list in the test suite to include them all. + +There are also three terminating codons (also known as 'STOP' codons); if any of these codons are encountered (by the ribosome), all translation ends and the protein is terminated. + +All subsequent codons after are ignored, like this: + +RNA: `"AUGUUUUCUUAAAUG"` => + +Codons: `"AUG", "UUU", "UCU", "UAG", "AUG"` => + +Protein: `"Methionine", "Phenylalanine", "Serine"` + +Note the stop codon terminates the translation and the final methionine is not translated into the protein sequence. + +Below are the codons and resulting Amino Acids needed for the exercise. + +Codon | Protein +:--- | :--- +AUG | Methionine +UUU, UUC | Phenylalanine +UUA, UUG | Leucine +UCU, UCC, UCA, UCG | Serine +UAU, UAC | Tyrosine +UGU, UGC | Cysteine +UGG | Tryptophan +UAA, UAG, UGA | STOP + +Learn more about [protein translation on Wikipedia](http://en.wikipedia.org/wiki/Translation_(biology)) + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine protein-translation.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Tyler Long + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/protein-translation/example.js b/exercises/protein-translation/example.js new file mode 100644 index 00000000..59e291c3 --- /dev/null +++ b/exercises/protein-translation/example.js @@ -0,0 +1,67 @@ +'use strict'; + +module.exports = translate; + +function translate(rnaStrand) { + var proteins = []; + + if (rnaStrand) { + for (var i = 0; i < rnaStrand.length; i += 3) { + var protein = getProtein(rnaStrand.substring(i, i + 3)); + + if (protein) { + if (protein === 'STOP') { + break; + } + + if (protein === 'INVALID') { + throw new Error('Invalid codon'); + } + + proteins.push(protein); + } + } + } + + return proteins; +} + +function getProtein(codon) { + switch (codon) { + case 'AUG': + return 'Methionine'; + + case 'UUU': + case 'UUC': + return 'Phenylalanine'; + + case 'UUA': + case 'UUG': + return 'Leucine'; + + case 'UCU': + case 'UCC': + case 'UCA': + case 'UCG': + return 'Serine'; + + case 'UAU': + case 'UAC': + return 'Tyrosine'; + + case 'UGU': + case 'UGC': + return 'Cysteine'; + + case 'UGG': + return 'Tryptophan'; + + case 'UAA': + case 'UAG': + case 'UGA': + return 'STOP'; + + default: + return 'INVALID'; + } +} diff --git a/exercises/protein-translation/protein-translation.spec.js b/exercises/protein-translation/protein-translation.spec.js new file mode 100644 index 00000000..39279744 --- /dev/null +++ b/exercises/protein-translation/protein-translation.spec.js @@ -0,0 +1,63 @@ +var translate = require('./protein-translation'); + +describe('ProteinTranslation', function () { + it('Empty RNA has no proteins', function () { + expect(translate()).toEqual([]); + }); + + xit('Methionine codon translates into protein', function () { + expect(translate('AUG')).toEqual(['Methionine']); + }); + + xit('Phenylalanine codons translate into protein', function () { + expect(translate('UUUUUC')).toEqual(['Phenylalanine', 'Phenylalanine']); + }); + + xit('Leucine codons translate into protein', function () { + expect(translate('UUAUUG')).toEqual(['Leucine', 'Leucine']); + }); + + xit('Serine codons translate into protein', function () { + expect(translate('UCUUCCUCAUCG')).toEqual(['Serine', 'Serine', 'Serine', 'Serine']); + }); + + xit('Tyrosine codons translate into protein', function () { + expect(translate('UAUUAC')).toEqual(['Tyrosine', 'Tyrosine']); + }); + + xit('Cysteine codons translate into protein', function () { + expect(translate('UGUUGC')).toEqual(['Cysteine', 'Cysteine']); + }); + + xit('Tryptophan codon translates into protein', function () { + expect(translate('UGG')).toEqual(['Tryptophan']); + }); + + xit('Sequence starts with stop codon 1', function () { + expect(translate('UAAUUUUUA')).toEqual([]); + }); + + xit('Sequence starts with stop codon 2', function () { + expect(translate('UAGAUGUAU')).toEqual([]); + }); + + xit('Sequence starts with stop codon 3', function () { + expect(translate('UGAUGU')).toEqual([]); + }); + + xit('Small RNA strand', function () { + expect(translate('AUGUUUUCU')).toEqual(['Methionine', 'Phenylalanine', 'Serine']); + }); + + xit('Stop codon ends translation', function () { + expect(translate('AUGUUUUCUUAAAUG')).toEqual(['Methionine', 'Phenylalanine', 'Serine']); + }); + + xit('Invalid codon throws error', function () { + expect( + function () { + translate('LOL'); + } + ).toThrow(new Error('Invalid codon')); + }); +}); diff --git a/exercises/proverb/README.md b/exercises/proverb/README.md index 51fdaac1..b7282a20 100644 --- a/exercises/proverb/README.md +++ b/exercises/proverb/README.md @@ -1,38 +1,46 @@ # Proverb -For want of a horseshoe nail, a kingdom was lost, or so the saying goes. Output -the full text of this proverbial rhyme: +For want of a horseshoe nail, a kingdom was lost, or so the saying goes. -> For want of a nail the shoe was lost. -> For want of a shoe the horse was lost. -> For want of a horse the rider was lost. -> For want of a rider the message was lost. -> For want of a message the battle was lost. -> For want of a battle the kingdom was lost. -> And all for the want of a horseshoe nail. +Given a list of inputs, generate the relevant proverb. For example, given the list `["nail", "shoe", "horse", "rider", "message", "battle", "kingdom"]`, you will output the full text of this proverbial rhyme: -## Setup +```text +For want of a nail the shoe was lost. +For want of a shoe the horse was lost. +For want of a horse the rider was lost. +For want of a rider the message was lost. +For want of a message the battle was lost. +For want of a battle the kingdom was lost. +And all for the want of a nail. +``` + +Note that the list of inputs may vary; your solution should be able to handle lists of arbitrary length and content. No line of the output text should be a static, unchanging string; all should vary according to the input given. -Go through the setup instructions for JavaScript to -install the necessary dependencies: +## Setup -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine proverb.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/proverb/example.js b/exercises/proverb/example.js index 1600e3e4..729c214c 100644 --- a/exercises/proverb/example.js +++ b/exercises/proverb/example.js @@ -1,36 +1,36 @@ -module.exports = function(){ +module.exports = function () { var last = arguments[arguments.length - 1]; var chain = Array.from(arguments); this.options = {}; - if(typeof last == "object" && last.hasOwnProperty("qualifier")){ + if (typeof last === 'object' && last.hasOwnProperty('qualifier')) { this.options = chain.pop(); } this.chain = chain; this.qualifier = this.options.qualifier ? this.options.qualifier + ' ' : ''; - this.toString = function(){ + this.toString = function () { return this.chainOfEvents() + this.conclusion(); }.bind(this); - this.chainOfEvents = function(){ - return this.causesAndEffects().map( function(entry){ - return "For want of a " + entry.cause + - " the " + entry.effect + " was lost.\n"; - }.bind(this) ).join(''); + this.chainOfEvents = function () { + return this.causesAndEffects().map( function (entry) { + return 'For want of a ' + entry.cause + + ' the ' + entry.effect + ' was lost.\n'; + } ).join(''); }.bind(this); - this.causesAndEffects = function(){ - return this.chain.reduce( function(array, event, index){ - if(index < this.chain.length - 1){ + this.causesAndEffects = function () { + return this.chain.reduce( function (array, event, index) { + if (index < this.chain.length - 1) { array.push({ cause: event, effect: this.chain[index + 1] }); } return array; }.bind(this), [] ); }.bind(this); - this.conclusion = function(){ - return "And all for the want of a " + this.qualifier + this.chain[0] + "."; + this.conclusion = function () { + return 'And all for the want of a ' + this.qualifier + this.chain[0] + '.'; }.bind(this); }; diff --git a/exercises/proverb/proverb.spec.js b/exercises/proverb/proverb.spec.js index 8ee75647..50788a2c 100644 --- a/exercises/proverb/proverb.spec.js +++ b/exercises/proverb/proverb.spec.js @@ -1,76 +1,76 @@ var Proverb = require('./proverb'); -describe('Proverb Test Suite', function() { - it('tests a single consequence', function() { +describe('Proverb Test Suite', function () { + it('tests a single consequence', function () { var proverb = new Proverb('nail', 'shoe'); expect(proverb.toString()).toEqual( - "For want of a nail the shoe was lost.\n" + - "And all for the want of a nail."); + 'For want of a nail the shoe was lost.\n' + + 'And all for the want of a nail.'); }); - - it('tests a short chain of consequences', function() { + + it('tests a short chain of consequences', function () { var proverb = new Proverb('nail', 'shoe', 'horse'); expect(proverb.toString()).toEqual( - "For want of a nail the shoe was lost.\n" + - "For want of a shoe the horse was lost.\n" + - "And all for the want of a nail."); + 'For want of a nail the shoe was lost.\n' + + 'For want of a shoe the horse was lost.\n' + + 'And all for the want of a nail.'); }); - it('tests a longer chain of consequences', function() { + it('tests a longer chain of consequences', function () { var proverb = new Proverb('nail', 'shoe', 'horse', 'rider'); expect(proverb.toString()).toEqual( - "For want of a nail the shoe was lost.\n" + - "For want of a shoe the horse was lost.\n" + - "For want of a horse the rider was lost.\n" + - "And all for the want of a nail."); + 'For want of a nail the shoe was lost.\n' + + 'For want of a shoe the horse was lost.\n' + + 'For want of a horse the rider was lost.\n' + + 'And all for the want of a nail.'); }); - it('tests Proverb class does not hard code the rhyme dictionary', - function() { - var proverb = new Proverb('key', 'value'); + it('tests Proverb class does not hard code the rhyme dictionary', + function () { + var proverb = new Proverb('key', 'value'); - expect(proverb.toString()).toEqual( - "For want of a key the value was lost.\n" + - "And all for the want of a key."); - }); + expect(proverb.toString()).toEqual( + 'For want of a key the value was lost.\n' + + 'And all for the want of a key.'); + }); - it('tests the whole proveb', function() { - var proverb = new Proverb('nail', 'shoe', 'horse', 'rider', - 'message', 'battle', 'kingdom'); + it('tests the whole proveb', function () { + var proverb = new Proverb('nail', 'shoe', 'horse', 'rider', + 'message', 'battle', 'kingdom'); expect(proverb.toString()).toEqual( - "For want of a nail the shoe was lost.\n" + - "For want of a shoe the horse was lost.\n" + - "For want of a horse the rider was lost.\n" + - "For want of a rider the message was lost.\n" + - "For want of a message the battle was lost.\n" + - "For want of a battle the kingdom was lost.\n" + - "And all for the want of a nail."); + 'For want of a nail the shoe was lost.\n' + + 'For want of a shoe the horse was lost.\n' + + 'For want of a horse the rider was lost.\n' + + 'For want of a rider the message was lost.\n' + + 'For want of a message the battle was lost.\n' + + 'For want of a battle the kingdom was lost.\n' + + 'And all for the want of a nail.'); }); - it('tests the use of an optional qualifier in the final consequence', - function() { - var proverb = new Proverb('nail', 'shoe', 'horse', 'rider', - 'message', 'battle', 'kingdom', - { qualifier: 'horseshoe' }); + it('tests the use of an optional qualifier in the final consequence', + function () { + var proverb = new Proverb('nail', 'shoe', 'horse', 'rider', + 'message', 'battle', 'kingdom', + { qualifier: 'horseshoe' }); - expect(proverb.toString()).toEqual( - "For want of a nail the shoe was lost.\n" + - "For want of a shoe the horse was lost.\n" + - "For want of a horse the rider was lost.\n" + - "For want of a rider the message was lost.\n" + - "For want of a message the battle was lost.\n" + - "For want of a battle the kingdom was lost.\n" + - "And all for the want of a horseshoe nail."); - }); + expect(proverb.toString()).toEqual( + 'For want of a nail the shoe was lost.\n' + + 'For want of a shoe the horse was lost.\n' + + 'For want of a horse the rider was lost.\n' + + 'For want of a rider the message was lost.\n' + + 'For want of a message the battle was lost.\n' + + 'For want of a battle the kingdom was lost.\n' + + 'And all for the want of a horseshoe nail.'); + }); - it('tests the proverb is the same each time', function(){ + it('tests the proverb is the same each time', function () { var proverb = new Proverb('nail', 'shoe'); expect(proverb.toString()).toEqual(proverb.toString()); diff --git a/exercises/pythagorean-triplet/README.md b/exercises/pythagorean-triplet/README.md index 7165790b..fc3b3b94 100644 --- a/exercises/pythagorean-triplet/README.md +++ b/exercises/pythagorean-triplet/README.md @@ -3,13 +3,13 @@ A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for which, -``` +```text a**2 + b**2 = c**2 ``` -For example, +For example, -``` +```text 3**2 + 4**2 = 9 + 16 = 25 = 5**2. ``` @@ -19,26 +19,29 @@ Find the product a * b * c. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine pythagorean-triplet.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/pythagorean-triplet/example.js b/exercises/pythagorean-triplet/example.js index 0e7ba3f0..a30323bc 100644 --- a/exercises/pythagorean-triplet/example.js +++ b/exercises/pythagorean-triplet/example.js @@ -15,7 +15,7 @@ function Triplets(conditions) { } Triplet.prototype.isPythagorean = function () { - return this.a*this.a + this.b*this.b === this.c*this.c; + return this.a * this.a + this.b * this.b === this.c * this.c; }; Triplet.prototype.product = function () { @@ -35,7 +35,8 @@ Triplets.prototype.isDesired = function (triplet) { }; Triplets.prototype.toArray = function () { - var triplet, triplets = []; + var triplet = []; + var triplets = []; for (var a = this.min; a < this.max - 1; a++) { for (var b = a + 1; b < this.max; b++) { for (var c = b + 1; c <= this.max; c++) { @@ -47,4 +48,4 @@ Triplets.prototype.toArray = function () { } } return triplets; -}; \ No newline at end of file +}; diff --git a/exercises/pythagorean-triplet/pythagorean-triplet.spec.js b/exercises/pythagorean-triplet/pythagorean-triplet.spec.js index 0dcdec3f..0ad346cd 100644 --- a/exercises/pythagorean-triplet/pythagorean-triplet.spec.js +++ b/exercises/pythagorean-triplet/pythagorean-triplet.spec.js @@ -1,7 +1,6 @@ var Triplet = require('./pythagorean-triplet'); describe('Triplet', function () { - it('calculates the sum', function () { expect(new Triplet(3, 4, 5).sum()).toBe(12); }); @@ -41,5 +40,4 @@ describe('Triplet', function () { }); expect(products).toEqual([118080, 168480, 202500]); }); - }); diff --git a/exercises/queen-attack/README.md b/exercises/queen-attack/README.md index 7c311f4f..f9c6c5bf 100644 --- a/exercises/queen-attack/README.md +++ b/exercises/queen-attack/README.md @@ -11,7 +11,7 @@ A chessboard can be represented by an 8 by 8 array. So if you're told the white queen is at (2, 3) and the black queen at (5, 6), then you'd know you've got a set-up like so: -```plain +```text _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ W _ _ _ _ @@ -28,26 +28,29 @@ share a diagonal. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine queen-attack.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/queen-attack/example.js b/exercises/queen-attack/example.js index 545b283e..ebe07a5d 100644 --- a/exercises/queen-attack/example.js +++ b/exercises/queen-attack/example.js @@ -1,18 +1,17 @@ 'use strict'; -module.exports = function(options) { - if (options === undefined) { - options = { white: [0,3], black: [7,3] }; - } + +module.exports = function (passedInOptions) { + var options = passedInOptions || {white: [0, 3], black: [7, 3]}; if (options.white[0] === options.black[0] && options.white[1] === options.black[1]) { - throw 'Queens cannot share the same space'; + throw String('Queens cannot share the same space'); } this.white = options.white; this.black = options.black; - this.canAttack = function() { + this.canAttack = function () { var canAttack = false; if (this.white[0] === this.black[0]) { @@ -36,7 +35,7 @@ module.exports = function(options) { return canAttack; }; - this.boardRepresentation = function() { + this.boardRepresentation = function () { var boardRepresentation = ''; for (var i = 0; i < 8; i++) { @@ -57,7 +56,8 @@ module.exports = function(options) { return boardRepresentation; }; - this.toString = function() { + this.toString = function () { return this.boardRepresentation(); }; }; + diff --git a/exercises/queen-attack/queen-attack.spec.js b/exercises/queen-attack/queen-attack.spec.js index 69f1a151..b2d4525f 100644 --- a/exercises/queen-attack/queen-attack.spec.js +++ b/exercises/queen-attack/queen-attack.spec.js @@ -1,82 +1,82 @@ var Queens = require('./queen-attack'); -describe('Queens', function() { - it('has the correct default positions', function() { - var queens = new Queens; +describe('Queens', function () { + it('has the correct default positions', function () { + var queens = new Queens(); expect(queens.white).toEqual([0, 3]); expect(queens.black).toEqual([7, 3]); }); - xit('initialized with specific placement', function() { - var queens = new Queens({white: [3,7], black: [6,1]}); + xit('initialized with specific placement', function () { + var queens = new Queens({white: [3, 7], black: [6, 1]}); expect(queens.white).toEqual([3, 7]); expect(queens.black).toEqual([6, 1]); }); - xit('cannot occupy the same space', function() { - var positioning = {white: [2,4], black: [2,4]}; + xit('cannot occupy the same space', function () { + var positioning = {white: [2, 4], black: [2, 4]}; try { var queens = new Queens(positioning); - } catch(error) { + expect(queens.white).toEqual([2, 4]); + expect(queens.black).toEqual([2, 4]); + } catch (error) { expect(error).toEqual('Queens cannot share the same space'); } - }); - xit('toString representation', function() { + xit('toString representation', function () { var positioning = {white: [2, 4], black: [6, 6]}; var queens = new Queens(positioning); - var board = '_ _ _ _ _ _ _ _\n\ -_ _ _ _ _ _ _ _\n\ -_ _ _ _ W _ _ _\n\ -_ _ _ _ _ _ _ _\n\ -_ _ _ _ _ _ _ _\n\ -_ _ _ _ _ _ _ _\n\ -_ _ _ _ _ _ B _\n\ -_ _ _ _ _ _ _ _\n\ -'; + var board = '_ _ _ _ _ _ _ _\n' + +'_ _ _ _ _ _ _ _\n' + +'_ _ _ _ W _ _ _\n' + +'_ _ _ _ _ _ _ _\n' + +'_ _ _ _ _ _ _ _\n' + +'_ _ _ _ _ _ _ _\n' + +'_ _ _ _ _ _ B _\n' + +'_ _ _ _ _ _ _ _\n' +; expect(queens.toString()).toEqual(board); }); - xit('queens cannot attack', function() { - var queens = new Queens({ white: [2,3], black: [4,7] }); + xit('queens cannot attack', function () { + var queens = new Queens({ white: [2, 3], black: [4, 7] }); expect(queens.canAttack()).toEqual(false); }); - xit('queens can attack when they are on the same row', function() { - var queens = new Queens({ white: [2,4], black: [2,7] }); + xit('queens can attack when they are on the same row', function () { + var queens = new Queens({ white: [2, 4], black: [2, 7] }); expect(queens.canAttack()).toEqual(true); }); - xit('queens can attack when they are on the same column', function() { - var queens = new Queens({ white: [5,4], black: [2,4] }); + xit('queens can attack when they are on the same column', function () { + var queens = new Queens({ white: [5, 4], black: [2, 4] }); expect(queens.canAttack()).toEqual(true); }); - xit('queens can attack diagonally', function() { + xit('queens can attack diagonally', function () { var queens = new Queens({ white: [1, 1], black: [6, 6] }); expect(queens.canAttack()).toEqual(true); }); - xit('queens can attack another diagonally', function() { + xit('queens can attack another diagonally', function () { var queens = new Queens({ white: [0, 6], black: [1, 7] }); expect(queens.canAttack()).toEqual(true); }); - xit('queens can attack yet another diagonally', function() { + xit('queens can attack yet another diagonally', function () { var queens = new Queens({ white: [4, 1], black: [6, 3] }); expect(queens.canAttack()).toEqual(true); }); - xit('queens can attack on a north-east/south-west diagonal', function() { + xit('queens can attack on a north-east/south-west diagonal', function () { var queens = new Queens({ white: [7, 0], black: [0, 7] }); expect(queens.canAttack()).toEqual(true); }); - xit('queens can attack on another ne/sw diagonal', function() { + xit('queens can attack on another ne/sw diagonal', function () { var queens = new Queens({ white: [2, 6], black: [5, 3] }); expect(queens.canAttack()).toEqual(true); }); - }); diff --git a/exercises/raindrops/README.md b/exercises/raindrops/README.md index 21754775..541b58df 100644 --- a/exercises/raindrops/README.md +++ b/exercises/raindrops/README.md @@ -19,26 +19,29 @@ Convert a number to a string, the contents of which depend on the number's facto ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine raindrops.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/raindrops/example.js b/exercises/raindrops/example.js index b062b08b..ebaa473f 100644 --- a/exercises/raindrops/example.js +++ b/exercises/raindrops/example.js @@ -9,9 +9,8 @@ Raindrops.prototype.convert = function (n) { if (n % 7 === 0) { result += 'Plong'; } if (result === '') { return n.toString(); - } else { - return result; } + return result; }; -module.exports = Raindrops; \ No newline at end of file +module.exports = Raindrops; diff --git a/exercises/raindrops/raindrops.spec.js b/exercises/raindrops/raindrops.spec.js index 7e8730f3..abfa9058 100644 --- a/exercises/raindrops/raindrops.spec.js +++ b/exercises/raindrops/raindrops.spec.js @@ -1,70 +1,69 @@ var Raindrops = require('./raindrops'); -describe('Raindrops', function() { +describe('Raindrops', function () { var drops = new Raindrops(); - it('converts 1', function() { + it('converts 1', function () { expect(drops.convert(1)).toEqual('1'); }); - xit('converts 3', function() { + xit('converts 3', function () { expect(drops.convert(3)).toEqual('Pling'); }); - xit('converts 5', function() { + xit('converts 5', function () { expect(drops.convert(5)).toEqual('Plang'); }); - xit('converts 7', function() { + xit('converts 7', function () { expect(drops.convert(7)).toEqual('Plong'); }); - xit('converts 6', function() { + xit('converts 6', function () { expect(drops.convert(6)).toEqual('Pling'); }); - xit('converts 9', function() { + xit('converts 9', function () { expect(drops.convert(9)).toEqual('Pling'); }); - xit('converts 10', function() { + xit('converts 10', function () { expect(drops.convert(10)).toEqual('Plang'); }); - xit('converts 14', function() { + xit('converts 14', function () { expect(drops.convert(14)).toEqual('Plong'); }); - xit('converts 15', function() { + xit('converts 15', function () { expect(drops.convert(15)).toEqual('PlingPlang'); }); - xit('converts 21', function() { + xit('converts 21', function () { expect(drops.convert(21)).toEqual('PlingPlong'); }); - xit('converts 25', function() { + xit('converts 25', function () { expect(drops.convert(25)).toEqual('Plang'); }); - xit('converts 35', function() { + xit('converts 35', function () { expect(drops.convert(35)).toEqual('PlangPlong'); }); - xit('converts 49', function() { + xit('converts 49', function () { expect(drops.convert(49)).toEqual('Plong'); }); - xit('converts 52', function() { + xit('converts 52', function () { expect(drops.convert(52)).toEqual('52'); }); - xit('converts 105', function() { + xit('converts 105', function () { expect(drops.convert(105)).toEqual('PlingPlangPlong'); }); - xit('converts 12121', function() { + xit('converts 12121', function () { expect(drops.convert(12121)).toEqual('12121'); }); - -}); \ No newline at end of file +}); diff --git a/exercises/rational-numbers/README.md b/exercises/rational-numbers/README.md new file mode 100644 index 00000000..12cb067b --- /dev/null +++ b/exercises/rational-numbers/README.md @@ -0,0 +1,62 @@ +# Rational Numbers + +A rational number is defined as the quotient of two integers `a` and `b`, called the numerator and denominator, respectively, where `b != 0`. + +The absolute value `|r|` of the rational number `r = a/b` is equal to `|a|/|b|`. + +The sum of two rational numbers `r1 = a1/b1` and `r2 = a2/b2` is `r1 + r2 = a1/b1 + a2/b2 = (a1 * b2 + a2 * b1) / (b1 * b2)`. + +The difference of two rational numbers `r1 = a1/b1` and `r2 = a2/b2` is `r1 - r2 = a1/b1 - a2/b2 = (a1 * b2 - a2 * b1) / (b1 * b2)`. + +The product (multiplication) of two rational numbers `r1 = a1/b1` and `r2 = a2/b2` is `r1 * r2 = (a1 * a2) / (b1 * b2)`. + +Dividing a rational number `r1 = a1/b1` by another `r2 = a2/b2` is `r1 / r2 = (a1 * b2) / (a2 * b1)` if `a2 * b1` is not zero. + +Exponentiation of a rational number `r = a/b` to a non-negative integer power `n` is `r^n = (a^n)/(b^n)`. + +Exponentiation of a rational number `r = a/b` to a negative integer power `n` is `r^n = (b^m)/(a^m)`, where `m = |n|`. + +Exponentiation of a rational number `r = a/b` to a real (floating-point) number `x` is the quotient `(a^x)/(b^x)`, which is a real number. + +Exponentiation of a real number `x` to a rational number `r = a/b` is `x^(a/b) = root(x^a, b)`, where `root(p, q)` is the `q`th root of `p`. + +Implement the following operations: + - addition, subtraction, multiplication and division of two rational numbers, + - absolute value, exponentiation of a given rational number to an integer power, exponentiation of a given rational number to a real (floating-point) power, exponentiation of a real number to a rational number. + +Your implementation of rational numbers should always be reduced to lowest terms. For example, `4/4` should reduce to `1/1`, `30/60` should reduce to `1/2`, `12/8` should reduce to `3/2`, etc. To reduce a rational number `r = a/b`, divide `a` and `b` by the greatest common divisor (gcd) of `a` and `b`. So, for example, `gcd(12, 8) = 4`, so `r = 12/8` can be reduced to `(12/4)/(8/4) = 3/2`. + +Assume that the programming language you are using does not have an implementation of rational numbers. + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine rational-numbers.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Rational_number](https://en.wikipedia.org/wiki/Rational_number) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/rational-numbers/example.js b/exercises/rational-numbers/example.js new file mode 100644 index 00000000..cd95bdc1 --- /dev/null +++ b/exercises/rational-numbers/example.js @@ -0,0 +1,69 @@ +function Rational(numerator, denominator) { + if (denominator === 0) {throw new Error('Denominator must not be zero.');} + + this.numerator = numerator; + this.denominator = denominator; + + this.reduce(); + this.ensureSignInNumerator(); +} + +Rational.prototype.add = function (that) { + var commonDenominator = this.denominator * that.denominator; + return new Rational(this.numerator * that.denominator + that.numerator * this.denominator, commonDenominator); +}; + +Rational.prototype.sub = function (that) { + var commonDenominator = this.denominator * that.denominator; + return new Rational(this.numerator * that.denominator - that.numerator * this.denominator, commonDenominator); +}; + +Rational.prototype.mul = function (that) { + return new Rational(this.numerator * that.numerator, this.denominator * that.denominator); +}; + +Rational.prototype.div = function (that) { + return new Rational(this.numerator * that.denominator, this.denominator * that.numerator); +}; + +Rational.prototype.abs = function () { + return new Rational(Math.abs(this.numerator), Math.abs(this.denominator)); +}; + +Rational.prototype.exprational = function (n) { + return new Rational(Math.pow(this.numerator, n), Math.pow(this.denominator, n)); +}; + +Rational.prototype.expreal = function (base) { + return Math.pow(10.0, Math.log10(Math.pow(base, this.numerator)) / this.denominator); +}; + +Rational.prototype.reduce = function () { + var commonDivisor = this.gcd(this.numerator, this.denominator); + + this.numerator /= commonDivisor; + this.denominator /= commonDivisor; + this.ensureSignInNumerator(); + + return this; +}; + +Rational.prototype.gcd = function (a, b) { + var localA = a; + var localB = b; + while (localB !== 0) { + var t = localB; + localB = localA % localB; + localA = t; + } + return localA; +}; + +Rational.prototype.ensureSignInNumerator = function () { + if (this.denominator < 0) { + this.denominator = -this.denominator; + this.numerator = -this.numerator; + } +}; + +module.exports = Rational; diff --git a/exercises/rational-numbers/rational-numbers.spec.js b/exercises/rational-numbers/rational-numbers.spec.js new file mode 100644 index 00000000..b11c7ed3 --- /dev/null +++ b/exercises/rational-numbers/rational-numbers.spec.js @@ -0,0 +1,197 @@ +var Rational = require('./rational-numbers'); + +describe('Addition', function () { + it('Add two positive rational numbers', function () { + var expected = new Rational(7, 6); + expect(new Rational(1, 2).add(new Rational(2, 3))).toEqual(expected); + }); + + xit('Add a positive rational number and a negative rational number', function () { + var expected = new Rational(-1, 6); + expect(new Rational(1, 2).add(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Add two negative rational numbers', function () { + var expected = new Rational(-7, 6); + expect(new Rational(-1, 2).add(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Add a rational number to its additive inverse', function () { + var expected = new Rational(0, 1); + expect(new Rational(1, 2).add(new Rational(-1, 2))).toEqual(expected); + }); +}); + +describe('Subtraction', function () { + xit('Subtract two positive rational numbers', function () { + var expected = new Rational(-1, 6); + expect(new Rational(1, 2).sub(new Rational(2, 3))).toEqual(expected); + }); + + xit('Subtract a positive rational number and a negative rational number', function () { + var expected = new Rational(7, 6); + expect(new Rational(1, 2).sub(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Subtract two negative rational numbers', function () { + var expected = new Rational(1, 6); + expect(new Rational(-1, 2).sub(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Subtract a rational number from itself', function () { + var expected = new Rational(0, 1); + expect(new Rational(1, 2).sub(new Rational(1, 2))).toEqual(expected); + }); +}); + +describe('Multiplication', function () { + xit('Multiply two positive rational numbers', function () { + var expected = new Rational(1, 3); + expect(new Rational(1, 2).mul(new Rational(2, 3))).toEqual(expected); + }); + + xit('Multiply a negative rational number by a positive rational number', function () { + var expected = new Rational(-1, 3); + expect(new Rational(-1, 2).mul(new Rational(2, 3))).toEqual(expected); + }); + + xit('Multiply two negative rational numbers', function () { + var expected = new Rational(1, 3); + expect(new Rational(-1, 2).mul(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Multiply a rational number by its reciprocal', function () { + var expected = new Rational(1, 1); + expect(new Rational(1, 2).mul(new Rational(2, 1))).toEqual(expected); + }); + + xit('Multiply a rational number by 1', function () { + var expected = new Rational(1, 2); + expect(new Rational(1, 2).mul(new Rational(1, 1))).toEqual(expected); + }); + + xit('Multiply a rational number by 0', function () { + var expected = new Rational(0, 1); + expect(new Rational(1, 2).mul(new Rational(0, 1))).toEqual(expected); + }); +}); + +describe('Division', function () { + xit('Divide two positive rational numbers', function () { + var expected = new Rational(3, 4); + expect(new Rational(1, 2).div(new Rational(2, 3))).toEqual(expected); + }); + + xit('Divide a positive rational number by a negative rational number', function () { + var expected = new Rational(-3, 4); + expect(new Rational(1, 2).div(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Divide two negative rational numbers', function () { + var expected = new Rational(3, 4); + expect(new Rational(-1, 2).div(new Rational(-2, 3))).toEqual(expected); + }); + + xit('Divide a rational number by 1', function () { + var expected = new Rational(1, 2); + expect(new Rational(1, 2).div(new Rational(1, 1))).toEqual(expected); + }); +}); + +describe('Absolute value', function () { + xit('Absolute value of a positive rational number', function () { + var expected = new Rational(1, 2); + expect(new Rational(1, 2).abs()).toEqual(expected); + }); + + xit('Absolute value of a negative rational number', function () { + var expected = new Rational(1, 2); + expect(new Rational(-1, 2).abs()).toEqual(expected); + }); + + xit('Absolute value of zero', function () { + var expected = new Rational(0, 1); + expect(new Rational(0, 1).abs()).toEqual(expected); + }); +}); + +describe('Exponentiation of a rational number', function () { + xit('Raise a positive rational number to a positive integer power', function () { + var expected = new Rational(1, 8); + expect(new Rational(1, 2).exprational(3)).toEqual(expected); + }); + + xit('Raise a negative rational number to a positive integer power', function () { + var expected = new Rational(-1, 8); + expect(new Rational(-1, 2).exprational(3)).toEqual(expected); + }); + + xit('Raise zero to an integer power', function () { + var expected = new Rational(0, 1); + expect(new Rational(0, 1).exprational(5)).toEqual(expected); + }); + + xit('Raise one to an integer power', function () { + var expected = new Rational(1, 1); + expect(new Rational(1, 1).exprational(4)).toEqual(expected); + }); + + xit('Raise a positive rational number to the power of zero', function () { + var expected = new Rational(1, 1); + expect(new Rational(1, 2).exprational(0)).toEqual(expected); + }); + + xit('Raise a negative rational number to the power of zero', function () { + var expected = new Rational(1, 1); + expect(new Rational(-1, 2).exprational(0)).toEqual(expected); + }); +}); + +describe('Exponentiation of a real number to a rational number', function () { + xit('Raise a real number to a positive rational number', function () { + var expected = 16.0; + expect(new Rational(4, 3).expreal(8)).toEqual(expected); + }); + + xit('Raise a real number to a negative rational number', function () { + var expected = 0.3333333333333333; + expect(new Rational(-1, 2).expreal(9)).toEqual(expected); + }); + + xit('Raise a real number to a zero rational number', function () { + var expected = 1.0; + expect(new Rational(0, 1).expreal(2)).toEqual(expected); + }); +}); + +describe('Reduction to lowest terms', function () { + xit('Reduce a positive rational number to lowest terms', function () { + var expected = new Rational(1, 2); + expect(new Rational(2, 4).reduce()).toEqual(expected); + }); + + xit('Reduce a negative rational number to lowest terms', function () { + var expected = new Rational(-2, 3); + expect(new Rational(-4, 6).reduce()).toEqual(expected); + }); + + xit('Reduce a rational number with a negative denominator to lowest terms', function () { + var expected = new Rational(-1, 3); + expect(new Rational(3, -9).reduce()).toEqual(expected); + }); + + xit('Reduce zero to lowest terms', function () { + var expected = new Rational(0, 1); + expect(new Rational(0, 6).reduce()).toEqual(expected); + }); + + xit('Reduce an integer to lowest terms', function () { + var expected = new Rational(-2, 1); + expect(new Rational(-14, 7).reduce()).toEqual(expected); + }); + + xit('Reduce one to lowest terms', function () { + var expected = new Rational(1, 1); + expect(new Rational(13, 13).reduce()).toEqual(expected); + }); +}); diff --git a/exercises/rectangles/README.md b/exercises/rectangles/README.md new file mode 100644 index 00000000..362ed98c --- /dev/null +++ b/exercises/rectangles/README.md @@ -0,0 +1,91 @@ +# Rectangles + +Count the rectangles in an ASCII diagram like the one below. + +```text + +--+ + ++ | ++-++--+ +| | | ++--+--+ +``` + +The above diagram contains 6 rectangles: + +```text + + ++-----+ +| | ++-----+ +``` + +```text + +--+ + | | + | | + | | + +--+ +``` + +```text + +--+ + | | + +--+ + + +``` + +```text + + + +--+ + | | + +--+ +``` + +```text + + ++--+ +| | ++--+ +``` + +```text + + ++ + ++ + + +``` + +You may assume that the input is always a proper rectangle (i.e. the length of +every line equals the length of the first line). + +## Setup + +Go through the setup instructions for JavaScript to +install the necessary dependencies: + +http://exercism.io/languages/javascript + +## Making the Test Suite Pass + +Execute the tests with: + + jasmine .spec.js + +Replace `` with the name of the current exercise. E.g., to +test the Hello World exercise: + + jasmine hello-world.spec.js + +In many test suites all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +changing `xit` to `it`. + + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/rectangles/example.js b/exercises/rectangles/example.js new file mode 100644 index 00000000..f9cb52c3 --- /dev/null +++ b/exercises/rectangles/example.js @@ -0,0 +1,66 @@ +var GLYPH = { corner: '+', edgeV: '|', edgeH: '-' }; + +var Vertex = function () { + this.right = []; + this.down = []; +}; + +// number of rectangles with given top left corner +Vertex.prototype.findRectangles = function () { + var corners = []; + var rectangles = 0; + + this.right.forEach(function (topLeft) { + topLeft.down.forEach(function (bottomRight) { + corners.push(bottomRight); + }); + }); + this.down.forEach(function (bottomLeft) { + bottomLeft.right.forEach(function (bottomRight) { + if (corners.indexOf(bottomRight) >= 0) { + rectangles++; + } + }); + }); + return rectangles; +}; + +// finds connected corners right and down from every corner +var toVertices = function (grid) { + var vertices = []; + grid.forEach(function (row, y) { + row.forEach(function (cell, x) { + if (cell === GLYPH.corner) { + var newVert = new Vertex(); + var side; + + vertices.push(newVert); + grid[y][x] = newVert; // replace glyph with the vertex + for (var u = y - 1; u >= 0; u--) { // search *up* along the side + side = grid[u][x]; + if (side instanceof Vertex) side.down.push(newVert); + else if (side !== GLYPH.edgeV) break; + } + for (var l = x - 1; l >= 0; l--) { // search *left* along the side + side = grid[y][l]; + if (side instanceof Vertex) side.right.push(newVert); + else if (side !== GLYPH.edgeH) break; + } + } + }); + }); + return vertices; +}; + +var rectangles = function (input) { + var grid; + var corners; + + grid = input.map(function (row) { return row.split(''); }); + corners = toVertices(grid); + return corners.reduce(function (total, vert) { + return total + vert.findRectangles(); + }, 0); +}; + +module.exports = rectangles; diff --git a/exercises/rectangles/rectangles.spec.js b/exercises/rectangles/rectangles.spec.js new file mode 100644 index 00000000..af89e07d --- /dev/null +++ b/exercises/rectangles/rectangles.spec.js @@ -0,0 +1,108 @@ +var rectangles = require('./rectangles'); + +describe('Rectangles', function () { + it('no rows', function () { + expect(rectangles([])).toBe(0); + }); + + xit('no columns', function () { + expect(rectangles([''])).toBe(0); + }); + + xit('no rectangles', function () { + expect(rectangles([' '])).toBe(0); + }); + + xit('one rectangle', function () { + var input = [ + '+-+', + '| |', + '+-+']; + expect(rectangles(input)).toBe(1); + }); + + xit('two rectangles without shared parts', function () { + var input = [ + ' +-+', + ' | |', + '+-+-+', + '| | ', + '+-+ ']; + expect(rectangles(input)).toBe(2); + }); + + xit('five rectangles with shared parts', function () { + var input = [ + ' +-+', + ' | |', + '+-+-+', + '| | |', + '+-+-+']; + expect(rectangles(input)).toBe(5); + }); + + xit('rectangle of height 1 is counted', function () { + var input = [ + '+--+', + '+--+']; + expect(rectangles(input)).toBe(1); + }); + + xit('rectangle of width 1 is counted', function () { + var input = [ + '++', + '||', + '++']; + expect(rectangles(input)).toBe(1); + }); + + xit('1x1 square is counted', function () { + var input = [ + '++', + '++']; + expect(rectangles(input)).toBe(1); + }); + + xit('only complete rectangles are counted', function () { + var input = [ + ' +-+', + ' |', + '+-+-+', + '| | -', + '+-+-+']; + expect(rectangles(input)).toBe(1); + }); + + xit('rectangles can be of different sizes', function () { + var input = [ + '+------+----+', + '| | |', + '+---+--+ |', + '| | |', + '+---+-------+']; + expect(rectangles(input)).toBe(3); + }); + + xit('corner is required for a rectangle to be complete', function () { + var input = [ + '+------+----+', + '| | |', + '+------+ |', + '| | |', + '+---+-------+']; + expect(rectangles(input)).toBe(2); + }); + + xit('large input with many rectangles', function () { + var input = [ + '+---+--+----+', + '| +--+----+', + '+---+--+ |', + '| +--+----+', + '+---+--+--+-+', + '+---+--+--+-+', + '+------+ | |', + ' +-+']; + expect(rectangles(input)).toBe(60); + }); +}); diff --git a/exercises/reverse-string/README.md b/exercises/reverse-string/README.md new file mode 100644 index 00000000..f9edf6c5 --- /dev/null +++ b/exercises/reverse-string/README.md @@ -0,0 +1,40 @@ +# Reverse String + +Reverse a string + +For example: +input: "cool" +output: "looc" + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine reverse-string.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Introductory challenge to reverse an input string [https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb](https://medium.freecodecamp.org/how-to-reverse-a-string-in-javascript-in-3-different-ways-75e4763c68cb) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/reverse-string/example.js b/exercises/reverse-string/example.js new file mode 100644 index 00000000..b19b8d8d --- /dev/null +++ b/exercises/reverse-string/example.js @@ -0,0 +1,11 @@ +'use strict'; + +function reverseString(string) { + var revString = ''; + for (var i = string.length - 1; i >= 0; i--) { + revString += string[i]; + } + return revString; +} + +module.exports = reverseString; diff --git a/exercises/reverse-string/reverse-string.spec.js b/exercises/reverse-string/reverse-string.spec.js new file mode 100644 index 00000000..c6d6327c --- /dev/null +++ b/exercises/reverse-string/reverse-string.spec.js @@ -0,0 +1,33 @@ +var reverseString = require('./reverse-string'); + +describe('ReverseString', function () { + it('empty string', function () { + var expected = ''; + var actual = reverseString(''); + expect(actual).toEqual(expected); + }); + + xit('a word', function () { + var expected = 'tobor'; + var actual = reverseString('robot'); + expect(actual).toEqual(expected); + }); + + xit('a capitalized word', function () { + var expected = 'nemaR'; + var actual = reverseString('Ramen'); + expect(actual).toEqual(expected); + }); + + xit('a sentence with punctuation', function () { + var expected = '!yrgnuh ma I'; + var actual = reverseString('I am hungry!'); + expect(actual).toEqual(expected); + }); + + xit('a palindrome', function () { + var expected = 'racecar'; + var actual = reverseString('racecar'); + expect(actual).toEqual(expected); + }); +}); diff --git a/exercises/rna-transcription/README.md b/exercises/rna-transcription/README.md index 53944760..ab942a69 100644 --- a/exercises/rna-transcription/README.md +++ b/exercises/rna-transcription/README.md @@ -1,4 +1,4 @@ -# Rna Transcription +# RNA Transcription Given a DNA strand, return its RNA complement (per RNA transcription). @@ -20,26 +20,29 @@ each nucleotide with its complement: ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine rna-transcription.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/rna-transcription/example.js b/exercises/rna-transcription/example.js index 8198ac20..f8ad9d26 100644 --- a/exercises/rna-transcription/example.js +++ b/exercises/rna-transcription/example.js @@ -1,6 +1,6 @@ 'use strict'; -var DnaTranscriber = function(){}; +var DnaTranscriber = function () {}; var dnaToRna = { G: 'C', @@ -9,15 +9,15 @@ var dnaToRna = { A: 'U' }; -var transcribeDna = function(dna, lookupTable) { - return dna.replace(/./g, function(dnaNucleotide) { +var transcribeDna = function (dna, lookupTable) { + return dna.replace(/./g, function (dnaNucleotide) { if (!(dnaNucleotide in lookupTable)) { throw Error('Invalid input'); } return lookupTable[dnaNucleotide]; }); -} +}; -DnaTranscriber.prototype.toRna = function(dna) { +DnaTranscriber.prototype.toRna = function (dna) { return transcribeDna(dna, dnaToRna); -} +}; module.exports = DnaTranscriber; diff --git a/exercises/rna-transcription/rna-transcription.spec.js b/exercises/rna-transcription/rna-transcription.spec.js index 0306d2a4..81be79b2 100644 --- a/exercises/rna-transcription/rna-transcription.spec.js +++ b/exercises/rna-transcription/rna-transcription.spec.js @@ -1,38 +1,37 @@ var DnaTranscriber = require('./rna-transcription'); var dnaTranscriber = new DnaTranscriber(); -describe('toRna()', function() { - - it('transcribes cytosine to guanine', function() { +describe('toRna()', function () { + it('transcribes cytosine to guanine', function () { expect(dnaTranscriber.toRna('C')).toEqual('G'); }); - xit('transcribes guanine to cytosine', function() { + xit('transcribes guanine to cytosine', function () { expect(dnaTranscriber.toRna('G')).toEqual('C'); }); - xit('transcribes adenine to uracil', function() { + xit('transcribes adenine to uracil', function () { expect(dnaTranscriber.toRna('A')).toEqual('U'); }); - xit('transcribes thymine to adenine', function() { + xit('transcribes thymine to adenine', function () { expect(dnaTranscriber.toRna('T')).toEqual('A'); }); - xit('transcribes all dna nucleotides to their rna complements', function() { + xit('transcribes all dna nucleotides to their rna complements', function () { expect(dnaTranscriber.toRna('ACGTGGTCTTAA')) - .toEqual('UGCACCAGAAUU'); + .toEqual('UGCACCAGAAUU'); }); xit('correctly handles completely invalid input', function () { - expect(function () { dnaTranscriber.toRna('XXX') }).toThrow( - new Error('Invalid input') - ); + expect(function () { dnaTranscriber.toRna('XXX'); }).toThrow( + new Error('Invalid input') + ); }); xit('correctly handles partially invalid input', function () { - expect(function () { dnaTranscriber.toRna('ACGTXXXCTTAA') }).toThrow( - new Error('Invalid input') - ); + expect(function () { dnaTranscriber.toRna('ACGTXXXCTTAA'); }).toThrow( + new Error('Invalid input') + ); }); }); diff --git a/exercises/robot-name/README.md b/exercises/robot-name/README.md index e679b1ad..7b875976 100644 --- a/exercises/robot-name/README.md +++ b/exercises/robot-name/README.md @@ -17,26 +17,29 @@ every existing robot has a unique name. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine robot-name.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/robot-name/example.js b/exercises/robot-name/example.js index 64356a8b..cb3ab616 100644 --- a/exercises/robot-name/example.js +++ b/exercises/robot-name/example.js @@ -1,4 +1,4 @@ -function randomLetter () { +function randomLetter() { var letters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; return letters.charAt(Math.floor(Math.random() * letters.length)); @@ -19,10 +19,10 @@ Robot.prototype = { // This awesome err msg will never see the light of day. ;_; Checking the // length was slowing down the program too much. // -// if (Object.keys(this.constructor.usedNames).length >= 676000) { -// throw new Error("All possible names have been taken. " + -// "Our robots are taking over the world! : D"); -// } + // if (Object.keys(this.constructor.usedNames).length >= 676000) { + // throw new Error("All possible names have been taken. " + + // "Our robots are taking over the world! : D"); + // } var name = randomLetter().toUpperCase(); name += randomLetter().toUpperCase(); @@ -37,9 +37,9 @@ Robot.prototype = { return name; }, - get name () { return this._name; }, + get name() { return this._name; }, - set name (newName) { + set name(newName) { if (!(/^[A-Z]{2}\d{3}$/).test(newName)) { throw new Error('Name must be 2 capital letters followed by 3 ints.'); } @@ -47,7 +47,7 @@ Robot.prototype = { this._name = newName; }, - reset: function() { this.name = this.generateName(); } + reset: function () { this.name = this.generateName(); } }; module.exports = Robot; diff --git a/exercises/robot-name/robot-name.spec.js b/exercises/robot-name/robot-name.spec.js index fb4de6a4..f9b244f5 100644 --- a/exercises/robot-name/robot-name.spec.js +++ b/exercises/robot-name/robot-name.spec.js @@ -1,32 +1,32 @@ var Robot = require('./robot-name'); -describe('Robot', function() { +describe('Robot', function () { // NOTE: The 'beforeEach()' and 'afterEach()' act as setup/teardown for this // test suite. See more: http://jasmine.github.io/2.0/introduction.html var robot; - beforeEach(function() { + beforeEach(function () { robot = new Robot(); }); - afterEach(function() { + afterEach(function () { robot = null; }); - it('has a name', function() { + it('has a name', function () { expect(robot.name).toMatch(/^[A-Z]{2}\d{3}$/); }); - xit('name is the same each time', function() { + xit('name is the same each time', function () { expect(robot.name).toEqual(robot.name); }); - xit('different robots have different names', function() { + xit('different robots have different names', function () { var differentRobot = new Robot(); expect(differentRobot.name).not.toEqual(robot.name); }); - xit('is able to reset the name', function() { + xit('is able to reset the name', function () { var originalName = robot.name; robot.reset(); var newName = robot.name; @@ -34,10 +34,10 @@ describe('Robot', function() { expect(originalName).not.toEqual(newName); }); - xit('should set a unique name after reset', function() { - var i, - numResets = 10000, - usedNames = {}; + xit('should set a unique name after reset', function () { + var i; + var numResets = 10000; + var usedNames = {}; usedNames[robot.name] = true; @@ -48,12 +48,12 @@ describe('Robot', function() { expect(Object.keys(usedNames).length).toEqual(numResets + 1); }); - - //This test is optional. - xit('there can be lots of robots with different names each', function() { - var i, - numRobots = 10000, - usedNames = {}; + + // This test is optional. + xit('there can be lots of robots with different names each', function () { + var i; + var numRobots = 10000; + var usedNames = {}; for (i = 0; i < numRobots; i++) { var newRobot = new Robot(); diff --git a/exercises/robot-simulator/README.md b/exercises/robot-simulator/README.md index cf8731bf..796b4e6e 100644 --- a/exercises/robot-simulator/README.md +++ b/exercises/robot-simulator/README.md @@ -29,26 +29,29 @@ direction it is pointing. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine robot-simulator.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/robot-simulator/example.js b/exercises/robot-simulator/example.js index bca213ad..96bb5c90 100644 --- a/exercises/robot-simulator/example.js +++ b/exercises/robot-simulator/example.js @@ -1,87 +1,85 @@ -var Robot = (function () { - 'use strict'; +'use strict'; - var VALID_DIRECTIONS = ['north', 'east', 'south', 'west'] - var INSTRUCTION_KEYS = { - A: 'advance', - L: 'turnLeft', - R: 'turnRight' - } - - function Robot () { - this.coordinates = [0, 0]; - this.bearing = 'north'; - }; +var VALID_DIRECTIONS = ['north', 'east', 'south', 'west']; +var INSTRUCTION_KEYS = { + A: 'advance', + L: 'turnLeft', + R: 'turnRight' +}; - Robot.prototype.at = function (x, y) { - this.coordinates = [x, y]; - }; +function Robot() { + this.coordinates = [0, 0]; + this.bearing = 'north'; +} - Robot.prototype.orient = function (direction) { - if (VALID_DIRECTIONS.indexOf(direction) === -1) { - throw new Error('Invalid Robot Bearing'); - } +Robot.prototype.at = function (x, y) { + this.coordinates = [x, y]; +}; - this.bearing = direction; - }; +Robot.prototype.orient = function (direction) { + if (VALID_DIRECTIONS.indexOf(direction) === -1) { + throw new Error('Invalid Robot Bearing'); + } - Robot.prototype.advance = function () { - switch (this.bearing) { - case 'north': - this.coordinates[1]++; - break; - case 'east': - this.coordinates[0]++; - break; - case 'south': - this.coordinates[1]--; - break; - case 'west': - this.coordinates[0]--; - break; - }; - }; + this.bearing = direction; +}; - Robot.prototype.turnLeft = function () { - var directionPosition = VALID_DIRECTIONS.indexOf(this.bearing); +Robot.prototype.advance = function () { + switch (this.bearing) { + case 'north': + this.coordinates[1]++; + break; + case 'east': + this.coordinates[0]++; + break; + case 'south': + this.coordinates[1]--; + break; + case 'west': + this.coordinates[0]--; + break; + default: + break; + } +}; - if (directionPosition > 0) { - this.orient(VALID_DIRECTIONS[--directionPosition]); - } else { - this.orient(VALID_DIRECTIONS[VALID_DIRECTIONS.length - 1]); - } - }; +Robot.prototype.turnLeft = function () { + var directionPosition = VALID_DIRECTIONS.indexOf(this.bearing); - Robot.prototype.turnRight = function () { - var directionPosition = VALID_DIRECTIONS.indexOf(this.bearing); + if (directionPosition > 0) { + this.orient(VALID_DIRECTIONS[--directionPosition]); + } else { + this.orient(VALID_DIRECTIONS[VALID_DIRECTIONS.length - 1]); + } +}; - if (directionPosition < (VALID_DIRECTIONS.length - 1)) { - this.orient(VALID_DIRECTIONS[++directionPosition]); - } else { - this.orient(VALID_DIRECTIONS[0]); - } - }; +Robot.prototype.turnRight = function () { + var directionPosition = VALID_DIRECTIONS.indexOf(this.bearing); - Robot.prototype.instructions = function (instructionKeys) { - return instructionKeys.split('') - .map(function (key) { - return INSTRUCTION_KEYS[key]; - }); - }; + if (directionPosition < (VALID_DIRECTIONS.length - 1)) { + this.orient(VALID_DIRECTIONS[++directionPosition]); + } else { + this.orient(VALID_DIRECTIONS[0]); + } +}; - Robot.prototype.place = function (args) { - this.coordinates = [args.x, args.y]; - this.bearing = args.direction; - }; +Robot.prototype.instructions = function (instructionKeys) { + return instructionKeys.split('') + .map(function (key) { + return INSTRUCTION_KEYS[key]; + }); +}; - Robot.prototype.evaluate = function (instructionKeys) { - this.instructions(instructionKeys) - .forEach(function (instruction) { - this[instruction](); - }, this); - }; +Robot.prototype.place = function (args) { + this.coordinates = [args.x, args.y]; + this.bearing = args.direction; +}; - return Robot -})() +Robot.prototype.evaluate = function (instructionKeys) { + this.instructions(instructionKeys) + .forEach(function (instruction) { + this[instruction](); + }, this); +}; module.exports = Robot; diff --git a/exercises/robot-simulator/robot-simulator.spec.js b/exercises/robot-simulator/robot-simulator.spec.js index a94b1446..f69d86f7 100644 --- a/exercises/robot-simulator/robot-simulator.spec.js +++ b/exercises/robot-simulator/robot-simulator.spec.js @@ -1,9 +1,9 @@ var Robot = require('./robot-simulator'); -describe('Robot', function() { +describe('Robot', function () { var robot = new Robot(); - it('robot bearing', function() { + it('robot bearing', function () { var directions = [ 'east', 'west', 'north', 'south' ]; for (var i = 0; i < directions.length; i++) { @@ -13,7 +13,7 @@ describe('Robot', function() { } }); - xit('invalid robot bearing', function() { + xit('invalid robot bearing', function () { var incorrectlyOrientRobot = function () { robot.orient('crood'); }; @@ -21,118 +21,118 @@ describe('Robot', function() { expect(incorrectlyOrientRobot).toThrow(new Error('Invalid Robot Bearing')); }); - xit('turn right from north', function() { + xit('turn right from north', function () { robot.orient('north'); robot.turnRight(); expect(robot.bearing).toEqual('east'); }); - xit('turn right from east', function() { + xit('turn right from east', function () { robot.orient('east'); robot.turnRight(); expect(robot.bearing).toEqual('south'); }); - xit('turn right from south', function() { + xit('turn right from south', function () { robot.orient('south'); robot.turnRight(); expect(robot.bearing).toEqual('west'); }); - xit('turn right from west', function() { + xit('turn right from west', function () { robot.orient('west'); robot.turnRight(); expect(robot.bearing).toEqual('north'); }); - xit('turn left from north', function() { + xit('turn left from north', function () { robot.orient('north'); robot.turnLeft(); expect(robot.bearing).toEqual('west'); }); - xit('turn left from east', function() { + xit('turn left from east', function () { robot.orient('east'); robot.turnLeft(); expect(robot.bearing).toEqual('north'); }); - xit('turn left from south', function() { + xit('turn left from south', function () { robot.orient('south'); robot.turnLeft(); expect(robot.bearing).toEqual('east'); }); - xit('turn left from west', function() { + xit('turn left from west', function () { robot.orient('west'); robot.turnLeft(); expect(robot.bearing).toEqual('south'); }); - xit('robot coordinates', function() { + xit('robot coordinates', function () { robot.at(3, 0); - expect(robot.coordinates).toEqual([3,0]); + expect(robot.coordinates).toEqual([3, 0]); }); - xit('other robot coordinates', function() { + xit('other robot coordinates', function () { robot.at(-2, 5); - expect(robot.coordinates).toEqual([-2,5]); + expect(robot.coordinates).toEqual([-2, 5]); }); - xit('advance when facing north', function() { - robot.at(0,0); + xit('advance when facing north', function () { + robot.at(0, 0); robot.orient('north'); robot.advance(); - expect(robot.coordinates).toEqual([0,1]); + expect(robot.coordinates).toEqual([0, 1]); }); - xit('advance when facing east', function() { - robot.at(0,0); + xit('advance when facing east', function () { + robot.at(0, 0); robot.orient('east'); robot.advance(); - expect(robot.coordinates).toEqual([1,0]); + expect(robot.coordinates).toEqual([1, 0]); }); - xit('advance when facing south', function() { - robot.at(0,0); + xit('advance when facing south', function () { + robot.at(0, 0); robot.orient('south'); robot.advance(); - expect(robot.coordinates).toEqual([0,-1]); + expect(robot.coordinates).toEqual([0, -1]); }); - xit('advance when facing west', function() { - robot.at(0,0); + xit('advance when facing west', function () { + robot.at(0, 0); robot.orient('west'); robot.advance(); - expect(robot.coordinates).toEqual([-1,0]); + expect(robot.coordinates).toEqual([-1, 0]); }); - xit('instructions for turning left', function() { + xit('instructions for turning left', function () { expect(robot.instructions('L')).toEqual(['turnLeft']); }); - xit('instructions for turning right', function() { + xit('instructions for turning right', function () { expect(robot.instructions('R')).toEqual(['turnRight']); }); - xit('instructions for advancing', function() { + xit('instructions for advancing', function () { expect(robot.instructions('A')).toEqual(['advance']); }); - xit('series of instructions', function() { + xit('series of instructions', function () { expect(robot.instructions('RAAL')) .toEqual(['turnRight', 'advance', 'advance', 'turnLeft']); }); - xit('instruct robot', function() { + xit('instruct robot', function () { robot.place({x: -2, y: 1, direction: 'east'}); robot.evaluate('RLAALAL'); - expect(robot.coordinates).toEqual([0,2]); + expect(robot.coordinates).toEqual([0, 2]); expect(robot.bearing).toEqual('west'); }); - xit('instruct many robots', function() { + xit('instruct many robots', function () { var robot1 = new Robot(); var robot2 = new Robot(); var robot3 = new Robot(); diff --git a/exercises/roman-numerals/README.md b/exercises/roman-numerals/README.md index 77174297..ab2f8dc0 100644 --- a/exercises/roman-numerals/README.md +++ b/exercises/roman-numerals/README.md @@ -14,7 +14,7 @@ The Romans wrote numbers using letters - I, V, X, L, C, D, M. (notice these letters have lots of straight lines and are hence easy to hack into stone tablets). -``` +```text 1 => I 10 => X 7 => VII @@ -44,26 +44,29 @@ See also: http://www.novaroma.org/via_romana/numbers.html ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine roman-numerals.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/roman-numerals/example.js b/exercises/roman-numerals/example.js index 8ff668c4..a39d19cc 100644 --- a/exercises/roman-numerals/example.js +++ b/exercises/roman-numerals/example.js @@ -1,28 +1,29 @@ 'use strict'; -module.exports = function(number) { +module.exports = function (number) { var result = ''; + var numbers = number; var mappings = [ {arabic: 1000, roman: 'M'}, - {arabic: 900, roman: 'CM'}, - {arabic: 500, roman: 'D'}, - {arabic: 400, roman: 'CD'}, - {arabic: 100, roman: 'C'}, - {arabic: 90, roman: 'XC'}, - {arabic: 50, roman: 'L'}, - {arabic: 40, roman: 'XL'}, - {arabic: 10, roman: 'X'}, - {arabic: 9, roman: 'IX'}, - {arabic: 5, roman: 'V'}, - {arabic: 4, roman: 'IV'}, - {arabic: 1, roman: 'I'} + {arabic: 900, roman: 'CM'}, + {arabic: 500, roman: 'D'}, + {arabic: 400, roman: 'CD'}, + {arabic: 100, roman: 'C'}, + {arabic: 90, roman: 'XC'}, + {arabic: 50, roman: 'L'}, + {arabic: 40, roman: 'XL'}, + {arabic: 10, roman: 'X'}, + {arabic: 9, roman: 'IX'}, + {arabic: 5, roman: 'V'}, + {arabic: 4, roman: 'IV'}, + {arabic: 1, roman: 'I'} ]; - for (var i=0; i < mappings.length; i++) { + for (var i = 0; i < mappings.length; i++) { var mapping = mappings[i]; - while (number >= mapping.arabic) { + while (numbers >= mapping.arabic) { result = result + mapping.roman; - number = number - mapping.arabic; + numbers = numbers - mapping.arabic; } } diff --git a/exercises/roman-numerals/roman-numerals.spec.js b/exercises/roman-numerals/roman-numerals.spec.js index cc81660b..539ed665 100644 --- a/exercises/roman-numerals/roman-numerals.spec.js +++ b/exercises/roman-numerals/roman-numerals.spec.js @@ -1,75 +1,75 @@ var toRoman = require('./roman-numerals'); -describe('toRoman()', function() { - it('converts 1', function() { +describe('toRoman()', function () { + it('converts 1', function () { expect(toRoman(1)).toEqual('I'); }); - xit('converts 2', function() { + xit('converts 2', function () { expect(toRoman(2)).toEqual('II'); }); - xit('converts 3', function() { + xit('converts 3', function () { expect(toRoman(3)).toEqual('III'); }); - xit('converts 4', function() { + xit('converts 4', function () { expect(toRoman(4)).toEqual('IV'); }); - xit('converts 5', function() { + xit('converts 5', function () { expect(toRoman(5)).toEqual('V'); }); - xit('converts 6', function() { + xit('converts 6', function () { expect(toRoman(6)).toEqual('VI'); }); - xit('converts 9', function() { + xit('converts 9', function () { expect(toRoman(9)).toEqual('IX'); }); - xit('converts 27', function() { + xit('converts 27', function () { expect(toRoman(27)).toEqual('XXVII'); }); - xit('converts 48', function() { + xit('converts 48', function () { expect(toRoman(48)).toEqual('XLVIII'); }); - xit('converts 59', function() { + xit('converts 59', function () { expect(toRoman(59)).toEqual('LIX'); }); - xit('converts 93', function() { + xit('converts 93', function () { expect(toRoman(93)).toEqual('XCIII'); }); - xit('converts 141', function() { + xit('converts 141', function () { expect(toRoman(141)).toEqual('CXLI'); }); - xit('converts 163', function() { + xit('converts 163', function () { expect(toRoman(163)).toEqual('CLXIII'); }); - xit('converts 402', function() { + xit('converts 402', function () { expect(toRoman(402)).toEqual('CDII'); }); - xit('converts 575', function() { + xit('converts 575', function () { expect(toRoman(575)).toEqual('DLXXV'); }); - xit('converts 911', function() { + xit('converts 911', function () { expect(toRoman(911)).toEqual('CMXI'); }); - xit('converts 1024', function() { + xit('converts 1024', function () { expect(toRoman(1024)).toEqual('MXXIV'); }); - xit('converts 3000', function() { + xit('converts 3000', function () { expect(toRoman(3000)).toEqual('MMM'); }); }); diff --git a/exercises/rotational-cipher/README.md b/exercises/rotational-cipher/README.md new file mode 100644 index 00000000..01384ca3 --- /dev/null +++ b/exercises/rotational-cipher/README.md @@ -0,0 +1,64 @@ +# Rotational Cipher + +Create an implementation of the rotational cipher, also sometimes called the Caesar cipher. + +The Caesar cipher is a simple shift cipher that relies on +transposing all the letters in the alphabet using an integer key +between `0` and `26`. Using a key of `0` or `26` will always yield +the same output due to modular arithmetic. The letter is shifted +for as many values as the value of the key. + +The general notation for rotational ciphers is `ROT + `. +The most commonly used rotational cipher is `ROT13`. + +A `ROT13` on the Latin alphabet would be as follows: + +```text +Plain: abcdefghijklmnopqrstuvwxyz +Cipher: nopqrstuvwxyzabcdefghijklm +``` + +It is stronger than the Atbash cipher because it has 27 possible keys, and 25 usable keys. + +Ciphertext is written out in the same formatting as the input including spaces and punctuation. + +## Examples + +- ROT5 `omg` gives `trl` +- ROT0 `c` gives `c` +- ROT26 `Cool` gives `Cool` +- ROT13 `The quick brown fox jumps over the lazy dog.` gives `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` +- ROT13 `Gur dhvpx oebja sbk whzcf bire gur ynml qbt.` gives `The quick brown fox jumps over the lazy dog.` + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine rotational-cipher.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Wikipedia [https://en.wikipedia.org/wiki/Caesar_cipher](https://en.wikipedia.org/wiki/Caesar_cipher) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/rotational-cipher/example.js b/exercises/rotational-cipher/example.js new file mode 100644 index 00000000..fa3e7baa --- /dev/null +++ b/exercises/rotational-cipher/example.js @@ -0,0 +1,24 @@ +var RotationalCipher = function () {}; + +RotationalCipher.prototype.rotate = function (text, shiftKey) { + if (text.length === 1) { + if (text.charCodeAt(0) >= 97 && text.charCodeAt(0) <= 122) return this.rotateLowerCase(text, shiftKey); + if (text.charCodeAt(0) >= 65 && text.charCodeAt(0) <= 90) return this.rotateUpperCase(text, shiftKey); + return text; + } + return this.rotate(text.charAt(0), shiftKey) + this.rotate(text.slice(1), shiftKey); +}; + +RotationalCipher.prototype.rotateLowerCase = function (letter, shiftKey) { + var rotatedLowerCase = String.fromCharCode(letter.charCodeAt(0) + shiftKey); + if (rotatedLowerCase.charCodeAt(0) > 122) rotatedLowerCase = String.fromCharCode(rotatedLowerCase.charCodeAt(0) - 26); + return rotatedLowerCase; +}; + +RotationalCipher.prototype.rotateUpperCase = function (letter, shiftKey) { + var rotatedUpperCase = String.fromCharCode(letter.charCodeAt(0) + shiftKey); + if (rotatedUpperCase.charCodeAt(0) > 90) rotatedUpperCase = String.fromCharCode(rotatedUpperCase.charCodeAt(0) - 26); + return rotatedUpperCase; +}; + +module.exports = RotationalCipher; diff --git a/exercises/rotational-cipher/rotational-cipher.spec.js b/exercises/rotational-cipher/rotational-cipher.spec.js new file mode 100644 index 00000000..5e6f864d --- /dev/null +++ b/exercises/rotational-cipher/rotational-cipher.spec.js @@ -0,0 +1,55 @@ +var RotationalCipher = require('./rotational-cipher'); + +describe('RotationalCipher', function () { + var rotationalCipher = new RotationalCipher(); + + it('rotate a by 0, same output as input', function () { + var expected = 'a'; + expect(rotationalCipher.rotate('a', 0)).toEqual(expected); + }); + + xit('rotate a by 1', function () { + var expected = 'b'; + expect(rotationalCipher.rotate('a', 1)).toEqual(expected); + }); + + xit('rotate a by 26, same output as input', function () { + var expected = 'a'; + expect(rotationalCipher.rotate('a', 26)).toEqual(expected); + }); + + xit('rotate m by 13', function () { + var expected = 'z'; + expect(rotationalCipher.rotate('m', 13)).toEqual(expected); + }); + + xit('rotate n by 13 with wrap around alphabet', function () { + var expected = 'a'; + expect(rotationalCipher.rotate('n', 13)).toEqual(expected); + }); + + xit('rotate capital letters', function () { + var expected = 'TRL'; + expect(rotationalCipher.rotate('OMG', 5)).toEqual(expected); + }); + + xit('rotate spaces', function () { + var expected = 'T R L'; + expect(rotationalCipher.rotate('O M G', 5)).toEqual(expected); + }); + + xit('rotate numbers', function () { + var expected = 'Xiwxmrk 1 2 3 xiwxmrk'; + expect(rotationalCipher.rotate('Testing 1 2 3 testing', 4)).toEqual(expected); + }); + + xit('rotate punctuation', function () { + var expected = 'Gzo\'n zvo, Bmviyhv!'; + expect(rotationalCipher.rotate('Let\'s eat, Grandma!', 21)).toEqual(expected); + }); + + xit('rotate all letters', function () { + var expected = 'Gur dhvpx oebja sbk whzcf bire gur ynml qbt.'; + expect(rotationalCipher.rotate('The quick brown fox jumps over the lazy dog.', 13)).toEqual(expected); + }); +}); diff --git a/exercises/run-length-encoding/README.md b/exercises/run-length-encoding/README.md index e91fd159..e4499e71 100644 --- a/exercises/run-length-encoding/README.md +++ b/exercises/run-length-encoding/README.md @@ -7,44 +7,47 @@ Run-length encoding (RLE) is a simple form of data compression, where runs For example we can represent the original 53 characters with only 13. -``` +```text "WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB" -> "12WB12W3B24WB" ``` RLE allows the original data to be perfectly reconstructed from the compressed data, which makes it a lossless data compression. -``` +```text "AABCCCDEEEE" -> "2AB3CD4E" -> "AABCCCDEEEE" ``` For simplicity, you can assume that the unencoded string will only contain -the letters A through Z (either lower or upper case) and whitespace. This way -data to be encoded will never contain any numbers and numbers inside data to +the letters A through Z (either lower or upper case) and whitespace. This way +data to be encoded will never contain any numbers and numbers inside data to be decoded always represent the count for the following character. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine run-length-encoding.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/run-length-encoding/example.js b/exercises/run-length-encoding/example.js index 6a900cc4..4e4447d4 100644 --- a/exercises/run-length-encoding/example.js +++ b/exercises/run-length-encoding/example.js @@ -1,11 +1,11 @@ exports.encode = function encode(plaintext) { - return plaintext.replace(/([\w\s])\1*/g, function(match) { - return match.length > 1 ? match.length + match[0] : match[0]; - }); + return plaintext.replace(/([\w\s])\1*/g, function (match) { + return match.length > 1 ? match.length + match[0] : match[0]; + }); }; exports.decode = function decode(cypher) { - return cypher.replace(/(\d+)(\w|\s)/g, function(match, repeats, char) { - return new Array(+repeats + 1).join(char); - }); + return cypher.replace(/(\d+)(\w|\s)/g, function (match, repeats, char) { + return new Array(+repeats + 1).join(char); + }); }; diff --git a/exercises/run-length-encoding/run-length-encoding.spec.js b/exercises/run-length-encoding/run-length-encoding.spec.js index bfd56787..a18e61ac 100644 --- a/exercises/run-length-encoding/run-length-encoding.spec.js +++ b/exercises/run-length-encoding/run-length-encoding.spec.js @@ -1,41 +1,39 @@ var RLE = require('./run-length-encoding'); -describe('Run-length encoding', function() { - - it('encode empty string', function() { - expect(RLE.encode('')).toEqual(''); - }); - - xit('encode single characters only', function() { - expect(RLE.encode('XYZ')).toEqual('XYZ'); - }); - - xit('decode empty string', function() { - expect(RLE.decode('')).toEqual(''); - }); - - xit('decode single characters only', function() { - expect(RLE.decode('XYZ')).toEqual('XYZ'); - }); - - xit('encode simple', function() { - expect(RLE.encode('AABBBCCCC')).toEqual('2A3B4C'); - }); - - xit('decode simple', function() { - expect(RLE.decode('2A3B4C')).toEqual('AABBBCCCC'); - }); - - xit('encode with single values', function() { - expect(RLE.encode('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB')).toEqual('12WB12W3B24WB'); - }); - - xit('decode with single values', function() { - expect(RLE.decode('12WB12W3B24WB')).toEqual('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB'); - }); - - xit('decode(encode(...))combination', function() { - expect(RLE.decode(RLE.encode('zzz ZZ zZ'))).toEqual('zzz ZZ zZ'); - }); - +describe('Run-length encoding', function () { + it('encode empty string', function () { + expect(RLE.encode('')).toEqual(''); + }); + + xit('encode single characters only', function () { + expect(RLE.encode('XYZ')).toEqual('XYZ'); + }); + + xit('decode empty string', function () { + expect(RLE.decode('')).toEqual(''); + }); + + xit('decode single characters only', function () { + expect(RLE.decode('XYZ')).toEqual('XYZ'); + }); + + xit('encode simple', function () { + expect(RLE.encode('AABBBCCCC')).toEqual('2A3B4C'); + }); + + xit('decode simple', function () { + expect(RLE.decode('2A3B4C')).toEqual('AABBBCCCC'); + }); + + xit('encode with single values', function () { + expect(RLE.encode('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB')).toEqual('12WB12W3B24WB'); + }); + + xit('decode with single values', function () { + expect(RLE.decode('12WB12W3B24WB')).toEqual('WWWWWWWWWWWWBWWWWWWWWWWWWBBBWWWWWWWWWWWWWWWWWWWWWWWWB'); + }); + + xit('decode(encode(...))combination', function () { + expect(RLE.decode(RLE.encode('zzz ZZ zZ'))).toEqual('zzz ZZ zZ'); + }); }); diff --git a/exercises/saddle-points/README.md b/exercises/saddle-points/README.md index 24a59c28..aa61f4cd 100644 --- a/exercises/saddle-points/README.md +++ b/exercises/saddle-points/README.md @@ -4,7 +4,7 @@ Detect saddle points in a matrix. So say you have a matrix like so: -```plain +```text 0 1 2 |--------- 0 | 9 8 7 @@ -15,7 +15,7 @@ So say you have a matrix like so: It has a saddle point at (1, 0). It's called a "saddle point" because it is greater than or equal to -every element in its row and the less than or equal to every element in +every element in its row and less than or equal to every element in its column. A matrix may have zero or more saddle points. @@ -28,26 +28,29 @@ but the tests for this exercise follow the above unambiguous definition. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine saddle-points.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/saddle-points/example.js b/exercises/saddle-points/example.js index 80e562b1..ac1cde4f 100644 --- a/exercises/saddle-points/example.js +++ b/exercises/saddle-points/example.js @@ -1,83 +1,59 @@ 'use strict'; -function toInt(s) { - return parseInt(s, 10); -} - module.exports = function Matrix(matrix) { - this.rows = []; - this.columns = []; - - var rows = matrix.split('\n'); - var i, j, currentRow; - - for (i = 0; i < rows.length; i++) { - currentRow = rows[i].replace(/^\s+|\s+$/g,'').split(' ').map( toInt ); - this.rows.push(currentRow); - } - - for (i = 0; i < this.rows[0].length; i++) { - this.columns.push([]); - } - - for (i = 0; i < this.rows.length; i++) { - for (j = 0; j < this.columns.length; j++) { - this.columns[j].push(this.rows[i][j]); - } - } - - this.indexesOfMaxValues = function(array) { - var i, currentElement, maxValue, indexes = []; - - for (i = 0; i < array.length; i++) { - currentElement = array[i]; - if (maxValue === undefined || currentElement > maxValue) { - maxValue = currentElement; - indexes = [i]; - } else if (currentElement === maxValue) { - indexes.push(i); - } - } - - return indexes; + this.rows = matrix.split('\n').map(function (row) { + return row.split(' ').map(function (val) { return parseInt(val, 10); }); + }); + + this.columns = this.rows[0].map(function () { + return []; + }).map(function (column, index) { + return this.rows.map(function (row) { return row[index]; }); + }, this); + + this.indexesOfMaxValues = function (array) { + var maxValue = array.reduce(function (acc, curr) { + return Math.max(acc, curr); + }); + + return this.indexsOf(array, maxValue); }; - this.indexesOfMinValues = function(array) { - var i, currentElement, minValue, indexes = []; - - for (i = 0; i < array.length; i++) { - currentElement = array[i]; - if (minValue === undefined || currentElement < minValue) { - minValue = currentElement; - indexes = [i]; - } else if (currentElement === minValue) { - indexes.push(i); - } - } + this.indexesOfMinValues = function (array) { + var minValue = array.reduce(function (acc, curr) { + return Math.min(acc, curr); + }); - return indexes; + return this.indexsOf(array, minValue); }; - this.calculateSaddlePoints = function(rows,columns) { - var i, j, maxIndexes, minIndexes, currentMaxIndex, saddlePoints = []; - - for (i = 0; i < rows.length; i++) { + this.indexsOf = function (array, value) { + return array.map(function (val, index) { + return val === value ? index : null; + }).filter(function (val) { + return val !== null; + }); + }; - maxIndexes = this.indexesOfMaxValues(rows[i]); + this.calculateSaddlePoints = function (rows, columns) { + var maxIndexes; + var minIndexes; + var saddlePoints = []; - for (j = 0; j < maxIndexes.length; j++) { + rows.forEach(function (row, i) { + maxIndexes = this.indexesOfMaxValues(row); - currentMaxIndex = maxIndexes[j]; + maxIndexes.forEach(function (currentMaxIndex) { minIndexes = this.indexesOfMinValues(columns[currentMaxIndex]); if (minIndexes.indexOf(i) >= 0) { saddlePoints.push([i, currentMaxIndex]); } - } + }, this); + }, this); - } return saddlePoints; }; - this.saddlePoints = this.calculateSaddlePoints(this.rows,this.columns); -}; \ No newline at end of file + this.saddlePoints = this.calculateSaddlePoints(this.rows, this.columns); +}; diff --git a/exercises/saddle-points/saddle-points.spec.js b/exercises/saddle-points/saddle-points.spec.js index 35f5c31c..836a8cbb 100644 --- a/exercises/saddle-points/saddle-points.spec.js +++ b/exercises/saddle-points/saddle-points.spec.js @@ -1,42 +1,42 @@ var Matrix = require('./saddle-points'); -describe('Matrix', function() { - it('extracts a row', function() { +describe('Matrix', function () { + it('extracts a row', function () { var matrix = new Matrix('1 2\n10 20'); - expect(matrix.rows[0]).toEqual([1,2]); + expect(matrix.rows[0]).toEqual([1, 2]); }); - xit('extracts other row', function() { + xit('extracts other row', function () { var matrix = new Matrix('9 8 7\n19 18 17'); expect(matrix.rows[1]).toEqual([19, 18, 17]); }); - xit('extracts a column', function() { + xit('extracts a column', function () { var matrix = new Matrix('1 2 3\n4 5 6\n7 8 9\n8 7 6'); expect(matrix.columns[0]).toEqual([1, 4, 7, 8]); }); - xit('extracts another column', function() { + xit('extracts another column', function () { var matrix = new Matrix('89 1903 3\n18 3 1\n9 4 800'); expect(matrix.columns[1]).toEqual([1903, 3, 4]); }); - xit('no saddle point', function() { + xit('no saddle point', function () { var matrix = new Matrix('2 1\n1 2'); expect(matrix.saddlePoints).toEqual([]); }); - xit('a saddle point', function() { + xit('a saddle point', function () { var matrix = new Matrix('1 2\n3 4'); - expect(matrix.saddlePoints).toEqual([[0,1]]); + expect(matrix.saddlePoints).toEqual([[0, 1]]); }); - xit('another saddle point', function() { + xit('another saddle point', function () { var matrix = new Matrix('18 3 39 19 91\n38 10 8 77 320\n3 4 8 6 7'); - expect(matrix.saddlePoints).toEqual([[2,2]]); + expect(matrix.saddlePoints).toEqual([[2, 2]]); }); - xit('multiple saddle points', function() { + xit('multiple saddle points', function () { var matrix = new Matrix('4 5 4\n3 5 5\n1 5 4'); expect(matrix.saddlePoints).toEqual([[0, 1], [1, 1], [2, 1]]); }); diff --git a/exercises/say/README.md b/exercises/say/README.md index 7be49a95..bd67005b 100644 --- a/exercises/say/README.md +++ b/exercises/say/README.md @@ -64,26 +64,29 @@ Use _and_ (correctly) when spelling out the number in English: ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine say.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/say/example.js b/exercises/say/example.js index 3b00023d..0b96b824 100644 --- a/exercises/say/example.js +++ b/exercises/say/example.js @@ -1,16 +1,16 @@ 'use strict'; var smallNumbers = { - 0 : 'zero', - 1 : 'one', - 2 : 'two', - 3 : 'three', - 4 : 'four', - 5 : 'five', - 6 : 'six', - 7 : 'seven', - 8 : 'eight', - 9 : 'nine', + 0: 'zero', + 1: 'one', + 2: 'two', + 3: 'three', + 4: 'four', + 5: 'five', + 6: 'six', + 7: 'seven', + 8: 'eight', + 9: 'nine', 10: 'ten', 11: 'eleven', 12: 'twelve', @@ -35,18 +35,19 @@ var decades = { }; var bigNumbers = { - 1000: 'thousand', - 1000000: 'million', + 1000: 'thousand', + 1000000: 'million', 1000000000: 'billion' }; function bigPart(number) { - var factor, result = ''; + var factor; + var result = ''; for (var bigNumber = 1000000000; bigNumber >= 1000; bigNumber /= 1000) { if (number.current >= bigNumber) { - factor = Math.floor(number.current/bigNumber); + factor = Math.floor(number.current / bigNumber); result += threeDigit(factor) + ' ' + bigNumbers[bigNumber] + ' '; - number.current = number.current-(factor*bigNumber); + number.current = number.current - (factor * bigNumber); } } return result; @@ -55,9 +56,10 @@ function bigPart(number) { function sayDecade(n) { for (var decade = 90; decade >= 20; decade -= 10) { if (n >= decade) { - return decades[decade] + '-' + smallNumbers[n-decade]; + return decades[decade] + '-' + smallNumbers[n - decade]; } } + throw new Error('Number must be between 10 and 99.'); } function twoDigit(n) { @@ -73,18 +75,17 @@ function twoDigit(n) { function threeDigit(n) { if (n < 100) { return twoDigit(n); - } else { - return smallNumbers[Math.floor(n/100)] + ' hundred ' + twoDigit(n%100); } + return smallNumbers[Math.floor(n / 100)] + ' hundred ' + twoDigit(n % 100); } exports.inEnglish = function (n) { - var result, number = {current: n}; - if (0 <= n && n < 1000000000000) { + var result; + var number = {current: n}; + if (n >= 0 && n < 1000000000000) { result = bigPart(number); result += threeDigit(number.current); return result.replace(/.zero/, ''); - } else { - throw new Error('Number must be between 0 and 999,999,999,999.'); } -}; \ No newline at end of file + throw new Error('Number must be between 0 and 999,999,999,999.'); +}; diff --git a/exercises/say/say.spec.js b/exercises/say/say.spec.js index d638be89..729b6324 100644 --- a/exercises/say/say.spec.js +++ b/exercises/say/say.spec.js @@ -1,7 +1,6 @@ var say = require('./say'); describe('say', function () { - it('zero', function () { expect(say.inEnglish(0)).toBe('zero'); }); @@ -74,5 +73,4 @@ describe('say', function () { say.inEnglish(1000000000000); }).toThrow(new Error('Number must be between 0 and 999,999,999,999.')); }); - -}); \ No newline at end of file +}); diff --git a/exercises/scrabble-score/README.md b/exercises/scrabble-score/README.md index b0592bef..59b1d90d 100644 --- a/exercises/scrabble-score/README.md +++ b/exercises/scrabble-score/README.md @@ -6,7 +6,7 @@ Given a word, compute the scrabble score for that word. You'll need these: -```plain +```text Letter Value A, E, I, O, U, L, N, R, S, T 1 D, G 2 @@ -18,6 +18,7 @@ Q, Z 10 ``` ## Examples + "cabbage" should be scored as worth 14 points: - 3 points for C @@ -34,31 +35,35 @@ And to total: - = 14 ## Extensions + - You can play a double or a triple letter. - You can play a double or a triple word. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine scrabble-score.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/scrabble-score/example.js b/exercises/scrabble-score/example.js index 7c116e96..be6cd36c 100644 --- a/exercises/scrabble-score/example.js +++ b/exercises/scrabble-score/example.js @@ -1,22 +1,21 @@ 'use strict'; var letterScores = { - 'a' : 1, 'e' : 1, 'i' : 1, 'o' : 1, - 'u' : 1, 'l' : 1, 'n' : 1, 'r' : 1, - 's' : 1, 't' : 1, 'd' : 2, 'g' : 2, - 'b' : 3, 'c' : 3, 'm' : 3, 'p' : 3, - 'f' : 4, 'h' : 4, 'v' : 4, 'w' : 4, - 'y' : 4, 'k' : 5, 'j' : 8, 'x' : 8, - 'q' : 10, 'z' : 10 + 'a': 1, 'e': 1, 'i': 1, 'o': 1, + 'u': 1, 'l': 1, 'n': 1, 'r': 1, + 's': 1, 't': 1, 'd': 2, 'g': 2, + 'b': 3, 'c': 3, 'm': 3, 'p': 3, + 'f': 4, 'h': 4, 'v': 4, 'w': 4, + 'y': 4, 'k': 5, 'j': 8, 'x': 8, + 'q': 10, 'z': 10 }; function letterScore(letter) { return letterScores[letter] || 0; } -module.exports = function(word) { - word || (word = ''); - word = word.toLowerCase(); +module.exports = function (wrd) { + var word = wrd ? wrd.toLowerCase() : ''; var sum = 0; var idx = -1; diff --git a/exercises/scrabble-score/scrabble-score.spec.js b/exercises/scrabble-score/scrabble-score.spec.js index dc9a8787..45c30b7e 100644 --- a/exercises/scrabble-score/scrabble-score.spec.js +++ b/exercises/scrabble-score/scrabble-score.spec.js @@ -1,27 +1,27 @@ var score = require('./scrabble-score'); -describe('Scrabble', function() { - it('scores an empty word as zero',function() { +describe('Scrabble', function () { + it('scores an empty word as zero', function () { expect(score('')).toEqual(0); }); - xit('scores a null as zero',function() { + xit('scores a null as zero', function () { expect(score(null)).toEqual(0); }); - xit('scores a very short word',function() { + xit('scores a very short word', function () { expect(score('a')).toEqual(1); }); - xit('scores the word by the number of letters',function() { + xit('scores the word by the number of letters', function () { expect(score('street')).toEqual(6); }); - xit('scores more complicated words with more',function() { + xit('scores more complicated words with more', function () { expect(score('quirky')).toEqual(22); }); - xit('scores case insensitive words',function() { + xit('scores case insensitive words', function () { expect(score('OXYPHENBUTAZONE')).toEqual(41); }); }); diff --git a/exercises/secret-handshake/README.md b/exercises/secret-handshake/README.md index dfdd361c..15e4d426 100644 --- a/exercises/secret-handshake/README.md +++ b/exercises/secret-handshake/README.md @@ -6,7 +6,7 @@ You and your fellow cohort of those in the "know" when it comes to binary decide to come up with a secret "handshake". -``` +```text 1 = wink 10 = double blink 100 = close your eyes @@ -30,30 +30,33 @@ has caused the array to be reversed. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine secret-handshake.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source -Bert, in Mary Poppins [http://www.imdb.com/character/ch0011238/quotes](http://www.imdb.com/character/ch0011238/quotes) +Bert, in Mary Poppins [http://www.imdb.com/title/tt0058331/quotes/qt0437047](http://www.imdb.com/title/tt0058331/quotes/qt0437047) ## Submitting Incomplete Solutions It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/secret-handshake/example.js b/exercises/secret-handshake/example.js index b6ceb788..873ccc97 100644 --- a/exercises/secret-handshake/example.js +++ b/exercises/secret-handshake/example.js @@ -8,17 +8,16 @@ function SecretHandshake(handshake) { throw new Error('Handshake must be a number'); } - this.commands = function() { + this.commands = function () { return this.shakeWith; }; - this.calculateHandshake = function(handshake) { - /*jshint bitwise:false */ + this.calculateHandshake = function () { var shakeWith = []; for (var i = 0; i < handshakeCommands.length; i++) { var currentCommand = handshakeCommands[i]; - var handshakeHasCommand = (handshake & Math.pow(2,i)); + var handshakeHasCommand = (handshake & Math.pow(2, i)); if (handshakeHasCommand) { if (currentCommand === 'REVERSE') { @@ -33,7 +32,6 @@ function SecretHandshake(handshake) { }; this.shakeWith = this.calculateHandshake(handshake); - } -module.exports = SecretHandshake; \ No newline at end of file +module.exports = SecretHandshake; diff --git a/exercises/secret-handshake/secret-handshake.spec.js b/exercises/secret-handshake/secret-handshake.spec.js index dd9b0ded..bf5fc41d 100644 --- a/exercises/secret-handshake/secret-handshake.spec.js +++ b/exercises/secret-handshake/secret-handshake.spec.js @@ -1,44 +1,45 @@ var SecretHandshake = require('./secret-handshake'); -describe('Secret Handshake', function() { - it('1 is a wink', function() { +describe('Secret Handshake', function () { + it('1 is a wink', function () { var handshake = new SecretHandshake(1); expect(handshake.commands()).toEqual(['wink']); }); - xit('10 is a double blink', function() { + xit('10 is a double blink', function () { var handshake = new SecretHandshake(2); expect(handshake.commands()).toEqual(['double blink']); }); - xit('100 is close your eyes', function() { + xit('100 is close your eyes', function () { var handshake = new SecretHandshake(4); expect(handshake.commands()).toEqual(['close your eyes']); }); - xit('1000 is jump', function() { + xit('1000 is jump', function () { var handshake = new SecretHandshake(8); expect(handshake.commands()).toEqual(['jump']); }); - xit('11 is wink and double blink', function() { + xit('11 is wink and double blink', function () { var handshake = new SecretHandshake(3); - expect(handshake.commands()).toEqual(['wink','double blink']); + expect(handshake.commands()).toEqual(['wink', 'double blink']); }); - xit('10011 is double blink and wink', function() { + xit('10011 is double blink and wink', function () { var handshake = new SecretHandshake(19); - expect(handshake.commands()).toEqual(['double blink','wink']); + expect(handshake.commands()).toEqual(['double blink', 'wink']); }); - xit('11111 is jump, close your eyes, double blink, and wink', function() { + xit('11111 is jump, close your eyes, double blink, and wink', function () { var handshake = new SecretHandshake(31); - expect(handshake.commands()).toEqual(['jump','close your eyes','double blink','wink']); + expect(handshake.commands()).toEqual(['jump', 'close your eyes', 'double blink', 'wink']); }); - xit('text is an invalid secret handshake', function() { + xit('text is an invalid secret handshake', function () { expect( function () { - var handshake = new SecretHandshake('piggies'); + /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "[iI]gnored" }]*/ + var ignoredHandshake = new SecretHandshake('piggies'); }).toThrow(new Error('Handshake must be a number')); }); }); diff --git a/exercises/series/README.md b/exercises/series/README.md index 81133429..752330d4 100644 --- a/exercises/series/README.md +++ b/exercises/series/README.md @@ -22,26 +22,29 @@ in the input; the digits need not be *numerically consecutive*. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine series.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/series/example.js b/exercises/series/example.js index 448c59d5..dd05784d 100644 --- a/exercises/series/example.js +++ b/exercises/series/example.js @@ -18,10 +18,10 @@ Series.prototype.slices = function (sliceSize) { if (sliceSize > this.digits.length) { throw new Error('Slice size is too big.'); } - + for (var i = 0; i < this.digits.length - sliceSize + 1; i++) { for (var j = 0; j < sliceSize; j++) { - slice.push(this.digits[i+j]); + slice.push(this.digits[i + j]); } result.push(slice); slice = []; @@ -30,4 +30,4 @@ Series.prototype.slices = function (sliceSize) { return result; }; -module.exports = Series; \ No newline at end of file +module.exports = Series; diff --git a/exercises/series/series.spec.js b/exercises/series/series.spec.js index 6cae7a56..10b783c2 100644 --- a/exercises/series/series.spec.js +++ b/exercises/series/series.spec.js @@ -1,7 +1,6 @@ var Series = require('./series'); describe('Series', function () { - it('has digits (short)', function () { expect(new Series('01234').digits).toEqual([0, 1, 2, 3, 4]); }); @@ -56,5 +55,4 @@ describe('Series', function () { new Series('01032987583').slices(12); }).toThrow(new Error('Slice size is too big.')); }); - -}); \ No newline at end of file +}); diff --git a/exercises/sieve/README.md b/exercises/sieve/README.md index b64850a4..33f66f28 100644 --- a/exercises/sieve/README.md +++ b/exercises/sieve/README.md @@ -29,26 +29,29 @@ correct list of primes. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine sieve.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/sieve/example.js b/exercises/sieve/example.js index 6282ef9b..3684753f 100644 --- a/exercises/sieve/example.js +++ b/exercises/sieve/example.js @@ -1,7 +1,8 @@ 'use strict'; function newArrayWithRange(first, last) { - var i, array = []; + var i; + var array = []; for ( i = first; i <= last; i++ ) { array.push(i); } @@ -13,7 +14,9 @@ function indivisibleBy(value) { } function sieve(n) { - var i, prime, possibilities, primes = []; + var prime; + var possibilities; + var primes = []; possibilities = newArrayWithRange(2, n); @@ -28,4 +31,4 @@ function sieve(n) { module.exports = function (n) { this.primes = sieve(n); -}; \ No newline at end of file +}; diff --git a/exercises/sieve/sieve.spec.js b/exercises/sieve/sieve.spec.js index 16a4d8b5..b5f1c299 100644 --- a/exercises/sieve/sieve.spec.js +++ b/exercises/sieve/sieve.spec.js @@ -1,17 +1,15 @@ var Sieve = require('./sieve'); -describe('Sieve', function() { - - it('finds primes up to 10', function() { +describe('Sieve', function () { + it('finds primes up to 10', function () { expect(new Sieve(10).primes).toEqual([2, 3, 5, 7]); }); - xit('finds primes up to 13, and considers the limit passed in', function() { + xit('finds primes up to 13, and considers the limit passed in', function () { expect(new Sieve(13).primes).toEqual([2, 3, 5, 7, 11, 13]); }); - xit('finds primes up to 1000', function() { + xit('finds primes up to 1000', function () { expect(new Sieve(1000).primes).toEqual([2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829, 839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947, 953, 967, 971, 977, 983, 991, 997]); }); - }); diff --git a/exercises/simple-cipher/README.md b/exercises/simple-cipher/README.md index 37536369..e0ee4353 100644 --- a/exercises/simple-cipher/README.md +++ b/exercises/simple-cipher/README.md @@ -58,15 +58,13 @@ would get the same thing as the Caesar Cipher. The weakest link in any cipher is the human being. Let's make your substitution cipher a little more fault tolerant by providing a source -of randomness and ensuring that the key is not composed of numbers or -capital letters. +of randomness and ensuring that the key contains only lowercase letters. If someone doesn't submit a key at all, generate a truly random key of -at least 100 characters in length, accessible via Cipher#key (the # -syntax means instance variable) +at least 100 characters in length. -If the key submitted has capital letters or numbers, throw an -ArgumentError with a message to that effect. +If the key submitted is not composed only of lowercase letters, your +solution should handle the error in a language-appropriate way. ## Extensions @@ -85,26 +83,29 @@ on Wikipedia][dh] for one of the first implementations of this scheme. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine simple-cipher.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/simple-cipher/example.js b/exercises/simple-cipher/example.js index a55a265b..6f0177fb 100644 --- a/exercises/simple-cipher/example.js +++ b/exercises/simple-cipher/example.js @@ -3,8 +3,8 @@ var ALPHABET = 'abcdefghijklmnopqrstuvwxyz'; function randomKey() { - var i, result = ''; - for ( i = 0; i < 100; i++ ) { + var result; + for ( var i = 0; i < 100; i++ ) { result += ALPHABET[randomUpTo(ALPHABET.length)]; } return result; @@ -15,19 +15,16 @@ function randomUpTo(n) { } module.exports = function (userDefinedKey) { - var key; - function addEncodedCharacter(character, index, array) { - /*jshint validthis:true */ - var i = ALPHABET.indexOf(character) + ALPHABET.indexOf(key[index]); + function addEncodedCharacter(character, index) { + var i = ALPHABET.indexOf(character) + ALPHABET.indexOf(key[index % key.length]); if (i >= ALPHABET.length) { i -= ALPHABET.length; } this.push(ALPHABET[i]); } - function addDecodedCharacter(character, index, array) { - /*jshint validthis:true */ - var i = ALPHABET.indexOf(character) - ALPHABET.indexOf(key[index]); + function addDecodedCharacter(character, index) { + var i = ALPHABET.indexOf(character) - ALPHABET.indexOf(key[index % key.length]); if (i < 0) { i += ALPHABET.length; } this.push(ALPHABET[i]); } @@ -50,4 +47,4 @@ module.exports = function (userDefinedKey) { if (userDefinedKey === '' || key.match(/[\dA-Z]/)) { throw new Error('Bad key'); } -}; \ No newline at end of file +}; diff --git a/exercises/simple-cipher/simple-cipher.spec.js b/exercises/simple-cipher/simple-cipher.spec.js index 15a3d272..c59c16cf 100644 --- a/exercises/simple-cipher/simple-cipher.spec.js +++ b/exercises/simple-cipher/simple-cipher.spec.js @@ -1,10 +1,24 @@ var Cipher = require('./simple-cipher'); +describe('Random key generation', function () { + xit('generates keys at random', function () { + // Strictly speaking, this is difficult to test with 100% certainty. + // But, if you have a generator that generates 100-character-long + // strings of lowercase letters at random, the odds of two consecutively + // generated keys being identical are astronomically low. + expect(new Cipher().key).not.toEqual(new Cipher().key); + }); +}); + describe('Random key cipher', function () { var cipher = new Cipher(); it('has a key made of letters', function () { - expect(cipher.key).toMatch(/[a-z]+/); + expect(cipher.key).toMatch(/^[a-z]+$/); + }); + + xit('has a key that is at least 100 characters long', function () { + expect(cipher.key.length).toBeGreaterThanOrEqual(100); }); // Here we take advantage of the fact that plaintext of "aaa..." @@ -24,26 +38,30 @@ describe('Random key cipher', function () { }); }); +/* eslint-disable no-new */ + describe('Incorrect key cipher', function () { xit('throws an error with an all caps key', function () { - expect( function () { + expect(function () { new Cipher('ABCDEF'); }).toThrow(new Error('Bad key')); }); xit('throws an error with a numeric key', function () { - expect( function () { + expect(function () { new Cipher('12345'); }).toThrow(new Error('Bad key')); }); xit('throws an error with an empty key', function () { - expect( function () { + expect(function () { new Cipher(''); }).toThrow(new Error('Bad key')); }); }); +/* eslint-enable no-new */ + describe('Substitution cipher', function () { var key = 'abcdefghij'; var cipher = new Cipher(key); @@ -69,7 +87,16 @@ describe('Substitution cipher', function () { .toEqual('qayaeaagaciai'); }); - xit('can wrap', function () { + xit('can wrap on encode', function () { expect(cipher.encode('zzzzzzzzzz')).toEqual('zabcdefghi'); }); + + xit('can wrap on decode', () => { + expect(cipher.decode('zabcdefghi')).toEqual('zzzzzzzzzz'); + }); + + xit('can handle messages longer than the key', function () { + expect(new Cipher('abc').encode('iamapandabear')) + .toEqual('iboaqcnecbfcr'); + }); }); diff --git a/exercises/simple-linked-list/README.md b/exercises/simple-linked-list/README.md index f9e7ff91..07e40594 100644 --- a/exercises/simple-linked-list/README.md +++ b/exercises/simple-linked-list/README.md @@ -23,26 +23,29 @@ implement your own abstract data type. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine simple-linked-list.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/simple-linked-list/example.js b/exercises/simple-linked-list/example.js index 5d9cfed0..e8fca85f 100644 --- a/exercises/simple-linked-list/example.js +++ b/exercises/simple-linked-list/example.js @@ -1,24 +1,24 @@ -function Element (value, next) { +function Element(value, next) { if (!(this instanceof Element)) { throw new Error('Element is a constructor.'); } - if (value === undefined) { + if (typeof value === 'undefined') { throw new Error('Value required.'); } - if (next !== undefined && !(next instanceof Element)) { + if (typeof next !== 'undefined' && !(next instanceof Element)) { throw new Error('A Element instance as next value is required.'); } this.value = value; this.next = next; -}; +} -function List () {}; +function List() {} List.prototype.push = function (value) { - if (value === undefined) { + if (typeof value === 'undefined') { throw new Error('Argument required.'); } @@ -40,7 +40,7 @@ List.prototype.push = function (value) { }; List.prototype.unshift = function (value) { - if (value === undefined) { + if (typeof value === 'undefined') { throw new Error('Argument required.'); } @@ -65,18 +65,20 @@ List.prototype.pop = function () { return; } - var penultEl, lastEl = this.head; + var penultEl; + var lastEl = this.head; while (lastEl.next) { penultEl = lastEl; lastEl = lastEl.next; } + /* eslint-disable no-undefined */ if (!penultEl) { this.head = undefined; - } - else { + } else { penultEl.next = undefined; } + /* eslint-enable no-undefined */ }; List.prototype.reverse = function () { @@ -84,7 +86,8 @@ List.prototype.reverse = function () { return; } - var current, previous; + var current; + var previous; while (this.head) { current = this.head; this.shift(); @@ -97,10 +100,11 @@ List.prototype.reverse = function () { List.prototype.toArray = function () { var array = []; + var current = this.head; - while (this.head) { - array.push(this.head.value); - this.shift(); + while (current) { + array.push(current.value); + current = current.next; } return array; diff --git a/exercises/simple-linked-list/simple-linked-list.spec.js b/exercises/simple-linked-list/simple-linked-list.spec.js index e1f8724e..75460d35 100644 --- a/exercises/simple-linked-list/simple-linked-list.spec.js +++ b/exercises/simple-linked-list/simple-linked-list.spec.js @@ -3,7 +3,6 @@ var List = SimpleLinkedList.List; var Element = SimpleLinkedList.Element; describe('simple-linked-list', function () { - it('exports a List constructor', function () { expect(List).toBeDefined(); }); @@ -13,14 +12,15 @@ describe('simple-linked-list', function () { }); describe('Element', function () { - xit('is a constructor', function () { var el = new Element(1); expect(el).toBeDefined(); + /* eslint-disable new-cap */ expect(function () { - var el = Element(1); + el = Element(1); }).toThrow(); + /* eslint-enable new-cap */ }); xit('requires an argument', function () { @@ -28,7 +28,7 @@ describe('simple-linked-list', function () { expect(el).toBeDefined(); expect(function () { - var el = new Element(); + el = new Element(); }).toThrow(); }); @@ -49,9 +49,9 @@ describe('simple-linked-list', function () { expect(elTwo.next).toBe(elOne); }); + /* eslint-disable no-unused-vars */ xit('requires an instance of Element as next element', function () { expect(function () { - var el = new Element(1, true); var el = new Element(1, false); }).toThrow(); expect(function () { @@ -64,9 +64,9 @@ describe('simple-linked-list', function () { var el = new Element(1, {}); }).toThrow(); }); + /* eslint-enable no-unused-vars */ describe('List', function () { - xit('is a constructor', function () { var ll = new List(); expect(ll).toBeDefined(); @@ -141,6 +141,9 @@ describe('simple-linked-list', function () { expect(a.length).toBe(2); expect(a[0]).toBe(1); expect(a[1]).toBe(2); + + expect(ll.head.value).toBe(1); + expect(ll.head.next.value).toBe(2); }); xit('allows you to reverse a List', function () { @@ -154,7 +157,5 @@ describe('simple-linked-list', function () { expect(ll.head.next.value).toBe(2); expect(ll.head.next.next.value).toBe(1); }); - }); - }); diff --git a/exercises/space-age/README.md b/exercises/space-age/README.md index 68bc8ed3..523cc173 100644 --- a/exercises/space-age/README.md +++ b/exercises/space-age/README.md @@ -12,33 +12,36 @@ Given an age in seconds, calculate how old someone would be on: - Neptune: orbital period 164.79132 Earth years So if you were told someone were 1,000,000,000 seconds old, you should -be able to say that they're 31 Earth-years old. +be able to say that they're 31.69 Earth-years old. If you're wondering why Pluto didn't make the cut, go watch [this youtube video](http://www.youtube.com/watch?v=Z_2gbGXzFbs). ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine space-age.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/space-age/example.js b/exercises/space-age/example.js index 41f9a53a..d20722cd 100644 --- a/exercises/space-age/example.js +++ b/exercises/space-age/example.js @@ -5,50 +5,50 @@ function SpaceAge(seconds) { this.earthYears = seconds / 31557600; this.earthToOtherPlanets = { - mercury : 0.2408467, - venus : 0.61519726, - earth : 1, - mars : 1.8808158, - jupiter : 11.862615, - saturn : 29.447498, - uranus : 84.016846, - neptune : 164.79132 + mercury: 0.2408467, + venus: 0.61519726, + earth: 1, + mars: 1.8808158, + jupiter: 11.862615, + saturn: 29.447498, + uranus: 84.016846, + neptune: 164.79132 }; - this.yearsOnPlanet = function(planet) { + this.yearsOnPlanet = function (planet) { var years = this.earthYears / this.earthToOtherPlanets[planet]; return parseFloat(years.toFixed(2)); }; - this.onMercury = function() { + this.onMercury = function () { return this.yearsOnPlanet('mercury'); }; - this.onVenus = function() { + this.onVenus = function () { return this.yearsOnPlanet('venus'); }; - this.onEarth = function() { + this.onEarth = function () { return this.yearsOnPlanet('earth'); }; - this.onMars = function() { + this.onMars = function () { return this.yearsOnPlanet('mars'); }; - this.onJupiter = function() { + this.onJupiter = function () { return this.yearsOnPlanet('jupiter'); }; - this.onSaturn = function() { + this.onSaturn = function () { return this.yearsOnPlanet('saturn'); }; - this.onUranus = function() { + this.onUranus = function () { return this.yearsOnPlanet('uranus'); }; - this.onNeptune = function() { + this.onNeptune = function () { return this.yearsOnPlanet('neptune'); }; } diff --git a/exercises/space-age/space-age.spec.js b/exercises/space-age/space-age.spec.js index ba6508f1..08fcb9da 100644 --- a/exercises/space-age/space-age.spec.js +++ b/exercises/space-age/space-age.spec.js @@ -1,53 +1,53 @@ var SpaceAge = require('./space-age'); -describe('Space Age', function() { - it('age in seconds', function() { +describe('Space Age', function () { + it('age in seconds', function () { var age = new SpaceAge(1000000); expect(age.seconds).toEqual(1000000); }); - xit('age in earth years', function() { + xit('age in earth years', function () { var age = new SpaceAge(1000000000); expect(age.onEarth()).toEqual(31.69); }); - xit('age in mercury years', function() { + xit('age in mercury years', function () { var age = new SpaceAge(2134835688); expect(age.onEarth()).toEqual(67.65); expect(age.onMercury()).toEqual(280.88); }); - xit('age in venus years', function() { + xit('age in venus years', function () { var age = new SpaceAge(189839836); expect(age.onEarth()).toEqual(6.02); expect(age.onVenus()).toEqual(9.78); }); - xit('age in mars years', function() { + xit('age in mars years', function () { var age = new SpaceAge(2329871239); expect(age.onEarth()).toEqual(73.83); expect(age.onMars()).toEqual(39.25); }); - xit('age in jupiter years', function() { + xit('age in jupiter years', function () { var age = new SpaceAge(901876382); expect(age.onEarth()).toEqual(28.58); expect(age.onJupiter()).toEqual(2.41); }); - xit('age in saturn years', function() { + xit('age in saturn years', function () { var age = new SpaceAge(3000000000); expect(age.onEarth()).toEqual(95.06); expect(age.onSaturn()).toEqual(3.23); }); - xit('age in uranus years', function() { + xit('age in uranus years', function () { var age = new SpaceAge(3210123456); expect(age.onEarth()).toEqual(101.72); expect(age.onUranus()).toEqual(1.21); }); - xit('age in neptune year', function() { + xit('age in neptune year', function () { var age = new SpaceAge(8210123456); expect(age.onEarth()).toEqual(260.16); expect(age.onNeptune()).toEqual(1.58); diff --git a/exercises/strain/README.md b/exercises/strain/README.md index f726bb2f..f58e2b2d 100644 --- a/exercises/strain/README.md +++ b/exercises/strain/README.md @@ -35,26 +35,29 @@ basic tools instead. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine strain.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/strain/example.js b/exercises/strain/example.js index 711d4875..4cbd75b5 100644 --- a/exercises/strain/example.js +++ b/exercises/strain/example.js @@ -1,9 +1,9 @@ 'use strict'; module.exports = { - strain: function(array, filter, keepMatches) { + strain: function (array, filter, keepMatches) { var results = []; - for (var i=0; i < array.length; i++) { + for (var i = 0; i < array.length; i++) { var item = array[i]; if (filter(item) === keepMatches) { results.push(item); diff --git a/exercises/strain/strain.spec.js b/exercises/strain/strain.spec.js index 66acc7d5..b57cf89f 100644 --- a/exercises/strain/strain.spec.js +++ b/exercises/strain/strain.spec.js @@ -1,30 +1,29 @@ var strain = require('./strain'); -describe('strain', function() { - - it('keeps on empty array returns empty array', function() { - expect(strain.keep([], function(e) { return e < 10; })).toEqual([]); +describe('strain', function () { + it('keeps on empty array returns empty array', function () { + expect(strain.keep([], function (e) { return e < 10; })).toEqual([]); }); - xit('keeps everything ', function() { - expect(strain.keep([1, 2, 3], function(e) { return e < 10; })).toEqual([1, 2, 3]); + xit('keeps everything ', function () { + expect(strain.keep([1, 2, 3], function (e) { return e < 10; })).toEqual([1, 2, 3]); }); - xit('keeps first and last', function() { - expect(strain.keep([1, 2, 3], function(e) { return (e % 2) === 1; })).toEqual([1, 3]); + xit('keeps first and last', function () { + expect(strain.keep([1, 2, 3], function (e) { return (e % 2) === 1; })).toEqual([1, 3]); }); - xit('keeps neither first nor last', function() { - expect(strain.keep([1, 2, 3, 4, 5], function(e) { return (e % 2) === 0; })).toEqual([2, 4]); + xit('keeps neither first nor last', function () { + expect(strain.keep([1, 2, 3, 4, 5], function (e) { return (e % 2) === 0; })).toEqual([2, 4]); }); - xit('keeps strings', function() { + xit('keeps strings', function () { var words = 'apple zebra banana zombies cherimoya zelot'.split(' '); - var result = strain.keep(words, function(word) { return word.indexOf('z') === 0; }); + var result = strain.keep(words, function (word) { return word.indexOf('z') === 0; }); expect(result).toEqual('zebra zombies zelot'.split(' ')); }); - xit('keeps arrays', function() { + xit('keeps arrays', function () { var rows = [ [1, 2, 3], [5, 5, 5], @@ -34,34 +33,34 @@ describe('strain', function() { [2, 2, 1], [1, 2, 5] ]; - var result = strain.keep(rows, function(row) { return row.indexOf(5) > -1; }); + var result = strain.keep(rows, function (row) { return row.indexOf(5) > -1; }); expect(result).toEqual([[5, 5, 5], [5, 1, 2], [1, 5, 2], [1, 2, 5]]); }); - xit('empty discard', function() { - expect(strain.discard([], function(e) { return e < 10;})).toEqual([]); + xit('empty discard', function () { + expect(strain.discard([], function (e) { return e < 10;})).toEqual([]); }); - xit('discards nothing', function() { - expect(strain.discard([1, 2, 3], function(e) { return e > 10; })).toEqual([1, 2, 3]); + xit('discards nothing', function () { + expect(strain.discard([1, 2, 3], function (e) { return e > 10; })).toEqual([1, 2, 3]); }); - xit('discards first and last', function() { - expect(strain.discard([1, 2, 3], function(e) { return e % 2 === 1; })).toEqual([2]); + xit('discards first and last', function () { + expect(strain.discard([1, 2, 3], function (e) { return e % 2 === 1; })).toEqual([2]); }); - xit('discards neither first nor last', function() { - var result = strain.discard([1, 2, 3, 4, 5], function(e) { return e % 2 === 0; }); + xit('discards neither first nor last', function () { + var result = strain.discard([1, 2, 3, 4, 5], function (e) { return e % 2 === 0; }); expect(result).toEqual([1, 3, 5]); }); - xit('discards strings', function() { + xit('discards strings', function () { var words = 'apple zebra banana zombies cherimoya zelot'.split(' '); - var result = strain.discard(words, function(word) { return word.indexOf('z') === 0; }); + var result = strain.discard(words, function (word) { return word.indexOf('z') === 0; }); expect(result).toEqual('apple banana cherimoya'.split(' ')); }); - xit('discards arrays', function() { + xit('discards arrays', function () { var rows = [ [1, 2, 3], [5, 5, 5], @@ -71,9 +70,8 @@ describe('strain', function() { [2, 2, 1], [1, 2, 5] ]; - var result = strain.discard(rows, function(row) { return row.indexOf(5) > -1; }); + var result = strain.discard(rows, function (row) { return row.indexOf(5) > -1; }); expect(result).toEqual([[1, 2, 3], [2, 1, 2], [2, 2, 1]]); }); - }); diff --git a/exercises/sublist/README.md b/exercises/sublist/README.md index 974d3f06..0b5d6d8c 100644 --- a/exercises/sublist/README.md +++ b/exercises/sublist/README.md @@ -19,32 +19,29 @@ Examples: ## Setup -Go through the setup instructions for ECMAScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/ecmascript +http://exercism.io/languages/javascript/installation -## Requirements +## Running the test suite -Install assignment dependencies: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -```bash -$ npm install -g jasmine +```sh +npm install -g jasmine ``` -## Making the test suite pass +Run the test suite from the exercise directory with: -Execute the tests with: - -```bash -$ jasmine sublist.spec.js +```sh +jasmine sublist.spec.js ``` -In the test suites all tests but the first have been skipped. - -Once you get a test passing, you can enable the next one by -changing `xit` to `it`. - +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Submitting Incomplete Solutions It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/sublist/example.js b/exercises/sublist/example.js index 8b670af2..a1f041f8 100644 --- a/exercises/sublist/example.js +++ b/exercises/sublist/example.js @@ -3,27 +3,27 @@ function List(list) { return { list: this.list, - compare: function(other){ - return { - '-1': isSublist(other.list, this.list) - ? 'SUBLIST' - : 'UNEQUAL', - '0': isSublist(other.list, this.list) - ? 'EQUAL' - : 'UNEQUAL', - '1': isSublist(this.list, other.list) - ? 'SUPERLIST' - : 'UNEQUAL' - }[lengthDiff(this, other)]; + compare: function (other) { + return { + '-1': isSublist(other.list, this.list) + ? 'SUBLIST' + : 'UNEQUAL', + '0': isSublist(other.list, this.list) + ? 'EQUAL' + : 'UNEQUAL', + '1': isSublist(this.list, other.list) + ? 'SUPERLIST' + : 'UNEQUAL' + }[lengthDiff(this, other)]; } - } + }; } -function lengthDiff(one, two){ +function lengthDiff(one, two) { return String(Math.sign(one.list.length - two.list.length)); } -function isSublist(one, two){ +function isSublist(one, two) { return one.join().match(two.join()); } diff --git a/exercises/sublist/sublist.spec.js b/exercises/sublist/sublist.spec.js index f080c951..bd420bc4 100644 --- a/exercises/sublist/sublist.spec.js +++ b/exercises/sublist/sublist.spec.js @@ -1,126 +1,123 @@ var List = require('./sublist'); -describe('sublist', function() { - - it('two empty lists are equal', function() { +describe('sublist', function () { + it('two empty lists are equal', function () { var listOne = new List(); var listTwo = new List(); expect(listOne.compare(listTwo)).toEqual('EQUAL'); }); - xit('an empty list is a sublist of a non-empty list', function() { + xit('an empty list is a sublist of a non-empty list', function () { var listOne = new List(); var listTwo = new List([1, 2, 3]); expect(listOne.compare(listTwo)).toEqual('SUBLIST'); }); - xit('non empty list contains empty list', function() { + xit('non empty list contains empty list', function () { var listOne = new List([1, 2, 3]); var listTwo = new List(); expect(listOne.compare(listTwo)).toEqual('SUPERLIST'); }); - xit('a non-empty list equals itself', function() { + xit('a non-empty list equals itself', function () { var listOne = new List([1, 2, 3]); var listTwo = new List([1, 2, 3]); expect(listOne.compare(listTwo)).toEqual('EQUAL'); }); - xit('two different lists are unequal', function() { + xit('two different lists are unequal', function () { var listOne = new List([1, 2, 3]); var listTwo = new List([2, 3, 4]); expect(listOne.compare(listTwo)).toEqual('UNEQUAL'); }); - xit('false start', function() { + xit('false start', function () { var listOne = new List([1, 2, 5]); var listTwo = new List([0, 1, 2, 3, 1, 2, 5, 6]); expect(listOne.compare(listTwo)).toEqual('SUBLIST'); - }); - xit('consecutive', function() { + xit('consecutive', function () { var listOne = new List([1, 1, 2]); var listTwo = new List([0, 1, 1, 1, 2, 1, 2]); expect(listOne.compare(listTwo)).toEqual('SUBLIST'); }); - xit('sublist at start', function() { + xit('sublist at start', function () { var listOne = new List([0, 1, 2]); var listTwo = new List([0, 1, 2, 3, 4, 5]); expect(listOne.compare(listTwo)).toEqual('SUBLIST'); }); - xit('sublist in middle', function() { + xit('sublist in middle', function () { var listOne = new List([2, 3, 4]); var listTwo = new List([0, 1, 2, 3, 4, 5]); expect(listOne.compare(listTwo)).toEqual('SUBLIST'); }); - xit('sublist at end', function() { + xit('sublist at end', function () { var listOne = new List([3, 4, 5]); var listTwo = new List([0, 1, 2, 3, 4, 5]); expect(listOne.compare(listTwo)).toEqual('SUBLIST'); }); - xit('at start of superlist', function() { + xit('at start of superlist', function () { var listOne = new List([0, 1, 2, 3, 4, 5]); var listTwo = new List([0, 1, 2]); expect(listOne.compare(listTwo)).toEqual('SUPERLIST'); }); - xit('in middle of superlist', function() { + xit('in middle of superlist', function () { var listOne = new List([0, 1, 2, 3, 4, 5]); var listTwo = new List([2, 3]); expect(listOne.compare(listTwo)).toEqual('SUPERLIST'); }); - xit('at end of superlist', function() { + xit('at end of superlist', function () { var listOne = new List([0, 1, 2, 3, 4, 5]); var listTwo = new List([3, 4, 5]); expect(listOne.compare(listTwo)).toEqual('SUPERLIST'); }); - xit('first list missing element from second list', function() { + xit('first list missing element from second list', function () { var listOne = new List([1, 3]); var listTwo = new List([1, 2, 3]); expect(listOne.compare(listTwo)).toEqual('UNEQUAL'); }); - xit('second list missing element from first list', function() { + xit('second list missing element from first list', function () { var listOne = new List([1, 2, 3]); var listTwo = new List([1, 3]); expect(listOne.compare(listTwo)).toEqual('UNEQUAL'); }); - xit('order matters to a list', function() { + xit('order matters to a list', function () { var listOne = new List([1, 2, 3]); var listTwo = new List([3, 2, 1]); expect(listOne.compare(listTwo)).toEqual('UNEQUAL'); }); - xit('same digits but different numbers', function() { + xit('same digits but different numbers', function () { var listOne = new List([1, 0, 1]); var listTwo = new List([10, 1]); expect(listOne.compare(listTwo)).toEqual('UNEQUAL'); }); - }); diff --git a/exercises/sum-of-multiples/README.md b/exercises/sum-of-multiples/README.md index 7766bd68..ace5cad7 100644 --- a/exercises/sum-of-multiples/README.md +++ b/exercises/sum-of-multiples/README.md @@ -1,38 +1,38 @@ # Sum Of Multiples -Given a number, find the sum of all the multiples of particular numbers up to +Given a number, find the sum of all the unique multiples of particular numbers up to but not including that number. -If we list all the natural numbers up to but not including 20 that are -multiples of either 3 or 5, we get 3, 5, 6 and 9, 10, 12, 15, and 18. +If we list all the natural numbers below 20 that are multiples of 3 or 5, +we get 3, 5, 6, 9, 10, 12, 15, and 18. The sum of these multiples is 78. -Given a number, find the sum of the multiples of a given set of numbers, -up to but not including that number. - ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine sum-of-multiples.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/sum-of-multiples/example.js b/exercises/sum-of-multiples/example.js index 0feb4e00..35d90e20 100644 --- a/exercises/sum-of-multiples/example.js +++ b/exercises/sum-of-multiples/example.js @@ -1,7 +1,7 @@ 'use strict'; function isMultiple(i) { - /*jshint validthis:true */ + /* jshint validthis:true */ var result = false; this.multiples.forEach(function (multiple) { if (i % multiple === 0) { diff --git a/exercises/sum-of-multiples/sum-of-multiples.spec.js b/exercises/sum-of-multiples/sum-of-multiples.spec.js index 8866cda9..8ff4a443 100644 --- a/exercises/sum-of-multiples/sum-of-multiples.spec.js +++ b/exercises/sum-of-multiples/sum-of-multiples.spec.js @@ -2,38 +2,38 @@ var SumOfMultiples = require('./sum-of-multiples'); describe('SumOfMultiples', function () { it('to 1', function () { - expect(SumOfMultiples([3, 5]).to(1)).toBe(0); + expect(new SumOfMultiples([3, 5]).to(1)).toBe(0); }); xit('to 3', function () { - expect(SumOfMultiples([3, 5]).to(4)).toBe(3); + expect(new SumOfMultiples([3, 5]).to(4)).toBe(3); }); xit('to 10', function () { - expect(SumOfMultiples([3, 5]).to(10)).toBe(23); + expect(new SumOfMultiples([3, 5]).to(10)).toBe(23); }); xit('to 100', function () { - expect(SumOfMultiples([3, 5]).to(100)).toBe(2318); + expect(new SumOfMultiples([3, 5]).to(100)).toBe(2318); }); xit('to 1000', function () { - expect(SumOfMultiples([3, 5]).to(1000)).toBe(233168); + expect(new SumOfMultiples([3, 5]).to(1000)).toBe(233168); }); xit('[7, 13, 17] to 20', function () { - expect(SumOfMultiples([7, 13, 17]).to(20)).toBe(51); + expect(new SumOfMultiples([7, 13, 17]).to(20)).toBe(51); }); xit('[4, 6] to 15', function () { - expect(SumOfMultiples([4, 6]).to(15)).toBe(30); + expect(new SumOfMultiples([4, 6]).to(15)).toBe(30); }); xit('[5, 6, 8] to 150', function () { - expect(SumOfMultiples([5, 6, 8]).to(150)).toBe(4419); + expect(new SumOfMultiples([5, 6, 8]).to(150)).toBe(4419); }); xit('[43, 47] to 10000', function () { - expect(SumOfMultiples([43, 47]).to(10000)).toBe(2203160); + expect(new SumOfMultiples([43, 47]).to(10000)).toBe(2203160); }); }); diff --git a/exercises/transpose/README.md b/exercises/transpose/README.md new file mode 100644 index 00000000..05c69022 --- /dev/null +++ b/exercises/transpose/README.md @@ -0,0 +1,92 @@ +# Transpose + +Given an input text output it transposed. + +Roughly explained, the transpose of a matrix: + +```text +ABC +DEF +``` + +is given by: + +```text +AD +BE +CF +``` + +Rows become columns and columns become rows. See . + +If the input has rows of different lengths, this is to be solved as follows: + +- Pad to the left with spaces. +- Don't pad to the right. + +Therefore, transposing this matrix: + +```text +ABC +DE +``` + +results in: + +```text +AD +BE +C +``` + +And transposing: + +```text +AB +DEF +``` + +results in: + +```text +AD +BE + F +``` + +In general, all characters from the input should also be present in the transposed output. +That means that if a column in the input text contains only spaces on its bottom-most row(s), +the corresponding output row should contain the spaces in its right-most column(s). + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine transpose.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Reddit r/dailyprogrammer challenge #270 [Easy]. [https://www.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text](https://www.reddit.com/r/dailyprogrammer/comments/4msu2x/challenge_270_easy_transpose_the_input_text) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/transpose/example.js b/exercises/transpose/example.js new file mode 100644 index 00000000..874ccea9 --- /dev/null +++ b/exercises/transpose/example.js @@ -0,0 +1,17 @@ +'use strict'; + +function transpose(text) { + return text.reduce(function (result, line, lineNo) { + line.split('').map(function (value, key) { + if (typeof result[key] === 'undefined') { + result[key] = new Array(lineNo + 1).join(' '); + } + + result[key] += value; + }); + + return result; + }, []); +} + +module.exports = transpose; diff --git a/exercises/transpose/transpose.spec.js b/exercises/transpose/transpose.spec.js new file mode 100644 index 00000000..59f7fe38 --- /dev/null +++ b/exercises/transpose/transpose.spec.js @@ -0,0 +1,67 @@ +var transpose = require('./transpose'); + +describe('Transpose', function () { + it('test empty string', function () { + expect(transpose([])).toEqual([]); + }); + + xit('test two characters in a row', function () { + var input = ['A1']; + var expected = ['A', '1']; + expect(transpose(input)).toEqual(expected); + }); + + xit('test two characters in a column', function () { + var input = ['A', '1']; + var expected = ['A1']; + expect(transpose(input)).toEqual(expected); + }); + + xit('test simple', function () { + var input = ['ABC', '123']; + var expected = ['A1', 'B2', 'C3']; + expect(transpose(input)).toEqual(expected); + }); + + xit('test single line', function () { + var input = ['Single line.']; + var expected = ['S', 'i', 'n', 'g', 'l', 'e', ' ', 'l', 'i', 'n', 'e', '.']; + expect(transpose(input)).toEqual(expected); + }); + + xit('test first line longer than second line', function () { + var input = ['The fourth line.', 'The fifth line.']; + var expected = ['TT', 'hh', 'ee', ' ', 'ff', 'oi', 'uf', 'rt', 'th', 'h ', ' l', 'li', 'in', 'ne', 'e.', '.']; + expect(transpose(input)).toEqual(expected); + }); + + xit('test second line longer than first line', function () { + var input = ['The first line.', 'The second line.']; + var expected = ['TT', 'hh', 'ee', ' ', 'fs', 'ie', 'rc', 'so', 'tn', ' d', 'l ', 'il', 'ni', 'en', '.e', ' .']; + expect(transpose(input)).toEqual(expected); + }); + + xit('test square', function () { + var input = ['HEART', 'EMBER', 'ABUSE', 'RESIN', 'TREND']; + var expected = ['HEART', 'EMBER', 'ABUSE', 'RESIN', 'TREND']; + expect(transpose(input)).toEqual(expected); + }); + + xit('test rectangle', function () { + var input = ['FRACTURE', 'OUTLINED', 'BLOOMING', 'SEPTETTE']; + var expected = ['FOBS', 'RULE', 'ATOP', 'CLOT', 'TIME', 'UNIT', 'RENT', 'EDGE']; + expect(transpose(input)).toEqual(expected); + }); + + xit('test triangle', function () { + var input = ['T', 'EE', 'AAA', 'SSSS', 'EEEEE', 'RRRRRR']; + var expected = ['TEASER', ' EASER', ' ASER', ' SER', ' ER', ' R']; + expect(transpose(input)).toEqual(expected); + }); + + xit('test many lines', function () { + var input = ['Chor. Two households, both alike in dignity,', 'In fair Verona, where we lay our scene,', 'From ancient grudge break to new mutiny,', 'Where civil blood makes civil hands unclean.', 'From forth the fatal loins of these two foes', 'A pair of star-cross\'d lovers take their life;', 'Whose misadventur\'d piteous overthrows', 'Doth with their death bury their parents\' strife.', 'The fearful passage of their death-mark\'d love,', 'And the continuance of their parents\' rage,', 'Which, but their children\'s end, naught could remove,', 'Is now the two hours\' traffic of our stage;', 'The which if you with patient ears attend,', 'What here shall miss, our toil shall strive to mend.']; + var expected = ['CIFWFAWDTAWITW', 'hnrhr hohnhshh', 'o oeopotedi ea', 'rfmrmash cn t', '.a e ie fthow ', ' ia fr weh,whh', 'Trnco miae ie', 'w ciroitr btcr', 'oVivtfshfcuhhe', ' eeih a uote ', 'hrnl sdtln is', 'oot ttvh tttfh', 'un bhaeepihw a', 'saglernianeoyl', 'e,ro -trsui ol', 'h uofcu sarhu ', 'owddarrdan o m', 'lhg to\'egccuwi', 'deemasdaeehris', 'sr als t ists', ',ebk \'phool\'h,', ' reldi ffd ', 'bweso tb rtpo', 'oea ileutterau', 't kcnoorhhnatr', 'hl isvuyee\'fi ', ' atv es iisfet', 'ayoior trr ino', 'l lfsoh ecti', 'ion vedpn l', 'kuehtteieadoe ', 'erwaharrar,fas', ' nekt te rh', 'ismdsehphnnosa', 'ncuse ra-tau l', ' et tormsural', 'dniuthwea\'g t ', 'iennwesnr hsts', 'g,ycoitkrttet', 'n,l rs\'a anr', 'ief \'dgcgdi', 'taol eoe,v', 'yneisl,u;e', ',.sftol ', ' ervdt', ' ;ie o', ' f,r ', ' eem', ' .me', ' on', ' vd', ' e.', ' ,']; + expect(transpose(input)).toEqual(expected); + }); +}); diff --git a/exercises/triangle/README.md b/exercises/triangle/README.md index 32272340..10d05dd2 100644 --- a/exercises/triangle/README.md +++ b/exercises/triangle/README.md @@ -2,45 +2,51 @@ Determine if a triangle is equilateral, isosceles, or scalene. -An _equilateral_ triangle has all three sides the same length.
+An _equilateral_ triangle has all three sides the same length. + An _isosceles_ triangle has at least two sides the same length. (It is sometimes specified as having exactly two sides the same length, but for the purposes of -this exercise we'll say at least two.)
+this exercise we'll say at least two.) + A _scalene_ triangle has all sides of different lengths. ## Note -For a shape to be a triangle at all, all sides have to be of length > 0, and -the sum of the lengths of any two sides must be greater than or equal to the +For a shape to be a triangle at all, all sides have to be of length > 0, and +the sum of the lengths of any two sides must be greater than or equal to the length of the third side. See [Triangle Inequality](https://en.wikipedia.org/wiki/Triangle_inequality). ## Dig Deeper -The case where the sum of the lengths of two sides _equals_ that of the -third is known as a _degenerate_ triangle - it has zero area and looks like +The case where the sum of the lengths of two sides _equals_ that of the +third is known as a _degenerate_ triangle - it has zero area and looks like a single line. Feel free to add your own code/tests to check for degenerate triangles. -## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +## Setup -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine triangle.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/triangle/example.js b/exercises/triangle/example.js index 0b4fea4d..eb2b9a83 100644 --- a/exercises/triangle/example.js +++ b/exercises/triangle/example.js @@ -1,9 +1,9 @@ -function Triangle(a,b,c) { +function Triangle(a, b, c) { 'use strict'; this.sides = [ a, b, c ]; - this.kind = function() { + this.kind = function () { var name = 'scalene'; if (this.isIllegal()) { @@ -17,28 +17,27 @@ function Triangle(a,b,c) { return name; }; - this.isIllegal = function() { + this.isIllegal = function () { return this.violatesInequality() || this.hasImpossibleSides(); }; - this.violatesInequality = function() { - var a = this.sides[0], b = this.sides[1], c = this.sides[2]; + this.violatesInequality = function () { return (a + b < c) || (a + c < b) || (b + c < a); }; - this.hasImpossibleSides = function() { + this.hasImpossibleSides = function () { return this.sides[0] <= 0 || this.sides[1] <= 0 || this.sides[2] <= 0; }; - this.isEquilateral = function() { + this.isEquilateral = function () { return this.uniqueSides().length === 1; }; - this.isIsosceles = function() { + this.isIsosceles = function () { return this.uniqueSides().length === 2; }; - this.uniqueSides = function() { + this.uniqueSides = function () { var sides = this.sides; var uniques = {}; @@ -50,7 +49,9 @@ function Triangle(a,b,c) { var uniqueSides = []; for (var uniqueSide in uniques) { - uniqueSides.push(uniqueSide); + if (uniques.hasOwnProperty(uniqueSide)) { + uniqueSides.push(uniqueSide); + } } return uniqueSides; diff --git a/exercises/triangle/triangle.spec.js b/exercises/triangle/triangle.spec.js index a23c7a79..fd826893 100644 --- a/exercises/triangle/triangle.spec.js +++ b/exercises/triangle/triangle.spec.js @@ -1,85 +1,83 @@ var Triangle = require('./triangle'); -describe('Triangle', function() { - - it('equilateral triangles have equal sides', function() { - var triangle = new Triangle(2,2,2); +describe('Triangle', function () { + it('equilateral triangles have equal sides', function () { + var triangle = new Triangle(2, 2, 2); expect(triangle.kind()).toEqual('equilateral'); }); - xit('larger equilateral triangles also have equal sides', function() { - var triangle = new Triangle(10,10,10); + xit('larger equilateral triangles also have equal sides', function () { + var triangle = new Triangle(10, 10, 10); expect(triangle.kind()).toEqual('equilateral'); }); - xit('isosceles triangles have last two sides equal', function() { - var triangle = new Triangle(3,4,4); + xit('isosceles triangles have last two sides equal', function () { + var triangle = new Triangle(3, 4, 4); expect(triangle.kind()).toEqual('isosceles'); }); - xit('isosceles triangles have first two sides equal', function() { - var triangle = new Triangle(2,2,3); + xit('isosceles triangles have first two sides equal', function () { + var triangle = new Triangle(2, 2, 3); expect(triangle.kind()).toEqual('isosceles'); }); - xit('isosceles trianges have first and last sides equal', function() { - var triangle = new Triangle(4,3,4); + xit('isosceles trianges have first and last sides equal', function () { + var triangle = new Triangle(4, 3, 4); expect(triangle.kind()).toEqual('isosceles'); }); - xit('isosceles triangles have two first sides equal', function() { - var triangle = new Triangle(4,4,3); + xit('isosceles triangles have two first sides equal', function () { + var triangle = new Triangle(4, 4, 3); expect(triangle.kind()).toEqual('isosceles'); }); - xit('isosceles triangles have in fact exactly two sides equal', function() { - var triangle = new Triangle(10,10,2); + xit('isosceles triangles have in fact exactly two sides equal', function () { + var triangle = new Triangle(10, 10, 2); expect(triangle.kind()).toEqual('isosceles'); }); - xit('scalene triangles have no equal sides', function() { - var triangle = new Triangle(3,4,5); + xit('scalene triangles have no equal sides', function () { + var triangle = new Triangle(3, 4, 5); expect(triangle.kind()).toEqual('scalene'); }); - xit('scalene triangles have no equal sides at a larger scale too', function() { - var triangle = new Triangle(10,11,12); + xit('scalene triangles have no equal sides at a larger scale too', function () { + var triangle = new Triangle(10, 11, 12); expect(triangle.kind()).toEqual('scalene'); }); - xit('scalene triangles have no equal sides in descending order either', function() { - var triangle = new Triangle(5,4,2); + xit('scalene triangles have no equal sides in descending order either', function () { + var triangle = new Triangle(5, 4, 2); expect(triangle.kind()).toEqual('scalene'); }); - xit('very small triangles are legal', function() { - var triangle = new Triangle(0.4,0.6,0.3); + xit('very small triangles are legal', function () { + var triangle = new Triangle(0.4, 0.6, 0.3); expect(triangle.kind()).toEqual('scalene'); }); - xit('test triangles with no size are illegal', function() { - var triangle = new Triangle(0,0,0); + xit('test triangles with no size are illegal', function () { + var triangle = new Triangle(0, 0, 0); expect(triangle.kind.bind(triangle)).toThrow(); }); - xit('triangles with negative sides are illegal', function() { - var triangle = new Triangle(3,4,-5); + xit('triangles with negative sides are illegal', function () { + var triangle = new Triangle(3, 4, -5); expect(triangle.kind.bind(triangle)).toThrow(); }); - xit('triangles violating triangle inequality are illegal', function() { - var triangle = new Triangle(1,1,3); + xit('triangles violating triangle inequality are illegal', function () { + var triangle = new Triangle(1, 1, 3); expect(triangle.kind.bind(triangle)).toThrow(); }); - xit('triangles violating triangle inequality are illegal 2', function() { - var triangle = new Triangle(7,3,2); + xit('triangles violating triangle inequality are illegal 2', function () { + var triangle = new Triangle(7, 3, 2); expect(triangle.kind.bind(triangle)).toThrow(); }); - xit('triangles violating triangle inequality are illegal 3', function() { - var triangle = new Triangle(10,1,3); + xit('triangles violating triangle inequality are illegal 3', function () { + var triangle = new Triangle(10, 1, 3); expect(triangle.kind.bind(triangle)).toThrow(); }); - }); diff --git a/exercises/trinary/README.md b/exercises/trinary/README.md index 5d4fd424..16f94ea3 100644 --- a/exercises/trinary/README.md +++ b/exercises/trinary/README.md @@ -11,7 +11,7 @@ Trinary numbers contain three symbols: 0, 1, and 2. The last place in a trinary number is the 1's place. The second to last is the 3's place, the third to last is the 9's place, etc. -```bash +```shell # "102012" 1 0 2 0 1 2 # the number 1*3^5 + 0*3^4 + 2*3^3 + 0*3^2 + 1*3^1 + 2*3^0 # the value @@ -23,26 +23,29 @@ conversion, pretend it doesn't exist and implement it yourself. ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js - -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine trinary.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/trinary/example.js b/exercises/trinary/example.js index d6294340..a580034f 100644 --- a/exercises/trinary/example.js +++ b/exercises/trinary/example.js @@ -8,11 +8,11 @@ function Trinary(decimal) { this.digits = decimal.split('').reverse().map(Number); } -Trinary.prototype.toDecimal = function() { +Trinary.prototype.toDecimal = function () { var decimal = this.digits.reduce(this.accumulator, 0); return isNaN(decimal) ? 0 : decimal; }; -Trinary.prototype.accumulator = function(decimal, digit, index) { - return decimal += digit * Math.pow(BASE, index); +Trinary.prototype.accumulator = function (decimal, digit, index) { + return decimal + digit * Math.pow(BASE, index); }; diff --git a/exercises/trinary/trinary.spec.js b/exercises/trinary/trinary.spec.js index 792df1c7..202fce1c 100644 --- a/exercises/trinary/trinary.spec.js +++ b/exercises/trinary/trinary.spec.js @@ -1,41 +1,39 @@ var Trinary = require('./trinary'); describe('Trinary', function () { - - it('1 is decimal 1', function() { + it('1 is decimal 1', function () { expect(new Trinary('1').toDecimal()).toEqual(1); }); - xit('2 is decimal 2', function() { + xit('2 is decimal 2', function () { expect(new Trinary('2').toDecimal()).toEqual(2); }); - xit('10 is decimal 3', function() { + xit('10 is decimal 3', function () { expect(new Trinary('10').toDecimal()).toEqual(3); }); - xit('11 is decimal 4', function() { + xit('11 is decimal 4', function () { expect(new Trinary('11').toDecimal()).toEqual(4); }); - xit('100 is decimal 9', function() { + xit('100 is decimal 9', function () { expect(new Trinary('100').toDecimal()).toEqual(9); }); - xit('112 is decimal 14', function() { + xit('112 is decimal 14', function () { expect(new Trinary('112').toDecimal()).toEqual(14); }); - xit('222 is 26', function() { + xit('222 is 26', function () { expect(new Trinary('222').toDecimal()).toEqual(26); }); - xit('1122000120 is 32091', function() { + xit('1122000120 is 32091', function () { expect(new Trinary('1122000120').toDecimal()).toEqual(32091); }); - xit('invalid trinary is decimal 0', function() { + xit('invalid trinary is decimal 0', function () { expect(new Trinary('carrot').toDecimal()).toEqual(0); }); - }); diff --git a/exercises/twelve-days/README.md b/exercises/twelve-days/README.md new file mode 100644 index 00000000..9647f728 --- /dev/null +++ b/exercises/twelve-days/README.md @@ -0,0 +1,62 @@ +# Twelve Days + +Output the lyrics to 'The Twelve Days of Christmas'. + +```text +On the first day of Christmas my true love gave to me, a Partridge in a Pear Tree. + +On the second day of Christmas my true love gave to me, two Turtle Doves, and a Partridge in a Pear Tree. + +On the third day of Christmas my true love gave to me, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. + +On the fourth day of Christmas my true love gave to me, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. + +On the fifth day of Christmas my true love gave to me, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. + +On the sixth day of Christmas my true love gave to me, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. + +On the seventh day of Christmas my true love gave to me, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. + +On the eighth day of Christmas my true love gave to me, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. + +On the ninth day of Christmas my true love gave to me, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. + +On the tenth day of Christmas my true love gave to me, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. + +On the eleventh day of Christmas my true love gave to me, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. + +On the twelfth day of Christmas my true love gave to me, twelve Drummers Drumming, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree. +``` + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine twelve-days.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +Wikipedia [http://en.wikipedia.org/wiki/The_Twelve_Days_of_Christmas_(song)](http://en.wikipedia.org/wiki/The_Twelve_Days_of_Christmas_(song)) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/twelve-days/example.js b/exercises/twelve-days/example.js new file mode 100644 index 00000000..38001978 --- /dev/null +++ b/exercises/twelve-days/example.js @@ -0,0 +1,49 @@ +var TwelveDays = function () { + this.verseList = [ + 'On the first day of Christmas my true love gave to me, a Partridge in a Pear Tree.', + 'On the second day of Christmas my true love gave to me, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the third day of Christmas my true love gave to me, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the fourth day of Christmas my true love gave to me, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the fifth day of Christmas my true love gave to me, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the sixth day of Christmas my true love gave to me, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the seventh day of Christmas my true love gave to me, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the eighth day of Christmas my true love gave to me, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the ninth day of Christmas my true love gave to me, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the tenth day of Christmas my true love gave to me, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the eleventh day of Christmas my true love gave to me, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.', + 'On the twelfth day of Christmas my true love gave to me, twelve Drummers Drumming, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.' + ]; +}; + +TwelveDays.prototype.startFromZero = function (oneIndexArray) { + var newArray = oneIndexArray.map(function (item) { return item - 1; }); + return newArray; +}; + +TwelveDays.prototype.singleVerse = function (verseIndex) { + var verse = this.verseList[verseIndex].concat('\n'); + return verse; +}; + +TwelveDays.prototype.multiVerse = function (startIndex, endIndex) { + return this.verseList + .filter(function (verse, index) { return index >= startIndex; }) + .filter(function (verse, index) { return index <= endIndex; }) + .join('\n\n').concat('\n'); +}; + +TwelveDays.prototype.verse = function (args) { + var indexArray = this.startFromZero(args); + + if (args.length === 2) { + return this.multiVerse(indexArray[0], indexArray[1]); + } + return this.singleVerse(indexArray[0]); +}; + +TwelveDays.prototype.sing = function () { + var song = this.verseList.join('\n\n').concat('\n'); + return song; +}; + +module.exports = TwelveDays; diff --git a/exercises/twelve-days/twelve-days.spec.js b/exercises/twelve-days/twelve-days.spec.js new file mode 100644 index 00000000..1541e766 --- /dev/null +++ b/exercises/twelve-days/twelve-days.spec.js @@ -0,0 +1,103 @@ +var TwelveDays = require('./twelve-days'); + + +describe('TwelveDays', function () { + var twelveDaysObject = new TwelveDays(); + + it('test verse one', function () { + var expectedVerseOne = + 'On the first day of Christmas my true love gave to me, a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([1])).toEqual(expectedVerseOne); + }); + + xit('test verse two', function () { + var expectedVerseTwo = + 'On the second day of Christmas my true love gave to me, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([2])).toEqual(expectedVerseTwo); + }); + + xit('test verse three', function () { + var expectedVerseThree = + 'On the third day of Christmas my true love gave to me, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([3])).toEqual(expectedVerseThree); + }); + + xit('test verse four', function () { + var expectedVerseFour = + 'On the fourth day of Christmas my true love gave to me, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([4])).toEqual(expectedVerseFour); + }); + + xit('test verse five', function () { + var expectedVerseFive = + 'On the fifth day of Christmas my true love gave to me, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([5])).toEqual(expectedVerseFive); + }); + + xit('test verse six', function () { + var expectedVerseSix = + 'On the sixth day of Christmas my true love gave to me, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([6])).toEqual(expectedVerseSix); + }); + + xit('test verse seven', function () { + var expectedVerseSeven = + 'On the seventh day of Christmas my true love gave to me, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([7])).toEqual(expectedVerseSeven); + }); + + xit('test verse eight', function () { + var expectedVerseEight = + 'On the eighth day of Christmas my true love gave to me, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([8])).toEqual(expectedVerseEight); + }); + + xit('test verse nine', function () { + var expectedVerseNine = + 'On the ninth day of Christmas my true love gave to me, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([9])).toEqual(expectedVerseNine); + }); + + xit('test verse ten', function () { + var expectedVerseTen = + 'On the tenth day of Christmas my true love gave to me, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([10])).toEqual(expectedVerseTen); + }); + + xit('test verse eleven', function () { + var expectedVerseEleven = + 'On the eleventh day of Christmas my true love gave to me, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([11])).toEqual(expectedVerseEleven); + }); + + xit('test verse twelve', function () { + var expectedVerseTwelve = + 'On the twelfth day of Christmas my true love gave to me, twelve Drummers Drumming, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([12])).toEqual(expectedVerseTwelve); + }); + + xit('test multiple verse', function () { + var expectedVerseOneToThree = + 'On the first day of Christmas my true love gave to me, a Partridge in a Pear Tree.\n\n' + + 'On the second day of Christmas my true love gave to me, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the third day of Christmas my true love gave to me, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.verse([1, 3])).toEqual(expectedVerseOneToThree); + }); + + xit('test sing whole song', function () { + var expectedSong = + 'On the first day of Christmas my true love gave to me, a Partridge in a Pear Tree.\n\n' + + 'On the second day of Christmas my true love gave to me, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the third day of Christmas my true love gave to me, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the fourth day of Christmas my true love gave to me, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the fifth day of Christmas my true love gave to me, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the sixth day of Christmas my true love gave to me, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the seventh day of Christmas my true love gave to me, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the eighth day of Christmas my true love gave to me, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the ninth day of Christmas my true love gave to me, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the tenth day of Christmas my true love gave to me, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the eleventh day of Christmas my true love gave to me, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n\n' + + 'On the twelfth day of Christmas my true love gave to me, twelve Drummers Drumming, eleven Pipers Piping, ten Lords-a-Leaping, nine Ladies Dancing, eight Maids-a-Milking, seven Swans-a-Swimming, six Geese-a-Laying, five Gold Rings, four Calling Birds, three French Hens, two Turtle Doves, and a Partridge in a Pear Tree.\n'; + expect(twelveDaysObject.sing()).toEqual(expectedSong); + }); +}); diff --git a/exercises/two-bucket/README.md b/exercises/two-bucket/README.md index 493d70c2..dfa17296 100644 --- a/exercises/two-bucket/README.md +++ b/exercises/two-bucket/README.md @@ -4,22 +4,22 @@ Given two buckets of different size, demonstrate how to measure an exact number Since this mathematical problem is fairly subject to interpretation / individual approach, the tests have been written specifically to expect one overarching solution. -To help, the tests provide you with which bucket to fill first. That means, when starting with the larger bucket full, you are NOT allowed at any point to have the smaller bucket full and the larger bucket empty (aka, the opposite starting point); that would defeat the purpose of comparing both approaches! +To help, the tests provide you with which bucket to fill first. That means, when starting with the larger bucket full, you are NOT allowed at any point to have the smaller bucket full and the larger bucket empty (aka, the opposite starting point); that would defeat the purpose of comparing both approaches! Your program will take as input: -- the size of bucket one, passed as a numeric value -- the size of bucket two, passed as a numeric value -- the desired number of liters to reach, passed as a numeric value -- which bucket to fill first, passed as a String (either 'one' or 'two') +- the size of bucket one +- the size of bucket two +- the desired number of liters to reach +- which bucket to fill first, either bucket one or bucket two Your program should determine: -- the total number of "moves" it should take to reach the desired number of liters, including the first fill - expects a numeric value -- which bucket should end up with the desired number of liters (let's say this is bucket A) - expects a String (either 'one' or 'two') -- how many liters are left in the other bucket (bucket B) - expects a numeric value +- the total number of "moves" it should take to reach the desired number of liters, including the first fill +- which bucket should end up with the desired number of liters (let's say this is bucket A) - either bucket one or bucket two +- how many liters are left in the other bucket (bucket B) -Note: any time a change is made to either or both buckets counts as one (1) move. +Note: any time a change is made to either or both buckets counts as one (1) move. -Example: +Example: Bucket one can hold up to 7 liters, and bucket two can hold up to 11 liters. Let's say bucket one, at a given step, is holding 7 liters, and bucket two is holding 8 liters (7,8). If you empty bucket one and make no change to bucket two, leaving you with 0 liters and 8 liters respectively (0,8), that counts as one "move". Instead, if you had poured from bucket one into bucket two until bucket two was full, leaving you with 4 liters in bucket one and 11 liters in bucket two (4,11), that would count as only one "move" as well. To conclude, the only valid moves are: @@ -31,26 +31,29 @@ Written with <3 at [Fullstack Academy](http://www.fullstackacademy.com/) by [Lin ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: +Go through the setup instructions for JavaScript to install the + necessary dependencies: -http://exercism.io/languages/javascript +http://exercism.io/languages/javascript/installation -## Making the Test Suite Pass +## Running the test suite -Execute the tests with: +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: - jasmine .spec.js +```sh +npm install -g jasmine +``` -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +Run the test suite from the exercise directory with: - jasmine hello-world.spec.js +```sh +jasmine two-bucket.spec.js +``` -In many test suites all but the first test have been skipped. - -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/two-bucket/example.js b/exercises/two-bucket/example.js index c6be2d57..91080a15 100644 --- a/exercises/two-bucket/example.js +++ b/exercises/two-bucket/example.js @@ -1,89 +1,86 @@ 'use strict'; -function TwoBucket(x,y,z,starter) { - this.starter = starter; - this.x = x; - this.y = y; +function TwoBucket(bucketOne, bucketTwo, goal, startBucket) { + this.bucketOne = bucketOne; + this.bucketTwo = bucketTwo; + this.goal = goal; + this.startBucket = startBucket; - this.reachedGoal = function(measurements) { - var reached = false; - if(measurements[0] == z || measurements[1] == z) { - if(measurements[0] == z) { - this.goalBucket = 'one'; - this.otherBucket = measurements[1]; - } else { - this.goalBucket = 'two'; - this.otherBucket = measurements[0]; - } - reached = true; + this.reachedGoal = function (currentBucketOne, currentBucketTwo) { + return (currentBucketOne === goal || currentBucketTwo === goal); + }; + + this.recordGoal = function (currentBucketOne, currentBucketTwo) { + if (currentBucketOne === goal) { + this.goalBucket = 'one'; + this.otherBucket = currentBucketTwo; + } else { + this.goalBucket = 'two'; + this.otherBucket = currentBucketOne; } - return reached; }; - this.bigFirst = function(measurements, moveCount, prBool) { - var j = measurements[0], k = measurements[1]; - while(true) { - if(this.reachedGoal(measurements)) break; - if(k > x && j == 0 && moveCount == 0) { - j = x; - k = y - j; - } else if(j == x) { - j = 0; - } else if((k > x && j !== 0) || (k > x && prBool)) { - k = k - (x-j); - j = x; - } else if(k > x || j == 0) { - j = k; - k = k - j; - } else if(k == 0) { - k = y; + this.bigFirst = function (initialBucketOne, initialBucketTwo) { + var currentBucketOne = initialBucketOne; + var currentBucketTwo = initialBucketTwo; + var moveCount = 0; + var pourOrReceive = true; + while (!this.reachedGoal(currentBucketOne, currentBucketTwo)) { + if (currentBucketTwo > bucketOne && currentBucketOne === 0 && moveCount === 0) { + currentBucketOne = bucketOne; + currentBucketTwo = bucketTwo - currentBucketOne; + } else if (currentBucketOne === bucketOne) { + currentBucketOne = 0; + } else if ((currentBucketTwo > bucketOne && currentBucketOne !== 0) || (currentBucketTwo > bucketOne && pourOrReceive)) { + currentBucketTwo = currentBucketTwo - (bucketOne - currentBucketOne); + currentBucketOne = bucketOne; + } else if (currentBucketTwo > bucketOne || currentBucketOne === 0) { + currentBucketOne = currentBucketTwo; + currentBucketTwo = currentBucketTwo - currentBucketOne; + } else if (currentBucketTwo === 0) { + currentBucketTwo = bucketTwo; } - measurements = [j,k]; moveCount++; - prBool ? prBool = false : prBool = true; + pourOrReceive ? pourOrReceive = false : pourOrReceive = true; } + this.recordGoal(currentBucketOne, currentBucketTwo); return moveCount; }; - this.smallFirst = function(measurements, moveCount, prBool) { - var j = measurements[0], k = measurements[1]; - while(true) { - if(this.reachedGoal(measurements)) break; - if(j == x && moveCount == 0) { - j = 0; - k = x; - } else if(j == 0) { - j = x; - } else if(j == x && k < y) { - var tempK = k; - k + j > y ? k = y : k = tempK + j; - tempK + j > y ? j = j - (y- tempK) : j = 0; - } else if(k == y) { - k = 0; - } else if(k == 0 && j < x) { - k = j; - j = 0; + this.smallFirst = function (initialBucketOne, initialBucketTwo) { + var currentBucketOne = initialBucketOne; + var currentBucketTwo = initialBucketTwo; + var moveCount = 0; + var pourOrReceive = true; + while (!this.reachedGoal(currentBucketOne, currentBucketTwo)) { + if (currentBucketOne === bucketOne && moveCount === 0) { + currentBucketOne = 0; + currentBucketTwo = bucketOne; + } else if (currentBucketOne === 0) { + currentBucketOne = bucketOne; + } else if (currentBucketOne === bucketOne && currentBucketTwo < bucketTwo) { + var temp = currentBucketTwo; + currentBucketTwo + currentBucketOne > bucketTwo ? currentBucketTwo = bucketTwo : currentBucketTwo = temp + currentBucketOne; + temp + currentBucketOne > bucketTwo ? currentBucketOne = currentBucketOne - (bucketTwo - temp) : currentBucketOne = 0; + } else if (currentBucketTwo === bucketTwo) { + currentBucketTwo = 0; + } else if (currentBucketTwo === 0 && currentBucketOne < bucketOne) { + currentBucketTwo = currentBucketOne; + currentBucketOne = 0; } - measurements = [j,k]; moveCount++; - prBool ? prBool = false : prBool = true; + pourOrReceive ? pourOrReceive = false : pourOrReceive = true; } + this.recordGoal(currentBucketOne, currentBucketTwo); return moveCount; }; -} -TwoBucket.prototype.moves = function() { - var j = 0, k = 0; //j will be running val of bucket one, k = running val of bucket two - this.starter == 'one' ? j = this.x : k = this.y; - var measurements = [j,k]; - var moveCount = 0; - var prBool = true; // pour / receive boolean - need to pour or receive every other turn - if(this.starter == 'one') { - moveCount = this.smallFirst(measurements, moveCount, prBool); - } else { - moveCount = this.bigFirst(measurements, moveCount, prBool); - } - return moveCount + 1; //accounts for first move made before loop (and moveCount starts at zero before loop) -}; + this.moves = function () { + if (this.startBucket === 'one') { + return this.smallFirst(this.bucketOne, 0) + 1; + } + return this.bigFirst(0, this.bucketTwo) + 1; + }; +} module.exports = TwoBucket; diff --git a/exercises/two-bucket/two-bucket.spec.js b/exercises/two-bucket/two-bucket.spec.js index 412a4cde..0edf78a0 100644 --- a/exercises/two-bucket/two-bucket.spec.js +++ b/exercises/two-bucket/two-bucket.spec.js @@ -1,44 +1,44 @@ var TwoBucket = require('./two-bucket'); -describe('TwoBucket', function(){ - describe('works for input of 3,5,1', function(){ - var buckOne = 3; - var buckTwo = 5; +describe('TwoBucket', function () { + describe('Measure using bucket one of size 3 and bucket two of size 5', function () { + var bucketOne = 3; + var bucketTwo = 5; var goal = 1; - it('starting with bucket one', function(){ - var starterBuck = 'one'; //indicates which bucket to fill first - var twoBucket = new TwoBucket(buckOne,buckTwo,goal,starterBuck); - expect(twoBucket.moves()).toEqual(4); //includes the first fill - expect(twoBucket.goalBucket).toEqual('one'); //which bucket should end up with the desired # of liters - expect(twoBucket.otherBucket).toEqual(5); //leftover value in the "other" bucket once the goal has been reached + it('start with bucket one', function () { + var twoBucket = new TwoBucket(bucketOne, bucketTwo, goal, 'one'); + + expect(twoBucket.moves()).toEqual(4); // includes the first fill + expect(twoBucket.goalBucket).toEqual('one'); // which bucket should end up with the desired # of liters + expect(twoBucket.otherBucket).toEqual(5); // leftover value in the "other" bucket once the goal has been reached }); - xit('starting with bucket two', function(){ - var starterBuck = 'two'; - var twoBucket = new TwoBucket(buckOne,buckTwo,goal,starterBuck); + xit('start with bucket two', function () { + var twoBucket = new TwoBucket(bucketOne, bucketTwo, goal, 'two'); + expect(twoBucket.moves()).toEqual(8); expect(twoBucket.goalBucket).toEqual('two'); expect(twoBucket.otherBucket).toEqual(3); }); }); - describe('works for input of 7,11,2', function(){ - var buckOne = 7; - var buckTwo = 11; + describe('Measure using bucket one of size 7 and bucket two of size 11', function () { + var bucketOne = 7; + var bucketTwo = 11; var goal = 2; - xit('starting with bucket one', function(){ - var starterBuck = 'one'; - var twoBucket = new TwoBucket(buckOne,buckTwo,goal,starterBuck); + xit('start with bucket one', function () { + var twoBucket = new TwoBucket(bucketOne, bucketTwo, goal, 'one'); + expect(twoBucket.moves()).toEqual(14); expect(twoBucket.goalBucket).toEqual('one'); expect(twoBucket.otherBucket).toEqual(11); }); - xit('starting with bucket two', function(){ - var starterBuck = 'two'; - var twoBucket = new TwoBucket(buckOne,buckTwo,goal,starterBuck); + xit('start with bucket two', function () { + var twoBucket = new TwoBucket(bucketOne, bucketTwo, goal, 'two'); + expect(twoBucket.moves()).toEqual(18); expect(twoBucket.goalBucket).toEqual('two'); expect(twoBucket.otherBucket).toEqual(7); diff --git a/exercises/two-fer/README.md b/exercises/two-fer/README.md new file mode 100644 index 00000000..868b6c46 --- /dev/null +++ b/exercises/two-fer/README.md @@ -0,0 +1,46 @@ +# Two Fer + +`Two-fer` or `2-fer` is short for two for one. One for you and one for me. + +```text +"One for X, one for me." +``` + +When X is a name or "you". + +If the given name is "Alice", the result should be "One for Alice, one for me." +If no name is given, the result should be "One for you, one for me." + + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine two-fer.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Source + +This is an exercise to introduce users to basic programming constructs, just after Hello World. [https://en.wikipedia.org/wiki/Two-fer](https://en.wikipedia.org/wiki/Two-fer) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/two-fer/example.js b/exercises/two-fer/example.js new file mode 100644 index 00000000..5719a4cc --- /dev/null +++ b/exercises/two-fer/example.js @@ -0,0 +1,10 @@ +var TwoFer = function () {}; + +TwoFer.prototype.twoFer = function (who) { + if (who) { + return 'One for ' + who + ', one for me.'; + } + return 'One for you, one for me.'; +}; + +module.exports = TwoFer; diff --git a/exercises/two-fer/two-fer.js b/exercises/two-fer/two-fer.js new file mode 100644 index 00000000..88ab610d --- /dev/null +++ b/exercises/two-fer/two-fer.js @@ -0,0 +1,12 @@ +var TwoFer = function () {}; + +TwoFer.prototype.twoFer = function (who) { + // your code goes here + // You will have to use the parameter who + // in some way. In this example, it is just + // returned, but your solution will have to + // use a conditional. + return who; +}; + +module.exports = TwoFer; diff --git a/exercises/two-fer/two-fer.spec.js b/exercises/two-fer/two-fer.spec.js new file mode 100644 index 00000000..fe262efa --- /dev/null +++ b/exercises/two-fer/two-fer.spec.js @@ -0,0 +1,18 @@ + +var TwoFer = require('./two-fer'); + +describe('Two Fer', function () { + var twoFer = new TwoFer(); + + it('gives one to you if no parameter given', function () { + expect(twoFer.twoFer()).toEqual('One for you, one for me.'); + }); + + xit('gives one to Alice if \'Alice\' is given', function () { + expect(twoFer.twoFer('Alice')).toEqual('One for Alice, one for me.'); + }); + + xit('gives one to Bob if \'Bob\' is given', function () { + expect(twoFer.twoFer('Bob')).toEqual('One for Bob, one for me.'); + }); +}); diff --git a/exercises/variable-length-quantity/README.md b/exercises/variable-length-quantity/README.md new file mode 100644 index 00000000..7e1203a4 --- /dev/null +++ b/exercises/variable-length-quantity/README.md @@ -0,0 +1,62 @@ +# Variable Length Quantity + +Implement variable length quantity encoding and decoding. + +The goal of this exercise is to implement [VLQ](https://en.wikipedia.org/wiki/Variable-length_quantity) encoding/decoding. + +In short, the goal of this encoding is to encode integer values in a way that would save bytes. +Only the first 7 bits of each byte is significant (right-justified; sort of like an ASCII byte). +So, if you have a 32-bit value, you have to unpack it into a series of 7-bit bytes. +Of course, you will have a variable number of bytes depending upon your integer. +To indicate which is the last byte of the series, you leave bit #7 clear. +In all of the preceding bytes, you set bit #7. + +So, if an integer is between `0-127`, it can be represented as one byte. +Although VLQ can deal with numbers of arbitrary sizes, for this exercise we will restrict ourselves to only numbers that fit in a 32-bit unsigned integer. +Here are examples of integers as 32-bit values, and the variable length quantities that they translate to: + +```text + NUMBER VARIABLE QUANTITY +00000000 00 +00000040 40 +0000007F 7F +00000080 81 00 +00002000 C0 00 +00003FFF FF 7F +00004000 81 80 00 +00100000 C0 80 00 +001FFFFF FF FF 7F +00200000 81 80 80 00 +08000000 C0 80 80 00 +0FFFFFFF FF FF FF 7F +``` + +## Setup + +Go through the setup instructions for JavaScript to +install the necessary dependencies: + +http://exercism.io/languages/javascript + +## Making the Test Suite Pass + +Execute the tests with: + + jasmine .spec.js + +Replace `` with the name of the current exercise. E.g., to +test the Hello World exercise: + + jasmine hello-world.spec.js + +In many test suites all but the first test have been skipped. + +Once you get a test passing, you can unskip the next one by +changing `xit` to `it`. + +## Source + +A poor Splice developer having to implement MIDI encoding/decoding. [https://splice.com](https://splice.com) + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/variable-length-quantity/example.js b/exercises/variable-length-quantity/example.js new file mode 100644 index 00000000..9aeec820 --- /dev/null +++ b/exercises/variable-length-quantity/example.js @@ -0,0 +1,51 @@ +var LENGTH = 7; +var CONT_BITS = 1 << LENGTH; +var DATA_BITS = CONT_BITS - 1; + +var encodeOne = function (val) { + var buf = []; + var left = val; + + while (left) { + var bits = left & DATA_BITS | CONT_BITS; // set continuation everywhere + left = left >>> LENGTH; + buf.push(bits); + } + buf[0] = buf[0] & DATA_BITS; // cancel the last continuation + return buf.reverse(); +}; + +var decodeOne = function (buf) { + var val = 0; + + for (var i = 0; i < buf.length; i++) { + val = val << LENGTH | buf[i] & DATA_BITS; + } + return val >>> 0; // convert to unsigned 32-bit +}; + +module.exports = { + encode: function encode(data) { + var buf = []; + + for (var i = 0; i < data.length; i++) { + buf = buf.concat(encodeOne(data[i])); + } + return buf; + }, + decode: function decode(data) { + var start = 0; + var vals = []; + + for (var i = 0; i < data.length; i++) { + if (~data[i] & CONT_BITS) { + vals.push(decodeOne(data.slice(start, i + 1))); + start = i + 1; + } + } + if (start < data.length) { + throw new Error('Incomplete sequence'); + } + return vals; + } +}; diff --git a/exercises/variable-length-quantity/variable-length-quantity.spec.js b/exercises/variable-length-quantity/variable-length-quantity.spec.js new file mode 100644 index 00000000..43d066dc --- /dev/null +++ b/exercises/variable-length-quantity/variable-length-quantity.spec.js @@ -0,0 +1,115 @@ +var VLQ = require('./variable-length-quantity'); + +describe('VariableLengthQuantity', function () { + describe('Encode a series of integers, producing a series of bytes.', function () { + it('zero', function () { + expect(VLQ.encode([0])).toEqual([0]); + }); + + it('arbitrary single byte', function () { + expect(VLQ.encode([0x40])).toEqual([0x40]); + }); + + it('largest single byte', function () { + expect(VLQ.encode([0x7f])).toEqual([0x7f]); + }); + + it('smallest double byte', function () { + expect(VLQ.encode([0x80])).toEqual([0x81, 0]); + }); + + it('arbitrary double byte', function () { + expect(VLQ.encode([0x2000])).toEqual([0xc0, 0]); + }); + + it('largest double byte', function () { + expect(VLQ.encode([0x3fff])).toEqual([0xff, 0x7f]); + }); + + it('smallest triple byte', function () { + expect(VLQ.encode([0x4000])).toEqual([0x81, 0x80, 0]); + }); + + it('arbitrary triple byte', function () { + expect(VLQ.encode([0x100000])).toEqual([0xc0, 0x80, 0]); + }); + + it('largest triple byte', function () { + expect(VLQ.encode([0x1fffff])).toEqual([0xff, 0xff, 0x7f]); + }); + + it('smallest quadruple byte', function () { + expect(VLQ.encode([0x200000])).toEqual([0x81, 0x80, 0x80, 0]); + }); + + it('arbitrary quadruple byte', function () { + expect(VLQ.encode([0x8000000])).toEqual([0xc0, 0x80, 0x80, 0]); + }); + + it('largest quadruple byte', function () { + expect(VLQ.encode([0xfffffff])).toEqual([0xff, 0xff, 0xff, 0x7f]); + }); + + it('smallest quintuple byte', function () { + expect(VLQ.encode([0x10000000])).toEqual([0x81, 0x80, 0x80, 0x80, 0]); + }); + + it('arbitrary quintuple byte', function () { + expect(VLQ.encode([0xff000000])).toEqual([0x8f, 0xf8, 0x80, 0x80, 0]); + }); + + it('maximum 32-bit integer input', function () { + expect(VLQ.encode([0xffffffff])).toEqual([0x8f, 0xff, 0xff, 0xff, 0x7f]); + }); + + it('two single-byte values', function () { + expect(VLQ.encode([0x40, 0x7f])).toEqual([0x40, 0x7f]); + }); + + it('two multi-byte values', function () { + expect(VLQ.encode([0x4000, 0x123456])).toEqual([0x81, 0x80, 0, 0xc8, 0xe8, 0x56]); + }); + + it('many multi-byte values', function () { + var input = [0x2000, 0x123456, 0xfffffff, 0, 0x3fff, 0x4000]; + var expected = [0xc0, 0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0, 0xff, 0x7f, 0x81, 0x80, 0]; + expect(VLQ.encode(input)).toEqual(expected); + }); + }); + + describe('Decode a series of bytes, producing a series of integers.', function () { + it('one byte', function () { + expect(VLQ.decode([0x7f])).toEqual([0x7f]); + }); + + it('two bytes', function () { + expect(VLQ.decode([0xc0, 0])).toEqual([0x2000]); + }); + + it('three bytes', function () { + expect(VLQ.decode([0xff, 0xff, 0x7f])).toEqual([0x1fffff]); + }); + + it('four bytes', function () { + expect(VLQ.decode([0x81, 0x80, 0x80, 0])).toEqual([0x200000]); + }); + + it('maximum 32-bit integer', function () { + expect(VLQ.decode([0x8f, 0xff, 0xff, 0xff, 0x7f])).toEqual([0xffffffff]); + }); + + it('incomplete sequence causes error', function () { + expect(function () { VLQ.decode([0xff]); }).toThrow(new Error('Incomplete sequence')); + }); + + it('incomplete sequence causes error, even if value is zero', function () { + expect(function () { VLQ.decode([0x80]); }).toThrow(new Error('Incomplete sequence')); + }); + + it('multiple values', function () { + var input = [0xc0, 0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0, 0xff, 0x7f, 0x81, 0x80, 0]; + var expected = [0x2000, 0x123456, 0xfffffff, 0, 0x3fff, 0x4000]; + expect(VLQ.decode(input)).toEqual(expected); + }); + }); +}); diff --git a/exercises/word-count/README.md b/exercises/word-count/README.md index ae006d10..e0bd287f 100644 --- a/exercises/word-count/README.md +++ b/exercises/word-count/README.md @@ -4,36 +4,38 @@ Given a phrase, count the occurrences of each word in that phrase. For example for the input `"olly olly in come free"` -```plain +```text olly: 2 in: 1 come: 1 free: 1 ``` - ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine word-count.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/word-count/example.js b/exercises/word-count/example.js index 2a357994..34a07d19 100644 --- a/exercises/word-count/example.js +++ b/exercises/word-count/example.js @@ -5,9 +5,9 @@ function Words() {} Words.prototype.count = function (input) { var counts = {}; var words = input.toLowerCase() - .replace(/[,."\/!&@$%\^\*;:{}()¡¿?]/g, ' ') - .replace(/\s'(\w+)'\s/, ' '+'$1'+' ') - .match(/\S+/g); + .replace(/[,."\/!&@$%\^\*;:{}()¡¿?]/g, ' ') + .replace(/\s'(\w+)'\s/, ' ' + '$1' + ' ') + .match(/\S+/g); words.forEach(function (word) { counts[word] = counts.hasOwnProperty(word) ? counts[word] + 1 : 1; diff --git a/exercises/word-count/word-count.spec.js b/exercises/word-count/word-count.spec.js index 8b34faf0..71bb0235 100644 --- a/exercises/word-count/word-count.spec.js +++ b/exercises/word-count/word-count.spec.js @@ -1,79 +1,79 @@ var Words = require('./word-count'); -describe('count()', function() { +describe('count()', function () { var words = new Words(); - it('counts one word', function() { + it('counts one word', function () { var expectedCounts = { word: 1 }; expect(words.count('word')).toEqual(expectedCounts); }); - xit('counts one of each word', 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 of a word', 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('handles cramped lists', function() { + 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() { + 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() { + xit('includes numbers', function () { var expectedCounts = { testing: 2, 1: 1, 2: 1 }; expect(words.count('testing 1 2 testing')).toEqual(expectedCounts); }); - xit('normalizes to lowercase', function() { + xit('normalizes to lowercase', function () { var expectedCounts = { go: 3 }; expect(words.count('go Go GO')).toEqual(expectedCounts); }); - xit('counts words with apostrophes', function() { + 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() { + 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() { + xit('counts properly international characters', function () { var expectedCounts = { 'hola': 1, 'qué': 1, 'tal': 1, 'привет': 1 }; expect(words.count('¡Hola! ¿Qué tal? Привет!')).toEqual(expectedCounts); }); - xit('counts multiline', function() { + xit('counts multiline', function () { var expectedCounts = { hello: 1, world: 1 }; expect(words.count('hello\nworld')).toEqual(expectedCounts); }); - xit('counts tabs as white space', function() { + xit('counts tabs as white space', function () { var expectedCounts = { hello: 1, world: 1 }; expect(words.count('hello\tworld')).toEqual(expectedCounts); }); - xit('counts multiple spaces as one', function() { + xit('counts multiple spaces as one', function () { var expectedCounts = { hello: 1, world: 1 }; expect(words.count('hello world')).toEqual(expectedCounts); }); - xit('does not count leading or trailing whitespace', function() { + xit('does not count leading or trailing whitespace', function () { var expectedCounts = { introductory: 1, course: 1 }; expect(words.count('\t\tIntroductory Course ')).toEqual(expectedCounts); }); - xit('handles properties that exist on Object’s prototype', 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 }; expect(words.count('reserved words like constructor and toString ok?')).toEqual(expectedCounts); }); diff --git a/exercises/wordy/README.md b/exercises/wordy/README.md index 4186cc06..c4950341 100644 --- a/exercises/wordy/README.md +++ b/exercises/wordy/README.md @@ -2,7 +2,6 @@ Parse and evaluate simple math word problems returning the answer as an integer. - ## Iteration 1 — Addition Add two numbers together. @@ -13,7 +12,6 @@ Evaluates to 18. Handle large numbers and negative numbers. - ## Iteration 2 — Subtraction, Multiplication and Division Now, perform the other three operations. @@ -30,7 +28,6 @@ Now, perform the other three operations. 5 - ## Iteration 3 — Multiple Operations Handle a set of operations, in sequence. @@ -46,7 +43,6 @@ left-to-right, _ignoring the typical order of operations._ 15 (i.e. not 9) - ## Bonus — Exponentials If you'd like, handle exponentials. @@ -55,29 +51,31 @@ If you'd like, handle exponentials. 32 - ## Setup -Go through the setup instructions for JavaScript to -install the necessary dependencies: - -http://exercism.io/languages/javascript +Go through the setup instructions for JavaScript to install the + necessary dependencies: -## Making the Test Suite Pass +http://exercism.io/languages/javascript/installation -Execute the tests with: +## Running the test suite - jasmine .spec.js +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: -Replace `` with the name of the current exercise. E.g., to -test the Hello World exercise: +```sh +npm install -g jasmine +``` - jasmine hello-world.spec.js +Run the test suite from the exercise directory with: -In many test suites all but the first test have been skipped. +```sh +jasmine wordy.spec.js +``` -Once you get a test passing, you can unskip the next one by -changing `xit` to `it`. +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. ## Source diff --git a/exercises/wordy/example.js b/exercises/wordy/example.js index 693fb2fe..819cae70 100644 --- a/exercises/wordy/example.js +++ b/exercises/wordy/example.js @@ -4,10 +4,10 @@ exports.WordProblem = WordProblem; exports.ArgumentError = ArgumentError; var BINARY_OPERATORS = { - 'plus': function(l, r) { return l + r; }, - 'minus': function(l, r) { return l - r; }, - 'multiplied by': function(l, r) { return l * r; }, - 'divided by': function(l, r) { return l / r; } + 'plus': function (l, r) { return l + r; }, + 'minus': function (l, r) { return l - r; }, + 'multiplied by': function (l, r) { return l * r; }, + 'divided by': function (l, r) { return l / r; } }; function operators() { @@ -32,34 +32,34 @@ function WordProblem(question) { this.matches = this.question.match(pattern()); } -WordProblem.prototype.tooComplicated = function() { +WordProblem.prototype.tooComplicated = function () { return this.matches === null; }; -WordProblem.prototype.answer = function() { +WordProblem.prototype.answer = function () { if (this.tooComplicated()) { throw new ArgumentError('I don\'t understand the question'); } return this.evaluate(); }; -WordProblem.prototype.evaluate = function() { +WordProblem.prototype.evaluate = function () { var out = 0; var m = this.matches; - if (m[1] !== undefined && m[2] !== undefined && m[3] !== undefined) { + if ( (typeof m[1]) === 'string' && (typeof m[2]) === 'string' && (typeof m[3]) === 'string') { out = this.operate(m[2], m[1], m[3]); } - if (m[4] !== undefined && m[5] !== undefined) { + if ( (typeof m[4]) === 'string' && (typeof m[5]) === 'string') { out = this.operate(m[4], out, m[5]); } return out; }; -WordProblem.prototype.operate = function(operation, l, r) { - var fn = BINARY_OPERATORS[operation] || function() { return 0; }; +WordProblem.prototype.operate = function (operation, l, r) { + var fn = BINARY_OPERATORS[operation] || function () { return 0; }; return fn(Number(l), Number(r)); }; diff --git a/exercises/wordy/wordy.spec.js b/exercises/wordy/wordy.spec.js index 01d5dc4d..6e0a73af 100644 --- a/exercises/wordy/wordy.spec.js +++ b/exercises/wordy/wordy.spec.js @@ -1,90 +1,88 @@ var WordProblem = require('./wordy').WordProblem; var ArgumentError = require('./wordy').ArgumentError; -describe('Word Problem', function() { - - it('add 1', function() { +describe('Word Problem', function () { + it('add 1', function () { var question = 'What is 1 plus 1?'; expect(new WordProblem(question).answer()).toEqual(2); }); - xit('add 2', function() { + xit('add 2', function () { var question = 'What is 53 plus 2?'; expect(new WordProblem(question).answer()).toEqual(55); }); - xit('add negative numbers', function() { + xit('add negative numbers', function () { var question = 'What is -1 plus -10?'; expect(new WordProblem(question).answer()).toEqual(-11); }); - xit('add more digits', function() { + xit('add more digits', function () { var question = 'What is 123 plus 45678?'; expect(new WordProblem(question).answer()).toEqual(45801); }); - xit('subtract', function() { + xit('subtract', function () { var question = 'What is 4 minus -12?'; expect(new WordProblem(question).answer()).toEqual(16); }); - xit('multiply', function() { + xit('multiply', function () { var question = 'What is -3 multiplied by 25?'; expect(new WordProblem(question).answer()).toEqual(-75); }); - xit('divide', function() { + xit('divide', function () { var question = 'What is 33 divided by -3?'; expect(new WordProblem(question).answer()).toEqual(-11); }); - xit('add twice', function() { + xit('add twice', function () { var question = 'What is 1 plus 1 plus 1?'; expect(new WordProblem(question).answer()).toEqual(3); }); - xit('add then subtract', function() { + xit('add then subtract', function () { var question = 'What is 1 plus 5 minus -2?'; expect(new WordProblem(question).answer()).toEqual(8); }); - xit('subtract twice', function() { + xit('subtract twice', function () { var question = 'What is 20 minus 4 minus 13?'; expect(new WordProblem(question).answer()).toEqual(3); }); - xit('subtract then add', function() { + xit('subtract then add', function () { var question = 'What is 17 minus 6 plus 3?'; expect(new WordProblem(question).answer()).toEqual(14); }); - xit('multiply twice', function() { + xit('multiply twice', function () { var question = 'What is 2 multiplied by -2 multiplied by 3?'; expect(new WordProblem(question).answer()).toEqual(-12); }); - xit('add then multiply', function() { + xit('add then multiply', function () { var question = 'What is -3 plus 7 multiplied by -2?'; expect(new WordProblem(question).answer()).toEqual(-8); }); - xit('divide twice', function() { + xit('divide twice', function () { var question = 'What is -12 divided by 2 divided by -3?'; expect(new WordProblem(question).answer()).toEqual(2); }); - xit('too advanced', function() { + xit('too advanced', function () { var question = 'What is 53 cubed?'; var problem = new WordProblem(question); expect(problem.answer.bind(problem)).toThrow(new ArgumentError()); }); - xit('irrelevant', function() { + xit('irrelevant', function () { var question = 'Who is the president of the United States?'; var problem = new WordProblem(question); expect(problem.answer.bind(problem)).toThrow(new ArgumentError()); }); - }); diff --git a/exercises/zipper/README.md b/exercises/zipper/README.md new file mode 100644 index 00000000..ab780272 --- /dev/null +++ b/exercises/zipper/README.md @@ -0,0 +1,57 @@ +# Zipper + +Creating a zipper for a binary tree. + +[Zippers](https://en.wikipedia.org/wiki/Zipper_%28data_structure%29) are +a purely functional way of navigating within a data structure and +manipulating it. They essentially contain a data structure and a +pointer into that data structure (called the focus). + +For example given a rose tree (where each node contains a value and a +list of child nodes) a zipper might support these operations: + +- `from_tree` (get a zipper out of a rose tree, the focus is on the root node) +- `to_tree` (get the rose tree out of the zipper) +- `value` (get the value of the focus node) +- `prev` (move the focus to the previous child of the same parent, + returns a new zipper) +- `next` (move the focus to the next child of the same parent, returns a + new zipper) +- `up` (move the focus to the parent, returns a new zipper) +- `set_value` (set the value of the focus node, returns a new zipper) +- `insert_before` (insert a new subtree before the focus node, it + becomes the `prev` of the focus node, returns a new zipper) +- `insert_after` (insert a new subtree after the focus node, it becomes + the `next` of the focus node, returns a new zipper) +- `delete` (removes the focus node and all subtrees, focus moves to the + `next` node if possible otherwise to the `prev` node if possible, + otherwise to the parent node, returns a new zipper) + +## Setup + +Go through the setup instructions for JavaScript to install the + necessary dependencies: + +http://exercism.io/languages/javascript/installation + +## Running the test suite + +The provided test suite uses [Jasmine](https://jasmine.github.io/). +You can install it by opening a terminal window and running the +following command: + +```sh +npm install -g jasmine +``` + +Run the test suite from the exercise directory with: + +```sh +jasmine zipper.spec.js +``` + +In many test suites all but the first test have been marked "pending". +Once you get a test passing, activate the next one by changing `xit` to `it`. + +## Submitting Incomplete Solutions +It's possible to submit an incomplete solution so you can see how others have completed the exercise. diff --git a/exercises/zipper/example.js b/exercises/zipper/example.js new file mode 100644 index 00000000..d651c4ef --- /dev/null +++ b/exercises/zipper/example.js @@ -0,0 +1,100 @@ +'use strict'; + +function fromTrail(tree, last) { + if (last[0] === 'left') { + return { + value: last[1], + left: tree, + right: last[2] + }; + } + return { + value: last[1], + left: last[2], + right: tree + }; +} + +function rebuildTree(tree, trail) { + if (trail.length === 0) return tree; + + var last = trail[0]; + return rebuildTree(fromTrail(tree, last), trail.slice(1)); +} + +var Zipper = function (tree, trail) { + this.tree = tree; + this.trail = trail; +}; + +Zipper.fromTree = function (tree) { + return new Zipper(tree, []); +}; + +Zipper.prototype.toTree = function () { + return rebuildTree(this.tree, this.trail); +}; + +Zipper.prototype.value = function () { + return this.tree.value; +}; + +Zipper.prototype.left = function () { + if (!this.tree.left) return null; + + return new Zipper( + this.tree.left, + [['left', this.tree.value, this.tree.right]].concat(this.trail) + ); +}; + +Zipper.prototype.right = function () { + if (!this.tree.right) return null; + + return new Zipper( + this.tree.right, + [['right', this.tree.value, this.tree.left]].concat(this.trail) + ); +}; + +Zipper.prototype.up = function () { + if (this.trail.length === 0) return null; + + var last = this.trail[0]; + return new Zipper(fromTrail(this.tree, last), this.trail.slice(1)); +}; + +Zipper.prototype.setValue = function (value) { + return new Zipper( + { + value: value, + left: this.tree.left, + right: this.tree.right + }, + this.trail + ); +}; + +Zipper.prototype.setLeft = function (left) { + return new Zipper( + { + value: this.tree.value, + left: left, + right: this.tree.right + }, + this.trail + ); +}; + +Zipper.prototype.setRight = function (right) { + return new Zipper( + { + value: this.tree.value, + left: this.tree.left, + right: right + }, + this.trail + ); +}; + +module.exports = Zipper; diff --git a/exercises/zipper/zipper.spec.js b/exercises/zipper/zipper.spec.js new file mode 100644 index 00000000..c3b95d12 --- /dev/null +++ b/exercises/zipper/zipper.spec.js @@ -0,0 +1,77 @@ +var Zipper = require('./zipper'); + +// Tests adapted from `problem-specifications/zipper/canonical-data.json` @ v1.0.0 + +function bt(value, left, right) { + return { + value: value, + left: left, + right: right + }; +} + +function leaf(value) { + return bt(value, null, null); +} + +describe('Zipper', function () { + var t1 = bt(1, bt(2, null, leaf(3)), leaf(4)); + var t2 = bt(1, bt(5, null, leaf(3)), leaf(4)); + var t3 = bt(1, bt(2, leaf(5), leaf(3)), leaf(4)); + var t4 = bt(1, leaf(2), leaf(4)); + var t5 = bt(1, bt(2, null, leaf(3)), bt(6, leaf(7), leaf(8))); + var t6 = bt(1, bt(2, null, leaf(5)), leaf(4)); + var zipper; + + beforeEach(function () { + zipper = Zipper.fromTree(t1); + }); + + it('data is retained', function () { + expect(zipper.toTree(t1)).toEqual(t1); + }); + + xit('left, right and value', function () { + expect(zipper.left().right().value()).toEqual(3); + }); + + xit('dead end', function () { + expect(zipper.left().left()).toBe(null); + }); + + xit('tree from deep focus', function () { + expect(zipper.left().right().toTree()).toEqual(t1); + }); + + xit('traversing up from top', function () { + expect(zipper.up()).toEqual(null); + }); + + xit('left, right and up', function () { + expect(zipper.left().up().right().up().left().right().value()).toEqual(3); + }); + + xit('setValue', function () { + expect(zipper.left().setValue(5).toTree()).toEqual(t2); + }); + + xit('setValue after traversing up', function () { + expect(zipper.left().right().up().setValue(5).toTree()).toEqual(t2); + }); + + xit('setLeft with leaf', function () { + expect(zipper.left().setLeft(leaf(5)).toTree()).toEqual(t3); + }); + + xit('setRight with null', function () { + expect(zipper.left().setRight(null).toTree()).toEqual(t4); + }); + + xit('setRight with subtree', function () { + expect(zipper.setRight(bt(6, leaf(7), leaf(8))).toTree()).toEqual(t5); + }); + + xit('setValue on deep focus', function () { + expect(zipper.left().right().setValue(5).toTree()).toEqual(t6); + }); +}); diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 00000000..94eab4b5 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1839 @@ +{ + "name": "javascript", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0-beta.31.tgz", + "integrity": "sha512-yd7CkUughvHQoEahQqcMdrZw6o/6PwUxiRkfZuVDVHCDe77mysD/suoNyk5mK6phTnRW1kyIbPHyCJgxw++LXg==", + "dev": true, + "requires": { + "chalk": "2.3.0", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + } + }, + "@babel/helper-function-name": { + "version": "7.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.31.tgz", + "integrity": "sha512-c+DAyp8LMm2nzSs2uXEuxp4LYGSUYEyHtU3fU57avFChjsnTmmpWmXj2dv0yUxHTEydgVAv5fIzA+4KJwoqWDA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "7.0.0-beta.31", + "@babel/template": "7.0.0-beta.31", + "@babel/traverse": "7.0.0-beta.31", + "@babel/types": "7.0.0-beta.31" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.31.tgz", + "integrity": "sha512-m7rVVX/dMLbbB9NCzKYRrrFb0qZxgpmQ4Wv6y7zEsB6skoJHRuXVeb/hAFze79vXBbuD63ci7AVHXzAdZSk9KQ==", + "dev": true, + "requires": { + "@babel/types": "7.0.0-beta.31" + } + }, + "@babel/template": { + "version": "7.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.0.0-beta.31.tgz", + "integrity": "sha512-97IRmLvoDhIDSQkqklVt3UCxJsv0LUEVb/0DzXWtc8Lgiyxj567qZkmTG9aR21CmcJVVIvq2Y/moZj4oEpl5AA==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.31", + "@babel/types": "7.0.0-beta.31", + "babylon": "7.0.0-beta.31", + "lodash": "4.17.4" + } + }, + "@babel/traverse": { + "version": "7.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.0.0-beta.31.tgz", + "integrity": "sha512-3N+VJW+KlezEjFBG7WSYeMyC5kIqVLPb/PGSzCDPFcJrnArluD1GIl7Y3xC7cjKiTq2/JohaLWHVPjJWHlo9Gg==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.31", + "@babel/helper-function-name": "7.0.0-beta.31", + "@babel/types": "7.0.0-beta.31", + "babylon": "7.0.0-beta.31", + "debug": "3.1.0", + "globals": "10.4.0", + "invariant": "2.2.2", + "lodash": "4.17.4" + } + }, + "@babel/types": { + "version": "7.0.0-beta.31", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.0.0-beta.31.tgz", + "integrity": "sha512-exAHB+NeFGxkfQ5dSUD03xl3zYGneeSk2Mw2ldTt/nTvYxuDiuSp3DlxgUBgzbdTFG4fbwPk0WtKWOoTXCmNGg==", + "dev": true, + "requires": { + "esutils": "2.0.2", + "lodash": "4.17.4", + "to-fast-properties": "2.0.0" + } + }, + "acorn": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.2.1.tgz", + "integrity": "sha512-jG0u7c4Ly+3QkkW18V+NRDN+4bWHdln30NL1ZL2AvFZZmQe/BfopYCtghCKKVBUSetZ4QKcyA0pY6/4Gw8Pv8w==", + "dev": true + }, + "acorn-jsx": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz", + "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=", + "dev": true, + "requires": { + "acorn": "3.3.0" + }, + "dependencies": { + "acorn": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz", + "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=", + "dev": true + } + } + }, + "ajv": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.1.tgz", + "integrity": "sha1-s4u4h22ehr7plJVqBOch6IskjrI=", + "dev": true, + "requires": { + "co": "4.6.0", + "fast-deep-equal": "1.0.0", + "fast-json-stable-stringify": "2.0.0", + "json-schema-traverse": "0.3.1" + } + }, + "ajv-keywords": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.1.tgz", + "integrity": "sha1-YXmX/F9gV2iUxDX5QNgZ4TW4B2I=", + "dev": true + }, + "ansi-escapes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.0.0.tgz", + "integrity": "sha512-O/klc27mWNUigtv0F8NJWbLF00OcegQalkqKURWdosW08YZKi4m6CnSUSvIZG1otNJbTWhN01Hhz389DW7mvDQ==", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.0.tgz", + "integrity": "sha512-NnSOmMEYtVR2JVMIGTzynRkkaxtiq1xnFBcdQD/DnNCYPoEPsVJhM98BDyaoNOQIi7p4okdi3E27eN7GQbsUug==", + "dev": true, + "requires": { + "color-convert": "1.9.1" + } + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "array-includes": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz", + "integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=", + "dev": true, + "requires": { + "define-properties": "1.1.2", + "es-abstract": "1.10.0" + } + }, + "array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=", + "dev": true, + "requires": { + "array-uniq": "1.0.3" + } + }, + "array-uniq": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=", + "dev": true + }, + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=", + "dev": true + }, + "asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=", + "dev": true + }, + "babel-code-frame": { + "version": "6.26.0", + "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz", + "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "esutils": "2.0.2", + "js-tokens": "3.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "babel-eslint": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-8.0.3.tgz", + "integrity": "sha512-7D4iUpylEiKJPGbeSAlNddGcmA41PadgZ6UAb6JVyh003h3d0EbZusYFBR/+nBgqtaVJM2J2zUVa3N0hrpMH6g==", + "dev": true, + "requires": { + "@babel/code-frame": "7.0.0-beta.31", + "@babel/traverse": "7.0.0-beta.31", + "@babel/types": "7.0.0-beta.31", + "babylon": "7.0.0-beta.31" + } + }, + "babylon": { + "version": "7.0.0-beta.31", + "resolved": "https://registry.npmjs.org/babylon/-/babylon-7.0.0-beta.31.tgz", + "integrity": "sha512-6lm2mV3S51yEnKmQQNnswoABL1U1H1KHoCCVwdwI3hvIv+W7ya4ki7Aw4o4KxtUHjNKkK5WpZb22rrMMOcJXJQ==", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "caller-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz", + "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=", + "dev": true, + "requires": { + "callsites": "0.2.0" + } + }, + "callsites": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz", + "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=", + "dev": true + }, + "chalk": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz", + "integrity": "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q==", + "dev": true, + "requires": { + "ansi-styles": "3.2.0", + "escape-string-regexp": "1.0.5", + "supports-color": "4.5.0" + } + }, + "chardet": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz", + "integrity": "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I=", + "dev": true + }, + "circular-json": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz", + "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==", + "dev": true + }, + "cli-cursor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz", + "integrity": "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=", + "dev": true, + "requires": { + "restore-cursor": "2.0.0" + } + }, + "cli-width": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz", + "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=", + "dev": true + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "color-convert": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.1.tgz", + "integrity": "sha512-mjGanIiwQJskCC18rPR6OmrZ6fm2Lc7PeGFYwCmy5J34wC6F1PzdGL6xeMfmgicfYcNLGuVFA3WzXtIDCQSZxQ==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz", + "integrity": "sha1-CqxmL9Ur54lk1VMvaUeE5wEQrPc=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "readable-stream": "2.3.3", + "typedarray": "0.0.6" + } + }, + "contains-path": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz", + "integrity": "sha1-/ozxhP9mcLa67wGp1IYaXL7EEgo=", + "dev": true + }, + "core-js": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", + "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cross-spawn": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz", + "integrity": "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk=", + "dev": true, + "requires": { + "lru-cache": "4.1.1", + "shebang-command": "1.2.0", + "which": "1.3.0" + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.2.tgz", + "integrity": "sha1-g6c/L+pWmJj7c3GTyPhzyvbUXJQ=", + "dev": true, + "requires": { + "foreach": "2.0.5", + "object-keys": "1.0.11" + } + }, + "del": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha1-wSyYHQZ4RshLyvhiz/kw2Qf/0ag=", + "dev": true, + "requires": { + "globby": "5.0.0", + "is-path-cwd": "1.0.0", + "is-path-in-cwd": "1.0.0", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1", + "rimraf": "2.6.2" + } + }, + "doctrine": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.0.2.tgz", + "integrity": "sha512-y0tm5Pq6ywp3qSTZ1vPgVdAnbDEoeoc5wlOHXoY1c4Wug/a7JvqHIl7BTvwodaHmejWkK/9dSb3sCYfyo/om8A==", + "dev": true, + "requires": { + "esutils": "2.0.2" + } + }, + "encoding": { + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", + "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", + "dev": true, + "requires": { + "iconv-lite": "0.4.19" + } + }, + "error-ex": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz", + "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=", + "dev": true, + "requires": { + "is-arrayish": "0.2.1" + } + }, + "es-abstract": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.10.0.tgz", + "integrity": "sha512-/uh/DhdqIOSkAWifU+8nG78vlQxdLckUdI/sPgy0VhuXi2qJ7T8czBmqIYtLQVpCIFYafChnsRsB5pyb1JdmCQ==", + "dev": true, + "requires": { + "es-to-primitive": "1.1.1", + "function-bind": "1.1.1", + "has": "1.0.1", + "is-callable": "1.1.3", + "is-regex": "1.0.4" + } + }, + "es-to-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.1.1.tgz", + "integrity": "sha1-RTVSSKiJeQNLZ5Lhm7gfK3l13Q0=", + "dev": true, + "requires": { + "is-callable": "1.1.3", + "is-date-object": "1.0.1", + "is-symbol": "1.0.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-4.13.1.tgz", + "integrity": "sha512-UCJVV50RtLHYzBp1DZ8CMPtRSg4iVZvjgO9IJHIKyWU/AnJVjtdRikoUPLB29n5pzMB7TnsLQWf0V6VUJfoPfw==", + "dev": true, + "requires": { + "ajv": "5.5.1", + "babel-code-frame": "6.26.0", + "chalk": "2.3.0", + "concat-stream": "1.6.0", + "cross-spawn": "5.1.0", + "debug": "3.1.0", + "doctrine": "2.0.2", + "eslint-scope": "3.7.1", + "espree": "3.5.2", + "esquery": "1.0.0", + "estraverse": "4.2.0", + "esutils": "2.0.2", + "file-entry-cache": "2.0.0", + "functional-red-black-tree": "1.0.1", + "glob": "7.1.2", + "globals": "11.1.0", + "ignore": "3.3.7", + "imurmurhash": "0.1.4", + "inquirer": "3.3.0", + "is-resolvable": "1.0.1", + "js-yaml": "3.10.0", + "json-stable-stringify-without-jsonify": "1.0.1", + "levn": "0.3.0", + "lodash": "4.17.4", + "minimatch": "3.0.4", + "mkdirp": "0.5.1", + "natural-compare": "1.4.0", + "optionator": "0.8.2", + "path-is-inside": "1.0.2", + "pluralize": "7.0.0", + "progress": "2.0.0", + "require-uncached": "1.0.3", + "semver": "5.4.1", + "strip-ansi": "4.0.0", + "strip-json-comments": "2.0.1", + "table": "4.0.2", + "text-table": "0.2.0" + }, + "dependencies": { + "globals": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.1.0.tgz", + "integrity": "sha512-uEuWt9mqTlPDwSqi+sHjD4nWU/1N+q0fiWI9T1mZpD2UENqX20CFD5T/ziLZvztPaBKl7ZylUi1q6Qfm7E2CiQ==", + "dev": true + } + } + }, + "eslint-config-airbnb-base": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-12.1.0.tgz", + "integrity": "sha512-/vjm0Px5ZCpmJqnjIzcFb9TKZrKWz0gnuG/7Gfkt0Db1ELJR51xkZth+t14rYdqWgX836XbuxtArbIHlVhbLBA==", + "dev": true, + "requires": { + "eslint-restricted-globals": "0.1.1" + } + }, + "eslint-config-airbnb-es5": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eslint-config-airbnb-es5/-/eslint-config-airbnb-es5-1.2.0.tgz", + "integrity": "sha512-MaOKwNpqNZIRy+3augFj5vGHJ4F1sskPjJ/Od7K3N8Vv+8pD6t73XCL18KrHrF1m58qFxPBDl1US6bswE65IbQ==", + "dev": true, + "requires": { + "strip-json-comments": "1.0.2" + }, + "dependencies": { + "strip-json-comments": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.2.tgz", + "integrity": "sha1-WkirlgI9usG3uND/q/b2PxZ3vp8=", + "dev": true + } + } + }, + "eslint-import-resolver-node": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.1.tgz", + "integrity": "sha512-yUtXS15gIcij68NmXmP9Ni77AQuCN0itXbCc/jWd8C6/yKZaSNXicpC8cgvjnxVdmfsosIXrjpzFq7GcDryb6A==", + "dev": true, + "requires": { + "debug": "2.6.9", + "resolve": "1.5.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-module-utils": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz", + "integrity": "sha512-jDI/X5l/6D1rRD/3T43q8Qgbls2nq5km5KSqiwlyUbGo5+04fXhMKdCPhjwbqAa6HXWaMxj8Q4hQDIh7IadJQw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "pkg-dir": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "eslint-plugin-import": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.8.0.tgz", + "integrity": "sha512-Rf7dfKJxZ16QuTgVv1OYNxkZcsu/hULFnC+e+w0Gzi6jMC3guQoWQgxYxc54IDRinlb6/0v5z/PxxIKmVctN+g==", + "dev": true, + "requires": { + "builtin-modules": "1.1.1", + "contains-path": "0.1.0", + "debug": "2.6.9", + "doctrine": "1.5.0", + "eslint-import-resolver-node": "0.3.1", + "eslint-module-utils": "2.1.1", + "has": "1.0.1", + "lodash.cond": "4.5.2", + "minimatch": "3.0.4", + "read-pkg-up": "2.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "doctrine": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-1.5.0.tgz", + "integrity": "sha1-N53Ocw9hZvds76TmcHoVmwLFpvo=", + "dev": true, + "requires": { + "esutils": "2.0.2", + "isarray": "1.0.0" + } + } + } + }, + "eslint-plugin-jasmine": { + "version": "2.9.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jasmine/-/eslint-plugin-jasmine-2.9.1.tgz", + "integrity": "sha1-IuGaWfFvOl9kOgSroEQ40OMEcDA=", + "dev": true + }, + "eslint-plugin-react": { + "version": "7.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.5.1.tgz", + "integrity": "sha512-YGSjB9Qu6QbVTroUZi66pYky3DfoIPLdHQ/wmrBGyBRnwxQsBXAov9j2rpXt/55i8nyMv6IRWJv2s4d4YnduzQ==", + "dev": true, + "requires": { + "doctrine": "2.0.2", + "has": "1.0.1", + "jsx-ast-utils": "2.0.1", + "prop-types": "15.6.0" + } + }, + "eslint-restricted-globals": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz", + "integrity": "sha1-NfDVy8ZMLj7WLpO0saevBbp+1Nc=", + "dev": true + }, + "eslint-scope": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-3.7.1.tgz", + "integrity": "sha1-PWPD7f2gLgbgGkUq2IyqzHzctug=", + "dev": true, + "requires": { + "esrecurse": "4.2.0", + "estraverse": "4.2.0" + } + }, + "espree": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.2.tgz", + "integrity": "sha512-sadKeYwaR/aJ3stC2CdvgXu1T16TdYN+qwCpcWbMnGJ8s0zNWemzrvb2GbD4OhmJ/fwpJjudThAlLobGbWZbCQ==", + "dev": true, + "requires": { + "acorn": "5.2.1", + "acorn-jsx": "3.0.1" + } + }, + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + }, + "esquery": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.0.tgz", + "integrity": "sha1-z7qLV9f7qT8XKYqKAGoEzaE9gPo=", + "dev": true, + "requires": { + "estraverse": "4.2.0" + } + }, + "esrecurse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz", + "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=", + "dev": true, + "requires": { + "estraverse": "4.2.0", + "object-assign": "4.1.1" + } + }, + "estraverse": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", + "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "external-editor": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-2.1.0.tgz", + "integrity": "sha512-E44iT5QVOUJBKij4IIV3uvxuNlbKS38Tw1HiupxEIHPv9qtC2PrDYohbXV5U+1jnfIXttny8gUhj+oZvflFlzA==", + "dev": true, + "requires": { + "chardet": "0.4.2", + "iconv-lite": "0.4.19", + "tmp": "0.0.33" + } + }, + "fast-deep-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz", + "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fbjs": { + "version": "0.8.16", + "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.16.tgz", + "integrity": "sha1-XmdDL1UNxBtXK/VYR7ispk5TN9s=", + "dev": true, + "requires": { + "core-js": "1.2.7", + "isomorphic-fetch": "2.2.1", + "loose-envify": "1.3.1", + "object-assign": "4.1.1", + "promise": "7.3.1", + "setimmediate": "1.0.5", + "ua-parser-js": "0.7.17" + } + }, + "figures": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz", + "integrity": "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=", + "dev": true, + "requires": { + "escape-string-regexp": "1.0.5" + } + }, + "file-entry-cache": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz", + "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=", + "dev": true, + "requires": { + "flat-cache": "1.3.0", + "object-assign": "4.1.1" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "2.1.0", + "pinkie-promise": "2.0.1" + } + }, + "flat-cache": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.0.tgz", + "integrity": "sha1-0wMLMrOBVPTjt+nHCfSQ9++XxIE=", + "dev": true, + "requires": { + "circular-json": "0.3.3", + "del": "2.2.2", + "graceful-fs": "4.1.11", + "write": "0.2.1" + } + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", + "dev": true + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, + "glob": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz", + "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "globals": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-10.4.0.tgz", + "integrity": "sha512-uNUtxIZpGyuaq+5BqGGQHsL4wUlJAXRqOm6g3Y48/CWNGTLONgBibI0lh6lGxjR2HljFYUfszb+mk4WkgMntsA==", + "dev": true + }, + "globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha1-69hGZ8oNuzMLmbz8aOrCvFQ3Dg0=", + "dev": true, + "requires": { + "array-union": "1.0.2", + "arrify": "1.0.1", + "glob": "7.1.2", + "object-assign": "4.1.1", + "pify": "2.3.0", + "pinkie-promise": "2.0.1" + } + }, + "graceful-fs": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", + "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=", + "dev": true + }, + "has": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.1.tgz", + "integrity": "sha1-hGFzP1OLCDfJNh45qauelwTcLyg=", + "dev": true, + "requires": { + "function-bind": "1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz", + "integrity": "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE=", + "dev": true + }, + "hosted-git-info": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz", + "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.19", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.19.tgz", + "integrity": "sha512-oTZqweIP51xaGPI4uPa56/Pri/480R+mo7SeU+YETByQNhDG55ycFyNLIgta9vXhILrxXDmF7ZGhqZIcuN0gJQ==", + "dev": true + }, + "ignore": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.7.tgz", + "integrity": "sha512-YGG3ejvBNHRqu0559EOxxNFihD0AjpvHlC/pdGKd3X3ofe+CoJkYazwNJYTNebqpPKN+VVQbh4ZFn1DivMNuHA==", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "inquirer": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz", + "integrity": "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ==", + "dev": true, + "requires": { + "ansi-escapes": "3.0.0", + "chalk": "2.3.0", + "cli-cursor": "2.1.0", + "cli-width": "2.2.0", + "external-editor": "2.1.0", + "figures": "2.0.0", + "lodash": "4.17.4", + "mute-stream": "0.0.7", + "run-async": "2.3.0", + "rx-lite": "4.0.8", + "rx-lite-aggregates": "4.0.8", + "string-width": "2.1.1", + "strip-ansi": "4.0.0", + "through": "2.3.8" + } + }, + "invariant": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz", + "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=", + "dev": true, + "requires": { + "loose-envify": "1.3.1" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "1.1.1" + } + }, + "is-callable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.3.tgz", + "integrity": "sha1-hut1OSgF3cM69xySoO7fdO52BLI=", + "dev": true + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-path-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha1-0iXsIxMuie3Tj9p2dHLmLmXxEG0=", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz", + "integrity": "sha1-ZHdYK4IU1gI0YJRWcAO+ip6sBNw=", + "dev": true, + "requires": { + "is-path-inside": "1.0.1" + } + }, + "is-path-inside": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha1-jvW33lBDej/cprToZe96pVy0gDY=", + "dev": true, + "requires": { + "path-is-inside": "1.0.2" + } + }, + "is-promise": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz", + "integrity": "sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=", + "dev": true + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "1.0.1" + } + }, + "is-resolvable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.0.1.tgz", + "integrity": "sha512-y5CXYbzvB3jTnWAZH1Nl7ykUWb6T3BcTs56HUruwBf8MhF56n1HWqhDWnVFo8GHrUPDgvUUNVhrc2U8W7iqz5g==", + "dev": true + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.1.tgz", + "integrity": "sha1-PMWfAAJRlLarLjjbrmaJJWtmBXI=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isomorphic-fetch": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", + "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", + "dev": true, + "requires": { + "node-fetch": "1.7.3", + "whatwg-fetch": "2.0.3" + } + }, + "jasmine": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-3.1.0.tgz", + "integrity": "sha1-K9Wf1+xuwOistk4J9Fpo7SrRlSo=", + "dev": true, + "requires": { + "glob": "7.1.2", + "jasmine-core": "3.1.0" + } + }, + "jasmine-core": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.1.0.tgz", + "integrity": "sha1-pHheE11d9lAk38kiSVPfWFvSdmw=", + "dev": true + }, + "js-tokens": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz", + "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=", + "dev": true + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + } + }, + "json-schema-traverse": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz", + "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "jsx-ast-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz", + "integrity": "sha1-6AGxs5mF4g//yHtA43SAgOLcrH8=", + "dev": true, + "requires": { + "array-includes": "3.0.3" + } + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "load-json-file": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz", + "integrity": "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg=", + "dev": true, + "requires": { + "graceful-fs": "4.1.11", + "parse-json": "2.2.0", + "pify": "2.3.0", + "strip-bom": "3.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "2.0.0", + "path-exists": "3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "lodash.cond": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/lodash.cond/-/lodash.cond-4.5.2.tgz", + "integrity": "sha1-9HGh2khr5g9quVXRcRVSPdHSVdU=", + "dev": true + }, + "loose-envify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz", + "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=", + "dev": true, + "requires": { + "js-tokens": "3.0.2" + } + }, + "lru-cache": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz", + "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==", + "dev": true, + "requires": { + "pseudomap": "1.0.2", + "yallist": "2.1.2" + } + }, + "mimic-fn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.1.0.tgz", + "integrity": "sha1-5md4PZLonb00KBi1IwudYqZyrRg=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stream": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz", + "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=", + "dev": true + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "node-fetch": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", + "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", + "dev": true, + "requires": { + "encoding": "0.1.12", + "is-stream": "1.1.0" + } + }, + "normalize-package-data": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz", + "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==", + "dev": true, + "requires": { + "hosted-git-info": "2.5.0", + "is-builtin-module": "1.0.0", + "semver": "5.4.1", + "validate-npm-package-license": "3.0.1" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-keys": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.11.tgz", + "integrity": "sha1-xUYBd4rVYPEULODgG8yotW0TQm0=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "onetime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz", + "integrity": "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=", + "dev": true, + "requires": { + "mimic-fn": "1.1.0" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "p-limit": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.1.0.tgz", + "integrity": "sha1-sH/y2aXYi+yAYDWJWiurZqJ5iLw=", + "dev": true + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "1.1.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "1.3.1" + } + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "2.0.1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-is-inside": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=", + "dev": true + }, + "path-parse": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.5.tgz", + "integrity": "sha1-PBrfhx6pzWyUMbbqK9dKD/BVxME=", + "dev": true + }, + "path-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz", + "integrity": "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM=", + "dev": true, + "requires": { + "pify": "2.3.0" + } + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "pkg-dir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz", + "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=", + "dev": true, + "requires": { + "find-up": "1.1.2" + } + }, + "pluralize": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz", + "integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow==", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "progress": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.0.tgz", + "integrity": "sha1-ihvjZr+Pwj2yvSPxDG/pILQ4nR8=", + "dev": true + }, + "promise": { + "version": "7.3.1", + "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", + "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", + "dev": true, + "requires": { + "asap": "2.0.6" + } + }, + "prop-types": { + "version": "15.6.0", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.0.tgz", + "integrity": "sha1-zq8IMCL8RrSjX2nhPvda7Q1jmFY=", + "dev": true, + "requires": { + "fbjs": "0.8.16", + "loose-envify": "1.3.1", + "object-assign": "4.1.1" + } + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "read-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz", + "integrity": "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg=", + "dev": true, + "requires": { + "load-json-file": "2.0.0", + "normalize-package-data": "2.4.0", + "path-type": "2.0.0" + } + }, + "read-pkg-up": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz", + "integrity": "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4=", + "dev": true, + "requires": { + "find-up": "2.1.0", + "read-pkg": "2.0.0" + }, + "dependencies": { + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "2.0.0" + } + } + } + }, + "readable-stream": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz", + "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==", + "dev": true, + "requires": { + "core-util-is": "1.0.2", + "inherits": "2.0.3", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "safe-buffer": "5.1.1", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "require-uncached": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz", + "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=", + "dev": true, + "requires": { + "caller-path": "0.1.0", + "resolve-from": "1.0.1" + } + }, + "resolve": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.5.0.tgz", + "integrity": "sha512-hgoSGrc3pjzAPHNBg+KnFcK2HwlHTs/YrAGUr6qgTVUZmXv1UEXXl0bZNBKMA9fud6lRYFdPGz0xXxycPzmmiw==", + "dev": true, + "requires": { + "path-parse": "1.0.5" + } + }, + "resolve-from": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz", + "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=", + "dev": true + }, + "restore-cursor": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz", + "integrity": "sha1-n37ih/gv0ybU/RYpI9YhKe7g368=", + "dev": true, + "requires": { + "onetime": "2.0.1", + "signal-exit": "3.0.2" + } + }, + "rimraf": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.2.tgz", + "integrity": "sha512-lreewLK/BlghmxtfH36YYVg1i8IAce4TI7oao75I1g245+6BctqTVQiBP3YUJ9C6DQOXJmkYR9X9fCLtCOJc5w==", + "dev": true, + "requires": { + "glob": "7.1.2" + } + }, + "run-async": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.3.0.tgz", + "integrity": "sha1-A3GrSuC91yDUFm19/aZP96RFpsA=", + "dev": true, + "requires": { + "is-promise": "2.1.0" + } + }, + "rx-lite": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz", + "integrity": "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ=", + "dev": true + }, + "rx-lite-aggregates": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz", + "integrity": "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74=", + "dev": true, + "requires": { + "rx-lite": "4.0.8" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "slice-ansi": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-1.0.0.tgz", + "integrity": "sha512-POqxBK6Lb3q6s047D/XsDVNPnF9Dl8JSaqe9h9lURl0OdNqy/ujDrOiIHtsqXMGbWWTIomRzAMaTyawAU//Reg==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0" + } + }, + "spdx-correct": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz", + "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=", + "dev": true, + "requires": { + "spdx-license-ids": "1.2.2" + } + }, + "spdx-expression-parse": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz", + "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=", + "dev": true + }, + "spdx-license-ids": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz", + "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=", + "dev": true + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "string-width": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz", + "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==", + "dev": true, + "requires": { + "is-fullwidth-code-point": "2.0.0", + "strip-ansi": "4.0.0" + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + } + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true + }, + "supports-color": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz", + "integrity": "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s=", + "dev": true, + "requires": { + "has-flag": "2.0.0" + } + }, + "table": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/table/-/table-4.0.2.tgz", + "integrity": "sha512-UUkEAPdSGxtRpiV9ozJ5cMTtYiqz7Ni1OGqLXRCynrvzdtR1p+cfOWe2RJLwvUG8hNanaSRjecIqwOjqeatDsA==", + "dev": true, + "requires": { + "ajv": "5.5.1", + "ajv-keywords": "2.1.1", + "chalk": "2.3.0", + "lodash": "4.17.4", + "slice-ansi": "1.0.0", + "string-width": "2.1.1" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dev": true, + "requires": { + "os-tmpdir": "1.0.2" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.17", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.17.tgz", + "integrity": "sha512-uRdSdu1oA1rncCQL7sCj8vSyZkgtL7faaw9Tc9rZ3mGgraQ7+Pdx7w5mnOSF3gw9ZNG6oc+KXfkon3bKuROm0g==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz", + "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=", + "dev": true, + "requires": { + "spdx-correct": "1.0.2", + "spdx-expression-parse": "1.0.4" + } + }, + "whatwg-fetch": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz", + "integrity": "sha1-nITsLc9oGH/wC8ZOEnS0QhduHIQ=", + "dev": true + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "write": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz", + "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=", + "dev": true, + "requires": { + "mkdirp": "0.5.1" + } + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..001c8229 --- /dev/null +++ b/package.json @@ -0,0 +1,35 @@ +{ + "name": "javascript", + "version": "1.0.0", + "description": "Exercism exercises in JavaScript.", + "main": "index.js", + "repository": "https://github.com/exercism/javascript", + "author": "Katrina Owen", + "license": "MIT", + "devDependencies": { + "babel-eslint": "^8.0.0", + "eslint": "^4.10.0", + "eslint-config-airbnb-base": "^12.1.0", + "eslint-config-airbnb-es5": "^1.2.0", + "eslint-plugin-import": "^2.8.0", + "eslint-plugin-jasmine": "^2.9.1", + "eslint-plugin-react": "^7.3.0", + "jasmine": "^3.1.0" + }, + "scripts": { + "lint": "eslint .", + "lint-fix": "eslint . --fix" + }, + "eslintConfig": { + "plugins": [ + "jasmine" + ], + "env": { + "jasmine": true + }, + "extends": "eslint-config-airbnb-es5", + "rules": { + "func-names": "off" + } + } +}