<commit_before>var express = require('express');
var app = express();

var chalk = require('chalk');
var cheerio = require('cheerio');
var cors = require('cors');
var Higgins = require('./higgins.js');
var morgan = require('morgan');

// Morgan is a replacement for express.logger()
app.use(morgan('dev'));

// Serve anything in public as static files
app.use(express.static(__dirname + '/public'));

console.log(chalk.red('Node environment: ') + chalk.cyan(app.get('env')));

// Enable CORS for some domains
var corsWhitelist = ['http://203.33.230.66', 'http://www.commerce.wa.gov.au', 'https://www.commerce.wa.gov.au'];
var corsOptions = {
  origin: function (origin, callback) {
//    var originIsWhitelisted = corsWhitelist.indexOf(origin) !== -1;
//    callback(null, originIsWhitelisted);
    // Setting to "true" to whitelist all origins for development
    callback(null, true);
    console.log(chalk.red('Origin is: ') + chalk.cyan(origin));
  },
};
app.use(cors(corsOptions));

// Redirect root requests to a nice index page.
app.get('/', function (req, res) {
  res.redirect('/public/index.html');
});

// ========================================
// Public endpoints for returning JSON data
// ========================================

// 'v1' for Version 1 of the API :)

// Commerce Media Releases from the 'Announcements' section of the website
app.get('/v1/commerce-news', function (req, res, next) {
  // URL of Commerce Media Releases ("Announcements")
//  var url = 'http://www.commerce.wa.gov.au/taxonomy/term/182/feed';
  var url = 'http://www.commerce.wa.gov.au/announcements/182/all/feed';

  // Feed formatting instructions for Pantry - xml or json
  var feedType = 'xml';

  // Get cache clear query string from URL
  var clear = false;

  if (req.query.clearCache === 'true') {
    clear = true;
  }
//  console.log(chalk.magenta('Cache clear status is: %s'), clear);
//  console.dir(req.query);

  Higgins.newsPlease(url, feedType, clear, function (error, news) {
    if (error) { return next(error); }
//    console.dir(news.$, { colors: 'true' });
//    console.dir(news.channel[0].item[5], { colors: 'true', depth: 5 });
//    console.log('Number of items: ' + news.channel[0].item.length);
//    res.type('json');
//    res.send(news);
    res.jsonp(news);
  });
});

app.get('/v1/ministerials', function (req, res, next) {
  // URL of Ministerial Media Statements built by this app
  var url = '/v1/build/ministerials';

  // Feed formatting instructions for Pantry - xml or json
  var feedType = 'json';

  // Get cache clear param from URL
  var clear = false;

  if (req.query.clearCache === 'true') {
    clear = true;
  }

  Higgins.newsPlease(url, feedType, clear, function (error, news) {
    if (error) { return next(error); }
//    res.send(news);
    res.jsonp(news);
  });
});

// ===================================
// Endpoints for building sets of data
// ===================================

app.get('/v1/build/ministerials', function (req, res, next) {
//  console.log('Request: ' + req);
  // URL of Ministerial Media Statements start page
  var startUrl = 'https://www.mediastatements.wa.gov.au/Pages/Portfolios/Commerce.aspx';

  res.jsonp({ "result": "This is where the data goes." });
//  res.send('some text here');
});

// ===================================
// All the error things go at the end.
// ===================================

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function (err, req, res, next) {
    res.status(err.status || 500).send(err.stack);
    console.error('Error stack: \n' + err.stack);
//    console.dir(req);
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
  res.status(err.status || 500).send('Error: ' + err.message);
  console.error('Error stack: \n' + err.stack);
});

// catch 404 as a final thing
app.use(function (req, res, next) {
  res.status(404).send('404 Not Found');
  console.dir(req);
});

// port setup with env var for Heroku
var port = process.env.PORT || 3000;
app.listen(port, function () {
  console.log('Listening on ' + port);
});
<commit_msg>Renamed "clear" argument/variable to more accurate "forceRefresh". Renamed Higgins to higgins as per standards.<commit_after>var express = require('express');
var app = express();

var chalk = require('chalk');
var cheerio = require('cheerio');
var cors = require('cors');
var higgins = require('./higgins.js');
var morgan = require('morgan');

// Morgan is a replacement for express.logger()
app.use(morgan('dev'));

// Serve anything in public as static files
app.use(express.static(__dirname + '/public'));

console.log(chalk.red('Node environment: ') + chalk.cyan(app.get('env')));

// Enable CORS for some domains
var corsWhitelist = ['http://203.33.230.66', 'http://www.commerce.wa.gov.au', 'https://www.commerce.wa.gov.au'];
var corsOptions = {
  origin: function (origin, callback) {
//    var originIsWhitelisted = corsWhitelist.indexOf(origin) !== -1;
//    callback(null, originIsWhitelisted);
    // Setting to "true" to whitelist all origins for development
    callback(null, true);
    console.log(chalk.red('Origin is: ') + chalk.cyan(origin));
  },
};
app.use(cors(corsOptions));

// Redirect root requests to a nice index page.
app.get('/', function (req, res) {
  res.redirect('/public/index.html');
});

// ========================================
// Public endpoints for returning JSON data
// ========================================

// 'v1' for Version 1 of the API :)

// Commerce Media Releases from the 'Announcements' section of the website
app.get('/v1/commerce-news', function (req, res, next) {
  // URL of Commerce Media Releases ("Announcements")
//  var url = 'http://www.commerce.wa.gov.au/taxonomy/term/182/feed';
  var url = 'http://www.commerce.wa.gov.au/announcements/182/all/feed';

  // Feed formatting instructions for Pantry - xml or json
  var feedType = 'xml';

  // Get cache clear query string from URL
  var forceRefresh = false;

  if (req.query.forceRefresh === 'true') {
    forceRefresh = true;
  }
//  console.log(chalk.magenta('Cache clear status is: %s'), clear);
//  console.dir(req.query);

  higgins.newsPlease(url, feedType, forceRefresh, function (error, news) {
    if (error) { return next(error); }
//    console.dir(news.$, { colors: 'true' });
//    console.dir(news.channel[0].item[5], { colors: 'true', depth: 5 });
//    console.log('Number of items: ' + news.channel[0].item.length);
//    res.type('json');
//    res.send(news);
    res.jsonp(news);
  });
});

app.get('/v1/ministerials', function (req, res, next) {
  // URL of Ministerial Media Statements built by this app
  var url = '/v1/build/ministerials';

  // Feed formatting instructions for Pantry - xml or json
  var feedType = 'json';

  // Get cache clear param from URL
  var forceRefresh = false;

  if (req.query.forceRefresh === 'true') {
    forceRefresh = true;
  }

  higgins.newsPlease(url, feedType, forceRefresh, function (error, news) {
    if (error) { return next(error); }
//    res.send(news);
    res.jsonp(news);
  });
});

// ===================================
// Endpoints for building sets of data
// ===================================

app.get('/v1/build/ministerials', function (req, res, next) {
//  console.log('Request: ' + req);
  // URL of Ministerial Media Statements start page
  var startUrl = 'https://www.mediastatements.wa.gov.au/Pages/Portfolios/Commerce.aspx';

  res.jsonp({ "result": "This is where the data goes." });
//  res.send('some text here');
});

// ===================================
// All the error things go at the end.
// ===================================

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use(function (err, req, res, next) {
    res.status(err.status || 500).send(err.stack);
    console.error('Error stack: \n' + err.stack);
//    console.dir(req);
  });
}

// production error handler
// no stacktraces leaked to user
app.use(function (err, req, res, next) {
  res.status(err.status || 500).send('Error: ' + err.message);
  console.error('Error stack: \n' + err.stack);
});

// catch 404 as a final thing
app.use(function (req, res, next) {
  res.status(404).send('404 Not Found');
  console.dir(req);
});

// port setup with env var for Heroku
var port = process.env.PORT || 3000;
app.listen(port, function () {
  console.log('Listening on ' + port);
});
<|endoftext|>


<commit_before>var alexa = require('alexa-app');
var config = require("./config.json");
var route = config.route || "tivo_control";
var port = process.env.port || config.port || 8080;
var bodyParser = require('body-parser');
var express = require('express');
var net = require('net');

var express_app = express();
express_app.use(bodyParser.urlencoded({ extended: true }));
express_app.use(bodyParser.json());
express_app.set('view engine','ejs');

var app = new alexa.app(route);

app.launch(function(request,response) {
    response.say("Welcome to Tivo Control");
});

var IRCODE_COMMANDS = ["UP", "DOWN", "LEFT", "RIGHT", "SELECT", "TIVO", "LIVETV", "GUIDE", "INFO", "EXIT", "THUMBSUP", "THUMBSDOWN", "CHANNELUP", "CHANNELDOWN", "MUTE", "VOLUMEUP", "VOLUMEDOWN", "TVINPUT", "VIDEO_MODE_FIXED_480i", "VIDEO_MODE_FIXED_480p", "VIDEO_MODE_FIXED_720p", "VIDEO_MODE_FIXED_1080i", "VIDEO_MODE_HYBRID", "VIDEO_MODE_HYBRID_720p", "VIDEO_MODE_HYBRID_1080i", "VIDEO_MODE_NATIVE", "CC_ON", "CC_OFF", "OPTIONS", "ASPECT_CORRECTION_FULL", "ASPECT_CORRECTION_PANEL", "ASPECT_CORRECTION_ZOOM", "ASPECT_CORRECTION_WIDE_ZOOM", "PLAY", "FORWARD", "REVERSE", "PAUSE", "SLOW", "REPLAY", "ADVANCE", "RECORD", "NUM0", "NUM1", "NUM2", "NUM3", "NUM4", "NUM5", "NUM6", "NUM7", "NUM8", "NUM9", "ENTER", "CLEAR", "ACTION_A", "ACTION_B", "ACTION_C", "ACTION_D"];
var KEYBOARD_COMMANDS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "MINUS", "EQUALS", "LBRACKET", "RBRACKET", "BACKSLASH", "SEMICOLON", "QUOTE", "COMMA", "PERIOD", "SLASH", "BACKQUOTE", "SPACE", "KBDUP", "KBDDOWN", "KBDLEFT", "KBDRIGHT", "PAGEUP", "PAGEDOWN", "HOME", "END", "CAPS", "LSHIFT", "RSHIFT", "INSERT", "BACKSPACE", "DELETE", "KBDENTER", "STOP", "VIDEO_ON_DEMAND"];
var TELEPORT_COMMANDS = ["TIVO", "LIVETV", "GUIDE", "NOWPLAYING"];

