<!DOCTYPE html>
<html>

  <head>
    <title>Jasmine Testing Environment</title>
    <link data-require="jasmine@2.4.1" data-semver="2.4.1" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.css" />
    <script data-require="jasmine@2.4.1" data-semver="2.4.1" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine.js"></script>
    <script data-require="jasmine@2.4.1" data-semver="2.4.1" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/jasmine-html.js"></script>
    <script data-require="jasmine@2.4.1" data-semver="2.4.1" src="https://cdnjs.cloudflare.com/ajax/libs/jasmine/2.4.1/boot.js"></script>
    <link rel="stylesheet" href="style.css" />
    <script src="script.js"></script>
  </head>

  <body></body>

</html>
// Code goes here
function compose(...fns) {
  return fns.reduceRight(function reducer(fn1, fn2) {
    return function composed(...args) {
      return fn2(fn1(...args));
    };
  });
}

function curry(fn, arity = fn.length) {
  return (function nextCurried(prevArgs) {
    return function curried(...nextArgs) {
      var args = prevArgs.concat( nextArgs );

      if(args.length >= arity) {
        return fn( ...args );
      } else {
        return nextCurried( args );
      }
    }
  })( [] );
}

function unboundMethod(methodName, argCount = 2) {
  return curry(
    function(...args) {
      var obj = args.pop();
      return obj[methodName](...args)
    },
    argCount
  );
}

function range(min, max) {
  let x = min;
  let arr = []
  while (x <= max) {
    arr.push(x++);
  }
  return arr
}

var reduce = unboundMethod('reduce', 3);
var map = unboundMethod('map', 2);
var square = x => x * x;
var sum = (x,y) => x + y;

var sumOfSquares = compose( reduce( sum, 0 ), map( square ) );
var squareOfSum = compose( square, reduce( sum, 0 ));

var theRange = range(1, 100);

var sumSquareDifference = function (range) {
  return squareOfSum(range) - sumOfSquares(range);
}

console.log(sumSquareDifference(theRange));

describe('range', function () {
  it('should produce an array of natural numbers given a min and max', function() {
    expect(range(1,2)).toEqual([1,2])
    expect(range(4,7)).toEqual([4,5,6,7])
    expect(range(-4,-1)).toEqual([-4,-3,-2,-1])
  })
})

describe('square', function () {
  it('should square a number', function () {
    expect(square(2)).toEqual(4)
    expect(square(-2)).toEqual(4)
    expect(square(2.5)).toEqual(6.25)
  })
})

describe('sum', function () {
  it('should sum two numbers', function () {
    expect(sum(2, 2)).toEqual(4)
    expect(sum(-2, -2)).toEqual(-4)
    expect(sum(-3, 4)).toEqual(1)
  })
})

describe('sumOfSquares', function () {
  it('should sum the sqaures of an array of numbers', function () {
    expect(sumOfSquares([1,2,3])).toEqual(14)
    expect(sumOfSquares([1,2,3,4])).toEqual(30)
    expect(sumOfSquares(range(1,10))).toEqual(385)
  })
})

describe('squareOfSum', function () {
  it('should sum the sqaures of an array of numbers', function () {
    expect(squareOfSum([1,2,3])).toEqual(36)
    expect(squareOfSum([1,2,3,4])).toEqual(100)
    expect(squareOfSum(range(1,10))).toEqual(3025)
  })
})

describe('sumSquareDifference', function () {
  it('should return difference of squareOfSum and sumOfSquares for a range', function () {
    expect(sumSquareDifference(range(1,2))).toEqual(4);
    expect(sumSquareDifference(range(1,3))).toEqual(22);
    expect(sumSquareDifference(range(1,10))).toEqual(2640);
  })
})
/* Styles go here */