<commit_before>var redis = require('redis');
var client = redis.createClient();

var proximity = require('../main.js').initialize(client);

var lat = 43.646838,
    lon = -79.403723;

var rangeIndex = [
    0.6, //52
    1, //50
    2.19, //48
    4.57, //46
    9.34, //44
    14.4, //42
    33.18, //40
    62.1, //38
    128.55, //36
    252.9, //34
    510.02, //32
    1015.8, //30
    2236.5, //28
    3866.9, //26
    8749.7, //24
    15664, //22
    33163.5, //20
    72226.3, //18
    150350, //16
    306600, //14
    474640, //12
    1099600, //10
    2349600, //8
    4849600, //6
    10018863 //4
];

var addArray = [];

exports['Exporting OK'] = function(test) {

    client.flushall();

    test.expect(4);

    test.equal(typeof proximity === 'object', true);
    test.equal(typeof proximity.initialize === 'function', true);
    test.equal(proximity.client.constructor.name, 'RedisClient');
    test.equal(proximity.zset, 'geo:locations');
    test.done();

};

exports['Add Location'] = function(test) {

    client.flushall();

    test.expect(1);

    proximity.addLocation("Toronto", 43.6667, -79.4167, function(err, reply) {
        if (err) throw err;
        test.equal(reply, 1);
        test.done();
    });

};

exports['Add Locations'] = function(test){

  client.flushall();

  test.expect(2);

  var locationRange;
  var locationArray = [];
  var distance = 0;
  var count = 1;

  locationArray.push([lat, lon, "center_0"]);

  for (var i = 0; i < 100000; i++) {
    distance = i*(i/100);
    locationRange = getMinMaxs(lat, lon, distance);
    locationArray.push([locationRange.latmin, locationRange.lonmin, "sw_"+distance]);
    locationArray.push([locationRange.latmax, locationRange.lonmin, "nw_"+distance]);
    locationArray.push([locationRange.latmin, locationRange.lonmax, "se_"+distance]);
    locationArray.push([locationRange.latmax, locationRange.lonmax, "ne_"+distance]);
    count += 4;
  }

  proximity.addLocations(locationArray, function (err, reply){
    if(err) throw err;
    test.equal(err, null);
    test.equal(400001, reply);
    test.done();
  });

};

exports['Basic Query'] = function(test){

  test.expect(1);

  proximity.nearby(lat, lon, 50000, function(err, replies){
    if(err) throw err;
    // console.log("NUMBER OF GEOHASH MATCHES", replies.length);
    test.equal(replies.length, 6835);
    test.done();
  });
};

// // exports.performantQuery = function(test){

// //   test.expect(1);

// //   var cachedQuery = proximity.getQueryCache(lat, lon, 50000);

// //   proximity.queryWithCache(cachedQuery, function(err, replies){
// //     if(err) throw err;
// //     test.equal(replies.length, 6835);
// //     test.done();
// //   });

// // };

// exports['Remove Location'] = function(test){

//   test.expect(1);

//   var oneToDelete = "";
//   var ranges = proximity.getQueryRangesFromRadius(lat, lon, 50000);

//   proximity.queryByRanges(ranges, function(err, replies){
//     if(err) throw err;
//     oneToDelete = replies[replies.length-1];

//     proximity.removelocation(oneToDelete, function(err, reply){
//       if(err) throw err;
//       // console.log("TIMESTAMP Delete One", new Date().getTime()-startTime);
//       // console.log(JSON.stringify(reply));
//       test.equal(reply, 1);
//       test.done();
//     });
//   });
// };

// exports.removelocations = function(test){

//   test.expect(1);

//   var arrayToDelete = [];
//   var ranges = proximity.getQueryRangesFromRadius(lat, lon, 50000);

//   proximity.queryByRanges(ranges, function(err, replies){

//     if(err) throw err;
//     arrayToDelete = replies;

//     proximity.removelocations(arrayToDelete, function(err, reply){
//       if(err) throw err;
//       test.equal(reply, 6834);

//       test.done();
//     });
//   });
// };

// exports.testLargeRadius = function(test){

//   client.flushall();

//   test.expect(1);

//   proximity.addLocation(1,2,"debugger", function(err, reply){});
//   proximity.addLocation(2,3,"boostbob", function(err, reply){});
//   proximity.query(2,2,100000000, function(err, replies) {
//     test.equal(replies[2], null);
//     test.done();
//   });

// };

// exports.addNearbyRanges = function(test){

//   client.flushall();

//   test.expect(2);

//   var locationRange;
//   var locationArray = [];
//   var distance = 0;
//   var count = 1;

//   locationArray.push([lat, lon, "center_0"]);

//   for (var i = 0; i < 100000; i++) {
//     distance = i*(i/100);
//     locationRange = getMinMaxs(lat, lon, distance);
//     locationArray.push([locationRange.latmin, locationRange.lonmin, "sw_"+distance]);
//     locationArray.push([locationRange.latmax, locationRange.lonmin, "nw_"+distance]);
//     locationArray.push([locationRange.latmin, locationRange.lonmax, "se_"+distance]);
//     locationArray.push([locationRange.latmax, locationRange.lonmax, "ne_"+distance]);
//     count += 4;
//   }

//   proximity.addLocations(locationArray, function (err, reply){
//     if(err) throw err;

//     test.equal(err, null);
//     test.equal(count, reply);
//     test.done();
//   });
// };

// var startBitDepth = 52;

// exports.testRangeBitDepths = function(test){

//   test.expect(25);

//   query(startBitDepth, test, function(){
//     test.done();
//   });

// };

// function query(bitDepth, test, next){

//   // console.log("Querying bit depth", lat, lon, bitDepth);

//   proximity.queryByBitDepth(lat, lon, bitDepth, function (err, replies){

//     if(err) throw err;

//     var max = 0;
//     var maxname = "";

//     for (var i = 0; i < replies.length; i++) {
//       var split = replies[i].split("_");
//       if(Number(split[1]) > max){
//         max = Number(split[1]);
//         maxname = replies[i];
//       }
//     }

//     test.equal((max > rangeIndex[(52-bitDepth)/2] || max < rangeIndex[((52-bitDepth)/2) + 1]), true);

//     console.log("Max Radius for BitDepth", bitDepth, max, maxname );

//     startBitDepth -= 2;

//     if(startBitDepth > 2){
//       query(startBitDepth, test, next);
//     }
//     else{
//       next();
//     }
//   });
// }

// var startRadius = 0.4;

// exports.testRangesRadius = function(test){

//   test.expect(22);

//   queryRadius(startRadius, test, function(){
//     test.done();
//   });

// };

// function queryRadius(radius, test, next){

//   // console.log("Querying bit depth", lat, lon, radius);

//   proximity.query(lat, lon, radius, function (err, replies){

//     if(err) throw err;

//     var max = 0;
//     var maxname = "";

//     for (var i = 0; i < replies.length; i++) {
//       var split = replies[i].split("_");
//       if(Number(split[1]) > max){
//         max = Number(split[1]);
//         maxname = replies[i];
//       }
//     }

//     test.equal((max > radius-(radius/2) || max < radius+(radius/2)), true);

//     console.log("Max Radius for Radius", radius, max, maxname );

//     startRadius *= 2;

//     if(startRadius < 1000000){
//       queryRadius(startRadius, test, next);
//     }
//     else{
//       next();
//     }
//   });
// }

// exports.differentSets = function(test){

//   test.expect(2);

//   var people       = [[43.6667,-79.4167, "John"],
//                      [39.9523,-75.1638, "Shankar"],
//                      [37.4688,-122.1411, "Cynthia"],
//                      [37.7691,-122.4449, "Chen"]];

//   var places       = [[43.6667,-79.4167, "Toronto"],
//                      [39.9523,-75.1638, "Philadelphia"],
//                      [37.4688,-122.1411, "Palo Alto"],
//                      [37.7691,-122.4449, "San Francisco"],
//                      [47.5500,-52.6667, "St. John's"]];

//   proximity.addLocations(people, {zset: "geo:locations:people"}, function(err, reply){
//     if(err) throw err;
//     // console.log("ADD successful:", reply);

//     proximity.addLocations(places, {zset: "geo:locations:places"}, function(err, reply){
//       if(err) throw err;
//       // console.log("ADD successful:", reply);

//       // will find all PEOPLE ~5000m from the passed in location
//       proximity.query(39.9523, -75.1638, 5000, {zset: "geo:locations:people"}, function(err, people){
//         if(err) throw err;
//         // console.log(people);

//         test.equal(people[0], "Shankar");

//         // will find all PLACES ~5000m from the passed in location
//         proximity.query(39.9523, -75.1638, 5000, {zset: "geo:locations:places"}, function(err, places){

//           if(err) throw err;
//           // console.log(places);

//           test.equal(places[0], "Philadelphia");
//           test.done();
//           // client.quit();

//         });
//       });
//     });
//   });
// };

// exports.differentSetsWithValues = function(test){

//   test.expect(6);

//   proximity.query(39.9523, -75.1638, 5000000, {zset: "geo:locations:people", values: true}, function(err, people){

//     if(err) throw err;

//     // console.log(people);
//     // [37.4688,-122.1411, "Cynthia"],
//     // [ 'Cynthia', 37.468800991773605, -122.14110106229782 ]

//     var cynthia = people[1];
//     var inlatRange = (cynthia[1] > 37.4688-0.005 && cynthia[1] < 37.4688+0.005) ? true : false;
//     var inlonRange = (cynthia[2] > -122.1411-0.005 && cynthia[2] < -122.1411+0.005) ? true : false;

//     test.equal(cynthia[0], "Cynthia");
//     test.equal(inlatRange, true);
//     test.equal(inlonRange, true);

//     // will find all PLACES ~5000m from the passed in location
//     proximity.query(39.9523, -75.1638, 5000000, {zset: "geo:locations:places", values: true}, function(err, places){

//       if(err) throw err;