app.dictionary = {"commands":["UP", "DOWN", "LEFT", "RIGHT", "SELECT", "TIVO", "THUMBSUP", "THUMBSDOWN", "CHANNELUP", "CHANNELDOWN", "MUTE", "VOLUMEDOWN", "VOLUMEUP", "TVINPUT", "OPTIONS", "RECORD", "DISPLAY", "DIRECTV", "ENTER", "CLEAR", "PLAY", "PAUSE", "SLOW", "FORWARD", "REVERSE", "STANDBY", "NOWSHOWING", "REPLAY", "ADVANCE", "DELIMITER", "GUIDE", "KBDUP", "KBDDOWN", "KBDLEFT", "KBDRIGHT", "PAGEUP", "PAGEDOWN", "HOME", "END", "SPACE", "BACKQUOTE", "SLASH", "PERIOD", "COMMA", "QUOTE", "SEMICOLON", "BACKSLASH", "RBRACKET", "LBRACKET", "EQUALS", "MINUS", "CAPS", "LSHIFT", "RSHIFT", "INSERT", "BACKSPACE", "DELETE", "KBDENTER", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]};

app.intent('SendCommand',
    {
        "slots":{"TIVOCOMMAND":"LITERAL"},
        "utterances":[ "send {the|} {command|} {commands|TIVOCOMMAND}" ]
    },
    function(request,response) {
        sendCommand(request.slot("TIVOCOMMAND").toUpperCase());
    });

app.intent('Pause',
    {
        "slots":{},
        "utterances":[ "pause" ]
    },
    function(request,response) {
        sendCommand("PAUSE");
});

app.intent('LiveTV',
    {
        "slots":{},
        "utterances":[ "send {the|} {command|} live tv", "go to live tv" ]
    },
    function(request,response) {
        sendCommand("GUIDE");
        sendCommand("LIVETV");
    });

app.intent('Play',
    {
        "slots":{},
        "utterances":[ "play" ]
    },
    function(request,response) {
        sendCommand("PLAY");
});

app.intent('FastForward',
    {
        "slots":{},
        "utterances":[ "fast forward" ]
    },
    function(request,response) {
        sendCommand("FORWARD");
});

app.intent('SkipCommerial',
    {
        "slots":{},
        "utterances":[ "skip {the|} {this|} {commercial|forward|ahead}" ]
    },
    function(request,response) {
        sendCommand("ACTION_D");
});

app.intent('Record',
    {
        "slots":{},
        "utterances":[ "record {this|the|} {show|current show|this}" ]
    },
    function(request,response) {
        sendCommand("RECORD");
});

app.intent('GoHome',
    {
        "slots":{},
        "utterances":[ "{show|go} {to the|} home {screen|}" ]
    },
    function(request,response) {
        sendCommand("TIVO");
    });

app.intent('Netflix',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} netflix" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('Amazon',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} amazon {video|}" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('Hulu',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} hulu" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('YouTube',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} youtube" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('ChangeChannel',
    {
        "slots":{"TIVOCHANNEL":"NUMBER"},
        "utterances":[ "{change|go to} channel {1-100|TIVOCHANNEL}" ]
    },
    function(request,response) {
        changeChannel(request.slot("TIVOCHANNEL"));
    });

app.intent('ForceChannel',
    {
        "slots":{"TIVOCHANNEL":"NUMBER"},
        "utterances":[ "force channel {1-100|TIVOCHANNEL}" ]
    },
    function(request,response) {
        forceChannel(request.slot("TIVOCHANNEL"));
    });

// Manually hook the handler function into express
express_app.post('/'+route,function(req,res) {
    app.request(req.body)        // connect express to alexa-app
        .then(function(response) { // alexa-app returns a promise with the response
            res.json(response);      // stream it to express' output
        });
});

app.express(express_app, "/", true);

if ((process.argv.length === 3) && (process.argv[2] === 'schema'))  {
    console.log (app.schema ());
    console.log (app.utterances ());
}

function sendNextCommand () {
    clearInterval(interval);
    if(queuedCommands.length == 0) {
        if(typeof telnetSocket != "undefined" && typeof telnetSocket.end != "undefined") {
            telnetSocket.end();
            telnetSocket.destroy();
        }
        socketOpen = false;
    }
    else {
        var command = queuedCommands.shift();
        var timeToWait = 100;
        if(typeof command == "object" && typeof command["explicit"] != "undefined") {
            telnetSocket.write(command["command"].toUpperCase() + "\r");
            console.log("Sending Command: " + command["command"].toUpperCase());
            if(command.indexOf("TELEPORT"))
                timeToWait = 300;
        }
        else {
            if(typeof command == "object")
                command = command["command"];
            var prefix = determinePrefix(command);
            if(prefix === false) {
                console.log("ERROR: Command Not Supported: " + command);
                telnetSocket.end();
            }
            else {
                telnetSocket.write(prefix + " " + command.toUpperCase() + "\r");
                console.log("Sending Command: "+prefix + " " + command.toUpperCase());
            }
            if(prefix == "TELEPORT")
                timeToWait = 300;
        }
        setTimeout(sendNextCommand, timeToWait);
    }
}

var queuedCommands = [];
var telnetSocket;
var socketOpen = false;
var interval;
var noResponse = true;
function sendCommands(commands) {

    var host = config.tivoIP;
    var port = config.tivoPort;

    queuedCommands = [];
    for(var i=0; i<commands.length; i++) {
        queuedCommands.push(commands[i]);
    }
    console.log("QueuedCommands: "+queuedCommands.join(","));

    telnetSocket = net.createConnection({
        port: port,
        host: host
    });
    console.log("Connection Created");
    socketOpen = true;
    telnetSocket.on('data', function(data) {
        noResponse = false;
        console.log("RECEIVED: "+data.toString());
        interval = setInterval(sendNextCommand, 100);
    });
    telnetSocket.on('timeout', function(data) {
        console.log("TIMEOUT RECEIVED");
        if(socketOpen)
            sendNextCommand();
    });
    telnetSocket.on('end', function(data) {
        socketOpen = false;
    });
    noResponse = true;
    setTimeout(function(){
        if(noResponse) {
            telnetSocket.write("TELEPORT GUIDE" + "\r");
        }
    }, 700);
}

function sendCommand(command, explicit) {
    if(typeof explicit == "undefined") {
        explicit = false;
    }
    var host = config.tivoIP;
    var port = config.tivoPort;
    var telnetSocket = net.createConnection({
        port: port,
        host: host
    });
    telnetSocket.on('data', function(data) {
        console.log("RECEIVED: "+data.toString());
    });
    if(explicit) {
        telnetSocket.write(command.toUpperCase() + "\r");
        console.log("Sending Command: " + command.toUpperCase());
    }
    else {
        var prefix = determinePrefix(command);
        if(prefix === false)
            console.log("ERROR: Command Not Support: "+command);
        else {
            telnetSocket.write(prefix + " " + command.toUpperCase() + "\r");
            console.log("Sending Command: "+prefix + " " + command.toUpperCase());
        }
    }
    telnetSocket.end();
    telnetSocket.destroy();
}

function changeChannel(channel) {
    return sendCommand("SETCH "+channel, true);
}

function forceChannel(channel) {
    return sendCommand("FORCECH "+channel, true);
}

function determinePrefix(command) {
    if(TELEPORT_COMMANDS.indexOf(command) != -1)
        return "TELEPORT";
    else if(IRCODE_COMMANDS.indexOf(command) != -1)
        return "IRCODE";
    else if(KEYBOARD_COMMANDS.indexOf(command) != -1)
        return "KEYBOARD";
    else
        return false;
}

express_app.listen(port);<commit_msg>Fix for repeated navigation from one app to another.<commit_after>var alexa = require('alexa-app');
var config = require("./config.json");
var route = config.route || "tivo_control";
var port = process.env.port || config.port || 8080;
var bodyParser = require('body-parser');
var express = require('express');
var net = require('net');

var express_app = express();
express_app.use(bodyParser.urlencoded({ extended: true }));
express_app.use(bodyParser.json());
express_app.set('view engine','ejs');

var app = new alexa.app(route);

app.launch(function(request,response) {
    response.say("Welcome to Tivo Control");
});

var IRCODE_COMMANDS = ["UP", "DOWN", "LEFT", "RIGHT", "SELECT", "TIVO", "LIVETV", "GUIDE", "INFO", "EXIT", "THUMBSUP", "THUMBSDOWN", "CHANNELUP", "CHANNELDOWN", "MUTE", "VOLUMEUP", "VOLUMEDOWN", "TVINPUT", "VIDEO_MODE_FIXED_480i", "VIDEO_MODE_FIXED_480p", "VIDEO_MODE_FIXED_720p", "VIDEO_MODE_FIXED_1080i", "VIDEO_MODE_HYBRID", "VIDEO_MODE_HYBRID_720p", "VIDEO_MODE_HYBRID_1080i", "VIDEO_MODE_NATIVE", "CC_ON", "CC_OFF", "OPTIONS", "ASPECT_CORRECTION_FULL", "ASPECT_CORRECTION_PANEL", "ASPECT_CORRECTION_ZOOM", "ASPECT_CORRECTION_WIDE_ZOOM", "PLAY", "FORWARD", "REVERSE", "PAUSE", "SLOW", "REPLAY", "ADVANCE", "RECORD", "NUM0", "NUM1", "NUM2", "NUM3", "NUM4", "NUM5", "NUM6", "NUM7", "NUM8", "NUM9", "ENTER", "CLEAR", "ACTION_A", "ACTION_B", "ACTION_C", "ACTION_D"];
var KEYBOARD_COMMANDS = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "MINUS", "EQUALS", "LBRACKET", "RBRACKET", "BACKSLASH", "SEMICOLON", "QUOTE", "COMMA", "PERIOD", "SLASH", "BACKQUOTE", "SPACE", "KBDUP", "KBDDOWN", "KBDLEFT", "KBDRIGHT", "PAGEUP", "PAGEDOWN", "HOME", "END", "CAPS", "LSHIFT", "RSHIFT", "INSERT", "BACKSPACE", "DELETE", "KBDENTER", "STOP", "VIDEO_ON_DEMAND"];
var TELEPORT_COMMANDS = ["TIVO", "LIVETV", "GUIDE", "NOWPLAYING"];

app.dictionary = {"commands":["UP", "DOWN", "LEFT", "RIGHT", "SELECT", "TIVO", "THUMBSUP", "THUMBSDOWN", "CHANNELUP", "CHANNELDOWN", "MUTE", "VOLUMEDOWN", "VOLUMEUP", "TVINPUT", "OPTIONS", "RECORD", "DISPLAY", "DIRECTV", "ENTER", "CLEAR", "PLAY", "PAUSE", "SLOW", "FORWARD", "REVERSE", "STANDBY", "NOWSHOWING", "REPLAY", "ADVANCE", "DELIMITER", "GUIDE", "KBDUP", "KBDDOWN", "KBDLEFT", "KBDRIGHT", "PAGEUP", "PAGEDOWN", "HOME", "END", "SPACE", "BACKQUOTE", "SLASH", "PERIOD", "COMMA", "QUOTE", "SEMICOLON", "BACKSLASH", "RBRACKET", "LBRACKET", "EQUALS", "MINUS", "CAPS", "LSHIFT", "RSHIFT", "INSERT", "BACKSPACE", "DELETE", "KBDENTER", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]};

app.intent('SendCommand',
    {
        "slots":{"TIVOCOMMAND":"LITERAL"},
        "utterances":[ "send {the|} {command|} {commands|TIVOCOMMAND}" ]
    },
    function(request,response) {
        sendCommand(request.slot("TIVOCOMMAND").toUpperCase());
    });

