<commit_before>
/**
 * Module dependencies.
 */
var _ = require('underscore')._;

var express = require('express'),
    fs = require('fs');

var app = module.exports = express.createServer();
var assetManager = require('connect-assetmanager');
var io = require('socket.io').listen(app);
var lobbyClass = require('./lib/lobby.js');
var siteConfig = require('./siteConfig.js');
var gzippo = require('gzippo');

var lobby = new lobbyClass.Lobby(io);

// Configuration

var assetManagerGroups = {
  'js': {
    'route': /js\/.*\.js/
    , 'path': './app/'
    , 'dataType': 'javascript'
    , 'files': [
        'lib/jquery.cookie/jquery.cookie.js',
        'lib/underscore.min.js',
        'lib/angular/angular.min.js',
        'js/app.js',
        'js/controllers.js',
        'js/directives.js',
        'js/filters.js',
        'js/services.js'
    ]
  },
  'css': {
    'route': /css\/.*\.css/
    , 'path': './app/'
    , 'dataType': 'css'
    , 'files': [
      'css/bootstrap.min.css',
      'css/app.css'
    ]
  }
}
var assetsManagerMiddleware = assetManager(assetManagerGroups);

app.configure(function(){
  app.set('views', __dirname + '/app');
  app.set('view engine', 'ejs');
  app.set('view options', {
      layout: false
  });
  app.use(express.logger());
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.staticCache());
});

app.configure('development', function(){
  app.use(gzippo.staticGzip(__dirname + '/app'));
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  var oneYear = 31557600000;
  app.use(assetsManagerMiddleware);
  app.use(gzippo.staticGzip(__dirname + '/app', { maxAge: oneYear, clientMaxAge: oneYear }));
  app.use(express.errorHandler());
});

// Template helpers
app.dynamicHelpers({
  'assetsCacheHashes': function(req, res) {
    return assetsManagerMiddleware.cacheHashes;
  }
});

app.get('/', function(req, res) {
  res.render('index.ejs', { siteConfig: siteConfig });
});

app.get('/debug_state', function(req, res) {
  console.log(lobby.rooms);
  res.json(_.map(lobby.rooms, function(room, key) { return room.json() } ));
});

app.get('/:id', function(req, res) {
  if (req.params.id in lobby.rooms) {
    res.render('index.ejs', { siteConfig: siteConfig });
  } else {
    res.redirect('/', { siteConfig: siteConfig });
  }
});

io.configure(function () {
  io.set('transports', ['websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']);
});

io.configure('production', function(){
  io.enable('browser client minification');
  io.enable('browser client etag');
  io.enable('browser client gzip');
  io.set('log level', 1);
});
io.configure('development', function(){
  io.set('log level', 2);
});

var port = process.env.app_port || 5000; // Use the port that Heroku provides or default to 5000
app.listen(port, function() {
  console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});

/* EVENT LISTENERS */

io.sockets.on('connection', function (socket) {

  // console.log("On connect", socket.id);

  socket.on('disconnect', function () {
    // console.log("On disconnect", socket.id);
    lobby.broadcastDisconnect(socket);
  });

  socket.on('create room', function (data, callback) {
    // console.log("on create room", socket.id, data);
    callback(lobby.createRoom());
  });

  socket.on('join room', function (data, callback) {
    // console.log("on join room " + data.roomUrl, socket.id, data);
    var room = lobby.joinRoom(socket, data);
    if(room.error) {
      callback( { error: room.error } );
    } else {
      callback(room.info());
    }
  });

  socket.on('room info', function (data, callback) {
    // console.log("on room info for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    // room = { error: "there was an error" };
    if (room.error) {
      callback( { error: room.error } );
    } else {
      callback(room.info());
    }
  });

  socket.on('set card pack', function (data, cardPack) {
    // console.log("on set card pack " + data.cardPack + " for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    // console.log("error=" + room.error);
    if (!room.error) {
      room.setCardPack(data);
    }
  });

  socket.on('vote', function (data, callback) {
    // console.log("on vote " + data.vote + " received for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.recordVote(socket, data);
      callback( {} );
    }
  });

  socket.on('unvote', function (data, callback) {
    // console.log("omn unvote received for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.destroyVote(socket, data);
      callback( {} );
    }
  });

  socket.on('reset vote', function (data, callback) {
    // console.log("on reset vote  received for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.resetVote();
      callback( {} );
    }
  });

  socket.on('force reveal', function (data, callback) {
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.forceReveal();
      callback( {} );
    }
  });

  socket.on('toggle voter', function (data, callback) {
    // console.log("on toggle voter for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.toggleVoter(data);
      callback( {} );
    }
  });

});<commit_msg>Don't gzip on development - causing some issues.<commit_after>
/**
 * Module dependencies.
 */
var _ = require('underscore')._;

var express = require('express'),
    fs = require('fs');

var app = module.exports = express.createServer();
var assetManager = require('connect-assetmanager');
var io = require('socket.io').listen(app);
var lobbyClass = require('./lib/lobby.js');
var siteConfig = require('./siteConfig.js');
var gzippo = require('gzippo');

var lobby = new lobbyClass.Lobby(io);

// Configuration

var assetManagerGroups = {
  'js': {
    'route': /js\/.*\.js/
    , 'path': './app/'
    , 'dataType': 'javascript'
    , 'files': [
        'lib/jquery.cookie/jquery.cookie.js',
        'lib/underscore.min.js',
        'lib/angular/angular.min.js',
        'js/app.js',
        'js/controllers.js',
        'js/directives.js',
        'js/filters.js',
        'js/services.js'
    ]
  },
  'css': {
    'route': /css\/.*\.css/
    , 'path': './app/'
    , 'dataType': 'css'
    , 'files': [
      'css/bootstrap.min.css',
      'css/app.css'
    ]
  }
}
var assetsManagerMiddleware = assetManager(assetManagerGroups);

app.configure(function(){
  app.set('views', __dirname + '/app');
  app.set('view engine', 'ejs');
  app.set('view options', {
      layout: false
  });
  app.use(express.logger());
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.staticCache());
});

app.configure('development', function(){
  app.use(express.static(__dirname + '/app'));
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  var oneYear = 31557600000;
  app.use(assetsManagerMiddleware);
  app.use(gzippo.staticGzip(__dirname + '/app', { maxAge: oneYear, clientMaxAge: oneYear }));
  app.use(express.errorHandler());
});

// Template helpers
app.dynamicHelpers({
  'assetsCacheHashes': function(req, res) {
    return assetsManagerMiddleware.cacheHashes;
  }
});

app.get('/', function(req, res) {
  res.render('index.ejs', { siteConfig: siteConfig });
});

app.get('/debug_state', function(req, res) {
  console.log(lobby.rooms);
  res.json(_.map(lobby.rooms, function(room, key) { return room.json() } ));
});

app.get('/:id', function(req, res) {
  if (req.params.id in lobby.rooms) {
    res.render('index.ejs', { siteConfig: siteConfig });
  } else {
    res.redirect('/', { siteConfig: siteConfig });
  }
});

io.configure(function () {
  io.set('transports', ['websocket', 'htmlfile', 'xhr-polling', 'jsonp-polling']);
});

io.configure('production', function(){
  io.enable('browser client minification');
  io.enable('browser client etag');
  io.enable('browser client gzip');
  io.set('log level', 1);
});
io.configure('development', function(){
  io.set('log level', 2);
});

var port = process.env.app_port || 5000; // Use the port that Heroku provides or default to 5000
app.listen(port, function() {
  console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
});

/* EVENT LISTENERS */

io.sockets.on('connection', function (socket) {

  // console.log("On connect", socket.id);

  socket.on('disconnect', function () {
    // console.log("On disconnect", socket.id);
    lobby.broadcastDisconnect(socket);
  });

  socket.on('create room', function (data, callback) {
    // console.log("on create room", socket.id, data);
    callback(lobby.createRoom());
  });

  socket.on('join room', function (data, callback) {
    // console.log("on join room " + data.roomUrl, socket.id, data);
    var room = lobby.joinRoom(socket, data);
    if(room.error) {
      callback( { error: room.error } );
    } else {
      callback(room.info());
    }
  });

  socket.on('room info', function (data, callback) {
    // console.log("on room info for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    // room = { error: "there was an error" };
    if (room.error) {
      callback( { error: room.error } );
    } else {
      callback(room.info());
    }
  });

  socket.on('set card pack', function (data, cardPack) {
    // console.log("on set card pack " + data.cardPack + " for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    // console.log("error=" + room.error);
    if (!room.error) {
      room.setCardPack(data);
    }
  });

  socket.on('vote', function (data, callback) {
    // console.log("on vote " + data.vote + " received for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.recordVote(socket, data);
      callback( {} );
    }
  });

  socket.on('unvote', function (data, callback) {
    // console.log("omn unvote received for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.destroyVote(socket, data);
      callback( {} );
    }
  });

  socket.on('reset vote', function (data, callback) {
    // console.log("on reset vote  received for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.resetVote();
      callback( {} );
    }
  });

  socket.on('force reveal', function (data, callback) {
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.forceReveal();
      callback( {} );
    }
  });

  socket.on('toggle voter', function (data, callback) {
    // console.log("on toggle voter for " + data.roomUrl, socket.id, data);
    var room = lobby.getRoom(data.roomUrl);
    if (room.error) {
      callback( { error: room.error });
    } else {
      room.toggleVoter(data);
      callback( {} );
    }
  });

});<|endoftext|>


<commit_before>var camp = require('camp').start({
  port: process.env.PORT||+process.argv[2]||80
});
var https = require('https');
var badge = require('./badge.js');
var svg2img = require('./svg-to-img.js');
var serverStartTime = new Date((new Date()).toGMTString());

// Travis integration.
camp.route(/^\/travis\/(.*)\.(svg|png|gif|jpg)$/,
function(data, match, end, ask) {
  var userRepo = match[1];  // eg, `joyent/node`.
  var format = match[2];
  var apiUrl = 'https://api.travis-ci.org/repositories/' + userRepo + '.json';
  var badgeData = {text:['build', 'n/a'], colorscheme:'lightgrey'};
  https.get(apiUrl, function(res) {
    var buffer = '';
    res.on('data', function(chunk) { buffer += ''+chunk; });
    res.on('end', function(chunk) {
      if (chunk) { buffer += ''+chunk; }
      try {
        var data = JSON.parse(buffer);
      } catch(e) {
        badgeData.text[1] = 'invalid';
        badge(badgeData, makeSend(format, ask.res, end));
        return;
      }
      if (data.last_build_status === 0) {
        badgeData.text[1] = 'passing';
        badgeData.colorscheme = 'green';
      } else if (data.last_build_status === 1) {
        badgeData.text[1] = 'failing';
        badgeData.colorscheme = 'red';
      } else if (data.last_build_status === null) {
        badgeData.text[1] = 'pending';
        badgeData.colorscheme = 'yellow';
      } else {
        badgeData.text[1] = 'n/a';
        badgeData.colorscheme = 'lightgrey';
      }
      badge(badgeData, makeSend(format, ask.res, end));
    });
  }).on('error', function(e) {
    badgeData.text[1] = 'inaccessible';
    badge(badgeData, makeSend(format, ask.res, end));
  });
});

// Gittip integration.
camp.route(/^\/gittip\/(.*)\.(svg|png|gif|jpg)$/,
function(data, match, end, ask) {
  var user = match[1];  // eg, `JSFiddle`.
  var format = match[2];
  var apiUrl = 'https://www.gittip.com/' + user + '/public.json';
  var badgeData = {text:['tips', 'n/a'], colorscheme:'lightgrey'};
  https.get(apiUrl, function(res) {
    var buffer = '';
    res.on('data', function(chunk) { buffer += ''+chunk; });
    res.on('end', function(chunk) {
      if (chunk) { buffer += ''+chunk; }
      try {
        var data = JSON.parse(buffer);
        var money = parseInt(data.receiving);
      } catch(e) {
        badgeData.text[1] = 'invalid';
        badge(badgeData, makeSend(format, ask.res, end));
        return;
      }
      badgeData.text[1] = '$' + money + ' /week';
      if (money === 0) {
        badgeData.colorscheme = 'red';
      } else if (money < 10) {
        badgeData.colorscheme = 'yellow';
      } else if (money < 100) {
        badgeData.colorscheme = 'yellowgreen';
      } else {
        badgeData.colorscheme = 'green';
      }
      badge(badgeData, makeSend(format, ask.res, end));
    });
  }).on('error', function(e) {
    badgeData.text[1] = 'inaccessible';
    badge(badgeData, makeSend(format, ask.res, end));
  });
});