//       // console.log(places);
//       // [39.9523,-75.1638, "Philadelphia"]
//       // [ 'Philadelphia', 39.95230123400688, -75.16379803419113 ]

//       var philadelphia = places[3];

//       inlatRange = (philadelphia[1] > 39.9523-0.005 && philadelphia[1] < 39.9523+0.005) ? true : false;
//       inlonRange = (philadelphia[2] > -75.1638-0.005 && philadelphia[2] < -75.1638+0.005) ? true : false;

//       test.equal(philadelphia[0], "Philadelphia");
//       test.equal(inlatRange, true);
//       test.equal(inlonRange, true);

//       test.done();
//       client.quit();

//     });
//   });

// };

exports['Quitting Client'] = function(test) {
    client.quit();
    test.done();
};

exports.tearDown = function(done) {

    done();
};

function getMinMaxs(lat, lon, radius){

  var latr = radius/111111;
  var lonr = radius/(111111 *  Math.abs(Math.cos(lat)));

  var latmin = lat - latr;
  var latmax = lat + latr;
  var lonmin = lon - lonr;
  var lonmax = lon + lonr;

  return {latmin: latmin, latmax: latmax, lonmin: lonmin, lonmax: lonmax};
}

return exports;
<commit_msg>Updating Full Set of Tests.<commit_after>var redis = require('redis');
var client = redis.createClient();

var proximity = require('../main.js').initialize(client),
    people, places;

var lat = 43.646838,
    lon = -79.403723;

var rangeIndex = [
    0.6, //52
    1, //50
    2.19, //48
    4.57, //46
    9.34, //44
    14.4, //42
    33.18, //40
    62.1, //38
    128.55, //36
    252.9, //34
    510.02, //32
    1015.8, //30
    2236.5, //28
    3866.9, //26
    8749.7, //24
    15664, //22
    33163.5, //20
    72226.3, //18
    150350, //16
    306600, //14
    474640, //12
    1099600, //10
    2349600, //8
    4849600, //6
    10018863 //4
];

var addArray = [];

exports['Exporting OK'] = function(test) {

    client.flushall();

    test.expect(4);

    test.equal(typeof proximity === 'object', true);
    test.equal(typeof proximity.initialize === 'function', true);
    test.equal(proximity.client.constructor.name, 'RedisClient');
    test.equal(proximity.zset, 'geo:locations');
    test.done();

};

exports['Add Location'] = function(test) {

    client.flushall();

    test.expect(1);

    proximity.addLocation("Toronto", 43.6667, -79.4167, function(err, reply) {
        if (err) throw err;
        test.equal(reply, 1);
        test.done();
    });

};

exports['Add Locations'] = function(test) {

    client.flushall();

    test.expect(2);

    var locationRange;
    var locationArray = [];
    var distance = 0;
    var count = 1;

    locationArray.push([lat, lon, "center_0"]);

    for (var i = 0; i < 100000; i++) {
        distance = i * (i / 100);
        locationRange = getMinMaxs(lat, lon, distance);
        locationArray.push([locationRange.latmin, locationRange.lonmin, "sw_" + distance]);
        locationArray.push([locationRange.latmax, locationRange.lonmin, "nw_" + distance]);
        locationArray.push([locationRange.latmin, locationRange.lonmax, "se_" + distance]);
        locationArray.push([locationRange.latmax, locationRange.lonmax, "ne_" + distance]);
        count += 4;
    }

    proximity.addLocations(locationArray, function(err, reply) {
        if (err) throw err;
        test.equal(err, null);
        test.equal(400001, reply);
        test.done();
    });

};

exports['Basic Query'] = function(test) {

    test.expect(1);

    proximity.nearby(lat, lon, 50000, function(err, replies) {
        if (err) throw err;
        // console.log("NUMBER OF GEOHASH MATCHES", replies.length);
        test.equal(replies.length, 6835);
        test.done();
    });
};

// // exports.performantQuery = function(test){

// //   test.expect(1);

// //   var cachedQuery = proximity.getQueryCache(lat, lon, 50000);

// //   proximity.queryWithCache(cachedQuery, function(err, replies){
// //     if(err) throw err;
// //     test.equal(replies.length, 6835);
// //     test.done();
// //   });

// // };

exports['Remove Location'] = function(test) {

    test.expect(1);

    var oneToDelete = "";
    // var ranges = proximity.getQueryRangesFromRadius(lat, lon, 50000);

    proximity.nearby(lat, lon, 50000, function(err, replies) {
        if (err) throw err;
        oneToDelete = replies[replies.length - 1];

        proximity.removeLocation(oneToDelete, function(err, numberRemoved) {
            if (err) throw err;
            // console.log("TIMESTAMP Delete One", new Date().getTime()-startTime);
            // console.log(JSON.stringify(reply));
            test.equal(numberRemoved, 1);
            test.done();
        });
    });
};

exports['Remove Locations'] = function(test) {

    test.expect(1);

    var arrayToDelete = [];

    proximity.nearby(lat, lon, 50000, function(err, replies) {

        if (err) throw err;
        arrayToDelete = replies;

        proximity.removeLocations(arrayToDelete, function(err, numberRemoved) {
            if (err) throw err;
            test.equal(numberRemoved, 6834);

            test.done();
        });
    });
};

exports['Large Radius'] = function(test) {

    client.flushall();

    test.expect(1);

    proximity.addLocation(1, 2, "debugger", function(err, reply) {});
    proximity.addLocation(2, 3, "boostbob", function(err, reply) {});

    proximity.nearby(2, 2, 100000000, function(err, replies) {
        test.equal(replies[2], null);
        test.done();
    });
};

exports['Add Nearby Ranges'] = function(test) {

    client.flushall();

    test.expect(2);

    var locationRange;
    var locationArray = [];
    var distance = 0;
    var count = 1;

    locationArray.push([lat, lon, "center_0"]);

    for (var i = 0; i < 100000; i++) {
        distance = i * (i / 100);
        locationRange = getMinMaxs(lat, lon, distance);
        locationArray.push([locationRange.latmin, locationRange.lonmin, "sw_" + distance]);
        locationArray.push([locationRange.latmax, locationRange.lonmin, "nw_" + distance]);
        locationArray.push([locationRange.latmin, locationRange.lonmax, "se_" + distance]);
        locationArray.push([locationRange.latmax, locationRange.lonmax, "ne_" + distance]);
        count += 4;
    }

    proximity.addLocations(locationArray, function(err, reply) {
        if (err) throw err;

        test.equal(err, null);
        test.equal(count, reply);
        test.done();
    });
};

var startRadius = 0.4;

exports['Radii Ranges'] = function(test) {

    test.expect(22);

    queryRadius(startRadius, test, function() {
        test.done();
    });

};

function queryRadius(radius, test, next) {

    proximity.nearby(lat, lon, radius, function(err, replies) {

        if (err) throw err;

        var max = 0;
        var maxname = "";

        for (var i = 0; i < replies.length; i++) {
            var split = replies[i].split("_");
            if (Number(split[1]) > max) {
                max = Number(split[1]);
                maxname = replies[i];
            }
        }

        test.equal((max > radius - (radius / 2) || max < radius + (radius / 2)), true);

        console.log("Max Radius for Radius", radius, max, maxname);

        startRadius *= 2;

        if (startRadius < 1000000) {
            queryRadius(startRadius, test, next);
        } else {
            next();
        }
    });
}

exports['Multiple Sets'] = function(test) {

    test.expect(2);

    var peopleLocations = [
        [43.6667, -79.4167, "John"],
        [39.9523, -75.1638, "Shankar"],
        [37.4688, -122.1411, "Cynthia"],
        [37.7691, -122.4449, "Chen"]
    ];

    var placesLocations = [
        [43.6667, -79.4167, "Toronto"],
        [39.9523, -75.1638, "Philadelphia"],
        [37.4688, -122.1411, "Palo Alto"],
        [37.7691, -122.4449, "San Francisco"],
        [47.5500, -52.6667, "St. John's"]
    ];

    places = proximity.addSet('places');
    people = proximity.addSet('people');

    people.addLocations(peopleLocations, function(err, reply) {

        if (err) throw err;

        places.addLocations(placesLocations, function(err, reply) {

            if (err) throw err;

            people.nearby(39.9523, -75.1638, 5000, function(err, people) {
                if (err) throw err;

                test.equal(people[0], "Shankar");
                places.nearby(39.9523, -75.1638, 5000, function(err, places) {

                    if (err) throw err;
                    test.equal(places[0], "Philadelphia");
                    test.done();
                });
            });
        });
    });
};

exports['Multiple Sets With Values'] = function(test) {

    test.expect(6);

    people.nearby(39.9523, -75.1638, 5000000, {
        values: true
    }, function(err, people) {

        if (err) throw err;

        var cynthia = people[1];
        var inlatRange = (cynthia[1] > 37.4688 - 0.005 && cynthia[1] < 37.4688 + 0.005) ? true : false;
        var inlonRange = (cynthia[2] > -122.1411 - 0.005 && cynthia[2] < -122.1411 + 0.005) ? true : false;

        test.equal(cynthia[0], "Cynthia");
        test.equal(inlatRange, true);
        test.equal(inlonRange, true);

        places.nearby(39.9523, -75.1638, 5000000, {
            values: true
        }, function(err, places) {

            if (err) throw err;

            var philadelphia = places[3];

            inlatRange = (philadelphia[1] > 39.9523 - 0.005 && philadelphia[1] < 39.9523 + 0.005) ? true : false;
            inlonRange = (philadelphia[2] > -75.1638 - 0.005 && philadelphia[2] < -75.1638 + 0.005) ? true : false;

            test.equal(philadelphia[0], "Philadelphia");
            test.equal(inlatRange, true);
            test.equal(inlonRange, true);

            test.done();
            client.quit();

        });
    });
};

exports['Quitting Client'] = function(test) {
    client.quit();
    test.done();
};

exports.tearDown = function(done) {

    done();
};