app.intent('Pause',
    {
        "slots":{},
        "utterances":[ "pause" ]
    },
    function(request,response) {
        sendCommand("PAUSE");
});

app.intent('LiveTV',
    {
        "slots":{},
        "utterances":[ "send {the|} {command|} live tv", "go to live tv" ]
    },
    function(request,response) {
        sendCommand("GUIDE");
        sendCommand("LIVETV");
    });

app.intent('Play',
    {
        "slots":{},
        "utterances":[ "play" ]
    },
    function(request,response) {
        sendCommand("PLAY");
});

app.intent('FastForward',
    {
        "slots":{},
        "utterances":[ "fast forward" ]
    },
    function(request,response) {
        sendCommand("FORWARD");
});

app.intent('SkipCommerial',
    {
        "slots":{},
        "utterances":[ "skip {the|} {this|} {commercial|forward|ahead}" ]
    },
    function(request,response) {
        sendCommand("ACTION_D");
});

app.intent('Record',
    {
        "slots":{},
        "utterances":[ "record {this|the|} {show|current show|this}" ]
    },
    function(request,response) {
        sendCommand("RECORD");
});

app.intent('GoHome',
    {
        "slots":{},
        "utterances":[ "{show|go} {to the|} home {screen|}" ]
    },
    function(request,response) {
        sendCommand("TIVO");
    });

app.intent('Netflix',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} netflix" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('Amazon',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} amazon {video|}" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('Hulu',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} hulu" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('YouTube',
    {
        "slots":{},
        "utterances":[ "{go to|open|turn on|open up|display|jump to|} youtube" ]
    },
    function(request,response) {
        var commands = [
            "GUIDE",
            "TIVO",
            "DOWN",
            "DOWN",
            "RIGHT",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "DOWN",
            "RIGHT"
        ];
        sendCommands(commands);
    });

app.intent('ChangeChannel',
    {
        "slots":{"TIVOCHANNEL":"NUMBER"},
        "utterances":[ "{change|go to} channel {1-100|TIVOCHANNEL}" ]
    },
    function(request,response) {
        changeChannel(request.slot("TIVOCHANNEL"));
    });

app.intent('ForceChannel',
    {
        "slots":{"TIVOCHANNEL":"NUMBER"},
        "utterances":[ "force channel {1-100|TIVOCHANNEL}" ]
    },
    function(request,response) {
        forceChannel(request.slot("TIVOCHANNEL"));
    });

// Manually hook the handler function into express
express_app.post('/'+route,function(req,res) {
    app.request(req.body)        // connect express to alexa-app
        .then(function(response) { // alexa-app returns a promise with the response
            res.json(response);      // stream it to express' output
        });
});

app.express(express_app, "/", true);

if ((process.argv.length === 3) && (process.argv[2] === 'schema'))  {
    console.log (app.schema ());
    console.log (app.utterances ());
}

function sendNextCommand () {
    clearInterval(interval);
    if(queuedCommands.length == 0) {
        if(typeof telnetSocket != "undefined" && typeof telnetSocket.end != "undefined") {
            telnetSocket.end();
            telnetSocket.destroy();
        }
        socketOpen = false;
    }
    else {
        var command = queuedCommands.shift();
        var timeToWait = 100;
        if(typeof command == "object" && typeof command["explicit"] != "undefined") {
            telnetSocket.write(command["command"].toUpperCase() + "\r");
            console.log("Sending Command: " + command["command"].toUpperCase());
            if(command.indexOf("TELEPORT"))
                timeToWait = 700;
        }
        else {
            if(typeof command == "object")
                command = command["command"];
            var prefix = determinePrefix(command);
            if(prefix === false) {
                console.log("ERROR: Command Not Supported: " + command);
                telnetSocket.end();
            }
            else {
                telnetSocket.write(prefix + " " + command.toUpperCase() + "\r");
                console.log("Sending Command: "+prefix + " " + command.toUpperCase());
            }
            if(prefix == "TELEPORT")
                timeToWait = 700;
        }
        setTimeout(sendNextCommand, timeToWait);
    }
}

var queuedCommands = [];
var telnetSocket;
var socketOpen = false;
var interval;
var noResponse = true;
function sendCommands(commands) {

    var host = config.tivoIP;
    var port = config.tivoPort;

    queuedCommands = [];
    for(var i=0; i<commands.length; i++) {
        queuedCommands.push(commands[i]);
    }
    console.log("QueuedCommands: "+queuedCommands.join(","));

    telnetSocket = net.createConnection({
        port: port,
        host: host
    });
    console.log("Connection Created");
    socketOpen = true;
    telnetSocket.on('data', function(data) {
        noResponse = false;
        console.log("RECEIVED: "+data.toString());
        interval = setInterval(sendNextCommand, 100);
    });
    telnetSocket.on('timeout', function(data) {
        console.log("TIMEOUT RECEIVED");
        if(socketOpen)
            sendNextCommand();
    });
    telnetSocket.on('end', function(data) {
        socketOpen = false;
    });
    noResponse = true;
    setTimeout(function(){
        if(noResponse) {
            telnetSocket.write("TELEPORT GUIDE" + "\r");
        }
    }, 700);
}

function sendCommand(command, explicit) {
    if(typeof explicit == "undefined") {
        explicit = false;
    }
    var host = config.tivoIP;
    var port = config.tivoPort;
    var telnetSocket = net.createConnection({
        port: port,
        host: host
    });
    telnetSocket.on('data', function(data) {
        console.log("RECEIVED: "+data.toString());
    });
    if(explicit) {
        telnetSocket.write(command.toUpperCase() + "\r");
        console.log("Sending Command: " + command.toUpperCase());
    }
    else {
        var prefix = determinePrefix(command);
        if(prefix === false)
            console.log("ERROR: Command Not Support: "+command);
        else {
            telnetSocket.write(prefix + " " + command.toUpperCase() + "\r");
            console.log("Sending Command: "+prefix + " " + command.toUpperCase());
        }
    }
    telnetSocket.end();
    telnetSocket.destroy();
}

function changeChannel(channel) {
    return sendCommand("SETCH "+channel, true);
}

function forceChannel(channel) {
    return sendCommand("FORCECH "+channel, true);
}

function determinePrefix(command) {
    if(TELEPORT_COMMANDS.indexOf(command) != -1)
        return "TELEPORT";
    else if(IRCODE_COMMANDS.indexOf(command) != -1)
        return "IRCODE";
    else if(KEYBOARD_COMMANDS.indexOf(command) != -1)
        return "KEYBOARD";
    else
        return false;
}

express_app.listen(port);<|endoftext|>


<commit_before>const express = require('express');
const path = require('path');
const logger = require('morgan');
const bodyParser = require('body-parser');

const chapter04 = require('./chapter_04/router');

const app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(require('node-sass-middleware')({
  src: path.join(__dirname, 'public'),
  dest: path.join(__dirname, 'public'),
  indentedSyntax: false,
  sourceMap: true
}));

app.use(express.static(path.join(__dirname, 'public')));

app.get('/', (req, res) => {
  res.render('index', { title: 'AWS Examples' });
});

app.use('/chapter_04', chapter04);
// app.get('/chapter_:chapterNumber/:example', (req, res) => {
//   console.log(req.params.chapterNumber);
//   console.log(req.params.example);
// });

// catch 404 and forward to error handler
app.use((req, res, next) => {
  const err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use((err, req, res) => {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: err
  });
});

module.exports = app;
<commit_msg>Remove routing comment<commit_after>const express = require('express');
const path = require('path');
const logger = require('morgan');
const bodyParser = require('body-parser');

const chapter04 = require('./chapter_04/router');

const app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');

app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(require('node-sass-middleware')({
  src: path.join(__dirname, 'public'),
  dest: path.join(__dirname, 'public'),
  indentedSyntax: false,
  sourceMap: true
}));

app.use(express.static(path.join(__dirname, 'public')));

app.get('/', (req, res) => {
  res.render('index', { title: 'AWS Examples' });
});

app.use('/chapter_04', chapter04);

// catch 404 and forward to error handler
app.use((req, res, next) => {
  const err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handler
app.use((err, req, res) => {
  res.status(err.status || 500);
  res.render('error', {
    message: err.message,
    error: err
  });
});

module.exports = app;
<|endoftext|>


<commit_before>
/**
 * Module dependencies.
 */

var express = require('express')
  , fs = require('fs')
  // pass false to disable use of memcached
  , processor = require('./process.js')

var app = module.exports = express.createServer();

// Configuration

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

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

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes

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

app.get('/compile', function(req, res) {
    function processCallback(err, data) {
        if (err) {
            res.writeHead(500, {'content-type': 'text/plain'});
            res.write(err.toString());
            res.end();
        } else {
            res.writeHead(200, {
                'content-type': 'application/pdf',
                'content-length': data.length
            });
            res.write(data);
            res.end();
        }
    }
    if (req.query['git'] && req.query['target']) {
        processor.processGit(req.query['git'], req.query['target'], processCallback);
    } else {
        processor.processUrl(req.query['url'], processCallback);
    }

});

app.post('/data', function(req, res) {
    if (!req.query['target']) {
        res.writeHead(412, {'content-type': 'text/plain'});
        res.write("You're using old remote-compile.sh tool\n");
        res.write("Upgrade at https://github.com/aslushnikov/latex-online");
        res.end();
        return;
    }
    processor.processFile(req.files['file'].path, req.query['target'], function(err, data) {
        if (err) {
            res.writeHead(400, {'content-type': 'text/plain'});
            res.write(err.toString());
            res.end();
        } else {
            res.writeHead(200, {
                'content-type': 'application/pdf',
                'content-length': data.length
            });
            res.write(data);
            res.end();
        }
    });
});

app.listen(2700);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
<commit_msg>Refactoring app.js routes<commit_after>
/**
 * Module dependencies.
 */

var express = require('express')
  , fs = require('fs')
  // pass false to disable use of memcached
  , processor = require('./process.js')

var app = module.exports = express.createServer();

// Configuration

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
});

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

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Routes

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

function success(req, res, next) {
    if (req.latexOnline.err) {
        res.writeHead(400, {'content-type': 'text/plain'});
        res.write(req.latexOnline.err.toString());
        res.end();
    } else {
        res.writeHead(200, {
            'content-type': 'application/pdf',
            'content-length': req.latexOnline.data.length
        });
        res.write(req.latexOnline.data);
        res.end();
    }
}

function computeCompilation(req, res, next) {
    if (req.query['git'] && req.query['target']) {
        processor.processGit(req.query['git'], req.query['target'], function(err, data) {
            req.latexOnline = {err: err, data: data};
            next();
        });
    } else {
        processor.processUrl(req.query['url'], function(err, data) {
            req.latexOnline = {err: err, data: data};
            next();
        });
    }
}

function checkUtilityCompatability(req, res, next) {
    if (!req.query['target']) {
        res.writeHead(412, {'content-type': 'text/plain'});
        res.write("You're using old remote-compile.sh tool\n");
        res.write("Upgrade at https://github.com/aslushnikov/latex-online");
        res.end();
        return;
    }
    next();
}

