<commit_before>(function() {
    console.log('Ninja Block Starting Up');
    var fs = require('fs'),
        path = require('path'),
        util = require('util'),
        http = require('http'),
        exec = require('child_process').exec,
        io = require('socket.io-client'),
        serialport = require('serialport'),
        SerialPort = serialport.SerialPort,
        emptyBeats = 0,
        sendIv = 0,
        watchDogIv,
        instantContainer = {},
        readings = {},
        config =  {
            cloudHost: 'dojo.ninja.is',
            cloudStream: 'stream.ninja.is',
            cloudStreamPort: 443,
            cloudPort: 443,
            devtty: "/dev/ttyO1",
            serialFile: "/etc/opt/ninja/serial.conf",
            tokenFile: "/etc/opt/ninja/token.conf",
            updateLock: '/etc/utilities/tmp/has_updated',
            heartbeat_interval: 500,
            secure:true,
            version:0.1
        },
        ioOpts = {
            'port':config.cloudPort,
            'transports':['xhr-polling'],
            'try multiple transports':false,
            'secure':config.secure
        },
        nodedetails = {
            id:fs.readFileSync(config.serialFile).toString().replace(/\n/g,'')
        },
        sutil = require('./lib/client-utils');
        sutil.configure(config);

    // Try and fetch the token
    nodedetails.token = (path.existsSync(config.tokenFile))
                        ? fs.readFileSync(config.tokenFile).toString().replace(/\n/g,'')
                        : false;
    // development overwrites
    if (process.argv[2] == 'local') {
        config.cloudHost = process.argv[3];
        config.cloudStream = process.argv[3];
        config.cloudStreamPort = 3003;
        ioOpts["port"] = 3001;
        ioOpts.secure = false;
    };
    // Connect
    var socket = io.connect(config.cloudHost,ioOpts);
    // Various
    socket.on('connecting',function(transport){
        console.log("Connecting");
        sutil.changeLEDColor(tty,'cyan');
    });
    socket.on('connect', function () {
        console.log("Connected");
        console.log("Authenticating");
        socket.emit('hello',nodedetails.id);
    });
    socket.on('error',function(err) {
        console.log(err);
        console.log("Socket error, restarting.")
        setStateToError();
        setTimeout(function() {
            process.exit(1);
        },30000);
    });
    socket.on('disconnect', function () {
        console.log("Disconnected, restarting.")
        setStateToError();
        setTimeout(function () {
            process.exit(1);
        },30000);
    });
    socket.on('reconnecting',function() {
        console.log("Reconnecting");
        sutil.changeLEDColor(tty,'cyan');
    });
    socket.on('reconnect_failed',function() {
        console.log("Reconnect failed, restarting.");
        setStateToError();
        setTimeout(function () {
            process.exit(1);
        },30000);
    });
    socket.on('whoareyou',function() {
        if (nodedetails.token) {
            socket.emit('iam',{client:'beagle',version:config.version,token:nodedetails.token});
        } else {
            console.log('Awaiting Activation');
            sutil.changeLEDColor(tty,'purple');
            socket.emit('notsure',{client:'beagle',version:config.version});
            socket.on('youare',function(token) {
                console.log("Received Authorisation")
                fs.writeFileSync(config.tokenFile, token.token, 'utf8');
                nodedetails["token"] = token.token;
                socket.emit('iam',{client:'beagle',version:config.version,token:nodedetails.token});
            });
        }
    });
    socket.on('begin',function() {
        console.log("Authenticated");
        console.log("Sending/Receiving...");
        clearInterval(sendIv);
        sendIv = setInterval(function(){
            if (beatThrottle.isGoodToGo() && socket.socket.buffer.length==0) {
                socket.emit('heartbeat',getHeartbeat());
            }
        },config.heartbeat_interval);
        setStateToOK();
    });
    socket.on('command',function(data) {
        console.log(data);
        executeCommand(data);
    });
    socket.on('invalidToken',function() {
        console.log("Invalid Token, rebooting");
        // Delete token
        fs.unlinkSync(config.tokenFile);
        // Restart
        process.exit(1);
    });
    socket.on('updateYourself',function() {
        console.log("Updating");
        // Remove the update lock file
        fs.unlinkSync(config.updateLock);
        // Stop writing to the watchdog
        clearInterval(watchDogIv);
        sutil.changeLEDColor(tty,'white');
    });
    // Setup the TTY serial port
    var tty = new SerialPort(config.devtty, {
        parser: serialport.parsers.readline("\n")
    });
    tty.on('data',function(data){
        handleRawTtyData(data);
    });
    var handleRawTtyData = function(data) {
        var jsonTtyData = sutil.getJSON(data) || false;
        if (!jsonTtyData) return;
        var deviceDataPoints = jsonTtyData.DEVICE;
        if (!(deviceDataPoints instanceof Array)) return;
        // only keep latest reading per device between heartbeats
        for (var i=0; i<deviceDataPoints.length; i++) {
            var device = deviceDataPoints[i];
            // Build the GUID
            device.GUID = sutil.buildDeviceGuid(nodedetails.id,device);
            // If we have meta data about the device, handle it.
            if (sutil.deviceHasMetaData(device)) {
                var meta = sutil.getDeviceMetaData(device);
                if (meta.instant) trySendInstantData(device);
            }
            // Add the devices data to the heartbeat container
            readings[deviceDataPoints[i].GUID] = deviceDataPoints[i];
        }
    };
    var trySendInstantData = function(deviceData) {
        if (instantContainer.hasOwnProperty(deviceData.GUID)) {
            // We've got stuff
            if (instantContainer[deviceData.GUID].DA!==deviceData.DA) {
                // It's different
                var newMsg = {
                    "NODE_ID":nodedetails.id,
                    "TIMESTAMP": new Date().getTime(),
                    "DEVICE":[deviceData]
                }
                socket.emit('data',JSON.stringify(newMsg));
            }
        }
        instantContainer[deviceData.GUID] = deviceData;
    };
    var getHeartbeat = function(){
        var hb = {
            "NODE_ID":nodedetails.id,
            "TIMESTAMP": null,
            "DEVICE":[]
        };
        hb.TIMESTAMP = new Date().getTime();
        for (r in readings) {
            hb.DEVICE.unshift(readings[r]);
        }
        readings={};
        return JSON.stringify(hb);
    }
    var beatThrottle = {
        isGoodToGo : function() {
            if (!sutil.isEmpty(readings) || beatThrottle.counter>beatThrottle.rate) {
                beatThrottle.counter = 0;
                return true;
            } else {
                beatThrottle.counter++;
                return false;
            }
        },
        rate : 10000/config.heartbeat_interval,
        counter: 0
    };
    var executeCommand = function(data){
        var data = sutil.getJSON(data);
       //if (data && data.welcome) return;
        var ds = data.DEVICE;
        if (ds && ds.length>0) {
            for (d in ds) {
                var guid = ds[d].GUID;
                delete ds[d].GUID;
                ds[d].G = ds[d].G.toString(); //TODO get JP to fix for 0
                switch(ds[d].D) {
                    case 1003:
                        // Take picture
                        sutil.takePicture(guid,nodedetails.token);
                    break;
                    case 1004:
                        // Take stream
                        sutil.sendCameraStream(guid,nodedetails.token);
                    break;
                    default:
                        sutil.writeTTY(tty,'{"DEVICE":['+JSON.stringify(ds[d])+']}');
                    break;
                }
            }
        } else {
            console.log(data.toString());
        }
    }
    var setStateToOK = function() {
        sutil.changeLEDColor(tty,'green');
    };
    var setStateToError = function() {
        sutil.changeLEDColor(tty,'red');
    };
    // Camera
    var Inotify = require('inotify-plusplus'), // should be 'inotify++', but npm has issues with the ++
        inotify,
        directive,
        options,
        cameraIv,
        cameraGuid;

    inotify = Inotify.create(true); // stand-alone, persistent mode, runs until you hit ctrl+c
    directive = (function() {
        return {
          create: function (ev) {
            if(ev.name == 'v4l'){
                cameraGuid = sutil.buildDeviceGuid(nodedetails.id,{G:"0",V:0,D:1003});
                clearInterval(cameraIv);
                cameraIv = setInterval(function() {
                    readings[cameraIv] = {
                        GUID:cameraGuid,
                        G:"0",
                        V:0,
                        D:1003,
                        DA:1
                    };
                },config.heartbeat_interval);
            }
          },
          delete: function(ev) {
            if(ev.name == 'v4l'){
                clearInterval(cameraIv);
            }
          }
        };
    }());
    inotify.watch(directive, '/dev/');
    try {
        // Query the entry
        stats = fs.lstatSync('/dev/video0');
        // Is it a directory?
        if (stats.isCharacterDevice()) {
            // Yes it is
            console.log("Camera is Connected");
            cameraGuid = sutil.buildDeviceGuid(nodedetails.id,{G:"0",V:0,D:1003});
            cameraIv = setInterval(function() {
                readings[cameraIv] = {
                    GUID:cameraGuid,
                    G:"0",
                    V:0,
                    D:1003,
                    DA:1
                };
            },config.heartbeat_interval);
        }
    }
    catch (e) { }
    // Watdog Timer
    var watchDogStream = fs.open('/dev/watchdog','r+',function(err,fd) {
        if (err) console.log(err);
        var watchDogPayload = new Buffer(1);
        watchDogPayload.write('\n','utf8');
        watchDogIv = setInterval(function() {
            fs.write(fd,watchDogPayload,0, watchDogPayload.length, -1,function(err) {
                if (err) console.log(err);
            });
        },30000);
    });
    process.on('exit',function() {
        sutil.changeLEDColor(tty,'yellow');
    });
})();
<commit_msg>Camera is now 1003<commit_after>(function() {
    console.log('Ninja Block Starting Up');
    var fs = require('fs'),
        path = require('path'),
        util = require('util'),
        http = require('http'),
        exec = require('child_process').exec,
        io = require('socket.io-client'),
        serialport = require('serialport'),
        SerialPort = serialport.SerialPort,
        emptyBeats = 0,
        sendIv = 0,
        watchDogIv,
        instantContainer = {},
        readings = {},
        config =  {
            cloudHost: 'dojo.ninja.is',
            cloudStream: 'stream.ninja.is',
            cloudStreamPort: 443,
            cloudPort: 443,
            devtty: "/dev/ttyO1",
            serialFile: "/etc/opt/ninja/serial.conf",
            tokenFile: "/etc/opt/ninja/token.conf",
            updateLock: '/etc/utilities/tmp/has_updated',
            heartbeat_interval: 500,
            secure:true,
            version:0.1
        },
        ioOpts = {
            'port':config.cloudPort,
            'transports':['xhr-polling'],
            'try multiple transports':false,
            'secure':config.secure
        },
        nodedetails = {
            id:fs.readFileSync(config.serialFile).toString().replace(/\n/g,'')
        },
        sutil = require('./lib/client-utils');
        sutil.configure(config);

    // Try and fetch the token
    nodedetails.token = (path.existsSync(config.tokenFile))
                        ? fs.readFileSync(config.tokenFile).toString().replace(/\n/g,'')
                        : false;
    // development overwrites
    if (process.argv[2] == 'local') {
        config.cloudHost = process.argv[3];
        config.cloudStream = process.argv[3];
        config.cloudStreamPort = 3003;
        ioOpts["port"] = 3001;
        ioOpts.secure = false;
    };
    // Connect
    var socket = io.connect(config.cloudHost,ioOpts);
    // Various
    socket.on('connecting',function(transport){
        console.log("Connecting");
        sutil.changeLEDColor(tty,'cyan');
    });
    socket.on('connect', function () {
        console.log("Connected");
        console.log("Authenticating");
        socket.emit('hello',nodedetails.id);
    });
    socket.on('error',function(err) {
        console.log(err);
        console.log("Socket error, restarting.")
        setStateToError();
        setTimeout(function() {
            process.exit(1);
        },30000);
    });
    socket.on('disconnect', function () {
        console.log("Disconnected, restarting.")
        setStateToError();
        setTimeout(function () {
            process.exit(1);
        },30000);
    });
    socket.on('reconnecting',function() {
        console.log("Reconnecting");
        sutil.changeLEDColor(tty,'cyan');
    });
    socket.on('reconnect_failed',function() {
        console.log("Reconnect failed, restarting.");
        setStateToError();
        setTimeout(function () {
            process.exit(1);
        },30000);
    });
    socket.on('whoareyou',function() {
        if (nodedetails.token) {
            socket.emit('iam',{client:'beagle',version:config.version,token:nodedetails.token});
        } else {
            console.log('Awaiting Activation');
            sutil.changeLEDColor(tty,'purple');
            socket.emit('notsure',{client:'beagle',version:config.version});
            socket.on('youare',function(token) {
                console.log("Received Authorisation")
                fs.writeFileSync(config.tokenFile, token.token, 'utf8');
                nodedetails["token"] = token.token;
                socket.emit('iam',{client:'beagle',version:config.version,token:nodedetails.token});
            });
        }
    });
    socket.on('begin',function() {
        console.log("Authenticated");
        console.log("Sending/Receiving...");
        clearInterval(sendIv);
        sendIv = setInterval(function(){
            if (beatThrottle.isGoodToGo() && socket.socket.buffer.length==0) {
                socket.emit('heartbeat',getHeartbeat());
            }
        },config.heartbeat_interval);
        setStateToOK();
    });
    socket.on('command',function(data) {
        console.log(data);
        executeCommand(data);
    });
    socket.on('invalidToken',function() {
        console.log("Invalid Token, rebooting");
        // Delete token
        fs.unlinkSync(config.tokenFile);
        // Restart
        process.exit(1);
    });
    socket.on('updateYourself',function() {
        console.log("Updating");
        // Remove the update lock file
        fs.unlinkSync(config.updateLock);
        // Stop writing to the watchdog
        clearInterval(watchDogIv);
        sutil.changeLEDColor(tty,'white');
    });
    // Setup the TTY serial port
    var tty = new SerialPort(config.devtty, {
        parser: serialport.parsers.readline("\n")
    });
    tty.on('data',function(data){
        handleRawTtyData(data);
    });
    var handleRawTtyData = function(data) {
        var jsonTtyData = sutil.getJSON(data) || false;
        if (!jsonTtyData) return;
        var deviceDataPoints = jsonTtyData.DEVICE;
        if (!(deviceDataPoints instanceof Array)) return;
        // only keep latest reading per device between heartbeats
        for (var i=0; i<deviceDataPoints.length; i++) {
            var device = deviceDataPoints[i];
            // Build the GUID
            device.GUID = sutil.buildDeviceGuid(nodedetails.id,device);
            // If we have meta data about the device, handle it.
            if (sutil.deviceHasMetaData(device)) {
                var meta = sutil.getDeviceMetaData(device);
                if (meta.instant) trySendInstantData(device);
            }
            // Add the devices data to the heartbeat container
            readings[deviceDataPoints[i].GUID] = deviceDataPoints[i];
        }
    };
    var trySendInstantData = function(deviceData) {
        if (instantContainer.hasOwnProperty(deviceData.GUID)) {
            // We've got stuff
            if (instantContainer[deviceData.GUID].DA!==deviceData.DA) {
                // It's different
                var newMsg = {
                    "NODE_ID":nodedetails.id,
                    "TIMESTAMP": new Date().getTime(),
                    "DEVICE":[deviceData]
                }
                socket.emit('data',JSON.stringify(newMsg));
            }
        }
        instantContainer[deviceData.GUID] = deviceData;
    };
    var getHeartbeat = function(){
        var hb = {
            "NODE_ID":nodedetails.id,
            "TIMESTAMP": null,
            "DEVICE":[]
        };
        hb.TIMESTAMP = new Date().getTime();
        for (r in readings) {
            hb.DEVICE.unshift(readings[r]);
        }
        readings={};
        return JSON.stringify(hb);
    }
    var beatThrottle = {
        isGoodToGo : function() {
            if (!sutil.isEmpty(readings) || beatThrottle.counter>beatThrottle.rate) {
                beatThrottle.counter = 0;
                return true;
            } else {
                beatThrottle.counter++;
                return false;
            }
        },
        rate : 10000/config.heartbeat_interval,
        counter: 0
    };
    var executeCommand = function(data){
        var data = sutil.getJSON(data);
       //if (data && data.welcome) return;
        var ds = data.DEVICE;
        if (ds && ds.length>0) {
            for (d in ds) {
                var guid = ds[d].GUID;
                delete ds[d].GUID;
                ds[d].G = ds[d].G.toString(); //TODO get JP to fix for 0
                switch(ds[d].D) {
                    case 1004:
                        // Take picture
                        sutil.takePicture(guid,nodedetails.token);
                    break;
                    default:
                        sutil.writeTTY(tty,'{"DEVICE":['+JSON.stringify(ds[d])+']}');
                    break;
                }
            }
        } else {
            console.log(data.toString());
        }
    }
    var setStateToOK = function() {
        sutil.changeLEDColor(tty,'green');
    };
    var setStateToError = function() {
        sutil.changeLEDColor(tty,'red');
    };
    // Camera
    var Inotify = require('inotify-plusplus'), // should be 'inotify++', but npm has issues with the ++
        inotify,
        directive,
        options,
        cameraIv,
        cameraGuid;

    inotify = Inotify.create(true); // stand-alone, persistent mode, runs until you hit ctrl+c
    directive = (function() {
        return {
          create: function (ev) {
            if(ev.name == 'v4l'){
                cameraGuid = sutil.buildDeviceGuid(nodedetails.id,{G:"0",V:0,D:1003});
                clearInterval(cameraIv);
                cameraIv = setInterval(function() {
                    readings[cameraIv] = {
                        GUID:cameraGuid,
                        G:"0",
                        V:0,
                        D:1004,
                        DA:1
                    };
                },config.heartbeat_interval);
            }
          },
          delete: function(ev) {
            if(ev.name == 'v4l'){
                clearInterval(cameraIv);
            }
          }
        };
    }());
    inotify.watch(directive, '/dev/');
    try {
        // Query the entry
        stats = fs.lstatSync('/dev/video0');
        // Is it a directory?
        if (stats.isCharacterDevice()) {
            // Yes it is
            console.log("Camera is Connected");
            cameraGuid = sutil.buildDeviceGuid(nodedetails.id,{G:"0",V:0,D:1003});
            cameraIv = setInterval(function() {
                readings[cameraIv] = {
                    GUID:cameraGuid,
                    G:"0",
                    V:0,
                    D:1004,
                    DA:1
                };
            },config.heartbeat_interval);
        }
    }
    catch (e) { }
    // Watdog Timer
    var watchDogStream = fs.open('/dev/watchdog','r+',function(err,fd) {
        if (err) console.log(err);
        var watchDogPayload = new Buffer(1);
        watchDogPayload.write('\n','utf8');
        watchDogIv = setInterval(function() {
            fs.write(fd,watchDogPayload,0, watchDogPayload.length, -1,function(err) {
                if (err) console.log(err);
            });
        },30000);
    });
    process.on('exit',function() {
        sutil.changeLEDColor(tty,'yellow');
    });
})();
<|endoftext|>