function getMinMaxs(lat, lon, radius) {

    var latr = radius / 111111;
    var lonr = radius / (111111 * Math.abs(Math.cos(lat)));

    var latmin = lat - latr;
    var latmax = lat + latr;
    var lonmin = lon - lonr;
    var lonmax = lon + lonr;

    return {
        latmin: latmin,
        latmax: latmax,
        lonmin: lonmin,
        lonmax: lonmax
    };
}

return exports;
<|endoftext|>


<commit_before>'use strict';

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

const domainPing = require('../domain-ping');

describe('Testing domain-ping', () => {

    describe('Basic errors', () => {

        it('should return error for empty domain', (done) => {
            domainPing('')
                .then((res) => {
                    done(Error('Expected to fail'));
                })
                .catch((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.false;
                    expect(res).to.have.property('error');
                    expect(res.error).to.be.a('string');
                    expect(res.error).to.be.equal('Invalid domain name');
                    done();
                })
                .catch(done);
        });

        it('should return error for invalid domain', (done) => {
            domainPing('abc123')
                .then((res) => {
                    done(Error('Expected to fail'));
                })
                .catch((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.false;
                    expect(res).to.have.property('error');
                    expect(res.error).to.be.a('string');
                    expect(res.error).to.be.equal('Invalid domain name');
                    done();
                })
                .catch(done);
        });

        it('should return error for domain that doesn\'t exist', (done) => {
            domainPing('githubabc.com')
                .then((res) => {
                    done(Error('Expected to fail'));
                })
                .catch((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.false;
                    expect(res).to.have.property('error');
                    expect(res.error).to.be.a('string');
                    expect(res.error).to.be.equal('getaddrinfo ENOTFOUND githubabc.com');
                    done();
                })
                .catch(done);
        });

    });

    describe('Valid domains', () => {

        it('should return correct data for github.com', (done) => {
            domainPing('github.com')
                .then((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.true;
                    expect(res).to.have.property('ip');
                    expect(res.ip).to.be.a('string');
                    expect(res).to.have.property('ping');
                    expect(res.ping).to.be.a('boolean');
                    // expect(res.ping).to.be.true; // Travis CI can't ping
                    expect(res).to.have.property('online');
                    expect(res.online).to.be.a('boolean');
                    expect(res.online).to.be.true;
                    expect(res).to.have.property('statusCode');
                    expect(res.statusCode).to.be.a('number');
                    expect(res.statusCode).to.be.equal(200);
                    done();
                })
                .catch(done);
        });

        it('should return correct data for netflix.com (no ping)', (done) => {
            domainPing('netflix.com')
                .then((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.true;
                    expect(res).to.have.property('ip');
                    expect(res.ip).to.be.a('string');
                    expect(res).to.have.property('ping');
                    expect(res.ping).to.be.a('boolean');
                    expect(res.ping).to.be.false; // Firewall blocking ICMP
                    expect(res).to.have.property('online');
                    expect(res.online).to.be.a('boolean');
                    expect(res.online).to.be.true;
                    expect(res).to.have.property('statusCode');
                    expect(res.statusCode).to.be.a('number');
                    expect(res.statusCode).to.be.equal(200);
                    done();
                })
                .catch(done);
        });

    });

});
<commit_msg>Changed tests because of debug<commit_after>'use strict';

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

const domainPing = require('../domain-ping');

describe('Testing domain-ping', () => {

    describe('Basic errors', () => {

        it('should return error for empty domain', (done) => {
            domainPing('')
                .then((res) => {
                    done(Error('Expected to fail'));
                })
                .catch((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.false;
                    expect(res).to.have.property('error');
                    expect(res.error).to.be.a('string');
                    expect(res.error).to.be.equal('invalid domain name ""');
                    done();
                })
                .catch(done);
        });

        it('should return error for invalid domain', (done) => {
            domainPing('abc123')
                .then((res) => {
                    done(Error('Expected to fail'));
                })
                .catch((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.false;
                    expect(res).to.have.property('error');
                    expect(res.error).to.be.a('string');
                    expect(res.error).to.be.equal('invalid domain name "abc123"');
                    done();
                })
                .catch(done);
        });

        it('should return error for domain that doesn\'t exist', (done) => {
            domainPing('githubabc.com')
                .then((res) => {
                    done(Error('Expected to fail'));
                })
                .catch((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.false;
                    expect(res).to.have.property('error');
                    expect(res.error).to.be.a('string');
                    expect(res.error).to.be.equal('getaddrinfo ENOTFOUND githubabc.com');
                    done();
                })
                .catch(done);
        });

    });

    describe('Valid domains', () => {

        it('should return correct data for github.com', (done) => {
            domainPing('github.com')
                .then((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.true;
                    expect(res).to.have.property('ip');
                    expect(res.ip).to.be.a('string');
                    expect(res).to.have.property('ping');
                    expect(res.ping).to.be.a('boolean');
                    // expect(res.ping).to.be.true; // Travis CI can't ping
                    expect(res).to.have.property('online');
                    expect(res.online).to.be.a('boolean');
                    expect(res.online).to.be.true;
                    expect(res).to.have.property('statusCode');
                    expect(res.statusCode).to.be.a('number');
                    expect(res.statusCode).to.be.equal(200);
                    done();
                })
                .catch(done);
        });

        it('should return correct data for netflix.com (no ping)', (done) => {
            domainPing('netflix.com')
                .then((res) => {
                    expect(res).to.be.an('object');
                    expect(res).to.have.property('success');
                    expect(res.success).to.be.true;
                    expect(res).to.have.property('ip');
                    expect(res.ip).to.be.a('string');
                    expect(res).to.have.property('ping');
                    expect(res.ping).to.be.a('boolean');
                    expect(res.ping).to.be.false; // Firewall blocking ICMP
                    expect(res).to.have.property('online');
                    expect(res.online).to.be.a('boolean');
                    expect(res.online).to.be.true;
                    expect(res).to.have.property('statusCode');
                    expect(res.statusCode).to.be.a('number');
                    expect(res.statusCode).to.be.equal(200);
                    done();
                })
                .catch(done);
        });

    });

});
<|endoftext|>