// Coveralls integration.
camp.route(/^\/coveralls\/(.*)\.(svg|png|gif|jpg)$/,
function(data, match, end, ask) {
  var userRepo = match[1];  // eg, `jekyll/jekyll`.
  var format = match[2];
  var apiUrl = 'https://coveralls.io/repos/' + userRepo + '/badge.png?branch=master';
  var badgeData = {text:['coverage', 'n/a'], colorscheme:'lightgrey'};
  https.get(apiUrl, function(res) {
    // We should get a 302. Look inside the Location header.
    var buffer = res.headers.location;
    if (!buffer) {
      badgeData.text[1] = 'invalid';
      badge(badgeData, makeSend(format, ask.res, end));
      return;
    }
    try {
      var score = buffer.split('_')[1].split('.')[0];
      var percentage = parseInt(score);
      if (percentage !== percentage) {
        // It is NaN, treat it as unknown.
        badgeData.text[1] = 'unknown';
        badge(badgeData, makeSend(format, ask.res, end));
        return;
      }
    } catch(e) {
      badgeData.text[1] = 'malformed';
      badge(badgeData, makeSend(format, ask.res, end));
      return;
    }
    badgeData.text[1] = score + '%';
    if (percentage < 80) {
      badgeData.colorscheme = 'red';
    } else if (percentage < 90) {
      badgeData.colorscheme = 'yellow';
    } else {
      badgeData.colorscheme = 'green';
    }
    badge(badgeData, makeSend(format, ask.res, end));
  }).on('error', function(e) {
    badgeData.text[1] = 'inaccessible';
    badge(badgeData, makeSend(format, ask.res, end));
  });
});

// Any badge.
camp.route(/^\/:(([^-]|--)+)-(([^-]|--)+)-(([^-]|--)+)\.(svg|png|gif|jpg)$/,
function(data, match, end, ask) {
  var subject = escapeFormat(match[1]);
  var status = escapeFormat(match[3]);
  var color = escapeFormat(match[5]);
  var format = match[7];

  // Cache management.
  var cacheDuration = (3600*24*1)|0;  // 1 day.
  ask.res.setHeader('Cache-Control', 'public, max-age=' + cacheDuration);
  if (+(new Date(ask.req.headers['if-modified-since'])) >= +serverStartTime) {
    ask.res.statusCode = 304;
    ask.res.end();  // not modified.
    return;
  }
  ask.res.setHeader('Last-Modified', serverStartTime.toGMTString());

  // Badge creation.
  try {
    var badgeData = {text: [subject, status]};
    if (sixHex(color)) {
      badgeData.colorB = '#' + color;
    } else {
      badgeData.colorscheme = color;
    }
    badge(badgeData, makeSend(format, ask.res, end));
  } catch(e) {
    badge({text: ['error', 'bad badge'], colorscheme: 'red'},
      makeSend(format, ask.res, end));
  }
});

// Escapes `t` using the format specified in
// <https://github.com/espadrine/gh-badges/issues/12#issuecomment-31518129>
function escapeFormat(t) {
  return t
    // Inline single underscore.
    .replace(/([^_])_([^_])/g, '$1 $2')
    // Leading or trailing underscore.
    .replace(/([^_])_$/, '$1 ').replace(/^_([^_])/, ' $1')
    // Double underscore and double dash.
    .replace(/__/g, '_').replace(/--/g, '-');
}

function sixHex(s) { return /^[0-9a-fA-F]{6}$/.test(s); }

function makeSend(format, askres, end) {
  if (format === 'svg') {
    return function(res) { sendSVG(res, askres, end); };
  } else {
    return function(res) { sendOther(format, res, askres, end); };
  }
}

function sendSVG(res, askres, end) {
  askres.setHeader('Content-Type', 'image/svg+xml');
  end(null, {template: streamFromString(res)});
}

function sendOther(format, res, askres, end) {
  askres.setHeader('Content-Type', 'image/' + format);
  svg2img(res, format, askres);
}

var stream = require('stream');
function streamFromString(str) {
  var newStream = new stream.Readable();
  newStream._read = function() { newStream.push(str); newStream.push(null); };
  return newStream;
}
<commit_msg>server: Send SVG images as UTF-8<commit_after>var camp = require('camp').start({
  port: process.env.PORT||+process.argv[2]||80
});
var https = require('https');
var badge = require('./badge.js');
var svg2img = require('./svg-to-img.js');
var serverStartTime = new Date((new Date()).toGMTString());

// Travis integration.
camp.route(/^\/travis\/(.*)\.(svg|png|gif|jpg)$/,
function(data, match, end, ask) {
  var userRepo = match[1];  // eg, `joyent/node`.
  var format = match[2];
  var apiUrl = 'https://api.travis-ci.org/repositories/' + userRepo + '.json';
  var badgeData = {text:['build', 'n/a'], colorscheme:'lightgrey'};
  https.get(apiUrl, function(res) {
    var buffer = '';
    res.on('data', function(chunk) { buffer += ''+chunk; });
    res.on('end', function(chunk) {
      if (chunk) { buffer += ''+chunk; }
      try {
        var data = JSON.parse(buffer);
      } catch(e) {
        badgeData.text[1] = 'invalid';
        badge(badgeData, makeSend(format, ask.res, end));
        return;
      }
      if (data.last_build_status === 0) {
        badgeData.text[1] = 'passing';
        badgeData.colorscheme = 'green';
      } else if (data.last_build_status === 1) {
        badgeData.text[1] = 'failing';
        badgeData.colorscheme = 'red';
      } else if (data.last_build_status === null) {
        badgeData.text[1] = 'pending';
        badgeData.colorscheme = 'yellow';
      } else {
        badgeData.text[1] = 'n/a';
        badgeData.colorscheme = 'lightgrey';
      }
      badge(badgeData, makeSend(format, ask.res, end));
    });
  }).on('error', function(e) {
    badgeData.text[1] = 'inaccessible';
    badge(badgeData, makeSend(format, ask.res, end));
  });
});

// Gittip integration.
camp.route(/^\/gittip\/(.*)\.(svg|png|gif|jpg)$/,
function(data, match, end, ask) {
  var user = match[1];  // eg, `JSFiddle`.
  var format = match[2];
  var apiUrl = 'https://www.gittip.com/' + user + '/public.json';
  var badgeData = {text:['tips', 'n/a'], colorscheme:'lightgrey'};
  https.get(apiUrl, function(res) {
    var buffer = '';
    res.on('data', function(chunk) { buffer += ''+chunk; });
    res.on('end', function(chunk) {
      if (chunk) { buffer += ''+chunk; }
      try {
        var data = JSON.parse(buffer);
        var money = parseInt(data.receiving);
      } catch(e) {
        badgeData.text[1] = 'invalid';
        badge(badgeData, makeSend(format, ask.res, end));
        return;
      }
      badgeData.text[1] = '$' + money + ' /week';
      if (money === 0) {
        badgeData.colorscheme = 'red';
      } else if (money < 10) {
        badgeData.colorscheme = 'yellow';
      } else if (money < 100) {
        badgeData.colorscheme = 'yellowgreen';
      } else {
        badgeData.colorscheme = 'green';
      }
      badge(badgeData, makeSend(format, ask.res, end));
    });
  }).on('error', function(e) {
    badgeData.text[1] = 'inaccessible';
    badge(badgeData, makeSend(format, ask.res, end));
  });
});

// Coveralls integration.
camp.route(/^\/coveralls\/(.*)\.(svg|png|gif|jpg)$/,
function(data, match, end, ask) {
  var userRepo = match[1];  // eg, `jekyll/jekyll`.
  var format = match[2];
  var apiUrl = 'https://coveralls.io/repos/' + userRepo + '/badge.png?branch=master';
  var badgeData = {text:['coverage', 'n/a'], colorscheme:'lightgrey'};
  https.get(apiUrl, function(res) {
    // We should get a 302. Look inside the Location header.
    var buffer = res.headers.location;
    if (!buffer) {
      badgeData.text[1] = 'invalid';
      badge(badgeData, makeSend(format, ask.res, end));
      return;
    }
    try {
      var score = buffer.split('_')[1].split('.')[0];
      var percentage = parseInt(score);
      if (percentage !== percentage) {
        // It is NaN, treat it as unknown.
        badgeData.text[1] = 'unknown';
        badge(badgeData, makeSend(format, ask.res, end));
        return;
      }
    } catch(e) {
      badgeData.text[1] = 'malformed';
      badge(badgeData, makeSend(format, ask.res, end));
      return;
    }
    badgeData.text[1] = score + '%';
    if (percentage < 80) {
      badgeData.colorscheme = 'red';
    } else if (percentage < 90) {
      badgeData.colorscheme = 'yellow';
    } else {
      badgeData.colorscheme = 'green';
    }
    badge(badgeData, makeSend(format, ask.res, end));
  }).on('error', function(e) {
    badgeData.text[1] = 'inaccessible';
    badge(badgeData, makeSend(format, ask.res, end));
  });
});

// Any badge.
camp.route(/^\/:(([^-]|--)+)-(([^-]|--)+)-(([^-]|--)+)\.(svg|png|gif|jpg)$/,
function(data, match, end, ask) {
  var subject = escapeFormat(match[1]);
  var status = escapeFormat(match[3]);
  var color = escapeFormat(match[5]);
  var format = match[7];

  // Cache management.
  var cacheDuration = (3600*24*1)|0;  // 1 day.
  ask.res.setHeader('Cache-Control', 'public, max-age=' + cacheDuration);
  if (+(new Date(ask.req.headers['if-modified-since'])) >= +serverStartTime) {
    ask.res.statusCode = 304;
    ask.res.end();  // not modified.
    return;
  }
  ask.res.setHeader('Last-Modified', serverStartTime.toGMTString());

  // Badge creation.
  try {
    var badgeData = {text: [subject, status]};
    if (sixHex(color)) {
      badgeData.colorB = '#' + color;
    } else {
      badgeData.colorscheme = color;
    }
    badge(badgeData, makeSend(format, ask.res, end));
  } catch(e) {
    badge({text: ['error', 'bad badge'], colorscheme: 'red'},
      makeSend(format, ask.res, end));
  }
});

// Escapes `t` using the format specified in
// <https://github.com/espadrine/gh-badges/issues/12#issuecomment-31518129>
function escapeFormat(t) {
  return t
    // Inline single underscore.
    .replace(/([^_])_([^_])/g, '$1 $2')
    // Leading or trailing underscore.
    .replace(/([^_])_$/, '$1 ').replace(/^_([^_])/, ' $1')
    // Double underscore and double dash.
    .replace(/__/g, '_').replace(/--/g, '-');
}

function sixHex(s) { return /^[0-9a-fA-F]{6}$/.test(s); }

function makeSend(format, askres, end) {
  if (format === 'svg') {
    return function(res) { sendSVG(res, askres, end); };
  } else {
    return function(res) { sendOther(format, res, askres, end); };
  }
}

function sendSVG(res, askres, end) {
  askres.setHeader('Content-Type', 'image/svg+xml;charset=utf-8');
  end(null, {template: streamFromString(res)});
}

function sendOther(format, res, askres, end) {
  askres.setHeader('Content-Type', 'image/' + format);
  svg2img(res, format, askres);
}

