<commit_before>'use strict'

var buddyQuery = require('../lib/buddyQuery')

/*!
 *
 * Public
 *
 */

function getPublicResponse (request, reply) {
  var message = {
    message: "Hello, I'm your API"
  }
  reply(message)
}

/*!
 *
 * User
 *
 */

function getUser (request, reply) {
  var username = request.params.username
  var query = "SELECT * FROM dbMetakatalog.dbo.tblObjects WHERE ID = '" + username + "'"

  buddyQuery(query, function (err, data) {
    if (err) {
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUserName (request, reply) {
  var username = request.params.username
  var query = 'SELECT Firstname as firstName, Midlename as middleName, Lastname as lastName ' +
    'FROM dbMetakatalog.dbo.tblObjects ' +
    "WHERE ID = '" +
    username +
    "'"
  buddyQuery(query, function (err, data) {
    if (err) {
      console.log(query)
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUserMail (request, reply) {
  var username = request.params.username
  var query = 'SELECT Mail as email ' +
    'FROM dbMetakatalog.dbo.tblObjects ' +
    "WHERE ID = '" +
    username +
    "'"
  buddyQuery(query, function (err, data) {
    if (err) {
      console.log(query)
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUserGroupsOwner (request, reply) {
  var username = request.params.username
  var query = 'SELECT ' +
  'm.AttributeName as Role,m.ID as GroupID,m.StringValue as Username,o.ObjectType,o.GroupType,o.Description,n.StringValue as Unit ' +
  'FROM dbMetakatalog.dbo.tblMultiValue m, dbMetakatalog.dbo.tblObjects o ' +
  'inner join dbMetakatalog.dbo.tblMultiValue n on n.ID = o.ID ' +
  "WHERE n.AttributeName = 'Enhet' AND o.ID = m.ID AND m.StringValue like '" +
  username +
  "' and m.AttributeName = 'Owner' AND m.ID NOT LIKE '%" +
  username +
  "'"

  buddyQuery(query, function (err, data) {
    if (err) {
      console.log(query)
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUserGroups (request, reply) {
//  var loggedInUser = 'elimariannh'
  var username = request.params.username
  var query = 'SELECT ' +
  'o.SSN, m.ID, m.AttributeName, m.StringValue from dbMetakatalog.dbo.tblObjects o, dbMetakatalog.dbo.tblMultiValue m WHERE ' +
  "o.ID = m.StringValue AND m.AttributeName in ('Owner', 'Member') AND o.Mail LIKE '%t-fk.no' " +
//  "AND o.GroupType != 'Kontakgruppe' " +
//  "AND o.GroupType != 'Managergruppe' " +
  "AND m.StringValue = '" +
  username +
  "'"

  buddyQuery(query, function (err, data) {
    if (err) {
      console.log(query)
      reply(err)
    } else {
      console.log(query)
      reply(data)
    }
  })
}

/*!
 *
 * Units
 *
 */

function getUnits (request, reply) {
  var query = 'SELECT ' +
    'o.id as name,m.id,m.org,m.beskrivelse,o.ObjectType,o.DisplayName,o.Status,o.PostalAddress,o.Street,o.PostalCode,o.City,o.OrganizationNumber ' +
    "FROM dbMetakatalog.dbo.tblKonverterIDer m, dbMetakatalog.dbo.tblObjects o where m.konverterTil = o.ID AND o.ObjectType = 'Enhet' AND m.org = 'TFK'"
  buddyQuery(query, function (err, data) {
    if (err) {
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUnit (request, reply) {
  var unitId = request.params.unitId
  var query = 'SELECT ' +
    'o.id as name,m.id,m.org,m.beskrivelse,o.ObjectType,o.DisplayName,o.Status,o.PostalAddress,o.Street,o.PostalCode,o.City,o.OrganizationNumber ' +
    "FROM dbMetakatalog.dbo.tblKonverterIDer m, dbMetakatalog.dbo.tblObjects o where m.konverterTil = o.ID AND o.ObjectType = 'Enhet' AND m.org = 'TFK' and m.id = '" +
    unitId +
    "'"

  buddyQuery(query, function (err, data) {
    if (err) {
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUnitGroups (request, reply) {
  var unitId = request.params.unitId
  var query = 'SELECT mv.ID as groupName, mv.AttributeName as groupType, mv.StringValue as unitName, ki.id as unitId ' +
   'FROM dbMetakatalog.dbo.tblMultiValue mv, dbMetakatalog.dbo.tblKonverterIDer ki ' +
   'WHERE mv.StringValue = ki.konverterTil ' +
   "AND ki.id = '" +
   unitId +
   "' " +
   "AND mv.ID LIKE mv.StringValue  + '%'" +
   'ORDER BY mv.ID ASC'

  buddyQuery(query, function (err, data) {
    if (err) {
      reply(err)
    } else {
      reply(data)
    }
  })
}

/*!
 *
 * Groups
 *
 */

function getGroup (request, reply) {
  var groupId = request.params.groupId
  var query = 'SELECT mv.ID, mv.AttributeName as groupType, mv.StringValue as unitId, ' +
    'o.ObjectType as objectType, o.GroupType as groupTypeDesc, o.Description as description ' +
    'FROM dbMetakatalog.dbo.tblMultiValue mv, dbMetakatalog.dbo.tblObjects o ' +
    'WHERE mv.ID = o.ID ' +
    "AND AttributeName = 'Enhet' " +
    "AND mv.ID = '" +
    groupId +
    "'"
  buddyQuery(query, function (err, data) {
    if (err) {
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getGroupMembers (request, reply) {
  var groupId = request.params.groupId
  var query = 'SELECT mv.ID as groupId, mv.AttributeName as memberType, mv.StringValue as username, ' +
    'o.Firstname as firstName, o.Midlename as middleName, o.Lastname as lastName, o.SSN as ssn ' +
    'FROM dbMetakatalog.dbo.tblMultiValue mv, dbMetakatalog.dbo.tblObjects o ' +
    'WHERE mv.StringValue = o.ID ' +
    "AND mv.AttributeName = 'Member'" +
    "AND mv.ID = '" +
    groupId +
    "'"
  buddyQuery(query, function (err, data) {
    if (err) {
      console.log(err)
      reply(err)
    } else {
      reply(data)
    }
  })
}

/*!
 *
 * Organizations
 *
 */

function getOrganizations (request, reply) {
  var query = 'SELECT * ' +
    "FROM dbMetakatalog.dbo.tblObjects where ObjectType = 'Organisasjon'"

  if (request.params.id) {
    query = 'SELECT * ' +
      "FROM dbMetakatalog.dbo.tblObjects WHERE ObjectType = 'Organisasjon' AND id = '" + Number(request.params.id) + "'"
  }
  buddyQuery(query, function (err, data) {
    if (err) {
      reply(err)
    } else {
      reply(data)
    }
  })
}

function schools (request, reply) {
  var query = 'SELECT ' +
   'o.id as name,m.id,m.org,m.beskrivelse,o.ObjectType,o.DisplayName,o.Status,o.PostalAddress,o.Street,o.PostalCode,o.City,o.OrganizationNumber ' +
   "FROM dbMetakatalog.dbo.tblKonverterIDer m, dbMetakatalog.dbo.tblObjects o where m.konverterTil = o.ID AND o.ObjectType = 'Enhet' " +
   // Filter
   "AND m.org = 'TFK' AND o.OrganizationNumber LIKE 'NO974568%'"

  buddyQuery(query, function (err, data) {
    if (err) {
      reply(err)
    } else {
      reply(data)
    }
  })
}

module.exports.getUser = getUser

module.exports.getUserGroups = getUserGroups

module.exports.getUserGroupsOwner = getUserGroupsOwner

module.exports.getUserName = getUserName

module.exports.getUserMail = getUserMail

module.exports.getOrganizations = getOrganizations

module.exports.getUnits = getUnits

module.exports.getUnit = getUnit

module.exports.getUnitGroups = getUnitGroups

module.exports.getGroup = getGroup

module.exports.getGroupMembers = getGroupMembers

module.exports.schools = schools

module.exports.getPublicResponse = getPublicResponse
<commit_msg>Refactors handlers<commit_after>'use strict'

var buddyQuery = require('../lib/buddyQuery')

/*!
 *
 * Public
 *
 */

function getPublicResponse (request, reply) {
  var message = {
    message: "Hello, I'm your API"
  }
  reply(message)
}

/*!
 *
 * User
 *
 */

function getUser (request, reply) {
  var username = request.params.username
  var query = "SELECT * FROM dbMetakatalog.dbo.tblObjects WHERE ID = '" + username + "'"

  buddyQuery(query, function (err, data) {
    if (err) {
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUserName (request, reply) {
  var username = request.params.username
  var query = 'SELECT Firstname as firstName, Midlename as middleName, Lastname as lastName ' +
    'FROM dbMetakatalog.dbo.tblObjects ' +
    "WHERE ID = '" +
    username +
    "'"
  buddyQuery(query, function (err, data) {
    if (err) {
      console.log(query)
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUserMail (request, reply) {
  var username = request.params.username
  var query = 'SELECT Mail as email ' +
    'FROM dbMetakatalog.dbo.tblObjects ' +
    "WHERE ID = '" +
    username +
    "'"
  buddyQuery(query, function (err, data) {
    if (err) {
      console.log(query)
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUserGroupsOwner (request, reply) {
  var username = request.params.username
  var query = 'SELECT ' +
  'm.AttributeName as Role,m.ID as GroupID,m.StringValue as Username,o.ObjectType,o.GroupType,o.Description,n.StringValue as Unit ' +
  'FROM dbMetakatalog.dbo.tblMultiValue m, dbMetakatalog.dbo.tblObjects o ' +
  'inner join dbMetakatalog.dbo.tblMultiValue n on n.ID = o.ID ' +
  "WHERE n.AttributeName = 'Enhet' AND o.ID = m.ID AND m.StringValue like '" +
  username +
  "' and m.AttributeName = 'Owner' AND m.ID NOT LIKE '%" +
  username +
  "'"

  buddyQuery(query, function (err, data) {
    if (err) {
      console.log(query)
      reply(err)
    } else {
      reply(data)
    }
  })
}

function getUserGroups (request, reply) {
//  var loggedInUser = 'elimariannh'
  var username = request.params.username
  var query = 'SELECT ' +
  'o.SSN, m.ID, m.AttributeName, m.StringValue from dbMetakatalog.dbo.tblObjects o, dbMetakatalog.dbo.tblMultiValue m WHERE ' +
  "o.ID = m.StringValue AND m.AttributeName in ('Owner', 'Member') AND o.Mail LIKE '%t-fk.no' " +
//  "AND o.GroupType != 'Kontakgruppe' " +
//  "AND o.GroupType != 'Managergruppe' " +
  "AND m.StringValue = '" +
  username +
  "'"

  buddyQuery(query, function (error, data) {
    console.log(query)
    reply(error || data)
  })
}

/*!
 *
 * Units
 *
 */

function getUnits (request, reply) {
  var query = 'SELECT ' +
    'o.id as name,m.id,m.org,m.beskrivelse,o.ObjectType,o.DisplayName,o.Status,o.PostalAddress,o.Street,o.PostalCode,o.City,o.OrganizationNumber ' +
    "FROM dbMetakatalog.dbo.tblKonverterIDer m, dbMetakatalog.dbo.tblObjects o where m.konverterTil = o.ID AND o.ObjectType = 'Enhet' AND m.org = 'TFK'"
  buddyQuery(query, function (error, data) {
    reply(error || data)
  })
}

function getUnit (request, reply) {
  var unitId = request.params.unitId
  var query = 'SELECT ' +
    'o.id as name,m.id,m.org,m.beskrivelse,o.ObjectType,o.DisplayName,o.Status,o.PostalAddress,o.Street,o.PostalCode,o.City,o.OrganizationNumber ' +
    "FROM dbMetakatalog.dbo.tblKonverterIDer m, dbMetakatalog.dbo.tblObjects o where m.konverterTil = o.ID AND o.ObjectType = 'Enhet' AND m.org = 'TFK' and m.id = '" +
    unitId +
    "'"

  buddyQuery(query, function (error, data) {
    reply(error || data)
  })
}

function getUnitGroups (request, reply) {
  var unitId = request.params.unitId
  var query = 'SELECT mv.ID as groupName, mv.AttributeName as groupType, mv.StringValue as unitName, ki.id as unitId ' +
   'FROM dbMetakatalog.dbo.tblMultiValue mv, dbMetakatalog.dbo.tblKonverterIDer ki ' +
   'WHERE mv.StringValue = ki.konverterTil ' +
   "AND ki.id = '" +
   unitId +
   "' " +
   "AND mv.ID LIKE mv.StringValue  + '%'" +
   'ORDER BY mv.ID ASC'

  buddyQuery(query, function (error, data) {
    reply(error || data)
  })
}

/*!
 *
 * Groups
 *
 */

function getGroup (request, reply) {
  var groupId = request.params.groupId
  var query = 'SELECT mv.ID, mv.AttributeName as groupType, mv.StringValue as unitId, ' +
    'o.ObjectType as objectType, o.GroupType as groupTypeDesc, o.Description as description ' +
    'FROM dbMetakatalog.dbo.tblMultiValue mv, dbMetakatalog.dbo.tblObjects o ' +
    'WHERE mv.ID = o.ID ' +
    "AND AttributeName = 'Enhet' " +
    "AND mv.ID = '" +
    groupId +
    "'"
  buddyQuery(query, function (error, data) {
    reply(error || data)
  })
}

function getGroupMembers (request, reply) {
  var groupId = request.params.groupId
  var query = 'SELECT mv.ID as groupId, mv.AttributeName as memberType, mv.StringValue as username, ' +
    'o.Firstname as firstName, o.Midlename as middleName, o.Lastname as lastName, o.SSN as ssn ' +
    'FROM dbMetakatalog.dbo.tblMultiValue mv, dbMetakatalog.dbo.tblObjects o ' +
    'WHERE mv.StringValue = o.ID ' +
    "AND mv.AttributeName = 'Member'" +
    "AND mv.ID = '" +
    groupId +
    "'"
  buddyQuery(query, function (error, data) {
    reply(error || data)
  })
}

/*!
 *
 * Organizations
 *
 */

function getOrganizations (request, reply) {
  var query = 'SELECT * ' +
    "FROM dbMetakatalog.dbo.tblObjects where ObjectType = 'Organisasjon'"

  if (request.params.id) {
    query = 'SELECT * ' +
      "FROM dbMetakatalog.dbo.tblObjects WHERE ObjectType = 'Organisasjon' AND id = '" + Number(request.params.id) + "'"
  }
  buddyQuery(query, function (error, data) {
    reply(error || data)
  })
}

function schools (request, reply) {
  var query = 'SELECT ' +
   'o.id as name,m.id,m.org,m.beskrivelse,o.ObjectType,o.DisplayName,o.Status,o.PostalAddress,o.Street,o.PostalCode,o.City,o.OrganizationNumber ' +
   "FROM dbMetakatalog.dbo.tblKonverterIDer m, dbMetakatalog.dbo.tblObjects o where m.konverterTil = o.ID AND o.ObjectType = 'Enhet' " +
   // Filter
   "AND m.org = 'TFK' AND o.OrganizationNumber LIKE 'NO974568%'"

  buddyQuery(query, function (error, data) {
    reply(error || data)
  })
}

module.exports.getUser = getUser

module.exports.getUserGroups = getUserGroups

module.exports.getUserGroupsOwner = getUserGroupsOwner

module.exports.getUserName = getUserName

module.exports.getUserMail = getUserMail

module.exports.getOrganizations = getOrganizations

module.exports.getUnits = getUnits

module.exports.getUnit = getUnit

module.exports.getUnitGroups = getUnitGroups

module.exports.getGroup = getGroup

module.exports.getGroupMembers = getGroupMembers

module.exports.schools = schools

module.exports.getPublicResponse = getPublicResponse
<|endoftext|>


<commit_before>var spawn = require('child_process').spawn,
    http = require('http'),
    urlmod = require('url'),
    fs = require('fs');
var logLevel = 0;
var vidProc,
    player,
    vidProcLog = '',
    files = [],
    currFile = 0,
    playing = false;
var localAddress = '',
    remoteAddress = '',
    port = 3000,
    req,
    res;

// INIT ////////////////////////////////////

// standardized exit function
var exitFunction = function (code) {
    console.log('exiting vidcomm');
    if (code) console.log('exited with code '+code);
    if (vidProcLog.length) console.log(vidProcLog);
    // show cursor
    console.log('\033[?12l\033[?25h');
}

var echo = function (msg) {
    if (logLevel) console.log(msg);
}

// HTTP SERVER /////////////////////////////

// find local ip address
var findLocalAddress = function () {
    echo('find local address');
    require('child_process').exec('ifconfig eth0 | grep \'inet addr:\' | cut -d: -f2 | awk \'{ print $1}\'', function (error, stdout, stderr) {
        if (stdout.search(/192\.168\.1\.\d+/) !== -1) {
            localAddress = stdout;
            echo(localAddress);
            startServer();
        } else {
            echo('couldn\'t find local ip address. letting server down.');
            playNextVideo();
        }
    });
}

// start local http server
var startServer = function () {
    echo('start server');
    http.createServer(function (req_, res_) {
        req = req_;
        res = res_;
        if (req.method === 'GET') {
            req.on('close', function() { echo('error: connection closed'); });
            req.on('data', function(data) { /* void */ });
            req.on('end', function() { parseRequest(); });
        } else {
            echo('error: no accepted HTTP method');
            respond('no');
        }
    }).listen(port, localAddress);
    echo('server running at http://'+localAddress+':'+port);
    // query remote server for status
    queryRemote('playing');
}

// parse incoming http requests
var parseRequest = function () {
    echo('parse request');
    var url = urlmod.parse(req.url);
    if (url.href) {
        var cmd = url.href.slice(1);
        echo(cmd);
        if (cmd === 'playing') respond(isPlaying());
        else if (cmd === 'ended') playNextVideo();
        else respond('bad command');
    } else {
        echo('bad url '+url);
        respond('error: bad url');
    }
}

// respond to remote http requests
var respond = function (data) {
    echo('respond '+ data);
    var headers = {
        'Content-Length': Buffer.byteLength(data),
        'Content-Type': 'text/plain; charset=utf-8',
        'Expires': (new Date(Date.now)).toUTCString()
    }
    res.writeHead(200, headers);
    res.end(data);
}

// REMOTE QUERIES //////////////////////////

// query remote server
var queryRemote = function (query) {
    echo('query remote '+ query);
    var url = 'http://'+remoteAddress+':'+port+'/'+query;
    http.get(url, function(res_) {
        res_.on('data', function (data) { parseServerResponse(data) });
    }).on('error', function(e) {
        echo("got error: " + e.message);
    });
}

// parse remote server's response to query
var parseServerResponse = function (data) {
    echo('parse server response '+ data);
    if (data == 'no') {
        // remote is not playing, play local file
        echo('remote is not playing, play local file');
        playNextVideo();
    } else {
        echo('remote is playing, wait for remote message, so, do nothing');
        // wait for remote message, so, do nothing
    }
}

// VIDEO ///////////////////////////////////

// establish video playing status
var isPlaying = function () {
    if (playing) return 'yes';
    else return 'no';
}

// play video files
var playNextVideo = function () {
    // next file to play
    var filename = files[currFile++];
    // if it doesn't exist, reset filename to the first one
    if (!filename) filename = files[0];
    // play only if the file exists
    if (!filename) {
        console.log('vidcomm playback ended');
        exitFunction();
        process.exit(0);
    } else {
        playing = true;
        echo('play video '+filename);
        vidProc = (player === 'omxplayer') ? spawn('omxplayer', ['-o', 'local', filename]) : spawn('mplayer', ['-vm', filename]);
        vidProc.stdout.on('data', function (data) { vidProcLog += data; });
        vidProc.stderr.on('data', function (data) { vidProcLog += data; });
        vidProc.on('exit', function (code) {
            playing = false;
            echo(player+' exited with code '+code);
            queryRemote('ended');
        });
    }
}

// PROCESS /////////////////////////////////

// parse process' incoming arguments
var parseArgv = function () {
    echo('parse argv');
    var conf;
    files = [];

    // parse arguments
    if (process.argv.length < 3) {
        // no arguments case
        conf = 'vidcomm.conf';
    } else {
        process.argv.forEach(function (val, idx, arr) {
            if (val.search(/^\.*[^\.]+\.conf$/) !== -1) {
                // configuration file case
                conf = val;
                // readConf();
            } else if (val.search(/^\.*[^\.]+\.(mp4|m4v|mov)$/) !== -1) {
                // video filename case
                files.push(val);
            } else if (val.search(/192\.168\.1\.\d+/) !== -1) {
                // remote address case
                remoteAddress = val;
            }
        });
    }

    // if a configuration file was given
    if (conf) {
        var data = fs.readFileSync(conf, {encoding:'utf-8'});
        if (data.length) {
            data.split('\n').forEach(function (val, idx, arr) {
                if (val.search(/^\.*[^\.]+\.(mp4|m4v|mov)$/) !== -1) {
                    // video filename case
                    files.push(val);
                } else if (val.search(/192\.168\.1\.\d+/) !== -1) {
                    // remote address case
                    remoteAddress = val;
                }
            });
        }
    }

    // if video files were given
    if (files.length) {
        // clear terminal, move cursor to top left and hide it
        // console.log('\033[2J\033\033[H\033[?25l');

        // if a remote server address was given
        if (remoteAddress.length) {
            findLocalAddress();
        } else {
            playNextVideo();
        }
    }

    // failsafe
    if (!conf && !files.length) {
        exitFunction();
        process.exit(1);
    }
}

// check whether other vidcomm process is running on the system
var checkForDuplicates = function () {
    echo('check for duplicates');
    require('child_process').exec('ps aux | grep '+player+' | grep -v grep', function (error, stdout, stderr) {
        if (stdout.length) {
            console.log('a video player is already running on this machine.');
            console.log(stdout);
            exitFunction();
            process.exit(1);
        } else {
            echo('vidcomm starting.');
            parseArgv();
        }
    });
}

// handle ctrl-C gracefully
process.on('SIGINT', function () {
    console.log(' ');
    exitFunction();
    process.exit(1);
});

// START ///////////////////////////////////

// check which player is available on the system
require('child_process').exec('which omxplayer', function (error, stdout, stderr) {
    if (stdout[0] !== '/') {
        require('child_process').exec('which mplayer', function (error, stdout, stderr) {
            if (stdout[0] !== '/') {
                console.log('no video player available.');
                exitFunction();
                process.exit(1);
            } else {
                player = 'mplayer';
                echo('player is '+player);
                checkForDuplicates();
            }
        });
    } else {
        player = 'omxplayer';
        echo('player is '+player);
        checkForDuplicates();
    }
});<commit_msg>turned logging on<commit_after>var spawn = require('child_process').spawn,
    http = require('http'),
    urlmod = require('url'),
    fs = require('fs');
var logLevel = 1;
var vidProc,
    player,
    vidProcLog = '',
    files = [],
    currFile = 0,
    playing = false;
var localAddress = '',
    remoteAddress = '',
    port = 3000,
    req,
    res;

// INIT ////////////////////////////////////

// standardized exit function
var exitFunction = function (code) {
    console.log('exiting vidcomm');
    if (code) console.log('exited with code '+code);
    if (vidProcLog.length) console.log(vidProcLog);
    // show cursor
    console.log('\033[?12l\033[?25h');
}

var echo = function (msg) {
    if (logLevel) console.log(msg);
}

// HTTP SERVER /////////////////////////////

// find local ip address
var findLocalAddress = function () {
    echo('find local address');
    require('child_process').exec('ifconfig eth0 | grep \'inet addr:\' | cut -d: -f2 | awk \'{ print $1}\'', function (error, stdout, stderr) {
        if (stdout.search(/192\.168\.1\.\d+/) !== -1) {
            localAddress = stdout;
            echo(localAddress);
            startServer();
        } else {
            echo('couldn\'t find local ip address. letting server down.');
            playNextVideo();
        }
    });
}

// start local http server
var startServer = function () {
    echo('start server');
    http.createServer(function (req_, res_) {
        req = req_;
        res = res_;
        if (req.method === 'GET') {
            req.on('close', function() { echo('error: connection closed'); });
            req.on('data', function(data) { /* void */ });
            req.on('end', function() { parseRequest(); });
        } else {
            echo('error: no accepted HTTP method');
            respond('no');
        }
    }).listen(port, localAddress);
    echo('server running at http://'+localAddress+':'+port);
    // query remote server for status
    queryRemote('playing');
}

// parse incoming http requests
var parseRequest = function () {
    echo('parse request');
    var url = urlmod.parse(req.url);
    if (url.href) {
        var cmd = url.href.slice(1);
        echo(cmd);
        if (cmd === 'playing') respond(isPlaying());
        else if (cmd === 'ended') playNextVideo();
        else respond('bad command');
    } else {
        echo('bad url '+url);
        respond('error: bad url');
    }
}

// respond to remote http requests
var respond = function (data) {
    echo('respond '+ data);
    var headers = {
        'Content-Length': Buffer.byteLength(data),
        'Content-Type': 'text/plain; charset=utf-8',
        'Expires': (new Date(Date.now)).toUTCString()
    }
    res.writeHead(200, headers);
    res.end(data);
}

// REMOTE QUERIES //////////////////////////

// query remote server
var queryRemote = function (query) {
    echo('query remote '+ query);
    var url = 'http://'+remoteAddress+':'+port+'/'+query;
    http.get(url, function(res_) {
        res_.on('data', function (data) { parseServerResponse(data) });
    }).on('error', function(e) {
        echo("got error: " + e.message);
    });
}

// parse remote server's response to query
var parseServerResponse = function (data) {
    echo('parse server response '+ data);
    if (data == 'no') {
        // remote is not playing, play local file
        echo('remote is not playing, play local file');
        playNextVideo();
    } else {
        echo('remote is playing, wait for remote message, so, do nothing');
        // wait for remote message, so, do nothing
    }
}

// VIDEO ///////////////////////////////////

// establish video playing status
var isPlaying = function () {
    if (playing) return 'yes';
    else return 'no';
}

// play video files
var playNextVideo = function () {
    // next file to play
    var filename = files[currFile++];
    // if it doesn't exist, reset filename to the first one
    if (!filename) filename = files[0];
    // play only if the file exists
    if (!filename) {
        console.log('vidcomm playback ended');
        exitFunction();
        process.exit(0);
    } else {
        playing = true;
        echo('play video '+filename);
        vidProc = (player === 'omxplayer') ? spawn('omxplayer', ['-o', 'local', filename]) : spawn('mplayer', ['-vm', filename]);
        vidProc.stdout.on('data', function (data) { vidProcLog += data; });
        vidProc.stderr.on('data', function (data) { vidProcLog += data; });
        vidProc.on('exit', function (code) {
            playing = false;
            echo(player+' exited with code '+code);
            queryRemote('ended');
        });
    }
}

// PROCESS /////////////////////////////////

// parse process' incoming arguments
var parseArgv = function () {
    echo('parse argv');
    var conf;
    files = [];

    // parse arguments
    if (process.argv.length < 3) {
        // no arguments case
        conf = 'vidcomm.conf';
    } else {
        process.argv.forEach(function (val, idx, arr) {
            if (val.search(/^\.*[^\.]+\.conf$/) !== -1) {
                // configuration file case
                conf = val;
                // readConf();
            } else if (val.search(/^\.*[^\.]+\.(mp4|m4v|mov)$/) !== -1) {
                // video filename case
                files.push(val);
            } else if (val.search(/192\.168\.1\.\d+/) !== -1) {
                // remote address case
                remoteAddress = val;
            }
        });
    }

    // if a configuration file was given
    if (conf) {
        var data = fs.readFileSync(conf, {encoding:'utf-8'});
        if (data.length) {
            data.split('\n').forEach(function (val, idx, arr) {
                if (val.search(/^\.*[^\.]+\.(mp4|m4v|mov)$/) !== -1) {
                    // video filename case
                    files.push(val);
                } else if (val.search(/192\.168\.1\.\d+/) !== -1) {
                    // remote address case
                    remoteAddress = val;
                }
            });
        }
    }

    // if video files were given
    if (files.length) {
        // clear terminal, move cursor to top left and hide it
        // console.log('\033[2J\033\033[H\033[?25l');

        // if a remote server address was given
        if (remoteAddress.length) {
            findLocalAddress();
        } else {
            playNextVideo();
        }
    }

    // failsafe
    if (!conf && !files.length) {
        exitFunction();
        process.exit(1);
    }
}

// check whether other vidcomm process is running on the system
var checkForDuplicates = function () {
    echo('check for duplicates');
    require('child_process').exec('ps aux | grep '+player+' | grep -v grep', function (error, stdout, stderr) {
        if (stdout.length) {
            console.log('a video player is already running on this machine.');
            console.log(stdout);
            exitFunction();
            process.exit(1);
        } else {
            echo('vidcomm starting.');
            parseArgv();
        }
    });
}

// handle ctrl-C gracefully
process.on('SIGINT', function () {
    console.log(' ');
    exitFunction();
    process.exit(1);
});

// START ///////////////////////////////////

// check which player is available on the system
require('child_process').exec('which omxplayer', function (error, stdout, stderr) {
    if (stdout[0] !== '/') {
        require('child_process').exec('which mplayer', function (error, stdout, stderr) {
            if (stdout[0] !== '/') {
                console.log('no video player available.');
                exitFunction();
                process.exit(1);
            } else {
                player = 'mplayer';
                echo('player is '+player);
                checkForDuplicates();
            }
        });
    } else {
        player = 'omxplayer';
        echo('player is '+player);
        checkForDuplicates();
    }
});<|endoftext|>


<commit_before>/* jshint -W097 */// jshint strict:false
/*jslint node: true */
var expect = require('chai').expect;
var setup  = require(__dirname + '/lib/setup');

var objects = null;
var states  = null;
var onStateChanged = null;
var onObjectChanged = null;
var sendToID = 1;

var adapterShortName = setup.adapterName.substring(setup.adapterName.indexOf('.')+1);

function checkConnectionOfAdapter(cb, counter) {
    counter = counter || 0;
    console.log('Try check #' + counter);
    if (counter > 30) {
        if (cb) cb('Cannot check connection');
        return;
    }

    states.getState('system.adapter.' + adapterShortName + '.0.alive', function (err, state) {
        if (err) console.error(err);
        if (state && state.val) {
            if (cb) cb();
        } else {
            setTimeout(function () {
                checkConnectionOfAdapter(cb, counter + 1);
            }, 1000);
        }
    });
}

function checkValueOfState(id, value, cb, counter) {
    counter = counter || 0;
    if (counter > 20) {
        if (cb) cb('Cannot check value Of State ' + id);
        return;
    }

    states.getState(id, function (err, state) {
        if (err) console.error(err);
        if (value === null && !state) {
            if (cb) cb();
        } else
        if (state && (value === undefined || state.val === value)) {
            if (cb) cb();
        } else {
            setTimeout(function () {
                checkValueOfState(id, value, cb, counter + 1);
            }, 500);
        }
    });
}

function sendTo(target, command, message, callback) {
    onStateChanged = function (id, state) {
        if (id === 'messagebox.system.adapter.test.0') {
            callback(state.message);
        }
    };

    states.pushMessage('system.adapter.' + target, {
        command:    command,
        message:    message,
        from:       'system.adapter.test.0',
        callback: {
            message: message,
            id:      sendToID++,
            ack:     false,
            time:    (new Date()).getTime()
        }
    });
}

describe('Test ' + adapterShortName + ' adapter', function() {
    before('Test ' + adapterShortName + ' adapter: Start js-controller', function (_done) {
        this.timeout(600000); // because of first install from npm

        setup.setupController(function () {
            var config = setup.getAdapterConfig();
            // enable adapter
            config.common.enabled  = true;
            config.common.loglevel = 'debug';

            //config.native.serialport = '/dev/ttyS';

            setup.setAdapterConfig(config.common, config.native);

            setup.startController(true, function(id, obj) {}, function (id, state) {
                    if (onStateChanged) onStateChanged(id, state);
                },
                function (_objects, _states) {
                    objects = _objects;
                    states  = _states;
                    _done();
                });
        });
    });

/*
    ENABLE THIS WHEN ADAPTER RUNS IN DEAMON MODE TO CHECK THAT IT HAS STARTED SUCCESSFULLY
*/
    it('Test ' + adapterShortName + ' adapter: Check if adapter started', function (done) {
        this.timeout(60000);
        checkConnectionOfAdapter(function (res) {
            if (res) console.log(res);
            expect(res).not.to.be.equal('Cannot check connection');
            objects.setObject('system.adapter.test.0', {
                    common: {

                    },
                    type: 'instance'
                },
                function () {
                    states.subscribeMessage('system.adapter.test.0');
                    done();
                });
        });
    });
/**/

/*
    PUT YOUR OWN TESTS HERE USING
    it('Testname', function ( done) {
        ...
    });

    You can also use "sendTo" method to send messages to the started adapter
*/

    after('Test ' + adapterShortName + ' adapter: Stop js-controller', function (done) {
        this.timeout(10000);

        setup.stopController(function (normalTerminated) {
            console.log('Adapter normal terminated: ' + normalTerminated);
            done();
        });
    });
});
<commit_msg>Update testAdapter.js<commit_after>/* jshint -W097 */// jshint strict:false
/*jslint node: true */
var expect = require('chai').expect;
var setup  = require(__dirname + '/lib/setup');

var objects = null;
var states  = null;
var onStateChanged = null;
var onObjectChanged = null;
var sendToID = 1;

var adapterShortName = setup.adapterName.substring(setup.adapterName.indexOf('.')+1);

function checkConnectionOfAdapter(cb, counter) {
    counter = counter || 0;
    console.log('Try check #' + counter);
    if (counter > 30) {
        if (cb) cb('Cannot check connection');
        return;
    }

    states.getState('system.adapter.' + adapterShortName + '.0.alive', function (err, state) {
        if (err) console.error(err);
        if (state && state.val) {
            if (cb) cb();
        } else {
            setTimeout(function () {
                checkConnectionOfAdapter(cb, counter + 1);
            }, 1000);
        }
    });
}

function checkValueOfState(id, value, cb, counter) {
    counter = counter || 0;
    if (counter > 20) {
        if (cb) cb('Cannot check value Of State ' + id);
        return;
    }

    states.getState(id, function (err, state) {
        if (err) console.error(err);
        if (value === null && !state) {
            if (cb) cb();
        } else
        if (state && (value === undefined || state.val === value)) {
            if (cb) cb();
        } else {
            setTimeout(function () {
                checkValueOfState(id, value, cb, counter + 1);
            }, 500);
        }
    });
}

function sendTo(target, command, message, callback) {
    onStateChanged = function (id, state) {
        if (id === 'messagebox.system.adapter.test.0') {
            callback(state.message);
        }
    };

    states.pushMessage('system.adapter.' + target, {
        command:    command,
        message:    message,
        from:       'system.adapter.test.0',
        callback: {
            message: message,
            id:      sendToID++,
            ack:     false,
            time:    (new Date()).getTime()
        }
    });
}

describe('Test ' + adapterShortName + ' adapter', function() {
    before('Test ' + adapterShortName + ' adapter: Start js-controller', function (_done) {
        this.timeout(600000); // because of first install from npm

        setup.setupController(function () {
            var config = setup.getAdapterConfig();
            // enable adapter
            config.common.enabled  = true;
            config.common.loglevel = 'debug';

            //config.native.serialport = '/dev/ttyS';

            config.native.sensors = [
                {
                    "sid": "18",
                    "usid": "1",
                    "stype": "emonTH",
                    "name": "example emonTH"
                },
                {
                    "sid": "0",
                    "usid": "2",
                    "stype": "LaCrosseBMP180",
                    "name": "example superjee"
                },
                {
                    "sid": "56",
                    "usid": "3",
                    "stype": "LaCrosseDTH",
                    "name": "example LaCrosseDTH"
                },
                {
                    "sid": "22",
                    "usid": "4",
                    "stype": "LaCrosseDTH",
                    "name": "example LaCrosseDTH"
                },
                {
                    "sid": "60",
                    "usid": "5",
                    "stype": "LaCrosseWS",
                    "name": "example LaCrosseWS"
                },
                {
                    "sid": "188",
                    "usid": "6",
                    "stype": "EC3000",
                    "name": "example EC3000"
                },
                {
                    "sid": "5451",
                    "usid": "7",
                    "stype": "EMT7110",
                    "name": "example EMT7110"
                },
                {
                    "sid": "1",
                    "usid": "8",
                    "stype": "level",
                    "name": "example level"
                }
    ];

            setup.setAdapterConfig(config.common, config.native);

            setup.startController(true, function(id, obj) {}, function (id, state) {
                    if (onStateChanged) onStateChanged(id, state);
                },
                function (_objects, _states) {
                    objects = _objects;
                    states  = _states;
                    _done();
                });
        });
    });

/*
    ENABLE THIS WHEN ADAPTER RUNS IN DEAMON MODE TO CHECK THAT IT HAS STARTED SUCCESSFULLY
*/
    it('Test ' + adapterShortName + ' adapter: Check if adapter started', function (done) {
        this.timeout(60000);
        checkConnectionOfAdapter(function (res) {
            if (res) console.log(res);
            expect(res).not.to.be.equal('Cannot check connection');
            objects.setObject('system.adapter.test.0', {
                    common: {

                    },
                    type: 'instance'
                },
                function () {
                    states.subscribeMessage('system.adapter.test.0');
                    done();
                });
        });
    });
/**/

/*
    PUT YOUR OWN TESTS HERE USING
    it('Testname', function ( done) {
        ...
    });

    You can also use "sendTo" method to send messages to the started adapter
*/
   it('Test ' + adapterShortName + ' adapter: Check existence of LaCrosseDTH', function (done) {
        this.timeout(30000);
        setTimeout(function () {
            states.getState('jeelink.0.LaCrosse_4.temp', function (err, state) {
                if (err) console.error(err);
                expect(state).to.exist;
                if (!state) {
                    console.error('state "jeelink.0.LaCrosse_4.temp" not set');
                }
                else {
                    console.log('jeelink.0.LaCrosse_4.temp          ... ' + state.val);
                    expect(state.val).to.exist;
                    //expect(state.val).to.be.equal(17.5);
                    done();
                }
            });
        }, 1000);
    });
    it('Test ' + adapterShortName + ' adapter: Check existence of LaCrosseDMP180', function (done) {
        this.timeout(30000);
        setTimeout(function () {
            states.getState('jeelink.0.LaCrosse_2.temp', function (err, state) {
                if (err) console.error(err);
                expect(state).to.exist;
                if (!state) {
                    console.error('state "jeelink.0.LaCrosse_2.temp" not set');
                }
                else {
                    console.log('jeelink.0.LaCrosse_2.temp          ... ' + state.val);
                    expect(state.val).to.exist;
                    //expect(state.val).to.be.equal(17.5);
                    done();
                }
            });
        }, 1000);
    });

    after('Test ' + adapterShortName + ' adapter: Stop js-controller', function (done) {
        this.timeout(10000);

        setup.stopController(function (normalTerminated) {
            console.log('Adapter normal terminated: ' + normalTerminated);
            done();
        });
    });
});
<|endoftext|>


<commit_before>var requestFrame = (function () {
  var window = this
  var raf = window.requestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    function fallbackRAF(func) {
      return window.setTimeout(func, 20)
    }
  return function requestFrameFunction(func) {
    return raf(func)
  }
})()

var cancelFrame = (function () {
  var window = this
  var cancel = window.cancelAnimationFrame ||
    window.mozCancelAnimationFrame ||
    window.webkitCancelAnimationFrame ||
    window.clearTimeout
  return function cancelFrameFunction(id) {
    return cancel(id)
  }
})()

function resizeListener(e) {
  var win = e.target || e.srcElement
  if (win.__resizeRAF__) {
    cancelFrame(win.__resizeRAF__)
  }
  win.__resizeRAF__ = requestFrame(function () {
    var trigger = win.__resizeTrigger__
    trigger.__resizeListeners__.forEach(function (fn) {
      fn.call(trigger, e)
    })
  })
}

var exports = function exports(element, fn) {
  var window = this
  var document = window.document
  var isIE

  var attachEvent = document.attachEvent
  if (typeof navigator !== 'undefined') {
    isIE = navigator.userAgent.match(/Trident/) ||
      navigator.userAgent.match(/Edge/)
  }

  function objectLoad() {
    this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__
    this.contentDocument.defaultView.addEventListener('resize', resizeListener)
  }

  if (!element.__resizeListeners__) {
    element.__resizeListeners__ = []
    if (attachEvent) {
      element.__resizeTrigger__ = element
      element.attachEvent('onresize', resizeListener)
    } else {
      if (getComputedStyle(element).position === 'static') {
        element.style.position = 'relative'
      }
      var obj = (element.__resizeTrigger__ = document.createElement('object'))
      obj.setAttribute(
        'style',
        'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1; opacity: 0;'
      )
      obj.setAttribute('class', 'resize-sensor')
      obj.__resizeElement__ = element
      obj.onload = objectLoad
      obj.type = 'text/html'
      if (isIE) {
        element.appendChild(obj)
      }
      obj.data = 'about:blank'
      if (!isIE) {
        element.appendChild(obj)
      }
    }
  }
  element.__resizeListeners__.push(fn)
}

module.exports = typeof window === 'undefined' ? exports : exports.bind(window)

module.exports.unbind = function (element, fn) {
  var attachEvent = document.attachEvent
  if (fn) {
    element.__resizeListeners__.splice(
      element.__resizeListeners__.indexOf(fn),
      1
    )
  } else {
    element.__resizeListeners__ = []
  }
  if (!element.__resizeListeners__.length) {
    if (attachEvent) {
      element.detachEvent('onresize', resizeListener)
    } else {
      element.__resizeTrigger__.contentDocument.defaultView.removeEventListener(
        'resize',
        resizeListener
      )
      delete element.__resizeTrigger__.contentDocument.defaultView.__resizeTrigger__
      element.__resizeTrigger__ = !element.removeChild(
        element.__resizeTrigger__
      )
    }
    delete element.__resizeListeners__
  }
}
<commit_msg>make sure that trigger exists before calling listeners on it<commit_after>var requestFrame = (function () {
  var window = this
  var raf = window.requestAnimationFrame ||
    window.mozRequestAnimationFrame ||
    window.webkitRequestAnimationFrame ||
    function fallbackRAF(func) {
      return window.setTimeout(func, 20)
    }
  return function requestFrameFunction(func) {
    return raf(func)
  }
})()

var cancelFrame = (function () {
  var window = this
  var cancel = window.cancelAnimationFrame ||
    window.mozCancelAnimationFrame ||
    window.webkitCancelAnimationFrame ||
    window.clearTimeout
  return function cancelFrameFunction(id) {
    return cancel(id)
  }
})()

function resizeListener(e) {
  var win = e.target || e.srcElement
  if (win.__resizeRAF__) {
    cancelFrame(win.__resizeRAF__)
  }
  win.__resizeRAF__ = requestFrame(function () {
    var trigger = win.__resizeTrigger__
    trigger && trigger.__resizeListeners__.forEach(function (fn) {
      fn.call(trigger, e)
    })
  })
}

var exports = function exports(element, fn) {
  var window = this
  var document = window.document
  var isIE

  var attachEvent = document.attachEvent
  if (typeof navigator !== 'undefined') {
    isIE = navigator.userAgent.match(/Trident/) ||
      navigator.userAgent.match(/Edge/)
  }

  function objectLoad() {
    this.contentDocument.defaultView.__resizeTrigger__ = this.__resizeElement__
    this.contentDocument.defaultView.addEventListener('resize', resizeListener)
  }

  if (!element.__resizeListeners__) {
    element.__resizeListeners__ = []
    if (attachEvent) {
      element.__resizeTrigger__ = element
      element.attachEvent('onresize', resizeListener)
    } else {
      if (getComputedStyle(element).position === 'static') {
        element.style.position = 'relative'
      }
      var obj = (element.__resizeTrigger__ = document.createElement('object'))
      obj.setAttribute(
        'style',
        'display: block; position: absolute; top: 0; left: 0; height: 100%; width: 100%; overflow: hidden; pointer-events: none; z-index: -1; opacity: 0;'
      )
      obj.setAttribute('class', 'resize-sensor')
      obj.__resizeElement__ = element
      obj.onload = objectLoad
      obj.type = 'text/html'
      if (isIE) {
        element.appendChild(obj)
      }
      obj.data = 'about:blank'
      if (!isIE) {
        element.appendChild(obj)
      }
    }
  }
  element.__resizeListeners__.push(fn)
}

module.exports = typeof window === 'undefined' ? exports : exports.bind(window)

module.exports.unbind = function (element, fn) {
  var attachEvent = document.attachEvent
  if (fn) {
    element.__resizeListeners__.splice(
      element.__resizeListeners__.indexOf(fn),
      1
    )
  } else {
    element.__resizeListeners__ = []
  }
  if (!element.__resizeListeners__.length) {
    if (attachEvent) {
      element.detachEvent('onresize', resizeListener)
    } else {
      element.__resizeTrigger__.contentDocument.defaultView.removeEventListener(
        'resize',
        resizeListener
      )
      delete element.__resizeTrigger__.contentDocument.defaultView.__resizeTrigger__
      element.__resizeTrigger__ = !element.removeChild(
        element.__resizeTrigger__
      )
    }
    delete element.__resizeListeners__
  }
}
<|endoftext|>


<commit_before>var EventEmitter = require("events").EventEmitter;
var exec = require('child_process').exec;
var async = require('async');

var power = new EventEmitter();

power.chargeLight = 'enabled';
power.gpsEnabled = 'enabled';
power.wifiEnabled = true;
power.autoOffMinutes = 10;
power.autoOffDisabled = false;

var powerControlBase = 0x17; // gps off, wifi off
var powerWifi = 0x40;
var powerGps = 0x8;

var powerDownTimerHandle = null;

function axpSet(reg, val, callback) {
    reg = parseInt(reg);
    val = parseInt(val);
    if(reg != null && val != null) {
        exec("i2cset -y -f 0 0x34 0x" + reg.toString(16) + " 0x" + val.toString(16), callback);
    } else {
        callback('invalid parameters');
    }
}

function axpGet(reg, callback) {
    reg = parseInt(reg);
    if(reg != null) {
        exec("i2cget -y -f 0 0x34 0x" + reg.toString(16), function(err, stdout) {
            if(!err && stdout) {
                callback && callback(null, parseInt(stdout.trim()));
            } else {
                callback(err);
            }
        });
    } else {
        callback('invalid parameters');
    }
}

power.init = function(disableLight) {
    axpSet(0x81, 0xf9); // fix issue with wifi power on
    axpSet(0x34, 0x57); // set chgled to blink
    axpSet(0x33, 0xdc); // set charge rate to 1.5A
    axpSet(0x30, 0x60); // set system current limit to 900mA
    axpSet(0x82, 0xff); // enable ADC for battery monitoring

    if(disableLight) {
        power.chargeLight = 'disabled';
        axpSet(0x32, 0x8); // disable chgled
    } else {
        power.chargeLight = 'enabled';
        axpSet(0x32, 0x0); // enable chgled
    }
}

function setPower(callback) {
    var setting = powerControlBase;
    if(power.gpsEnabled != 'disabled') setting |= powerGps;
    if(power.wifiEnabled) setting |= powerWifi;
    console.log("setting power control to 0x" + setting.toString(16));
    axpSet(0x12, setting, callback); // set power switches
}

var blinkIntervalHandle = null;
power.setButtons = function(mode) {
    if(!mode) mode = "disabled";
    power.buttonMode = mode;
    if(blinkIntervalHandle) {
        clearInterval(blinkIntervalHandle);
        blinkIntervalHandle = null;
    }
    if(mode == 'disabled') {
        power.buttonPowerLight(false);
        power.button1Light(false);
        power.button2Light(false);
        power.button3Light(false);
    } else if(mode == 'power') {
        power.buttonPowerLight(true);
        power.button1Light(false);
        power.button2Light(false);
        power.button3Light(false);

    } else if(mode == 'all') {
        power.buttonPowerLight(true);
        power.button1Light(true);
        power.button2Light(true);
        power.button3Light(true);
    } else if(mode == 'blink') {
        power.buttonPowerBlink();
        power.button1Light(false);
        power.button2Light(false);
        power.button3Light(false);
        blinkIntervalHandle = setInterval(power.buttonPowerBlink, 5000);
    }
}

power.setAutoOff = function(minutes) {
    if(powerDownTimerHandle) clearTimeout(powerDownTimerHandle);
    powerDownTimerHandle = null;
    power.autoOffMinutes = minutes;
    power.activity();
}

power.activity = function() {
    if(powerDownTimerHandle) clearTimeout(powerDownTimerHandle);
    powerDownTimerHandle = null;
    if(power.autoOffMinutes && !power.autoOffDisabled) {
        powerDownTimerHandle = setTimeout(function(){
            if(power.charging || power.percentage == 100) {
                return; // don't power down if plugged in
            } else {
                power.shutdown();
            }
        }, power.autoOffMinutes * 60000);
    }
}
power.activity();

power.shutdown = function() {
    exec("nohup init 0");
}

power.reboot = function() {
    exec("nohup init 6");
}

power.disableAutoOff = function() {
    power.autoOffDisabled = true;
    power.activity();
}

power.enableAutoOff = function() {
    power.autoOffDisabled = false;
    power.activity();
}

power.gps = function(enable, callback) {
    if(enable) console.log("powering on GPS");
    else console.log("powering off GPS");
    power.gpsEnabled = enable ? 'enabled' : 'disabled';
    setPower(callback);
}

power.wifi = function(enable, callback) {
    power.wifiEnabled = enable;
    setPower(function(){
        setTimeout(callback, 3000); // give time for modules to load/unload
    });
}

var statsRegs = {
//    POWER_STATUS: 0x00,
    POWER_OP_MODE: 0x01,
//    CHARGE_CTL: 0x33,
//    CHARGE_CTL2: 0x34,
    BAT_VOLT_MSB: 0x78,
    BAT_VOLT_LSB: 0x79,
    USB_VOLT_MSB: 0x5a,
    USB_VOLT_LSB: 0x5b,
    USB_CURR_MSB: 0x5c,
    USB_CURR_LSB: 0x5d,
    BAT_IDISCHG_MSB: 0x7c,
    BAT_IDISCHG_LSB: 0x7d,
    BAT_ICHG_MSB: 0x7a,
    BAT_ICHG_LSB: 0x7b,
    TEMP_MSB: 0x5e,
    TEMP_LSB: 0x5f,
    BAT_GAUGE: 0xb9,
    BAT_WARN: 0x49
}

function getPowerStats(callback) {
    var stats = {};
    axpSet(0x82, 0xff, function() {
        async.mapValuesSeries(statsRegs, function(reg, key, cb) {
            axpGet(reg, cb);
        }, function(err, res) {
            if(!err && res) {
                stats.batteryCharging = ((res.POWER_OP_MODE & 0x40) / 64) ? true : false;
                stats.axpTemperature = ((res.TEMP_MSB << 4) | (res.TEMP_LSB & 0x0F)) * 0.1 - 144.7;
                stats.batteryPercent = res.BAT_GAUGE;
                stats.batteryVoltage = ((res.BAT_VOLT_MSB << 4) | (res.BAT_VOLT_LSB & 0x0F)) * 1.1 / 1000;
                stats.usbVoltage = ((res.USB_VOLT_MSB << 4) | (res.USB_VOLT_LSB & 0x0F)) * 1.7 / 1000;
                stats.usbCurrent = ((res.USB_CURR_MSB << 4) | (res.USB_CURR_LSB & 0x0F)) * 0.375 / 1000;
                stats.usbWatts = stats.usbVoltage * stats.usbCurrent;
                stats.batteryDischargeCurrent = ((res.BAT_IDISCHG_MSB << 5) | (res.BAT_IDISCHG_LSB & 0x0F)) * 0.5 / 1000;
                stats.batteryChargeCurrent = ((res.BAT_ICHG_MSB << 4) | (res.BAT_ICHG_LSB & 0x0F)) * 0.5 / 1000;
                stats.batteryWarning = ((res.BAT_WARN & 0x20) / 32) ? true : false;
                stats.batteryWatts = stats.batteryVoltage * stats.batteryDischargeCurrent;
                stats.shutdownNow = ((res.BAT_WARN & 0x10) / 16) ? true : false;
                stats.pluggedIn = stats.usbWatts > 0 ? true : false;
                if(stats.batteryPercent >= 100) {
                    if(stats.batteryCharging) {
                        stats.batteryPercent = 99;
                    } else {
                        stats.batteryPercent = 100;
                    }
                }
                if(stats.batteryPercent < 1) stats.batteryPercent = 100;
                if(stats.batteryWarning) stats.batteryPercent = 0;
                //console.log(stats);
                var logString = stats.batteryPercent + "," + stats.batteryVoltage + "," + stats.batteryDischargeCurrent + ',' + stats.batteryWarning + ',' + stats.shutdownNow;
                exec('echo "' + logString + '" >> /home/root/powerlog.txt', function(err, stderr){
                    if(err) console.log(stderr);
                });

                callback && callback(null, stats);
            } else {
                callback && callback(err);
            }
        });
    });
}

function twoDigits(val) {
    return Math.round(val * 100) / 100;
}

power.infoText = function() {
    var info = "";
    info += "External Power: " + (power.stats.pluggedIn ? 'YES' : 'NO');
    if(power.stats.pluggedIn) info += "\tBattery charging: " + (power.stats.batteryCharging ? 'YES' : 'NO');
    if(power.stats.pluggedIn) info += "\tConsumption: " + twoDigits(power.stats.usbWatts) + "W";
    if(!power.stats.pluggedIn) info += "\tConsumption: " + twoDigits(power.stats.batteryWatts) + "W";
    if(power.stats.pluggedIn) info += "\tUSB Volts: " + twoDigits(power.stats.usbVoltage) + "V";
    if(power.stats.pluggedIn) info += "\tUSB Current: " + twoDigits(power.stats.usbCurrent) + "A";
    info += "\tBattery Level: " + twoDigits(power.stats.batteryPercent) + "%";
    info += "\tBattery Volts: " + twoDigits(power.stats.batteryVoltage) + "V";
    if(!power.stats.pluggedIn) info += "\tBattery Current: " + twoDigits(power.stats.batteryDischargeCurrent) + "A";
    if(power.stats.pluggedIn) info += "\tCharge Current: " + twoDigits(power.stats.batteryChargeCurrent) + "A";
    info += "\tPMIC Temp: " + twoDigits(power.stats.axpTemperature) + "°C";
    return info;
}

power.update = function(noEvents) {
    getPowerStats(function(err, stats) {
        if(!err && stats) {
            power.stats = stats;
            if(stats.pluggedIn != null && stats.pluggedIn != power.charging) {
                power.charging = stats.pluggedIn;
                power.emit("charging", power.charging);
            }

            if(stats.batteryPercent != null && stats.batteryPercent != power.percentage) {
                power.percentage = stats.batteryPercent;
                power.emit("percentage", power.percentage);
            }

            if(stats.batteryWarning) {
                power.emit("warning", power.warning);
                power.percentage = 0;
                power.emit("percentage", power.percentage);
            }

            if(stats.shutdownNow) {
                console.log("WARNING: low battery - sending shutdown event");
                power.emit("shutdown");
            }
        }
    });
};

power.buttonPowerLight = function(on) {
    if(on) {
        exec("echo 255 | sudo tee /sys/class/leds/view-button-power/brightness");
    } else {
        exec("echo 0 | sudo tee /sys/class/leds/view-button-power/brightness");
    }
}

power.buttonPowerBlink = function() {
    exec("echo 255 | sudo tee /sys/class/leds/view-button-power/brightness; echo 0 | sudo tee /sys/class/leds/view-button-power/brightness");
}

power.button1Light = function(on) {
    if(on) {
        exec("echo 255 | sudo tee /sys/class/leds/view-button-1/brightness");
    } else {
        exec("echo 0 | sudo tee /sys/class/leds/view-button-1/brightness");
    }
}

power.button2Light = function(on) {
    if(on) {
        exec("echo 255 | sudo tee /sys/class/leds/view-button-2/brightness");
    } else {
        exec("echo 0 | sudo tee /sys/class/leds/view-button-2/brightness");
    }
}

power.button3Light = function(on) {
    if(on) {
        exec("echo 255 | sudo tee /sys/class/leds/view-button-3/brightness");
    } else {
        exec("echo 0 | sudo tee /sys/class/leds/view-button-3/brightness");
    }
}

//setInterval(power.update, 5000);
setInterval(power.update, 60000);

module.exports = power;<commit_msg>battery testing<commit_after>var EventEmitter = require("events").EventEmitter;
var exec = require('child_process').exec;
var async = require('async');

var power = new EventEmitter();

power.chargeLight = 'enabled';
power.gpsEnabled = 'enabled';
power.wifiEnabled = true;
power.autoOffMinutes = 10;
power.autoOffDisabled = false;

var powerControlBase = 0x17; // gps off, wifi off
var powerWifi = 0x40;
var powerGps = 0x8;

var powerDownTimerHandle = null;

function axpSet(reg, val, callback) {
    reg = parseInt(reg);
    val = parseInt(val);
    if(reg != null && val != null) {
        exec("i2cset -y -f 0 0x34 0x" + reg.toString(16) + " 0x" + val.toString(16), callback);
    } else {
        callback('invalid parameters');
    }
}

function axpGet(reg, callback) {
    reg = parseInt(reg);
    if(reg != null) {
        exec("i2cget -y -f 0 0x34 0x" + reg.toString(16), function(err, stdout) {
            if(!err && stdout) {
                callback && callback(null, parseInt(stdout.trim()));
            } else {
                callback(err);
            }
        });
    } else {
        callback('invalid parameters');
    }
}

power.init = function(disableLight) {
    axpSet(0x81, 0xf9); // fix issue with wifi power on
    axpSet(0x34, 0x57); // set chgled to blink
    axpSet(0x33, 0xdc); // set charge rate to 1.5A
    axpSet(0x30, 0x60); // set system current limit to 900mA
    axpSet(0x82, 0xff); // enable ADC for battery monitoring

    if(disableLight) {
        power.chargeLight = 'disabled';
        axpSet(0x32, 0x8); // disable chgled
    } else {
        power.chargeLight = 'enabled';
        axpSet(0x32, 0x0); // enable chgled
    }
}

function setPower(callback) {
    var setting = powerControlBase;
    if(power.gpsEnabled != 'disabled') setting |= powerGps;
    if(power.wifiEnabled) setting |= powerWifi;
    console.log("setting power control to 0x" + setting.toString(16));
    axpSet(0x12, setting, callback); // set power switches
}

var blinkIntervalHandle = null;
power.setButtons = function(mode) {
    if(!mode) mode = "disabled";
    power.buttonMode = mode;
    if(blinkIntervalHandle) {
        clearInterval(blinkIntervalHandle);
        blinkIntervalHandle = null;
    }
    if(mode == 'disabled') {
        power.buttonPowerLight(false);
        power.button1Light(false);
        power.button2Light(false);
        power.button3Light(false);
    } else if(mode == 'power') {
        power.buttonPowerLight(true);
        power.button1Light(false);
        power.button2Light(false);
        power.button3Light(false);

    } else if(mode == 'all') {
        power.buttonPowerLight(true);
        power.button1Light(true);
        power.button2Light(true);
        power.button3Light(true);
    } else if(mode == 'blink') {
        power.buttonPowerBlink();
        power.button1Light(false);
        power.button2Light(false);
        power.button3Light(false);
        blinkIntervalHandle = setInterval(power.buttonPowerBlink, 5000);
    }
}

power.setAutoOff = function(minutes) {
    if(powerDownTimerHandle) clearTimeout(powerDownTimerHandle);
    powerDownTimerHandle = null;
    power.autoOffMinutes = minutes;
    power.activity();
}

power.activity = function() {
    if(powerDownTimerHandle) clearTimeout(powerDownTimerHandle);
    powerDownTimerHandle = null;
    if(power.autoOffMinutes && !power.autoOffDisabled) {
        powerDownTimerHandle = setTimeout(function(){
            if(power.charging || power.percentage == 100) {
                return; // don't power down if plugged in
            } else {
                power.shutdown();
            }
        }, power.autoOffMinutes * 60000);
    }
}
power.activity();

power.shutdown = function() {
    exec("nohup init 0");
}

power.reboot = function() {
    exec("nohup init 6");
}

power.disableAutoOff = function() {
    power.autoOffDisabled = true;
    power.activity();
}

power.enableAutoOff = function() {
    power.autoOffDisabled = false;
    power.activity();
}

power.gps = function(enable, callback) {
    if(enable) console.log("powering on GPS");
    else console.log("powering off GPS");
    power.gpsEnabled = enable ? 'enabled' : 'disabled';
    setPower(callback);
}

power.wifi = function(enable, callback) {
    power.wifiEnabled = enable;
    setPower(function(){
        setTimeout(callback, 3000); // give time for modules to load/unload
    });
}

var statsRegs = {
//    POWER_STATUS: 0x00,
    POWER_OP_MODE: 0x01,
//    CHARGE_CTL: 0x33,
//    CHARGE_CTL2: 0x34,
    BAT_VOLT_MSB: 0x78,
    BAT_VOLT_LSB: 0x79,
    USB_VOLT_MSB: 0x5a,
    USB_VOLT_LSB: 0x5b,
    USB_CURR_MSB: 0x5c,
    USB_CURR_LSB: 0x5d,
    BAT_IDISCHG_MSB: 0x7c,
    BAT_IDISCHG_LSB: 0x7d,
    BAT_ICHG_MSB: 0x7a,
    BAT_ICHG_LSB: 0x7b,
    TEMP_MSB: 0x5e,
    TEMP_LSB: 0x5f,
    BAT_GAUGE: 0xb9,
    BAT_WARN: 0x49
}

function getPowerStats(callback) {
    var stats = {};
    axpSet(0x82, 0xff, function() {
        async.mapValuesSeries(statsRegs, function(reg, key, cb) {
            axpGet(reg, cb);
        }, function(err, res) {
            if(!err && res) {
                stats.batteryCharging = ((res.POWER_OP_MODE & 0x40) / 64) ? true : false;
                stats.axpTemperature = ((res.TEMP_MSB << 4) | (res.TEMP_LSB & 0x0F)) * 0.1 - 144.7;
                stats.batteryPercent = res.BAT_GAUGE;
                stats.batteryVoltage = ((res.BAT_VOLT_MSB << 4) | (res.BAT_VOLT_LSB & 0x0F)) * 1.1 / 1000;
                stats.usbVoltage = ((res.USB_VOLT_MSB << 4) | (res.USB_VOLT_LSB & 0x0F)) * 1.7 / 1000;
                stats.usbCurrent = ((res.USB_CURR_MSB << 4) | (res.USB_CURR_LSB & 0x0F)) * 0.375 / 1000;
                stats.usbWatts = stats.usbVoltage * stats.usbCurrent;
                stats.batteryDischargeCurrent = ((res.BAT_IDISCHG_MSB << 5) | (res.BAT_IDISCHG_LSB & 0x0F)) * 0.5 / 1000;
                stats.batteryChargeCurrent = ((res.BAT_ICHG_MSB << 4) | (res.BAT_ICHG_LSB & 0x0F)) * 0.5 / 1000;
                stats.batteryWarning = ((res.BAT_WARN & 0x20) / 32) ? true : false;
                stats.batteryWatts = stats.batteryVoltage * stats.batteryDischargeCurrent;
                stats.shutdownNow = ((res.BAT_WARN & 0x10) / 16) ? true : false;
                stats.pluggedIn = stats.usbWatts > 0 ? true : false;
                if(stats.batteryPercent >= 100) {
                    if(stats.batteryCharging) {
                        stats.batteryPercent = 99;
                    } else {
                        stats.batteryPercent = 100;
                    }
                }
                if(stats.batteryPercent < 1) stats.batteryPercent = 100;
                if(stats.batteryWarning) stats.batteryPercent = 0;
                //console.log(stats);
                var logString = stats.batteryPercent + "," + stats.batteryVoltage + "," + stats.batteryDischargeCurrent + ',' + stats.batteryWarning + ',' + stats.shutdownNow;
                exec('echo "' + logString + '" >> /root/powerlog.txt', function(err, stderr){
                    if(err) console.log(stderr);
                });

                callback && callback(null, stats);
            } else {
                callback && callback(err);
            }
        });
    });
}

function twoDigits(val) {
    return Math.round(val * 100) / 100;
}

power.infoText = function() {
    var info = "";
    info += "External Power: " + (power.stats.pluggedIn ? 'YES' : 'NO');
    if(power.stats.pluggedIn) info += "\tBattery charging: " + (power.stats.batteryCharging ? 'YES' : 'NO');
    if(power.stats.pluggedIn) info += "\tConsumption: " + twoDigits(power.stats.usbWatts) + "W";
    if(!power.stats.pluggedIn) info += "\tConsumption: " + twoDigits(power.stats.batteryWatts) + "W";
    if(power.stats.pluggedIn) info += "\tUSB Volts: " + twoDigits(power.stats.usbVoltage) + "V";
    if(power.stats.pluggedIn) info += "\tUSB Current: " + twoDigits(power.stats.usbCurrent) + "A";
    info += "\tBattery Level: " + twoDigits(power.stats.batteryPercent) + "%";
    info += "\tBattery Volts: " + twoDigits(power.stats.batteryVoltage) + "V";
    if(!power.stats.pluggedIn) info += "\tBattery Current: " + twoDigits(power.stats.batteryDischargeCurrent) + "A";
    if(power.stats.pluggedIn) info += "\tCharge Current: " + twoDigits(power.stats.batteryChargeCurrent) + "A";
    info += "\tPMIC Temp: " + twoDigits(power.stats.axpTemperature) + "°C";
    return info;
}

power.update = function(noEvents) {
    getPowerStats(function(err, stats) {
        if(!err && stats) {
            power.stats = stats;
            if(stats.pluggedIn != null && stats.pluggedIn != power.charging) {
                power.charging = stats.pluggedIn;
                power.emit("charging", power.charging);
            }

            if(stats.batteryPercent != null && stats.batteryPercent != power.percentage) {
                power.percentage = stats.batteryPercent;
                power.emit("percentage", power.percentage);
            }

            if(stats.batteryWarning) {
                power.emit("warning", power.warning);
                power.percentage = 0;
                power.emit("percentage", power.percentage);
            }

            if(stats.shutdownNow) {
                console.log("WARNING: low battery - sending shutdown event");
                power.emit("shutdown");
            }
        }
    });
};

power.buttonPowerLight = function(on) {
    if(on) {
        exec("echo 255 | sudo tee /sys/class/leds/view-button-power/brightness");
    } else {
        exec("echo 0 | sudo tee /sys/class/leds/view-button-power/brightness");
    }
}

power.buttonPowerBlink = function() {
    exec("echo 255 | sudo tee /sys/class/leds/view-button-power/brightness; echo 0 | sudo tee /sys/class/leds/view-button-power/brightness");
}

power.button1Light = function(on) {
    if(on) {
        exec("echo 255 | sudo tee /sys/class/leds/view-button-1/brightness");
    } else {
        exec("echo 0 | sudo tee /sys/class/leds/view-button-1/brightness");
    }
}

power.button2Light = function(on) {
    if(on) {
        exec("echo 255 | sudo tee /sys/class/leds/view-button-2/brightness");
    } else {
        exec("echo 0 | sudo tee /sys/class/leds/view-button-2/brightness");
    }
}

power.button3Light = function(on) {
    if(on) {
        exec("echo 255 | sudo tee /sys/class/leds/view-button-3/brightness");
    } else {
        exec("echo 0 | sudo tee /sys/class/leds/view-button-3/brightness");
    }
}

//setInterval(power.update, 5000);
setInterval(power.update, 60000);

module.exports = power;<|endoftext|>


<commit_before>// Morse code as of ITU M.1677-1-200910.
//
// As Morse code is a digital protocol at the bottom (signal / no signal), it
// is represented using true (signal) and false (no signal).

// Look mom - no var!
// Look dad - no for!

const assert = require('chai').assert;
const expect = require('chai').expect;

const table = {
  'a': '.-',
  'b': '-...',
  'c': '-.-.',
  'd': '-..',
  'e': '.',
  'f': '..-.',
  'g': '--.',
  'h': '....',
  'i': '..',
  'j': '.---',
  'k': '-.-',
  'l': '.-..',
  'm': '--',
  'n': '-.',
  'o': '---',
  'p': '.--.',
  'q': '--.-',
  'r': '.-.',
  's': '...',
  't': '-',
  'u': '..-',
  'v': '...-',
  'w': '.--',
  'x': '-..-',
  'y': '-.--',
  'z': '--..',

  '1': '.----',
  '2': '..---',
  '3': '...--',
  '4': '....-',
  '5': '.....',
  '6': '-....',
  '7': '--...',
  '8': '---..',
  '9': '----.',
  '0': '-----',

  '.': '.-.-.-',
  ',': '--..--',
  ':': '---...',
  '?': '..--..',
  '\'': '.----.',
  '-': '-....-',
  '/': '-..-.',
  '(': '-.--.',
  ')': '-.--.-',
  '"': '.-..-.',
  '=': '-...-',
  '+': '.-.-.',
  '*': '-..-',
  '@': '.--.-.'

};

const controlTable = {
  'understood': '...-.',
  'error': '........',
  'invitation_to_transmit': '-.-',
  'wait': '.-...',
  'end_of_work': '...-.-',
  // To precede every transmission
  'start': '-.-.-'
};

expect(table.e).to.equal('.');
expect(table['7']).to.equal('--...');

// Representation of a long 'dah'
const dah = '-';

// Representation of a short 'dit'
const dit = '.';

// Representation of pause/ break/ nothing
const pause = ' ';

// Return true if character is a long 'dah' in morse notation.
// :: String[1] -> Boolean
const isDah = c => dah === c;

// Avoid .to.be.true because linter will complain about expression
expect(isDah(dah)).to.equal(true);
expect(isDah(dit)).to.equal(false);

// Return true if character is a short 'dit' in morse notation.
// :: String[1] -> Boolean
const isDit = c => dit === c;

expect(isDit(dit)).to.equal(true);
expect(isDit(dah)).to.equal(false);

// 2.1 A dash is equal to three dots.
// :: Int
const dashDotRatio = 3;

// 2.2 The space between the signals forming the same letter is equal to one
// dot.
// :: Int
const symbolDotRatio = 1;

// 2.3 The space between two letters is equal to three dots.
// :: Int
const letterDotRatio = 3;

// 2.4: The space between two words is equal to seven dots.
const wordDotRatio = 7;

// Utility: Flatten array
// :: [a] -> [b]
const flatten = as => [].concat.apply([], as);

// Utility: Create array of length n, and prepopulate with d
// :: a -> Number -> [a]
const mkArray = (d, n) => Array.apply(null, new Array(n)).map(_ => d);

expect(mkArray(true, 2)).to.be.eql([true, true]);
expect(mkArray(0, 3)).to.be.eql([0, 0, 0]);

const mkPause = n => mkArray(' ', n).join('');
expect(mkPause(2)).to.equal('  ');

// Encode a character text into morse.
// :: String[1] -> String
const encodeLetter = c => table[c];

// Encode text into morse.
// TODO Using a String is suboptimal, because it hardcodes the underlying buffer
// resp. transport representation (could be file based, stream based, ...).
// :: String -> String
const encode = exports.encode = s => {
  return s
    .toLowerCase()
    .split(' ')
    .map(word => {
      return s
        .split('')
        .map(letter => table[letter])
        .join(mkPause(1));
    })
    .join(mkPause(3));
};

////////////////////////////////////////////////////////////////////////////////
//
// Signal functions
//
////////////////////////////////////////////////////////////////////////////////

// Map true -> '=' and false -> '_'
// :: Boolean -> Character
const wikipediaNotation = a => { return a ? '=' : '_'; };

expect(wikipediaNotation([ true, true, false ])).to.eql('=', '_', '=');

// Convert a text into a signal (on/ off).
// :: String -> [Boolean]
const signal = exports.signal = s => {
  // ECMAScripts Array.prototype.join() does not offer anything other than
  // Strings, so instead of boolean true and false the implementation is based
  // on characters '0' and '1'.
  const off = '0';
  const on = '1';

  // A little macro-ish like helper
  const sep0 = n => mkArray(off, n).join('');
  const sep1 = n => mkArray(on, n).join('');

  const wordSep = sep0(wordDotRatio);
  const letterSep = sep0(letterDotRatio);
  const symbolSep = sep0(symbolDotRatio);

  const dah = sep1(dashDotRatio);
  const dit = sep1(1);
  return s
    .toLowerCase()
    .split(' ')
    .map(word => {
      // console.log('* Word: ' + word);
      return word
        .split('')
        .map(letter => {
          // console.log('* * Letter: ' + letter);
          return encodeLetter(letter)
            .split('')
            .map(symbol => {
              // console.log('* * * Symbol: ' + symbol);
              return (isDah(symbol) ? dah : dit);
            })
            .join(symbolSep);
        })
        .join(letterSep);
    })
    .join(wordSep)
    .split('')
    .map(c => { return c === on ? true : false; });
};

expect(signal('morse code')
    .map(wikipediaNotation)
    .join(''))
  .to
  .equal('===_===___===_===_===___=_===_=___=_=_=___=_______' +
      '===_=_===_=___===_===_===___===_=_=___=');

// EOF
<commit_msg>refactor: Replace clumsy array stuff<commit_after>// Morse code as of ITU M.1677-1-200910.
//
// As Morse code is a digital protocol at the bottom (signal / no signal), it
// is represented using true (signal) and false (no signal).

// Look mom - no var!
// Look dad - no for!

const assert = require('chai').assert;
const expect = require('chai').expect;

const table = {
  'a': '.-',
  'b': '-...',
  'c': '-.-.',
  'd': '-..',
  'e': '.',
  'f': '..-.',
  'g': '--.',
  'h': '....',
  'i': '..',
  'j': '.---',
  'k': '-.-',
  'l': '.-..',
  'm': '--',
  'n': '-.',
  'o': '---',
  'p': '.--.',
  'q': '--.-',
  'r': '.-.',
  's': '...',
  't': '-',
  'u': '..-',
  'v': '...-',
  'w': '.--',
  'x': '-..-',
  'y': '-.--',
  'z': '--..',

  '1': '.----',
  '2': '..---',
  '3': '...--',
  '4': '....-',
  '5': '.....',
  '6': '-....',
  '7': '--...',
  '8': '---..',
  '9': '----.',
  '0': '-----',

  '.': '.-.-.-',
  ',': '--..--',
  ':': '---...',
  '?': '..--..',
  '\'': '.----.',
  '-': '-....-',
  '/': '-..-.',
  '(': '-.--.',
  ')': '-.--.-',
  '"': '.-..-.',
  '=': '-...-',
  '+': '.-.-.',
  '*': '-..-',
  '@': '.--.-.'

};

const controlTable = {
  'understood': '...-.',
  'error': '........',
  'invitation_to_transmit': '-.-',
  'wait': '.-...',
  'end_of_work': '...-.-',
  // To precede every transmission
  'start': '-.-.-'
};

expect(table.e).to.equal('.');
expect(table['7']).to.equal('--...');

// Representation of a long 'dah'
const dah = '-';

// Representation of a short 'dit'
const dit = '.';

// Representation of pause/ break/ nothing
const pause = ' ';

// Return true if character is a long 'dah' in morse notation.
// :: String[1] -> Boolean
const isDah = c => dah === c;

// Avoid .to.be.true because linter will complain about expression
expect(isDah(dah)).to.equal(true);
expect(isDah(dit)).to.equal(false);

// Return true if character is a short 'dit' in morse notation.
// :: String[1] -> Boolean
const isDit = c => dit === c;

expect(isDit(dit)).to.equal(true);
expect(isDit(dah)).to.equal(false);

// 2.1 A dash is equal to three dots.
// :: Int
const dashDotRatio = 3;

// 2.2 The space between the signals forming the same letter is equal to one
// dot.
// :: Int
const symbolDotRatio = 1;

// 2.3 The space between two letters is equal to three dots.
// :: Int
const letterDotRatio = 3;

// 2.4: The space between two words is equal to seven dots.
const wordDotRatio = 7;

// Utility: Flatten array
// :: [a] -> [b]
const flatten = as => [].concat.apply([], as);

// Utility: Create array of length n, and prepopulate with d
// :: a -> Number -> [a]
const mkArray = (d, n) => Array.apply(null, new Array(n)).map(_ => d);

expect(mkArray(true, 2)).to.be.eql([true, true]);
expect(mkArray(0, 3)).to.be.eql([0, 0, 0]);

// Encode a character text into morse.
// :: String[1] -> String
const encodeLetter = c => table[c];

// Encode text into morse.
// TODO Using a String is suboptimal, because it hardcodes the underlying buffer
// resp. transport representation (could be file based, stream based, ...).
// :: String -> String
const encode = exports.encode = s => {
  return s
    .toLowerCase()
    .split(' ')
    .map(word => {
      return s
        .split('')
        .map(letter => table[letter])
        .join(' '.repeat(letterDotRatio));
    })
    .join(' '.repeat(wordDotRatio));
};

////////////////////////////////////////////////////////////////////////////////
//
// Signal functions
//
////////////////////////////////////////////////////////////////////////////////

// Map true -> '=' and false -> '_'
// :: Boolean -> Character
const wikipediaNotation = a => { return a ? '=' : '_'; };

expect(wikipediaNotation([ true, true, false ])).to.eql('=', '_', '=');

// Convert a text into a signal (on/ off).
// :: String -> [Boolean]
const signal = exports.signal = s => {
  // ECMAScripts Array.prototype.join() does not offer anything other than
  // Strings, so instead of boolean true and false the implementation is based
  // on characters '0' and '1'.
  const off = '0';
  const on = '1';

  // A little macro-ish like helper
  const sep0 = n => mkArray(off, n).join('');
  const sep1 = n => mkArray(on, n).join('');

  const wordSep = sep0(wordDotRatio);
  const letterSep = sep0(letterDotRatio);
  const symbolSep = sep0(symbolDotRatio);

  const dah = sep1(dashDotRatio);
  const dit = sep1(1);
  return s
    .toLowerCase()
    .split(' ')
    .map(word => {
      // console.log('* Word: ' + word);
      return word
        .split('')
        .map(letter => {
          // console.log('* * Letter: ' + letter);
          return encodeLetter(letter)
            .split('')
            .map(symbol => {
              // console.log('* * * Symbol: ' + symbol);
              return (isDah(symbol) ? dah : dit);
            })
            .join(symbolSep);
        })
        .join(letterSep);
    })
    .join(wordSep)
    .split('')
    .map(c => { return c === on ? true : false; });
};

expect(signal('morse code')
    .map(wikipediaNotation)
    .join(''))
  .to
  .equal('===_===___===_===_===___=_===_=___=_=_=___=_______' +
      '===_=_===_=___===_===_===___===_=_=___=');

// EOF
<|endoftext|>