<commit_before>module.exports = function (robot) {
    'use strict'

    var slackmsg = require("./slackMsgs.js");
    var request = require('request');
    var rp = require('request-promise');
    var Trello = require('node-trello');
    var db = require("./mlab-login").db();

    // auth
    var key = process.env.HUBOT_TRELLO_KEY;
    var secret = process.env.HUBOT_TRELLO_OAUTH;
    var token = process.env.HUBOT_TRELLO_TOKEN;
    var trelloAuth = new Trello(key, token);

    var collection = db.collection('trello')

    var cb = `https://andreasbot.herokuapp.com/hubot/trello-token`;
    var t = new Trello.OAuth(key, secret, cb, 'App Name');
    // robot.logger.warning(t);
    var tgr = t.getRequestToken(function (err, data) {
        robot.logger.warning(data)
        collection.insertAsync(data)
            .then(result => robot.logger.info(result))
            .catch(error => robot.logger.error(error));
    })

    robot.router.get('/hubot/trello-token', function (req, res) {
        let args = req.query;
        robot.logger.info(args);
        collection.find().toArray(function (err, result) {
            if (err) throw err;
            let index = Object.keys(result).length;
            //args = result[index];
            console.log(`Result[${index}]: ${args}`);
            //args['oauth_token_secret'] = '8852d39c4874774eb737c77fe1ccef0e';
            t.getAccessToken(args, function (err, data) {
                if (err) throw err;
                robot.logger.info(`getAccessToken: ${data}`);
            })
        });
        res.send(`
Token succesfuly received. You can now close the window.
\n
					<button onclick=window.close()>close</button>`)
    });

    // convert node-trello callbacks to promises
    const Promise = require("bluebird");
    var trello = Promise.promisifyAll(trelloAuth);

    robot.hear(/trello hooks/, function (res) {
        let boardId = 'BE7seI7e';
        let cb_url = 'https://andreasbot.herokuapp.com/hubot/trello-webhooks';
        let args = { description: "my test webhook", callbackURL: cb_url, idModel: '59245663c76f54b975558854' };

        trello.postAsync('/1/webhooks', args).then(function (data) {
            res.send(data)
        }).catch(function (err) {
            res.send();
            robot.logger.error(err.Error)
        })
    })

    robot.on('trello-webhook-event', function (data, res) {

        var room = "random";
        let payload = data.body;
        let type = payload.action.type;
        robot.logger.info(type);
        switch (type) {
            case 'updateList':
                robot.messageRoom(room, `updateList`);
                break;
            default:
                robot.messageRoom(room, `trello-webhook-event`);
                break;
        }
    })

    /*******************************************************************/
    /*                   Slack Buttons Implementation                  */
    /*******************************************************************/

    function sendMessageToSlackResponseURL(responseURL, JSONmessage) {
        var postOptions = {
            uri: responseURL,
            method: 'POST',
            headers: {
                'Content-type': 'application/json'
            },
            json: JSONmessage
        };
        request(postOptions, (error, response, body) => {
            if (error) {
                // handle errors as you see fit
            };
        })
    }

    // trello board
    robot.hear(/trello board/i, function (res_r) {
        // TODO: fetch the board id from other source (env, redis or mongodb)
        let boardId = 'BE7seI7e';
        let args = { fields: "name,url,prefs" };

        trello.get("/1/board/" + boardId, args, function (err, data) {
            if (err) {
                res.send('Error: ' + err);
                robot.logger.error(err);
                return 0;
            }
            // else !err
            let msg = slackmsg.buttons();
            msg.attachments[0].title = `<${data.url}|${data.name}>`;
            msg.attachments[0].title_url = 'www.google.com'
            msg.attachments[0].author_name = 'Board'
            msg.attachments[0].callback_id = `trello_board`;
            msg.attachments[0].color = `${data.prefs.backgroundColor}`;

            // attach the board lists to buttons
            let joinBtn = { "name": "join", "text": "Join", "type": "button", "value": "join" };
            let subBtn = { "name": "sub", "text": "Subscribe", "type": "button", "value": "sub" };
            let starBtn = { "name": "star", "text": "Star", "type": "button", "value": "star" };
            let listsBtn = { "name": "lists", "text": "Lists", "type": "button", "value": "lists" };
            let doneBtn = { "name": "done", "text": "Done", "type": "button", "value": "done", "style": "danger" };
            msg.attachments[0].actions.push(joinBtn);
            msg.attachments[0].actions.push(subBtn);
            msg.attachments[0].actions.push(starBtn);
            msg.attachments[0].actions.push(listsBtn);
            msg.attachments[0].actions.push(doneBtn);

            res_r.send(msg);
        })
    })

    var slackCB = 'slack:msg_action:';

    // responding to 'trello_board' interactive message
    robot.on(slackCB + 'trello_board', function (data, res) {
        robot.logger.info(`robot.on: ${slackCB}trello_board`);
        let btnId = data.actions[0].value;
        let btnName = data.actions[0].name;
        let response_url = data.response_url;
        let msg;

        switch (btnId) {
            case 'join':
                break;
            case 'sub':
                break;
            case 'star':
                break;
            case 'lists':
                res.status(200).end(); // best practice to respond with 200 status
                // get board info to fetch lists
                let boardId = 'BE7seI7e';
                let args = { lists: "all" };
                trello.get("1/board/" + boardId, args, function (err, data) {
                    if (err) {
                        res.send(err);
                        robot.logger.error(err);
                        return;
                    }
                    // else if (!err)
                    // create buttons msg
                    let msg = slackmsg.buttons();
                    msg.text = `*${data.name}* board`;

                    msg.attachments[0].text = `Available lists`;
                    msg.attachments[0].callback_id = `trello_list`;
                    let listsNum = Object.keys(data.lists).length;
                    for (var i = 0; i < listsNum; i++) {
                        // TODO change value to some id or something similar
                        let name = data.lists[i].name;
                        let id = data.lists[i].id;
                        let list = { "name": name, "text": name, "type": "button", "value": id };
                        msg.attachments[0].actions.push(list);
                    }
                    sendMessageToSlackResponseURL(response_url, msg);
                })
                break;
            case 'done':
                //res.status(200).end() // best practice to respond with 200 status
                msg = slackmsg.plainText();
                res.send(msg);
                //sendMessageToSlackResponseURL(response_url, msg);
                // res.send(msg);
                break;
            default:
                //Statements executed when none of the values match the value of the expression
                break;
        }
    })

    // responding to 'trello_list' interactive message
    robot.on(slackCB + 'trello_list', function (data_board, res) {
        let response_url = data_board.response_url;

        res.status(200).end() // best practice to respond with 200 status
        robot.logger.info(`robot.on: ${slackCB}trello_list`);
        let listId = data_board.actions[0].value;
        let listName = data_board.actions[0].name;

        // call function to fetch list - provide list id
        let args = { cards: "all" };
        trello.get("/1/lists/" + listId, args, function (err, data) {
            if (err) {
                robot.logger.error(err);
                res.send(`Error: ${err}`)
                return 0;
            }
            // else !err
            // create buttons msg
            let msg = slackmsg.buttons();
            msg.text = `*${listName}* list`;
            msg.attachments[0].text = `Available Cards`;
            msg.attachments[0].callback_id = `trello_list`;

            let cardsNum = Object.keys(data.cards).length;
            robot.logger.info(`total cards: ${cardsNum}`);
            for (var i = 0; i < cardsNum; i++) {
                let card = data.cards[i].name;
                let cardId = data.cards[i].id;
                let item = { "name": card, "text": card, "type": "button", "value": cardId };
                msg.attachments[0].actions.push(item);
            }

            // respond with information for that list
            sendMessageToSlackResponseURL(response_url, msg);
        })
    })
}
<commit_msg>trello token<commit_after>module.exports = function (robot) {
    'use strict'

    var slackmsg = require("./slackMsgs.js");
    var request = require('request');
    var rp = require('request-promise');
    var Trello = require('node-trello');
    var db = require("./mlab-login").db();

    // auth
    var key = process.env.HUBOT_TRELLO_KEY;
    var secret = process.env.HUBOT_TRELLO_OAUTH;
    var token = process.env.HUBOT_TRELLO_TOKEN;
    var trelloAuth = new Trello(key, token);

    var collection = db.collection('trello')
    const oauth_secrets = {};

    var cb = `https://andreasbot.herokuapp.com/hubot/trello-token`;
    var t = new Trello.OAuth(key, secret, cb, 'App Name');
    // robot.logger.warning(t);
    var tgr = t.getRequestToken(function (err, data) {
        robot.logger.warning(data)
        oauth_secrets = data;
        collection.insertAsync(data)
            .then(result => robot.logger.info(result))
            .catch(error => robot.logger.error(error));
    })

    robot.router.get('/hubot/trello-token', function (req, res) {
        let args = req.query;
        robot.logger.info(oauth_secrets);
        collection.find().toArray(function (err, result) {
            if (err) throw err;
            let index = Object.keys(result).length;
            //args = result[index];
            console.log(`Result[${index}]: ${args}`);
            //args['oauth_token_secret'] = '8852d39c4874774eb737c77fe1ccef0e';
            t.getAccessToken(args, function (err, data) {
                if (err) throw err;
                robot.logger.info(`getAccessToken: ${data}`);
            })
        });
        res.send(`
Token succesfuly received. You can now close the window.
\n
					<button onclick=window.close()>close</button>`)
    });

    // convert node-trello callbacks to promises
    const Promise = require("bluebird");
    var trello = Promise.promisifyAll(trelloAuth);

    robot.hear(/trello hooks/, function (res) {
        let boardId = 'BE7seI7e';
        let cb_url = 'https://andreasbot.herokuapp.com/hubot/trello-webhooks';
        let args = { description: "my test webhook", callbackURL: cb_url, idModel: '59245663c76f54b975558854' };

        trello.postAsync('/1/webhooks', args).then(function (data) {
            res.send(data)
        }).catch(function (err) {
            res.send();
            robot.logger.error(err.Error)
        })
    })

    robot.on('trello-webhook-event', function (data, res) {

        var room = "random";
        let payload = data.body;
        let type = payload.action.type;
        robot.logger.info(type);
        switch (type) {
            case 'updateList':
                robot.messageRoom(room, `updateList`);
                break;
            default:
                robot.messageRoom(room, `trello-webhook-event`);
                break;
        }
    })

    /*******************************************************************/
    /*                   Slack Buttons Implementation                  */
    /*******************************************************************/

    function sendMessageToSlackResponseURL(responseURL, JSONmessage) {
        var postOptions = {
            uri: responseURL,
            method: 'POST',
            headers: {
                'Content-type': 'application/json'
            },
            json: JSONmessage
        };
        request(postOptions, (error, response, body) => {
            if (error) {
                // handle errors as you see fit
            };
        })
    }

    // trello board
    robot.hear(/trello board/i, function (res_r) {
        // TODO: fetch the board id from other source (env, redis or mongodb)
        let boardId = 'BE7seI7e';
        let args = { fields: "name,url,prefs" };

        trello.get("/1/board/" + boardId, args, function (err, data) {
            if (err) {
                res.send('Error: ' + err);
                robot.logger.error(err);
                return 0;
            }
            // else !err
            let msg = slackmsg.buttons();
            msg.attachments[0].title = `<${data.url}|${data.name}>`;
            msg.attachments[0].title_url = 'www.google.com'
            msg.attachments[0].author_name = 'Board'
            msg.attachments[0].callback_id = `trello_board`;
            msg.attachments[0].color = `${data.prefs.backgroundColor}`;

            // attach the board lists to buttons
            let joinBtn = { "name": "join", "text": "Join", "type": "button", "value": "join" };
            let subBtn = { "name": "sub", "text": "Subscribe", "type": "button", "value": "sub" };
            let starBtn = { "name": "star", "text": "Star", "type": "button", "value": "star" };
            let listsBtn = { "name": "lists", "text": "Lists", "type": "button", "value": "lists" };
            let doneBtn = { "name": "done", "text": "Done", "type": "button", "value": "done", "style": "danger" };
            msg.attachments[0].actions.push(joinBtn);
            msg.attachments[0].actions.push(subBtn);
            msg.attachments[0].actions.push(starBtn);
            msg.attachments[0].actions.push(listsBtn);
            msg.attachments[0].actions.push(doneBtn);

            res_r.send(msg);
        })
    })

    var slackCB = 'slack:msg_action:';

    // responding to 'trello_board' interactive message
    robot.on(slackCB + 'trello_board', function (data, res) {
        robot.logger.info(`robot.on: ${slackCB}trello_board`);
        let btnId = data.actions[0].value;
        let btnName = data.actions[0].name;
        let response_url = data.response_url;
        let msg;

        switch (btnId) {
            case 'join':
                break;
            case 'sub':
                break;
            case 'star':
                break;
            case 'lists':
                res.status(200).end(); // best practice to respond with 200 status
                // get board info to fetch lists
                let boardId = 'BE7seI7e';
                let args = { lists: "all" };
                trello.get("1/board/" + boardId, args, function (err, data) {
                    if (err) {
                        res.send(err);
                        robot.logger.error(err);
                        return;
                    }
                    // else if (!err)
                    // create buttons msg
                    let msg = slackmsg.buttons();
                    msg.text = `*${data.name}* board`;

                    msg.attachments[0].text = `Available lists`;
                    msg.attachments[0].callback_id = `trello_list`;
                    let listsNum = Object.keys(data.lists).length;
                    for (var i = 0; i < listsNum; i++) {
                        // TODO change value to some id or something similar
                        let name = data.lists[i].name;
                        let id = data.lists[i].id;
                        let list = { "name": name, "text": name, "type": "button", "value": id };
                        msg.attachments[0].actions.push(list);
                    }
                    sendMessageToSlackResponseURL(response_url, msg);
                })
                break;
            case 'done':
                //res.status(200).end() // best practice to respond with 200 status
                msg = slackmsg.plainText();
                res.send(msg);
                //sendMessageToSlackResponseURL(response_url, msg);
                // res.send(msg);
                break;
            default:
                //Statements executed when none of the values match the value of the expression
                break;
        }
    })

    // responding to 'trello_list' interactive message
    robot.on(slackCB + 'trello_list', function (data_board, res) {
        let response_url = data_board.response_url;

        res.status(200).end() // best practice to respond with 200 status
        robot.logger.info(`robot.on: ${slackCB}trello_list`);
        let listId = data_board.actions[0].value;
        let listName = data_board.actions[0].name;

        // call function to fetch list - provide list id
        let args = { cards: "all" };
        trello.get("/1/lists/" + listId, args, function (err, data) {
            if (err) {
                robot.logger.error(err);
                res.send(`Error: ${err}`)
                return 0;
            }
            // else !err
            // create buttons msg
            let msg = slackmsg.buttons();
            msg.text = `*${listName}* list`;
            msg.attachments[0].text = `Available Cards`;
            msg.attachments[0].callback_id = `trello_list`;

            let cardsNum = Object.keys(data.cards).length;
            robot.logger.info(`total cards: ${cardsNum}`);
            for (var i = 0; i < cardsNum; i++) {
                let card = data.cards[i].name;
                let cardId = data.cards[i].id;
                let item = { "name": card, "text": card, "type": "button", "value": cardId };
                msg.attachments[0].actions.push(item);
            }

            // respond with information for that list
            sendMessageToSlackResponseURL(response_url, msg);
        })
    })
}
<|endoftext|>