var stream = require('stream');
function streamFromString(str) {
  var newStream = new stream.Readable();
  newStream._read = function() { newStream.push(str); newStream.push(null); };
  return newStream;
}
<|endoftext|>


<commit_before>"use strict";

var fs = require('fs');
var nconf = require('nconf');
var path = require('path');
var _ = require('lodash');

var Saver = require('./saver.js');

var config_file = "config.json";

var baseDir;
var loadedData = [];
var url_opts = {};

var init = function(_path, cb) {
    baseDir = path.resolve(_path);
    console.log("working from " + baseDir);
    reload(cb);
};

var updatePackage = function(cb) {
    var Package = require("./package.js");

    var source = getSource();
    console.log("source", source);

    var p = new Package({repo:source.repo, updated_at:source.updated_at, dest:defaultSaversDir()});
    p.checkLatestRelease(cb);
};

var reload = function(cb) {
    var configPath = baseDir + "/" + config_file;

    console.log("baseDir: " + path);
    // create our main directory
    if ( ! fs.existsSync(baseDir) ) {
        console.log("creating " + baseDir);
        fs.mkdirSync(baseDir);
    }

    // create a folder for the actual screensavers
    // @todo multiple folder support?
    let saversDir = defaultSaversDir();

    if ( ! fs.existsSync(saversDir) ) {
        console.log("create: " + saversDir);
        fs.mkdirSync(saversDir);
    }
    else {
        console.log(saversDir + " already exists");
    }

    // specify config path
    console.log("load config from " + configPath);
    nconf.file({
        file: configPath
    });

    ensureDefaults();

    console.log("update package");

    updatePackage(function(data) {
        console.log("UPDATED!", data);

        if ( data.downloaded == true ) {
//            setConfig('source:hash', data.etag);
            setConfig('source:updated_at', data.updated_at);
        }

        var current = nconf.get('saver');
        console.log("CURRENT: " + current);
        if ( current === undefined || getCurrentData() === undefined ) {
            console.log("creating config defaults");
            listAll(function(data) {
                console.log("listall");
                console.log(data);
                if ( data.length > 0 ) {
                    console.log("setting default saver to first in list " + data[0].key);
                    setConfig('saver', data[0].key);
                }

                write(cb);
            }, true);
        }
        else {
            write(function() {
                listAll(cb);
            });
        }
    });
};

var defaultSaversDir = function() {
    return baseDir + "/savers";
};

/**
 * setup some reasonable defaults
 */
var ensureDefaults = function() {
    var source = nconf.get('source');
    if ( source === undefined ) {
        console.log("add default source");
        setConfig('source',{
            repo:'muffinista/before-dawn-screensavers',
            hash: ''
        });
    }

    // //
    // // copy our default set of screensavers into the app directory
    // //
    // // @todo maybe only do this once or even not at all
    // var src = undefined;
    // if ( fs.existsSync(__dirname + "/savers") ) {
    //     src = __dirname + "/savers";
    // }
    // else if ( fs.existsSync(__dirname + "/../savers") ) {
    //     src = __dirname + "/../savers";
    // }
};

/**
 * look up a screensaver by key, and return it
 */
var getByKey = function(key) {
    var result = _.find(loadedData, function(obj) {
        return obj.key === key;
    });
    console.log("getByKey: " + key);
    console.log(result);
    return result;
};

/**
 * return the key of the current screensaver
 */
var getCurrent = function() {
    return nconf.get('saver');
};

/**
 * return the object/data of the current screensaver
 */
var getCurrentData = function() {
    var key = nconf.get('saver');
    return getByKey(key);
};

/**
 * return the URL of a zip file that is the source we will check to update our screensavers
 */
var getSource = function() {
    return nconf.get('source');
};
var setSource = function(x) {
    if ( x !== getSource()["repo"] ) {
        return nconf.set('source', {
            repo: x
        });
    }
    else {
        return nconf.get('source');
    }
};

var getLocalSources = function() {
    return nconf.get('localSources') || [];
};
var setLocalSources = function(x) {
    return nconf.set('localSources', x);
};

/**
 * set config var k to value v
 */
var setConfig = function(k, v) {
    nconf.set(k, v);
    console.log("set "+ k + " to " + v);
};

/**
 * set current screensaver key
 */
var setCurrent = function(x, opts) {
    setConfig('saver', x);

    if ( typeof(opts) !== "undefined" ) {
        setOptions(opts, x);
    }
};

var setDelay = function(x) {
    setConfig('delay', x);
};

var setLock = function(x) {
    setConfig('lock', x);
};

var getDelay = function() {
    return nconf.get('delay') || 15;
};

var getLock = function() {
    return nconf.get('lock') || false;
};

/**
 * set options for the specified screensaver
 */
var setOptions = function(opts, s) {
    var key;
    if ( typeof(s) === "undefined" ) {
        s = getCurrent();
    }
    key = "options:" + s;
    console.log("SET OPTIONS", key, opts);
    setConfig(key, opts);
};

var getOptions = function(name) {
    if ( typeof(name) === "undefined" ) {
        name = getCurrent();
    }
    var key = "options:" + name;
    console.log("GET OPTIONS " + key);
    var result = nconf.get(key) || {};

    return result;
};

/**
 * recursively parse through a directory structure
 *  @see http://stackoverflow.com/questions/2727167/getting-all-filenames-in-a-directory-with-node-js
 */
var walk = function(currentDirPath, callback) {
    var fs = require('fs'), path = require('path');
    fs.readdirSync(currentDirPath).forEach(function(name) {
        var filePath = path.join(currentDirPath, name);
        var stat = fs.statSync(filePath);
        if (stat.isFile()) {
            callback(filePath, stat);
        } else if (stat.isDirectory()) {
            walk(filePath, callback);
        }
    });
};

/**
 * search for all screensavers we can find on the filesystem. if cb is specified,
 * call it with data when done. if reload == true, don't use cached data.
 */
var listAll = function(cb) {
    var dir = require('node-dir');

    var root = baseDir + '/savers/';
    var folders = [root].concat( getLocalSources() );

    console.log("MY FOLDERS", folders);

    loadedData = [];

    folders.forEach( function ( src ) {
        console.log("let's walk " + src);
        walk(src, function(f, stat) {
            if ( f.match(/saver.json$/) ) {
                var content = fs.readFileSync( f );
                var contents = JSON.parse(content);

                var stub = path.dirname(f);
                console.log("STUB: " + stub);
                contents.key = stub + "/" + contents.source;

                console.log("KEY: " + contents.key);

                // allow for a specified URL -- this way you could create a screensaver
                // that pointed to a remote URL
                if ( typeof(contents.url) === "undefined" ) {
                    contents.url = 'file://' + contents.key;
                }

                contents.settings = getOptions(contents.key);
                console.log("OPTIONS", contents.settings);

                var s = new Saver(contents);

                loadedData.push(s);
            }
        });
    });

    if ( typeof(cb) !== "undefined" ) {
        cb(loadedData);
    }

    return loadedData;
};

var findScreensavers = function(root) {
    console.log("let's walk " + root);
    walk(root, function(f, stat) {
        if ( f.match(/saver.json$/) ) {
            var content = fs.readFileSync( f );
            var contents = JSON.parse(content);

            var stub = path.dirname(f);
            console.log("STUB: " + stub);
            contents.key = stub + "/" + contents.source;

            console.log("KEY: " + contents.key);

            // allow for a specified URL -- this way you could create a screensaver
            // that pointed to a remote URL
            if ( typeof(contents.url) === "undefined" ) {
                contents.url = 'file://' + contents.key;
            }

            contents.settings = getOptions(contents.key);
            console.log("OPTIONS", contents.settings);

            var s = new Saver(contents);

            loadedData.push(s);
        }
    });
};

/**
 * get a URL we can use to render current screensaver. if opts is passed in, use them
 * when generating URL. otherwise use our global URL options
 */
var getCurrentUrl = function(opts) {
    var s = getCurrentData();
    return s.getUrl(opts);
};

/**
 * return URL of the screensaver matching key
 */
var getUrl = function(key) {
    var url = 'file://' + baseDir + '/savers/';
    if ( typeof(key) === "undefined" ) {
        key = getCurrent();
    }
    url = url + key;

    return url;
};

var write = function(cb) {
    var configPath = baseDir + "/" + config_file;
    console.log("write config to " + configPath);
    nconf.save(cb);
};

exports.init = init;
exports.reload = reload;
exports.getByKey = getByKey;
exports.getCurrent = getCurrent;
exports.getSource = getSource;
exports.setSource = setSource;
exports.getLocalSources = getLocalSources;
exports.setLocalSources = setLocalSources;
exports.getCurrentData = getCurrentData;
exports.setCurrent = setCurrent;
exports.setOptions = setOptions;
exports.setDelay = setDelay;
exports.setLock = setLock;
exports.getDelay = getDelay;
exports.getLock = getLock;
exports.getOptions = getOptions;
exports.listAll = listAll;
exports.getCurrentUrl = getCurrentUrl;
exports.getUrl = getUrl;
exports.loadedData = loadedData;
exports.write = write;
<commit_msg>cleanup<commit_after>"use strict";

var fs = require('fs');
var nconf = require('nconf');
var path = require('path');
var _ = require('lodash');

var Saver = require('./saver.js');

var config_file = "config.json";

var baseDir;
var loadedData = [];
var url_opts = {};

var init = function(_path, cb) {
    baseDir = path.resolve(_path);
    console.log("working from " + baseDir);
    reload(cb);
};

var updatePackage = function(cb) {
    var Package = require("./package.js");

    var source = getSource();
    console.log("source", source);

    var p = new Package({repo:source.repo, updated_at:source.updated_at, dest:defaultSaversDir()});
    p.checkLatestRelease(cb);
};

var reload = function(cb) {
    var configPath = baseDir + "/" + config_file;

    console.log("baseDir: " + path);
    // create our main directory
    if ( ! fs.existsSync(baseDir) ) {
        console.log("creating " + baseDir);
        fs.mkdirSync(baseDir);
    }

    // create a folder for the actual screensavers
    // @todo multiple folder support?
    let saversDir = defaultSaversDir();

    if ( ! fs.existsSync(saversDir) ) {
        console.log("create: " + saversDir);
        fs.mkdirSync(saversDir);
    }
    else {
        console.log(saversDir + " already exists");
    }

    // specify config path
    console.log("load config from " + configPath);
    nconf.file({
        file: configPath
    });

    ensureDefaults();

    console.log("update package");

    updatePackage(function(data) {
        console.log("UPDATED!", data);

        if ( data.downloaded == true ) {
//            setConfig('source:hash', data.etag);
            setConfig('source:updated_at', data.updated_at);
        }

        var current = nconf.get('saver');
        console.log("CURRENT: " + current);
        if ( current === undefined || getCurrentData() === undefined ) {
            console.log("creating config defaults");
            listAll(function(data) {
                console.log("listall");
                console.log(data);
                if ( data.length > 0 ) {
                    console.log("setting default saver to first in list " + data[0].key);
                    setConfig('saver', data[0].key);
                }

                write(cb);
            }, true);
        }
        else {
            write(function() {
                listAll(cb);
            });
        }
    });
};

var defaultSaversDir = function() {
    return baseDir + "/savers";
};

/**
 * setup some reasonable defaults
 */
var ensureDefaults = function() {
    var source = nconf.get('source');
    if ( source === undefined ) {
        console.log("add default source");
        setConfig('source',{
            repo:'muffinista/before-dawn-screensavers',
            hash: ''
        });
    }

    // //
    // // copy our default set of screensavers into the app directory
    // //
    // // @todo maybe only do this once or even not at all
    // var src = undefined;
    // if ( fs.existsSync(__dirname + "/savers") ) {
    //     src = __dirname + "/savers";
    // }
    // else if ( fs.existsSync(__dirname + "/../savers") ) {
    //     src = __dirname + "/../savers";
    // }
};

/**
 * look up a screensaver by key, and return it
 */
var getByKey = function(key) {
    var result = _.find(loadedData, function(obj) {
        return obj.key === key;
    });
    console.log("getByKey: " + key);
    console.log(result);
    return result;
};

