exports.start = function (res) { // res being the Express response object, being the server package I used
    const network = new NN.NeuralNetwork();
    let dataTypes = []
    let listOfTrainingData = []
    let listOfTestData = []
    let trainingDataRaw = []
    let testDataRaw = []
    const trainingOptions = { /* config options */ }
    var parser = csv({ delimiter: ',' }, function (err, data) { // in general, I find processing of arbitrary data files hard to do with pure functions - so I took some short cuts...
        if (err || data.length === 0) {
            return null
        } else {
            dataTypes = data[0].slice(0) // not very pure
            parseTrainingData(data.slice(1)) // this should normally return the completed data - see in-function comments below
        }
    })
    try { // not really pure either, but I don't know a better way of handling contact with the file system. At least the event-driven code is all in one place
        const stream = fs.createReadStream(path.join(__dirname, 'data.csv'))
        stream.pipe(parser)
        stream.on('close', () => {
            network.train(definedTrainingDataset(trainingDataRaw), trainingOptions)
            const nnConfig = network.toJSON()
            const significantInputs = identifySignificantInputs(nnConfig)
            fs.writeFileSync('savedNN.json', JSON.stringify(nnConfig, null, 2))
            res.send({ msg: '', result: generatedTestResults(testData), keyInputData: significantInputs, testedData: listOfTestData })
        })
        stream.on('error', (error) => {
            throw(error)
        })
    } catch (err) {
        res.send({ msg: err })
    }
    function parseTrainingData (data) {
        if (data[0][0] === 'TEST') {
            return parseTestData(data.slice(1))
        } else if (data.length === 0) {
            return // normally a recursive function would return the completed data, but see next comment for why not in this case
        } else {
            listOfTrainingData.push(data[0][0]) // not very pure but I'm OK with it for now. Hard to return two new arrays and then two more test data arrays
            trainingDataRaw.push(data[0].slice(1))
            return parseTrainingData(data.slice(1))
        }
    }
    function parseTestData (data) {
        if (data.length === 0) {
            return // see above regarding return values
        } else {
            listOfTestData.push(data[0][0]) // not very pure either!
            testDataRaw.push(data[0].slice(1))
            return parseTestData(data.slice(1))
        }
    }
    function identifySignificantInputs (nnConfigData) {
        const listOfHiddenNodes = Object.values(nnConfigData.layers[1])
        const summedWeights = listOfHiddenNodes.map((node) => {
            return Object.values(node.weights).reduce(function sumWeights (sum, weight) {
                return sum + weight
            })
        })
        const numWeights = summedWeights.length > 10 ? 10 : summedWeights.length
        const topTen = summedWeights.sort().slice(summedWeights.length - numWeights)
        return topTen.map((summedWeight) => { // what is actually wanted are the indexes of the highest 10 summedWeights values
            return dataTypes[summedWeights.indexOf(summedWeight)] // then match these to the original data (column) names
        })
    }
    function definedTrainingDataset(rawData) {
        return rawData.map((data) => {
            const input = data.slice(0, data.length - 1)
            const output = data.slice(data.length - 1) // the CSV defines the desired neural network output as the last item in a row
            return { input, output } // Brain.js specifies this type of object for the training set
        })
    }
    function generatedTestResults(dataToTest) {
        return dataToTest.map((dataPoint) => {
            const input = dataPoint.slice(0, dataPoint.length - 1)
            const output = dataPoint.slice(dataPoint.length - 1) // output is last item in a row
            return { actual: network.run(input), desired: output } // not pure, as running the test function here - probably should segregate this better
        })
    }
}