<commit_before>var http = require('http');
var fs = require('fs');
var util = require('util');
// var qs = require('querystring');
// var child = require('child_process');
var sutil = require('./lib/client-utils');
var serialport = require("serialport");
var SerialPort = serialport.SerialPort;

// base config for beagle
var config =  {
    cloudHost: 'ninj.herokuapp.com',
    cloudPort: 80,
    devtty: "/dev/ttyO1",
    serialfile: "/utilities/etc/serial.conf",
    heartbeat_interval: 500
}
// commandline config
if (process.argv[2] == 'local') {
    config.cloudHost = 'localhost';
    config.cloudPort = '3001';
}
if (process.argv[3] == 'ftdi') {
    config.devtty = "/dev/tty.usbserial-AE01AAE3";
    config.serialfile = "/Users/danfriedman/Code/ninjablocks/client/serialnumber";
}
console.log(config);

var tty = new SerialPort(config.devtty, {
    parser: serialport.parsers.readline("\n")
});

var nodedetails = {}
fs.readFile(config.serialfile,'ascii',function(err,data){
    nodedetails["id"] = data.replace(/\n/g,"");
    // Set here because of a race condition
    cmdOptions.path += nodedetails.id;
    console.log(cmdOptions);
    longpoll()
})
nodedetails["token"] = "1234123412341234"; // TODO

var readings = {};
tty.on('data',function(data){
     //console.log(data); // the almost raw serial data
    var nm = sutil.getJSON(data) || false;
    if (nm) {
        // only keep latest reading per device between heartbeats
        for (var x=0; x<nm.DEVICE.length; x++) {
            nm.DEVICE[x].GUID = nodedetails.id+'_'+nm.DEVICE[x].G+'_'+nm.DEVICE[x].V+'_'+nm.DEVICE[x].D;
            readings[nm.DEVICE[x].GUID] = nm.DEVICE[x];
        }
    }
});

var getHeartbeat = function(){
    hb = {  "NODE_ID":nodedetails.id,
            "TOKEN": nodedetails.token,
            "TIMESTAMP": null,
            "DEVICE":[] }
    hb.TIMESTAMP = new Date().getTime();
    for (r in readings) {
        hb.DEVICE.unshift(readings[r]);
        delete readings[r];
    }
    return JSON.stringify(hb);
}

/*
*   Sending Data
*/
var net = require('net');

var stream = net.createConnection(config.cloudPort, config.cloudHost);

stream.on('error', function (err) {
    if (err.code === 'ECONNREFUSED' || err.code === 'ENOENT') {
        console.log("Connection refused, retrying...")
        setTimeout(function () {
            stream.connect(config.cloudPort,config.cloudHost);
        }, 1000);
    }
});

stream.on('end', function () {
    console.log('Reconnecting...');
    setTimeout(function () {
        stream.connect(config.cloudPort,config.cloudHost);
    }, 1000);
});

stream.on('connect',function(socket) {
    console.log('Connected')
    setInterval(function(){
        // Only send empty heartbeats every 10s
        // TODO reduce frequency of identical heartbeats
        if (beatThrottle.isGoodToGo()) {
            stream.write(getHeartbeat()+'\n');
        }
    },config.heartbeat_interval);
});