/**
 * return the key of the current screensaver
 */
var getCurrent = function() {
    return nconf.get('saver');
};

/**
 * return the object/data of the current screensaver
 */
var getCurrentData = function() {
    var key = nconf.get('saver');
    return getByKey(key);
};

/**
 * return the URL of a zip file that is the source we will check to update our screensavers
 */
var getSource = function() {
    return nconf.get('source');
};
var setSource = function(x) {
    if ( x !== getSource()["repo"] ) {
        return nconf.set('source', {
            repo: x
        });
    }
    else {
        return nconf.get('source');
    }
};

var getLocalSources = function() {
    return nconf.get('localSources') || [];
};
var setLocalSources = function(x) {
    return nconf.set('localSources', x);
};

/**
 * set config var k to value v
 */
var setConfig = function(k, v) {
    nconf.set(k, v);
    console.log("set "+ k + " to " + v);
};

/**
 * set current screensaver key
 */
var setCurrent = function(x, opts) {
    setConfig('saver', x);

    if ( typeof(opts) !== "undefined" ) {
        setOptions(opts, x);
    }
};

var setDelay = function(x) {
    setConfig('delay', x);
};

var setLock = function(x) {
    setConfig('lock', x);
};

var getDelay = function() {
    return nconf.get('delay') || 15;
};

var getLock = function() {
    return nconf.get('lock') || false;
};

/**
 * set options for the specified screensaver
 */
var setOptions = function(opts, s) {
    var key;
    if ( typeof(s) === "undefined" ) {
        s = getCurrent();
    }
    key = "options:" + s;
    console.log("SET OPTIONS", key, opts);
    setConfig(key, opts);
};

var getOptions = function(name) {
    if ( typeof(name) === "undefined" ) {
        name = getCurrent();
    }
    var key = "options:" + name;
    console.log("GET OPTIONS " + key);
    var result = nconf.get(key) || {};

    return result;
};

/**
 * recursively parse through a directory structure
 *  @see http://stackoverflow.com/questions/2727167/getting-all-filenames-in-a-directory-with-node-js
 */
var walk = function(currentDirPath, callback) {
    var fs = require('fs'), path = require('path');
    fs.readdirSync(currentDirPath).forEach(function(name) {
        var filePath = path.join(currentDirPath, name);
        var stat = fs.statSync(filePath);
        if (stat.isFile()) {
            callback(filePath, stat);
        } else if (stat.isDirectory()) {
            walk(filePath, callback);
        }
    });
};

/**
 * search for all screensavers we can find on the filesystem. if cb is specified,
 * call it with data when done. if reload == true, don't use cached data.
 */
var listAll = function(cb) {
    var dir = require('node-dir');

    var root = baseDir + '/savers/';
    var folders = [root].concat( getLocalSources() );

    loadedData = [];

    folders.forEach( function ( src ) {
        console.log("let's walk " + src);
        walk(src, function(f, stat) {
            if ( f.match(/saver.json$/) ) {
                var content = fs.readFileSync( f );
                var contents = JSON.parse(content);

                var stub = path.dirname(f);
                console.log("STUB: " + stub);
                contents.key = stub + "/" + contents.source;

                console.log("KEY: " + contents.key);

                // allow for a specified URL -- this way you could create a screensaver
                // that pointed to a remote URL
                if ( typeof(contents.url) === "undefined" ) {
                    contents.url = 'file://' + contents.key;
                }

                contents.settings = getOptions(contents.key);
                console.log("OPTIONS", contents.settings);

                var s = new Saver(contents);

                loadedData.push(s);
            }
        });
    });

    if ( typeof(cb) !== "undefined" ) {
        cb(loadedData);
    }

    return loadedData;
};

var findScreensavers = function(root) {
    console.log("let's walk " + root);
    walk(root, function(f, stat) {
        if ( f.match(/saver.json$/) ) {
            var content = fs.readFileSync( f );
            var contents = JSON.parse(content);

            var stub = path.dirname(f);
            console.log("STUB: " + stub);
            contents.key = stub + "/" + contents.source;

            console.log("KEY: " + contents.key);

            // allow for a specified URL -- this way you could create a screensaver
            // that pointed to a remote URL
            if ( typeof(contents.url) === "undefined" ) {
                contents.url = 'file://' + contents.key;
            }

            contents.settings = getOptions(contents.key);
            console.log("OPTIONS", contents.settings);

            var s = new Saver(contents);

            loadedData.push(s);
        }
    });
};

/**
 * get a URL we can use to render current screensaver. if opts is passed in, use them
 * when generating URL. otherwise use our global URL options
 */
var getCurrentUrl = function(opts) {
    var s = getCurrentData();
    return s.getUrl(opts);
};

/**
 * return URL of the screensaver matching key
 */
var getUrl = function(key) {
    var url = 'file://' + baseDir + '/savers/';
    if ( typeof(key) === "undefined" ) {
        key = getCurrent();
    }
    url = url + key;

    return url;
};

var write = function(cb) {
    var configPath = baseDir + "/" + config_file;
    console.log("write config to " + configPath);
    nconf.save(cb);
};

exports.init = init;
exports.reload = reload;
exports.getByKey = getByKey;
exports.getCurrent = getCurrent;
exports.getSource = getSource;
exports.setSource = setSource;
exports.getLocalSources = getLocalSources;
exports.setLocalSources = setLocalSources;
exports.getCurrentData = getCurrentData;
exports.setCurrent = setCurrent;
exports.setOptions = setOptions;
exports.setDelay = setDelay;
exports.setLock = setLock;
exports.getDelay = getDelay;
exports.getLock = getLock;
exports.getOptions = getOptions;
exports.listAll = listAll;
exports.getCurrentUrl = getCurrentUrl;
exports.getUrl = getUrl;
exports.loadedData = loadedData;
exports.write = write;
<|endoftext|>


<commit_before>'use strict'
const express = require('express')
const Slapp = require('slapp')
const ConvoStore = require('slapp-convo-beepboop')
const Context = require('slapp-context-beepboop')

	function HashMap(other) {
		this.clear();
		switch (arguments.length) {
			case 0: break;
			case 1: this.copy(other); break;
			default: multi(this, arguments); break;
		}
	}

	var proto = HashMap.prototype = {
		constructor:HashMap,

		get:function(key) {
			var data = this._data[this.hash(key)];
			return data && data[1];
		},

		set:function(key, value) {
			// Store original key as well (for iteration)
			var hash = this.hash(key);
			if ( !(hash in this._data) ) {
				this._count++;
			}
			this._data[hash] = [key, value];
		},

		multi:function() {
			multi(this, arguments);
		},

		copy:function(other) {
			for (var hash in other._data) {
				if ( !(hash in this._data) ) {
					this._count++;
				}
				this._data[hash] = other._data[hash];
			}
		},

		has:function(key) {
			return this.hash(key) in this._data;
		},

		search:function(value) {
			for (var key in this._data) {
				if (this._data[key][1] === value) {
					return this._data[key][0];
				}
			}

			return null;
		},

		remove:function(key) {
			var hash = this.hash(key);
			if ( hash in this._data ) {
				this._count--;
				delete this._data[hash];
			}
		},

		type:function(key) {
			var str = Object.prototype.toString.call(key);
			var type = str.slice(8, -1).toLowerCase();
			// Some browsers yield DOMWindow for null and undefined, works fine on Node
			if (type === 'domwindow' && !key) {
				return key + '';
			}
			return type;
		},

		keys:function() {
			var keys = [];
			this.forEach(function(_, key) { keys.push(key); });
			return keys;
		},

		values:function() {
			var values = [];
			this.forEach(function(value) { values.push(value); });
			return values;
		},

		count:function() {
			return this._count;
		},

		clear:function() {
			// TODO: Would Object.create(null) make any difference
			this._data = {};
			this._count = 0;
		},

		clone:function() {
			return new HashMap(this);
		},

		hash:function(key) {
			switch (this.type(key)) {
				case 'undefined':
				case 'null':
				case 'boolean':
				case 'number':
				case 'regexp':
					return key + '';

				case 'date':
					return '♣' + key.getTime();

				case 'string':
					return '♠' + key;

				case 'array':
					var hashes = [];
					for (var i = 0; i < key.length; i++) {
						hashes[i] = this.hash(key[i]);
					}
					return '♥' + hashes.join('⁞');

				default:
					// TODO: Don't use expandos when Object.defineProperty is not available?
					if (!key.hasOwnProperty('_hmuid_')) {
						key._hmuid_ = ++HashMap.uid;
						hide(key, '_hmuid_');
					}

					return '♦' + key._hmuid_;
			}
		},

		forEach:function(func, ctx) {
			for (var key in this._data) {
				var data = this._data[key];
				func.call(ctx || this, data[1], data[0]);
			}
		}
	};

	HashMap.uid = 0;

	//- Add chaining to all methods that don't return something

	['set','multi','copy','remove','clear','forEach'].forEach(function(method) {
		var fn = proto[method];
		proto[method] = function() {
			fn.apply(this, arguments);
			return this;
		};
	});

	//- Utils

	function multi(map, args) {
		for (var i = 0; i < args.length; i += 2) {
			map.set(args[i], args[i+1]);
		}
	}

	function hide(obj, prop) {
		// Make non iterable if supported
		if (Object.defineProperty) {
			Object.defineProperty(obj, prop, {enumerable:false});
		}
	}

var stringMap = new HashMap();

var dictionary = [
  'OpenBCI',
  'BCI',
  'EEG',
  'EMG',
  'Decoding',
  'Meetup',
  'Frequency',
  'Freq',
  'Signal',
  'EMD',
  'Matlab',
  'Python',
  'C++',
  'Noise',
	'Empirical Mode Decomposition'
]

for(var i=0;i<dictionary.length;i++){
  stringMap.set(dictionary[i],0)
}
// Debug print on console
function _(s){
  var str = JSON.stringify(s, null, 4);
  console.log(str);
}
// use `PORT` env var on Beep Boop - default to 3000 locally
var port = process.env.PORT || 3000
var slapp = Slapp({
  // Beep Boop sets the SLACK_VERIFY_TOKEN env var
  verify_token: process.env.SLACK_VERIFY_TOKEN,
  convo_store: ConvoStore(),
  context: Context()
})
var HELP_TEXT = `
I will respond to the following messages:
\`help\` - to see this message.
\`stats\` - I will show you what people are talking about the most.
`
var WELCOME_TEXT = `
Welcome to NeuroTechX slack, I'm the EduBotX, I'm here to help you get started.
If you want to learn about neurotechnologies, please visit www.neurotechedu.com
If you want to now about the activities of NeuroTechX, please visit www.neurotechx.com
Please introduce yourself on the #introductions channel.
`
//*********************************************
// Setup different handlers for messages
//*********************************************

// response to the user typing "help"
slapp.message('help', ['mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT)
})