app.get('/compile', computeCompilation, success);

app.post('/data', checkUtilityCompatability, function(req, res, next) {
    processor.processFile(req.files['file'].path,
            req.query['target'], function(err, data) {
                req.latexOnline = {err: err, data:data};
                next();
            });
}, success);

app.listen(2700);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);
<|endoftext|>


<commit_before>var canvas  = document.getElementsByTagName("canvas")[0],
    wrapper = document.getElementById("canvaswrapper"),
    ctx     = canvas.getContext("2d"),
    gif     = new GIFEncoder(),
    color   = document.getElementById("currentColor");

var W = 16, H = 16;

gif.setRepeat(0); //auto-loop
gif.setDelay(1000);
gif.setSize(W, H);
gif.start();

ctx.imageSmoothingEnabled = false;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, W, H);

var mx, my, imgData = ctx.getImageData(0, 0, W, H), currentFrame = 0;

wrapper.addEventListener("mousemove", function(e) {
  mx = Math.round((e.offsetX - 5) / 40);
  my = Math.round((e.offsetY - 5) / 40);
});

wrapper.addEventListener("mouseout", function() {
  mx = -1;
  my = -1;
});

wrapper.addEventListener("click", function(e) {
  ctx.globalAlpha = 1.0;
  ctx.fillStyle = color.value;
  ctx.fillRect(mx, my, 1, 1);
  imgData = ctx.getImageData(0, 0, W, H);
  gif.addFrame(canvas);
})

document.getElementById("addFrame").addEventListener("click", function(e) {
    var img = new Image();
    img.id = "frame" + currentFrame;
    img.className = "frame";
    img.src = canvas.toDataURL("image/png");
    gif.addFrame(ctx);
    currentFrame++;
    wrapper.insertBefore(img, canvas);

    // Clear

    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, W, H);
    imgData = ctx.getImageData(0, 0, W, H);

});

document.getElementById("export").addEventListener("click", function(e) {
    gif.finish();
    document.getElementById('output').src = 'data:image/gif;base64,'+encode64(gif.stream().getData())
});

function render() {
  ctx.putImageData(imgData, 0, 0);
  /*
  if(currentFrame > 0) {
    ctx.globalAlpha = 0.5;
    ctx.drawImage(document.getElementById("frame" + (currentFrame - 1)), 0, 0);
    ctx.globalAlpha = 1.0;
  }*/
  ctx.fillRect(mx, my, 1, 1);
  requestAnimationFrame(render);
}
render();
<commit_msg>Removed dead code<commit_after>var canvas  = document.getElementsByTagName("canvas")[0],
    wrapper = document.getElementById("canvaswrapper"),
    ctx     = canvas.getContext("2d"),
    gif     = new GIFEncoder(),
    color   = document.getElementById("currentColor");

var W = 16, H = 16;

gif.setRepeat(0); //auto-loop
gif.setDelay(1000);
gif.setSize(W, H);
gif.start();

ctx.imageSmoothingEnabled = false;
ctx.fillStyle = "white";
ctx.fillRect(0, 0, W, H);

var mx, my, imgData = ctx.getImageData(0, 0, W, H), currentFrame = 0;

wrapper.addEventListener("mousemove", function(e) {
  mx = Math.round((e.offsetX - 5) / 40);
  my = Math.round((e.offsetY - 5) / 40);
});

wrapper.addEventListener("mouseout", function() {
  mx = -1;
  my = -1;
});

wrapper.addEventListener("click", function(e) {
  ctx.globalAlpha = 1.0;
  ctx.fillStyle = color.value;
  ctx.fillRect(mx, my, 1, 1);
  imgData = ctx.getImageData(0, 0, W, H);
  gif.addFrame(canvas);
})

document.getElementById("addFrame").addEventListener("click", function(e) {
    var img = new Image();
    img.id = "frame" + currentFrame;
    img.className = "frame";
    img.src = canvas.toDataURL("image/png");
    gif.addFrame(ctx);
    currentFrame++;
    wrapper.insertBefore(img, canvas);

    // Clear

    ctx.fillStyle = "white";
    ctx.fillRect(0, 0, W, H);
    imgData = ctx.getImageData(0, 0, W, H);

});

document.getElementById("export").addEventListener("click", function(e) {
    gif.finish();
    document.getElementById('output').src = 'data:image/gif;base64,'+encode64(gif.stream().getData())
});

function render() {
  ctx.putImageData(imgData, 0, 0);
  ctx.fillRect(mx, my, 1, 1);
  requestAnimationFrame(render);
}
render();
<|endoftext|>


<commit_before>var express = require('express');
var app = express();

app.use(express.static(__dirname + '/public'));

var port = process.env.PORT || 8989;

var server = app.listen(port);

var io = require('socket.io')(server);

var farms = {};
var marketListings = [];

var Farm = function(pw, row, col) {
  this.gold = 20;
  this.farm = [];
  for (var i = 0; i < row; i++) {
    this.farm.push([]);
    for (var j = 0; j < col; j++) {
      this.farm[i].push({
        row: i,
        col: j,
        plant: {}
      });
    }
  }
  this.inventory = [];
  this.inventory.push({
    plant: mutatePlant(new Plant(), false),
    quantity: 3
  });
  this.password = pw;
};

var Plant = function() {
  this.name = "carrot";
  this.age = 0;
  this.ripetime = 10;
  this.yield = 10;
  this.color = "#FF0000";
  this.shape = 0;
  this.hash = this.name + this.ripetime + this.yield + this.color + this.shape;
};

var mutatePlant = function(plant, attrmod) {
  var plantTypes = ["tomato", "carrot", "pickle", "peas"];
  plant.age = 0;
  var decreaseRipe = Math.floor(Math.random() * 2);
  if (decreaseRipe === 0 && attrmod) plant.ripetime /= Math.floor(Math.random() * 2) + 1;
  else plant.ripetime *= Math.floor(Math.random() * 5) + 1;
  plant.color = '#' + Math.floor(Math.random() * 16777215).toString(16);
  var changeYield = Math.floor(Math.random() * 2);
  if (changeYield === 0 && attrmod) plant.yield += Math.floor(Math.random() * 51);
  var plantType = Math.floor(Math.random() * 4);
  plant.name = plantTypes[plantType];
  plant.hash = plant.name + plant.ripetime + plant.yield + plant.color + plant.shape;
  return plant;
};

console.log("Farmland is running on port 8989");

function plantFood(owner, tile, cb) {
  var inventory = farms[owner].inventory;
  var row = tile.row;
  var col = tile.col;
  var plant = farms[owner].farm[row][col].plant;
  if (plant.hash !== undefined) {
    return false;
  }
  var found = false;
  inventory.forEach(function(item) {
    if (tile.plant.hash == item.plant.hash && item.quantity > 0) {
      item.quantity--;
      item.plant.age = 0;
      farms[owner].farm[row][col] = {
        row: row,
        col: col,
        plant: item.plant
      };
      found = true;
    }
  });
  return found;
}

function pickFood(owner, row, col) {
  var plant = farms[owner].farm[row][col].plant;
  var inventory = farms[owner].inventory;
  if (plant.hash !== undefined && plant.age > plant.ripetime) {
    var found = false;
    inventory.forEach(function(item) {
      if (item.plant.hash == plant.hash) {
        var seedYield = Math.floor(Math.random() * 2) + 1;
        var mutate = Math.floor(Math.random() * 10);
        if (mutate === 0) {
          var newitem = mutatePlant(JSON.parse(JSON.stringify(item.plant)), true);
          inventory.push({
            plant: newitem,
            quantity: seedYield
          });
        } else item.quantity += seedYield;
        farms[owner].farm[row][col] = {
          row: row,
          col: col,
          plant: {}
        };
        found = true;
      }
    });
    if (!found) {
      plant.age = 0;
      inventory.push({
        plant: plant,
        quantity: 3
      });
      plant = {
        row: row,
        col: col,
        plant: {}
      };
    }
    return true;
  }
  return false;
}

io.on('connection', function(socket) {
  var name = "";
  var interval;
  socket.on("createFarm", function(nm, pw, cb) {
    name = nm;
    if (farms[nm] === undefined) {
      var farm = new Farm(pw, 7, 7);
      farms[nm] = farm;
      cb(farm);
    } else if (farms[nm].password == pw) {
      cb(farms[nm]);
			socket.emit("market", marketListings);
    } else {
      cb(false);
    }
    interval = setInterval(growFood, 1000);
  });
  socket.on("plantFood", function(nm, tile, cb) {
    cb(plantFood(nm, tile));
		socket.emit("update", farms[name]);
  });
  socket.on("pickFood", function(nm, row, col, cb) {
    cb(pickFood(nm, row, col));
  });
  socket.on("sell", function(item) {
    if (item.quantity > 0) {
      farms[name].inventory.forEach(function(i) {
        if (item.plant.hash == i.plant.hash) {
          i.quantity--;
          farms[name].gold += i.plant.yield;
          socket.emit("update", farms[name]);
        }
      });
    }
  });
	socket.on("buy", function(index){
		var listing = marketListings[index];
		if(listing !== undefined && listing.quantity > 0){
			listing.quantity--;
			farms[listing.seller].gold += Math.abs(listing.price);
			farms[name].gold -= Math.abs(listing.price);
			var found = false;
			farms[name].inventory.forEach(function(item){
				if(item.plant.hash == listing.plant.hash){
					item.quantity++;
					console.log(item);
					found = true;
				}
			});
			if(!found) farms[name].inventory.push({plant:listing.plant, quantity:1});
			io.emit("market", marketListings);
			socket.emit("update", farms[name]);
		}
	});
	socket.on("market", function(item){
		farms[name].inventory.forEach(function(i){
			if(item.plant.hash == i.plant.hash){
				i.quantity--;
				var found = false;
				marketListings.forEach(function(q){
					if(i.plant.hash == q.plant.hash && q.seller == name){
						found = true;
						q.quantity++;
					}
				});
				if(!found) marketListings.push({plant: item.plant, price: item.plant.yield+15, seller: name, quantity: 1});
				socket.emit("update", farms[name]);
				io.emit("market", marketListings);
			}
		});
	});
	socket.on("buyland", function(){

	});
  var growFood = function() {
    farms[name].farm.forEach(function(row) {
      row.forEach(function(tile) {
        if (tile.plant.age !== undefined) {
          tile.plant.age++;
          socket.emit("update", farms[name]);
        }
      });
    });
  };
  socket.on("disconnect", function() {
    clearInterval(interval);
  });
});
<commit_msg>tabs, not spaces<commit_after>var express = require('express');
var app = express();

app.use(express.static(__dirname + '/public'));

var port = process.env.PORT || 8989;

var server = app.listen(port);

var io = require('socket.io')(server);

var farms = {};
var marketListings = [];

var Farm = function(pw, row, col) {
	this.gold = 20;
	this.farm = [];
	for (var i = 0; i < row; i++) {
		this.farm.push([]);
		for (var j = 0; j < col; j++) {
			this.farm[i].push({
				row: i,
				col: j,
				plant: {}
			});
		}
	}
	this.inventory = [];
	this.inventory.push({
		plant: mutatePlant(new Plant(), false),
		quantity: 3
	});
	this.password = pw;
};