<commit_before>import './mc-project-experiments.component';
import './mc-project-experiments-table.component';
import './experiment/move-step.service';
import './experiment/mc-experiment.component';
import './experiment/components/mc-experiment-details.component';
import './experiment/components/mc-experiment-outline.component';
import './experiment/current-step.service';
<commit_msg>Add the experiments service.<commit_after>import './mc-project-experiments.component';
import './mc-project-experiments-table.component';
import './experiment/move-step.service';
import './experiment/mc-experiment.component';
import './experiment/components/mc-experiment-details.component';
import './experiment/components/mc-experiment-outline.component';
import './services/experiments-service.service';
import './experiment/current-step.service';
<|endoftext|>


<commit_before>var armyc2 = armyc2 || {};
armyc2.c2sd = armyc2.c2sd || {};
armyc2.c2sd.graphics2d = armyc2.c2sd.graphics2d || {};
armyc2.c2sd.graphics2d.FontMetrics = function() {
    var _fontRenderContext = null;
    var _font = null;
    if (arguments.length > 0)
        _font = arguments[0];

    var textInfoBuffer = document.createElement('canvas');
    textInfoBuffer.width = 1;
    textInfoBuffer.height = 1;
    this.textInfoContext = textInfoBuffer.getContext('2d');
    this.stringWidth = function(str)
    {
        //return Math.floor(_font.getSize() / 2) * str.length;
        //return (_font.getSize() / 2) * str.length;
        var location=new armyc2.c2sd.renderer.so.Point(0,0);
        var bounds = armyc2.c2sd.renderer.utilities.RendererUtilities.getTextBounds(this.textInfoContext, str, location, undefined);
        var stringWidth=bounds.width;
        return stringWidth;
    };
    this.stringHeight=function(str)
    {
        var location=new armyc2.c2sd.renderer.so.Point(0,0);
        var bounds = armyc2.c2sd.renderer.utilities.RendererUtilities.getTextBounds(this.textInfoContext, str, location, undefined);
        var stringHeight=bounds.height;
        return stringHeight;
    };
    this.getTextBounds=function(str)
    {
        var location=new armyc2.c2sd.renderer.so.Point(0,0);
        var bounds = armyc2.c2sd.renderer.utilities.RendererUtilities.getTextBounds(this.textInfoContext, str, location, undefined);
        return bounds;
    };
    this.getFontRenderContext = function() {
        return _fontRenderContext;
    };

};<commit_msg>changed to stringHeight()<commit_after>var armyc2 = armyc2 || {};
armyc2.c2sd = armyc2.c2sd || {};
armyc2.c2sd.graphics2d = armyc2.c2sd.graphics2d || {};
armyc2.c2sd.graphics2d.FontMetrics = function() {
    var _fontRenderContext = null;
    var _font = null;
    if (arguments.length > 0)
        _font = arguments[0];

    var textInfoBuffer = document.createElement('canvas');
    textInfoBuffer.width = 1;
    textInfoBuffer.height = 1;
    this.textInfoContext = textInfoBuffer.getContext('2d');
    this.stringWidth = function(str)
    {
        //return Math.floor(_font.getSize() / 2) * str.length;
        //return (_font.getSize() / 2) * str.length;
        var location=new armyc2.c2sd.renderer.so.Point(0,0);
        var bounds = armyc2.c2sd.renderer.utilities.RendererUtilities.getTextBounds(this.textInfoContext, str, location, undefined);
        var stringWidth=bounds.width;
        return stringWidth;
    };
    this.stringHeight=function(str)
    {
        //var location=new armyc2.c2sd.renderer.so.Point(0,0);
        //var bounds = armyc2.c2sd.renderer.utilities.RendererUtilities.getTextBounds(this.textInfoContext, str, location, undefined);
        //var stringHeight=bounds.height;

        //getTextBounds does 2 calculations.  Limit to what you need and just get height.
        var font = armyc2.c2sd.renderer.utilities.RendererSettings.getModifierFont();
        var height = armyc2.c2sd.renderer.utilities.RendererUtilities.measureTextHeightWithFontString(font);
        stringHeight = height;

        return stringHeight;
    };
    this.getTextBounds=function(str)
    {
        var location=new armyc2.c2sd.renderer.so.Point(0,0);
        var bounds = armyc2.c2sd.renderer.utilities.RendererUtilities.getTextBounds(this.textInfoContext, str, location, undefined);
        return bounds;
    };
    this.getFontRenderContext = function() {
        return _fontRenderContext;
    };

};<|endoftext|>


<commit_before>'use strict';

module.exports = function(app) {
	// Root routing
	var core = require('../../app/controllers/core.server.controller');
	app.route('/').get(core.index);
};<commit_msg>Support '/dashboard' route<commit_after>'use strict';

module.exports = function(app) {
	// Root routing
	var core = require('../../app/controllers/core.server.controller');
	app.route('/').get(core.index);
	app.route('/dashboard').get(core.index);
};
<|endoftext|>


<commit_before>/**!
 *
 * Copyright (c) 2015-2016 Cisco Systems, Inc. See LICENSE file.
 */

import {assert} from '@ciscospark/test-helper-chai';
import Mercury, {config as mercuryConfig, Socket} from '../..';
import sinon from '@ciscospark/test-helper-sinon';
import MockSpark from '@ciscospark/test-helper-mock-spark';
import MockWebSocket from '../lib/mock-web-socket';
import uuid from 'uuid';
import promiseTick from '../lib/promise-tick';
import lolex from 'lolex';