slapp.event('team_join', (msg) => {

  slapp.client.im.open({ token: msg.meta.bot_token,  user: msg.body.event.user.id }, (err, data) => {
    if (err) {
      return console.error(err)
    }
    msg.say({ channel: data.channel.id, text: WELCOME_TEXT })
    })

})
// slapp.message('(.*)', 'ambient', (msg) => {
//   var strings = msg.body.event.text.split(' ');
//   for(var i=0;i<strings.length;i++){
// 		var hash = stringMap.hash(strings[i]);
// 		if ( hash in stringMap._data ) {
//       stringMap.set(strings[i],stringMap.get(strings[i])+1);
//     }
//   }
// })
slapp.message('(.*)', 'ambient', (msg) => {
	stringMap.forEach(function(value, key) {
		var occ = msg.body.event.text.split(key).length - 1;
		stringMap.set(key,stringMap.get(key)+occ);
	})
})
slapp.command('/stats','(.*)', (msg, text, api)  => {
	let token = msg.meta.bot_token;
	if(isAdmin(token,msg.body.user_id)){
	  var str = '';
		_(msg);
	  stringMap.forEach(function(value, key) {
	    str = str + key + ' : ' + value + '\n';
	  });
	  msg.respond(str)
	}
	else {
		msg.say("Sorry you're not admin enough to do that");
	}
})
slapp.command('/stats_add_keywords','(.*)', (msg, text, params)  => {
	let token = msg.meta.bot_token;
	if(isAdmin(token,msg.body.user_id)){
	var strings = text.split(' ');
	for(var i=0; i<strings.length;i++){
		var hash = stringMap.hash(strings[i]);
		if ( ! (hash in stringMap._data) ) {
			stringMap.set(strings[i],0);
		}
	}
}
else {
	msg.say("Sorry you're not admin enough to do that");
}
})
slapp.command('/stats_delete_keywords','(.*)', (msg, text, params)  => {
	let token = msg.meta.bot_token;
	if(isAdmin(token,msg.body.user_id)){
	var strings = text.split(' ');
	for(var i=0; i<strings.length;i++){
		var hash = stringMap.hash(strings[i]);
		if ( (hash in stringMap._data) ) {
			stringMap.remove(strings[i]);
		}
	}
	}
	else {
		msg.say("Sorry you're not admin enough to do that");
	}
})
slapp.command('/stats_refresh','(.*)', (msg, text, params)  => {
	let token = msg.meta.bot_token;
	if(isAdmin(token,msg.body.user_id)){
		stringMap.clear();
	}
	else {
		msg.say("Sorry you're not admin enough to do that");
	}
})

function isAdmin(token,userid){
	slapp.client.list({}, (err, data) => {
		_("list");
		_(data);
	});
	slapp.client.users.info({token,userid}, (err, data) => {
		_(token)
		_(userid)
		_(err);
		_(data);
		if(data.ok){
			if(data.user.is_admin)
				return true;
		}
		return false;
	});

}
// slapp.command('/wordpress', 'auth (.*)', (msg, text, api) => {
//   // if "/wordpress auth key secret"
//   // text = auth key secret
//   // api = key secret
//   var strings = api.split(' ');
//   usr = strings[0];
//   pswd  = strings[1];
//   console.log("user " + usr + " pswd " + pswd);
// })
// slapp.command('/send', 'send (.*)', (msg, text, api) => {
//
//   var data = querystring.stringify({
//       'source' : 'John',
//       'content': 'test'
//   });
//   console.log("msg " + msg);
//   console.log("data "+ data);
//   // An object of options to indicate where to post to
//   var post_options = {
//       host: 'www.neurotechedu.com',
//       port: '80',
//       path: '/wp-json/wp/v2/analytic',
//       method: 'POST',
//       headers: {
//           'Authorization':  "Basic " +
//           + (new Buffer(usr + ":" + pswd).toString('base64'))
//       }
//   };
//
//   var post_req = http.request(post_options, function(res) {
//      res.setEncoding('utf8');
//      res.on('data', function (chunk) {
//          console.log('Response: ' + chunk);
//      });
//  });
//  post_req.write(data);
//  post_req.end();
//
// })

// "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
// slapp
//   .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
//     msg
//       .say(`${text}, how are you?`)
//       // sends next event from user to this route, passing along state
//       .route('how-are-you', { greeting: text })
//   })
//   .route('how-are-you', (msg, state) => {
//     var text = (msg.body.event && msg.body.event.text) || ''
//
//     // user may not have typed text as their next action, ask again and re-route
//     if (!text) {
//       return msg
//         .say("Whoops, I'm still waiting to hear how you're doing.")
//         .say('How are you?')
//         .route('how-are-you', state)
//     }
//
//     // add their response to state
//     state.status = text
//
//     msg
//       .say(`Ok then. What's your favorite color?`)
//       .route('color', state)
//   })
//   .route('color', (msg, state) => {
//     var text = (msg.body.event && msg.body.event.text) || ''
//
//     // user may not have typed text as their next action, ask again and re-route
//     if (!text) {
//       return msg
//         .say("I'm eagerly awaiting to hear your favorite color.")
//         .route('color', state)
//     }
//
//     // add their response to state
//     state.color = text
//
//     msg
//       .say('Thanks for sharing.')
//       .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
//     // At this point, since we don't route anywhere, the "conversation" is over
//   })

// Can use a regex as well
slapp.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
  // You can provide a list of responses, and a random one will be chosen
  // You can also include slack emoji in your responses
  msg.say([
    "You're welcome :smile:",
    'Anytime :full_moon_with_face:'
  ])
})

// // demonstrate returning an attachment...
// slapp.message('attachment', ['mention', 'direct_message'], (msg) => {
//   msg.say({
//     text: 'Check out this amazing attachment! :confetti_ball: ',
//     attachments: [{
//       text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
//       title: 'Slapp Library - Open Source',
//       image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
//       title_link: 'https://beepboophq.com/',
//       color: '#7CD197'
//     }]
//   })
// })

// Catch-all for any other responses not handled above
slapp.message('.*', ['direct_mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT);
})

// attach Slapp to express server
var server = slapp.attachToExpress(express())

// start http server
server.listen(port, (err) => {
  if (err) {
    return console.error(err)
  }
  console.log(`Listening on port ${port}`)
})

// function sendAnalytics(){
//   var options = {
//     host: url,
//     port: 80,
//     path: '/resource?id=foo&bar=baz',
//     method: 'POST'
//   };
//
//   http.request(options, function(res) {
//     console.log('STATUS: ' + res.statusCode);
//     console.log('HEADERS: ' + JSON.stringify(res.headers));
//     res.setEncoding('utf8');
//     res.on('data', function (chunk) {
//       console.log('BODY: ' + chunk);
//     });
//   }).end();
// }
<commit_msg>clients.users<commit_after>'use strict'
const express = require('express')
const Slapp = require('slapp')
const ConvoStore = require('slapp-convo-beepboop')
const Context = require('slapp-context-beepboop')

	function HashMap(other) {
		this.clear();
		switch (arguments.length) {
			case 0: break;
			case 1: this.copy(other); break;
			default: multi(this, arguments); break;
		}
	}

	var proto = HashMap.prototype = {
		constructor:HashMap,

		get:function(key) {
			var data = this._data[this.hash(key)];
			return data && data[1];
		},

		set:function(key, value) {
			// Store original key as well (for iteration)
			var hash = this.hash(key);
			if ( !(hash in this._data) ) {
				this._count++;
			}
			this._data[hash] = [key, value];
		},

		multi:function() {
			multi(this, arguments);
		},

		copy:function(other) {
			for (var hash in other._data) {
				if ( !(hash in this._data) ) {
					this._count++;
				}
				this._data[hash] = other._data[hash];
			}
		},

		has:function(key) {
			return this.hash(key) in this._data;
		},

		search:function(value) {
			for (var key in this._data) {
				if (this._data[key][1] === value) {
					return this._data[key][0];
				}
			}

			return null;
		},

		remove:function(key) {
			var hash = this.hash(key);
			if ( hash in this._data ) {
				this._count--;
				delete this._data[hash];
			}
		},

		type:function(key) {
			var str = Object.prototype.toString.call(key);
			var type = str.slice(8, -1).toLowerCase();
			// Some browsers yield DOMWindow for null and undefined, works fine on Node
			if (type === 'domwindow' && !key) {
				return key + '';
			}
			return type;
		},

		keys:function() {
			var keys = [];
			this.forEach(function(_, key) { keys.push(key); });
			return keys;
		},

		values:function() {
			var values = [];
			this.forEach(function(value) { values.push(value); });
			return values;
		},

		count:function() {
			return this._count;
		},

		clear:function() {
			// TODO: Would Object.create(null) make any difference
			this._data = {};
			this._count = 0;
		},

		clone:function() {
			return new HashMap(this);
		},

		hash:function(key) {
			switch (this.type(key)) {
				case 'undefined':
				case 'null':
				case 'boolean':
				case 'number':
				case 'regexp':
					return key + '';

				case 'date':
					return '♣' + key.getTime();

				case 'string':
					return '♠' + key;

				case 'array':
					var hashes = [];
					for (var i = 0; i < key.length; i++) {
						hashes[i] = this.hash(key[i]);
					}
					return '♥' + hashes.join('⁞');

				default:
					// TODO: Don't use expandos when Object.defineProperty is not available?
					if (!key.hasOwnProperty('_hmuid_')) {
						key._hmuid_ = ++HashMap.uid;
						hide(key, '_hmuid_');
					}

					return '♦' + key._hmuid_;
			}
		},

		forEach:function(func, ctx) {
			for (var key in this._data) {
				var data = this._data[key];
				func.call(ctx || this, data[1], data[0]);
			}
		}
	};

	HashMap.uid = 0;

	//- Add chaining to all methods that don't return something

	['set','multi','copy','remove','clear','forEach'].forEach(function(method) {
		var fn = proto[method];
		proto[method] = function() {
			fn.apply(this, arguments);
			return this;
		};
	});

	//- Utils

	function multi(map, args) {
		for (var i = 0; i < args.length; i += 2) {
			map.set(args[i], args[i+1]);
		}
	}

	function hide(obj, prop) {
		// Make non iterable if supported
		if (Object.defineProperty) {
			Object.defineProperty(obj, prop, {enumerable:false});
		}
	}

var stringMap = new HashMap();

var dictionary = [
  'OpenBCI',
  'BCI',
  'EEG',
  'EMG',
  'Decoding',
  'Meetup',
  'Frequency',
  'Freq',
  'Signal',
  'EMD',
  'Matlab',
  'Python',
  'C++',
  'Noise',
	'Empirical Mode Decomposition'
]

for(var i=0;i<dictionary.length;i++){
  stringMap.set(dictionary[i],0)
}
// Debug print on console
function _(s){
  var str = JSON.stringify(s, null, 4);
  console.log(str);
}
// use `PORT` env var on Beep Boop - default to 3000 locally
var port = process.env.PORT || 3000
var slapp = Slapp({
  // Beep Boop sets the SLACK_VERIFY_TOKEN env var
  verify_token: process.env.SLACK_VERIFY_TOKEN,
  convo_store: ConvoStore(),
  context: Context()
})
var HELP_TEXT = `
I will respond to the following messages:
\`help\` - to see this message.
\`stats\` - I will show you what people are talking about the most.
`
var WELCOME_TEXT = `
Welcome to NeuroTechX slack, I'm the EduBotX, I'm here to help you get started.
If you want to learn about neurotechnologies, please visit www.neurotechedu.com
If you want to now about the activities of NeuroTechX, please visit www.neurotechx.com
Please introduce yourself on the #introductions channel.
`
//*********************************************
// Setup different handlers for messages
//*********************************************

// response to the user typing "help"
slapp.message('help', ['mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT)
})

