<commit_before>
var fs = require('fs'),
    http = require('http'),
    exec = require('child_process').exec,
	_ = require('underscore'),
    Geo = require('./geo');

function dpc(t,fn) { if(typeof(t) == 'function') setTimeout(t,0); else setTimeout(fn,t); }

function Scanner(options) {

	var self = this;
    self.options = options;

    var config = eval('('+fs.readFileSync("scanner.cfg",'utf8')+')');
    var upload = fs.existsSync('upload.cfg') ? eval('('+fs.readFileSync("upload.cfg",'utf8')+')') : null;

    self.addr_pending = { }     // list of addresses waiting scan
    self.addr_digested = { }    // list of scanned addresses
    self.addr_working = { }     // list of working addresses

    self.geo = new Geo({ timeout : config.http_socket_timeout });

  	// -----------------------------------------
   	// local http server interface
    if(config.http_port)
    {
        var express = require('express');
        var app = express();
        app.configure(function(){
            app.use(express.bodyParser());
        });
        app.get('/', function(req, res) {
            var str = self.render();
            res.write(str);
            res.end();
        });

        http.createServer(app).listen(config.http_port, function() {
            console.log("HTTP server listening on port: ",config.http_port);
        });
    }

    var logo = fs.readFileSync("resources/"+config.currency.toLowerCase()+".png","base64");
    if(logo)
        logo = "data:image/png;base64,"+logo;

    self.render = function() {
        var str = ""
            +""
            +"";
        if(logo)
            str += "

";
        str += "PEER TO PEER "+(config.currency.toUpperCase())+" MINING NETWORK - PUBLIC NODE LIST
GENERATED ON: "+(new
Date())+"
"
        if(self.poolstats)
            str += "Pool speed: "+(self.poolstats.pool_hash_rate/1000000).toFixed(2)+" "+config.speed_abbrev+"";
        str += "Currently observing "+(self.nodes_total || "N/A")+" nodes.
"+_.size(self.addr_working)+" nodes are public with following IPs:
";
        str += "
";
        str += "

IPs

Fee

Uptime

Location
";
        str += "

";

        var list = _.sortBy(_.toArray(self.addr_working), function(o) { return o.stats ? -o.stats.uptime : 0; })

        var row = 0;
        _.each(list, function(info) {
            var ip = info.ip;

            var uptime = info.stats ? (info.stats.uptime / 60 / 60 / 24).toFixed(1) : "N/A";
            var fee = (info.fee || 0).toFixed(2);

            str += "

"+ip+":8336

"+fee+"%

"+uptime+" days
";
            str += "
";
            if(info.geo) {
                str += ""+info.geo.country+" "+"";
            }
            str += "
";
            str += "
";
            str += "
";
        })
        str += "

";
        str += ""
        return str;
    }

    // setup flushing of rendered HTML page to a file (useful for uploading to other sites)
    if(config.flush_to_file_every_N_msec && config.flush_filename) {
        function flush_rendering() {
            var str = self.render();
            fs.writeFile(config.flush_filename, str, { encoding : 'utf8'});
            dpc(config.flush_to_file_every_N_msec, flush_rendering);
        }

        dpc(5000, flush_rendering);
    }

    // defer init
    dpc(function(){
        self.restore_working();
        self.update();
    })

    var p2pool_init = true;

    // main function that reloads 'addr' file from p2pool
    self.update = function() {
        var filename = config.addr_file;
        if(!fs.existsSync(filename)) {
            console.error("Unable to fetch p2pool address list from:",config.addr_file);
            filename = config.init_file;    // if we can't read p2pool's addr file, we just cycle on the local default init...
        }

        fs.readFile(filename, { encoding : 'utf8' }, function(err, data) {
            if(err) {
                console.error(err);
            }
            else {
                try {
                    var addr_list = JSON.parse(data);
                    self.inject(addr_list);

                    // main init
                    if(p2pool_init) {
                        p2pool_init = false;

                        // if we can read p2pool addr file, also add our pre-collected IPs
                        // if(filename != config.init_file) {
                            var init_addr = JSON.parse(fs.readFileSync(config.init_file, 'utf8'));
                            self.inject(init_addr);
                        //}

                        for(var i = 0; i < (config.probe_N_IPs_simultaneously || 1); i++)
                            self.digest();
                        dpc(60*1000, function() { self.store_working(); })
                    }
                }
                catch(ex) {
                    console.error("Unable to parse p2pool address list");
                    console.error(ex);
                }
            }

            dpc(1000 * 60, self.update);
        })
    }

    // store public pools in a file that reloads at startup
    self.store_working = function() {
        var data = JSON.stringify(self.addr_working);
        fs.writeFile(config.store_file, data, { encoding : 'utf8' }, function(err) {
            dpc(60*1000, self.store_working);
        })
    }

    // reload public list at startup
    self.restore_working = function() {
        try {
            self.addr_working = JSON.parse(fs.readFileSync(config.store_file, 'utf8'));
        } catch(ex) { /*console.log(ex);*/ }
    }

    // inject new IPs from p2pool addr file
    self.inject = function(addr_list) {
        _.each(addr_list, function(info) {
            var ip = info[0][0];
            var port = info[0][1];

            if(!self.addr_digested[ip] && !self.addr_pending[ip]) {
                self.addr_pending[ip] = { ip : ip, port : port }
            }

            self.nodes_total = _.size(self.addr_digested) + _.size(self.addr_pending);
        });
    }

    // as we scan pools, we fetch global info from them to update the page
    self.update_global_stats = function(poolstats) {
        self.poolstats = poolstats;
    }

    // execute scan of a single IP
    self.digest = function() {

        if(!_.size(self.addr_pending))
            return self.list_complete();

        var info = _.find(self.addr_pending, function() { return true; });
        delete self.addr_pending[info.ip];
        self.addr_digested[info.ip] = info;
        // console.log("P2POOL DIGESTING:",info.ip);

        digest_ip(info, function(err, fee){
            if(!err) {
                info.fee = fee;
                self.addr_working[info.ip] = info;
                // console.log("FOUND WORKING POOL: ", info.ip);

                digest_local_stats(info, function(err, stats) {
                    if(!err)
                        info.stats = stats;
                    digest_global_stats(info, function(err, stats) {
                        if(!err)
                            self.update_global_stats(stats);

                        if(!info.geo)
                            self.geo.get(info.ip, function(err, geo) {
                                if(!err)
                                    info.geo = geo;

                                continue_digest();
                            });
                        else
                            continue_digest();
                    });
                });
            }
            else {
                delete self.addr_working[info.ip];
                continue_digest();
            }

            function continue_digest() {
                self.working_size = _.size(self.addr_working);
                dpc(self.digest);
            }
        });
    }

    // schedule restar of the scan once all IPs are done
    self.list_complete = function() {
        self.addr_pending = self.addr_digested;
        self.addr_digested = { }
        dpc(config.rescan_list_delay, self.digest);
    }

    // functions to fetch data from target node IP

    function digest_ip(info, callback) {

        var options = {
          host: info.ip,
          port: 8336,
          path: '/fee',
          method: 'GET'
        };

        self.request(options, callback);
    }

    function digest_local_stats(info, callback) {

        var options = {
          host: info.ip,
          port: 8336,
          path: '/local_stats',
          method: 'GET'
        };

        self.request(options, callback);
    }

    function digest_global_stats(info, callback) {

        var options = {
          host: info.ip,
          port: 8336,
          path: '/global_stats',
          method: 'GET'
        };

        self.request(options, callback);
    }

    // make http request to the target node ip
    self.request = function(options, callback, is_plain)
    {
        http_handler = http;
        var req = http_handler.request(options, function(res) {
            res.setEncoding('utf8');
            var result = '';
            res.on('data', function (data) {
                result += data;
            });

            res.on('end', function () {
                if(options.plain)
                    callback(null, result);
                else {
                    try {
                        var o = JSON.parse(result);
                        callback(null, o);
                    } catch(ex) {
                        console.error(ex);
                        callback(ex);
                    }
                }
            });
        });

        req.on('socket', function (socket) {
            socket.setTimeout(config.http_socket_timeout);
            socket.on('timeout', function() {
                req.abort();
            });
        });

        req.on('error', function(e) {
            callback(e);
        });

        req.end();
    }

    if(upload && process.platform != 'win32') {

        function do_upload() {

            if(upload.ftp) {
                var ftp = upload.ftp;
                if(!ftp.address || !ftp.username || !ftp.password)
                    return console.error("upload.cfg ftp configuration must contain target address, username and password");
                var cmd = "curl -T "+config.flush_filename+" "+ftp.address+" --user "+ftp.address+":"+ftp.password;
                exec(cmd, function(error){ if(error) console.error(error); });
            }

            if(upload.scp) {
                var scp = upload.scp;
                if(!scp.address)
                    return console.error("upload.cfg scp configuration must contain target address");
                var cmd = "scp -q ./"+config.flush_filename+" "+scp.address;
                exec(cmd, function(error){ if(error) console.error(error); });
            }

            dpc(config.upload_interval, do_upload);
        }

        dpc(5000, do_upload);
    }
    else
        console.log("upload.cfg not found, rendering available only on the local interface");
}

GLOBAL.scanner = new Scanner();

//
<commit_msg>added known cach pools dns<commit_after>
var fs = require('fs'),
    http = require('http'),
    exec = require('child_process').exec,
	_ = require('underscore'),
    Geo = require('./geo');

function dpc(t,fn) { if(typeof(t) == 'function') setTimeout(t,0); else setTimeout(fn,t); }