describe(`plugin-mercury`, () => {
  describe(`Mercury`, () => {
    describe(`Events`, () => {
      let clock,
        mercury,
        mockWebSocket,
        socketOpenStub,
        spark;

      const fakeTestMessage = {
        id: uuid.v4(),
        data: {
          eventType: `fake.test`
        },
        timestamp: Date.now(),
        trackingId: `suffix_${uuid.v4()}_${Date.now()}`
      };

      const statusStartTypingMessage = {
        id: uuid.v4(),
        data: {
          eventType: `status.start_typing`,
          actor: {
            id: `actorId`
          },
          conversationId: uuid.v4()
        },
        timestamp: Date.now(),
        trackingId: `suffix_${uuid.v4()}_${Date.now()}`
      };

      beforeEach(() => {
        clock = lolex.install(Date.now());
      });

      afterEach(() => {
        clock.uninstall();
      });

      beforeEach(() => {
        spark = new MockSpark({
          children: {
            mercury: Mercury
          }
        });

        spark.trackingId = `fakeTrackingId`;
        spark.config.mercury = mercuryConfig.mercury;

        spark.logger = console;

        mockWebSocket = new MockWebSocket();
        sinon.stub(Socket, `getWebSocketConstructor`).returns(() => mockWebSocket);

        const origOpen = Socket.prototype.open;
        socketOpenStub = sinon.stub(Socket.prototype, `open`, function(...args) {
          const promise = Reflect.apply(origOpen, this, args);
          process.nextTick(() => mockWebSocket.open());
          return promise;
        });

        mercury = spark.mercury;
      });

      afterEach(() => {
        if (socketOpenStub) {
          socketOpenStub.restore();
        }

        if (Socket.getWebSocketConstructor.restore) {
          Socket.getWebSocketConstructor.restore();
        }
      });

      describe(`when connected`, () => {
        it(`emits the \`online\` event`, () => {
          const spy = sinon.spy();
          mercury.on(`online`, spy);
          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => assert.called(spy));
        });
      });

      describe(`when disconnected`, () => {
        it(`emits the \`offline\` event`, () => {
          const spy = sinon.spy();
          mercury.on(`offline`, spy);
          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              const promise = mercury.disconnect();
              mockWebSocket.emit(`close`, {
                code: 1000,
                reason: `Done`
              });
              return promise;
            })
            .then(() => assert.calledOnce(spy));
        });

        describe(`when reconnected`, () => {
          it(`emits the \`online\` event`, () => {
            const spy = sinon.spy();
            mercury.on(`online`, spy);

            const promise = mercury.connect();
            mockWebSocket.open();
            return promise
              .then(() => assert.calledOnce(spy))
              .then(() => mockWebSocket.emit(`close`, {code: 1000, reason: `Idle`}))
              .then(() => mercury.connect())
              .then(() => assert.calledTwice(spy));
          });
        });
      });

      describe(`when \`mercury.buffer_state\` is received`, () => {
        // This test is here because the buffer states message may arrive before
        // the mercury Promise resolves.
        it(`gets emitted`, (done) => {
          const bufferStateSpy = sinon.spy();
          const onlineSpy = sinon.spy();

          mercury.on(`event:mercury.buffer_state`, bufferStateSpy);
          mercury.on(`online`, onlineSpy);

          Socket.getWebSocketConstructor.returns(() => {
            process.nextTick(() => {
              assert.isTrue(mercury.connecting, `Mercury is still connecting`);
              assert.isFalse(mercury.connected, `Mercury has not yet connected`);
              assert.notCalled(onlineSpy);
              mockWebSocket.emit(`message`, {
                data: JSON.stringify({
                  data: {
                    eventType: `mercury.buffer_state`
                  }
                })
              });

              promiseTick(1)
                .then(() => {
                  assert.calledOnce(bufferStateSpy);
                  done();
                })
                .catch(done);

            });
            return mockWebSocket;
          });

          // eslint-disable-next-line
          mockWebSocket.send = function noop() {};
          mercury.connect();
        });
      });

      describe(`when a CloseEvent is received`, () => {
        const events = [
          {
            code: 1000,
            reason: `idle`,
            action: `reconnect`
          },
          {
            code: 1000,
            reason: `done (forced)`,
            action: `reconnect`
          },
          {
            code: 1000,
            reason: `pong not received`,
            action: `reconnect`
          },
          {
            code: 1000,
            reason: `pong mismatch`,
            action: `reconnect`
          },
          {
            code: 1000,
            action: `close`
          },
          {
            code: 1003,
            action: `close`
          },
          {
            code: 1001,
            action: `reconnect`
          },
          {
            code: 1005,
            action: `reconnect`
          },
          {
            code: 1006,
            action: `reconnect`
          },
          {
            code: 1011,
            action: `reconnect`
          },
          {
            code: 4000,
            action: `replace`
          },
          {
            action: `close`
          }
        ];

        events.forEach((def) => {
          const {action, reason, code} = def;
          let description;
          if (code && reason) {
            description = `with code \`${code}\` and reason \`${reason}\``;
          }
          else if (code) {
            description = `with code \`${code}\``;
          }
          else if (reason) {
            description = `with reason \`${reason}\``;
          }

          describe(`when an event ${description} is received`, () => {
            it(`takes the ${action} action`, () => {
              if (mercury._reconnect.restore) {
                mercury._reconnect.restore();
              }

              sinon.spy(mercury, `connect`);

              const offlineSpy = sinon.spy();
              const permanentSpy = sinon.spy();
              const transientSpy = sinon.spy();
              const replacedSpy = sinon.spy();

              mercury.on(`offline`, offlineSpy);
              mercury.on(`offline.permanent`, permanentSpy);
              mercury.on(`offline.transient`, transientSpy);
              mercury.on(`offline.replaced`, replacedSpy);

              const promise = mercury.connect();
              mockWebSocket.open();
              return promise
                .then(() => {
                  // Make sure mercury.connect has a call count of zero
                  mercury.connect.reset();

                  mockWebSocket.emit(`close`, {code, reason});
                  return promiseTick(1);
                })
                .then(() => {
                  assert.called(offlineSpy);
                  assert.calledWith(offlineSpy, {code, reason});
                  switch (action) {
                  case `close`:
                    assert.called(permanentSpy);
                    assert.notCalled(transientSpy);
                    assert.notCalled(replacedSpy);
                    break;
                  case `reconnect`:
                    assert.notCalled(permanentSpy);
                    assert.called(transientSpy);
                    assert.notCalled(replacedSpy);
                    break;
                  case `replace`:
                    assert.notCalled(permanentSpy);
                    assert.notCalled(transientSpy);
                    assert.called(replacedSpy);
                    break;
                  default:
                    assert(false, `unreachable code reached`);
                  }
                  assert.isFalse(mercury.connected, `Mercury is not connected`);
                  if (action === `reconnect`) {
                    assert.called(mercury.connect);
                    assert.isTrue(mercury.connecting, `Mercury is connecting`);
                    // Block until reconnect completes so logs don't overlap
                    return mercury.connect();
                  }

                  assert.notCalled(mercury.connect);
                  assert.isFalse(mercury.connecting, `Mercury is not connecting`);
                  return Promise.resolve();
                });
            });
          });
        });
      });

      describe(`when a MessageEvent is received`, () => {
        it(`processes the Event via any autowired event handlers`, () => {
          spark.fake = {
            processTestEvent: sinon.spy()
          };

          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              mockWebSocket.emit(`message`, {data: JSON.stringify(fakeTestMessage)});
              return promiseTick(1);
            })
            .then(() => {
              assert.called(spark.fake.processTestEvent);
            });
        });

        it(`emits the Mercury envelope`, () => {
          const startSpy = sinon.spy();
          const stopSpy = sinon.spy();

          mercury.on(`event:status.start_typing`, startSpy);
          mercury.on(`event:status.stop_typing`, stopSpy);

          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              mockWebSocket.emit(`message`, {data: JSON.stringify(statusStartTypingMessage)});
              return promiseTick(1);
            })
            .then(() => {
              assert.calledOnce(startSpy);
              assert.notCalled(stopSpy);
              assert.calledWith(startSpy, statusStartTypingMessage);
            });
        });

        it(`emits the Mercury envelope named by the Mercury event's eventType`, () => {
          const startSpy = sinon.spy();
          const stopSpy = sinon.spy();

          mercury.on(`event:status.start_typing`, startSpy);
          mercury.on(`event:status.stop_typing`, stopSpy);

          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              mockWebSocket.emit(`message`, {data: JSON.stringify(statusStartTypingMessage)});
              return promiseTick(1);
            })
            .then(() => {
              assert.calledOnce(startSpy);
              assert.notCalled(stopSpy);
              assert.calledWith(startSpy, statusStartTypingMessage);
            });
        });
      });

      describe(`when a sequence number is skipped`, () => {
        it(`emits an event`, () => {
          const spy = sinon.spy();
          mercury.on(`sequence-mismatch`, spy);
          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              mockWebSocket.emit(`message`, {
                data: JSON.stringify({
                  sequenceNumber: 2,
                  id: `mockid`
                })
              });
              mockWebSocket.emit(`message`, {
                data: JSON.stringify({
                  sequenceNumber: 4,
                  id: `mockid`
                })
              });
              assert.called(spy);
            });
        });
      });
    });
  });

  /*
  // On mercury:
  online
  offline
  offline.transient
  offline.permanent
  offline.replaced
  event
  event:locus.participant_joined
  mockWebSocket.connection-failed
  mockWebSocket.sequence-mismatch

  // On spark:
  mercury.online
  mercury.offline
  mercury.offline.transient
  mercury.offline.permanent
  mercury.offline.replaced
  mercury.event
  mercury.event:locus.participant_joined
  mercury.mockWebSocket.connection-failed
  mercury.mockWebSocket.sequence-mismatch

  // TODO go through all it(`emits...`) and make sure corresponding tests are here
  */
});
<commit_msg>test(plugin-mercury): adjust buffer_state test to avoid test cross talk<commit_after>/**!
 *
 * Copyright (c) 2015-2016 Cisco Systems, Inc. See LICENSE file.
 */

import {assert} from '@ciscospark/test-helper-chai';
import Mercury, {config as mercuryConfig, Socket} from '../..';
import sinon from '@ciscospark/test-helper-sinon';
import MockSpark from '@ciscospark/test-helper-mock-spark';
import MockWebSocket from '../lib/mock-web-socket';
import uuid from 'uuid';
import promiseTick from '../lib/promise-tick';
import lolex from 'lolex';
import {wrap} from 'lodash';