slapp.event('team_join', (msg) => {

  slapp.client.im.open({ token: msg.meta.bot_token,  user: msg.body.event.user.id }, (err, data) => {
    if (err) {
      return console.error(err)
    }
    msg.say({ channel: data.channel.id, text: WELCOME_TEXT })
    })

})
// slapp.message('(.*)', 'ambient', (msg) => {
//   var strings = msg.body.event.text.split(' ');
//   for(var i=0;i<strings.length;i++){
// 		var hash = stringMap.hash(strings[i]);
// 		if ( hash in stringMap._data ) {
//       stringMap.set(strings[i],stringMap.get(strings[i])+1);
//     }
//   }
// })
slapp.message('(.*)', 'ambient', (msg) => {
	stringMap.forEach(function(value, key) {
		var occ = msg.body.event.text.split(key).length - 1;
		stringMap.set(key,stringMap.get(key)+occ);
	})
})
slapp.command('/stats','(.*)', (msg, text, api)  => {
	let token = msg.meta.bot_token;
	if(isAdmin(token,msg.body.user_id)){
	  var str = '';
		_(msg);
	  stringMap.forEach(function(value, key) {
	    str = str + key + ' : ' + value + '\n';
	  });
	  msg.respond(str)
	}
	else {
		msg.say("Sorry you're not admin enough to do that");
	}
})
slapp.command('/stats_add_keywords','(.*)', (msg, text, params)  => {
	let token = msg.meta.bot_token;
	if(isAdmin(token,msg.body.user_id)){
	var strings = text.split(' ');
	for(var i=0; i<strings.length;i++){
		var hash = stringMap.hash(strings[i]);
		if ( ! (hash in stringMap._data) ) {
			stringMap.set(strings[i],0);
		}
	}
}
else {
	msg.say("Sorry you're not admin enough to do that");
}
})
slapp.command('/stats_delete_keywords','(.*)', (msg, text, params)  => {
	let token = msg.meta.bot_token;
	if(isAdmin(token,msg.body.user_id)){
	var strings = text.split(' ');
	for(var i=0; i<strings.length;i++){
		var hash = stringMap.hash(strings[i]);
		if ( (hash in stringMap._data) ) {
			stringMap.remove(strings[i]);
		}
	}
	}
	else {
		msg.say("Sorry you're not admin enough to do that");
	}
})
slapp.command('/stats_refresh','(.*)', (msg, text, params)  => {
	let token = msg.meta.bot_token;
	if(isAdmin(token,msg.body.user_id)){
		stringMap.clear();
	}
	else {
		msg.say("Sorry you're not admin enough to do that");
	}
})

function isAdmin(token,userid){
	slapp.client.users.list({}, (err, data) => {
		_("list");
		_(data);
	});
	slapp.client.users.info({token,userid}, (err, data) => {
		_(token)
		_(userid)
		_(err);
		_(data);
		if(data.ok){
			if(data.user.is_admin)
				return true;
		}
		return false;
	});

}
// slapp.command('/wordpress', 'auth (.*)', (msg, text, api) => {
//   // if "/wordpress auth key secret"
//   // text = auth key secret
//   // api = key secret
//   var strings = api.split(' ');
//   usr = strings[0];
//   pswd  = strings[1];
//   console.log("user " + usr + " pswd " + pswd);
// })
// slapp.command('/send', 'send (.*)', (msg, text, api) => {
//
//   var data = querystring.stringify({
//       'source' : 'John',
//       'content': 'test'
//   });
//   console.log("msg " + msg);
//   console.log("data "+ data);
//   // An object of options to indicate where to post to
//   var post_options = {
//       host: 'www.neurotechedu.com',
//       port: '80',
//       path: '/wp-json/wp/v2/analytic',
//       method: 'POST',
//       headers: {
//           'Authorization':  "Basic " +
//           + (new Buffer(usr + ":" + pswd).toString('base64'))
//       }
//   };
//
//   var post_req = http.request(post_options, function(res) {
//      res.setEncoding('utf8');
//      res.on('data', function (chunk) {
//          console.log('Response: ' + chunk);
//      });
//  });
//  post_req.write(data);
//  post_req.end();
//
// })

// "Conversation" flow that tracks state - kicks off when user says hi, hello or hey
// slapp
//   .message('^(hi|hello|hey)$', ['direct_mention', 'direct_message'], (msg, text) => {
//     msg
//       .say(`${text}, how are you?`)
//       // sends next event from user to this route, passing along state
//       .route('how-are-you', { greeting: text })
//   })
//   .route('how-are-you', (msg, state) => {
//     var text = (msg.body.event && msg.body.event.text) || ''
//
//     // user may not have typed text as their next action, ask again and re-route
//     if (!text) {
//       return msg
//         .say("Whoops, I'm still waiting to hear how you're doing.")
//         .say('How are you?')
//         .route('how-are-you', state)
//     }
//
//     // add their response to state
//     state.status = text
//
//     msg
//       .say(`Ok then. What's your favorite color?`)
//       .route('color', state)
//   })
//   .route('color', (msg, state) => {
//     var text = (msg.body.event && msg.body.event.text) || ''
//
//     // user may not have typed text as their next action, ask again and re-route
//     if (!text) {
//       return msg
//         .say("I'm eagerly awaiting to hear your favorite color.")
//         .route('color', state)
//     }
//
//     // add their response to state
//     state.color = text
//
//     msg
//       .say('Thanks for sharing.')
//       .say(`Here's what you've told me so far: \`\`\`${JSON.stringify(state)}\`\`\``)
//     // At this point, since we don't route anywhere, the "conversation" is over
//   })

// Can use a regex as well
slapp.message(/^(thanks|thank you)/i, ['mention', 'direct_message'], (msg) => {
  // You can provide a list of responses, and a random one will be chosen
  // You can also include slack emoji in your responses
  msg.say([
    "You're welcome :smile:",
    'Anytime :full_moon_with_face:'
  ])
})

// // demonstrate returning an attachment...
// slapp.message('attachment', ['mention', 'direct_message'], (msg) => {
//   msg.say({
//     text: 'Check out this amazing attachment! :confetti_ball: ',
//     attachments: [{
//       text: 'Slapp is a robust open source library that sits on top of the Slack APIs',
//       title: 'Slapp Library - Open Source',
//       image_url: 'https://storage.googleapis.com/beepboophq/_assets/bot-1.22f6fb.png',
//       title_link: 'https://beepboophq.com/',
//       color: '#7CD197'
//     }]
//   })
// })

// Catch-all for any other responses not handled above
slapp.message('.*', ['direct_mention', 'direct_message'], (msg) => {
  msg.say(HELP_TEXT);
})

// attach Slapp to express server
var server = slapp.attachToExpress(express())

// start http server
server.listen(port, (err) => {
  if (err) {
    return console.error(err)
  }
  console.log(`Listening on port ${port}`)
})

// function sendAnalytics(){
//   var options = {
//     host: url,
//     port: 80,
//     path: '/resource?id=foo&bar=baz',
//     method: 'POST'
//   };
//
//   http.request(options, function(res) {
//     console.log('STATUS: ' + res.statusCode);
//     console.log('HEADERS: ' + JSON.stringify(res.headers));
//     res.setEncoding('utf8');
//     res.on('data', function (chunk) {
//       console.log('BODY: ' + chunk);
//     });
//   }).end();
// }
<|endoftext|>


<commit_before>'use strict';

/**
 * Libraries
 **/
var cluster = require('cluster');
var datefmt = require('dateformat');
var os = require('os');

/**
 * Setup
 **/
var env = process.env.NODE_ENV;
var cores = os.cpus().length;
var numOfCores;
if (env === "production") {
    numOfCores = cores === 1 ? cores : cores - 1;
} else {
    numOfCores = cores > 1 ? cores / 2 : cores;
}

var workers = parseInt(process.env.CLUSTER_WORKERS || numOfCores, 10);

cluster.setupMaster({ exec : "app.js" });

/**
 * Utilities
 **/
var restartCount = 0;

function say(message) {
    console.log("[SERVER] " + message);
}

function checkRestart() {
    if (restartCount >= 8) {
        say("FATAL: Too many restarts in too short a time.");
        process.exit(1);
    }
    restartCount = 0;
}
setInterval(checkRestart, 2000);

/**
 * Startup Messaging
 **/
say("Master starting:");
say("time        => " + datefmt(new Date(), "ddd, dd mmm yyyy hh:MM:ss Z"));
say("pid         => " + process.pid);
say("environment => " + env);

/**
 * Fork Workers
 **/
say("Workers starting:");

for (var i = 0; i < workers; i += 1) {
    cluster.fork();
}

/**
 * Worker Event Handlers
 **/
cluster.on('exit', function (worker) {
    say('worker      => with pid: ' +
        worker.process.pid +
        ', died. Restarting...');
    restartCount++;
    cluster.fork();
});

cluster.on('online', function (worker) {
    say('worker      => start with pid: ' + worker.process.pid + '.');
});

// vim: ft=javascript sw=4 sts=4 et:
<commit_msg>Remove unneeded variable.<commit_after>'use strict';

/**
 * Libraries
 **/
var cluster = require('cluster');
var datefmt = require('dateformat');
var os = require('os');

/**
 * Setup
 **/
var env = process.env.NODE_ENV;
var cores = os.cpus().length;
if (env === "production") {
    cores = cores === 1 ? cores : cores - 1;
} else {
    cores = cores > 1 ? cores / 2 : cores;
}

var workers = parseInt(process.env.CLUSTER_WORKERS || cores, 10);

cluster.setupMaster({ exec : "app.js" });

/**
 * Utilities
 **/
var restartCount = 0;

function say(message) {
    console.log("[SERVER] " + message);
}

function checkRestart() {
    if (restartCount >= 8) {
        say("FATAL: Too many restarts in too short a time.");
        process.exit(1);
    }
    restartCount = 0;
}
setInterval(checkRestart, 2000);

/**
 * Startup Messaging
 **/
say("Master starting:");
say("time        => " + datefmt(new Date(), "ddd, dd mmm yyyy hh:MM:ss Z"));
say("pid         => " + process.pid);
say("environment => " + env);

/**
 * Fork Workers
 **/
say("Workers starting:");

for (var i = 0; i < workers; i += 1) {
    cluster.fork();
}

/**
 * Worker Event Handlers
 **/
cluster.on('exit', function (worker) {
    say('worker      => with pid: ' +
        worker.process.pid +
        ', died. Restarting...');
    restartCount++;
    cluster.fork();
});

cluster.on('online', function (worker) {
    say('worker      => start with pid: ' + worker.process.pid + '.');
});

// vim: ft=javascript sw=4 sts=4 et:
<|endoftext|>


<commit_before>var util = require('util');
var net = require('net');

var LISTEN_HOST = '*';  // Bind to all available addresses
var LISTEN_PORT = 4080;

// An HTTP header (either request or response)
var Header = function(name, value) {
    var name = name;
    var value = value;

    return {
        // Normalizes the header's name.
        //
        // Equivalent header names will have the same normalized name.
        normalizedName: function() {
            return name.toLowerCase();
        },

        // Compares this instance's name to another's.
        //
        // Returns `true` if this's name is equivalent to that of `other` (also
        // a Header object).
        isSameHeader: function(other) {
            return (normalizedName() == other.normalizedName());
        },

        // Returns the protocol string that should be output for this header.
        //
        // E.g. for Header('Connection', 'keep-alive') this would be
        //
        //     'Connection: keep-alive'
        protocolString: function() {
            return [name, value].join(': ');
        }
    }
};

var server = net.createServer(function (socket) {
    var response_headers = [];

    response_headers.push(new Header('Date', 'Tue, 30 Jul 2013 02:41:02 GMT'));
    response_headers.push(new Header('Content-Type', 'text/html; charset=UTF-8'));
    response_headers.push(new Header('Connection', 'close'));

    socket.write('HTTP/1.1 200 OK\n');
    response_headers.forEach(function(element, index, array) {
        socket.write(element.protocolString() + '\n');
    });
    socket.end();
});

if (LISTEN_HOST == '*') {
    server.listen(LISTEN_PORT);
} else {
    server.listen(LISTEN_PORT, LISTEN_HOST);
}

console.log(util.format('Server running at http://%s:%d/', LISTEN_HOST, LISTEN_PORT));
<commit_msg>Added argument parsing with optimist.<commit_after>var util = require('util');
var net = require('net');

var optimist = require('optimist');

var LISTEN_HOST = '*';  // Bind to all available addresses
var LISTEN_PORT = 4080;

// An HTTP header (either request or response)
var Header = function(name, value) {
    var name = name;
    var value = value;

    return {
        // Normalizes the header's name.
        //
        // Equivalent header names will have the same normalized name.
        normalizedName: function() {
            return name.toLowerCase();
        },

        // Compares this instance's name to another's.
        //
        // Returns `true` if this's name is equivalent to that of `other` (also
        // a Header object).
        isSameHeader: function(other) {
            return (normalizedName() == other.normalizedName());
        },

        // Returns the protocol string that should be output for this header.
        //
        // E.g. for Header('Connection', 'keep-alive') this would be
        //
        //     'Connection: keep-alive'
        protocolString: function() {
            return [name, value].join(': ');
        }
    }
};