var emptyBeats = 0;

var beatThrottle = {
    isGoodToGo : function() {
        if (!sutil.isEmpty(readings) || beatThrottle.counter>beatThrottle.rate) {
            beatThrottle.counter = 0;
            return true;
        } else {
            beatThrottle.counter++;
            return false;
        }
    },
    rate : 10000/config.heartbeat_interval,
    counter: 0
};
/*
var longPost = function(){
    var request = http.request(postOptions, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
            console.log('LongPost received a body: '+chunk);
        });
        res.on('end', function(){
            setTimeout(longPost,100);
        })
    });
    var sendBeats = setInterval(function(){
        // Only send empty heartbeats every 10s
        // TODO reduce frequency of identical heartbeats
        if (beatThrottle.isGoodToGo()) {
            request.write(getHeartbeat());
        }
    },config.heartbeat_interval);

    setTimeout(function(){
        // restart connection after 120s
        clearInterval(sendBeats);
        request.end();
    },120000)
    // console.log('connection');
    request.on('error', function(e){
        console.log('Longpost Error: '+e);
        setTimeout(longPost,1000);
    });
}
longPost();
*/
/*
*   Receiving Data
*/
var cmdOptions = {
    host: config.cloudHost,
    port: config.cloudPort,
    path: '/commands/',
    method: 'GET'
}
var longpoll = function(){
    http.get(cmdOptions, function (http_res) {
        http_res.on("data", function (data) {
            executeCommand(data);
        });
        http_res.on("end", function () {
            longpoll();
        });
        http_res.on("close", function () {
            longpoll();
        });
        http_res.on("error", function () {
            setTimeout(longpoll,5000)
        });

    }).on('error',function(err){
        console.log('Error in longpoll request: '+err);
        setTimeout(longpoll,5000)
    });
}

var executeCommand = function(data){
    var ds = sutil.getJSON(data).DEVICE;
    if (ds && ds.length>0) {
        for (d in ds) {
            delete ds[d].GUID;
            ds[d].G = ds[d].G.toString(); //TODO get JP to fix for 0
            sutil.writeTTY(tty,'{"DEVICE":['+JSON.stringify(ds[d])+']}');
        }
    } else {
        console.log(data.toString());
    }
}

process.on('uncaughtException', function (err) {
  // console.log('Caught Uncaught Exception: ' + util.inspect(err,null,true,true));
});
<commit_msg>Fixed bug with duplicate interval listeners<commit_after>var http = require('http');
var fs = require('fs');
var util = require('util');
// var qs = require('querystring');
// var child = require('child_process');
var sutil = require('./lib/client-utils');
var serialport = require("serialport");
var SerialPort = serialport.SerialPort;

// base config for beagle
var config =  {
    cloudHost: 'ninj.herokuapp.com',
    cloudPort: 80,
    devtty: "/dev/ttyO1",
    serialfile: "/utilities/etc/serial.conf",
    heartbeat_interval: 500
}
// commandline config
if (process.argv[2] == 'local') {
    config.cloudHost = 'localhost';
    config.cloudPort = '3001';
}
if (process.argv[3] == 'ftdi') {
    config.devtty = "/dev/tty.usbserial-AE01AAE3";
    config.serialfile = "/Users/danfriedman/Code/ninjablocks/client/serialnumber";
}
console.log(config);

var tty = new SerialPort(config.devtty, {
    parser: serialport.parsers.readline("\n")
});

var nodedetails = {}
fs.readFile(config.serialfile,'ascii',function(err,data){
    nodedetails["id"] = data.replace(/\n/g,"");
    // Set here because of a race condition
    cmdOptions.path += nodedetails.id;
    console.log(cmdOptions);
    longpoll()
})
nodedetails["token"] = "1234123412341234"; // TODO

var readings = {};
tty.on('data',function(data){
     //console.log(data); // the almost raw serial data
    var nm = sutil.getJSON(data) || false;
    if (nm) {
        // only keep latest reading per device between heartbeats
        for (var x=0; x<nm.DEVICE.length; x++) {
            nm.DEVICE[x].GUID = nodedetails.id+'_'+nm.DEVICE[x].G+'_'+nm.DEVICE[x].V+'_'+nm.DEVICE[x].D;
            readings[nm.DEVICE[x].GUID] = nm.DEVICE[x];
        }
    }
});

var getHeartbeat = function(){
    hb = {  "NODE_ID":nodedetails.id,
            "TOKEN": nodedetails.token,
            "TIMESTAMP": null,
            "DEVICE":[] }
    hb.TIMESTAMP = new Date().getTime();
    for (r in readings) {
        hb.DEVICE.unshift(readings[r]);
        delete readings[r];
    }
    return JSON.stringify(hb);
}

/*
*   Sending Data
*/
var net = require('net');

var stream = net.createConnection(config.cloudPort, config.cloudHost);

stream.on('error', function (err) {
    if (err.code === 'ECONNREFUSED' || err.code === 'ENOENT') {
        console.log("Connection refused, retrying...")
        setTimeout(function () {
            stream.connect(config.cloudPort,config.cloudHost);
        }, 1000);
    }
});

stream.on('end', function () {
    console.log('Reconnecting...');
    setTimeout(function () {
        stream.connect(config.cloudPort,config.cloudHost);
    }, 1000);
});
var sendIv = 0;
stream.on('connect',function(socket) {
    console.log('Connected')
    clearInterval(sendIv);
    sendIv = setInterval(function(){
        // Only send empty heartbeats every 10s
        // TODO reduce frequency of identical heartbeats
        if (beatThrottle.isGoodToGo()) {
            stream.write(getHeartbeat()+'\n');
            console.log(getHeartbeat());
        }
    },config.heartbeat_interval);
});

var emptyBeats = 0;

var beatThrottle = {
    isGoodToGo : function() {
        if (!sutil.isEmpty(readings) || beatThrottle.counter>beatThrottle.rate) {
            beatThrottle.counter = 0;
            return true;
        } else {
            beatThrottle.counter++;
            return false;
        }
    },
    rate : 10000/config.heartbeat_interval,
    counter: 0
};
/*
var longPost = function(){
    var request = http.request(postOptions, function(res) {
        res.setEncoding('utf8');
        res.on('data', function (chunk) {
            console.log('LongPost received a body: '+chunk);
        });
        res.on('end', function(){
            setTimeout(longPost,100);
        })
    });
    var sendBeats = setInterval(function(){
        // Only send empty heartbeats every 10s
        // TODO reduce frequency of identical heartbeats
        if (beatThrottle.isGoodToGo()) {
            request.write(getHeartbeat());
        }
    },config.heartbeat_interval);

    setTimeout(function(){
        // restart connection after 120s
        clearInterval(sendBeats);
        request.end();
    },120000)
    // console.log('connection');
    request.on('error', function(e){
        console.log('Longpost Error: '+e);
        setTimeout(longPost,1000);
    });
}
longPost();
*/
/*
*   Receiving Data
*/
var cmdOptions = {
    host: config.cloudHost,
    port: config.cloudPort,
    path: '/commands/',
    method: 'GET'
}
var longpoll = function(){
    http.get(cmdOptions, function (http_res) {
        http_res.on("data", function (data) {
            executeCommand(data);
        });
        http_res.on("end", function () {
            longpoll();
        });
        http_res.on("close", function () {
            longpoll();
        });
        http_res.on("error", function () {
            setTimeout(longpoll,5000)
        });

    }).on('error',function(err){
        console.log('Error in longpoll request: '+err);
        setTimeout(longpoll,5000)
    });
}

var executeCommand = function(data){
    var ds = sutil.getJSON(data).DEVICE;
    if (ds && ds.length>0) {
        for (d in ds) {
            delete ds[d].GUID;
            ds[d].G = ds[d].G.toString(); //TODO get JP to fix for 0
            sutil.writeTTY(tty,'{"DEVICE":['+JSON.stringify(ds[d])+']}');
        }
    } else {
        console.log(data.toString());
    }
}

process.on('uncaughtException', function (err) {
  // console.log('Caught Uncaught Exception: ' + util.inspect(err,null,true,true));
});
<|endoftext|>


<commit_before>'use strict';

const EventEmitter = require('events');
const ServiceProvider = require('./ServiceProvider');
const _pick = require('lodash.pick');

class ServiceEmitter extends EventEmitter {

  constructor (opts) {

    // Default value for `opts`.
    opts = opts || {};

    super(); // Call `EventEmitter` constructor.

    /**
     * Will hold object returned by `setInterval` to control service intervals.
     *
     * @private
     * @type {Object}
     */
    this._intervalObject = undefined;

    /**
     * Delay in milliseconds for intervals.
     *
     * @private
     * @constant
     * @type {Number}
     */
    this._delay = opts.delay || 1000;

    /**
     * Determines if {@link this._intervalCallback()} should be called immediately.
     *
     * @private
     * @constant
     * @type {Boolean}
     */
    this._runImmediately = opts.runImmediately || false;

    /**
     * Flag to know if we have to call {@link this.provider.requestData()}
     * automatically or not, default set to true.
     *
     * @private
     * @constant
     * @type {Boolean}
     */
    this._autoRequest = opts.autoRequest || true;

    /**
     * Keeps last data set by provider.
     *
     * @private
     * @type {Object}
     */
    this._data = undefined;

    /**
     * Some implementation of `ServiceProvider`.
     *
     * @private
     * @type {ServiceProvider}
     */
    this.provider = undefined;

    // Listen for new event listeners.
    this.on('newListener', (event, listener) => {

      // We do not handle 'removeListener' here.
      if (event === 'removeListener') { return; }

      // First we make sure `provider` is defined.
      if (!this.isProviderRegistered()) {
        throw new Error('"provider" should be registered before listening any event.');
      }

      // Only 'data' and 'error' events allowed.
      if (event !== 'data' && event !== 'error') {
        throw new Error('For now, only listening "data" and "error" events are allow.');
      }

      // event 'data' is our keyword event name for main process.
      if (event === 'data') {

        // When got first 'data' listener...
        if (!this.dataHasListeners()) {

          // ...set provider to ON.
          this.provider.turnON();

          // Listen for provider 'data' event to be able to transmit the message
          // to custom service emitters.
          this.provider.on('data', data => {

            // Implementation of `onProviderData` should return a `Boolean`
            // indicating if data received from provider is valid or not, if
            // valid then proceed to update `this._data`.
            if (this.onProviderData(data, (error, validatedData) => {
              if (error) {
                return this.emit('error', error);
              }

              this._data = validatedData;
              this.emit('data', this._data);
            })) {
              this._data = data;
            }
          });

          // Listen provider 'error' event to be able to transmit error to
          // custom service emitters.
          this.provider.on('error', err => this.onProviderError(err));
        }

        // Make sure we are not overriding `_intervalObject`.
        if (this._intervalObject === undefined) {
          this._intervalObject = setInterval(() => this._intervalCallback(), this._delay);

          // Call interval callback NOW if `runImmediately` option is true.
          if (this._runImmediately) {
            this._intervalCallback();
          }
        }
      }

      // Call `onNewListener` for custom behavior.
      this.onNewListener(event, listener);
    });

    // Listen removeListener event.
    this.on('removeListener', (event, listener) => {

      // If no one listens 'data' event then...
      if (!this.dataHasListeners()) {

        // Reset interval.
        clearInterval(this._intervalObject);
        this._intervalObject = undefined;

        // Reset data.
        this._data = undefined;

        // Make sure provider is registered before setting it OFF.
        if (this.isProviderRegistered()) {
          this.provider.turnOFF();

          // Remove all provider listeners, 'data', 'error' and 'wantsData'.
          this.provider.removeAllListeners();
        }
      }

      // Call `onRemoveListener` for custom behavior.
      this.onRemoveListener(event, listener);
    });
  }