function Scanner(options) {

	var self = this;
    self.options = options;

    var config = eval('('+fs.readFileSync("scanner.cfg",'utf8')+')');
    var upload = fs.existsSync('upload.cfg') ? eval('('+fs.readFileSync("upload.cfg",'utf8')+')') : null;

    self.addr_pending = { }     // list of addresses waiting scan
    self.addr_digested = { }    // list of scanned addresses
    self.addr_working = { }     // list of working addresses

    self.geo = new Geo({ timeout : config.http_socket_timeout });

  	// -----------------------------------------
   	// local http server interface
    if(config.http_port)
    {
        var express = require('express');
        var app = express();
        app.configure(function(){
            app.use(express.bodyParser());
        });
        app.get('/', function(req, res) {
            var str = self.render();
            res.write(str);
            res.end();
        });

        http.createServer(app).listen(config.http_port, function() {
            console.log("HTTP server listening on port: ",config.http_port);
        });
    }

    var logo = fs.readFileSync("resources/"+config.currency.toLowerCase()+".png","base64");
    if(logo)
        logo = "data:image/png;base64,"+logo;

    self.render = function() {
        var str = ""
            +""
            +"";
        if(logo)
            str += "

";
        str += "PEER TO PEER "+(config.currency.toUpperCase())+" MINING NETWORK - PUBLIC NODE LIST
GENERATED ON: "+(new
Date())+"
"
        if(self.poolstats)
            str += "Pool speed: "+(self.poolstats.pool_hash_rate/1000000).toFixed(2)+" "+config.speed_abbrev+"";
        str += "Currently observing "+(self.nodes_total || "N/A")+" nodes.
"+_.size(self.addr_working)+" nodes are public with following IPs:
";
        str += "
";
        str += "

IPs

Fee

Uptime

Location
";
        str += "

";

        var list = _.sortBy(_.toArray(self.addr_working), function(o) { return o.stats ? -o.stats.uptime : 0; })

        var row = 0;
        _.each(list, function(info) {
            var ip = info.ip;

            if (ip == '178.63.15.130') {
                ip = 'q30.qhor.net';
            }
            if (ip == '176.9.64.195') {
                ip = 'p2cache.syware.de';
            }

            var uptime = info.stats ? (info.stats.uptime / 60 / 60 / 24).toFixed(1) : "N/A";
            var fee = (info.fee || 0).toFixed(2);

            str += "

"+ip+":8336

"+fee+"%

"+uptime+" days
";
            str += "
";
            if(info.geo) {
                str += ""+info.geo.country+" "+"";
            }
            str += "
";
            str += "
";
            str += "
";
        })
        str += "

";
        str += ""
        return str;
    }

    // setup flushing of rendered HTML page to a file (useful for uploading to other sites)
    if(config.flush_to_file_every_N_msec && config.flush_filename) {
        function flush_rendering() {
            var str = self.render();
            fs.writeFile(config.flush_filename, str, { encoding : 'utf8'});
            dpc(config.flush_to_file_every_N_msec, flush_rendering);
        }

        dpc(5000, flush_rendering);
    }

    // defer init
    dpc(function(){
        self.restore_working();
        self.update();
    })

    var p2pool_init = true;

    // main function that reloads 'addr' file from p2pool
    self.update = function() {
        var filename = config.addr_file;
        if(!fs.existsSync(filename)) {
            console.error("Unable to fetch p2pool address list from:",config.addr_file);
            filename = config.init_file;    // if we can't read p2pool's addr file, we just cycle on the local default init...
        }

        fs.readFile(filename, { encoding : 'utf8' }, function(err, data) {
            if(err) {
                console.error(err);
            }
            else {
                try {
                    var addr_list = JSON.parse(data);
                    self.inject(addr_list);

                    // main init
                    if(p2pool_init) {
                        p2pool_init = false;

                        // if we can read p2pool addr file, also add our pre-collected IPs
                        // if(filename != config.init_file) {
                            var init_addr = JSON.parse(fs.readFileSync(config.init_file, 'utf8'));
                            self.inject(init_addr);
                        //}

                        for(var i = 0; i < (config.probe_N_IPs_simultaneously || 1); i++)
                            self.digest();
                        dpc(60*1000, function() { self.store_working(); })
                    }
                }
                catch(ex) {
                    console.error("Unable to parse p2pool address list");
                    console.error(ex);
                }
            }

            dpc(1000 * 60, self.update);
        })
    }

    // store public pools in a file that reloads at startup
    self.store_working = function() {
        var data = JSON.stringify(self.addr_working);
        fs.writeFile(config.store_file, data, { encoding : 'utf8' }, function(err) {
            dpc(60*1000, self.store_working);
        })
    }

    // reload public list at startup
    self.restore_working = function() {
        try {
            self.addr_working = JSON.parse(fs.readFileSync(config.store_file, 'utf8'));
        } catch(ex) { /*console.log(ex);*/ }
    }

    // inject new IPs from p2pool addr file
    self.inject = function(addr_list) {
        _.each(addr_list, function(info) {
            var ip = info[0][0];
            var port = info[0][1];

            if(!self.addr_digested[ip] && !self.addr_pending[ip]) {
                self.addr_pending[ip] = { ip : ip, port : port }
            }

            self.nodes_total = _.size(self.addr_digested) + _.size(self.addr_pending);
        });
    }

    // as we scan pools, we fetch global info from them to update the page
    self.update_global_stats = function(poolstats) {
        self.poolstats = poolstats;
    }

    // execute scan of a single IP
    self.digest = function() {

        if(!_.size(self.addr_pending))
            return self.list_complete();

        var info = _.find(self.addr_pending, function() { return true; });
        delete self.addr_pending[info.ip];
        self.addr_digested[info.ip] = info;
        // console.log("P2POOL DIGESTING:",info.ip);

        digest_ip(info, function(err, fee){
            if(!err) {
                info.fee = fee;
                self.addr_working[info.ip] = info;
                // console.log("FOUND WORKING POOL: ", info.ip);

                digest_local_stats(info, function(err, stats) {
                    if(!err)
                        info.stats = stats;
                    digest_global_stats(info, function(err, stats) {
                        if(!err)
                            self.update_global_stats(stats);

                        if(!info.geo)
                            self.geo.get(info.ip, function(err, geo) {
                                if(!err)
                                    info.geo = geo;

                                continue_digest();
                            });
                        else
                            continue_digest();
                    });
                });
            }
            else {
                delete self.addr_working[info.ip];
                continue_digest();
            }

            function continue_digest() {
                self.working_size = _.size(self.addr_working);
                dpc(self.digest);
            }
        });
    }

    // schedule restar of the scan once all IPs are done
    self.list_complete = function() {
        self.addr_pending = self.addr_digested;
        self.addr_digested = { }
        dpc(config.rescan_list_delay, self.digest);
    }

    // functions to fetch data from target node IP

    function digest_ip(info, callback) {

        var options = {
          host: info.ip,
          port: 8336,
          path: '/fee',
          method: 'GET'
        };

        self.request(options, callback);
    }

    function digest_local_stats(info, callback) {

        var options = {
          host: info.ip,
          port: 8336,
          path: '/local_stats',
          method: 'GET'
        };

        self.request(options, callback);
    }

    function digest_global_stats(info, callback) {

        var options = {
          host: info.ip,
          port: 8336,
          path: '/global_stats',
          method: 'GET'
        };

        self.request(options, callback);
    }

    // make http request to the target node ip
    self.request = function(options, callback, is_plain)
    {
        http_handler = http;
        var req = http_handler.request(options, function(res) {
            res.setEncoding('utf8');
            var result = '';
            res.on('data', function (data) {
                result += data;
            });

            res.on('end', function () {
                if(options.plain)
                    callback(null, result);
                else {
                    try {
                        var o = JSON.parse(result);
                        callback(null, o);
                    } catch(ex) {
                        console.error(ex);
                        callback(ex);
                    }
                }
            });
        });

        req.on('socket', function (socket) {
            socket.setTimeout(config.http_socket_timeout);
            socket.on('timeout', function() {
                req.abort();
            });
        });

        req.on('error', function(e) {
            callback(e);
        });

        req.end();
    }

    if(upload && process.platform != 'win32') {

        function do_upload() {

            if(upload.ftp) {
                var ftp = upload.ftp;
                if(!ftp.address || !ftp.username || !ftp.password)
                    return console.error("upload.cfg ftp configuration must contain target address, username and password");
                var cmd = "curl -T "+config.flush_filename+" "+ftp.address+" --user "+ftp.address+":"+ftp.password;
                exec(cmd, function(error){ if(error) console.error(error); });
            }

            if(upload.scp) {
                var scp = upload.scp;
                if(!scp.address)
                    return console.error("upload.cfg scp configuration must contain target address");
                var cmd = "scp -q ./"+config.flush_filename+" "+scp.address;
                exec(cmd, function(error){ if(error) console.error(error); });
            }

            dpc(config.upload_interval, do_upload);
        }

        dpc(5000, do_upload);
    }
    else
        console.log("upload.cfg not found, rendering available only on the local interface");
}

GLOBAL.scanner = new Scanner();

//
<|endoftext|>


<commit_before>var xml     = require('xml');
var generatorName = 'Feed for Node.js';

/*
If I do end up committing changes back should look at fixing the validation warnings:
line 2, column 0: Missing atom:link with rel="self" [help]
line 60, column 4: Missing textual content (8 occurrences) [help]
    </entry>
[http://validator.w3.org/feed/check.cgi]
*/

// ============================================================================
// Feed Main Module
// ============================================================================
function Feed(options) {
    this.title          = options.title;
    this.description    = options.description;
    this.link           = options.link;
    this.image          = options.image;
    this.copyright      = options.copyright;

    this.author         = options.author;

    this.items          = [];
    this.categories     = [];

    this.item = function (options) {
        options = options || {};
        var item = {
            title:          options.title,
            link:           options.link,
            description:    options.description,
            date:           options.date,
            image:          options.image,
            author:         options.author
        };

        this.items.push(item);
        return this;
    }

    this.category = function (category) {
        this.categories.push(category);
        return this;
    }

    this.render = function (format) {
        switch(format) {
            case 'rss-2.0':
                return rss_2_0(this);
            break;

            case 'atom-1.0':
                return atom_1_0(this);
            break;

            default:
                return rss_2_0(this);
        }
    };
};

// ============================================================================
// Atom 1.0 [application/atom+xml]
//
// - Reference: http://www.atomenabled.org/developers/syndication/
// ============================================================================

function atom_1_0(options) {
    var items       = [],
        container   = [],
        feed        = [],

        entries     = options.items,
        categories  = options.categories,
        author      = options.author,
        d           = new Date();

    var doctype = '<?xml version="1.0" encoding="utf-8"?>\n';

    container.push({ feed: feed });
    feed.push({ _attr: { xmlns: 'http://www.w3.org/2005/Atom' }});

    /**************************************************************************
     * "feed" node: REQUIRED elements
     *************************************************************************/
    feed.push({ title:      options.title });
    feed.push({ id:         options.link });
    feed.push({ updated:    RFC3339(d) });      // Auto-magic :)

    /**************************************************************************
     * "feed" node: recommended elements
     *************************************************************************/
    if(author)
    {
        var authorDetails = [];

        if(author.name)
            authorDetails.push({ name:     author.name });

        if(author.email)
            authorDetails.push({ email:     author.email });

        if(author.link)
            authorDetails.push({ uri:     author.link });

        feed.push({ author: authorDetails });
    }

    // link (relative link to feed) - will be added in a future version

    /**************************************************************************
     * "feed" node: optional elements
     *************************************************************************/
    if(options.description)
        feed.push({ subtitle:   options.description });

    if(options.image)
        feed.push({ logo:       options.image });

    if(options.copyright)
        feed.push({ rights:     options.copyright });

    feed.push({ generator:      generatorName });

    // Looping through categories (if any set!)
    for(var i=0; i<categories.length; i++)
        feed.push({ category: [{ _attr: { term: categories[i] } }] });

    // contributor

    // icon

    /**************************************************************************
     * "entry" nodes
     *************************************************************************/
    for(var i=0; i<entries.length; i++) {
        //
        // entry: required elements
        //
        var entry = [
            { title:        { _attr: { type: 'html' }, _cdata: entries[i].title }},
            { id:           entries[i].link },
            { link:         [{ _attr: { href: entries[i].link } }]},
            { updated:      RFC3339(entries[i].date) }
        ];

        //
        // entry: recommended elements
        //
        if(entries[i].description)
            entry.push({ summary: { _attr: { type: 'html' }, _cdata: entries[i].description }});

        // entry author(s)
        if(entries[i].author) {
            for(var y=0; y<items[i].author.length; y++) {
                var entryAuthor = [];

                if(entries[i].author[y].name)
                    entryAuthor.push({ name: entries[i].author[y].name });

                if(entries[i].author[y].email)
                    entryAuthor.push({ email: entries[i].author[y].email });

                if(entries[i].author[y].link)
                    entryAuthor.push({ uri: entries[i].author[y].link });

                entry.push({ author: entryAuthor });
            }
        }

        // content

        // link - relative link to article

        //
        // entry: optional elements
        //

        // category

        // contributor

        // published

        // source

        // rights

        feed.push({ entry: entry });
    }

    return doctype + xml(container, true);
}