// Process command-line arguments.
var argv = optimist
    .usage('Proxies requests and tampers with them in supposedly-acceptable ways.\n\nUSAGE: node server.js [--listen-host HOST] [--listen-port PORT] [--dest-host HOST] [--dest-port PORT]')
    .describe('listen-host', 'Listen on the host HOST')
    .describe('listen-port', 'Listen on the port PORT')
    .describe('dest-host', 'Proxy to the host HOST')
    .describe('dest-port', 'Proxy to the port PORT')
    .default('listen-host', '*')
    .default('listen-port', 4080)
    .default('dest-host', 'localhost')
    .default('dest-port', 80)
    .argv;
if (argv['help'] || argv['h']) {
    optimist.showHelp();
    process.exit();
}

// Define web server
var server = net.createServer(function (socket) {
    var response_headers = [];

    response_headers.push(new Header('Date', 'Tue, 30 Jul 2013 02:41:02 GMT'));
    response_headers.push(new Header('Content-Type', 'text/html; charset=UTF-8'));
    response_headers.push(new Header('Connection', 'close'));

    socket.write('HTTP/1.1 200 OK\n');
    response_headers.forEach(function(element, index, array) {
        socket.write(element.protocolString() + '\n');
    });
    socket.end();
});

// Start listening
if (argv['listen-host'] == '*') {
    server.listen(argv['listen-port']);
} else {
    server.listen(argv['listen-port'], argv['listen-host']);
}

console.log(util.format('Server running at http://%s:%d/', argv['listen-host'], argv['listen-port']));
<|endoftext|>


<commit_before>#!/usr/bin/env node
var logging = require("./modules/logging");
var querystring = require("querystring");
var config = require("./modules/config");
var clean = require("./modules/cleaner");
var http = require("http");
var mime = require("mime");
var url = require("url");
var fs = require("fs");
var server = null;

var routes = {
  index: require("./routes/index"),
  avatars: require("./routes/avatars"),
  skins: require("./routes/skins"),
  renders: require("./routes/renders"),
  capes: require("./routes/capes")
};

function asset_request(req, res) {
  var filename = __dirname + "/public/" + req.url.path_list.join("/");
  fs.exists(filename, function(exists) {
    if (exists) {
      res.writeHead(200, { "Content-type" : mime.lookup(filename) });
      fs.createReadStream(filename).pipe(res);
    } else {
      res.writeHead(404, {
        "Content-type" : "text/plain"
      });
      res.end("Not Found");
    }
  });
}

function requestHandler(req, res) {
  var request = req;
  request.url = url.parse(req.url, true);
  request.url.query = request.url.query || {};

  // remove trailing and double slashes + other junk
  var path_list = request.url.pathname.split("/");
  for (var i = 0; i < path_list.length; i++) {
    // URL decode
    path_list[i] = querystring.unescape(path_list[i]);
  }
  request.url.path_list = path_list;

  // generate 12 character random string
  request.id = Math.random().toString(36).substring(2,14) + " ";

  var local_path = request.url.path_list[1];
  logging.log(request.id + request.method + " " + request.url.href);
  if (request.method === "GET" || request.method === "HEAD") {
    try {
      switch (local_path) {
        case "":
        routes.index(request, res);
        break;
        case "avatars":
        routes.avatars(request, res);
        break;
        case "skins":
        routes.skins(request, res);
        break;
        case "renders":
        routes.renders(request, res);
        break;
        case "capes":
        routes.capes(request, res);
        break;
        default:
        asset_request(request, res);
      }
    } catch(e) {
      var error = JSON.stringify(req.headers) + "\n" + e.stack;
      logging.error(request.id + "Error: " + error);
      res.writeHead(500, {
        "Content-Type": "text/plain"
      });
      res.end(config.debug_enabled ? error : "Internal Server Error");
    }
  } else {
    res.writeHead(405, {
      "Content-Type": "text/plain"
    });
    res.end("Method Not Allowed");
  }
}

var exp = {};

exp.boot = function(callback) {
  var port = process.env.PORT || 3000;
  var bind_ip = process.env.BIND || "127.0.0.1";
  logging.log("Server running on http://" + bind_ip + ":" + port + "/");
  server = http.createServer(requestHandler).listen(port, bind_ip, function() {
    if (callback) {
      callback();
    }
  });
};

exp.close = function(callback) {
  server.close(function() {
    callback();
  });
};

module.exports = exp;

if (require.main === module) {
  exp.boot();

  // cleaning worker
  setInterval(clean.run, config.cleaning_interval * 1000);
}<commit_msg>server.js should be imported, not called directly<commit_after>#!/usr/bin/env node
var logging = require("./modules/logging");
var querystring = require("querystring");
var config = require("./modules/config");
var clean = require("./modules/cleaner");
var http = require("http");
var mime = require("mime");
var url = require("url");
var fs = require("fs");
var server = null;

var routes = {
  index: require("./routes/index"),
  avatars: require("./routes/avatars"),
  skins: require("./routes/skins"),
  renders: require("./routes/renders"),
  capes: require("./routes/capes")
};

function asset_request(req, res) {
  var filename = __dirname + "/public/" + req.url.path_list.join("/");
  fs.exists(filename, function(exists) {
    if (exists) {
      res.writeHead(200, { "Content-type" : mime.lookup(filename) });
      fs.createReadStream(filename).pipe(res);
    } else {
      res.writeHead(404, {
        "Content-type" : "text/plain"
      });
      res.end("Not Found");
    }
  });
}

function requestHandler(req, res) {
  var request = req;
  request.url = url.parse(req.url, true);
  request.url.query = request.url.query || {};

  // remove trailing and double slashes + other junk
  var path_list = request.url.pathname.split("/");
  for (var i = 0; i < path_list.length; i++) {
    // URL decode
    path_list[i] = querystring.unescape(path_list[i]);
  }
  request.url.path_list = path_list;

  // generate 12 character random string
  request.id = Math.random().toString(36).substring(2,14) + " ";

  var local_path = request.url.path_list[1];
  logging.log(request.id + request.method + " " + request.url.href);
  if (request.method === "GET" || request.method === "HEAD") {
    try {
      switch (local_path) {
        case "":
        routes.index(request, res);
        break;
        case "avatars":
        routes.avatars(request, res);
        break;
        case "skins":
        routes.skins(request, res);
        break;
        case "renders":
        routes.renders(request, res);
        break;
        case "capes":
        routes.capes(request, res);
        break;
        default:
        asset_request(request, res);
      }
    } catch(e) {
      var error = JSON.stringify(req.headers) + "\n" + e.stack;
      logging.error(request.id + "Error: " + error);
      res.writeHead(500, {
        "Content-Type": "text/plain"
      });
      res.end(config.debug_enabled ? error : "Internal Server Error");
    }
  } else {
    res.writeHead(405, {
      "Content-Type": "text/plain"
    });
    res.end("Method Not Allowed");
  }
}

var exp = {};

exp.boot = function(callback) {
  var port = process.env.PORT || 3000;
  var bind_ip = process.env.BIND || "127.0.0.1";
  logging.log("Server running on http://" + bind_ip + ":" + port + "/");
  server = http.createServer(requestHandler).listen(port, bind_ip, function() {
    if (callback) {
      callback();
    }
  });
};

exp.close = function(callback) {
  server.close(function() {
    callback();
  });
};

module.exports = exp;

if (require.main === module) {
  logging.error("Please use 'npm start' or 'bin/www.js'");
  process.exit(1);
}<|endoftext|>


<commit_before>/* Load packages */
var app = require('express')();
var request = require('http');
var http = require('http').Server(app);
var io = require('socket.io')(http);
var moment = require('moment');
var _ = require('underscore');
var validUrl = require('valid-url');
var youtubedl = require('youtube-dl');
var sprintf = require('sprintf-js').sprintf;
var vsprintf = require('sprintf-js').vsprintf

/* Object to store variables */
var storage = {
	/* The port the webserver listens to */
	"httpPort" : 1337,

	/* The default image displayed in the image section */
	'currentImage' : 'http://oi65.tinypic.com/i6gsbs.jpg',

	/* The default video title, uploader and resolution */
	'currentVideoTitle' : null,
	'currentVideoUploader' : null,
	'currentVideoResolution' : null,

	/* The default video displayed in the video section */
	'currentVideoUrl' : 'https://r12---sn-4g57kn7s.googlevideo.com/videoplayback?nh=IgpwcjAyLmZyYTE2KgkxMjcuMC4wLjE&upn=p12RUZUH9OM&initcwndbps=10550000&sparams=clen%2Cdur%2Cei%2Cgir%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cnh%2Cpl%2Cratebypass%2Crequiressl%2Csource%2Cupn%2Cexpire&source=youtube&pl=24&ei=nbwsWPrEBt38WJrmtqgH&lmt=1429522834789485&ip=5.230.147.63&expire=1479348477&id=o-AO97Ev3xXWxXPHJ2R8mnNLcQ56HgYj91tp_Co81Lki0m&gir=yes&mn=sn-4g57kn7s&mm=31&signature=23DB106F59FB7FC183E7D715F0A9C9D790C1AF70.4F5512E92A79AD53599E2471462B582CB7515DE3&itag=18&mv=m&mt=1479326711&ms=au&key=yt6&dur=199.296&requiressl=yes&ratebypass=yes&ipbits=0&clen=9036193&mime=video%2Fmp4',

	/* The time the default video starts at */
	'currentVideoTime' : '0',

	/* User list */
	'users' : {},

	/* History */
	'history' : []
};

/**
* Logging function
*/
function log () {
	var i;
	var args = [];
	for (i = 1; i < arguments.length; i++) {
		args.push(arguments[i]);
	}
	console.log('[%s] %s', moment().format('HH:mm:ss'), vsprintf(arguments[0], args));
}

/* HTTP routes */
app.get('/', function (req, res) {
	res.sendFile(__dirname + '/html/index.html');
});
app.get('*', function (req, res) {
	res.sendFile(__dirname + '/html/404.html');
});