var Plant = function() {
	this.name = "carrot";
	this.age = 0;
	this.ripetime = 10;
	this.yield = 10;
	this.color = "#FF0000";
	this.shape = 0;
	this.hash = this.name + this.ripetime + this.yield + this.color + this.shape;
};

var mutatePlant = function(plant, attrmod) {
	var plantTypes = ["tomato", "carrot", "pickle", "peas"];
	plant.age = 0;
	var decreaseRipe = Math.floor(Math.random() * 2);
	if (decreaseRipe === 0 && attrmod) plant.ripetime /= Math.floor(Math.random() * 2) + 1;
	else plant.ripetime *= Math.floor(Math.random() * 5) + 1;
	plant.color = '#' + Math.floor(Math.random() * 16777215).toString(16);
	var changeYield = Math.floor(Math.random() * 2);
	if (changeYield === 0 && attrmod) plant.yield += Math.floor(Math.random() * 51);
	var plantType = Math.floor(Math.random() * 4);
	plant.name = plantTypes[plantType];
	plant.hash = plant.name + plant.ripetime + plant.yield + plant.color + plant.shape;
	return plant;
};

console.log("Farmland is running on port 8989");

function plantFood(owner, tile, cb) {
	var inventory = farms[owner].inventory;
	var row = tile.row;
	var col = tile.col;
	var plant = farms[owner].farm[row][col].plant;
	if (plant.hash !== undefined) {
		return false;
	}
	var found = false;
	inventory.forEach(function(item) {
		if (tile.plant.hash == item.plant.hash && item.quantity > 0) {
			item.quantity--;
			item.plant.age = 0;
			farms[owner].farm[row][col] = {
				row: row,
				col: col,
				plant: item.plant
			};
			found = true;
		}
	});
	return found;
}

function pickFood(owner, row, col) {
	var plant = farms[owner].farm[row][col].plant;
	var inventory = farms[owner].inventory;
	if (plant.hash !== undefined && plant.age > plant.ripetime) {
		var found = false;
		inventory.forEach(function(item) {
			if (item.plant.hash == plant.hash) {
				var seedYield = Math.floor(Math.random() * 2) + 1;
				var mutate = Math.floor(Math.random() * 10);
				if (mutate === 0) {
					var newitem = mutatePlant(JSON.parse(JSON.stringify(item.plant)), true);
					inventory.push({
						plant: newitem,
						quantity: seedYield
					});
				} else item.quantity += seedYield;
				farms[owner].farm[row][col] = {
					row: row,
					col: col,
					plant: {}
				};
				found = true;
			}
		});
		if (!found) {
			plant.age = 0;
			inventory.push({
				plant: plant,
				quantity: 3
			});
			plant = {
				row: row,
				col: col,
				plant: {}
			};
		}
		return true;
	}
	return false;
}

io.on('connection', function(socket) {
	var name = "";
	var interval;
	socket.on("createFarm", function(nm, pw, cb) {
		name = nm;
		if (farms[nm] === undefined) {
			var farm = new Farm(pw, 7, 7);
			farms[nm] = farm;
			cb(farm);
		} else if (farms[nm].password == pw) {
			cb(farms[nm]);
			socket.emit("market", marketListings);
		} else {
			cb(false);
		}
		interval = setInterval(growFood, 1000);
	});
	socket.on("plantFood", function(nm, tile, cb) {
		cb(plantFood(nm, tile));
		socket.emit("update", farms[name]);
	});
	socket.on("pickFood", function(nm, row, col, cb) {
		cb(pickFood(nm, row, col));
	});
	socket.on("sell", function(item) {
		if (item.quantity > 0) {
			farms[name].inventory.forEach(function(i) {
				if (item.plant.hash == i.plant.hash) {
					i.quantity--;
					farms[name].gold += i.plant.yield;
					socket.emit("update", farms[name]);
				}
			});
		}
	});
	socket.on("buy", function(index){
		var listing = marketListings[index];
		if(listing !== undefined && listing.quantity > 0){
			listing.quantity--;
			farms[listing.seller].gold += Math.abs(listing.price);
			farms[name].gold -= Math.abs(listing.price);
			var found = false;
			farms[name].inventory.forEach(function(item){
				if(item.plant.hash == listing.plant.hash){
					item.quantity++;
					console.log(item);
					found = true;
				}
			});
			if(!found) farms[name].inventory.push({plant:listing.plant, quantity:1});
			io.emit("market", marketListings);
			socket.emit("update", farms[name]);
		}
	});
	socket.on("market", function(item){
		farms[name].inventory.forEach(function(i){
			if(item.plant.hash == i.plant.hash){
				i.quantity--;
				var found = false;
				marketListings.forEach(function(q){
					if(i.plant.hash == q.plant.hash && q.seller == name){
						found = true;
						q.quantity++;
					}
				});
				if(!found) marketListings.push({plant: item.plant, price: item.plant.yield+15, seller: name, quantity: 1});
				socket.emit("update", farms[name]);
				io.emit("market", marketListings);
			}
		});
	});
	socket.on("buyland", function(){

	});
	var growFood = function() {
		farms[name].farm.forEach(function(row) {
			row.forEach(function(tile) {
				if (tile.plant.age !== undefined) {
					tile.plant.age++;
					socket.emit("update", farms[name]);
				}
			});
		});
	};
	socket.on("disconnect", function() {
		clearInterval(interval);
	});
});
<|endoftext|>


<commit_before>'use strict';
var express = require('express'),
    app = express(),
    fs = require('fs'),
    http = require('http').Server(app),
    io = require('socket.io')(http);

var question,
    questionsList = JSON.parse(fs.readFileSync('./generatedCountries.json', 'utf8'));

var users = [];
var leaders = [{name: 'Anton', points: 50}, {name: 'Pasha', points: 60}, {name: 'Maryna', points: 70}];

question = getRandomQuestion();

sendLeaders(leaders);

sendQuestion(question)

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

  socket.on('user created', function(user){
    io.emit('user greeting', 'Hello, ' + user + '!');
    users.push({name: user, connectionId: socket.id});
    io.emit('online users', users);
  });

    io.emit('online users', users);

  socket.on('message', function(msg){
    var answer = msg.message;
    io.emit('message', msg);
    io.emit('answer', checkTheAnswer(answer));
  });

  socket.on('disconnect', function(){
    for(var i in users){
        if(users[i].connectionId === socket.id){
            users.splice(i, 1);
        }
    }
       io.emit('online users', users);
  });

});

app.set('port', (process.env.PORT || 3000))
app.use(express.static('public'));

http.listen(app.get('port'), function(){
  console.log('listening on *:3000');
});

function sendLeaders(leaders){
    app.get('/leaders', function(request, response) {
        leaders.map(function(leader){
            leader.points = Math.floor(Math.random() * (100 - 0 + 1)) + 0;
        });

        leaders.sort(function(obj1, obj2){
            return obj2.points - obj1.points;
        });

        response.send(leaders);
    });
}

function sendQuestion(question){
    app.get('/question', function(request, response) {
        response.send(question);
    });
}

function getRandomQuestion(){
    var randomQuestion = questionsList[Math.floor(Math.random()*questionsList.length)];
    return JSON.parse(randomQuestion);
}

function checkTheAnswer(userAnswer){
    if(question.answer.toLowerCase() === userAnswer.toLowerCase()){
        question = getRandomQuestion();
        return question;
    }
}
<commit_msg>move question to sendQuestion<commit_after>'use strict';
var express = require('express'),
    app = express(),
    fs = require('fs'),
    http = require('http').Server(app),
    io = require('socket.io')(http);

var question,
    questionsList = JSON.parse(fs.readFileSync('./generatedCountries.json', 'utf8'));

var users = [];
var leaders = [{name: 'Anton', points: 50}, {name: 'Pasha', points: 60}, {name: 'Maryna', points: 70}];

sendLeaders(leaders);

sendQuestion();

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

  socket.on('user created', function(user){
    io.emit('user greeting', 'Hello, ' + user + '!');
    users.push({name: user, connectionId: socket.id});
    io.emit('online users', users);
  });

    io.emit('online users', users);

  socket.on('message', function(msg){
    var answer = msg.message;
    io.emit('message', msg);
    io.emit('answer', checkTheAnswer(answer));
  });

  socket.on('disconnect', function(){
    for(var i in users){
        if(users[i].connectionId === socket.id){
            users.splice(i, 1);
        }
    }
       io.emit('online users', users);
  });

});

app.set('port', (process.env.PORT || 3000))
app.use(express.static('public'));

http.listen(app.get('port'), function(){
  console.log('listening on *:3000');
});

function sendLeaders(leaders){
    app.get('/leaders', function(request, response) {
        leaders.map(function(leader){
            leader.points = Math.floor(Math.random() * (100 - 0 + 1)) + 0;
        });

        leaders.sort(function(obj1, obj2){
            return obj2.points - obj1.points;
        });

        response.send(leaders);
    });
}

function sendQuestion(){
    question = getRandomQuestion();
    app.get('/question', function(request, response) {
        response.send(question);
    });
}

function getRandomQuestion(){
    var randomQuestion = questionsList[Math.floor(Math.random()*questionsList.length)];
    return JSON.parse(randomQuestion);
}

function checkTheAnswer(userAnswer){
    if(question.answer.toLowerCase() === userAnswer.toLowerCase()){
        question = getRandomQuestion();
        return question;
    }
}
<|endoftext|>


<commit_before>var express     = require('express');
var path        = require('path');
var app         = express();
var mongo       = require('./MongoDB.js');
var bodyParser  = require('body-parser');
var crypto      = require('crypto');
var signCode    = 'abc.123';

var md5 = function(str){
  var md5 = crypto.createHash('md5');
  md5.update(str);
  return md5.digest('hex');
}

app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'public')));

// index
app.get("/", function(req, res){
	res.redirect("/index.html");
});

// search logs
app.post('/MongoDB/search', function(req, res) {

  var project = req.body.project;
  var name    = req.body.name;
  var msg     = req.body.msg;
  var level   = req.body.level;
  var start   = new Date(req.body.startD + ' ' + req.body.startT)
  var end     = new Date(req.body.endD + ' ' + req.body.endT)

  var opt = {
    project: project,
    level: level,
    name: new RegExp(name),
    msg: new RegExp(msg),
    _time: {
      $gt: start.getTime(),
      $lt: end.getTime()
    }
  }

  level === 'ALL' && (delete opt.level);
  name  === 'ALL' && (delete opt.name);
  msg   === 'ALL' && (delete opt.msg);

  isNaN(start.getTime()) && (delete opt._time['$gt'])
  isNaN(end.getTime())   && (delete opt._time['$lt'])

  isNaN(start.getTime()) && isNaN(end.getTime()) && (delete opt._time)

  opt = {
    $query: opt,
    $orderby: {
      _time: -1
    }
  }

  mongo.select('logs', opt, function(err, docs) {
    res.json({results: docs});
  })

});