// ============================================================================
// Real Simple Syndication 2.0 (RSS 2.0)
//
// - Reference: http://feed2.w3.org/docs/rss2.html
// ============================================================================
function rss_2_0(options) {
    var items       = [],
        channel     = [],
        container   = [];

    var items = options.items;
    var categories = options.categories;
    var author = options.author;
    var d = new Date();

    var doctype = '<?xml version="1.0" encoding="utf-8"?>\n';

    container.push({ rss: [] });
    container[0].rss.push({ _attr: { version: '2.0' } });
    container[0].rss.push({ channel: channel });

    // Required RSS 2.0 channel elements
    channel.push({ title:           options.title });
    channel.push({ description:     options.description });
    channel.push({ link:            options.link });

    if(author.email && author.name)
        channel.push({ author: author.email + ' (' + author.name + ')' });

    else if(author.email && !author.name)
        channel.push({ author: author.email });

    else if(!author.email && author.name)
         channel.push({ author: author.name });

    channel.push({ lastBuildDate:   d.toUTCString() })

    if(options.image)
        channel.push({ image:   options.image });

    if(options.copyright)
        channel.push({ copyright:   options.copyright });

    channel.push({ generator:   generatorName });

    // Categories
    for(var i=0; i<categories.length; i++)
        channel.push({ category: categories[i] });

    // Items
    for(var i=0; i<items.length; i++) {
        var item = [
            { title:        { _cdata: items[i].title }},
            { link:         items[i].link },
            { pubDate:      items[i].date.toUTCString() },
            { description:  { _cdata: items[i].description }}
        ];

        if(items[i].author) {
            for(var y=0; y<items[i].author.length; y++) {
                var itemAuthor = [];

                if(items[i].author[y].name)
                    itemAuthor.push({ name: items[i].author[y].name });

                if(items[i].author[y].email)
                    itemAuthor.push({ email: items[i].author[y].email });

                if(items[i].author[y].link)
                    itemAuthor.push({ link: items[i].author[y].link });

                item.push({ author: itemAuthor });
            }
        }

        if(items[i].image)
            item.push({ enclosure: [{ _attr: { url: items[i].image } }] });

        channel.push({ item: item });
    }

    return doctype + xml(container, true);
}

function RFC3339(d) {
    function pad(n) { return n < 10 ? '0' + n : n }

    return d.getUTCFullYear()+'-'
        + pad(d.getUTCMonth()+1)+'-'
        + pad(d.getUTCDate())+'T'
        + pad(d.getUTCHours())+':'
        + pad(d.getUTCMinutes())+':'
        + pad(d.getUTCSeconds())+'Z'
}

module.exports = Feed;
<commit_msg>remove comment todo about feed validation warnings<commit_after>var xml     = require('xml');
var generatorName = 'Feed for Node.js';

// ============================================================================
// Feed Main Module
// ============================================================================
function Feed(options) {
    this.title          = options.title;
    this.description    = options.description;
    this.link           = options.link;
    this.image          = options.image;
    this.copyright      = options.copyright;

    this.author         = options.author;

    this.items          = [];
    this.categories     = [];

    this.item = function (options) {
        options = options || {};
        var item = {
            title:          options.title,
            link:           options.link,
            description:    options.description,
            date:           options.date,
            image:          options.image,
            author:         options.author
        };

        this.items.push(item);
        return this;
    }

    this.category = function (category) {
        this.categories.push(category);
        return this;
    }

    this.render = function (format) {
        switch(format) {
            case 'rss-2.0':
                return rss_2_0(this);
            break;

            case 'atom-1.0':
                return atom_1_0(this);
            break;

            default:
                return rss_2_0(this);
        }
    };
};

// ============================================================================
// Atom 1.0 [application/atom+xml]
//
// - Reference: http://www.atomenabled.org/developers/syndication/
// ============================================================================

function atom_1_0(options) {
    var items       = [],
        container   = [],
        feed        = [],

        entries     = options.items,
        categories  = options.categories,
        author      = options.author,
        d           = new Date();

    var doctype = '<?xml version="1.0" encoding="utf-8"?>\n';

    container.push({ feed: feed });
    feed.push({ _attr: { xmlns: 'http://www.w3.org/2005/Atom' }});

    /**************************************************************************
     * "feed" node: REQUIRED elements
     *************************************************************************/
    feed.push({ title:      options.title });
    feed.push({ id:         options.link });
    feed.push({ updated:    RFC3339(d) });      // Auto-magic :)

    /**************************************************************************
     * "feed" node: recommended elements
     *************************************************************************/
    if(author)
    {
        var authorDetails = [];

        if(author.name)
            authorDetails.push({ name:     author.name });

        if(author.email)
            authorDetails.push({ email:     author.email });

        if(author.link)
            authorDetails.push({ uri:     author.link });

        feed.push({ author: authorDetails });
    }

    // link (relative link to feed) - will be added in a future version

    /**************************************************************************
     * "feed" node: optional elements
     *************************************************************************/
    if(options.description)
        feed.push({ subtitle:   options.description });

    if(options.image)
        feed.push({ logo:       options.image });

    if(options.copyright)
        feed.push({ rights:     options.copyright });

    feed.push({ generator:      generatorName });

    // Looping through categories (if any set!)
    for(var i=0; i<categories.length; i++)
        feed.push({ category: [{ _attr: { term: categories[i] } }] });

    // contributor

    // icon

    /**************************************************************************
     * "entry" nodes
     *************************************************************************/
    for(var i=0; i<entries.length; i++) {
        //
        // entry: required elements
        //
        var entry = [
            { title:        { _attr: { type: 'html' }, _cdata: entries[i].title }},
            { id:           entries[i].link },
            { link:         [{ _attr: { href: entries[i].link } }]},
            { updated:      RFC3339(entries[i].date) }
        ];

        //
        // entry: recommended elements
        //
        if(entries[i].description)
            entry.push({ summary: { _attr: { type: 'html' }, _cdata: entries[i].description }});

        // entry author(s)
        if(entries[i].author) {
            for(var y=0; y<items[i].author.length; y++) {
                var entryAuthor = [];

                if(entries[i].author[y].name)
                    entryAuthor.push({ name: entries[i].author[y].name });

                if(entries[i].author[y].email)
                    entryAuthor.push({ email: entries[i].author[y].email });

                if(entries[i].author[y].link)
                    entryAuthor.push({ uri: entries[i].author[y].link });

                entry.push({ author: entryAuthor });
            }
        }

        // content

        // link - relative link to article

        //
        // entry: optional elements
        //

        // category

        // contributor

        // published

        // source

        // rights

        feed.push({ entry: entry });
    }

    return doctype + xml(container, true);
}

// ============================================================================
// Real Simple Syndication 2.0 (RSS 2.0)
//
// - Reference: http://feed2.w3.org/docs/rss2.html
// ============================================================================
function rss_2_0(options) {
    var items       = [],
        channel     = [],
        container   = [];

    var items = options.items;
    var categories = options.categories;
    var author = options.author;
    var d = new Date();

    var doctype = '<?xml version="1.0" encoding="utf-8"?>\n';

    container.push({ rss: [] });
    container[0].rss.push({ _attr: { version: '2.0' } });
    container[0].rss.push({ channel: channel });

    // Required RSS 2.0 channel elements
    channel.push({ title:           options.title });
    channel.push({ description:     options.description });
    channel.push({ link:            options.link });

    if(author.email && author.name)
        channel.push({ author: author.email + ' (' + author.name + ')' });

    else if(author.email && !author.name)
        channel.push({ author: author.email });

    else if(!author.email && author.name)
         channel.push({ author: author.name });

    channel.push({ lastBuildDate:   d.toUTCString() })

    if(options.image)
        channel.push({ image:   options.image });

    if(options.copyright)
        channel.push({ copyright:   options.copyright });

    channel.push({ generator:   generatorName });

    // Categories
    for(var i=0; i<categories.length; i++)
        channel.push({ category: categories[i] });

    // Items
    for(var i=0; i<items.length; i++) {
        var item = [
            { title:        { _cdata: items[i].title }},
            { link:         items[i].link },
            { pubDate:      items[i].date.toUTCString() },
            { description:  { _cdata: items[i].description }}
        ];

        if(items[i].author) {
            for(var y=0; y<items[i].author.length; y++) {
                var itemAuthor = [];

                if(items[i].author[y].name)
                    itemAuthor.push({ name: items[i].author[y].name });

                if(items[i].author[y].email)
                    itemAuthor.push({ email: items[i].author[y].email });

                if(items[i].author[y].link)
                    itemAuthor.push({ link: items[i].author[y].link });

                item.push({ author: itemAuthor });
            }
        }

        if(items[i].image)
            item.push({ enclosure: [{ _attr: { url: items[i].image } }] });

        channel.push({ item: item });
    }

    return doctype + xml(container, true);
}

function RFC3339(d) {
    function pad(n) { return n < 10 ? '0' + n : n }

    return d.getUTCFullYear()+'-'
        + pad(d.getUTCMonth()+1)+'-'
        + pad(d.getUTCDate())+'T'
        + pad(d.getUTCHours())+':'
        + pad(d.getUTCMinutes())+':'
        + pad(d.getUTCSeconds())+'Z'
}

module.exports = Feed;
<|endoftext|>


<commit_before>'use strict';

/*
 * A set of functions that manipulate and read files and filepaths
 */

module.exports = {
  read: read,
  find_closest_match: find_closest_match,
  is_markdown: is_markdown,
  is_dot: is_dot,
  has_extension: has_extension
};

var grunt = require('grunt');

function read (filename, folder) {
  console.log("Reading " + filename + " from " + folder);
  if (folder) filename = find_closest_match(folder, filename);
  return grunt.file.read(filename);
}