  /**
   * Interval callback for {@link this._intervalObject}.
   *
   * @private
   */
  _intervalCallback () {

    // If `this._autoRequest` is true and provider is registered then
    // request data to provider.
    if (this._autoRequest && this.isProviderRegistered()) {
      this.provider.requestData();
    }

    // Call `this.interval()` for custom emitters to know.
    this.interval();
  }

  /**
   * Checks if any listeners listen 'data' event.
   *
   * @return {Boolean} `true` if at least one client listens `data` event.
   */
  dataHasListeners () {
    return this.listenerCount('data') > 0;
  }

  /**
   * Checks if listener provided is listening event name.
   *
   * @param {String} event - Event name to check.
   * @param {Function} listener - Listener to check.
   * @return {Boolean} Whether listener listens event.
   */
  isListeningTo (event, listener) {
    return this.listeners(event).some(_listener => {
      return _listener === listener;
    });
  }

  /**
   * Public method for ServiceProvider registration.
   *
   * @param {ServiceProvider} provider - One of the available providers.
   */
  registerProvider (provider) {

    if (!(provider instanceof ServiceProvider)) {
      throw new Error('"provider" must be an instance of `ServiceProvider`.');
    }

    if (this.isProviderRegistered()) {
      throw new Error('"provider" is already registered!');
    }

    // Do the actual registration.
    this.provider = provider;
  }

  /**
   * Verifies if {@link this.provider} is already registered.
   *
   * @return {Boolean} `true` is registered, `false` otherwise.
   */
  isProviderRegistered () {
    return this.provider && this.provider instanceof ServiceProvider;
  }

  /**
   * Get current provider data with optional pick filter.
   *
   * @param {Array} [pick] - Array of properties to return in Object.
   * @return {Object} Current provider data Object.
   */
  getCurrentData (pick) {
    return !pick ? this._data : _pick(this._data, pick);
  }

  /**
   * Empty `interval` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called in each cycle of main interval.
   */
  interval () { }

  /**
   * Empty `onNewListener` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called on new event listener.
   * @param {String} event - Event name.
   * @param {Function} listener - Listener Function.
   */
  onNewListener (event, listener) { }

  /**
   * Empty `onRemoveListener` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called on remotion of event listener.
   * @param {String} event - Event name.
   * @param {Function} listener - Listener Function.
   */
  onRemoveListener (event, listener) { }

  /**
   * Empty `onProviderData` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called when provider emits new data.
   * @param {Object} data - Data to emit.
   * @return {Boolean} Indicates if data received from provider is valid or not.
   *
   * Note: The returned value by the implementation of this method will be used
   * to decide if we should update {@link this._data} with data received or not.
   */
  onProviderData (data, cb) { }

  /**
   * Empty `onProviderError` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called when provider emits an error.
   * @param {Object} err - Error to emit.
   */
  onProviderError (err) {
    this.emit('error', error);
  }
}

module.exports = ServiceEmitter;
<commit_msg>callback onProvider docs<commit_after>'use strict';

const EventEmitter = require('events');
const ServiceProvider = require('./ServiceProvider');
const _pick = require('lodash.pick');

class ServiceEmitter extends EventEmitter {

  constructor (opts) {

    // Default value for `opts`.
    opts = opts || {};

    super(); // Call `EventEmitter` constructor.

    /**
     * Will hold object returned by `setInterval` to control service intervals.
     *
     * @private
     * @type {Object}
     */
    this._intervalObject = undefined;

    /**
     * Delay in milliseconds for intervals.
     *
     * @private
     * @constant
     * @type {Number}
     */
    this._delay = opts.delay || 1000;

    /**
     * Determines if {@link this._intervalCallback()} should be called immediately.
     *
     * @private
     * @constant
     * @type {Boolean}
     */
    this._runImmediately = opts.runImmediately || false;

    /**
     * Flag to know if we have to call {@link this.provider.requestData()}
     * automatically or not, default set to true.
     *
     * @private
     * @constant
     * @type {Boolean}
     */
    this._autoRequest = opts.autoRequest || true;

    /**
     * Keeps last data set by provider.
     *
     * @private
     * @type {Object}
     */
    this._data = undefined;

    /**
     * Some implementation of `ServiceProvider`.
     *
     * @private
     * @type {ServiceProvider}
     */
    this.provider = undefined;

    // Listen for new event listeners.
    this.on('newListener', (event, listener) => {

      // We do not handle 'removeListener' here.
      if (event === 'removeListener') { return; }

      // First we make sure `provider` is defined.
      if (!this.isProviderRegistered()) {
        throw new Error('"provider" should be registered before listening any event.');
      }

      // Only 'data' and 'error' events allowed.
      if (event !== 'data' && event !== 'error') {
        throw new Error('For now, only listening "data" and "error" events are allow.');
      }

      // event 'data' is our keyword event name for main process.
      if (event === 'data') {

        // When got first 'data' listener...
        if (!this.dataHasListeners()) {

          // ...set provider to ON.
          this.provider.turnON();

          // Listen for provider 'data' event to be able to transmit the message
          // to custom service emitters.
          this.provider.on('data', data => {

            // Implementation of `onProviderData` should return a `Boolean`
            // indicating if data received from provider is valid or not, if
            // valid then proceed to update `this._data`.
            this.onProviderData(data, (error, validatedData) => {
              if (error) {
                return this.emit('error', error);
              }

              this._data = validatedData;
              this.emit('data', this._data);
            });
          });

          // Listen provider 'error' event to be able to transmit error to
          // custom service emitters.
          this.provider.on('error', err => this.onProviderError(err));
        }

        // Make sure we are not overriding `_intervalObject`.
        if (this._intervalObject === undefined) {
          this._intervalObject = setInterval(() => this._intervalCallback(), this._delay);

          // Call interval callback NOW if `runImmediately` option is true.
          if (this._runImmediately) {
            this._intervalCallback();
          }
        }
      }

      // Call `onNewListener` for custom behavior.
      this.onNewListener(event, listener);
    });

    // Listen removeListener event.
    this.on('removeListener', (event, listener) => {

      // If no one listens 'data' event then...
      if (!this.dataHasListeners()) {

        // Reset interval.
        clearInterval(this._intervalObject);
        this._intervalObject = undefined;

        // Reset data.
        this._data = undefined;

        // Make sure provider is registered before setting it OFF.
        if (this.isProviderRegistered()) {
          this.provider.turnOFF();

          // Remove all provider listeners, 'data', 'error' and 'wantsData'.
          this.provider.removeAllListeners();
        }
      }

      // Call `onRemoveListener` for custom behavior.
      this.onRemoveListener(event, listener);
    });
  }

  /**
   * Interval callback for {@link this._intervalObject}.
   *
   * @private
   */
  _intervalCallback () {

    // If `this._autoRequest` is true and provider is registered then
    // request data to provider.
    if (this._autoRequest && this.isProviderRegistered()) {
      this.provider.requestData();
    }

    // Call `this.interval()` for custom emitters to know.
    this.interval();
  }

  /**
   * Checks if any listeners listen 'data' event.
   *
   * @return {Boolean} `true` if at least one client listens `data` event.
   */
  dataHasListeners () {
    return this.listenerCount('data') > 0;
  }

  /**
   * Checks if listener provided is listening event name.
   *
   * @param {String} event - Event name to check.
   * @param {Function} listener - Listener to check.
   * @return {Boolean} Whether listener listens event.
   */
  isListeningTo (event, listener) {
    return this.listeners(event).some(_listener => {
      return _listener === listener;
    });
  }

  /**
   * Public method for ServiceProvider registration.
   *
   * @param {ServiceProvider} provider - One of the available providers.
   */
  registerProvider (provider) {

    if (!(provider instanceof ServiceProvider)) {
      throw new Error('"provider" must be an instance of `ServiceProvider`.');
    }

    if (this.isProviderRegistered()) {
      throw new Error('"provider" is already registered!');
    }

    // Do the actual registration.
    this.provider = provider;
  }

  /**
   * Verifies if {@link this.provider} is already registered.
   *
   * @return {Boolean} `true` is registered, `false` otherwise.
   */
  isProviderRegistered () {
    return this.provider && this.provider instanceof ServiceProvider;
  }

  /**
   * Get current provider data with optional pick filter.
   *
   * @param {Array} [pick] - Array of properties to return in Object.
   * @return {Object} Current provider data Object.
   */
  getCurrentData (pick) {
    return !pick ? this._data : _pick(this._data, pick);
  }

  /**
   * Empty `interval` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called in each cycle of main interval.
   */
  interval () { }

  /**
   * Empty `onNewListener` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called on new event listener.
   * @param {String} event - Event name.
   * @param {Function} listener - Listener Function.
   */
  onNewListener (event, listener) { }

  /**
   * Empty `onRemoveListener` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called on remotion of event listener.
   * @param {String} event - Event name.
   * @param {Function} listener - Listener Function.
   */
  onRemoveListener (event, listener) { }

  /**
   * Empty `onProviderData` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called when provider emits new data.
   * @param {Object} data - Data to emit.
   * @param {Function} cb - Function to be called after data validation.
   * @return {Boolean} Indicates if data received from provider is valid or not.
   *
   * Note: The returned value by the implementation of this method will be used
   * to decide if we should update {@link this._data} with data received or not.
   */
  onProviderData (data, cb) { }

  /**
   * Empty `onProviderError` function to be implemented by custom emitter.
   *
   * @abstract
   * @desc This function will be called when provider emits an error.
   * @param {Object} err - Error to emit.
   */
  onProviderError (err) {
    this.emit('error', err);
  }
}

module.exports = ServiceEmitter;
<|endoftext|>