// Add log
app.post('/MongoDB/logs', function(req, res){
  try {

    var now   = new Date().getTime();
    var t     = req.headers['x-time']
    var sign  = req.headers['x-sign'];

    if (now - t > 10000) {
      return res.json({err: 'Timeout'})
    }

    if (!t || !sign) {
      return res.json({err: 'NoHeader'});
    }

    if (md5(signCode + t) !== sign) {
      return res.json({err: "SignError"})
    }

    mongo.insert('logs', req.body, function(err, id, result){
      res.json({id: id});
    });

  } catch (e) {
    res.send(e);
  }
});

// Get log
// app.get('/MongoDB/logs/:col', function(req, res){

// 	var opt = req.query["options"];
// 	if (opt === undefined || opt === "")
// 		opt = {};
// 	else {
// 		opt = eval("(" + opt + ")")
// 	}

// 	mongo.select(req.param('col'), opt, function(err, docs){
// 		// Jsonp request
// 		res.jsonp(docs);
// 	});
// });

// Get log by id
// app.get('/MongoDB/logs/:col/:id', function(req, res){
// 	mongo.selectByID(req.param('col'), req.param('id'), function(err, docs){
// 		res.jsonp(docs);
// 	});
// });

// Modify log by id
// app.put('/MongoDB/logs/:col/:id', function(req, res){
// 	var doc = JSON.parse(req.body["doc"]);
// 	mongo.update(req.param('col'), req.param('id'), doc, function(err, result) {
// 		res.jsonp(result);
// 	});
// });

// Delete log by id
// app.delete('/MongoDB/logs/:col/:id', function(req, res){
// 	mongo.delete(req.param('col'), req.param('id'), function(err, result){
// 		res.jsonp(result);
// 	});
// });

app.listen(3000);
<commit_msg>update signcode<commit_after>var express     = require('express');
var path        = require('path');
var app         = express();
var mongo       = require('./MongoDB.js');
var bodyParser  = require('body-parser');
var crypto      = require('crypto');
var signCode    = 'your-sign-code';

var md5 = function(str){
  var md5 = crypto.createHash('md5');
  md5.update(str);
  return md5.digest('hex');
}

app.use(bodyParser.json());
app.use(express.static(path.join(__dirname, 'public')));

// index
app.get("/", function(req, res){
	res.redirect("/index.html");
});

// search logs
app.post('/MongoDB/search', function(req, res) {

  var project = req.body.project;
  var name    = req.body.name;
  var msg     = req.body.msg;
  var level   = req.body.level;
  var start   = new Date(req.body.startD + ' ' + req.body.startT)
  var end     = new Date(req.body.endD + ' ' + req.body.endT)

  var opt = {
    project: project,
    level: level,
    name: new RegExp(name),
    msg: new RegExp(msg),
    _time: {
      $gt: start.getTime(),
      $lt: end.getTime()
    }
  }

  level === 'ALL' && (delete opt.level);
  name  === 'ALL' && (delete opt.name);
  msg   === 'ALL' && (delete opt.msg);

  isNaN(start.getTime()) && (delete opt._time['$gt'])
  isNaN(end.getTime())   && (delete opt._time['$lt'])

  isNaN(start.getTime()) && isNaN(end.getTime()) && (delete opt._time)

  opt = {
    $query: opt,
    $orderby: {
      _time: -1
    }
  }

  mongo.select('logs', opt, function(err, docs) {
    res.json({results: docs});
  })

});

// Add log
app.post('/MongoDB/logs', function(req, res){
  try {

    var now   = new Date().getTime();
    var t     = req.headers['x-time']
    var sign  = req.headers['x-sign'];

    if (now - t > 10000) {
      return res.json({err: 'Timeout'})
    }

    if (!t || !sign) {
      return res.json({err: 'NoHeader'});
    }

    if (md5(signCode + t) !== sign) {
      return res.json({err: "SignError"})
    }

    mongo.insert('logs', req.body, function(err, id, result){
      res.json({id: id});
    });

  } catch (e) {
    res.send(e);
  }
});

// Get log
// app.get('/MongoDB/logs/:col', function(req, res){

// 	var opt = req.query["options"];
// 	if (opt === undefined || opt === "")
// 		opt = {};
// 	else {
// 		opt = eval("(" + opt + ")")
// 	}

// 	mongo.select(req.param('col'), opt, function(err, docs){
// 		// Jsonp request
// 		res.jsonp(docs);
// 	});
// });

// Get log by id
// app.get('/MongoDB/logs/:col/:id', function(req, res){
// 	mongo.selectByID(req.param('col'), req.param('id'), function(err, docs){
// 		res.jsonp(docs);
// 	});
// });

// Modify log by id
// app.put('/MongoDB/logs/:col/:id', function(req, res){
// 	var doc = JSON.parse(req.body["doc"]);
// 	mongo.update(req.param('col'), req.param('id'), doc, function(err, result) {
// 		res.jsonp(result);
// 	});
// });

// Delete log by id
// app.delete('/MongoDB/logs/:col/:id', function(req, res){
// 	mongo.delete(req.param('col'), req.param('id'), function(err, result){
// 		res.jsonp(result);
// 	});
// });

app.listen(3000);
console.log('Listen on 3000.')
<|endoftext|>


<commit_before>const WXAPI = require('wxapi/main')
App({
  navigateToLogin: false,
  onLaunch: function() {
    const that = this;
    // 检测新版本
    const updateManager = wx.getUpdateManager()
    updateManager.onUpdateReady(function () {
      wx.showModal({
        title: '更新提示',
        content: '新版本已经准备好，是否重启应用？',
        success(res) {
          if (res.confirm) {
            // 新的版本已经下载好，调用 applyUpdate 应用新版本并重启
            updateManager.applyUpdate()
          }
        }
      })
    })
    /**
     * 初次加载判断网络情况
     * 无网络状态下根据实际情况进行调整
     */
    wx.getNetworkType({
      success(res) {
        const networkType = res.networkType
        if (networkType === 'none') {
          that.globalData.isConnected = false
          wx.showToast({
            title: '当前无网络',
            icon: 'loading',
            duration: 2000
          })
        }
      }
    });
    /**
     * 监听网络状态变化
     * 可根据业务需求进行调整
     */
    wx.onNetworkStatusChange(function(res) {
      if (!res.isConnected) {
        that.globalData.isConnected = false
        wx.showToast({
          title: '网络已断开',
          icon: 'loading',
          duration: 2000,
          complete: function() {
            that.goStartIndexPage()
          }
        })
      } else {
        that.globalData.isConnected = true
        wx.hideToast()
      }
    });
    //  获取接口和后台权限
    WXAPI.vipLevel().then(res => {
      that.globalData.vipLevel = res.data
    })
    //  获取商城名称
    WXAPI.queryConfigBatch('mallName,recharge_amount_min,ALLOW_SELF_COLLECTION').then(function(res) {
      if (res.code == 0) {
        res.data.forEach(config => {
          wx.setStorageSync(config.key, config.value);
          if (config.key === 'recharge_amount_min') {
            that.globalData.recharge_amount_min = res.data.value;
          }
        })

      }
    })
    WXAPI.scoreRules({
      code: 'goodReputation'
    }).then(function(res) {
      if (res.code == 0) {
        that.globalData.order_reputation_score = res.data[0].score;
      }
    })
  },
  goLoginPageTimeOut: function() {
    if (this.navigateToLogin){
      return
    }
    wx.removeStorageSync('token')
    this.navigateToLogin = true
    setTimeout(function() {
      wx.navigateTo({
        url: "/pages/authorize/index"
      })
    }, 1000)
  },
  goStartIndexPage: function() {
    setTimeout(function() {
      wx.redirectTo({
        url: "/pages/start/start"
      })
    }, 1000)
  },
  onShow (e) {
    const _this = this
    const token = wx.getStorageSync('token');
    if (!token) {
      _this.goLoginPageTimeOut()
      return
    }
    WXAPI.checkToken(token).then(function (res) {
      if (res.code != 0) {
        wx.removeStorageSync('token')
        _this.goLoginPageTimeOut()
      }
    })
    wx.checkSession({
      fail() {
        _this.goLoginPageTimeOut()
      }
    })
    this.globalData.launchOption = e
    // 保存邀请人
    if (e && e.query && e.query.inviter_id) {
      wx.setStorageSync('referrer', e.query.inviter_id)
      if (e.shareTicket) {
        // 通过分享链接进来
        wx.getShareInfo({
          shareTicket: e.shareTicket,
          success: res => {
            console.error(res)
            console.error({
              referrer: e.query.inviter_id,
              encryptedData: res.encryptedData,
              iv: res.iv
            })
            WXAPI.shareGroupGetScore(
              e.query.inviter_id,
              res.encryptedData,
              res.iv
            )
          }
        })
      }
    }
  },
  globalData: {
    isConnected: true,
    launchOption: undefined,
    vipLevel: 0
  }
})<commit_msg>注释 console.log<commit_after>const WXAPI = require('wxapi/main')
App({
  navigateToLogin: false,
  onLaunch: function() {
    const that = this;
    // 检测新版本
    const updateManager = wx.getUpdateManager()
    updateManager.onUpdateReady(function () {
      wx.showModal({
        title: '更新提示',
        content: '新版本已经准备好，是否重启应用？',
        success(res) {
          if (res.confirm) {
            // 新的版本已经下载好，调用 applyUpdate 应用新版本并重启
            updateManager.applyUpdate()
          }
        }
      })
    })
    /**
     * 初次加载判断网络情况
     * 无网络状态下根据实际情况进行调整
     */
    wx.getNetworkType({
      success(res) {
        const networkType = res.networkType
        if (networkType === 'none') {
          that.globalData.isConnected = false
          wx.showToast({
            title: '当前无网络',
            icon: 'loading',
            duration: 2000
          })
        }
      }
    });
    /**
     * 监听网络状态变化
     * 可根据业务需求进行调整
     */
    wx.onNetworkStatusChange(function(res) {
      if (!res.isConnected) {
        that.globalData.isConnected = false
        wx.showToast({
          title: '网络已断开',
          icon: 'loading',
          duration: 2000,
          complete: function() {
            that.goStartIndexPage()
          }
        })
      } else {
        that.globalData.isConnected = true
        wx.hideToast()
      }
    });
    //  获取接口和后台权限
    WXAPI.vipLevel().then(res => {
      that.globalData.vipLevel = res.data
    })
    //  获取商城名称
    WXAPI.queryConfigBatch('mallName,recharge_amount_min,ALLOW_SELF_COLLECTION').then(function(res) {
      if (res.code == 0) {
        res.data.forEach(config => {
          wx.setStorageSync(config.key, config.value);
          if (config.key === 'recharge_amount_min') {
            that.globalData.recharge_amount_min = res.data.value;
          }
        })

      }
    })
    WXAPI.scoreRules({
      code: 'goodReputation'
    }).then(function(res) {
      if (res.code == 0) {
        that.globalData.order_reputation_score = res.data[0].score;
      }
    })
  },
  goLoginPageTimeOut: function() {
    if (this.navigateToLogin){
      return
    }
    wx.removeStorageSync('token')
    this.navigateToLogin = true
    setTimeout(function() {
      wx.navigateTo({
        url: "/pages/authorize/index"
      })
    }, 1000)
  },
  goStartIndexPage: function() {
    setTimeout(function() {
      wx.redirectTo({
        url: "/pages/start/start"
      })
    }, 1000)
  },
  onShow (e) {
    const _this = this
    const token = wx.getStorageSync('token');
    if (!token) {
      _this.goLoginPageTimeOut()
      return
    }
    WXAPI.checkToken(token).then(function (res) {
      if (res.code != 0) {
        wx.removeStorageSync('token')
        _this.goLoginPageTimeOut()
      }
    })
    wx.checkSession({
      fail() {
        _this.goLoginPageTimeOut()
      }
    })
    this.globalData.launchOption = e
    // 保存邀请人
    if (e && e.query && e.query.inviter_id) {
      wx.setStorageSync('referrer', e.query.inviter_id)
      if (e.shareTicket) {
        // 通过分享链接进来
        wx.getShareInfo({
          shareTicket: e.shareTicket,
          success: res => {
            // console.error(res)
            // console.error({
            //   referrer: e.query.inviter_id,
            //   encryptedData: res.encryptedData,
            //   iv: res.iv
            // })
            WXAPI.shareGroupGetScore(
              e.query.inviter_id,
              res.encryptedData,
              res.iv
            )
          }
        })
      }
    }
  },
  globalData: {
    isConnected: true,
    launchOption: undefined,
    vipLevel: 0
  }
})<|endoftext|>