function find_closest_match (folder, filename) {
  if (!grunt.file.isDir(folder)) grunt.warn.log("The folder " + folder + " does not exist.");

  var pattern = build_pattern(folder, filename);
  var file = grunt.file.expand(pattern);

  // Warn again if the resulting file doesn't exist
  if (!file.length) grunt.warn.log("The file " + pattern + " cannot be found.");

  return file[0];
};

function build_pattern (folder, filename) {
  var separator = '';
  if (folder) {
    separator = folder.length ? '/' : '';
  }
  var extension = has_extension(filename) ? '' : '.*';
  return folder + separator + filename + extension;
}

function is_markdown (file) {
  return /\.md$|\.md\..*$/.test(file);
};

function is_dot (file) {
  return /\.dot.html$/.test(file.toString());
};

function has_extension (file) {
  return file.toString().match(/\.[0-9a-z]+$/i);
};<commit_msg>Correct use of grunt warn. More comprehensive test for dot extension<commit_after>'use strict';

/*
 * A set of functions that manipulate and read files and filepaths
 */

module.exports = {
  read: read,
  find_closest_match: find_closest_match,
  is_markdown: is_markdown,
  is_dot: is_dot,
  has_extension: has_extension
};

var grunt = require('grunt');

function read (filename, folder) {
  if (folder) filename = find_closest_match(folder, filename);
  return grunt.file.read(filename);
}

function find_closest_match (folder, filename) {
  if (!grunt.file.isDir(folder)) grunt.warn.log("The folder " + folder + " does not exist.");

  var pattern = build_pattern(folder, filename);
  var file = grunt.file.expand(pattern);

  // Warn again if the resulting file doesn't exist
  if (!file.length) grunt.fail.warn("The file " + pattern + " cannot be found.");

  return file[0];
};

function build_pattern (folder, filename) {
  var separator = '';
  if (folder) {
    separator = folder.length ? '/' : '';
  }
  var extension = has_extension(filename) ? '' : '.*';
  return folder + separator + filename + extension;
}

function is_markdown (file) {
  return /\.md$|\.md\..*$/.test(file);
};

function is_dot (file) {
  return /\.dot$|\.dot\..*$/.test(file.toString());
};

function has_extension (file) {
  return file.toString().match(/\.[0-9a-z]+$/i);
};<|endoftext|>


<commit_before>/**
 *  flic
 *  Written by: Nick Comer <nick@comer.io> (http://nick.comer.io)
 *  Licensed under MIT
 */

var net = require("net")
	, util = require("util")
	, events = require("events")
	, debug = require("debug")("flic")
	, _ = require("lodash")
	, Message = require("./flic-message.js");

// slave1 --[SLAVE_TELL(slave_name, slave_event, params...)]-> master --[SLAVE_EVENT(from, callback_id, event_name, params)]-> slave2
// 	||																													||	  <-[EVENT_CALLBACK(to, callback_id, params)]-------------   ||
//	||	 <-[MSG_ACK(callback_id, params...)]-----------------   ||

const SLAVE_TELL = "slave_tell";
// when going to master
// [0] slave name
// [1] slave event
// [2] array of params

const SLAVE_EVENT = "slave_event";
// [0] sent from which slave
// [1] callback id
// [2] event name
// [3] array of params

const EVENT_CALLBACK = "event_callback";

const SLAVE_IDENT = "slave_ident";
// NOTE: slaveName can be attached to the message instead of having to be placed
// in the data array.

const MSG_ACK = "message_ack";
// [0] the id of the message that is being acknowledged
// [1] array of args
//
// NOTE: MSG_ACK should never EVER be sent to Master, this might results in a
// callback loop.

function Master(port){
	var self = this;
	if(!_.isNumber(port)) port = 8221;

	self.sockets = {};
	self.server = net.createServer(function(socket){
		debug("Master - new slave");

		socket.on("data", function(message){

			if(process.env.DEBUG_FLIC){
				debug("Slave --> Master: %s", message);
			}

			// message is a stringified JSON, let's parse it
			message = JSON.parse(message);

			// make sure that the message has a type
			if(message.hasOwnProperty("type") && _.isString(message.type)){
				switch(message.type){
					case SLAVE_IDENT:
						debug("Master - Received SLAVE_IDENT from %s", message.slaveName);

						// Check if slave name is already taken
						if(!!self.sockets[message.slaveName]){
							debug("Duplicate slave name: %s", message.slaveName);
							var err = new Error("Duplicate slave name!");
							var ack_w_err = new Message(MSG_ACK, [message.id, [err]]);
							socket.write(ack_w_err.toString());
							return;
						}

						// Save socket to list of sockets!
						self.sockets[message.slaveName] = socket;

						// Create MSG_ACK message
						var ack = new Message(MSG_ACK, [message.id, [null]]);

						// Send that bitch
						debug("Master - Sending MSG_ACK (id: %s)", message.id);
						self.sockets[message.slaveName].write(ack.toString());

						break;
					case SLAVE_TELL:
						debug("Master - Received SLAVE_TELL from %s", message.slaveName);

						if(!self.sockets[message.data[0]]){
							debug("Attempting to tell a non-existent slave: %s", message.data[0]);
							var err = new Error("Attempting to tell non-existent slave");
							var ack_w_err = new Message(MSG_ACK, [message.id, [err]]);
							self.sockets[message.slaveName].write(ack_w_err.toString());
							return;
						}

						// Okay so the slave exists, lets prepare a message

						var msg = new Message(SLAVE_EVENT, [message.slaveName, message.id, message.data[1], message.data[2]]);

						self.sockets[message.data[0]].write(msg.toString());
						break;
					case EVENT_CALLBACK:
						debug("Master - Received EVENT_CALLBACK from %s", message.slaveName);
						var to = message.data[0]
							, callback_id = message.data[1]
							, params = message.data[2]
							, msg;

						var msg = new Message(MSG_ACK, [callback_id, params]);

						self.sockets[to].write(msg.toString());
						break;
					default:
						debug("Master received unrecognized command");
				}
			}
		});
	}).listen(port, function(){
		debug("Master - listening on port %d", port);
	});
}

function Slave(name, port, callback){
	/*
	TODO:
	- if disconnected from Master attempt to reconnect
	 */

	var self = this;

	// Set slave name
	if(!_.isString(name) && !name.match(/^[a-zA-Z|_|$][a-zA-Z0-9|_|$]*$/))
		throw new Error("Slave must have a valid name");
	else
		self.slaveName = name;

	// Make sure we have a valid port number
	if(!_.isNumber(port)) port = 8221;

	// Set up an array to store waiting callbacks
	self.waiters = {};

	// Lets connect to the Master
	self.master = net.connect(port, function(){

		// Identify the slave to the master
		debug("Slave  - sending SLAVE_IDENT");

		// Create a new Message
		var ident = new Message(SLAVE_IDENT);

		// Attach the slave name
		ident.setSlaveName(self.slaveName);

		// Get the ID of the message so we can store the callback as a waiter
		var message_id = ident.getId();

		// store the callback in the waiters list
		self.waiters[message_id] = callback;

		// tell the master
		self.master.write(ident.toString());
	});

	self.master.on("data", function(message){

		if(process.env.DEBUG_FLIC){
			debug("Slave <-- Master: %s", message);
		}

		// message is a stringified JSON, let's parse it
		message = JSON.parse(message);

		if(message.hasOwnProperty("type")) {
			switch(message.type){
				case MSG_ACK:
					debug("Slave  - Received MSG_ACK from Master for message: %s", message.data[0]);
					// Save the message ack id - we'll be plucking it from the array later.
					var mid = message.data[0];
					if(self.waiters.hasOwnProperty(mid)){
						var callback = self.waiters[mid];

						if(_.isFunction(callback)){
							var args = message.data[1];

							callback.apply(self, args);

							debug("Slave  - removing callback %s from waiters", mid);
							delete self.waiters[mid];
						}
					}
					break;
				case SLAVE_EVENT:
					var from = message.data[0]
						, callback_id = message.data[1]
						, event_name = message.data[2]
						, params = message.data[3];

					// Define a callback function that can be called by a receiving function
					var cb = function(){
						// Grab all the args
						var args = Array.prototype.slice.call(arguments);

						// construct the message
						var msg = new Message(EVENT_CALLBACK, [from, callback_id, args]);

						// set a slave name just for kicks i guess
						msg.setSlaveName(self.slaveName);

						// send that mo-fucka
						self.master.write(msg.toString());
					};

					// push the callback to the end of the params array
					params.push(cb);

					// push the event name to the beginning
					params.unshift(event_name);

					// emit that sunuva-bitch
					self.emit.apply(self, params);
			}
		}

	});

	self.master.on("error", function(e){
		callback(err);
	});
}
util.inherits(Slave, events.EventEmitter);

/**
 * Slave.tell - Send an event to a remote slave w/ data
 * @param {string} who_what "slave_name:event_name" a string
 * @param (who_what) - {string}
 * @param {args} args - any amount of arguments that need to be sent to the event
 * @param {function} callback - a callback function if the slave decideds to reply
 * @return {null}
 */
Slave.prototype.tell = function() {
	var self, args, who_what, callback, tell_message, mid;

	self = this;
	args = Array.prototype.slice.call(arguments);
	who_what = args.shift();
	if(_.isFunction(args[args.length - 1])){
		callback = args.pop();
	}

	if(!(_.isString(who_what) && who_what.match(/^[a-zA-Z0-9|_|$]*:[a-zA-Z0-9|_|$]*$/)))
		throw new Error("Invalid tell statment");

	var i = who_what.indexOf(":");
	var slaveName = who_what.substring(0, i);
	var eventName = who_what.substring(i + 1);

	var destination = [slaveName, eventName, args];

	tell_message = new Message(SLAVE_TELL, destination);
	tell_message.setSlaveName(self.slaveName);

	if(!!callback){
		mid = tell_message.getId();
		self.waiters[mid] = callback;
	}

	self.master.write(tell_message.toString());
}

module.exports = {
	Master: Master,
	Slave: Slave
};
<commit_msg>unify formatting, lowercase exported API, not trying to be Go here.<commit_after>/**
 *  flic
 *  Written by: Nick Comer <nick@comer.io> (http://nick.comer.io)
 *  Licensed under MIT
 */

var net = require("net"),
	util = require("util"),
	events = require("events"),
	debug = require("debug")("flic"),
	_ = require("lodash"),
	Message = require("./flic-message.js");

// slave1 --[SLAVE_TELL(slave_name, slave_event, params...)]-> master --[SLAVE_EVENT(from, callback_id, event_name, params)]-> slave2
// 	||																													||	  <-[EVENT_CALLBACK(to, callback_id, params)]-------------   ||
//	||	 <-[MSG_ACK(callback_id, params...)]-----------------   ||

const SLAVE_TELL = "slave_tell";
// when going to master
// [0] slave name
// [1] slave event
// [2] array of params

const SLAVE_EVENT = "slave_event";
// [0] sent from which slave
// [1] callback id
// [2] event name
// [3] array of params