describe(`plugin-mercury`, () => {
  describe(`Mercury`, () => {
    describe(`Events`, () => {
      let clock,
        mercury,
        mockWebSocket,
        socketOpenStub,
        spark;

      const fakeTestMessage = {
        id: uuid.v4(),
        data: {
          eventType: `fake.test`
        },
        timestamp: Date.now(),
        trackingId: `suffix_${uuid.v4()}_${Date.now()}`
      };

      const statusStartTypingMessage = {
        id: uuid.v4(),
        data: {
          eventType: `status.start_typing`,
          actor: {
            id: `actorId`
          },
          conversationId: uuid.v4()
        },
        timestamp: Date.now(),
        trackingId: `suffix_${uuid.v4()}_${Date.now()}`
      };

      beforeEach(() => {
        clock = lolex.install(Date.now());
      });

      afterEach(() => {
        clock.uninstall();
      });

      beforeEach(() => {
        spark = new MockSpark({
          children: {
            mercury: Mercury
          }
        });

        spark.trackingId = `fakeTrackingId`;
        spark.config.mercury = mercuryConfig.mercury;

        spark.logger = console;

        mockWebSocket = new MockWebSocket();
        sinon.stub(Socket, `getWebSocketConstructor`).returns(() => mockWebSocket);

        const origOpen = Socket.prototype.open;
        socketOpenStub = sinon.stub(Socket.prototype, `open`, function(...args) {
          const promise = Reflect.apply(origOpen, this, args);
          process.nextTick(() => mockWebSocket.open());
          return promise;
        });

        mercury = spark.mercury;
      });

      afterEach(() => {
        if (socketOpenStub) {
          socketOpenStub.restore();
        }

        if (Socket.getWebSocketConstructor.restore) {
          Socket.getWebSocketConstructor.restore();
        }
      });

      describe(`when connected`, () => {
        it(`emits the \`online\` event`, () => {
          const spy = sinon.spy();
          mercury.on(`online`, spy);
          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => assert.called(spy));
        });
      });

      describe(`when disconnected`, () => {
        it(`emits the \`offline\` event`, () => {
          const spy = sinon.spy();
          mercury.on(`offline`, spy);
          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              const promise = mercury.disconnect();
              mockWebSocket.emit(`close`, {
                code: 1000,
                reason: `Done`
              });
              return promise;
            })
            .then(() => assert.calledOnce(spy));
        });

        describe(`when reconnected`, () => {
          it(`emits the \`online\` event`, () => {
            const spy = sinon.spy();
            mercury.on(`online`, spy);

            const promise = mercury.connect();
            mockWebSocket.open();
            return promise
              .then(() => assert.calledOnce(spy))
              .then(() => mockWebSocket.emit(`close`, {code: 1000, reason: `Idle`}))
              .then(() => mercury.connect())
              .then(() => assert.calledTwice(spy));
          });
        });
      });

      describe(`when \`mercury.buffer_state\` is received`, () => {
        // This test is here because the buffer states message may arrive before
        // the mercury Promise resolves.
        it(`gets emitted`, (done) => {
          const spy = mockWebSocket.send;
          const bufferStateSpy = sinon.spy();
          const onlineSpy = sinon.spy();

          mercury.on(`event:mercury.buffer_state`, bufferStateSpy);
          mercury.on(`online`, onlineSpy);

          Socket.getWebSocketConstructor.returns(() => {
            process.nextTick(() => {
              assert.isTrue(mercury.connecting, `Mercury is still connecting`);
              assert.isFalse(mercury.connected, `Mercury has not yet connected`);
              assert.notCalled(onlineSpy);
              assert.lengthOf(spy.args, 0, `The client has not yet sent the auth message`);
              mockWebSocket.emit(`message`, {
                data: JSON.stringify({
                  data: {
                    eventType: `mercury.buffer_state`
                  }
                })
              });
              assert.lengthOf(spy.args, 0, `The client has not acked the buffer_state message`);

              promiseTick(1)
                .then(() => {
                  assert.calledOnce(bufferStateSpy);
                  return assert.isFulfilled(mercury.connect())
                    .then(() => {
                      assert.lengthOf(spy.args, 3);
                    })
                    .then(done);
                })
                .catch(done);

            });
            return mockWebSocket;
          });

          // Delay send for a tick to ensure the buffer message comes before
          // auth completes.
          mockWebSocket.send = wrap(mockWebSocket.send, function(fn, ...args) {
            process.nextTick(() => {
              Reflect.apply(fn, this, args);
            });
          });
          mercury.connect();
          assert.lengthOf(spy.args, 0);
        });
      });

      describe(`when a CloseEvent is received`, () => {
        const events = [
          {
            code: 1000,
            reason: `idle`,
            action: `reconnect`
          },
          {
            code: 1000,
            reason: `done (forced)`,
            action: `reconnect`
          },
          {
            code: 1000,
            reason: `pong not received`,
            action: `reconnect`
          },
          {
            code: 1000,
            reason: `pong mismatch`,
            action: `reconnect`
          },
          {
            code: 1000,
            action: `close`
          },
          {
            code: 1003,
            action: `close`
          },
          {
            code: 1001,
            action: `reconnect`
          },
          {
            code: 1005,
            action: `reconnect`
          },
          {
            code: 1006,
            action: `reconnect`
          },
          {
            code: 1011,
            action: `reconnect`
          },
          {
            code: 4000,
            action: `replace`
          },
          {
            action: `close`
          }
        ];

        events.forEach((def) => {
          const {action, reason, code} = def;
          let description;
          if (code && reason) {
            description = `with code \`${code}\` and reason \`${reason}\``;
          }
          else if (code) {
            description = `with code \`${code}\``;
          }
          else if (reason) {
            description = `with reason \`${reason}\``;
          }

          describe(`when an event ${description} is received`, () => {
            it(`takes the ${action} action`, () => {
              if (mercury._reconnect.restore) {
                mercury._reconnect.restore();
              }

              sinon.spy(mercury, `connect`);

              const offlineSpy = sinon.spy();
              const permanentSpy = sinon.spy();
              const transientSpy = sinon.spy();
              const replacedSpy = sinon.spy();

              mercury.on(`offline`, offlineSpy);
              mercury.on(`offline.permanent`, permanentSpy);
              mercury.on(`offline.transient`, transientSpy);
              mercury.on(`offline.replaced`, replacedSpy);

              const promise = mercury.connect();
              mockWebSocket.open();
              return promise
                .then(() => {
                  // Make sure mercury.connect has a call count of zero
                  mercury.connect.reset();

                  mockWebSocket.emit(`close`, {code, reason});
                  return promiseTick(1);
                })
                .then(() => {
                  assert.called(offlineSpy);
                  assert.calledWith(offlineSpy, {code, reason});
                  switch (action) {
                  case `close`:
                    assert.called(permanentSpy);
                    assert.notCalled(transientSpy);
                    assert.notCalled(replacedSpy);
                    break;
                  case `reconnect`:
                    assert.notCalled(permanentSpy);
                    assert.called(transientSpy);
                    assert.notCalled(replacedSpy);
                    break;
                  case `replace`:
                    assert.notCalled(permanentSpy);
                    assert.notCalled(transientSpy);
                    assert.called(replacedSpy);
                    break;
                  default:
                    assert(false, `unreachable code reached`);
                  }
                  assert.isFalse(mercury.connected, `Mercury is not connected`);
                  if (action === `reconnect`) {
                    assert.called(mercury.connect);
                    assert.isTrue(mercury.connecting, `Mercury is connecting`);
                    // Block until reconnect completes so logs don't overlap
                    return mercury.connect();
                  }

                  assert.notCalled(mercury.connect);
                  assert.isFalse(mercury.connecting, `Mercury is not connecting`);
                  return Promise.resolve();
                });
            });
          });
        });
      });

      describe(`when a MessageEvent is received`, () => {
        it(`processes the Event via any autowired event handlers`, () => {
          spark.fake = {
            processTestEvent: sinon.spy()
          };

          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              mockWebSocket.emit(`message`, {data: JSON.stringify(fakeTestMessage)});
              return promiseTick(1);
            })
            .then(() => {
              assert.called(spark.fake.processTestEvent);
            });
        });

        it(`emits the Mercury envelope`, () => {
          const startSpy = sinon.spy();
          const stopSpy = sinon.spy();

          mercury.on(`event:status.start_typing`, startSpy);
          mercury.on(`event:status.stop_typing`, stopSpy);

          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              mockWebSocket.emit(`message`, {data: JSON.stringify(statusStartTypingMessage)});
              return promiseTick(1);
            })
            .then(() => {
              assert.calledOnce(startSpy);
              assert.notCalled(stopSpy);
              assert.calledWith(startSpy, statusStartTypingMessage);
            });
        });

        it(`emits the Mercury envelope named by the Mercury event's eventType`, () => {
          const startSpy = sinon.spy();
          const stopSpy = sinon.spy();

          mercury.on(`event:status.start_typing`, startSpy);
          mercury.on(`event:status.stop_typing`, stopSpy);

          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              mockWebSocket.emit(`message`, {data: JSON.stringify(statusStartTypingMessage)});
              return promiseTick(1);
            })
            .then(() => {
              assert.calledOnce(startSpy);
              assert.notCalled(stopSpy);
              assert.calledWith(startSpy, statusStartTypingMessage);
            });
        });
      });

      describe(`when a sequence number is skipped`, () => {
        it(`emits an event`, () => {
          const spy = sinon.spy();
          mercury.on(`sequence-mismatch`, spy);
          const promise = mercury.connect();
          mockWebSocket.open();
          return promise
            .then(() => {
              mockWebSocket.emit(`message`, {
                data: JSON.stringify({
                  sequenceNumber: 2,
                  id: `mockid`
                })
              });
              mockWebSocket.emit(`message`, {
                data: JSON.stringify({
                  sequenceNumber: 4,
                  id: `mockid`
                })
              });
              assert.called(spy);
            });
        });
      });
    });
  });

  /*
  // On mercury:
  online
  offline
  offline.transient
  offline.permanent
  offline.replaced
  event
  event:locus.participant_joined
  mockWebSocket.connection-failed
  mockWebSocket.sequence-mismatch

  // On spark:
  mercury.online
  mercury.offline
  mercury.offline.transient
  mercury.offline.permanent
  mercury.offline.replaced
  mercury.event
  mercury.event:locus.participant_joined
  mercury.mockWebSocket.connection-failed
  mercury.mockWebSocket.sequence-mismatch

  // TODO go through all it(`emits...`) and make sure corresponding tests are here
  */
});
<|endoftext|>


<commit_before>#! /usr/bin/env node
/**
 * @file
 * @description Ralphi Cli for running ralphi api server
 */
'use strict';

const path          = require('path');
const fs            = require('fs');
const program       = require('commander');
const _             = require('lodash');
const joi           = require('joi');
const pino          = require('pino');
const validators    = require('../lib/validators.js');
const server        = require('../lib/server.js');
const db            = require('../lib/db.js');
const serializers   = require('../lib/serializers.js');
const cleanInterval = require('../lib/clean-runner.js');
const buckets       = {};

let logger;

program
  .version('0.0.1')
  .usage('[options] [buckets...]')
  .description('Each bucket is a comma seperated defention in the form of name:String,size:Integer,ttl:Integer')
  .option('-c, --config <file>', 'Config file path (either .js or .json)')
  .option('-i, --clean-interval <n>', 'Clean interval in seconds')
  .option('-p, --port <n>', 'port', 8910)
  .option('-h, --host <ip>', 'host or ip to listen on', 'localhost')
  .option('-l, --log-level <level>', 'log level (debug,info,error,silent)', 'info')
  .parse(process.argv);

process.on('uncaughtException', showUsageOnError);

logger = pino({level: program.logLevel});

logger.serializers = serializers;

const config = {port: program.port, host: program.host, cleanInterval: program.cleanInterval, buckets: program.args};