<commit_before>var Backbone = require('backbone');
var $ = require('jquery');
Backbone.$ = $;
/**
Miners
**/
var Miner = require('./src/js/Miner.js');
var MinerCollection = require('./src/js/collections/MinerCollection.js');
var MinerView = require('./src/js/views/MinerView.js');

var a =  new Miner ({'name':'Pluto','group':'Solar','hashRate':'6 G/HS','powerUsage': 6});
var aView = new MinerView({model:a});
//var Servers = new MinerCollection.Miners();
console.log(MinerCollection);

 $("#miners").append(aView.render().el);
<commit_msg>preliminary information<commit_after>var Backbone = require('backbone');
var $ = require('jquery');
Backbone.$ = $;
/**
Miners
**/
var Miner = require('./src/js/Miner.js');
var MinerCollection = require('./src/js/collections/MinerCollection.js');
var MinerView = require('./src/js/views/MinerView.js');

var a =  new Miner ({'name':'Pluto','group':'Solar','hashRate':'6 G/HS','powerUsage': 6});
var aView = new MinerView({model:a});
//var Servers = new MinerCollection.Miners();
console.log(MinerCollection);

var app = Backbone.Router.extend({

  routes: {
    "index":             "",
    "miner/:miner":      "edit",
    "miner/new":         "new",
    "/miner/:id/status": "status"
  },

  edit: function() {
  },

  new: function() {
  },

  status: function(id) {
  }

});

 $("#miners").append(aView.render().el);
<|endoftext|>


<commit_before>var connectors = require('./connectors');
var strategies = require('./strategies');
var config = require('./config');
var moment = require('moment');
var async = require('async');

var debug = false;
var makeAndCancelOffers = true;

async.forever(function(cb) {
    var usdTotal = 0;
    var rateTotal = 0;
    console.log('-----------------------------------');
    console.log(new Date());
    console.log('-----------------------------------');
    console.log();
    async.forEachOfSeries(config.exchanges, function(exchange, exchangeName, cb) {
	async.forEachOfSeries(exchange.currencies, function(settings, currency, cb) {
	    if (settings.active) {
		var handle;
		if (exchangeName === 'bitfinex') {
		    handle = new connectors.bitfinex(config.exchanges.bitfinex.credentials);
		}
		else if (exchangeName === 'poloniex') {
		    handle = new connectors.poloniex(config.exchanges.poloniex.credentials);
		}
		if (handle) {
		    manage(exchangeName, handle, currency, settings, function(err, data) {
			if (err) {
			    console.log(err);
			}
			else {
			    var usd = data.loanTotal * data.usdPrice;
			    var rate = data.rateTotal / (data.loanTotal !== 0 ? data.loanTotal : 1); // covers divide by zero
			    usdTotal += usd;
			    rateTotal += usd * rate;
			}
			cb();
		    });
		}
		else {
		    cb({message: 'exchange '+exchangeName+' not found'});
		}
	    }
	    else {
		cb();
	    }
	},
	function(err) {
	    cb(err);
	});
    },
    function(err) {
	if (err) {
	    console.log(err);
	}
	console.log();
	console.log('summary');
	console.log('  grand total: $'+toUsd(usdTotal), 'loaned at', (rateTotal / usdTotal).toFixed(2)+'%');
	console.log();
	console.log('done');
	console.log();
	setTimeout(function() {
	    cb();
	}, config.loopDelayInMinutes * 60 * 1000);
    });
}, function(err) {
    console.log(err);
});