const EVENT_CALLBACK = "event_callback";
// [0] to
// [1] callback_id
// [2] params

const SLAVE_IDENT = "slave_ident";
// NOTE: slaveName can be attached to the message instead of having to be placed
// in the data array.

const MSG_ACK = "message_ack";
// [0] the id of the message that is being acknowledged
// [1] array of args
//
// NOTE: MSG_ACK should never EVER be sent to Master, this might results in a
// callback loop.

function Master(port) {
	var self = this;
	if (!_.isNumber(port)) port = 8221;

	self.sockets = {};
	self.server = net.createServer(function(socket) {
		debug("Master - new slave");

		socket.on("data", function(message) {

			if (process.env.DEBUG_FLIC) {
				debug("Slave --> Master: %s", message);
			}

			// message is a stringified JSON, let's parse it
			message = JSON.parse(message);

			// make sure that the message has a type
			if (message.hasOwnProperty("type") && _.isString(message.type)) {
				switch (message.type) {
					case SLAVE_IDENT:
						debug("Master - Received SLAVE_IDENT from %s", message.slaveName);

						// Check if slave name is already taken
						if ( !! self.sockets[message.slaveName]) {
							debug("Duplicate slave name: %s", message.slaveName);

							// Unfortunately Error containers don't translate across TCP, so
							// we have to fall back to just putting error messages in strings.
							//
							// Documentation should strongly advise using the "error-first"
							// style callbacks, as flic will send any non-fatal error messages
							// using this paradigm.
							var err = new Error("Duplicate slave name!");
							err = err.toString();

							var ack_w_err = new Message(MSG_ACK, [message.id, [err]]);
							socket.write(ack_w_err.toString());
							return;
						}

						// Save socket to list of sockets!
						self.sockets[message.slaveName] = socket;

						// Create MSG_ACK message
						var ack = new Message(MSG_ACK, [message.id, [null]]);

						// Send that bitch
						debug("Master - Sending MSG_ACK (id: %s)", message.id);
						self.sockets[message.slaveName].write(ack.toString());

						break;
					case SLAVE_TELL:
						debug("Master - Received SLAVE_TELL from %s", message.slaveName);
						var to_tell = message.data[0];
						if (!self.sockets[to_tell]) {
							debug("Attempting to tell a non-existent slave: %s", to_tell);

							var err = new Error("Attempting to tell non-existent slave");
							err = err.toString();

							var ack_w_err = new Message(MSG_ACK, [message.id, [err]]);
							self.sockets[message.slaveName].write(ack_w_err.toString());
							return;
						}

						// Okay so the slave exists, lets prepare a message

						var msg = new Message(SLAVE_EVENT, [message.slaveName, message.id, message.data[1], message.data[2]]);

						self.sockets[message.data[0]].write(msg.toString());
						break;
					case EVENT_CALLBACK:
						debug("Master - Received EVENT_CALLBACK from %s", message.slaveName);
						var to = message.data[0],
							callback_id = message.data[1],
							params = message.data[2],
							msg;

						var msg = new Message(MSG_ACK, [callback_id, params]);

						self.sockets[to].write(msg.toString());
						break;
					default:
						debug("Master received unrecognized command");
				}
			}
		});
	}).listen(port, function() {
		debug("Master - listening on port %d", port);
	});
}

function Slave(name, port, callback) {
	/*
	TODO:
	- if disconnected from Master attempt to reconnect
	 */

	var self = this;

	// Set slave name
	if (!_.isString(name) && !name.match(/^[a-zA-Z|_|$][a-zA-Z0-9|_|$]*$/))
		throw new Error("Slave must have a valid name");
	else
		self.slaveName = name;

	// Make sure we have a valid port number
	if (!_.isNumber(port)) port = 8221;

	// Set up an array to store waiting callbacks
	self.waiters = {};

	// Lets connect to the Master
	self.master = net.connect(port, function() {

		// Identify the slave to the master
		debug("Slave  - sending SLAVE_IDENT");

		// Create a new Message
		var ident = new Message(SLAVE_IDENT);

		// Attach the slave name
		ident.setSlaveName(self.slaveName);

		// Get the ID of the message so we can store the callback as a waiter
		var message_id = ident.getId();

		// store the callback in the waiters list
		self.waiters[message_id] = callback;

		// tell the master
		self.master.write(ident.toString());
	});

	self.master.on("data", function(message) {

		if (process.env.DEBUG_FLIC) {
			debug("Slave <-- Master: %s", message);
		}

		// message is a stringified JSON, let's parse it
		message = JSON.parse(message);

		if (message.hasOwnProperty("type")) {
			switch (message.type) {
				case MSG_ACK:
					debug("Slave  - Received MSG_ACK from Master for message: %s", message.data[0]);
					// Save the message ack id - we'll be plucking it from the array later.
					var mid = message.data[0];
					if (self.waiters.hasOwnProperty(mid)) {
						var callback = self.waiters[mid];

						if (_.isFunction(callback)) {
							var args = message.data[1];

							callback.apply(self, args);

							debug("Slave  - removing callback %s from waiters", mid);
							delete self.waiters[mid];
						}
					}
					break;
				case SLAVE_EVENT:
					var from = message.data[0],
						callback_id = message.data[1],
						event_name = message.data[2],
						params = message.data[3];

					// Define a callback function that can be called by a receiving function
					var cb = function() {
						// Grab all the args
						var args = Array.prototype.slice.call(arguments);

						// construct the message
						var msg = new Message(EVENT_CALLBACK, [from, callback_id, args]);

						// set a slave name just for kicks i guess
						msg.setSlaveName(self.slaveName);

						// send that mo-fucka
						self.master.write(msg.toString());
					};

					// push the callback to the end of the params array
					params.push(cb);

					// push the event name to the beginning
					params.unshift(event_name);

					// emit that sunuva-bitch
					self.emit.apply(self, params);
			}
		}

	});

	self.master.on("error", function(e) {
		callback(err);
	});
}
util.inherits(Slave, events.EventEmitter);

/**
 * Slave.tell - Send an event to a remote slave w/ data
 * @param {string} who_what "slave_name:event_name" a string
 * @param (who_what) - {string}
 * @param {args} args - any amount of arguments that need to be sent to the event
 * @param {function} callback - a callback function if the slave decideds to reply
 * @return {null}
 */
Slave.prototype.tell = function() {
	var self, args, who_what, callback, tell_message, mid;

	self = this;
	args = Array.prototype.slice.call(arguments);
	who_what = args.shift();
	if (_.isFunction(args[args.length - 1])) {
		callback = args.pop();
	}

	if (!(_.isString(who_what) && who_what.match(/^[a-zA-Z0-9|_|$]*:[a-zA-Z0-9|_|$]*$/)))
		throw new Error("Invalid tell statment");

	var i = who_what.indexOf(":");
	var slaveName = who_what.substring(0, i);
	var eventName = who_what.substring(i + 1);

	var destination = [slaveName, eventName, args];

	tell_message = new Message(SLAVE_TELL, destination);
	tell_message.setSlaveName(self.slaveName);

	if ( !! callback) {
		mid = tell_message.getId();
		self.waiters[mid] = callback;
	}

	self.master.write(tell_message.toString());

	return self;
}

Slave.prototype.shout = function() {

};

module.exports = {
	master: Master,
	slave: Slave
};<|endoftext|>


<commit_before>const childProcess = require('child_process')
    , childModule  = require.resolve('./child/index')

function fork (forkModule) {
  // suppress --debug flags while preserving others (like --harmony)
  var filteredArgs = process.execArgv.filter(function (v) {
  	return v.indexOf('--debug') === -1
  })

  var child = childProcess.fork(childModule, {execArgv: filteredArgs}, {
          env: process.env
        , cwd: process.cwd()
      })

  child.send({ module: forkModule })

  // return a send() function for this child
  return {
      send  : function (data) {
        try {
          child.send(data)
        } catch (e) {
          // this *should* be picked up by onExit and the operation requeued
        }
      }
    , child : child
  }
}

module.exports = fork
<commit_msg>Correct style in rvagg/node-worker-farm#31<commit_after>const childProcess = require('child_process')
    , childModule  = require.resolve('./child/index')

function fork (forkModule) {
  // suppress --debug flags while preserving others (like --harmony)
  var filteredArgs = process.execArgv.filter(function (v) {
    	return v == '--debug'
    })
    , child        = childProcess.fork(childModule, { execArgv: filteredArgs }, {
          env: process.env
        , cwd: process.cwd()
      })

  child.send({ module: forkModule })

  // return a send() function for this child
  return {
      send  : function (data) {
        try {
          child.send(data)
        } catch (e) {
          // this *should* be picked up by onExit and the operation requeued
        }
      }
    , child : child
  }
}

module.exports = fork
<|endoftext|>


<commit_before>/**
 * @fileOverview A partical object for game rules.
 * @author kclv@ermitejo.com (MORIYA Masaki, alias Gardejo)
 * @license The MIT license (See LICENSE file)
 */

'use strict';

// ================================================================
// Game Rules
// ================================================================

// ----------------------------------------------------------------
// Namespace for Game Rules
// ----------------------------------------------------------------

/**
 * A namespace of game rules.
 * @public
 */
kclv.Game = {};

// ----------------------------------------------------------------
// Game Rule about Materials
// ----------------------------------------------------------------

/**
 * A game rule about materials.
 * @public
 * @const
 * @constructor
 */
kclv.Game.Materials = ( function() {
    /**
     * (Reserved) The maximum value of supplies of materials.
     * @private {Object.<string, number>}
     * @const
     */
    /*
    var LIMIT = {
        Resources   : 300000,
        Consumables :   3000
    };
    */

    /**
     * Default limit quantity for resources in imaginary HQ level 0.
     * @private {number}
     * @const
     */
    var FLOOR = 750;

    /**
     * Raise in limit quantity for resources induced by HQ level up.
     * @private {number}
     * @const
     */
    var RAISE_CEILING_PER_LEVEL = 250;

    /**
     * An alignment which compares material kinds with concrete material names.
     * @private {Object.<string, Array.<string>>}
     * @const
     */
    var MATERIALS_OF = {
        Resources   : [ 'Fuel', 'Ammunition', 'Steel', 'Bauxite' ],
        Consumables : [ 'Repair', 'Construction', 'Development' ]
    };

    /**
     * A list of concrete materials as a flattened array.
     *     Note: It is in particular order (order sensitive).
     * @private {Array.<string>}
     * @const
     */
    var MATERIALS = [].concat(
        MATERIALS_OF.Resources, MATERIALS_OF.Consumables
    );

    return {
        /**
         * Get an alignment which compares material kinds with concrete
         *     material names.
         * @public
         * @returns {Object.<string, Array.<string>>} An alignment which
         *     compares material kinds with concrete material names.
         * @nosideeffects
         */
        MATERIALS_OF : MATERIALS_OF,

        /**
         * Get concrete material names as a flattened array.
         * @public
         * @returns {Array.<string>} Concrete material names.
         * @nosideeffects
         */
        MATERIALS : MATERIALS,

        /**
         * Get a string representing a material kind which combined material
         *     names.
         * @public
         * @param {string} material A concrete material name.
         * @returns {string} A combined material name.
         * @throws {kclv.Exception.InvalidMaterial} If the specified concrete
         *     material name is invalid.
         * @nosideeffects
         */
        getKindOf : function(material) {
            if (MATERIALS_OF[material]) {
                return material;
            }

            for ( var kind in MATERIALS_OF ) {
                if ( MATERIALS_OF[kind].indexOf(material) >= 0 ) {
                    return kind;
                }
            }

            throw new kclv.Exception.InvalidMaterial(material, MATERIALS);
        },

        /**
         * Calculate a ceiling of spontaneous recovery of resources.
         *     Formula is: HQ level * 250 + 750 (base (floor) value).
         * @public
         * @param {!string} kind A string representing a material kind.
         * @returns {number} Ceiling of spontaneous recovery of resources.
         * @nosideeffects
         */
        getCeilingOf : function(kind, level) {
            return kind === 'Resources' && level ?
                level * RAISE_CEILING_PER_LEVEL + FLOOR : 0;
        }
    };
}() );