<commit_before>(function() {
  'use strict';
  angular.module('civic.users.profile', []);
  angular.module('civic.users.common', []);
  angular.module('civic.users')
    .config(UsersViewConfig)
    .controller('UsersViewController', UsersViewController);

  // @ngInject
  function UsersViewConfig($stateProvider) {
    console.log('UsersViewConfig called.');
    $stateProvider
      .state('users', {
        abstract: true,
        url: '/users/:userId',
        template: '<ui-view id="users-view"></ui-view>',
        controller: 'UsersViewController'
      })
      .state('users.profile', {
        url:'/profile',
        templateUrl: 'app/views/users/profile/profile.tpl.html',
        resolve: {
          'Users': 'Users',
          'user': function(Users, $stateParams) {
            return Users.get($stateParams.userId);
          },
          'events': function(Users, $stateParams) {
            return Users.queryEvents($stateParams.userId);
          },
          'evidence': function(Search, user) {
            var query = {
              'operator':'AND',
              'save': false,
              'queries': [
                {
                  'field':'submitter',
                  'condition': {
                    'name':'is',
                    'parameters':[user.display_name]
                  }
                }
              ]};
            return Search.post(query);
          }
        },
        controller: 'ProfileController',
        data: {
          navMode: 'sub',
          titleExp: '"Profile: " + user.display_name'
        }
      })
      .state('users.edit', {
        url:'/edit',
        templateUrl: 'app/views/users/profile/edit/profileEdit.tpl.html',
        resolve: {
          'Users': 'Users',
          'user': function(Users, $stateParams) {
            return Users.get($stateParams.userId);
          }
        },
        controller: 'ProfileEditController',
        data: {
          navMode: 'sub',
          titleExp: '"Profile: " + user.display_name'
        }
      });
  }

  // @ngInject
  function UsersViewController() {
    console.log('UsersViewController instantiated.');
  }

})();
<commit_msg>use submitter id. fixes genome/civic-server#160<commit_after>(function() {
  'use strict';
  angular.module('civic.users.profile', []);
  angular.module('civic.users.common', []);
  angular.module('civic.users')
    .config(UsersViewConfig)
    .controller('UsersViewController', UsersViewController);

  // @ngInject
  function UsersViewConfig($stateProvider) {
    console.log('UsersViewConfig called.');
    $stateProvider
      .state('users', {
        abstract: true,
        url: '/users/:userId',
        template: '<ui-view id="users-view"></ui-view>',
        controller: 'UsersViewController'
      })
      .state('users.profile', {
        url:'/profile',
        templateUrl: 'app/views/users/profile/profile.tpl.html',
        resolve: {
          'Users': 'Users',
          'user': function(Users, $stateParams) {
            return Users.get($stateParams.userId);
          },
          'events': function(Users, $stateParams) {
            return Users.queryEvents($stateParams.userId);
          },
          'evidence': function(Search, user) {
            var query = {
              'operator':'AND',
              'save': false,
              'queries': [
                {
                  'field':'submitter_id',
                  'condition': {
                    'name':'is_equal_to',
                    'parameters':[user.id]
                  }
                }
              ]};
            return Search.post(query);
          }
        },
        controller: 'ProfileController',
        data: {
          navMode: 'sub',
          titleExp: '"Profile: " + user.display_name'
        }
      })
      .state('users.edit', {
        url:'/edit',
        templateUrl: 'app/views/users/profile/edit/profileEdit.tpl.html',
        resolve: {
          'Users': 'Users',
          'user': function(Users, $stateParams) {
            return Users.get($stateParams.userId);
          }
        },
        controller: 'ProfileEditController',
        data: {
          navMode: 'sub',
          titleExp: '"Profile: " + user.display_name'
        }
      });
  }

  // @ngInject
  function UsersViewController() {
    console.log('UsersViewController instantiated.');
  }

})();
<|endoftext|>


<commit_before>(function(w, d){
    var B = {
        dataArr:[

        ],
        addValue:function(name, data){

        },
        addArrValues: function(){

        },

    };

    function insertValues(name, value) {
        var patternConstructor = "/{{"+name+"}}/";
        var pattern = new RegExp(patternConstructor, "gi");//test

        var body = d.getElementsByTagName("body")[0];
        //var bodyText = document.getElementsByTagName("body")[0].innerHTML;
        var bodyText = body.innerHTML;
        bodyLikeText.replace(pattern, value);
        body.innerHTML = bodyText;
    }

    return B;
})(window, document);<commit_msg>Add function 'init'<commit_after>(function(w, d){
    var $B = {
        dataArr:{},
        addValue:function(name, value){
            this.dataArr[name] = value;
        },
        addArrValues: function(objVal){
            for (var name in objVal) {
                this.addValue(name, objVal[name]);
            }
        },
        init: function(){
            for (var key in this.dataArr) {
                this.insert(key, this.dataArr[key]);
            }
        },
        insert: insertValues()
    };

    function insertValues(name, value) {
        var patternConstructor = "/{{"+name+"}}/";
        var pattern = new RegExp(patternConstructor, "gi");
        var body = d.getElementsByTagName("body")[0];
        //var bodyText = document.getElementsByTagName("body")[0].innerHTML;
        var bodyText = body.innerHTML;
        bodyLikeText.replace(pattern, value);
        body.innerHTML = bodyText;
    }

    return $B;
})(window, document);<|endoftext|>


<commit_before><commit_msg>Based<commit_after>(function(w){
    var B = {};

    return B;
})(windows);<|endoftext|>


<commit_before>'use strict';
module.exports = {
  // TODO get ontology terms and other data

  toJson: function(str, pathwayMetadata, callback) {
    var thisJquery;
    var xmlSelection;
    // if we were just using Cheerio, we could select namespace elements like this:
    // xmlSelection('bp\\:PublicationXref')
    // but in my tests with this in Chrome, it appears jQuery doesn't work with that selector
    // so to make this work in both Node.js and the browser, I'm removing the namespace prefixes from element tagNames
    // namespace prefixes appear to work OK as attribute names.
    var denamespacedStr = str.replace(/bp\:/g, '');
    if (typeof window === 'undefined') {
      var Cheerio = require('cheerio');
      thisJquery = Cheerio.load(denamespacedStr, {
        normalizeWhitespace: true,
        xmlMode: true,
        decodeEntities: true,
        lowerCaseTags: false
      });
      xmlSelection = thisJquery.root();
      //xmlSelection = $('Biopax');
    } else {
      thisJquery = $;
      var xmlDoc = thisJquery.parseXML(str);
      xmlSelection = thisJquery(xmlDoc);
    }

    var jsonBiopax = pathwayMetadata;
    jsonBiopax.entities = [];

    var displayName = 1;
    xmlSelection.find('PublicationXref').each(function() {
      var xmlPublicationXrefSelection = thisJquery( this );
      var publicationXref = {};
      publicationXref.type = 'PublicationXref';
      publicationXref.id = xmlPublicationXrefSelection.attr('rdf:ID') || xmlPublicationXrefSelection.attr('rdf:about');
      publicationXref.dbName = xmlPublicationXrefSelection.find('db').text().toLowerCase();
      publicationXref.dbId = xmlPublicationXrefSelection.find('id').text();
      if (publicationXref.id.indexOf('identifiers') === -1 && (publicationXref.dbName === 'pubmed' || publicationXref.dbName === 'medline') && /^\d+$/g.test(publicationXref.dbId)) {
        publicationXref.deprecatedId = publicationXref.id;
        publicationXref.id = 'http://identifiers.org/pubmed/' + publicationXref.dbId;
      }
      publicationXref.displayName = displayName;
      displayName += 1;
      jsonBiopax.entities.push(publicationXref);
    });
    callback(null, jsonBiopax);
  }
};
<commit_msg>use de-namespaced string<commit_after>'use strict';
module.exports = {
  // TODO get ontology terms and other data

  toJson: function(str, pathwayMetadata, callback) {
    var thisJquery;
    var xmlSelection;
    // if we were just using Cheerio, we could select namespace elements like this:
    // xmlSelection('bp\\:PublicationXref')
    // but in my tests with this in Chrome, it appears jQuery doesn't work with that selector
    // so to make this work in both Node.js and the browser, I'm removing the namespace prefixes from element tagNames
    // namespace prefixes appear to work OK as attribute names.
    var denamespacedStr = str.replace(/bp\:/g, '');
    if (typeof window === 'undefined') {
      var Cheerio = require('cheerio');
      thisJquery = Cheerio.load(denamespacedStr, {
        normalizeWhitespace: true,
        xmlMode: true,
        decodeEntities: true,
        lowerCaseTags: false
      });
      xmlSelection = thisJquery.root();
      //xmlSelection = $('Biopax');
    } else {
      thisJquery = $;
      var xmlDoc = thisJquery.parseXML(denamespacedStr);
      xmlSelection = thisJquery(xmlDoc);
    }

    var jsonBiopax = pathwayMetadata;
    jsonBiopax.entities = [];

    var displayName = 1;
    xmlSelection.find('PublicationXref').each(function() {
      var xmlPublicationXrefSelection = thisJquery( this );
      var publicationXref = {};
      publicationXref.type = 'PublicationXref';
      publicationXref.id = xmlPublicationXrefSelection.attr('rdf:ID') || xmlPublicationXrefSelection.attr('rdf:about');
      publicationXref.dbName = xmlPublicationXrefSelection.find('db').text().toLowerCase();
      publicationXref.dbId = xmlPublicationXrefSelection.find('id').text();
      if (publicationXref.id.indexOf('identifiers') === -1 && (publicationXref.dbName === 'pubmed' || publicationXref.dbName === 'medline') && /^\d+$/g.test(publicationXref.dbId)) {
        publicationXref.deprecatedId = publicationXref.id;
        publicationXref.id = 'http://identifiers.org/pubmed/' + publicationXref.dbId;
      }
      publicationXref.displayName = displayName;
      displayName += 1;
      jsonBiopax.entities.push(publicationXref);
    });
    callback(null, jsonBiopax);
  }
};
<|endoftext|>


<commit_before>'use strict';
const tools = require('../tools.js');
const events = require('events');

function addInstance(device, options, cb){
	// options.newInstances
    // options.existingInstances
    // device - additional info about device
    // options.log - logger
    // options.language - system language
    tools.words['comments'] = {
        "en": "Warning! All Cameras/NVT on the network must have the same user",
		"de": "Warnung! Alle Kameras/NVT im Netzwerk müssen denselben Benutzer haben",
		"ru": "Предупреждение! Все камеры/NVT в сети должны иметь одного и того же пользователя",
		"pt": "Atenção! Todas as câmeras/NVT na rede devem ter o mesmo usuário",
		"nl": "Waarschuwing! Alle camera's/NVT op het netwerk moeten dezelfde gebruiker hebben",
		"fr": "Avertissement! Toutes les caméras/NVT sur le réseau doivent avoir le même utilisateur",
		"it": "Avvertimento! Tutte le telecamere/NVT sulla rete devono avere lo stesso utente",
		"es": "¡Advertencia! Todas las cámaras/NVT en la red deben tener el mismo usuario",
		"pl": "Ostrzeżenie! Wszystkie kamery/NVT w sieci muszą mieć tego samego użytkownika",
		"zh-cn": "警告！网络上的所有摄像机/ NVT必须具有相同的用户"
    };

    let instance = tools.findInstance(options, 'onvif', obj => {
		options.log.debug('Onvif. obj = ' + JSON.stringify(obj));
		return obj.common.name === 'onvif';
	});

    if (!instance){
		let comment = 'Cameras/NVT - ' + device.count + ' (' + tools.translate(options.language, 'comments') + ')';
		const id = tools.getNextInstanceID('onvif', options);

		instance = {
			_id: id,
			common: {
				name:    'onvif',
				enabled: true,
				title:   'Onvif Support'
			},
			comment: {
				add: [comment],
				inputs: [
					{
						name: 'native.user',
						def: 'admin',
						type: 'text', // text, checkbox, number, select, password. Select requires
						title: 'user', // see translation in words.js
						options: { // example for select
							name1: 'value1',
							name2: 'value2',
							name3: 'value3'
						}
					},
					{
						name:  'native.password',
						def:   'admin',
						type:  'password',
						title: 'password' // see translation in words.js
					}
				]
			},
			native: {
				"start_range": device.start_range,
				"end_range": device.end_range,
				"ip_list": device.ip_list,
				"ports": device.ports,
				"autostartDiscovery": true
			}
		};
		options.newInstances.push(instance);

		cb && cb(true);
    } else {
		options.log.debug('Onvif. The adapter instance is already installed.');
        cb && cb(false);
    }
}