function manage(exchangeName, handle, currency, settings, cb) {
    console.log(exchangeName, currency);

    var data = {};
    async.series([function(cb) {
	// 1. get this exchange's usd rate for this currency
	if (currency.toLowerCase() !== 'usd') {
	  handle.lastUSDPrice(currency, function(err, usdPrice) {
	      data.usdPrice = usdPrice;
	      console.log('  usd rate: $'+toUsd(usdPrice));
	      console.log();
	      setTimeout(function() {
		  cb(err);
	      }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
	  });
	}
	else {
	    data.usdPrice = 1;
	    cb();
	}
    },
    function(cb) {
	// 2. get active loans
	handle.activeLoans(currency, function(err, activeLoans) {
	    data.activeLoans = activeLoans;
	    setTimeout(function() {
		cb(err);
	    }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
	});
    },
    function(cb) {
	// 3. show active loans (with USD value)
	console.log('  active loans ('+data.activeLoans.length+')');
	data.loanTotal = 0;
	data.rateTotal = 0;
	async.eachSeries(data.activeLoans, function(loan, cb) {
	    console.log('   ', loan.amount.toFixed(8), loan.currency, '($'+toUsd(loan.amount * data.usdPrice)+') at',
			loan.rate.toFixed(2)+'%', loan.createDate, 'for', loan.duration, 'days',
			'(expires '+moment(loan.createDate).add(loan.duration, 'days').fromNow()+')');
	    data.loanTotal += loan.amount;
	    data.rateTotal += loan.rate * loan.amount;
	    cb();
        },
        function(err) {
	    if (data.loanTotal > 0) {
		console.log();
		console.log('      total:', data.loanTotal.toFixed(8), currency, '($'+toUsd(data.loanTotal * data.usdPrice)+')',
			    'at', (data.rateTotal / data.loanTotal).toFixed(2)+'%');
	    }
	    console.log();
	    cb();
	});
    },
    function(cb) {
	// 4. get order book
	handle.lendbook(currency, function(err, lendbook) {
            data.lendbook = lendbook;
            setTimeout(function() {
                cb(err);
            }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
        });
    },
    function(cb) {
	// 5. find desired rate
	var strategy = strategies.createLoan.topOfTheBook;
	if (settings.rateCreationStrategy.name === 'percentDepth') {
	    strategy = strategies.createLoan.percentDepth;
	}
	strategy(data, settings, exchangeName, function(err, rate) {
	    if (!err) {
		data.targetRate = rate;
		console.log('  target rate:', rate.toFixed(2)+'%');
		console.log();
		cb();
	    }
	    else {
		cb(err);
	    }
	});
    },
    function(cb) {
	// 6. find duration
	var strategy = strategies.loanDuration.rateBased;
	data.duration = strategy(data, settings, exchangeName);
	cb();
    },
    function(cb) {
	// 7. get open (unfilled) loan offers
	handle.openLoanOffers(currency, function(err, loanOffers) {
            data.loanOffers = loanOffers;
            setTimeout(function() {
                cb(err);
            }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
        });
    },
    function(cb) {
	// 8. show open (unfilled) loan offers
	if (data.loanOffers.length > 0) {
	    console.log('  open loan offers ('+data.loanOffers.length+')');
	    for (var x in data.loanOffers) {
		var offer = data.loanOffers[x];
		console.log('   ', offer.amount.toFixed(8), offer.currency, '($'+toUsd(offer.amount * data.usdPrice)+') at',
                            offer.rate.toFixed(2)+'%', offer.createDate, 'for', offer.duration, 'days');
	    }
	    console.log();
	    cb();
	}
	else {
	    cb();
	}
    },
    function(cb) {
	// 9. test all open offers to see if they should be updated or canceled
	var activity = false;
	async.eachSeries(data.loanOffers, function(offer, cb) {
	    var strategy = strategies.updateLoan.outOfRange;
            if (settings.rateUpdateStrategy.name === 'lowerRateWithTime') {
		strategy = strategies.updateLoan.lowerRateWithTime;
            }
            strategy(offer, data, settings, exchangeName, function(err, offer) {
		if (offer.action === 'cancel' || offer.rate < settings.minimumRate) {
		    // cancel this offer
		    if (makeAndCancelOffers) {
			activity = true;
			console.log('   cancelling', offer.amount.toFixed(8), offer.currency, '($'+toUsd(offer.amount * data.usdPrice)+') at',
				    offer.rate.toFixed(2)+'%', offer.createDate, 'for', offer.duration, 'days');
			handle.cancelLoanOffer(offer.id, function(err, res) {
			    if (debug) {
				console.log(res);
			    }
			    setTimeout(function() {
				cb(err);
			    }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
			});
		    }
		    else {
			cb();
		    }
		}
		else if (offer.action === 'update') {
		    // update this offer
		    if (makeAndCancelOffers && (offer.amount * data.usdPrice) >= settings.minimumSizeUSD) {
			activity = true;
			console.log('    updating', offer.amount.toFixed(8), offer.currency, '($'+toUsd(offer.amount * data.usdPrice)+') at',
				    offer.rate.toFixed(2)+'%', offer.createDate, 'for', offer.duration, 'days');
			handle.updateLoanOffer(offer, function(err, res) { // TODO: make this an update not a cancel!
			    if (debug) {
				console.log(res);
			    }
			    setTimeout(function() {
				cb(err);
			    }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
			});
		    }
		    else {
			cb();
		    }
		}
		else {
		    cb();
		}
	    });
	},
	function(err) {
	    if (activity) {
		console.log();
	    }
	    cb(err)
	});
    },
    function(cb) {
	// 10. get available balance for this currency
	handle.availableBalance(currency, function(err, availableBalance) {
            data.availableBalance = availableBalance;
	    console.log('  available balance:', data.availableBalance, currency, '($'+toUsd(data.availableBalance * data.usdPrice)+')');
	    console.log();
            setTimeout(function() {
                cb(err);
            }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
        });
    },
    function(cb) {
	// 11. optionally create offer
	if (data.availableBalance * data.usdPrice > settings.minimumSizeUSD && data.targetRate > settings.minimumRate) {
	    var amount = data.availableBalance;
	    if (amount * data.usdPrice > settings.maximumSizeUSD) {
		amount = Number((settings.maximumSizeUSD / data.usdPrice).toFixed(4));
	    }
	    console.log('  creating offer for', amount, currency, '($'+toUsd(amount * data.usdPrice)+') at',
			data.targetRate.toFixed(2)+'% for', data.duration, 'days');
	    if (makeAndCancelOffers) {
		handle.createLoanOffer(currency, amount, Number(data.targetRate.toFixed(2)), data.duration, function(err, res) {
		    if (debug) {
			console.log(res);
		    }
		    setTimeout(function() {
			cb(err);
		    }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
		});
	    }
	    else {
		cb();
	    }
	}
	else {
	    console.log('  not creating a new offer');
	    if (data.targetRate > settings.minimumRate) {
		console.log('    target rate of', data.targetRate+'% is less than minimum rate of', settings.minimumRate+'%');
	    }
	    else if (data.availableBalance * data.usdPrice > settings.minimumSizeUSD) {
		console.log('    value of', data.availableBalance, currency, '($'+toUsd(data.availableBalance * data.usdPrice)+')',
			    'is less than minimum size of $'+settings.minimumSizeUSD);
	    }
	    cb();
	}
    }],
    function(err) {
	console.log();
	cb(err, data);
    });
}

moment.relativeTimeRounding(function (value) {
    return Number(value.toFixed(2));
});

function toUsd(x) {
    return numberWithCommas(Number(x).toFixed(2));
}

function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
<commit_msg>app.js: trap reason properly<commit_after>var connectors = require('./connectors');
var strategies = require('./strategies');
var config = require('./config');
var moment = require('moment');
var async = require('async');

var debug = false;
var makeAndCancelOffers = true;

async.forever(function(cb) {
    var usdTotal = 0;
    var rateTotal = 0;
    console.log('-----------------------------------');
    console.log(new Date());
    console.log('-----------------------------------');
    console.log();
    async.forEachOfSeries(config.exchanges, function(exchange, exchangeName, cb) {
	async.forEachOfSeries(exchange.currencies, function(settings, currency, cb) {
	    if (settings.active) {
		var handle;
		if (exchangeName === 'bitfinex') {
		    handle = new connectors.bitfinex(config.exchanges.bitfinex.credentials);
		}
		else if (exchangeName === 'poloniex') {
		    handle = new connectors.poloniex(config.exchanges.poloniex.credentials);
		}
		if (handle) {
		    manage(exchangeName, handle, currency, settings, function(err, data) {
			if (err) {
			    console.log(err);
			}
			else {
			    var usd = data.loanTotal * data.usdPrice;
			    var rate = data.rateTotal / (data.loanTotal !== 0 ? data.loanTotal : 1); // covers divide by zero
			    usdTotal += usd;
			    rateTotal += usd * rate;
			}
			cb();
		    });
		}
		else {
		    cb({message: 'exchange '+exchangeName+' not found'});
		}
	    }
	    else {
		cb();
	    }
	},
	function(err) {
	    cb(err);
	});
    },
    function(err) {
	if (err) {
	    console.log(err);
	}
	console.log();
	console.log('summary');
	console.log('  grand total: $'+toUsd(usdTotal), 'loaned at', (rateTotal / usdTotal).toFixed(2)+'%');
	console.log();
	console.log('done');
	console.log();
	setTimeout(function() {
	    cb();
	}, config.loopDelayInMinutes * 60 * 1000);
    });
}, function(err) {
    console.log(err);
});

function manage(exchangeName, handle, currency, settings, cb) {
    console.log(exchangeName, currency);

    var data = {};
    async.series([function(cb) {
	// 1. get this exchange's usd rate for this currency
	if (currency.toLowerCase() !== 'usd') {
	  handle.lastUSDPrice(currency, function(err, usdPrice) {
	      data.usdPrice = usdPrice;
	      console.log('  usd rate: $'+toUsd(usdPrice));
	      console.log();
	      setTimeout(function() {
		  cb(err);
	      }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
	  });
	}
	else {
	    data.usdPrice = 1;
	    cb();
	}
    },
    function(cb) {
	// 2. get active loans
	handle.activeLoans(currency, function(err, activeLoans) {
	    data.activeLoans = activeLoans;
	    setTimeout(function() {
		cb(err);
	    }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
	});
    },
    function(cb) {
	// 3. show active loans (with USD value)
	console.log('  active loans ('+data.activeLoans.length+')');
	data.loanTotal = 0;
	data.rateTotal = 0;
	async.eachSeries(data.activeLoans, function(loan, cb) {
	    console.log('   ', loan.amount.toFixed(8), loan.currency, '($'+toUsd(loan.amount * data.usdPrice)+') at',
			loan.rate.toFixed(2)+'%', loan.createDate, 'for', loan.duration, 'days',
			'(expires '+moment(loan.createDate).add(loan.duration, 'days').fromNow()+')');
	    data.loanTotal += loan.amount;
	    data.rateTotal += loan.rate * loan.amount;
	    cb();
        },
        function(err) {
	    if (data.loanTotal > 0) {
		console.log();
		console.log('      total:', data.loanTotal.toFixed(8), currency, '($'+toUsd(data.loanTotal * data.usdPrice)+')',
			    'at', (data.rateTotal / data.loanTotal).toFixed(2)+'%');
	    }
	    console.log();
	    cb();
	});
    },
    function(cb) {
	// 4. get order book
	handle.lendbook(currency, function(err, lendbook) {
            data.lendbook = lendbook;
            setTimeout(function() {
                cb(err);
            }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
        });
    },
    function(cb) {
	// 5. find desired rate
	var strategy = strategies.createLoan.topOfTheBook;
	if (settings.rateCreationStrategy.name === 'percentDepth') {
	    strategy = strategies.createLoan.percentDepth;
	}
	strategy(data, settings, exchangeName, function(err, rate) {
	    if (!err) {
		data.targetRate = rate;
		console.log('  target rate:', rate.toFixed(2)+'%');
		console.log();
		cb();
	    }
	    else {
		cb(err);
	    }
	});
    },
    function(cb) {
	// 6. find duration
	var strategy = strategies.loanDuration.rateBased;
	data.duration = strategy(data, settings, exchangeName);
	cb();
    },
    function(cb) {
	// 7. get open (unfilled) loan offers
	handle.openLoanOffers(currency, function(err, loanOffers) {
            data.loanOffers = loanOffers;
            setTimeout(function() {
                cb(err);
            }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
        });
    },
    function(cb) {
	// 8. show open (unfilled) loan offers
	if (data.loanOffers.length > 0) {
	    console.log('  open loan offers ('+data.loanOffers.length+')');
	    for (var x in data.loanOffers) {
		var offer = data.loanOffers[x];
		console.log('   ', offer.amount.toFixed(8), offer.currency, '($'+toUsd(offer.amount * data.usdPrice)+') at',
                            offer.rate.toFixed(2)+'%', offer.createDate, 'for', offer.duration, 'days');
	    }
	    console.log();
	    cb();
	}
	else {
	    cb();
	}
    },
    function(cb) {
	// 9. test all open offers to see if they should be updated or canceled
	var activity = false;
	async.eachSeries(data.loanOffers, function(offer, cb) {
	    var strategy = strategies.updateLoan.outOfRange;
            if (settings.rateUpdateStrategy.name === 'lowerRateWithTime') {
		strategy = strategies.updateLoan.lowerRateWithTime;
            }
            strategy(offer, data, settings, exchangeName, function(err, offer) {
		if (offer.action === 'cancel' || offer.rate < settings.minimumRate) {
		    // cancel this offer
		    if (makeAndCancelOffers) {
			activity = true;
			console.log('   cancelling', offer.amount.toFixed(8), offer.currency, '($'+toUsd(offer.amount * data.usdPrice)+') at',
				    offer.rate.toFixed(2)+'%', offer.createDate, 'for', offer.duration, 'days');
			handle.cancelLoanOffer(offer.id, function(err, res) {
			    if (debug) {
				console.log(res);
			    }
			    setTimeout(function() {
				cb(err);
			    }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
			});
		    }
		    else {
			cb();
		    }
		}
		else if (offer.action === 'update') {
		    // update this offer
		    if (makeAndCancelOffers && (offer.amount * data.usdPrice) >= settings.minimumSizeUSD) {
			activity = true;
			console.log('    updating', offer.amount.toFixed(8), offer.currency, '($'+toUsd(offer.amount * data.usdPrice)+') at',
				    offer.rate.toFixed(2)+'%', offer.createDate, 'for', offer.duration, 'days');
			handle.updateLoanOffer(offer, function(err, res) { // TODO: make this an update not a cancel!
			    if (debug) {
				console.log(res);
			    }
			    setTimeout(function() {
				cb(err);
			    }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
			});
		    }
		    else {
			cb();
		    }
		}
		else {
		    cb();
		}
	    });
	},
	function(err) {
	    if (activity) {
		console.log();
	    }
	    cb(err)
	});
    },
    function(cb) {
	// 10. get available balance for this currency
	handle.availableBalance(currency, function(err, availableBalance) {
            data.availableBalance = availableBalance;
	    console.log('  available balance:', data.availableBalance, currency, '($'+toUsd(data.availableBalance * data.usdPrice)+')');
	    console.log();
            setTimeout(function() {
                cb(err);
            }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
        });
    },
    function(cb) {
	// 11. optionally create offer
	if (data.availableBalance * data.usdPrice >= settings.minimumSizeUSD && data.targetRate >= settings.minimumRate) {
	    var amount = data.availableBalance;
	    if (amount * data.usdPrice > settings.maximumSizeUSD) {
		amount = Number((settings.maximumSizeUSD / data.usdPrice).toFixed(4));
	    }
	    console.log('  creating offer for', amount, currency, '($'+toUsd(amount * data.usdPrice)+') at',
			data.targetRate.toFixed(2)+'% for', data.duration, 'days');
	    if (makeAndCancelOffers) {
		handle.createLoanOffer(currency, amount, Number(data.targetRate.toFixed(2)), data.duration, function(err, res) {
		    if (debug) {
			console.log(res);
		    }
		    setTimeout(function() {
			cb(err);
		    }, config.exchanges[exchangeName].msDelayBetweenAPICalls);
		});
	    }
	    else {
		cb();
	    }
	}
	else {
	    console.log('  not creating a new offer');
	    if (data.targetRate < settings.minimumRate) {
		console.log('    target rate of', data.targetRate+'% is less than minimum rate of', settings.minimumRate+'%');
	    }
	    else if (data.availableBalance * data.usdPrice < settings.minimumSizeUSD) {
		console.log('    value of', data.availableBalance, currency, '($'+toUsd(data.availableBalance * data.usdPrice)+')',
			    'is less than minimum size of $'+settings.minimumSizeUSD);
	    }
	    cb();
	}
    }],
    function(err) {
	console.log();
	cb(err, data);
    });
}

moment.relativeTimeRounding(function (value) {
    return Number(value.toFixed(2));
});

function toUsd(x) {
    return numberWithCommas(Number(x).toFixed(2));
}

function numberWithCommas(x) {
    return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
}
<|endoftext|>