function parseTTL (ttlString) {
	let ttl = parseInt(ttlString, 10);
	if (!ttl) {
		throw new Error ('ttl must be a positive integer');
	}
	const unit = ttlString.substring(ttl.toString().length) || 's';
	switch (unit) {
		case 'h':
			ttl *= 60;
			/*fallthrough*/
		case 'm':
			ttl *= 60;
			/*fallthrough*/
		case 's':
			ttl *= 1000;
			/*fallthrough*/
		case 'ms':
			return ttl;
		default:
			throw new Error(`Unknown ttl unit ${unit}`);
		}
}

config.buckets.forEach(bucket => {
	const [name, size, ttlString] = bucket.split(',').map(_.trim);

	let ttl;
	try {
		ttl = ttlString && parseTTL(ttlString);
	} catch (e) {
		throw new Error(`${e.message} for bucket ${bucket}`);
	}

	if (!name || !size || !ttl) {
		throw new Error(`Could not parse bucket ${bucket} name:${name} size:${size} ttl:${ttl}`);
	}

	if (buckets[name]) {
		throw new Error(`Bucket ${name} was already defined`);
	}

	buckets[name] = {size: joi.attempt(size, validators.bucketSize, 'bucket size'), ttl};
});

if (program.config) {
	let file = program.config;
	const ext = path.extname(file);
	if (['.js', '.json'].indexOf(ext.toLowerCase()) === -1) {
		throw new Error('Config file should be either .js or .json file');
	}
	if (file[0] !== '/') {
		file = path.join(process.cwd(), file);
	}

	if (!fs.existsSync(file)) {
		throw new Error(`Could not find file ${file}`);
	}

	logger.debug(`loading config ${file}`);
	const fileConf = require(file);
	_.map(fileConf.buckets, (bucket, name) => {
		try {
			buckets[name] = {ttl: parseTTL(bucket.ttl), size: bucket.size};
		} catch (e) {
			throw new Error(`${e.message} for bucket ${name}`);
		}
	});
	Object.assign(config, fileConf);
}

if (_.isEmpty(buckets)) {
	throw new Error('Bucket list is empty');
}

config.port = positiveInt(config.port, 'port');

if (config.cleanInterval !== undefined)  {
	config.cleanInterval = positiveInt(config.cleanInterval, 'clean interval');
	cleanInterval(db, logger, config.cleanInterval * 1000);
}

logger.debug({config, buckets});

server.create(Object.assign(config, {logger, buckets, db: db({buckets, logger})}));

process.removeListener('uncaughtException', showUsageOnError);

function positiveInt (val, name) {
	const int = parseInt(val, 10);
	if (int != val || int < 0) {
		throw new Error(`${name} must be a positive integer (${val})`);
	}
	return int;
}

function showUsageOnError (err) {
	process.stderr.write(err.stack + '\n');
	process.stderr.write(program.helpInformation());
	process.exit(1);
}<commit_msg>Fix(server.cleanInterval) not passing db instance to clean func<commit_after>#! /usr/bin/env node
/**
 * @file
 * @description Ralphi Cli for running ralphi api server
 */
'use strict';

const path          = require('path');
const fs            = require('fs');
const program       = require('commander');
const _             = require('lodash');
const joi           = require('joi');
const pino          = require('pino');
const validators    = require('../lib/validators.js');
const server        = require('../lib/server.js');
const Db            = require('../lib/db.js');
const serializers   = require('../lib/serializers.js');
const cleanInterval = require('../lib/clean-runner.js');
const buckets       = {};

let logger;

program
  .version('0.0.1')
  .usage('[options] [buckets...]')
  .description('Each bucket is a comma seperated defention in the form of name:String,size:Integer,ttl:Integer')
  .option('-c, --config <file>', 'Config file path (either .js or .json)')
  .option('-i, --clean-interval <n>', 'Clean interval in seconds')
  .option('-p, --port <n>', 'port', 8910)
  .option('-h, --host <ip>', 'host or ip to listen on', 'localhost')
  .option('-l, --log-level <level>', 'log level (debug,info,error,silent)', 'info')
  .parse(process.argv);

process.on('uncaughtException', showUsageOnError);

logger = pino({level: program.logLevel});

logger.serializers = serializers;

const config = {port: program.port, host: program.host, cleanInterval: program.cleanInterval, buckets: program.args};

function parseTTL (ttlString) {
	let ttl = parseInt(ttlString, 10);
	if (!ttl) {
		throw new Error ('ttl must be a positive integer');
	}
	const unit = ttlString.substring(ttl.toString().length) || 's';
	switch (unit) {
		case 'h':
			ttl *= 60;
			/*fallthrough*/
		case 'm':
			ttl *= 60;
			/*fallthrough*/
		case 's':
			ttl *= 1000;
			/*fallthrough*/
		case 'ms':
			return ttl;
		default:
			throw new Error(`Unknown ttl unit ${unit}`);
		}
}

config.buckets.forEach(bucket => {
	const [name, size, ttlString] = bucket.split(',').map(_.trim);

	let ttl;
	try {
		ttl = ttlString && parseTTL(ttlString);
	} catch (e) {
		throw new Error(`${e.message} for bucket ${bucket}`);
	}

	if (!name || !size || !ttl) {
		throw new Error(`Could not parse bucket ${bucket} name:${name} size:${size} ttl:${ttl}`);
	}

	if (buckets[name]) {
		throw new Error(`Bucket ${name} was already defined`);
	}

	buckets[name] = {size: joi.attempt(size, validators.bucketSize, 'bucket size'), ttl};
});

if (program.config) {
	let file = program.config;
	const ext = path.extname(file);
	if (['.js', '.json'].indexOf(ext.toLowerCase()) === -1) {
		throw new Error('Config file should be either .js or .json file');
	}
	if (file[0] !== '/') {
		file = path.join(process.cwd(), file);
	}

	if (!fs.existsSync(file)) {
		throw new Error(`Could not find file ${file}`);
	}

	logger.debug(`loading config ${file}`);
	const fileConf = require(file);
	_.map(fileConf.buckets, (bucket, name) => {
		try {
			buckets[name] = {ttl: parseTTL(bucket.ttl), size: bucket.size};
		} catch (e) {
			throw new Error(`${e.message} for bucket ${name}`);
		}
	});
	Object.assign(config, fileConf);
}

if (_.isEmpty(buckets)) {
	throw new Error('Bucket list is empty');
}

config.port = positiveInt(config.port, 'port');

const db = Db({buckets, logger});

if (config.cleanInterval !== undefined)  {
	config.cleanInterval = positiveInt(config.cleanInterval, 'clean interval');
	cleanInterval(db, logger, config.cleanInterval * 1000);
}

logger.debug({config, buckets});

server.create(Object.assign(config, {logger, buckets, db}));

process.removeListener('uncaughtException', showUsageOnError);

function positiveInt (val, name) {
	const int = parseInt(val, 10);
	if (int != val || int < 0) {
		throw new Error(`${name} must be a positive integer (${val})`);
	}
	return int;
}

function showUsageOnError (err) {
	process.stderr.write(err.stack + '\n');
	process.stderr.write(program.helpInformation());
	process.exit(1);
}<|endoftext|>


<commit_before>define(
	['backbone', 'underscore', 'util', 'app'],
	function(Backbone, _, util, app) {
		var DirectoryEntryView = Backbone.View.extend({
			template: _.template(app.templates.filename),

			initialize: function() {
				this.listenTo(this.model, 'change', this.render);
				this.listenTo(this.model, 'change:expanded', this.expandedChange);
			},

			expandedChange: function() {
				if (this.model.get('expanded')) {
					this.$el.addClass('expanded');
					this.directoryView.show();
				} else {
					this.$el.removeClass('expanded');
					this.directoryView.hide();
				}
			},

			events: {
				'click > a[data-type="dir"]': 'clickDir'
			},

			clickDir: function(ev) {
				ev.preventDefault();
				this.model.set('expanded', !this.model.get('expanded'));
			},

			tagName: 'li',

			render: function() {
				// extend directory entry's data with the complete path to it
				var parentPath = this.model.collection.url.replace('/files', '');
				var path = util.joinPaths(parentPath, this.model.get('name'));
				var data = _.extend(this.model.toJSON(), { path: path });

				this.$el.html(this.template(data));

				if (this.directoryView && this.model.get('expanded')) {
					var dirView = this.directoryView.render().$el;
					this.$el.append(dirView);
				}

				return this;
			}
		});

		return DirectoryEntryView;
	}
);
<commit_msg>DirectoryEntryView: extract function for getting the absolute path to this file/dir.<commit_after>define(
	['backbone', 'underscore', 'util', 'app'],
	function(Backbone, _, util, app) {
		var DirectoryEntryView = Backbone.View.extend({
			template: _.template(app.templates.filename),

			initialize: function() {
				this.listenTo(this.model, 'change', this.render);
				this.listenTo(this.model, 'change:expanded', this.expandedChange);
			},

			expandedChange: function() {
				if (this.model.get('expanded')) {
					this.$el.addClass('expanded');
					this.directoryView.show();
				} else {
					this.$el.removeClass('expanded');
					this.directoryView.hide();
				}
			},

			events: {
				'click > a[data-type="dir"]': 'clickDir'
			},

			clickDir: function(ev) {
				ev.preventDefault();
				this.model.set('expanded', !this.model.get('expanded'));
			},

			tagName: 'li',

			getAbsolutePath: function() {
				// extend directory entry's data with the complete path to it
				var parentPath = this.model.collection.url.replace('/files', '');
				var path = util.joinPaths(parentPath, this.model.get('name'));
				return path;
			},

			render: function() {
				var data = _.extend(this.model.toJSON(), { path: this.getAbsolutePath() });

				this.$el.html(this.template(data));

				if (this.directoryView && this.model.get('expanded')) {
					var dirView = this.directoryView.render().$el;
					this.$el.append(dirView);
				}

				return this;
			}
		});

		return DirectoryEntryView;
	}
);
<|endoftext|>