function s4() {
	return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};

function guid() {
	return (s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4());
};

var Discovery = Object.create(new events.EventEmitter());

function Discovery_probe(options, callback) {
	var cams = []
		, errors = []
		, messageID = 'urn:uuid:' + guid()
		, request = Buffer.from(
			'<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:dn="http://www.onvif.org/ver10/network/wsdl">' +
				'' +
					'<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">' + messageID + '</wsa:MessageID>' +
					'<wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>' +
					'<wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>' +
				'' +
				'' +
					'<Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
						'<Types>dn:NetworkVideoTransmitter</Types>' +
						'<Scopes />' +
					'</Probe>' +
				'' +
			'</Envelope>'
		)
		, socket = require('dgram').createSocket('udp4');

	socket.on('error', function(err) {
		Discovery.emit('error', err);
		callback(err, null);
	});

	const listener = function(msg, rinfo) {
		let message = msg.toString();
		options.log.debug('Onvif. listener: msg = ' + JSON.stringify(message));
		options.log.debug('Onvif. listener: rinfo = ' + JSON.stringify(rinfo));
		let start = message.indexOf('<d:XAddrs>') + 10;
		if (start > 10){
			let end = message.indexOf('</d:XAddrs>');
			message = message.substring(start, end);
			options.log.debug('Onvif. listener: msg = ' + JSON.stringify(message));
			start = message.indexOf('://') + 3;
			end = message.indexOf('/onvif/');
			message = message.substring(start, end);
			message = message.split(':');
			options.log.debug('Onvif. listener ip: ' + message[0] + ':' + message[1]);
			cams.push({
			'ip': message[0],
			'port': message[1]
			});
		}
	};

	socket.on('message', listener);
	socket.send(request, 0, request.length, 3702, '239.255.255.250');

	setTimeout(function() {
		socket.removeListener('message', listener);
		socket.close();
		callback(null, cams);
	}.bind(this), 5000);
};

function detect(ip, device, options, callback){
    function cb(err, is, ip){
        if (callback){
            callback(err, is, ip);
            callback = null;
        }
    }

	Discovery_probe(options, (err, cams) => {
		if (err) {
			cb && cb(err, false, ip);
		} else {
			let ports = '';
			let ip_list = [];
			let splits;
			let start_range;
			let end_range;
			let count = 0;
			cams.forEach(device => {
				count++;
				if (ports.indexOf(device.port) < 0){
					if (ports.length > 1) {ports = ports + ', ' + device.port}
					else {ports = device.port}
				}
				ip_list.push(device.ip);
				splits = device.ip.split('.');
				splits[3] = 1;
				start_range = splits.join('.');
				splits[3] = 254;
				end_range = splits.join('.');
			});

			device = {
				count: count,
				start_range: start_range,
				end_range: end_range,
				ip_list: ip_list,
				ports: ports
			}
			options.log.debug('Onvif. device = ' + JSON.stringify(device));
			if (count == 0) {
				cb && cb(null, false, ip);
			} else {
				addInstance(device, options, (state) => {
					cb && cb(null, state, ip);
				});
			}
		}
	});
}

exports.detect = detect;
exports.type = ['udp'];
exports.timeout = 6000;
<commit_msg>Update onvif.js<commit_after>'use strict';
const tools = require('../tools.js');
const events = require('events');

function addInstance(device, options, cb){
	// options.newInstances
    // options.existingInstances
    // device - additional info about device
    // options.log - logger
    // options.language - system language
    tools.words['comments'] = {
        "en": "Warning! All Cameras/NVT on the network must have the same user",
		"de": "Warnung! Alle Kameras/NVT im Netzwerk müssen denselben Benutzer haben",
		"ru": "Предупреждение! Все камеры/NVT в сети должны иметь одного и того же пользователя",
		"pt": "Atenção! Todas as câmeras/NVT na rede devem ter o mesmo usuário",
		"nl": "Waarschuwing! Alle camera's/NVT op het netwerk moeten dezelfde gebruiker hebben",
		"fr": "Avertissement! Toutes les caméras/NVT sur le réseau doivent avoir le même utilisateur",
		"it": "Avvertimento! Tutte le telecamere/NVT sulla rete devono avere lo stesso utente",
		"es": "¡Advertencia! Todas las cámaras/NVT en la red deben tener el mismo usuario",
		"pl": "Ostrzeżenie! Wszystkie kamery/NVT w sieci muszą mieć tego samego użytkownika",
		"zh-cn": "警告！网络上的所有摄像机/ NVT必须具有相同的用户"
    };

    let instance = tools.findInstance(options, 'onvif', obj => {
		options.log.debug('Onvif. obj = ' + JSON.stringify(obj));
		return obj.common.name === 'onvif';
	});

    if (!instance){
		let comment = 'Cameras/NVT - ' + device.count + ' (' + tools.translate(options.language, 'comments') + ')';
		const id = tools.getNextInstanceID('onvif', options);

		instance = {
			_id: id,
			common: {
				name:    'onvif',
				enabled: true,
				title:   'Onvif Support'
			},
			comment: {
				add: [comment],
				inputs: [
					{
						name: 'native.user',
						def: 'admin',
						type: 'text', // text, checkbox, number, select, password. Select requires
						title: 'user', // see translation in words.js
						options: { // example for select
							name1: 'value1',
							name2: 'value2',
							name3: 'value3'
						}
					},
					{
						name:  'native.password',
						def:   'admin',
						type:  'password',
						title: 'password' // see translation in words.js
					}
				]
			},
			native: {
				"start_range": device.start_range,
				"end_range": device.end_range,
				"ip_list": device.ip_list,
				"ports": device.ports,
				"autostartDiscovery": true
			}
		};
		options.newInstances.push(instance);

		cb && cb(true);
    } else {
		options.log.debug('Onvif. The adapter instance is already installed.');
        cb && cb(false);
    }
}

function s4() {
	return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1);
};

function guid() {
	return (s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4());
};

var Discovery = Object.create(new events.EventEmitter());

function Discovery_probe(options, callback) {
	var cams = []
		, errors = []
		, messageID = 'urn:uuid:' + guid()
		, request = Buffer.from(
			'<Envelope xmlns="http://www.w3.org/2003/05/soap-envelope" xmlns:dn="http://www.onvif.org/ver10/network/wsdl">' +
				'' +
					'<wsa:MessageID xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">' + messageID + '</wsa:MessageID>' +
					'<wsa:To xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">urn:schemas-xmlsoap-org:ws:2005:04:discovery</wsa:To>' +
					'<wsa:Action xmlns:wsa="http://schemas.xmlsoap.org/ws/2004/08/addressing">http://schemas.xmlsoap.org/ws/2005/04/discovery/Probe</wsa:Action>' +
				'' +
				'' +
					'<Probe xmlns="http://schemas.xmlsoap.org/ws/2005/04/discovery" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' +
						'<Types>dn:NetworkVideoTransmitter</Types>' +
						'<Scopes />' +
					'</Probe>' +
				'' +
			'</Envelope>'
		)
		, socket = require('dgram').createSocket('udp4');

	socket.on('error', function(err) {
		Discovery.emit('error', err);
		callback(err, null);
	});

	const listener = function(msg, rinfo) {
		let message = msg.toString();
		options.log.debug('Onvif. listener: msg = ' + JSON.stringify(message));
		options.log.debug('Onvif. listener: rinfo = ' + JSON.stringify(rinfo));
		let start = message.indexOf('<d:XAddrs>') + 10;
		if (start > 10){
			let end = message.indexOf('</d:XAddrs>');
			message = message.substring(start, end);
			options.log.debug('Onvif. listener: msg = ' + JSON.stringify(message));
			start = message.indexOf('://') + 3;
			end = message.indexOf('/onvif/');
			message = message.substring(start, end);
			message = message.split(':');
			options.log.debug('Onvif. listener ip: ' + message[0] + ':' + message[1]);
			cams.push({
			'ip': message[0],
			'port': message[1]
			});
		}
	};

	socket.on('message', listener);
	socket.send(request, 0, request.length, 3702, '239.255.255.250');

	setTimeout(function() {
		socket.removeListener('message', listener);
		socket.close();
		callback(null, cams);
	}.bind(this), 5000);
};

function detect(ip, device, options, callback){
    function cb(err, is, ip){
        if (callback){
            callback(err, is, ip);
            callback = null;
        }
    }

	Discovery_probe(options, (err, cams) => {
		if (err) {
			cb && cb(err, false, ip);
		} else {
			let ports = '';
			let ip_list = [];
			let splits;
			let start_range;
			let end_range;
			let count = 0;
			cams.forEach(device => {
				count++;
				if (ports.indexOf(device.port) < 0){
					if (ports.length > 1) {ports = ports + ', ' + device.port}
					else {ports = device.port}
				}
				if (ip_list.indexOf(device.ip) === -1) ip_list.push(device.ip);
				splits = device.ip.split('.');
				splits[3] = 1;
				start_range = splits.join('.');
				splits[3] = 254;
				end_range = splits.join('.');
			});

			device = {
				count: count,
				start_range: start_range,
				end_range: end_range,
				ip_list: ip_list,
				ports: ports
			}
			options.log.debug('Onvif. device = ' + JSON.stringify(device));
			if (count == 0) {
				cb && cb(null, false, ip);
			} else {
				addInstance(device, options, (state) => {
					cb && cb(null, state, ip);
				});
			}
		}
	});
}

exports.detect = detect;
exports.type = ['udp'];
exports.timeout = 6000;
<|endoftext|>


<commit_before>// Importing other shit
var Hapi = require('hapi');
var Request = require('request');
var Async = require('async');
// Importing my own shit
var Db = require('../db');
var Config = require('../config');
var Util = require('../utility');
var Proto = require('../proto');
// Private shit
var internals = {};

internals.dbHandler = function (prBuffer) {
  if (prBuffer) {
    console.log("We are getting the buffer from db");
    internals.reply.source = prBuffer;
    internals.reply.variety = 'buffer'; // or 'stream'
    internals.reply('success').type('application/bitcoin-payment-request');
  } else {
    var error = Hapi.error.notFound('Provided id not found in our database, try again later!');
    error.reformat();
    internals.reply(error)
  }

}

/**
 * Handler for /pay/{id}
 * @type {Object}
 */
exports.get = {
  handler: function (request, reply) {
    console.log(' [PAY]: ' + request.params.id);
    var id = Util.idToDBIndex(request.params.id);
    // request.reply("this is db index: " + id);
    internals.reply = reply || request.reply || {};
    Db.getPaymentRequestForId(id, internals.dbHandler);
  }
};<commit_msg>pay should return the payment request buffer<commit_after>// Importing other shit
var Hapi = require('hapi');
var Request = require('request');
var Async = require('async');
// Importing my own shit
var Db = require('../db');
var Config = require('../config');
var Util = require('../utility');
var Proto = require('../proto');
// Private shit
var internals = {};