// ----------------------------------------------------------------
// Game Rule about Ships
// ----------------------------------------------------------------

/**
 * A game rule about ships (Combined Fleet Girls).
 * @public
 * @const
 * @constructor
 */
kclv.Game.Ships = ( function() {
    /* jshint -W100 */

    return {
        /**
         * Array of abbreviations for ship classification.
         *     Caveat: WSH's Active Script engine requires us to append
         *     BOM, the root of all evils, when we use string literals
         *     which includes non-ASCII characters (such as Kanji).
         *     Note: JSHint persistently warn us against even non-ASCII
         *     characters "in comments"! We have no choice.
         * @public {Array.<string>}
         * @const
         */
        ABBREVIATION_FOR : {
            '\u6F5C\u6C34\u6BCD\u8266'             : 'AS',
                // Submarine Tender
            '\u5DE5\u4F5C\u8266'                   : 'AR',
                // Repair Ship
            '\u88C5\u7532\u7A7A\u6BCD'             : 'CVB',
                // (Armored) Aircraft Carrier
            '\u63DA\u9678\u8266'                   : 'LHA',
                // Amphibious Assultship
            '\u6C34\u4E0A\u6A5F\u6BCD\u8266'       : 'AV',
                // Seaplane Carrier
            '\u6F5C\u6C34\u7A7A\u6BCD'             : 'SSV',
                // Aircraft Carrying Submarine
            '\u6F5C\u6C34\u8266'                   : 'SS',
                // Submarine
            '\u6B63\u898F\u7A7A\u6BCD'             : 'CV',
                // (Regular) Aircraft Carrier
            '\u822A\u7A7A\u6226\u8266'             : 'BBV',
                // Aviation Battleship
            '\u6226\u8266'                         : 'BB',
                // Battleship
         // '\u5DE1\u6D0B\u6226\u8266'             : 'BC',
                // Battlecruiser
            '\u8EFD\u7A7A\u6BCD'                   : 'CVL',
                // Light Aircraft Carrier
            '\u822A\u7A7A\u5DE1\u6D0B\u8266'       : 'CAV',
                // Aircraft Cruiser
            '\u91CD\u5DE1\u6D0B\u8266'             : 'CA',
                // Heavy Cruiser
            '\u91CD\u96F7\u88C5\u5DE1\u6D0B\u8266' : 'CLT',
                // Torpedo Cruiser
            '\u8EFD\u5DE1\u6D0B\u8266'             : 'CL',
                // Light Cruiser
            '\u99C6\u9010\u8266'                   : 'DD'
                // Destroyer
        },

        /**
         * (Reserved) The maximum number of player's port size.
         * @public {number}
         * @const
         */
        /*
        PORT_SIZE : 190,
        */

        /*
         * Ticks of accumulated experience points required for level up of a
         *     ship (Combined Fleet Girl).
         * @public {Array.<number>}
         * @const
         * @see http://wikiwiki.jp/kancolle/?%B7%D0%B8%B3%C3%CD#yecfa05a
         */
        EXPERIENCES : [
                  0,     100,     300,     600,    1000, //   1 -   5
               1500,    2100,    2800,    3600,    4500, //   6 -  10
               5500,    6600,    7800,    9100,   10500, //  11 -  15
              12000,   13600,   15300,   17100,   19000, //  16 -  20
              21000,   23100,   25300,   27600,   30000, //  21 -  25
              32500,   35100,   37800,   40600,   43500, //  26 -  30
              46500,   49600,   52800,   56100,   59500, //  31 -  35
              63000,   66600,   70300,   74100,   78000, //  36 -  40
              82000,   86100,   90300,   94600,   99000, //  41 -  45
             103500,  108100,  112800,  117600,  122500, //  46 -  50
             127500,  132700,  138100,  143700,  149500, //  51 -  55
             155500,  161700,  168100,  174700,  181500, //  56 -  60
             188500,  195800,  203400,  211300,  219500, //  61 -  65
             228000,  236800,  245900,  255300,  265000, //  66 -  70
             275000,  285400,  296200,  307400,  319000, //  71 -  75
             331000,  343400,  356200,  369400,  383000, //  76 -  80
             397000,  411500,  426500,  442000,  458000, //  81 -  85
             474500,  491500,  509000,  527000,  545500, //  86 -  90
             564500,  584500,  606500,  631500,  661500, //  91 -  95
             701500,  761500,  851500, 1000000, 1000000, //  96 - 100
            1010000, 1011000, 1013000, 1016000, 1020000, // 101 - 105
            1025000, 1031000, 1038000, 1046000, 1055000, // 106 - 110
            1065000, 1077000, 1091000, 1107000, 1125000, // 111 - 115
            1145000, 1168000, 1194000, 1223000, 1255000, // 116 - 120
            1290000, 1329000, 1372000, 1419000, 1470000, // 121 - 125
            1525000, 1584000, 1647000, 1714000, 1785000, // 126 - 130
            1860000, 1940000, 2025000, 2115000, 2210000, // 131 - 135
            2310000, 2415000, 2525000, 2640000, 2760000, // 136 - 140
            2887000, 3021000, 3162000, 3310000, 3465000, // 141 - 145
            3628000, 3799000, 3978000, 4165000, 4360000  // 146 - 150
        ]
    };
}() );
<commit_msg>Remove a non-functioning directive<commit_after>/**
 * @fileOverview A partical object for game rules.
 * @author kclv@ermitejo.com (MORIYA Masaki, alias Gardejo)
 * @license The MIT license (See LICENSE file)
 */

'use strict';

// ================================================================
// Game Rules
// ================================================================

// ----------------------------------------------------------------
// Namespace for Game Rules
// ----------------------------------------------------------------

/**
 * A namespace of game rules.
 * @public
 */
kclv.Game = {};

// ----------------------------------------------------------------
// Game Rule about Materials
// ----------------------------------------------------------------

/**
 * A game rule about materials.
 * @public
 * @const
 * @constructor
 */
kclv.Game.Materials = ( function() {
    /**
     * (Reserved) The maximum value of supplies of materials.
     * @private {Object.<string, number>}
     * @const
     */
    /*
    var LIMIT = {
        Resources   : 300000,
        Consumables :   3000
    };
    */

    /**
     * Default limit quantity for resources in imaginary HQ level 0.
     * @private {number}
     * @const
     */
    var FLOOR = 750;

    /**
     * Raise in limit quantity for resources induced by HQ level up.
     * @private {number}
     * @const
     */
    var RAISE_CEILING_PER_LEVEL = 250;

    /**
     * An alignment which compares material kinds with concrete material names.
     * @private {Object.<string, Array.<string>>}
     * @const
     */
    var MATERIALS_OF = {
        Resources   : [ 'Fuel', 'Ammunition', 'Steel', 'Bauxite' ],
        Consumables : [ 'Repair', 'Construction', 'Development' ]
    };

    /**
     * A list of concrete materials as a flattened array.
     *     Note: It is in particular order (order sensitive).
     * @private {Array.<string>}
     * @const
     */
    var MATERIALS = [].concat(
        MATERIALS_OF.Resources, MATERIALS_OF.Consumables
    );

    return {
        /**
         * Get an alignment which compares material kinds with concrete
         *     material names.
         * @public
         * @returns {Object.<string, Array.<string>>} An alignment which
         *     compares material kinds with concrete material names.
         * @nosideeffects
         */
        MATERIALS_OF : MATERIALS_OF,

        /**
         * Get concrete material names as a flattened array.
         * @public
         * @returns {Array.<string>} Concrete material names.
         * @nosideeffects
         */
        MATERIALS : MATERIALS,

        /**
         * Get a string representing a material kind which combined material
         *     names.
         * @public
         * @param {string} material A concrete material name.
         * @returns {string} A combined material name.
         * @throws {kclv.Exception.InvalidMaterial} If the specified concrete
         *     material name is invalid.
         * @nosideeffects
         */
        getKindOf : function(material) {
            if (MATERIALS_OF[material]) {
                return material;
            }

            for ( var kind in MATERIALS_OF ) {
                if ( MATERIALS_OF[kind].indexOf(material) >= 0 ) {
                    return kind;
                }
            }

            throw new kclv.Exception.InvalidMaterial(material, MATERIALS);
        },

        /**
         * Calculate a ceiling of spontaneous recovery of resources.
         *     Formula is: HQ level * 250 + 750 (base (floor) value).
         * @public
         * @param {!string} kind A string representing a material kind.
         * @returns {number} Ceiling of spontaneous recovery of resources.
         * @nosideeffects
         */
        getCeilingOf : function(kind, level) {
            return kind === 'Resources' && level ?
                level * RAISE_CEILING_PER_LEVEL + FLOOR : 0;
        }
    };
}() );

// ----------------------------------------------------------------
// Game Rule about Ships
// ----------------------------------------------------------------

/**
 * A game rule about ships (Combined Fleet Girls).
 * @public
 * @const
 * @constructor
 */
