Using Node.js to steal £10,000: Putting it into code
Published: 2022-12-05 19:37:27

## Formulas to functions

To generate a list of daily transfer amounts, we need a few things:

- A savings goal and a savings period (to calculate `F`)
- Our `totalSaved` formula from earlier
  - `totalSaved = (dayNumber * (dayNumber + 1)) * F`
- Our `transferAmount` formula from earlier
  - `transferAmount(today) = totalSaved(today) -totalSaved(yesterday)`

```javascript
const generateDailyTransferAmounts = (savingsGoal, savingsPeriod) => {
    
    //multiplication factor
    const factor = savingsGoal / savingsPeriod / (savingsPeriod + 1)
    
    //totalSaved formula
    const calculateTotalSavedByDay = (dayNum) => {
        return dayNum * (dayNum+1) * factor
    }

    //transferAmount formula
    const calculateTransferAmount = (dayNum) => {
        return calculateTotalSavedByDay(dayNum) - calculateTotalSavedByDay(dayNum-1)     
    }
    
	...
    
}
```

We also need an array containing the numbers `1` to `savingsPeriod` to iterate over. 

To populate an array with the numbers `1` to `savingsPeriod`, we first pass the Array constructor `savingsPeriod + 1`, as we know the array will be zero indexed, and we don't want "Day 0". We can make use of the [`keys()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/keys) method, which returns a new array containing the keys for each index of the array, and the [spread operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax), which allows us to use [`slice()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) on the returned array, removing the leading `0` and giving us an array of length `savingsPeriod` containing the numbers `1` to `savingsPeriod`.

```javascript
const days = [...Array(savingsPeriod+1).keys()].slice(1)
```

We can now use `map()` on the `days` array, calling our `calculateTransferAmount()` function on each day number to calculate the amount to be transferred on each day. We assign the resulting array to `transferAmounts`.

```javascript
const transferAmounts = days.map(dayNum => parseFloat(calculateTransferAmount(dayNum).toFixed(2)))
```

So far our code looks likes this:

```javascript
const generateDailyTransferAmounts = (savingsGoal, savingsPeriod) => {
    
    const factor = savingsGoal/savingsPeriod/(savingsPeriod+1)
    
    const calculateTotalSaved = (dayNum) => {
        return dayNum * factor * (dayNum+1)
    }

    const calculateTransferAmount = (dayNum) => {
        return calculateTotalSaved(dayNum) - calculateTotalSaved(dayNum-1)     
    }
    
    //Array of numbers from 1 to savingsPeriod
    const days = [...Array(savingsPeriod+1).keys()].slice(1)

    //Array of transfer amounts for each day of the savingsPeriod
    const transferAmounts = days.map(dayNum => parseFloat(calculateTransferAmount(dayNum).toFixed(2)))

    ...
    
}
```


## Making things 'random' (not quite)

As it stands we have an array, `transferAmounts`, that is sorted in ascending order — our first transfer will be the smallest, and our last the biggest. 

To get the feeling of 'random' amounts leaving our account in the middle of night, we need to **shuffle** our `transferAmounts`. Shuffling – or **_truly_** shuffling — appears to be a contentious topic 😅

{% embed https://stackoverflow.com/questions/2450954/how-to-randomize-shuffle-a-javascript-array %}

As we don't really need the ultimate shuffle here – just enough for it to _feel_ random – we can use a nice clean implementation of the [Durstenfeld shuffle](http://en.wikipedia.org/wiki/Fisher-Yates_shuffle#The_modern_algorithm) (credit to [Laurens Holst](https://stackoverflow.com/users/310500/laurens-holst) on Stackoverflow).

```javascript
const shuffleArray = (array) => {
    for (let i = array.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [array[i], array[j]] = [array[j], array[i]];
    }
}
```

Our final code, then, for generating a shuffled list of daily transfer amounts, for our chosen savings goal and savings period is as follows:

```javascript
const generateDailyTransferAmounts = (goal, period) => {
	
    const savingsGoal = goal
    const savingsPeriod = period
    
    const factor = savingsGoal/savingsPeriod/(savingsPeriod+1)
    
    const calculateTotalSaved = (dayNum) => {
        return dayNum * factor * (dayNum+1)
    }

    const calculateTransferAmount = (dayNum) => {
        return calculateTotalSaved(dayNum) - calculateTotalSaved(dayNum-1)     
    }

    const days = [...Array(savingsPeriod+1).keys()].slice(1)

    const transferAmounts = days.map(dayNum => parseFloat(calculateTransferAmount(dayNum).toFixed(2)))

    const shuffleArray = (array) => {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];
        }
    }

    return shuffleArray(transferAmounts)    
    
}

module.exports = generateDailyTransferAmounts
```

We have included an `export` statement so this function can be used elsewhere.

## Writing our transfer amounts to a file

As we will be using Serverless and AWS Lambda to run our program every day, we need to make our shuffled transfer amounts array accessible in the file system to any Starling API-based function we will write. 

This is achieved through a new function, `writeDailyTransferAmounts`:

```javascript
// this allows us to interact with the file system
const fs = require("fs");

//we import our function from earlier
const generateDailyAmounts = require('./generateDailyAmounts')


const writeDailyAmounts = (goal, period) => {

    const dailyTransferAmounts = JSON.stringify(generateDailyTransferAmounts(goal,period))
    
    ...

}
```

You'll notice that as well as calling `generateDailyTransferAmounts` with our savings goal and savings period, we are using `JSON.stringify` on the result. This is because when you try and write an array to a file, it is converted to a string in the process, and you end up with something like this.

```javascript
var array = [1, 2, 3, 4];
console.log(array.toString());
// 1,2,3,4
``` 
And it loses its array functionality in the destination file.

Using `JSON.stringify` allows us to turn an array into a string in a way that means it stays functionally intact. 

We can now use `fs.writeFile()` to write our array to a new file. As we want a Javascript file that can be accessed by our Starling transfer function, we use [template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) to write our file content, substituting in our `dailyTransferAmounts` array:

```javascript
const fileContent = 
    `const dailyAmounts = ${dailyTransferAmounts}
    module.exports = dailyAmounts`
```

Next we write that content to the file system, to a file called `dailyAmounts.js`:

```javascript
fs.writeFile('../dailyTransferAmounts.js', content, function(err) {
    if(err) {
          console.log(err);
    } 
    else {
      console.log("Output saved to dailyAmounts.js");
    }
});
```

The full code for this step is as follows:

```javascript
const fs = require("fs");

const generateDailyAmounts = require('./generateDailyAmounts')

const writeDailyAmounts = (goal, period) => {

    const dailyTransferAmounts = JSON.stringify(generateDailyTransferAmounts(goal,period))
    
    const fileContent = 
    `const dailyAmounts = ${dailyTransferAmounts}
    module.exports = dailyAmounts`

    fs.writeFile('./dailyTransferAmounts.js', fileContent, function(err) {
        if(err) {
            console.log(err);
        } 
        else {
            console.log("Output saved to dailyAmounts.js");
        }
    })
}

module.exports = writeDailyAmounts
```
Again we include an `export` statement so this function can be used elsewhere.