internals.dbHandler = function (prBuffer) {
  if (prBuffer) {
    console.log("We are getting the buffer from db");
    prBuffer = new Buffer(prBuffer.encode, 'hex');
    internals.reply(prBuffer).header('content-length', prBuffer.length).type('application/bitcoin-payment-request');
  } else {
    var error = Hapi.error.notFound('Provided id not found in our database, try again later!');
    error.reformat();
    internals.reply(error)
  }

}

/**
 * Handler for /pay/{id}
 * @type {Object}
 */
exports.get = {
  handler: function (request, reply) {
    console.log(' [PAY]: ' + request.params.id);
    var id = Util.idToDBIndex(request.params.id);
    internals.reply = reply || request.reply || {};
    Db.getPaymentRequestForId(id, internals.dbHandler);
  }
};<|endoftext|>


<commit_before>function generate (inputs) {

    var previous_autotune = inputs.previous_autotune;
    //TODO: use pumpprofile to implement 20% limit on tuning
    var pumpprofile = inputs.pumpprofile;
    var basalprofile = previous_autotune.basalprofile;
    //console.error(basalprofile);
    var isf_profile = previous_autotune.isfProfile;
    //console.error(isf_profile);
    var isf = isf_profile.sensitivities[0].sensitivity;
    //console.error(isf);
    var carb_ratio = previous_autotune.carb_ratio;
    //console.error(carb_ratio);
    var csf = isf / carb_ratio;
    //console.error(csf);
    var prepped_glucose = inputs.prepped_glucose;
    var csf_glucose = prepped_glucose.csf_glucose_data;
    //console.error(csf_glucose[0]);
    var isf_glucose = prepped_glucose.isf_glucose_data;
    //console.error(isf_glucose[0]);
    var basal_glucose = prepped_glucose.basal_glucose_data;
    //console.error(basal_glucose[0]);

    // convert the basal profile to hourly if it isn't already
    hourlybasalprofile = [];
    for (var i=0; i < 24; i++) {
        for (var j=0; j < basalprofile.length; ++j) {
            if (basalprofile[j].minutes <= i * 60) {
                hourlybasalprofile[i] = JSON.parse(JSON.stringify(basalprofile[j]));
            }
        }
        hourlybasalprofile[i].i=i;
        hourlybasalprofile[i].minutes=i*60;
        hourlybasalprofile[i].rate=Math.round(hourlybasalprofile[i].rate*1000)/1000
    }
    console.error(hourlybasalprofile);

    // look at net deviations for each hour
    for (var hour=0; hour < 24; hour++) {
        var deviations = 0;
        for (var i=0; i < basal_glucose.length; ++i) {
            //console.error(basal_glucose[i].dateString);
            splitString = basal_glucose[i].dateString.split("T");
            timeString = splitString[1];
            splitTime = timeString.split(":");
            myHour = parseInt(splitTime[0]);
            if (hour == myHour) {
                //console.error(basal_glucose[i].deviation);
                deviations += parseFloat(basal_glucose[i].deviation);
            }
        }
        deviations = Math.round( deviations * 1000 ) / 1000
        //console.error("Hour",hour.toString(),"total deviations:",deviations,"mg/dL");
        // calculate how much less or additional basal insulin would have been required to eliminate the deviations
        // only apply 20% of the needed adjustment to keep things relatively stable
        basalNeeded = 0.2 * deviations / isf;
        basalNeeded = Math.round( basalNeeded * 1000 ) / 1000
        // if basalNeeded is positive, adjust each of the 1-3 hour prior basals by 10% of the needed adjustment
        console.error("Hour",hour,"basal adjustment needed:",basalNeeded,"U/hr");
        if (basalNeeded > 0 ) {
            for (var offset=-3; offset < 0; offset++) {
                offsetHour = hour + offset;
                if (offsetHour < 0) { offsetHour += 24; }
                //console.error(offsetHour);
                hourlybasalprofile[offsetHour].rate += basalNeeded / 3;
                hourlybasalprofile[offsetHour].rate=Math.round(hourlybasalprofile[offsetHour].rate*1000)/1000
            }
        // otherwise, figure out the percentage reduction required to the 1-3 hour prior basals
        // and adjust all of them downward proportionally
        } else if (basalNeeded < 0) {
            var threeHourBasal = 0;
            for (var offset=-3; offset < 0; offset++) {
                offsetHour = hour + offset;
                if (offsetHour < 0) { offsetHour += 24; }
                threeHourBasal += hourlybasalprofile[offsetHour].rate;
            }
            var adjustmentRatio = 1.0 + basalNeeded / threeHourBasal;
            console.error(adjustmentRatio);
            for (var offset=-3; offset < 0; offset++) {
                offsetHour = hour + offset;
                if (offsetHour < 0) { offsetHour += 24; }
                hourlybasalprofile[offsetHour].rate = hourlybasalprofile[offsetHour].rate * adjustmentRatio;
                hourlybasalprofile[offsetHour].rate=Math.round(hourlybasalprofile[offsetHour].rate*1000)/1000
            }
        }
    }
    console.error(hourlybasalprofile);
    basalprofile = hourlybasalprofile;

    // calculate median deviation and bgi in data attributable to ISF
    var deviations = [];
    var bgis = [];
    var avgDeltas = [];
    var ratios = [];
    var count = 0;
    for (var i=0; i < isf_glucose.length; ++i) {
       deviation = parseFloat(isf_glucose[i].deviation);
       deviations.push(deviation);
       bgi = parseFloat(isf_glucose[i].bgi);
       bgis.push(bgi);
       avgDelta = parseFloat(isf_glucose[i].avgDelta);
       avgDeltas.push(avgDelta);
       ratio = 1 + deviation / bgi;
       //console.error("Deviation:",deviation,"BGI:",bgi,"avgDelta:",avgDelta,"ratio:",ratio);
       ratios.push(ratio);
       count++;
    }
    avgDeltas.sort(function(a, b){return a-b});
    bgis.sort(function(a, b){return a-b});
    deviations.sort(function(a, b){return a-b});
    ratios.sort(function(a, b){return a-b});
    p50deviation = percentile(deviations, 0.50);
    p50bgi = percentile(bgis, 0.50);
    p50ratios = Math.round( percentile(ratios, 0.50) * 1000)/1000;

    // calculate what adjustments to ISF would have been necessary to bring median deviation to zero
    fullNewISF = isf * p50ratios;
    fullNewISF = Math.round( fullNewISF * 1000 ) / 1000;
    // and apply 10% of that adjustment
    newIsf = ( 0.9 * isf ) + ( 0.1 * fullNewISF );
    newIsf = Math.round( newIsf * 1000 ) / 1000;
    //console.error(avgRatio);
    //console.error(newIsf);
    console.error("p50deviation:",p50deviation,"p50bgi",p50bgi,"p50ratios:",p50ratios,"Old ISF:",isf,"fullNewISF:",fullNewISF,"newIsf:",newIsf);

    isf = newIsf;

    // calculate net deviations while carbs are absorbing
    // measured from carb entry until COB and deviations both drop to zero

    var deviations = 0;
    var mealCarbs = 0;
    var totalMealCarbs = 0;
    var totalDeviations = 0;
    //console.error(csf_glucose[0].mealAbsorption);
    //console.error(csf_glucose[0]);
    for (var i=0; i < csf_glucose.length; ++i) {
        //console.error(csf_glucose[i].mealAbsorption, i);
        if ( csf_glucose[i].mealAbsorption === "start" ) {
            deviations = 0;
            mealCarbs = parseInt(csf_glucose[i].mealCarbs);
        } else if (csf_glucose[i].mealAbsorption === "end") {
            deviations += parseFloat(csf_glucose[i].deviation);
            // compare the sum of deviations from start to end vs. current CSF * mealCarbs
            //console.error(csf,mealCarbs);
            csfRise = csf * mealCarbs;
            //console.error(deviations,isf);
            console.error("csfRise:",csfRise,"deviations:",deviations);
            totalMealCarbs += mealCarbs;
            totalDeviations += deviations;

        } else {
            deviations += Math.max(0*previous_autotune.min_5m_carbimpact,parseFloat(csf_glucose[i].deviation));
            mealCarbs = Math.max(mealCarbs, parseInt(csf_glucose[i].mealCarbs));
        }
    }
    if (totalMealCarbs == 0) { totalMealCarbs += mealCarbs; }
    if (totalDeviations == 0) { totalDeviations += deviations; }
    //console.error(totalDeviations, totalMealCarbs);
    if (totalMealCarbs == 0) {
        fullNewCSF = csf;
    } else {
        fullNewCSF = Math.round( (totalDeviations / totalMealCarbs)*100 )/100;
    }
    newCsf = ( 0.9 * csf ) + ( 0.1 * fullNewCSF );
    newCsf = Math.round( newCsf * 1000 ) / 1000;
    console.error("totalMealCarbs:",totalMealCarbs,"totalDeviations:",totalDeviations,"fullNewCSF:",fullNewCSF,"newCsf:",newCsf);
    csf = newCsf;

    // reconstruct updated version of previous_autotune as autotune_output
    autotune_output = previous_autotune;
    autotune_output.basalprofile = basalprofile;
    isf_profile.sensitivities[0].sensitivity = isf;
    autotune_output.isfProfile = isf_profile;
    autotune_output.csf = csf;
    carb_ratio = isf / csf;
    carb_ratio = Math.round( carb_ratio * 1000 ) / 1000;
    autotune_output.carb_ratio = carb_ratio;

    return autotune_output;
}

exports = module.exports = generate;

// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
// Returns the value at a given percentile in a sorted numeric array.
// "Linear interpolation between closest ranks" method
function percentile(arr, p) {
    if (arr.length === 0) return 0;
    if (typeof p !== 'number') throw new TypeError('p must be a number');
    if (p <= 0) return arr[0];
    if (p >= 1) return arr[arr.length - 1];

    var index = arr.length * p,
        lower = Math.floor(index),
        upper = lower + 1,
        weight = index % 1;

    if (upper >= arr.length) return arr[lower];
    return arr[lower] * (1 - weight) + arr[upper] * weight;
}