kclv.Game.Ships = ( function() {
    return {
        /**
         * Array of abbreviations for ship classification.
         *     Caveat: WSH's Active Script engine requires us to append
         *     BOM, the root of all evils, when we use string literals
         *     which includes non-ASCII characters (such as Kanji).
         *     Note: JSHint persistently warn us against even non-ASCII
         *     characters "in comments"! We have no choice.
         * @public {Array.<string>}
         * @const
         */
        ABBREVIATION_FOR : {
            '\u6F5C\u6C34\u6BCD\u8266'             : 'AS',
                // Submarine Tender
            '\u5DE5\u4F5C\u8266'                   : 'AR',
                // Repair Ship
            '\u88C5\u7532\u7A7A\u6BCD'             : 'CVB',
                // (Armored) Aircraft Carrier
            '\u63DA\u9678\u8266'                   : 'LHA',
                // Amphibious Assultship
            '\u6C34\u4E0A\u6A5F\u6BCD\u8266'       : 'AV',
                // Seaplane Carrier
            '\u6F5C\u6C34\u7A7A\u6BCD'             : 'SSV',
                // Aircraft Carrying Submarine
            '\u6F5C\u6C34\u8266'                   : 'SS',
                // Submarine
            '\u6B63\u898F\u7A7A\u6BCD'             : 'CV',
                // (Regular) Aircraft Carrier
            '\u822A\u7A7A\u6226\u8266'             : 'BBV',
                // Aviation Battleship
            '\u6226\u8266'                         : 'BB',
                // Battleship
         // '\u5DE1\u6D0B\u6226\u8266'             : 'BC',
                // Battlecruiser
            '\u8EFD\u7A7A\u6BCD'                   : 'CVL',
                // Light Aircraft Carrier
            '\u822A\u7A7A\u5DE1\u6D0B\u8266'       : 'CAV',
                // Aircraft Cruiser
            '\u91CD\u5DE1\u6D0B\u8266'             : 'CA',
                // Heavy Cruiser
            '\u91CD\u96F7\u88C5\u5DE1\u6D0B\u8266' : 'CLT',
                // Torpedo Cruiser
            '\u8EFD\u5DE1\u6D0B\u8266'             : 'CL',
                // Light Cruiser
            '\u99C6\u9010\u8266'                   : 'DD'
                // Destroyer
        },

        /**
         * (Reserved) The maximum number of player's port size.
         * @public {number}
         * @const
         */
        /*
        PORT_SIZE : 190,
        */

        /*
         * Ticks of accumulated experience points required for level up of a
         *     ship (Combined Fleet Girl).
         * @public {Array.<number>}
         * @const
         * @see http://wikiwiki.jp/kancolle/?%B7%D0%B8%B3%C3%CD#yecfa05a
         */
        EXPERIENCES : [
                  0,     100,     300,     600,    1000, //   1 -   5
               1500,    2100,    2800,    3600,    4500, //   6 -  10
               5500,    6600,    7800,    9100,   10500, //  11 -  15
              12000,   13600,   15300,   17100,   19000, //  16 -  20
              21000,   23100,   25300,   27600,   30000, //  21 -  25
              32500,   35100,   37800,   40600,   43500, //  26 -  30
              46500,   49600,   52800,   56100,   59500, //  31 -  35
              63000,   66600,   70300,   74100,   78000, //  36 -  40
              82000,   86100,   90300,   94600,   99000, //  41 -  45
             103500,  108100,  112800,  117600,  122500, //  46 -  50
             127500,  132700,  138100,  143700,  149500, //  51 -  55
             155500,  161700,  168100,  174700,  181500, //  56 -  60
             188500,  195800,  203400,  211300,  219500, //  61 -  65
             228000,  236800,  245900,  255300,  265000, //  66 -  70
             275000,  285400,  296200,  307400,  319000, //  71 -  75
             331000,  343400,  356200,  369400,  383000, //  76 -  80
             397000,  411500,  426500,  442000,  458000, //  81 -  85
             474500,  491500,  509000,  527000,  545500, //  86 -  90
             564500,  584500,  606500,  631500,  661500, //  91 -  95
             701500,  761500,  851500, 1000000, 1000000, //  96 - 100
            1010000, 1011000, 1013000, 1016000, 1020000, // 101 - 105
            1025000, 1031000, 1038000, 1046000, 1055000, // 106 - 110
            1065000, 1077000, 1091000, 1107000, 1125000, // 111 - 115
            1145000, 1168000, 1194000, 1223000, 1255000, // 116 - 120
            1290000, 1329000, 1372000, 1419000, 1470000, // 121 - 125
            1525000, 1584000, 1647000, 1714000, 1785000, // 126 - 130
            1860000, 1940000, 2025000, 2115000, 2210000, // 131 - 135
            2310000, 2415000, 2525000, 2640000, 2760000, // 136 - 140
            2887000, 3021000, 3162000, 3310000, 3465000, // 141 - 145
            3628000, 3799000, 3978000, 4165000, 4360000  // 146 - 150
        ]
    };
}() );
<|endoftext|>


<commit_before>const _ = require('underscore');

const Board = require('./board');
const Shape = require('./shape');
const hexHelper = require('./hex-helper');

const canvas = document.getElementById("game");
const ctx = canvas.getContext('2d');

var score = 0;

var isMouseDown = false;
var board = new Board(ctx);

var shapeInHand = null;
var shapeFrom = "second";

var mouseCoords = {};

var shapesInWaiting = {
  // first: new Shape(ctx),
  second: new Shape(ctx, 2),
  // third: new Shape(ctx)
}

const shapesInWaitingBoxes = [
  //{key: "first", bounds: [600, 700, 100, 200]},
  {key: "second", bounds: [600, 700, 250, 350]},
  //{key: "third", bounds: [600, 700, 400, 500]},
]

function drawShapesInWaiting() {
  //shapesInWaiting.first.draw(650, 150, .8);
  shapesInWaiting.second.draw(650, 300, .8);
  //shapesInWaiting.third.draw(650, 450, .8);
}

function drawShapeInHand(){
  if(isMouseDown && shapeInHand) {
    shapeInHand.draw(mouseCoords.x, mouseCoords.y);
  }
}

function whichShapeDidYouPick() {
  return shapesInWaiting.second;
  // return shapesInWaitingBoxes.reduce(function(shape, box) {
  //   var bounds = box.bounds;
  //   if(mouseCoords.x > bounds[0] && mouseCoords.x < bounds[1] && mouseCoords.y
  //     > bounds[2] && mouseCoords.y < bounds[3]){
  //     shape = shapesInWaiting[box.key];
  //     shapeFrom = box.key;
  //   }
  //   return shape;
  // }, false)
}

// board.addRandomTiles();

requestAnimationFrame(function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  board.draw();
  board.drawPotentialSlots(mouseCoords, shapeInHand);
  drawShapesInWaiting();
  drawShapeInHand();
  requestAnimationFrame(gameLoop);
});

document.addEventListener('mousedown', function(event){
  mouseCoords = getMousePos(canvas, event);
  isMouseDown = true;
  shapeInHand = whichShapeDidYouPick();
})

document.addEventListener('mouseup', function(event){
  pixels = hexHelper.subVector2(mouseCoords, hexHelper.boardOffset);
  if(shapeInHand && board.validDrop(pixels, shapeInHand)){
    let hexes = board.addTilesFromShape(pixels, shapeInHand);
    //console.log('hexes', hexes);
    hexes.forEach(hex => {
      score += board.removeThreePlus(hex);
      console.log('totlescore',score);
    });

    shapesInWaiting[shapeFrom] = new Shape(ctx, board.getMaxValue());
    // score += board.removeFullLines();
    document.getElementById("score-value").innerText = score;
    if(!board.movesRemaining(_.values(shapesInWaiting)))
      alert("No more moves");
  }

  isMouseDown = false;
  shapeInHand = null;
})

document.addEventListener('mousemove', function(event){
  if(isMouseDown){
    mouseCoords = getMousePos(canvas, event);
  }
})

function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}
<commit_msg>Rotate shape<commit_after>const _ = require('underscore');

const Board = require('./board');
const Shape = require('./shape');
const hexHelper = require('./hex-helper');

const canvas = document.getElementById("game");
const ctx = canvas.getContext('2d');

var score = 0;

var isMouseDown = false;
var board = new Board(ctx);

var shapeInHand = null;
var shapeFrom = "second";

var mouseCoords = {};

var shapesInWaiting = {
  // first: new Shape(ctx),
  second: new Shape(ctx, 2),
  // third: new Shape(ctx)
}

const shapesInWaitingBoxes = [
  //{key: "first", bounds: [600, 700, 100, 200]},
  {key: "second", bounds: [600, 700, 250, 350]},
  //{key: "third", bounds: [600, 700, 400, 500]},
]

function drawShapesInWaiting() {
  //shapesInWaiting.first.draw(650, 150, .8);
  shapesInWaiting.second.draw(650, 300, .8);
  //shapesInWaiting.third.draw(650, 450, .8);
}

function drawShapeInHand(){
  if(isMouseDown && shapeInHand) {
    shapeInHand.draw(mouseCoords.x, mouseCoords.y);
  }
}

function whichShapeDidYouPick() {
  return shapesInWaiting.second;
  // return shapesInWaitingBoxes.reduce(function(shape, box) {
  //   var bounds = box.bounds;
  //   if(mouseCoords.x > bounds[0] && mouseCoords.x < bounds[1] && mouseCoords.y
  //     > bounds[2] && mouseCoords.y < bounds[3]){
  //     shape = shapesInWaiting[box.key];
  //     shapeFrom = box.key;
  //   }
  //   return shape;
  // }, false)
}

// board.addRandomTiles();

requestAnimationFrame(function gameLoop() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);
  board.draw();
  board.drawPotentialSlots(mouseCoords, shapeInHand);
  drawShapesInWaiting();
  drawShapeInHand();
  requestAnimationFrame(gameLoop);
});

document.addEventListener('mousedown', function(event){
  mouseCoords = getMousePos(canvas, event);
  isMouseDown = true;
  shapeInHand = whichShapeDidYouPick();
})

document.addEventListener('mouseup', function(event){
  pixels = hexHelper.subVector2(mouseCoords, hexHelper.boardOffset);
  if(shapeInHand && board.validDrop(pixels, shapeInHand)){
    let hexes = board.addTilesFromShape(pixels, shapeInHand);
    //console.log('hexes', hexes);
    hexes.forEach(hex => {
      score += board.removeThreePlus(hex);
      console.log('totlescore',score);
    });

    shapesInWaiting[shapeFrom] = new Shape(ctx, board.getMaxValue());
    // score += board.removeFullLines();
    document.getElementById("score-value").innerText = score;
    if(!board.movesRemaining(_.values(shapesInWaiting)))
      alert("No more moves");
  }

  isMouseDown = false;
  shapeInHand = null;
})

document.addEventListener('mousemove', function(event){
  if(isMouseDown){
    mouseCoords = getMousePos(canvas, event);
  }
})

document.addEventListener('click', function(event){
  let bounds = shapesInWaitingBoxes[0].bounds;
  if (mouseCoords.x > bounds[0] && mouseCoords.x < bounds[1] && mouseCoords.y
      > bounds[2] && mouseCoords.y < bounds[3]) {
    //console.log('shapesInWaiting[shapeFrom]',shapesInWaiting[shapeFrom]);
    let shape = shapesInWaiting[shapeFrom];
    if (shape.tiles.length === 2 &&
      shape.tiles[0].tile.value !== shape.tiles[1].tile.value) {
      //console.log('BF shape.tiles',shape.tiles);
      let temp = shape.tiles[0].tile;
      shape.tiles[0].tile = shape.tiles[1].tile;
      shape.tiles[1].tile = temp;
      shape.draw(650, 300, .8);
    }
  }
})