/* New connection */
io.on('connection', function (socket) {
	/* Store the user's socket and it's corresponding IP address in the users object */
	storage.users[socket] = socket.request.connection.remoteAddress;
	log('%s: connected', storage.users[socket]);

	/* Broadcast the user count */
	io.emit('users count', _.keys(storage.users).length);

	/* Broadcast the history */
	io.emit('history list', storage.history);

	/* Log the join message */
	log('%s: client connected', storage.users[socket]);

	/* History */
	socket.on('history list', function () {
		socket.emit('history list', storage.history);
	});

	/* Received chat message */
	socket.on('chat message', function (data) {
		/* Check if the message is empty */
		if (data.message.length > 0) {
			/* Log it to the console */
			log('%s (%s): chat message: \'%s\'', storage.users[socket], data.user, data.message);

			/* Broadcast the message */
			io.emit('chat message', { user: data.user, message: data.message });
		} else {
			/* Log an error message (usually only occuring when user manipulated the frontend) */
			log('%s (%s): empty chat message', storage.users[socket], data.user);
		}
	});

	/* Image url get */
	socket.on('image get', function () {
		socket.emit('image set', storage.currentImage);
	});

	/* Image url set */
	socket.on('image set', function (url) {
		if (validUrl.isUri(url)) {
			log('updated image: %s', url);
			storage.currentImage = url;
			io.emit('image set', storage.currentImage);

			/* Push to the history */
			storage.history.push(sprintf('Image: %s', url, url));

			/* Broadcast the history */
			io.emit('history list', storage.history);
		} else {
			log('%s: received invalid url: %s', storage.users[socket], url);
		}
	});

	/* Video play */
	socket.on('video play', function (time) {
		//console.log('play, time: %s', time);
		io.emit('video play', time);
		storage.currentVideoTime = time;
	});

	/* Video pause */
	socket.on('video pause', function (time) {
		//console.log('pause, time: %s', time);
		io.emit('video pause', time);
		storage.currentVideoTime = time;
	});

	/* Video time get */
	socket.on('video time get', function () {
		socket.emit('video time set', storage.currentVideoTime);
	});

	/* Video time set */
	socket.on('video time set', function (time) {
		//console.log('update, time: %s', time);
		storage.currentVideoTime = time;
	});

	/* Video get */
	socket.on('video get', function () {
		socket.emit('video set', { title: storage.currentVideoName, uploader: storage.currentVideoUploader, resolution: storage.currentVideoResolution, url: storage.currentVideoUrl });
	});

	/* Video set */
	socket.on('video set', function (url) {
		/* If the url is valid */
		if (validUrl.isUri(url)) {
			/* If the url is a youtube video */
			if (url.indexOf('youtube.com') !== -1) {
				/* Get the youtube video data */
				var video = youtubedl(url,
					['--format=18'],
					{ cwd: __dirname });

					/* Info callback */
					video.on('info', function(info) {
						/* Number to store the highest available resolution */
						highest = 0;

						/* String to store the displayed resolution */
						fullresolution = 'unknown';

						/* Object to store all resolutions and their correstponding video url */
						var resolutions = {};
						console.log(info);
						/* Loop through all video formats */
						info['formats'].forEach(function (element) {
							/* If height, width and url exist */
							if ('height' in element && 'width' in element && element['width'] != null && element['height'] != null && element['width'] != undefined && element['height'] != undefined && element['url'] != undefined) {
								/* If the video has audio */
								if (element['acodec'] != 'none') {
									/* If the resolution is higher than the current one */
									if (highest < element['width']) {
										/* Update the current resolution */
										fullresolution = element['width'] + 'x' + element['height'];
										highest = element['width'];
									}
									/* Store the resolution with it's url */
									resolutions[element['width']] = element['url'];
								}
							}
						});
						/* Give out status message */
						log('%s: updated video (from youtube %s) - highest available resolution with audio: %s - url: %s', storage.users[socket], url, highest, resolutions[highest]);

						/* Push to the history */
						storage.history.push(sprintf('YouTube: %s by %s', url, info.fulltitle, info.uploader_url, info.uploader));

						/* Broadcast the history */
						io.emit('history list', storage.history);

						/* Update the video for all clients */
						io.emit('video set', { title: info.fulltitle, uploader: info.uploader, resolution: fullresolution, url: resolutions[highest] });

						/* Update the config */
						storage.currentVideoName = info.fulltitle;
						storage.currentVideoUploader = info.uploader;
						storage.currentVideoResolution = fullresolution;
						storage.currentVideoUrl = resolutions[highest];
					});
				} else {
					/* If the url was a direct stream */
					log('%s: updated video: %s', storage.users[socket], url);

					/* Push to the history */
					storage.history.push(sprintf('Video: %s', url, url));

					/* Broadcast the history */
					io.emit('history list', storage.history);

					/* Unset title and resolution and update the video for all clients */
					// TODO: get resolution from video
					io.emit('video set', { title: null, uploader: null, resolution: null, url: storage.currentVideoUrl });
					storage.currentVideoName = null;
					storage.currentVideoUploader = null;
					storage.currentVideoResolution = null;
					storage.currentVideoUrl = url;
				}
			} else {
				/* If invalid url was received */
				log('%s: received invalid url', storage.users[socket]);
			}

		});

		/* User disconnect */
		socket.on('disconnect', function () {
			/* Remove the socket from the users object */
			log('%s: disconnected', storage.users[socket]);
			delete storage.users[socket];
		});
	});

	/* Start the webserver */
	http.listen(storage.httpPort, function () {
		log('HTTP listening on *:%s', storage.httpPort);
	});
<commit_msg>Fixed user identification by assigning an unique id on connection<commit_after>/* Load packages */
var app = require('express')();
var request = require('http');
var http = require('http').Server(app);
var io = require('socket.io')(http);
var moment = require('moment');
var _ = require('underscore');
var validUrl = require('valid-url');
var youtubedl = require('youtube-dl');
var sprintf = require('sprintf-js').sprintf;
var vsprintf = require('sprintf-js').vsprintf

/* Object to store variables */
var storage = {
	/* The port the webserver listens to */
	"httpPort" : 1337,

	/* The default image displayed in the image section */
	'currentImage' : 'http://oi65.tinypic.com/i6gsbs.jpg',

	/* The default video title, uploader and resolution */
	'currentVideoTitle' : null,
	'currentVideoUploader' : null,
	'currentVideoResolution' : null,

	/* The default video displayed in the video section */
	'currentVideoUrl' : 'https://r12---sn-4g57kn7s.googlevideo.com/videoplayback?nh=IgpwcjAyLmZyYTE2KgkxMjcuMC4wLjE&upn=p12RUZUH9OM&initcwndbps=10550000&sparams=clen%2Cdur%2Cei%2Cgir%2Cid%2Cinitcwndbps%2Cip%2Cipbits%2Citag%2Clmt%2Cmime%2Cmm%2Cmn%2Cms%2Cmv%2Cnh%2Cpl%2Cratebypass%2Crequiressl%2Csource%2Cupn%2Cexpire&source=youtube&pl=24&ei=nbwsWPrEBt38WJrmtqgH&lmt=1429522834789485&ip=5.230.147.63&expire=1479348477&id=o-AO97Ev3xXWxXPHJ2R8mnNLcQ56HgYj91tp_Co81Lki0m&gir=yes&mn=sn-4g57kn7s&mm=31&signature=23DB106F59FB7FC183E7D715F0A9C9D790C1AF70.4F5512E92A79AD53599E2471462B582CB7515DE3&itag=18&mv=m&mt=1479326711&ms=au&key=yt6&dur=199.296&requiressl=yes&ratebypass=yes&ipbits=0&clen=9036193&mime=video%2Fmp4',

	/* The time the default video starts at */
	'currentVideoTime' : '0',

	/* User list */
	'users' : {},

	/* History */
	'history' : []
};

/**
* Logging function
*/
function log () {
	var i;
	var args = [];
	for (i = 1; i < arguments.length; i++) {
		args.push(arguments[i]);
	}
	console.log('[%s] %s', moment().format('HH:mm:ss'), vsprintf(arguments[0], args));
}

/* HTTP routes */
app.get('/', function (req, res) {
	res.sendFile(__dirname + '/html/index.html');
});
app.get('*', function (req, res) {
	res.sendFile(__dirname + '/html/404.html');
});

/* New connection */
io.on('connection', function (socket) {
	/* Store the user's sessionid and it's corresponding IP address in the users object */
	socket.id = Math.floor(Math.random() * 1000);
	storage.users[socket.id] = socket.request.connection.remoteAddress;
	log('%s: connected', storage.users[socket.id]);

	/* Broadcast the user count */
	io.emit('users count', _.keys(storage.users).length);

	/* Broadcast the history */
	io.emit('history list', storage.history);

	/* Log the join message */
	log('%s: client connected', storage.users[socket.id]);

	/* History */
	socket.on('history list', function () {
		socket.emit('history list', storage.history);
	});

	/* Received chat message */
	socket.on('chat message', function (data) {
		/* Check if the message is empty */
		if (data.message.length > 0) {
			/* Log it to the console */
			log('%s (%s): chat message: \'%s\'', storage.users[socket.id], data.user, data.message);

			/* Broadcast the message */
			io.emit('chat message', { user: data.user, message: data.message });
		} else {
			/* Log an error message (usually only occuring when user manipulated the frontend) */
			log('%s (%s): empty chat message', storage.users[socket.id], data.user);
		}
	});

	/* Image url get */
	socket.on('image get', function () {
		socket.emit('image set', storage.currentImage);
	});

	/* Image url set */
	socket.on('image set', function (url) {
		if (validUrl.isUri(url)) {
			log('updated image: %s', url);
			storage.currentImage = url;
			io.emit('image set', storage.currentImage);

			/* Push to the history */
			storage.history.push(sprintf('Image: %s', url, url));

			/* Broadcast the history */
			io.emit('history list', storage.history);
		} else {
			log('%s: received invalid url: %s', storage.users[socket.id], url);
		}
	});

	/* Video play */
	socket.on('video play', function (time) {
		//console.log('play, time: %s', time);
		io.emit('video play', time);
		storage.currentVideoTime = time;
	});

	/* Video pause */
	socket.on('video pause', function (time) {
		//console.log('pause, time: %s', time);
		io.emit('video pause', time);
		storage.currentVideoTime = time;
	});

	/* Video time get */
	socket.on('video time get', function () {
		socket.emit('video time set', storage.currentVideoTime);
	});

	/* Video time set */
	socket.on('video time set', function (time) {
		//console.log('update, time: %s', time);
		storage.currentVideoTime = time;
	});

	/* Video get */
	socket.on('video get', function () {
		socket.emit('video set', { title: storage.currentVideoName, uploader: storage.currentVideoUploader, resolution: storage.currentVideoResolution, url: storage.currentVideoUrl });
	});

	/* Video set */
	socket.on('video set', function (url) {
		/* If the url is valid */
		if (validUrl.isUri(url)) {
			/* If the url is a youtube video */
			if (url.indexOf('youtube.com') !== -1) {
				/* Get the youtube video data */
				var video = youtubedl(url,
					['--format=18'],
					{ cwd: __dirname });

					/* Info callback */
					video.on('info', function(info) {
						/* Number to store the highest available resolution */
						highest = 0;

						/* String to store the displayed resolution */
						fullresolution = 'unknown';

						/* Object to store all resolutions and their correstponding video url */
						var resolutions = {};
						console.log(info);
						/* Loop through all video formats */
						info['formats'].forEach(function (element) {
							/* If height, width and url exist */
							if ('height' in element && 'width' in element && element['width'] != null && element['height'] != null && element['width'] != undefined && element['height'] != undefined && element['url'] != undefined) {
								/* If the video has audio */
								if (element['acodec'] != 'none') {
									/* If the resolution is higher than the current one */
									if (highest < element['width']) {
										/* Update the current resolution */
										fullresolution = element['width'] + 'x' + element['height'];
										highest = element['width'];
									}
									/* Store the resolution with it's url */
									resolutions[element['width']] = element['url'];
								}
							}
						});
						/* Give out status message */
						log('%s: updated video (from youtube %s) - highest available resolution with audio: %s - url: %s', storage.users[socket], url, highest, resolutions[highest]);

						/* Push to the history */
						storage.history.push(sprintf('YouTube: %s by %s', url, info.fulltitle, info.uploader_url, info.uploader));

						/* Broadcast the history */
						io.emit('history list', storage.history);

						/* Update the video for all clients */
						io.emit('video set', { title: info.fulltitle, uploader: info.uploader, resolution: fullresolution, url: resolutions[highest] });

						/* Update the config */
						storage.currentVideoName = info.fulltitle;
						storage.currentVideoUploader = info.uploader;
						storage.currentVideoResolution = fullresolution;
						storage.currentVideoUrl = resolutions[highest];
					});
				} else {
					/* If the url was a direct stream */
					log('%s: updated video: %s', storage.users[socket.id], url);

					/* Push to the history */
					storage.history.push(sprintf('Video: %s', url, url));

					/* Broadcast the history */
					io.emit('history list', storage.history);

					/* Unset title and resolution and update the video for all clients */
					// TODO: get resolution from video
					io.emit('video set', { title: null, uploader: null, resolution: null, url: storage.currentVideoUrl });
					storage.currentVideoName = null;
					storage.currentVideoUploader = null;
					storage.currentVideoResolution = null;
					storage.currentVideoUrl = url;
				}
			} else {
				/* If invalid url was received */
				log('%s: received invalid url', storage.users[socket.id]);
			}

		});

		/* User disconnect */
		socket.on('disconnect', function () {
			/* Remove the socket from the users object */
			log('%s: disconnected', storage.users[socket.id]);
			delete storage.users[socket.id];
		});
	});

	/* Start the webserver */
	http.listen(storage.httpPort, function () {
		log('HTTP listening on *:%s', storage.httpPort);
	});
<|endoftext|>