// Returns the percentile of the given value in a sorted numeric array.
function percentRank(arr, v) {
    if (typeof v !== 'number') throw new TypeError('v must be a number');
    for (var i = 0, l = arr.length; i < l; i++) {
        if (v <= arr[i]) {
            while (i < l && v === arr[i]) i++;
            if (i === 0) return 0;
            if (v !== arr[i-1]) {
                i += (v - arr[i-1]) / (arr[i] - arr[i-1]);
            }
            return i / l;
        }
    }
    return 1;
}
<commit_msg>use pumpprofile to implement 20% limit on tuning<commit_after>function generate (inputs) {

    var previous_autotune = inputs.previous_autotune;
    var pumpbasalprofile = inputs.pumpprofile.basalprofile;
    //console.error(pumpbasalprofile);
    var basalprofile = previous_autotune.basalprofile;
    //console.error(basalprofile);
    var isf_profile = previous_autotune.isfProfile;
    //console.error(isf_profile);
    var isf = isf_profile.sensitivities[0].sensitivity;
    //console.error(isf);
    var carb_ratio = previous_autotune.carb_ratio;
    //console.error(carb_ratio);
    var csf = isf / carb_ratio;
    //console.error(csf);
    var prepped_glucose = inputs.prepped_glucose;
    var csf_glucose = prepped_glucose.csf_glucose_data;
    //console.error(csf_glucose[0]);
    var isf_glucose = prepped_glucose.isf_glucose_data;
    //console.error(isf_glucose[0]);
    var basal_glucose = prepped_glucose.basal_glucose_data;
    //console.error(basal_glucose[0]);

    // convert the basal profile to hourly if it isn't already
    hourlybasalprofile = [];
    hourlypumpprofile = [];
    for (var i=0; i < 24; i++) {
        // aututuned basal profile
        for (var j=0; j < basalprofile.length; ++j) {
            if (basalprofile[j].minutes <= i * 60) {
                hourlybasalprofile[i] = JSON.parse(JSON.stringify(basalprofile[j]));
            }
        }
        hourlybasalprofile[i].i=i;
        hourlybasalprofile[i].minutes=i*60;
        hourlybasalprofile[i].rate=Math.round(hourlybasalprofile[i].rate*1000)/1000
        // pump basal profile
        if (pumpbasalprofile[0]) {
            for (var j=0; j < pumpbasalprofile.length; ++j) {
                //console.error(pumpbasalprofile[j]);
                if (pumpbasalprofile[j].minutes <= i * 60) {
                    hourlypumpprofile[i] = JSON.parse(JSON.stringify(pumpbasalprofile[j]));
                }
            }
            hourlypumpprofile[i].i=i;
            hourlypumpprofile[i].minutes=i*60;
            hourlypumpprofile[i].rate=Math.round(hourlypumpprofile[i].rate*1000)/1000
        }
    }
    //console.error(hourlypumpprofile);
    //console.error(hourlybasalprofile);

    // look at net deviations for each hour
    for (var hour=0; hour < 24; hour++) {
        var deviations = 0;
        for (var i=0; i < basal_glucose.length; ++i) {
            //console.error(basal_glucose[i].dateString);
            splitString = basal_glucose[i].dateString.split("T");
            timeString = splitString[1];
            splitTime = timeString.split(":");
            myHour = parseInt(splitTime[0]);
            if (hour == myHour) {
                //console.error(basal_glucose[i].deviation);
                deviations += parseFloat(basal_glucose[i].deviation);
            }
        }
        deviations = Math.round( deviations * 1000 ) / 1000
        //console.error("Hour",hour.toString(),"total deviations:",deviations,"mg/dL");
        // calculate how much less or additional basal insulin would have been required to eliminate the deviations
        // only apply 20% of the needed adjustment to keep things relatively stable
        basalNeeded = 0.2 * deviations / isf;
        basalNeeded = Math.round( basalNeeded * 1000 ) / 1000
        // if basalNeeded is positive, adjust each of the 1-3 hour prior basals by 10% of the needed adjustment
        console.error("Hour",hour,"basal adjustment needed:",basalNeeded,"U/hr");
        if (basalNeeded > 0 ) {
            for (var offset=-3; offset < 0; offset++) {
                offsetHour = hour + offset;
                if (offsetHour < 0) { offsetHour += 24; }
                //console.error(offsetHour);
                hourlybasalprofile[offsetHour].rate += basalNeeded / 3;
                hourlybasalprofile[offsetHour].rate=Math.round(hourlybasalprofile[offsetHour].rate*1000)/1000
            }
        // otherwise, figure out the percentage reduction required to the 1-3 hour prior basals
        // and adjust all of them downward proportionally
        } else if (basalNeeded < 0) {
            var threeHourBasal = 0;
            for (var offset=-3; offset < 0; offset++) {
                offsetHour = hour + offset;
                if (offsetHour < 0) { offsetHour += 24; }
                threeHourBasal += hourlybasalprofile[offsetHour].rate;
            }
            var adjustmentRatio = 1.0 + basalNeeded / threeHourBasal;
            console.error(adjustmentRatio);
            for (var offset=-3; offset < 0; offset++) {
                offsetHour = hour + offset;
                if (offsetHour < 0) { offsetHour += 24; }
                hourlybasalprofile[offsetHour].rate = hourlybasalprofile[offsetHour].rate * adjustmentRatio;
                hourlybasalprofile[offsetHour].rate=Math.round(hourlybasalprofile[offsetHour].rate*1000)/1000
            }
        }
    }
    if (pumpbasalprofile[0]) {
        for (var hour=0; hour < 24; hour++) {
            //console.error(hourlybasalprofile[hour],hourlypumpprofile[hour].rate*1.2);
            var maxrate = hourlypumpprofile[hour].rate * 1.2;
            var minrate = hourlypumpprofile[hour].rate / 1.2;
            if (hourlybasalprofile[hour].rate > maxrate ) {
                console.error("Limiting hour",hour,"basal to",maxrate.toFixed(2),"(20% above pump basal of",hourlypumpprofile[hour].rate,")");
                hourlybasalprofile[hour].rate = hourlypumpprofile[hour].rate * 1.2;
            } else if (hourlybasalprofile[hour].rate < minrate ) {
                console.error("Limiting hour",hour,"basal to",minrate.toFixed(2),"(20% below pump basal of",hourlypumpprofile[hour].rate,")");
                hourlybasalprofile[hour].rate = hourlypumpprofile[hour].rate / 1.2;
            }
            hourlybasalprofile[hour].rate = Math.round(hourlybasalprofile[hour].rate*1000)/1000;
        }
    }

    console.error(hourlybasalprofile);
    basalprofile = hourlybasalprofile;

    // calculate median deviation and bgi in data attributable to ISF
    var deviations = [];
    var bgis = [];
    var avgDeltas = [];
    var ratios = [];
    var count = 0;
    for (var i=0; i < isf_glucose.length; ++i) {
       deviation = parseFloat(isf_glucose[i].deviation);
       deviations.push(deviation);
       bgi = parseFloat(isf_glucose[i].bgi);
       bgis.push(bgi);
       avgDelta = parseFloat(isf_glucose[i].avgDelta);
       avgDeltas.push(avgDelta);
       ratio = 1 + deviation / bgi;
       //console.error("Deviation:",deviation,"BGI:",bgi,"avgDelta:",avgDelta,"ratio:",ratio);
       ratios.push(ratio);
       count++;
    }
    avgDeltas.sort(function(a, b){return a-b});
    bgis.sort(function(a, b){return a-b});
    deviations.sort(function(a, b){return a-b});
    ratios.sort(function(a, b){return a-b});
    p50deviation = percentile(deviations, 0.50);
    p50bgi = percentile(bgis, 0.50);
    p50ratios = Math.round( percentile(ratios, 0.50) * 1000)/1000;

    // calculate what adjustments to ISF would have been necessary to bring median deviation to zero
    fullNewISF = isf * p50ratios;
    fullNewISF = Math.round( fullNewISF * 1000 ) / 1000;
    // and apply 10% of that adjustment
    newIsf = ( 0.9 * isf ) + ( 0.1 * fullNewISF );
    newIsf = Math.round( newIsf * 1000 ) / 1000;
    //console.error(avgRatio);
    //console.error(newIsf);
    console.error("p50deviation:",p50deviation,"p50bgi",p50bgi,"p50ratios:",p50ratios,"Old ISF:",isf,"fullNewISF:",fullNewISF,"newIsf:",newIsf);

    isf = newIsf;

    // calculate net deviations while carbs are absorbing
    // measured from carb entry until COB and deviations both drop to zero

    var deviations = 0;
    var mealCarbs = 0;
    var totalMealCarbs = 0;
    var totalDeviations = 0;
    //console.error(csf_glucose[0].mealAbsorption);
    //console.error(csf_glucose[0]);
    for (var i=0; i < csf_glucose.length; ++i) {
        //console.error(csf_glucose[i].mealAbsorption, i);
        if ( csf_glucose[i].mealAbsorption === "start" ) {
            deviations = 0;
            mealCarbs = parseInt(csf_glucose[i].mealCarbs);
        } else if (csf_glucose[i].mealAbsorption === "end") {
            deviations += parseFloat(csf_glucose[i].deviation);
            // compare the sum of deviations from start to end vs. current CSF * mealCarbs
            //console.error(csf,mealCarbs);
            csfRise = csf * mealCarbs;
            //console.error(deviations,isf);
            console.error("csfRise:",csfRise,"deviations:",deviations);
            totalMealCarbs += mealCarbs;
            totalDeviations += deviations;

        } else {
            deviations += Math.max(0*previous_autotune.min_5m_carbimpact,parseFloat(csf_glucose[i].deviation));
            mealCarbs = Math.max(mealCarbs, parseInt(csf_glucose[i].mealCarbs));
        }
    }
    if (totalMealCarbs == 0) { totalMealCarbs += mealCarbs; }
    if (totalDeviations == 0) { totalDeviations += deviations; }
    //console.error(totalDeviations, totalMealCarbs);
    if (totalMealCarbs == 0) {
        fullNewCSF = csf;
    } else {
        fullNewCSF = Math.round( (totalDeviations / totalMealCarbs)*100 )/100;
    }
    newCsf = ( 0.9 * csf ) + ( 0.1 * fullNewCSF );
    newCsf = Math.round( newCsf * 1000 ) / 1000;
    console.error("totalMealCarbs:",totalMealCarbs,"totalDeviations:",totalDeviations,"fullNewCSF:",fullNewCSF,"newCsf:",newCsf);
    csf = newCsf;

    // reconstruct updated version of previous_autotune as autotune_output
    autotune_output = previous_autotune;
    autotune_output.basalprofile = basalprofile;
    isf_profile.sensitivities[0].sensitivity = isf;
    autotune_output.isfProfile = isf_profile;
    autotune_output.csf = csf;
    carb_ratio = isf / csf;
    carb_ratio = Math.round( carb_ratio * 1000 ) / 1000;
    autotune_output.carb_ratio = carb_ratio;

    return autotune_output;
}

exports = module.exports = generate;

// From https://gist.github.com/IceCreamYou/6ffa1b18c4c8f6aeaad2
// Returns the value at a given percentile in a sorted numeric array.
// "Linear interpolation between closest ranks" method
function percentile(arr, p) {
    if (arr.length === 0) return 0;
    if (typeof p !== 'number') throw new TypeError('p must be a number');
    if (p <= 0) return arr[0];
    if (p >= 1) return arr[arr.length - 1];

    var index = arr.length * p,
        lower = Math.floor(index),
        upper = lower + 1,
        weight = index % 1;

    if (upper >= arr.length) return arr[lower];
    return arr[lower] * (1 - weight) + arr[upper] * weight;
}

// Returns the percentile of the given value in a sorted numeric array.
function percentRank(arr, v) {
    if (typeof v !== 'number') throw new TypeError('v must be a number');
    for (var i = 0, l = arr.length; i < l; i++) {
        if (v <= arr[i]) {
            while (i < l && v === arr[i]) i++;
            if (i === 0) return 0;
            if (v !== arr[i-1]) {
                i += (v - arr[i-1]) / (arr[i] - arr[i-1]);
            }
            return i / l;
        }
    }
    return 1;
}
<|endoftext|>