function getMousePos(canvas, evt) {
  var rect = canvas.getBoundingClientRect();
  return {
    x: evt.clientX - rect.left,
    y: evt.clientY - rect.top
  };
}
<|endoftext|>


<commit_before>const $ = require('jquery');

function Lingo(){
  $(document).ready(function(){
    $('#start-button').on('click',function(){
      console.log('congrats');
      // generateMysteryWord();
      // hideMysteryWord();
      // renderMysteryWord();
    });
  });

$(document).on('keypress',function(event){
    if (isLetter(event) === true) {

    } else {
      event.preventDefault();
    }

    //Check to see whether grid has one letter
    //If it does, move to next column in the table if gridIsFilled() (perhaps by simulating a tab key press)
    //If the rowIsFilled(); and a key is pressed, replace the last letter in the row with keyCode
    //On enter submit the row to the scanTron. (UI / RULES NEEDS TO INDICATE WHY ENTER)
    //The scanTran returns the results (x color in correct place, y color if wrong place, z color not in the word)
  });
}

    //IS BACKSPACE OR DELETE
    //13 IS THE ENTER KEY

    //SHOULD ANYTHING HAPPEN WHEN THE ARROW KEYS ARE PRESSED?
function isLetter(event){
    if (event.keyCode >= 97 && event.keyCode <= 122 ) {
      return true;
    }
}

function rowIsFilled(){
  var row;
  if (row.length === 5){
    return true;
  }
}

function generateMysteryWord(){
  // generate random number
  var array = ['sport','mulch','foams','phone','grunt'];
  var mysteryWord = array[(Math.floor(Math.random()*(array.length)))];
  // return array[randomize]
  return mysteryWord;
}

function hideMysteryWord() {
  var mysteryCharacterArray = generateMysteryWord().split("");
  for (var i = 1; i < mysteryCharacterArray.length; i++) {
    // mysteryCharacterArray = mysteryCharacterArray[i].hide();
  }
  return mysteryCharacterArray;
}

function renderMysteryWord() {
  // Display on the header-tile class
}

module.exports = Lingo;
<commit_msg>retargeted jquery<commit_after>const $ = require('jquery');

function Lingo(){
  $(document).ready(function(){
    $('#start-button').on('click',function(){
      console.log('congrats');
      // generateMysteryWord();
      // hideMysteryWord();
      // renderMysteryWord();
    });
  });

var guess = $('input').on('keypress',function(event){
    if (isLetter(event) === true) {
      console.log('him mom')
    } else {
      event.preventDefault();
    }
    if (isGridFull() === true) {
      // var nextInput = guess
    }

    //If it does, move to next column in the table if gridIsFilled() (perhaps by simulating a tab key press)
    //If the rowIsFilled(); and a key is pressed, replace the last letter in the row with keyCode
    //On enter submit the row to the scanTron. (UI / RULES NEEDS TO INDICATE WHY ENTER)
    //The scanTran returns the results (x color in correct place, y color if wrong place, z color not in the word)
    //IS BACKSPACE OR DELETE
    //13 IS THE ENTER KEY

    //SHOULD ANYTHING HAPPEN WHEN THE ARROW KEYS ARE PRESSED?
  });
}

function isGridFull(){
    if (this.find('.letter-guess') !== "") {
      return true;
    }
}

function isLetter(event){
    if (event.keyCode >= 97 && event.keyCode <= 122 ) {
      return true;
    }
}

function rowIsFilled(){
  var row;
  if (row.length === 5){
    return true;
  }
}

function generateMysteryWord(){
  // generate random number
  var array = ['sport','mulch','foams','phone','grunt'];
  var mysteryWord = array[(Math.floor(Math.random()*(array.length)))];
  // return array[randomize]
  return mysteryWord;
}

function hideMysteryWord() {
  var mysteryCharacterArray = generateMysteryWord().split("");
  for (var i = 1; i < mysteryCharacterArray.length; i++) {
    // mysteryCharacterArray = mysteryCharacterArray[i].hide();
  }
  return mysteryCharacterArray;
}

function renderMysteryWord() {
  // Display on the header-tile class
}

module.exports = Lingo;
<|endoftext|>


<commit_before>module.exports = function() {
  var parser = {
        encoding: parser_encoding,
        push: parser_push,
        pop: parser_pop
      },
      buffer = new Buffer(0),
      bufferOffset = 0,
      bufferLength = 0,
      encoding = "utf8",
      fragments = null,
      state = STATE_DEFAULT;

  function parser_encoding(newEncoding) {
    if (!arguments.length) return encoding;
    if (buffer != null) throw new Error("cannot change encoding after pushing data");
    if (!Buffer.isEncoding(newEncoding = newEncoding + "")) throw new Error("unknown encoding: " + newEncoding);
    encoding = newEncoding;
    return parser;
  }

  function parser_push(data) {
    if (bufferOffset < bufferLength) throw new Error("cannot push before all lines are popped");
    bufferLength = data.length;
    bufferOffset = 0;
    buffer = data;
  }

  function parser_pop(allowPartial) {
    var oldBufferOffset = bufferOffset;

    // Find the next line terminator.
    while (bufferOffset < bufferLength) {
      var code = buffer[bufferOffset++];
      if (state === STATE_MAYBE_CARRIAGE_RETURN_LINE_FEED) {
        if (code === CODE_LINE_FEED) {
          state = STATE_AFTER_CARRIAGE_RETURN_LINE_FEED;
        } else {
          state = STATE_AFTER_LINE_FEED; // treat bare \r as \n
          --bufferOffset;
        }
        break;
      }
      if (code === CODE_LINE_FEED) {
        state = STATE_AFTER_LINE_FEED;
        break;
      }
      if (code === CODE_CARRIAGE_RETURN) {
        state = STATE_MAYBE_CARRIAGE_RETURN_LINE_FEED;
        continue;
      }
    }

    // Slice the buffer up to the line terminator (or end of buffer).
    var afterLine = state === STATE_AFTER_LINE_FEED || state === STATE_AFTER_CARRIAGE_RETURN_LINE_FEED,
        terminatorLength = state === STATE_AFTER_CARRIAGE_RETURN_LINE_FEED ? 2 : state === STATE_DEFAULT ? 0 : 1,
        fragment = buffer.slice(oldBufferOffset, bufferOffset - terminatorLength);

    // If we read to the end of a line, return it!
    if (afterLine || allowPartial) {
      state = STATE_DEFAULT;

      // Combine this with previously-read line fragments, if any.
      if (fragments) {
        fragments.push(fragment);
        fragment = Buffer.concat(fragments);
        fragments = null;
      }

      // If this is the last line in a file not terminated with a new line,
      // then return the line even though there’s no trailing terminator.
      return !allowPartial || fragment.length ? fragment.toString(encoding) : null;
    }

    // Otherwise, we’ve read part of a line. Copy the fragment so that the
    // source buffer can be modified without changing the fragment contents.
    var fragmentCopy = new Buffer(fragment.length);
    fragment.copy(fragmentCopy);
    if (fragments) fragments.push(fragmentCopy);
    else fragments = [fragmentCopy];
    return null;
  }

  return parser;
};

var CODE_LINE_FEED = 10,
    CODE_CARRIAGE_RETURN = 13;

var STATE_DEFAULT = 1,
    STATE_AFTER_LINE_FEED = 2,
    STATE_AFTER_CARRIAGE_RETURN_LINE_FEED = 3,
    STATE_MAYBE_CARRIAGE_RETURN_LINE_FEED = 4;
<commit_msg>Actually correctly handle interrupted CRLF?<commit_after>module.exports = function() {
  var parser = {
        encoding: parser_encoding,
        push: parser_push,
        pop: parser_pop
      },
      buffer = new Buffer(0),
      bufferOffset = 0,
      bufferLength = 0,
      encoding = "utf8",
      fragment = null,
      state = STATE_DEFAULT;

  function parser_encoding(newEncoding) {
    if (!arguments.length) return encoding;
    if (buffer != null) throw new Error("cannot change encoding after pushing data");
    if (!Buffer.isEncoding(newEncoding = newEncoding + "")) throw new Error("unknown encoding: " + newEncoding);
    encoding = newEncoding;
    return parser;
  }

  function parser_push(data) {
    if (bufferOffset < bufferLength) throw new Error("cannot push before all lines are popped");
    bufferLength = data.length;
    bufferOffset = 0;
    buffer = data;
  }

  function parser_pop(allowPartial) {
    var oldBufferOffset = bufferOffset;

    // Find the next line terminator.
    while (bufferOffset < bufferLength) {
      var code = buffer[bufferOffset++];
      if (state === STATE_MAYBE_CARRIAGE_RETURN_LINE_FEED) {
        if (code === CODE_LINE_FEED) {
          state = STATE_AFTER_CARRIAGE_RETURN_LINE_FEED;
        } else {
          state = STATE_AFTER_LINE_FEED; // treat bare \r as \n
          --bufferOffset;
        }
        break;
      }
      if (code === CODE_LINE_FEED) {
        state = STATE_AFTER_LINE_FEED;
        break;
      }
      if (code === CODE_CARRIAGE_RETURN) {
        state = STATE_MAYBE_CARRIAGE_RETURN_LINE_FEED;
        continue;
      }
    }

    // Slice out the new data.
    var newFragment = buffer.slice(oldBufferOffset, bufferOffset);

    // Combine it with the old data, if any.
    if (fragment != null) {
      var oldFragment = newFragment;
      newFragment = new Buffer(fragment.length + oldFragment.length);
      fragment.copy(newFragment);
      oldFragment.copy(newFragment, fragment.length);
      fragment = null;
    }

    // Slice off the \r or \n.
    if (state === STATE_AFTER_LINE_FEED) {
      state = STATE_DEFAULT;
      return newFragment.slice(0, -1);
    }

    // Slice off the \r\n.
    if (state === STATE_AFTER_CARRIAGE_RETURN_LINE_FEED) {
      state = STATE_DEFAULT;
      return newFragment.slice(0, -2);
    }

    // Return the whole thing, if a trailing partial line is wanted.
    if (allowPartial) {
      state = STATE_DEFAULT;
      return newFragment.length ? newFragment : null;
    }

    // Otherwise, we’ve read part of a line. Copy the fragment so that the
    // source buffer can be modified without changing the fragment contents.
    fragment = new Buffer(newFragment.length);
    newFragment.copy(fragment);
    return null;
  }

  return parser;
};

var CODE_LINE_FEED = 10,
    CODE_CARRIAGE_RETURN = 13;

var STATE_DEFAULT = 1,
    STATE_AFTER_LINE_FEED = 2,
    STATE_AFTER_CARRIAGE_RETURN_LINE_FEED = 3,
    STATE_MAYBE_CARRIAGE_RETURN_LINE_FEED = 4;
<|endoftext|>