<commit_before>/**
 * @class Ds.gemo.WebShare
 * @classdesc:微博分享代码类
 * @extends
 * @example:
 * //微博分享
 * Ds.gemo.WebShare.SetWebShare('tsina', 'images/ShareImg.jpg', '分享内容', location.href);
 * @author: maksim email:maksim.lin@foxmail.com
 * @copyright:  我发起Ds库目的，简化方便工作项目开发。里面代码大部分理念来至曾经flash 前端时代，尽力减小类之间耦合，通过webpack按需request使用。Ds库里代码很多也都来源至或参考网络开源开放代码，所以这个库也开源开放。更多希望团队成员把积累工作中常用的代码，加快自己开发效率。
 * @constructor
 **/

 //111
(function(factory) {
    var root = (typeof self == 'object' && self.self == self && self) ||
        (typeof global == 'object' && global.global == global && global);

    if (typeof define === 'function' && define.amd) {
        define(['exports'], function(exports) {
            module.exports = factory(root, exports);
        });
    } else if (typeof exports !== 'undefined') {
        module.exports = factory(root, exports);
    } else {
        factory(root, {});
    }

}(function(root, modelObj) {
    root.Ds = root.Ds || {};
    root.Ds.gemo = root.Ds.gemo || {};
    root.Ds.gemo.WebShare = new WebShare();
    /**
     * 快速进行执行检测代码
     */
    function WebShare() {
        var _Self = this;
        var _ShareType = 'tsina',
            _ShareImg = 'images/ShareImg.jpg',
            _ShareContent = "分享内容",
            _ShareUrl = location.origin;
        /**
         * 设置分享
         * @param  {[String]} shareType   [分享类型 qqzone,tsina,renren,douban,kaixin,tenxun,weixin]
         * @param  {[String]} shareImg [分享图片]
         * @param  {[String]} shareContent [分享内容]
         * @param  {[String]} shareUrl [分享链接]
         */
        this.SetWebShare = function(shareType, shareImg, shareContent, shareUrl) {
            var _type = shareType || _ShareType,
                _img = shareImg || _ShareImg,
                _title = shareContent || _ShareContent,
                _url = shareUrl || _ShareUrl;
            if (_type == "qqzone") {
                window.location.href = ('http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + encodeURIComponent(_url) +
                    '&title=' + encodeURIComponent(_title + "") + '&pics=' + encodeURIComponent(_img) + '&summary=' + encodeURIComponent(_title));
            } else if (_type == "tsina") {
                window.location.href = ('http://s.jiathis.com/?webid=' + _type + '&title=' + encodeURIComponent(_title + "") + '&pic=' +
                    encodeURIComponent(_img) + "&url=" + encodeURIComponent(_url));
            } else if (_type == "renren") {
                window.location.href = ('http://s.jiathis.com/?webid=' + _type + '&summary=' + encodeURIComponent(_title) + '&url=' +
                    encodeURIComponent(_url) + '&title=' + '&pic=' + encodeURIComponent(_img));
            } else if (_type == "douban") {
                window.location.href = ('http://s.jiathis.com/?webid=' + _type + '&summary=' + '&title=' + encodeURIComponent(_title) +
                    '&pic=' + encodeURIComponent(_img) + "&url=" + encodeURIComponent(_url));
            } else if (_type == "kaixin") {
                window.location.href = ('http://www.kaixin001.com/rest/records.php?content=' + encodeURIComponent(_title) +
                    '&starid=&aid=&style=11&pic=' + encodeURIComponent(_img) + '&t=10&url=' + encodeURIComponent(_url));
            } else if (_type == "tenxun") {
                window.location.href = ("http://share.v.t.qq.com/index.php?c=share&a=index&title=" + encodeURIComponent(_title) + "&url=" +
                    encodeURIComponent(_url) + "&appkey=&site=&pic=" + encodeURIComponent(_img));
            } else if (_type == "weixin") {
                window.location.href = ("http://s.jiathis.com/?webid=weixin&uid=0&jtss=0&appkey=&ralateuid=&url=" +
                    encodeURIComponent(_url) + "&title=" + encodeURIComponent(_title) + "&pic=" +
                    encodeURIComponent(_img) + "&acn=&acu=&summary=&isexit=false");
            }
        };
    }

    return root.Ds.gemo.WebShare;
}));
<commit_msg>recall<commit_after>/**
 * @class Ds.gemo.WebShare
 * @classdesc:Web分享代码类
 * @extends
 * @example:
 * //Web分享
 * Ds.gemo.WebShare.SetWebShare('tsina', 'images/ShareImg.jpg', '分享内容', location.href);
 * @author: recall email:739736379.@qq.com11
 * @copyright:  WebShare类主要针对于其它APP的分享  一些常用的方法封装起来 方便以后使用
 * @constructor
 **/

 //
(function(factory) {
    var root = (typeof self == 'object' && self.self == self && self) ||
        (typeof global == 'object' && global.global == global && global);

    if (typeof define === 'function' && define.amd) {
        define(['exports'], function(exports) {
            module.exports = factory(root, exports);
        });
    } else if (typeof exports !== 'undefined') {
        module.exports = factory(root, exports);
    } else {
        factory(root, {});
    }

}(function(root, modelObj) {
    root.Ds = root.Ds || {};
    root.Ds.gemo = root.Ds.gemo || {};
    root.Ds.gemo.WebShare = new WebShare();
    /**
     * 快速进行执行检测代码
     */
    function WebShare() {
        var _Self = this;
        var _ShareType = 'tsina',
            _ShareImg = 'images/ShareImg.jpg',
            _ShareContent = "分享内容",
            _ShareUrl = location.origin;
        /**
         * 设置分享
         * @param  {[String]} shareType   [分享类型 qqzone,tsina,renren,douban,kaixin,tenxun,weixin]
         * @param  {[String]} shareImg [分享图片]
         * @param  {[String]} shareContent [分享内容]
         * @param  {[String]} shareUrl [分享链接]
         */
        this.SetWebShare = function(shareType, shareImg, shareContent, shareUrl) {
            var _type = shareType || _ShareType,
                _img = shareImg || _ShareImg,
                _title = shareContent || _ShareContent,
                _url = shareUrl || _ShareUrl;
            if (_type == "qqzone") {
                window.location.href = ('http://sns.qzone.qq.com/cgi-bin/qzshare/cgi_qzshare_onekey?url=' + encodeURIComponent(_url) +
                    '&title=' + encodeURIComponent(_title + "") + '&pics=' + encodeURIComponent(_img) + '&summary=' + encodeURIComponent(_title));
            } else if (_type == "tsina") {
                window.location.href = ('http://s.jiathis.com/?webid=' + _type + '&title=' + encodeURIComponent(_title + "") + '&pic=' +
                    encodeURIComponent(_img) + "&url=" + encodeURIComponent(_url));
            } else if (_type == "renren") {
                window.location.href = ('http://s.jiathis.com/?webid=' + _type + '&summary=' + encodeURIComponent(_title) + '&url=' +
                    encodeURIComponent(_url) + '&title=' + '&pic=' + encodeURIComponent(_img));
            } else if (_type == "douban") {
                window.location.href = ('http://s.jiathis.com/?webid=' + _type + '&summary=' + '&title=' + encodeURIComponent(_title) +
                    '&pic=' + encodeURIComponent(_img) + "&url=" + encodeURIComponent(_url));
            } else if (_type == "kaixin") {
                window.location.href = ('http://www.kaixin001.com/rest/records.php?content=' + encodeURIComponent(_title) +
                    '&starid=&aid=&style=11&pic=' + encodeURIComponent(_img) + '&t=10&url=' + encodeURIComponent(_url));
            } else if (_type == "tenxun") {
                window.location.href = ("http://share.v.t.qq.com/index.php?c=share&a=index&title=" + encodeURIComponent(_title) + "&url=" +
                    encodeURIComponent(_url) + "&appkey=&site=&pic=" + encodeURIComponent(_img));
            } else if (_type == "weixin") {
                window.location.href = ("http://s.jiathis.com/?webid=weixin&uid=0&jtss=0&appkey=&ralateuid=&url=" +
                    encodeURIComponent(_url) + "&title=" + encodeURIComponent(_title) + "&pic=" +
                    encodeURIComponent(_img) + "&acn=&acu=&summary=&isexit=false");
            }
        };
    }

    return root.Ds.gemo.WebShare;
}));
<|endoftext|>


<commit_before>
/** TurtleGUI - a javascript GUI library. Shared using MIT license (see LICENSE file)
*/

$.ajaxSetup ({
    // Disable caching of AJAX responses
    cache: false
});

var turtlegui = {};

turtlegui.root_element = $(document);

turtlegui._get_safe_value = function(elem, datasrc) {
    var gres = elem.attr(datasrc);
    if (!gres) {
        throw "No " + datasrc + " field on element " + elem.attr('id');
    }
    return turtlegui._relative_eval(elem, gres);
}

turtlegui._relative_eval = function(elem, gres) {
    try {
    var rel = elem.data('data-rel');
    }catch(e) {
        console.log("error ");
    }
    var switcharoo = {};
    for (var key in rel) {
        if (key in window) {
            switcharoo[key] = window[key];
        }
        window[key] = rel[key];
    }
    try {
        result = eval(gres);
    } catch(e) {
        try {
            console.log("Error at:");
            var getstack = function(elm) {
                return elm.parent().length > 0 && !elm.parent().is('body') ? getstack(elm.parent()).concat([elm]) : [elm];
            }
            var stack = getstack(elem);
            for (var i in stack) {
                var elm = $(stack[i]);
                var desc = elm.prop('nodeName') + (elm.attr('id')?'#'+elm.attr('id'):"") + "[" + elm.index() + "]";
                console.log("  ".repeat(i) + desc);
            }
            console.log("Error evaluating " + gres + " on elem : " + e);
        } catch (noconsole) {
            throw e;
        }
    } finally {
        for (var key in switcharoo) {
            window[key] = switcharoo[key];
        }
    }
    return result;
}

turtlegui.load_snippet = function(elem, url, rel_data) {
    elem.load(url, function(response, status, xhr) {
        if (status == 'success') {
            turtlegui.reload(elem, rel_data);
        } else {
            console.log("Could not load html snippet: " + url + " - " + xhr.status + " " + xhr.statusText);
        }
    });
}

turtlegui.reload = function(elem, rel_data) {
    if (!rel_data) rel_data = {};

    if (!elem) {
        elem = turtlegui.root_element;
    }
    if (rel_data) {
        elem.data('data-rel', rel_data);
    }
    if (elem.attr('data-gui-text')) {
        value = turtlegui._get_safe_value(elem, 'data-gui-text');
        elem.text(value);
    }
    if (elem.attr('data-gui-class')) {
        var value = turtlegui._get_safe_value(elem, 'data-gui-class');
        elem.addClass(value);
    }
    if (elem.attr('data-gui-id')) {
        var value = turtlegui._get_safe_value(elem, 'data-gui-id');
        $(elem).attr('id', value);
    }
    if (elem.attr('data-gui-show')) {
        var value = turtlegui._get_safe_value(elem, 'data-gui-show');
        if (value) {
            elem.show();
        } else {
            elem.hide();
            if (elem.attr('data-gui-id')) {
                $(elem).attr('id', null);
            }
            return;
        }
    }
    if (elem.attr('data-gui-click')) {
        elem.unbind('click').click(function() {
            return turtlegui._get_safe_value(elem, 'data-gui-click');
        });
    }
    if (elem.attr('data-gui-list')) {
        var list = turtlegui._get_safe_value(elem, 'data-gui-list');
        var rel_item = elem.attr('data-gui-item');
        var rel_key = elem.attr('data-gui-key');
        var orig_elems = elem.children();
        var first_elem = $(orig_elems[0]);
        first_elem.hide();
        var new_elems = [];
        for (var i in list) {
            var new_elem = $(first_elem).clone();
            new_elems[new_elems.length] = new_elem;
        }
        for (var i in new_elems) {
            var item = list[i];
            var new_elem = new_elems[i];
            elem.append(new_elem);
            new_elem.show();
            var rel_data = jQuery.extend({}, rel_data);
            rel_data[rel_item] = item;
            if (rel_key != null) {
                rel_data[rel_key] = i;
            }
            turtlegui.reload(new_elem, rel_data);
        }
        orig_elems.remove();
        elem.prepend(first_elem);
    }
    else if (elem.attr('data-gui-tree')) {
        var tree = turtlegui._get_safe_value(elem, 'data-gui-tree');
        var rel_item = elem.attr('data-gui-nodeitem');

        var orig_elems = elem.children();
        var first_elem = $(orig_elems[0]);
        first_elem.hide();
        var rel_data = jQuery.extend({}, rel_data);
        rel_data[rel_item] = tree;
        rel_data['_last_tree_elem'] = first_elem;
        rel_data['_last_tree_item'] = rel_item;

        var new_elem = $(first_elem).clone();
        elem.append(new_elem);
        new_elem.show();
        turtlegui.reload(new_elem, rel_data);

        orig_elems.remove();
        elem.prepend(first_elem);
    }
    else if (elem.attr('data-gui-node')) {
        var node = turtlegui._get_safe_value(elem, 'data-gui-node');

        var orig_elems = elem.children();
        var first_elem = rel_data['_last_tree_elem'];
        first_elem.hide();
        var rel_data = jQuery.extend({}, rel_data);
        rel_data[rel_item] = node;
        rel_data[rel_data['_last_tree_item']] = node;

        var new_elem = $(first_elem).clone();
        elem.append(new_elem);
        new_elem.show();
        turtlegui.reload(new_elem, rel_data);

        orig_elems.remove();
        elem.prepend(first_elem);
    }
    else if (elem.attr('data-gui-include') && !elem.attr('data-gui-included')) {
        elem.attr('data-gui-included', true);
        var url = turtlegui._get_safe_value(elem, 'data-gui-include');
        turtlegui.load_snippet(elem, url, rel_data);
    }
    else {
        elem.children().each(function() {
            turtlegui.reload($(this), rel_data);
        });
    }

    if (elem.attr('data-gui-val') || elem.attr('data-gui-change')) {
        // This overwrites any manually bound change events
        $(elem).unbind('change');
    }

    if (elem.attr('data-gui-val')) {
        var value = turtlegui._get_safe_value(elem, 'data-gui-val');
        if ($(elem).is(':checkbox')) {
            $(elem).prop('checked', value);
        } else {
            if (elem.attr('data-gui-format-func')) {
                if (value != null) {
                    value = turtlegui._relative_eval(elem, elem.attr('data-gui-format-func'))(value);
                }
            }
            $(elem).val(value);
        }
        $(elem).change(function () {
            var gres = elem.attr('data-gui-val');
            if ($(elem).is(':checkbox')) {
                turtlegui._relative_eval(elem, gres + " = " + $(elem).prop('checked'));
            } else if (elem.attr('data-gui-parse-func')) {
                var elem_val = $(elem).val();
                if (elem_val != null) {
                    // Complex objects don't parse so well with eval, so putting the result into the data-rel structure
                    var __formatted = turtlegui._relative_eval(elem, elem.attr('data-gui-parse-func'))(elem_val);
                    var rel = elem.data('data-rel');
                    rel['__formatted'] = __formatted;
                    turtlegui._relative_eval(elem, gres + " = __formatted");
                } else {
                    turtlegui._relative_eval(elem, gres + " = null");
                }
            } else {
                turtlegui._relative_eval(elem, gres + " = '" + $(elem).val() + "'");
            }
        });
    }
    if (elem.attr('data-gui-change')) {
        $(elem).change(function (){
            turtlegui._get_safe_value(elem, 'data-gui-change');
        });
    }
}
<commit_msg>Polishing strings with newlines<commit_after>
/** TurtleGUI - a javascript GUI library. Shared using MIT license (see LICENSE file)
*/

$.ajaxSetup ({
    // Disable caching of AJAX responses
    cache: false
});

var turtlegui = {};

turtlegui.root_element = $(document);

turtlegui._get_safe_value = function(elem, datasrc) {
    var gres = elem.attr(datasrc);
    if (!gres) {
        throw "No " + datasrc + " field on element " + elem.attr('id');
    }
    return turtlegui._relative_eval(elem, gres);
}

turtlegui._relative_eval = function(elem, gres) {
    try {
    var rel = elem.data('data-rel');
    }catch(e) {
        console.log("error ");
    }
    var switcharoo = {};
    for (var key in rel) {
        if (key in window) {
            switcharoo[key] = window[key];
        }
        window[key] = rel[key];
    }
    try {
        result = eval(gres);
    } catch(e) {
        try {
            console.log("Error at:");
            var getstack = function(elm) {
                return elm.parent().length > 0 && !elm.parent().is('body') ? getstack(elm.parent()).concat([elm]) : [elm];
            }
            var stack = getstack(elem);
            for (var i in stack) {
                var elm = $(stack[i]);
                var desc = elm.prop('nodeName') + (elm.attr('id')?'#'+elm.attr('id'):"") + "[" + elm.index() + "]";
                console.log("  ".repeat(i) + desc);
            }
            console.log("Error evaluating " + gres + " on elem : " + e);
        } catch (noconsole) {
            throw e;
        }
    } finally {
        for (var key in switcharoo) {
            window[key] = switcharoo[key];
        }
    }
    return result;
}

turtlegui.load_snippet = function(elem, url, rel_data) {
    elem.load(url, function(response, status, xhr) {
        if (status == 'success') {
            turtlegui.reload(elem, rel_data);
        } else {
            console.log("Could not load html snippet: " + url + " - " + xhr.status + " " + xhr.statusText);
        }
    });
}

turtlegui.reload = function(elem, rel_data) {
    if (!rel_data) rel_data = {};

    if (!elem) {
        elem = turtlegui.root_element;
    }
    if (rel_data) {
        elem.data('data-rel', rel_data);
    }
    if (elem.attr('data-gui-text')) {
        value = turtlegui._get_safe_value(elem, 'data-gui-text');
        elem.text(value);
    }
    if (elem.attr('data-gui-class')) {
        var value = turtlegui._get_safe_value(elem, 'data-gui-class');
        elem.addClass(value);
    }
    if (elem.attr('data-gui-id')) {
        var value = turtlegui._get_safe_value(elem, 'data-gui-id');
        $(elem).attr('id', value);
    }
    if (elem.attr('data-gui-show')) {
        var value = turtlegui._get_safe_value(elem, 'data-gui-show');
        if (value) {
            elem.show();
        } else {
            elem.hide();
            if (elem.attr('data-gui-id')) {
                $(elem).attr('id', null);
            }
            return;
        }
    }
    if (elem.attr('data-gui-click')) {
        elem.unbind('click').click(function() {
            return turtlegui._get_safe_value(elem, 'data-gui-click');
        });
    }
    if (elem.attr('data-gui-list')) {
        var list = turtlegui._get_safe_value(elem, 'data-gui-list');
        var rel_item = elem.attr('data-gui-item');
        var rel_key = elem.attr('data-gui-key');
        var orig_elems = elem.children();
        var first_elem = $(orig_elems[0]);
        first_elem.hide();
        var new_elems = [];
        for (var i in list) {
            var new_elem = $(first_elem).clone();
            new_elems[new_elems.length] = new_elem;
        }
        for (var i in new_elems) {
            var item = list[i];
            var new_elem = new_elems[i];
            elem.append(new_elem);
            new_elem.show();
            var rel_data = jQuery.extend({}, rel_data);
            rel_data[rel_item] = item;
            if (rel_key != null) {
                rel_data[rel_key] = i;
            }
            turtlegui.reload(new_elem, rel_data);
        }
        orig_elems.remove();
        elem.prepend(first_elem);
    }
    else if (elem.attr('data-gui-tree')) {
        var tree = turtlegui._get_safe_value(elem, 'data-gui-tree');
        var rel_item = elem.attr('data-gui-nodeitem');

        var orig_elems = elem.children();
        var first_elem = $(orig_elems[0]);
        first_elem.hide();
        var rel_data = jQuery.extend({}, rel_data);
        rel_data[rel_item] = tree;
        rel_data['_last_tree_elem'] = first_elem;
        rel_data['_last_tree_item'] = rel_item;

        var new_elem = $(first_elem).clone();
        elem.append(new_elem);
        new_elem.show();
        turtlegui.reload(new_elem, rel_data);

        orig_elems.remove();
        elem.prepend(first_elem);
    }
    else if (elem.attr('data-gui-node')) {
        var node = turtlegui._get_safe_value(elem, 'data-gui-node');

        var orig_elems = elem.children();
        var first_elem = rel_data['_last_tree_elem'];
        first_elem.hide();
        var rel_data = jQuery.extend({}, rel_data);
        rel_data[rel_item] = node;
        rel_data[rel_data['_last_tree_item']] = node;

        var new_elem = $(first_elem).clone();
        elem.append(new_elem);
        new_elem.show();
        turtlegui.reload(new_elem, rel_data);

        orig_elems.remove();
        elem.prepend(first_elem);
    }
    else if (elem.attr('data-gui-include') && !elem.attr('data-gui-included')) {
        elem.attr('data-gui-included', true);
        var url = turtlegui._get_safe_value(elem, 'data-gui-include');
        turtlegui.load_snippet(elem, url, rel_data);
    }
    else {
        elem.children().each(function() {
            turtlegui.reload($(this), rel_data);
        });
    }

    if (elem.attr('data-gui-val') || elem.attr('data-gui-change')) {
        // This overwrites any manually bound change events
        $(elem).unbind('change');
    }

    if (elem.attr('data-gui-val')) {
        var value = turtlegui._get_safe_value(elem, 'data-gui-val');
        if ($(elem).is(':checkbox')) {
            $(elem).prop('checked', value);
        } else {
            if (elem.attr('data-gui-format-func')) {
                if (value != null) {
                    value = turtlegui._relative_eval(elem, elem.attr('data-gui-format-func'))(value);
                }
            }
            $(elem).val(value);
        }
        $(elem).change(function () {
            var gres = elem.attr('data-gui-val');
            if ($(elem).is(':checkbox')) {
                turtlegui._relative_eval(elem, gres + " = " + $(elem).prop('checked'));
            } else if (elem.attr('data-gui-parse-func')) {
                var elem_val = $(elem).val();
                if (elem_val != null) {
                    // Complex objects don't parse so well with eval, so putting the result into the data-rel structure
                    var __formatted = turtlegui._relative_eval(elem, elem.attr('data-gui-parse-func'))(elem_val);
                    var rel = elem.data('data-rel');
                    rel['__formatted'] = __formatted;
                    turtlegui._relative_eval(elem, gres + " = __formatted");
                } else {
                    turtlegui._relative_eval(elem, gres + " = null");
                }
            } else {
                var elemval = $(elem).val();
                elemval = elemval.replace(/(?:\r\n|\r|\n)/g, '\\n');
                turtlegui._relative_eval(elem, gres + " = '" + elemval + "'");
            }
        });
    }
    if (elem.attr('data-gui-change')) {
        $(elem).change(function (){
            turtlegui._get_safe_value(elem, 'data-gui-change');
        });
    }
}
<|endoftext|>


<commit_before>const master = require("cluster");
const cluster = require("./cluster.js");
const numCPUs = require('os').cpus().length;
const logger = require("../utils/logger.js");
const EventEmitter = require("events");
const Eris = require("eris");
const Queue = require("../utils/queue.js");
const pkg = require("../../package.json")

/**
 *
 *
 * @class ClusterManager
 * @extends {EventEmitter}
 */
class ClusterManager extends EventEmitter {
    /**
     * Creates an instance of ClusterManager.
     * @param {any} token
     * @param {any} mainFile
     * @param {any} options
     * @memberof ClusterManager
     */
    constructor(token, mainFile, options) {
        super();

        this.shardCount = options.shards || 0;
        this.firstShardID = options.firstShardID || 0;
        this.lastShardID = options.lastShardID || (this.shardCount - 1);
        this.clusterCount = options.clusters || numCPUs;
        this.clusterTimeout = options.clusterTimeout * 1000 || 5000;

        this.token = token || false;

        this.clusters = new Map();
        this.workers = new Map();
        this.queue = new Queue();
        this.callbacks = new Map();

        this.options = {
            stats: options.stats || false,
            debug: options.debug || false
        };

        this.statsInterval = options.statsInterval || 60 * 1000;
        this.mainFile = mainFile;
        this.name = options.name || "Eris-Sharder";
        this.guildsPerShard = options.guildsPerShard || 1300;

        this.webhooks = Object.assign({
            cluster: undefined,
            shard: undefined
        }, options.webhooks);

        this.clientOptions = options.clientOptions || {};

        if (options.stats === true) {
            this.stats = {
                stats: {
                    guilds: 0,
                    users: 0,
                    totalRam: 0,
                    voice: 0,
                    exclusiveGuilds: 0,
                    largeGuilds: 0,
                    clusters: []
                },
                clustersCounted: 0
            }
        }

        if (this.token) {
            this.eris = new Eris(token);
            this.launch(false);
        } else {
            throw new Error("No token provided");
        }
    }

    isMaster() {
        return master.isMaster;
    }

    startStats() {
        if (this.statsInterval != null) {
            setInterval(() => {
                this.stats.stats.guilds = 0;
                this.stats.stats.users = 0;
                this.stats.stats.totalRam = 0;
                this.stats.stats.clusters = [];
                this.stats.stats.voice = 0;
                this.stats.stats.exclusiveGuilds = 0;
                this.stats.stats.largeGuilds = 0;
                this.stats.clustersCounted = 0;

                let clusters = Object.entries(master.workers);

                this.executeStats(clusters, 0);
            }, this.statsInterval);
        }
    }

    /**
     *
     *
     * @param {any} start
     * @memberof ClusterManager
     */
    executeStats(clusters, start) {
        const clusterToRequest = clusters.filter(c => c[1].state === 'online')[start];
        if (clusterToRequest) {
            let c = clusterToRequest[1];

            c.send({ name: "stats" });

            this.executeStats(clusters, start + 1);
        }
    }

    /**
     *
     *
     * @param {any} amount
     * @param {any} numSpawned
     * @memberof ClusterManager
     */
    start(clusterID) {
        if (clusterID === this.clusterCount) {
            logger.info("Cluster Manager", "Clusters have been launched!");

            let shards = [];

            for (let i = this.firstShardID; i <= this.lastShardID; i++) {
                shards.push(i);
            }

            let chunkedShards = this.chunk(shards, this.clusterCount);

            chunkedShards.forEach((chunk, clusterID) => {
                let cluster = this.clusters.get(clusterID);

                this.clusters.set(clusterID, Object.assign(cluster, {
                    firstShardID: Math.min(...chunk),
                    lastShardID: Math.max(...chunk)
                }));
            });

            this.connectShards();
        } else {
            let worker = master.fork();
            this.clusters.set(clusterID, { workerID: worker.id });
            this.workers.set(worker.id, clusterID);
            logger.info("Cluster Manager", `Launching cluster ${clusterID}`);
            clusterID += 1;

            this.start(clusterID);
        }
    }

    /**
     *
     *
     * @memberof ClusterManager
     */
    launch(test) {
        if (master.isMaster) {
            process.on("uncaughtException", err => {
                logger.error("Cluster Manager", err.stack);
            });

            this.printLogo();

            process.nextTick(async () => {
                logger.info("General", "Cluster Manager has started!");

                let shards = await this.calculateShards();

                this.shardCount = shards;

                logger.info("Cluster Manager", `Starting ${this.shardCount} shards in ${this.clusterCount} clusters`);

                let embed = {
                    title: `Starting ${this.shardCount} shards in ${this.clusterCount} clusters`
                }

                this.sendWebhook("cluster", embed);

                master.setupMaster({
                    silent: false
                });

                // Fork workers.
                this.start(0);
            });
        } else if (master.isWorker) {
            const Cluster = new cluster();
            Cluster.spawn();
        }

        master.on('message', async (worker, message, handle) => {
            if (message.name) {
                const clusterID = this.workers.get(worker.id);

                switch (message.name) {
                    case "log":
                        logger.log(`Cluster ${clusterID}`, `${message.msg}`);
                        break;
                    case "debug":
                        if (this.options.debug) {
                            logger.debug(`Cluster ${clusterID}`, `${message.msg}`);
                        }
                        break;
                    case "info":
                        logger.info(`Cluster ${clusterID}`, `${message.msg}`);
                        break;
                    case "warn":
                        logger.warn(`Cluster ${clusterID}`, `${message.msg}`);
                        break;
                    case "error":
                        logger.error(`Cluster ${clusterID}`, `${message.msg}`);
                        break;
                    case "shardsStarted":
                        this.queue.queue.splice(0, 1);

                        if (this.queue.queue.length > 0) {
                            setTimeout(() => this.queue.executeQueue(), this.clusterTimeout);
                        }
                        break;
                    case "cluster":
                        this.sendWebhook("cluster", message.embed);
                        break;
                    case "shard":
                        this.sendWebhook("shard", message.embed);
                        break;
                    case "stats":
                        this.stats.stats.guilds += message.stats.guilds;
                        this.stats.stats.users += message.stats.users;
                        this.stats.stats.voice += message.stats.voice;
                        this.stats.stats.totalRam += message.stats.ram;
                        let ram = message.stats.ram / 1000000;
                        this.stats.stats.exclusiveGuilds += message.stats.exclusiveGuilds;
                        this.stats.stats.largeGuilds += message.stats.largeGuilds;
                        this.stats.stats.clusters.push({
                            cluster: clusterID,
                            shards: message.stats.shards,
                            guilds: message.stats.guilds,
                            ram: ram,
                            voice: message.stats.voice,
                            uptime: message.stats.uptime,
                            exclusiveGuilds: message.stats.exclusiveGuilds,
                            largeGuilds: message.stats.largeGuilds,
                            shardsStats: message.stats.shardsStats
                        });

                        this.stats.clustersCounted += 1;

                        if (this.stats.clustersCounted === this.clusters.size) {
                            function compare(a, b) {
                                if (a.cluster < b.cluster)
                                    return -1;
                                if (a.cluster > b.cluster)
                                    return 1;
                                return 0;
                            }

                            let clusters = this.stats.stats.clusters.sort(compare);

                            this.emit("stats", {
                                guilds: this.stats.stats.guilds,
                                users: this.stats.stats.users,
                                voice: this.stats.stats.voice,
                                exclusiveGuilds: this.stats.stats.exclusiveGuilds,
                                largeGuilds: this.stats.stats.largeGuilds,
                                totalRam: this.stats.stats.totalRam / 1000000,
                                clusters: clusters
                            });
                        }
                        break;

                    case "fetchUser":
                        this.fetchInfo(0, "fetchUser", message.id);
                        this.callbacks.set(message.id, clusterID);
                        break;
                    case "fetchGuild":
                        this.fetchInfo(0, "fetchGuild", message.id);
                        this.callbacks.set(message.id, clusterID);
                        break;
                    case "fetchChannel":
                        this.fetchInfo(0, "fetchChannel", message.id);
                        this.callbacks.set(message.id, clusterID);
                        break;
                    case "fetchMember":
                        this.fetchInfo(0, "fetchMember", [message.guildID, message.memberID]);
                        this.callbacks.set(message.memberID, clusterID);
                        break;
                    case "fetchReturn":
                        console.log(message);
                        let callback = this.callbacks.get(message.value.id);

                        let cluster = this.clusters.get(callback);

                        if (cluster) {
                            master.workers[cluster.workerID].send({ name: "fetchReturn", id: message.value.id, value: message.value });
                            this.callbacks.delete(message.value.id);
                        }
                        break;
                    case "broadcast":
                        this.broadcast(0, message.msg);
                        break;
                    case "send":
                        this.sendTo(message.cluster, message.msg)
                        break;
                    case "apiRequest":
                        let response;
                        let error;

                        let { method, url, auth, body, file, _route, short } = message;

                        if (file && file.file) file.file = Buffer.from(file.file, 'base64');

                        try {
                            response = await this.eris.requestHandler.request(method, url, auth, body, file, _route, short);
                        } catch (err) {
                            error = {
                                code: err.code,
                                message: err.message,
                                stack: err.stack
                            };
                        }

                        if (error) {
                            this.sendTo(clusterID, { _eventName: `apiResponse.${message.requestID}`, err: error })
                        } else {
                            this.sendTo(clusterID, { _eventName: `apiResponse.${message.requestID}`, data: response });
                        }

                        break;
                }
            }
        });

        master.on('disconnect', (worker) => {
            const clusterID = this.workers.get(worker.id);
            logger.warn("Cluster Manager", `cluster ${clusterID} disconnected`);
        });

        master.on('exit', (worker, code, signal) => {
            this.restartCluster(worker, code, signal);
        });

        this.queue.on("execute", item => {
            let cluster = this.clusters.get(item.item);

            if (cluster) {
                master.workers[cluster.workerID].send(item.value);
            }
        });
    }

    chunk(shards, clusterCount) {

        if (clusterCount < 2) return [shards];

        let len = shards.length;
        let out = [];
        let i = 0;
        let size;

        if (len % clusterCount === 0) {
            size = Math.floor(len / clusterCount);

            while (i < len) {
                out.push(shards.slice(i, i += size));
            }
        } else {
            while (i < len) {
                size = Math.ceil((len - i) / clusterCount--);
                out.push(shards.slice(i, i += size));
            }
        }

        return out;
    }

    connectShards() {
        for (let clusterID in [...Array(this.clusterCount).keys()]) {
            clusterID = parseInt(clusterID);

            let cluster = this.clusters.get(clusterID);

            if (!cluster.hasOwnProperty('firstShardID')) break;

            this.queue.queueItem({
                item: clusterID,
                value: {
                    id: clusterID,
                    clusterCount: this.clusterCount,
                    name: "connect",
                    firstShardID: cluster.firstShardID,
                    lastShardID: cluster.lastShardID,
                    maxShards: this.shardCount,
                    token: this.token,
                    file: this.mainFile,
                    clientOptions: this.clientOptions,
                }
            });
        }

        logger.info("Cluster Manager", `All shards spread`);

        if (this.stats) {
            this.startStats();
        }
    }

    /**
     *
     *
     * @param {any} type
     * @param {any} embed
     * @memberof ClusterManager
     */
    sendWebhook(type, embed) {
        if (!this.webhooks || !this.webhooks[type]) return;
        let id = this.webhooks[type].id;
        let token = this.webhooks[type].token;
        embed.timestamp = new Date();
        if (id && token) {
            this.eris.executeWebhook(id, token, { embeds: [embed] });
        }
    }

    printLogo() {
        const logo = require('asciiart-logo');
        console.log(
            logo({
                name: this.name,
                font: 'Big',
                lineChars: 15,
                padding: 5,
                margin: 2
            })
                .emptyLine()
                .right(`eris-sharder ${pkg.version}`)
                .emptyLine()
                .render()
        );
    }

    restartCluster(worker, code, signal) {
        const clusterID = this.workers.get(worker.id);

        logger.warn("Cluster Manager", `cluster ${clusterID} died`);

        let cluster = this.clusters.get(clusterID);

        let embed = {
            title: `Cluster ${clusterID} died with code ${code}. Restarting...`,
            description: `Shards ${cluster.firstShardID} - ${cluster.lastShardID}`
        }

        this.sendWebhook("cluster", embed);

        let shards = cluster.shardCount;

        let newWorker = master.fork();

        this.workers.delete(worker.id);

        this.clusters.set(clusterID, Object.assign(cluster, { workerID: newWorker.id }));

        this.workers.set(newWorker.id, clusterID);

        logger.debug("Cluster Manager", `Restarting cluster ${clusterID}`);

        this.queue.queueItem({
            item: clusterID, value: {
                id: clusterID,
                clusterCount: this.clusterCount,
                name: "connect",
                shards: shards,
                firstShardID: cluster.firstShardID,
                lastShardID: cluster.lastShardID,
                maxShards: this.shardCount,
                token: this.token,
                file: this.mainFile,
                clientOptions: this.clientOptions,
                test: this.test
            }
        });
    }

    async calculateShards() {
        let shards = this.shardCount;

        if (this.shardCount !== 0) return Promise.resolve(this.shardCount);

        let result = await this.eris.getBotGateway();
        shards = result.shards;

        if (shards === 1) {
            return Promise.resolve(shards);
        } else {
            let guildCount = shards * 1000;
            let guildsPerShard = this.guildsPerShard;
            let shardsDecimal = guildCount / guildsPerShard;
            let finalShards = Math.ceil(shardsDecimal);
            return Promise.resolve(finalShards);
        }
    }

    fetchInfo(start, type, value) {
        let cluster = this.clusters.get(start);
        if (cluster) {
            master.workers[cluster.workerID].send({ name: type, value: value });
            this.fetchInfo(start + 1, type, value);
        }
    }

    broadcast(start, message) {
        let cluster = this.clusters.get(start);
        if (cluster) {
            master.workers[cluster.workerID].send(message);
            this.broadcast(start + 1, message);
        }
    }

    sendTo(cluster, message) {
        let worker = master.workers[this.clusters.get(cluster).workerID];
        if (worker) {
            worker.send(message);
        }
    }
}

module.exports = ClusterManager;
<commit_msg>Replace default shardCount with auto instead of zero<commit_after>const master = require("cluster");
const cluster = require("./cluster.js");
const numCPUs = require('os').cpus().length;
const logger = require("../utils/logger.js");
const EventEmitter = require("events");
const Eris = require("eris");
const Queue = require("../utils/queue.js");
const pkg = require("../../package.json")

/**
 *
 *
 * @class ClusterManager
 * @extends {EventEmitter}
 */
class ClusterManager extends EventEmitter {
    /**
     * Creates an instance of ClusterManager.
     * @param {any} token
     * @param {any} mainFile
     * @param {any} options
     * @memberof ClusterManager
     */
    constructor(token, mainFile, options) {
        super();

        this.shardCount = options.shards || 'auto';
        this.firstShardID = options.firstShardID || 0;
        this.lastShardID = options.lastShardID || 0;
        this.clusterCount = options.clusters || numCPUs;
        this.clusterTimeout = options.clusterTimeout * 1000 || 5000;

        this.token = token || false;

        this.clusters = new Map();
        this.workers = new Map();
        this.queue = new Queue();
        this.callbacks = new Map();

        this.options = {
            stats: options.stats || false,
            debug: options.debug || false
        };

        this.statsInterval = options.statsInterval || 60 * 1000;
        this.mainFile = mainFile;
        this.name = options.name || "Eris-Sharder";
        this.guildsPerShard = options.guildsPerShard || 1300;

        this.webhooks = Object.assign({
            cluster: undefined,
            shard: undefined
        }, options.webhooks);

        this.clientOptions = options.clientOptions || {};

        if (options.stats === true) {
            this.stats = {
                stats: {
                    guilds: 0,
                    users: 0,
                    totalRam: 0,
                    voice: 0,
                    exclusiveGuilds: 0,
                    largeGuilds: 0,
                    clusters: []
                },
                clustersCounted: 0
            }
        }

        if (this.token) {
            this.eris = new Eris(token);
            this.launch(false);
        } else {
            throw new Error("No token provided");
        }
    }

    isMaster() {
        return master.isMaster;
    }

    startStats() {
        if (this.statsInterval != null) {
            setInterval(() => {
                this.stats.stats.guilds = 0;
                this.stats.stats.users = 0;
                this.stats.stats.totalRam = 0;
                this.stats.stats.clusters = [];
                this.stats.stats.voice = 0;
                this.stats.stats.exclusiveGuilds = 0;
                this.stats.stats.largeGuilds = 0;
                this.stats.clustersCounted = 0;

                let clusters = Object.entries(master.workers);

                this.executeStats(clusters, 0);
            }, this.statsInterval);
        }
    }

    /**
     *
     *
     * @param {any} start
     * @memberof ClusterManager
     */
    executeStats(clusters, start) {
        const clusterToRequest = clusters.filter(c => c[1].state === 'online')[start];
        if (clusterToRequest) {
            let c = clusterToRequest[1];

            c.send({ name: "stats" });

            this.executeStats(clusters, start + 1);
        }
    }

    /**
     *
     *
     * @param {any} amount
     * @param {any} numSpawned
     * @memberof ClusterManager
     */
    start(clusterID) {
        if (clusterID === this.clusterCount) {
            logger.info("Cluster Manager", "Clusters have been launched!");

            let shards = [];

            for (let i = this.firstShardID; i <= this.lastShardID; i++) {
                shards.push(i);
            }

            let chunkedShards = this.chunk(shards, this.clusterCount);

            chunkedShards.forEach((chunk, clusterID) => {
                let cluster = this.clusters.get(clusterID);

                this.clusters.set(clusterID, Object.assign(cluster, {
                    firstShardID: Math.min(...chunk),
                    lastShardID: Math.max(...chunk)
                }));
            });

            this.connectShards();
        } else {
            let worker = master.fork();
            this.clusters.set(clusterID, { workerID: worker.id });
            this.workers.set(worker.id, clusterID);
            logger.info("Cluster Manager", `Launching cluster ${clusterID}`);
            clusterID += 1;

            this.start(clusterID);
        }
    }

    /**
     *
     *
     * @memberof ClusterManager
     */
    launch(test) {
        if (master.isMaster) {
            process.on("uncaughtException", err => {
                logger.error("Cluster Manager", err.stack);
            });

            this.printLogo();

            process.nextTick(async () => {
                logger.info("General", "Cluster Manager has started!");

                let shards = await this.calculateShards();

                this.shardCount = shards;

                if (this.lastShardID === 0) this.lastShardID = this.shardCount - 1;

                logger.info("Cluster Manager", `Starting ${this.shardCount} shards in ${this.clusterCount} clusters`);

                let embed = {
                    title: `Starting ${this.shardCount} shards in ${this.clusterCount} clusters`
                }

                this.sendWebhook("cluster", embed);

                master.setupMaster({
                    silent: false
                });

                // Fork workers.
                this.start(0);
            });
        } else if (master.isWorker) {
            const Cluster = new cluster();
            Cluster.spawn();
        }

        master.on('message', async (worker, message, handle) => {
            if (message.name) {
                const clusterID = this.workers.get(worker.id);

                switch (message.name) {
                    case "log":
                        logger.log(`Cluster ${clusterID}`, `${message.msg}`);
                        break;
                    case "debug":
                        if (this.options.debug) {
                            logger.debug(`Cluster ${clusterID}`, `${message.msg}`);
                        }
                        break;
                    case "info":
                        logger.info(`Cluster ${clusterID}`, `${message.msg}`);
                        break;
                    case "warn":
                        logger.warn(`Cluster ${clusterID}`, `${message.msg}`);
                        break;
                    case "error":
                        logger.error(`Cluster ${clusterID}`, `${message.msg}`);
                        break;
                    case "shardsStarted":
                        this.queue.queue.splice(0, 1);

                        if (this.queue.queue.length > 0) {
                            setTimeout(() => this.queue.executeQueue(), this.clusterTimeout);
                        }
                        break;
                    case "cluster":
                        this.sendWebhook("cluster", message.embed);
                        break;
                    case "shard":
                        this.sendWebhook("shard", message.embed);
                        break;
                    case "stats":
                        this.stats.stats.guilds += message.stats.guilds;
                        this.stats.stats.users += message.stats.users;
                        this.stats.stats.voice += message.stats.voice;
                        this.stats.stats.totalRam += message.stats.ram;
                        let ram = message.stats.ram / 1000000;
                        this.stats.stats.exclusiveGuilds += message.stats.exclusiveGuilds;
                        this.stats.stats.largeGuilds += message.stats.largeGuilds;
                        this.stats.stats.clusters.push({
                            cluster: clusterID,
                            shards: message.stats.shards,
                            guilds: message.stats.guilds,
                            ram: ram,
                            voice: message.stats.voice,
                            uptime: message.stats.uptime,
                            exclusiveGuilds: message.stats.exclusiveGuilds,
                            largeGuilds: message.stats.largeGuilds,
                            shardsStats: message.stats.shardsStats
                        });

                        this.stats.clustersCounted += 1;

                        if (this.stats.clustersCounted === this.clusters.size) {
                            function compare(a, b) {
                                if (a.cluster < b.cluster)
                                    return -1;
                                if (a.cluster > b.cluster)
                                    return 1;
                                return 0;
                            }

                            let clusters = this.stats.stats.clusters.sort(compare);

                            this.emit("stats", {
                                guilds: this.stats.stats.guilds,
                                users: this.stats.stats.users,
                                voice: this.stats.stats.voice,
                                exclusiveGuilds: this.stats.stats.exclusiveGuilds,
                                largeGuilds: this.stats.stats.largeGuilds,
                                totalRam: this.stats.stats.totalRam / 1000000,
                                clusters: clusters
                            });
                        }
                        break;

                    case "fetchUser":
                        this.fetchInfo(0, "fetchUser", message.id);
                        this.callbacks.set(message.id, clusterID);
                        break;
                    case "fetchGuild":
                        this.fetchInfo(0, "fetchGuild", message.id);
                        this.callbacks.set(message.id, clusterID);
                        break;
                    case "fetchChannel":
                        this.fetchInfo(0, "fetchChannel", message.id);
                        this.callbacks.set(message.id, clusterID);
                        break;
                    case "fetchMember":
                        this.fetchInfo(0, "fetchMember", [message.guildID, message.memberID]);
                        this.callbacks.set(message.memberID, clusterID);
                        break;
                    case "fetchReturn":
                        console.log(message);
                        let callback = this.callbacks.get(message.value.id);

                        let cluster = this.clusters.get(callback);

                        if (cluster) {
                            master.workers[cluster.workerID].send({ name: "fetchReturn", id: message.value.id, value: message.value });
                            this.callbacks.delete(message.value.id);
                        }
                        break;
                    case "broadcast":
                        this.broadcast(0, message.msg);
                        break;
                    case "send":
                        this.sendTo(message.cluster, message.msg)
                        break;
                    case "apiRequest":
                        let response;
                        let error;

                        let { method, url, auth, body, file, _route, short } = message;

                        if (file && file.file) file.file = Buffer.from(file.file, 'base64');

                        try {
                            response = await this.eris.requestHandler.request(method, url, auth, body, file, _route, short);
                        } catch (err) {
                            error = {
                                code: err.code,
                                message: err.message,
                                stack: err.stack
                            };
                        }

                        if (error) {
                            this.sendTo(clusterID, { _eventName: `apiResponse.${message.requestID}`, err: error })
                        } else {
                            this.sendTo(clusterID, { _eventName: `apiResponse.${message.requestID}`, data: response });
                        }

                        break;
                }
            }
        });

        master.on('disconnect', (worker) => {
            const clusterID = this.workers.get(worker.id);
            logger.warn("Cluster Manager", `cluster ${clusterID} disconnected`);
        });

        master.on('exit', (worker, code, signal) => {
            this.restartCluster(worker, code, signal);
        });

        this.queue.on("execute", item => {
            let cluster = this.clusters.get(item.item);

            if (cluster) {
                master.workers[cluster.workerID].send(item.value);
            }
        });
    }

    chunk(shards, clusterCount) {

        if (clusterCount < 2) return [shards];

        let len = shards.length;
        let out = [];
        let i = 0;
        let size;

        if (len % clusterCount === 0) {
            size = Math.floor(len / clusterCount);

            while (i < len) {
                out.push(shards.slice(i, i += size));
            }
        } else {
            while (i < len) {
                size = Math.ceil((len - i) / clusterCount--);
                out.push(shards.slice(i, i += size));
            }
        }

        return out;
    }

    connectShards() {
        for (let clusterID in [...Array(this.clusterCount).keys()]) {
            clusterID = parseInt(clusterID);

            let cluster = this.clusters.get(clusterID);

            if (!cluster.hasOwnProperty('firstShardID')) break;

            this.queue.queueItem({
                item: clusterID,
                value: {
                    id: clusterID,
                    clusterCount: this.clusterCount,
                    name: "connect",
                    firstShardID: cluster.firstShardID,
                    lastShardID: cluster.lastShardID,
                    maxShards: this.shardCount,
                    token: this.token,
                    file: this.mainFile,
                    clientOptions: this.clientOptions,
                }
            });
        }

        logger.info("Cluster Manager", `All shards spread`);

        if (this.stats) {
            this.startStats();
        }
    }

    /**
     *
     *
     * @param {any} type
     * @param {any} embed
     * @memberof ClusterManager
     */
    sendWebhook(type, embed) {
        if (!this.webhooks || !this.webhooks[type]) return;
        let id = this.webhooks[type].id;
        let token = this.webhooks[type].token;
        embed.timestamp = new Date();
        if (id && token) {
            this.eris.executeWebhook(id, token, { embeds: [embed] });
        }
    }

    printLogo() {
        const logo = require('asciiart-logo');
        console.log(
            logo({
                name: this.name,
                font: 'Big',
                lineChars: 15,
                padding: 5,
                margin: 2
            })
                .emptyLine()
                .right(`eris-sharder ${pkg.version}`)
                .emptyLine()
                .render()
        );
    }

    restartCluster(worker, code, signal) {
        const clusterID = this.workers.get(worker.id);

        logger.warn("Cluster Manager", `cluster ${clusterID} died`);

        let cluster = this.clusters.get(clusterID);

        let embed = {
            title: `Cluster ${clusterID} died with code ${code}. Restarting...`,
            description: `Shards ${cluster.firstShardID} - ${cluster.lastShardID}`
        }

        this.sendWebhook("cluster", embed);

        let shards = cluster.shardCount;

        let newWorker = master.fork();

        this.workers.delete(worker.id);

        this.clusters.set(clusterID, Object.assign(cluster, { workerID: newWorker.id }));

        this.workers.set(newWorker.id, clusterID);

        logger.debug("Cluster Manager", `Restarting cluster ${clusterID}`);

        this.queue.queueItem({
            item: clusterID, value: {
                id: clusterID,
                clusterCount: this.clusterCount,
                name: "connect",
                shards: shards,
                firstShardID: cluster.firstShardID,
                lastShardID: cluster.lastShardID,
                maxShards: this.shardCount,
                token: this.token,
                file: this.mainFile,
                clientOptions: this.clientOptions,
                test: this.test
            }
        });
    }

    async calculateShards() {
        let shards = this.shardCount;

        let result = await this.eris.getBotGateway();
        shards = result.shards;

        if (shards === 1) {
            return Promise.resolve(shards);
        } else {
            let guildCount = shards * 1000;
            let guildsPerShard = this.guildsPerShard;
            let shardsDecimal = guildCount / guildsPerShard;
            let finalShards = Math.ceil(shardsDecimal);
            return Promise.resolve(finalShards);
        }
    }

    fetchInfo(start, type, value) {
        let cluster = this.clusters.get(start);
        if (cluster) {
            master.workers[cluster.workerID].send({ name: type, value: value });
            this.fetchInfo(start + 1, type, value);
        }
    }

    broadcast(start, message) {
        let cluster = this.clusters.get(start);
        if (cluster) {
            master.workers[cluster.workerID].send(message);
            this.broadcast(start + 1, message);
        }
    }

    sendTo(cluster, message) {
        let worker = master.workers[this.clusters.get(cluster).workerID];
        if (worker) {
            worker.send(message);
        }
    }
}

module.exports = ClusterManager;
<|endoftext|>


<commit_before>/**
 * Created by rouven on 01.08.16.
 */

require(["common"], function(common) {
    require(["jquery", "socketio", "keyboard/settings"], function ($, io, settings) {

        //http://wowmotty.blogspot.de/2009/06/convert-jquery-rgb-output-to-hex-color.html
        function rgb2hex(orig){
            var rgb = orig.replace(/\s/g,'').match(/^rgba?\((\d+),(\d+),(\d+)/i);
            return (rgb && rgb.length === 4) ? "#" +
            ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
            ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) +
            ("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : orig;
        }

        //https://css-tricks.com/snippets/javascript/lighten-darken-color/
        function lightenDarkenColor(col, amt) {

            var usePound = false;

            if (col[0] == "#") {
                col = col.slice(1);
                usePound = true;
            }

            var num = parseInt(col,16);

            var r = (num >> 16) + amt;

            if (r > 255) r = 255;
            else if  (r < 0) r = 0;

            var b = ((num >> 8) & 0x00FF) + amt;

            if (b > 255) b = 255;
            else if  (b < 0) b = 0;

            var g = (num & 0x0000FF) + amt;

            if (g > 255) g = 255;
            else if (g < 0) g = 0;

            return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);

        }

        $.fn.redraw = function(){
            return $(this).each(function(){
                var redraw = this.offsetHeight;
            });
        };

        function showInput(str) {
            $('#inputOverlay').find('p').text(str).parent().addClass('active').redraw().removeClass('active');
        }

        function loadKeyboardLayout(layout, cb) {
            var fn = settings.ALL_KEYBOARDS[layout];
            if (fn == null) throw 'unknown layout: '+layout;
            fn = settings.KEYBOARDS_PATH+fn;
            var div = $('#keyboard-container');
            $.get(fn, function (data) {
                var svg = $(data.rootElement);
                svg.removeAttr('height').removeAttr('width').attr('id', 'keyboard');
                div.html('');
                div.append(svg);
                if (cb != null) cb();
            });

        }

        var clicked = [];

        function setKeyboardBindings(socket) {
            var idToColor = {};

            $("svg#keyboard > g > g").hover(function () {
                // hover in
                var path = $(this).find("> path:first-child");
                idToColor[path.attr('id')] = path.css('fill');
                //path.css('fill', lightenDarkenColor(rgb2hex(path.css('fill')), -10));
                if ($(this).attr("id") != "settings") {
                    path.css('fill', "rgb(215, 250, 255)");
                } else {
                    path.css('fill', "rgb(0, 125, 141)");
                }
            }, function () {
                // hover out
                var path = $(this).find("> path:first-child");
                //path.css('fill', lightenDarkenColor(rgb2hex(path.css('fill')), 10));
                path.css('fill', idToColor[path.attr("id")]);
            });
            // TODO: color change for click as well

            $("svg#keyboard > g > g#settings").click(function () {
                // open settings dialog
                $('#settings-modal').removeClass('closed');
            });

            // TODO: touch event support
            $("svg#keyboard > g > g:not(#settings)").on("mousedown", function () {
                var keyCode = parseInt($(this).attr('id'));
                console.info("Press", keyCode);
                socket.emit("boardEvent", {type: 0x01, code: keyCode, value: 1});
                if ($.inArray(keyCode, clicked) < 0) {
                    clicked.push(keyCode)
                }
            }).on("mouseleave mouseup", function () {
                var keyCode = parseInt($(this).attr('id'));
                var idx = $.inArray(keyCode, clicked);
                if (idx >= 0) {
                    console.info("Release", keyCode);
                    socket.emit("boardEvent", {type: 0x01, code: keyCode, value: 0});
                    clicked.splice(idx, 1);
                }
            });
        }

        function initDialog() {
            for (var i in settings.ALL_KEYBOARDS) {
                if (settings.keyboardLayout == i) {
                    $('#settings-layout').append(
                        '<option value="' + i + '" selected>' + i + '</option>'
                    );
                } else {
                    $('#settings-layout').append(
                        '<option value="' + i + '">' + i + '</option>'
                    );
                }
            }
            $('#settings-sticky').prop('checked', settings.stickyModKeys);
            $('#settings-physical').prop('checked', settings.physicalKeyboard);
        }

        function initSettings() {
            initDialog();
            $('#settings-form').submit(function (event) {
                var formData = {};
                $(this).find(':input').each(function (i, e) {
                    e = $(e);
                    var name = e.attr('name');
                    if (name == null) return;
                    var val;
                    if (e.attr('type') == 'checkbox') {
                        val = e.prop('checked');
                    } else {
                        val = e.val();
                    }
                    formData[name] = val;
                });
                settings.update(formData);
                $('#settings-modal').addClass('closed');
                event.preventDefault();
                event.stopPropagation();
            })
        }

        function init(cb) {
            loadKeyboardLayout(settings.keyboardLayout, cb);
            initSettings();
        }

        require(["lib/domReady"], function (domReady) {
            domReady(function () {
                var socket = io();

                init(function () {
                    $('.loader').hide();
                    socket.on("keyboardConnected", function(data) {
                        // var boardId = data.boardId;

                        setKeyboardBindings(socket);
                    });
                });

                socket.on("connect", function() {
                    socket.emit("connectKeyboard", null);
                });

                socket.on("disconnect", function() {
                    location.reload();
                });

                $("#keyboardInput").focus();

                $(".modal .close, .modal-wrapper").click(function (event) {
                    $(this).parents('.modal-wrapper').addBack('.modal-wrapper').addClass('closed');
                });
                $(".modal").click(function (event) {
                    event.stopPropagation();
                });

                $("window").on('keydown', function (e) {
                    $("#keyboardInput").keydown(e);
                });

                $("#keyboardInput").on('keydown', function (e) {
                    console.log(e.keyCode);
                    var keyCode = e.keyCode;
                    switch (keyCode) {
                        case 16:
                        case 17:
                        case 18:
                        case 20:
                        case 225:
                            return; // ignoring shift, ctrl, meta, alt, caps, alt gr
                    }
                    if (keyCode == 0 || keyCode == 229) {
                        // probably mobile keyboard
                        var v = $(this).val();
                        if (v.length > 0) {
                            var key = v[v.length-1];
                            $(this).val('')
                        }
                    } else {
                        var key = e.key;
                    }
                    var alt = e.altKey;
                    var altGr = e.keyModifierStateAltGraph;
                    var ctl = e.ctrlKey;
                    var shift = e.shiftKey;
                    var meta = e.metaKey;

                    var inputStr = [];
                    if (ctl) inputStr.push('Ctrl');
                    if (meta) inputStr.push('Meta');
                    if (alt) inputStr.push('Alt');
                    inputStr.push(key);
                    showInput(inputStr.join('+')+' ('+keyCode+')');
                    return false;
                });
            });
        });
    });
});
<commit_msg>Support touch events<commit_after>/**
 * Created by rouven on 01.08.16.
 */

require(["common"], function(common) {
    require(["jquery", "socketio", "keyboard/settings"], function ($, io, settings) {

        //http://wowmotty.blogspot.de/2009/06/convert-jquery-rgb-output-to-hex-color.html
        function rgb2hex(orig){
            var rgb = orig.replace(/\s/g,'').match(/^rgba?\((\d+),(\d+),(\d+)/i);
            return (rgb && rgb.length === 4) ? "#" +
            ("0" + parseInt(rgb[1],10).toString(16)).slice(-2) +
            ("0" + parseInt(rgb[2],10).toString(16)).slice(-2) +
            ("0" + parseInt(rgb[3],10).toString(16)).slice(-2) : orig;
        }

        //https://css-tricks.com/snippets/javascript/lighten-darken-color/
        function lightenDarkenColor(col, amt) {

            var usePound = false;

            if (col[0] == "#") {
                col = col.slice(1);
                usePound = true;
            }

            var num = parseInt(col,16);

            var r = (num >> 16) + amt;

            if (r > 255) r = 255;
            else if  (r < 0) r = 0;

            var b = ((num >> 8) & 0x00FF) + amt;

            if (b > 255) b = 255;
            else if  (b < 0) b = 0;

            var g = (num & 0x0000FF) + amt;

            if (g > 255) g = 255;
            else if (g < 0) g = 0;

            return (usePound?"#":"") + (g | (b << 8) | (r << 16)).toString(16);

        }

        $.fn.redraw = function(){
            return $(this).each(function(){
                var redraw = this.offsetHeight;
            });
        };

        function showInput(str) {
            $('#inputOverlay').find('p').text(str).parent().addClass('active').redraw().removeClass('active');
        }

        function loadKeyboardLayout(layout, cb) {
            var fn = settings.ALL_KEYBOARDS[layout];
            if (fn == null) throw 'unknown layout: '+layout;
            fn = settings.KEYBOARDS_PATH+fn;
            var div = $('#keyboard-container');
            $.get(fn, function (data) {
                var svg = $(data.rootElement);
                svg.removeAttr('height').removeAttr('width').attr('id', 'keyboard');
                div.html('');
                div.append(svg);
                if (cb != null) cb();
            });

        }

        var clicked = [];

        function setKeyboardBindings(socket) {
            var idToColor = {};

            $("svg#keyboard > g > g").hover(function () {
                // hover in
                var path = $(this).find("> path:first-child");
                idToColor[path.attr('id')] = path.css('fill');
                //path.css('fill', lightenDarkenColor(rgb2hex(path.css('fill')), -10));
                if ($(this).attr("id") != "settings") {
                    path.css('fill', "rgb(215, 250, 255)");
                } else {
                    path.css('fill', "rgb(0, 125, 141)");
                }
            }, function () {
                // hover out
                var path = $(this).find("> path:first-child");
                //path.css('fill', lightenDarkenColor(rgb2hex(path.css('fill')), 10));
                path.css('fill', idToColor[path.attr("id")]);
            });
            // TODO: color change for click as well

            $("svg#keyboard > g > g#settings").click(function () {
                // open settings dialog
                $('#settings-modal').removeClass('closed');
            });

            $("svg#keyboard > g > g:not(#settings)").on("mousedown touchstart", function (event) {
                event.preventDefault();
                var keyCode = parseInt($(this).attr('id'));
                console.info("Press", keyCode);
                socket.emit("boardEvent", {type: 0x01, code: keyCode, value: 1});
                if ($.inArray(keyCode, clicked) < 0) {
                    clicked.push(keyCode)
                }
            }).on("mouseleave mouseup touchend", function (event) {
                event.preventDefault();
                var keyCode = parseInt($(this).attr('id'));
                var idx = $.inArray(keyCode, clicked);
                if (idx >= 0) {
                    console.info("Release", keyCode);
                    socket.emit("boardEvent", {type: 0x01, code: keyCode, value: 0});
                    clicked.splice(idx, 1);
                }
            });
        }

        function initDialog() {
            for (var i in settings.ALL_KEYBOARDS) {
                if (settings.keyboardLayout == i) {
                    $('#settings-layout').append(
                        '<option value="' + i + '" selected>' + i + '</option>'
                    );
                } else {
                    $('#settings-layout').append(
                        '<option value="' + i + '">' + i + '</option>'
                    );
                }
            }
            $('#settings-sticky').prop('checked', settings.stickyModKeys);
            $('#settings-physical').prop('checked', settings.physicalKeyboard);
        }

        function initSettings() {
            initDialog();
            $('#settings-form').submit(function (event) {
                var formData = {};
                $(this).find(':input').each(function (i, e) {
                    e = $(e);
                    var name = e.attr('name');
                    if (name == null) return;
                    var val;
                    if (e.attr('type') == 'checkbox') {
                        val = e.prop('checked');
                    } else {
                        val = e.val();
                    }
                    formData[name] = val;
                });
                settings.update(formData);
                $('#settings-modal').addClass('closed');
                event.preventDefault();
                event.stopPropagation();
            })
        }

        function init(cb) {
            loadKeyboardLayout(settings.keyboardLayout, cb);
            initSettings();
        }

        require(["lib/domReady"], function (domReady) {
            domReady(function () {
                var socket = io();

                init(function () {
                    $('.loader').hide();
                    socket.on("keyboardConnected", function(data) {
                        // var boardId = data.boardId;

                        setKeyboardBindings(socket);
                    });
                });

                socket.on("connect", function() {
                    socket.emit("connectKeyboard", null);
                });

                socket.on("disconnect", function() {
                    location.reload();
                });

                $("#keyboardInput").focus();

                $(".modal .close, .modal-wrapper").click(function (event) {
                    $(this).parents('.modal-wrapper').addBack('.modal-wrapper').addClass('closed');
                });
                $(".modal").click(function (event) {
                    event.stopPropagation();
                });

                $("window").on('keydown', function (e) {
                    $("#keyboardInput").keydown(e);
                });

                $("#keyboardInput").on('keydown', function (e) {
                    console.log(e.keyCode);
                    var keyCode = e.keyCode;
                    switch (keyCode) {
                        case 16:
                        case 17:
                        case 18:
                        case 20:
                        case 225:
                            return; // ignoring shift, ctrl, meta, alt, caps, alt gr
                    }
                    if (keyCode == 0 || keyCode == 229) {
                        // probably mobile keyboard
                        var v = $(this).val();
                        if (v.length > 0) {
                            var key = v[v.length-1];
                            $(this).val('')
                        }
                    } else {
                        var key = e.key;
                    }
                    var alt = e.altKey;
                    var altGr = e.keyModifierStateAltGraph;
                    var ctl = e.ctrlKey;
                    var shift = e.shiftKey;
                    var meta = e.metaKey;

                    var inputStr = [];
                    if (ctl) inputStr.push('Ctrl');
                    if (meta) inputStr.push('Meta');
                    if (alt) inputStr.push('Alt');
                    inputStr.push(key);
                    showInput(inputStr.join('+')+' ('+keyCode+')');
                    return false;
                });
            });
        });
    });
});
<|endoftext|>


<commit_before>"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

var PriorityQueue = function () {
  function PriorityQueue() {
    _classCallCheck(this, PriorityQueue);

    this.data = [];
<<<<<<< HEAD
    this.head = 0;
=======
    this._highestPriority = Infinity;
    this._lowestPriority = 0;
>>>>>>> origin
  }

  _createClass(PriorityQueue, [{
    key: "enqueue",
    value: function enqueue(element) {
<<<<<<< HEAD
      this.data[this.head] = element;
      this.head++;
=======
      this.data[this.data.length] = element;
      if (element.priority > this._lowestPriority) {
        this._lowestPriority = element.priority;
      }
>>>>>>> origin
    }
  }, {
    key: "dequeue",
    value: function dequeue() {
<<<<<<< HEAD
      return this.head > 0 ? this.data.shift() : null;
=======
      if (!this.data.length) {
        return null;
      }
      var index = void 0;
      for (var i = 0; i < this.data.length; i++) {
        if (this.data[i].priority < this._highestPriority) {
          this._highestPriority = this.data[i].priority;
          index = i;
        }
      }
      return this.data.splice(index, 1);
>>>>>>> origin
    }
  }, {
    key: "front",
    value: function front() {
<<<<<<< HEAD
      return this.head > 0 ? this.data[0] : null;
=======
      if (!this.data.length) {
        return null;
      }
      var index = void 0;
      for (var i = 0; i < this.data.length; i++) {
        if (this.data[i].priority < this._highestPriority) {
          this._highestPriority = this.data[i].priority;
          index = i;
        }
      }
      return this.data[index];
>>>>>>> origin
    }
  }, {
    key: "back",
    value: function back() {
<<<<<<< HEAD
      return this.head > 0 ? this.data[this.head - 1] : null;
=======
      if (!this.data.length) {
        return null;
      }
      var index = void 0;
      for (var i = 0; i < this.data.length; i++) {
        if (this.data[i].priority >= this._lowestPriority) {
          this._lowestPriority = this.data[i].priority;
          index = i;
        }
      }
      return this.data[index];
>>>>>>> origin
    }
  }, {
    key: "isEmpty",
    value: function isEmpty() {
<<<<<<< HEAD
      return this.head === 0;
=======
      return this.data.length === 0;
>>>>>>> origin
    }
  }, {
    key: "length",
    value: function length() {
<<<<<<< HEAD
      return this.head > 0 ? this.head : null;
=======
      return this.data.length;
>>>>>>> origin
    }
  }]);

  return PriorityQueue;
}();

<<<<<<< HEAD
// const queue = new Queue()

// console.log(queue.dequeue())

=======
>>>>>>> origin
exports.default = PriorityQueue;<commit_msg>Delete PriorityQueue.js<commit_after><|endoftext|>


<commit_before>import React from 'react'
import Head from 'next/head';
import TopBar from './TopBar';

import { truncate, getQueryParams } from '../lib/utils';
import storage from '../lib/storage';

class Header extends React.Component {

  constructor(props) {
    super(props);
    const { description, image, twitterHandle } = props;
    const meta = {
      'twitter:site': 'opencollect',
      'twitter:creator': twitterHandle,
      'fb:app_id': '266835577107099',
      'og:image': image,
      'description': truncate(description, 256)
    };

    this.meta = [];
    for (const name in meta) {
      this.meta.push({
        name,
        content: meta[name]
      })
    }
  }

  componentDidMount() {
    const urlParams = getQueryParams();
    if (urlParams.referral) {
      storage.set('referral', urlParams.referral, 48 * 60 * 60 * 1000); // we keep the referral for 48h or until we receive a new ?referral=
    }
    if (urlParams.matchingFund) {
      storage.set('matchingFund', urlParams.matchingFund, 1 * 60 * 60 * 1000); // we keep the matchingFund for 1h or until we receive a new ?matchingFund=
    }
  }

  render() {
    const { className } = this.props;
    let title = this.props.title || "Open Collective - open your finances to your community";
    if (!title.match(/open collective/i)) {
      title += ` - Open Collective`;
    }
    return (
    <header>

      <Head>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta property="og:logo" content="/static/images/opencollectiveicon240x240" size="240x240" />
        <meta property="og:logo" content="/static/images/opencollectiveicon48x48" size="48x48" />
        <meta property="og:logo" content="/static/images/opencollectivelogo480x80" size="480x80" />
        <meta property="og:logo" content="/static/images/opencollectivelogo480x80@2x" size="960x160" />

        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" />
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/latest/css/bootstrap.min.css" />
        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700,900|Rubik" />
        <title>{title}</title>
        { this.meta.map(({name, content}, index) => <meta property={name} content={content} key={`meta-${index}`} />) }
      </Head>

      <style jsx global>{`
      @font-face {
        font-family: 'montserratlight';
        src: url('/static/fonts/montserrat/montserrat-light-webfont.eot');
        src: url('/static/fonts/montserrat/montserrat-light-webfont.eot?#iefix') format('embedded-opentype'),
          url('/static/fonts/montserrat/montserrat-light-webfont.woff2') format('woff2'),
          url('/static/fonts/montserrat/montserrat-light-webfont.woff') format('woff'),
          url('/static/fonts/montserrat/montserrat-light-webfont.ttf') format('truetype'),
          url('/static/fonts/montserrat/montserrat-light-webfont.svg#montserratlight') format('svg');
        font-weight: normal;
        font-style: normal;
      }
      @font-face {
        font-family: 'lato';
        src: url('/static/fonts/montserrat/lato-regular.ttf') format('truetype');
        font-weight: normal;
        font-style: normal;
      }

      body.showModal {
        overflow: hidden;
      }
      body.showModal .EventPage {
        filter: blur(3px); background: rgba(0,0,0,0.6);
      }

      body > div:first-child {
        position: relative;
        min-height: 100%;
      }

      @media(max-width: 600px) {
        html {
          font-size: 55%;
        }
      }

      #root {
        height: 100%;
      }

      .EventPage {
        position: relative;
        height: 100%;
      }

      @media(max-width: 600px) {
        .showModal .EventPage {
          display: none;
        }
      }

      section {
        margin: 3rem 0px;
        overflow: hidden;
      }

      h1, h2, h3, h4 {
        font-family: 'lato','montserratlight';
      }

      h1 {
        text-align: center;
        margin: 40px 0px 20px;
        font-size: 1.8rem;
        font-weight: bold;
      }

      .getTicketForm {
        margin: 20px auto;
        max-width: 400px;
      }

      .map {
        border: 1px solid #eee;
        height: 300px;
        position: relative;
      }

      .map-overlay {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0,0,0,0);
      }

      .row {
        display: flex;
        flex-direction: row;
      }

      @media(max-width: 600px) {
        .desktopOnly {
          display: none !important;
        }
      }
      #media(max-width: 400px) {
        .mediumScreenOnly {
          display: none !important;
        }
      }

      `}
      </style>
      <TopBar className={className} LoggedInUser={this.props.LoggedInUser} />
    </header>
    );
  }
}

export default Header;
<commit_msg>fix react-bootstrap<commit_after>import React from 'react'
import Head from 'next/head';
import TopBar from './TopBar';

import { truncate, getQueryParams } from '../lib/utils';
import storage from '../lib/storage';

class Header extends React.Component {

  constructor(props) {
    super(props);
    const { description, image, twitterHandle } = props;
    const meta = {
      'twitter:site': 'opencollect',
      'twitter:creator': twitterHandle,
      'fb:app_id': '266835577107099',
      'og:image': image,
      'description': truncate(description, 256)
    };

    this.meta = [];
    for (const name in meta) {
      this.meta.push({
        name,
        content: meta[name]
      })
    }
  }

  componentDidMount() {
    const urlParams = getQueryParams();
    if (urlParams.referral) {
      storage.set('referral', urlParams.referral, 48 * 60 * 60 * 1000); // we keep the referral for 48h or until we receive a new ?referral=
    }
    if (urlParams.matchingFund) {
      storage.set('matchingFund', urlParams.matchingFund, 1 * 60 * 60 * 1000); // we keep the matchingFund for 1h or until we receive a new ?matchingFund=
    }
  }

  render() {
    const { className } = this.props;
    let title = this.props.title || "Open Collective - open your finances to your community";
    if (!title.match(/open collective/i)) {
      title += ` - Open Collective`;
    }
    return (
    <header>

      <Head>
        <meta name="viewport" content="width=device-width, initial-scale=1" />
        <meta property="og:logo" content="/static/images/opencollectiveicon240x240" size="240x240" />
        <meta property="og:logo" content="/static/images/opencollectiveicon48x48" size="48x48" />
        <meta property="og:logo" content="/static/images/opencollectivelogo480x80" size="480x80" />
        <meta property="og:logo" content="/static/images/opencollectivelogo480x80@2x" size="960x160" />

        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/latest/css/font-awesome.min.css" />
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" />
        <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lato:400,700,900|Rubik" />
        <title>{title}</title>
        { this.meta.map(({name, content}, index) => <meta property={name} content={content} key={`meta-${index}`} />) }
      </Head>

      <style jsx global>{`
      @font-face {
        font-family: 'montserratlight';
        src: url('/static/fonts/montserrat/montserrat-light-webfont.eot');
        src: url('/static/fonts/montserrat/montserrat-light-webfont.eot?#iefix') format('embedded-opentype'),
          url('/static/fonts/montserrat/montserrat-light-webfont.woff2') format('woff2'),
          url('/static/fonts/montserrat/montserrat-light-webfont.woff') format('woff'),
          url('/static/fonts/montserrat/montserrat-light-webfont.ttf') format('truetype'),
          url('/static/fonts/montserrat/montserrat-light-webfont.svg#montserratlight') format('svg');
        font-weight: normal;
        font-style: normal;
      }
      @font-face {
        font-family: 'lato';
        src: url('/static/fonts/montserrat/lato-regular.ttf') format('truetype');
        font-weight: normal;
        font-style: normal;
      }

      body.showModal {
        overflow: hidden;
      }
      body.showModal .EventPage {
        filter: blur(3px); background: rgba(0,0,0,0.6);
      }

      body > div:first-child {
        position: relative;
        min-height: 100%;
      }

      @media(max-width: 600px) {
        html {
          font-size: 55%;
        }
      }

      #root {
        height: 100%;
      }

      .EventPage {
        position: relative;
        height: 100%;
      }

      @media(max-width: 600px) {
        .showModal .EventPage {
          display: none;
        }
      }

      section {
        margin: 3rem 0px;
        overflow: hidden;
      }

      h1, h2, h3, h4 {
        font-family: 'lato','montserratlight';
      }

      h1 {
        text-align: center;
        margin: 40px 0px 20px;
        font-size: 1.8rem;
        font-weight: bold;
      }

      .getTicketForm {
        margin: 20px auto;
        max-width: 400px;
      }

      .map {
        border: 1px solid #eee;
        height: 300px;
        position: relative;
      }

      .map-overlay {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        background: rgba(0,0,0,0);
      }

      .row {
        display: flex;
        flex-direction: row;
      }

      @media(max-width: 600px) {
        .desktopOnly {
          display: none !important;
        }
      }
      #media(max-width: 400px) {
        .mediumScreenOnly {
          display: none !important;
        }
      }

      `}
      </style>
      <TopBar className={className} LoggedInUser={this.props.LoggedInUser} />
    </header>
    );
  }
}

export default Header;
<|endoftext|>


<commit_before>// WebTorrent Desktop server API
// - Tell auto-updaters the latest version
// - Log crash reports
// - Log telemetry
module.exports = { serve }

const bodyParser = require('body-parser')
const config = require('../config')
const fs = require('fs')
const multer = require('multer')
const path = require('path')
const semver = require('semver')
const url = require('url')

var APP_VERSION = require('webtorrent-desktop/package.json').version
var RELEASE_PATH = 'https://github.com/feross/webtorrent-desktop/releases/download'

function serve (app) {
  serveTelemetryAPI(app)
  serveCrashReportsAPI(app)
  serveAnnouncementsAPI(app)
  serveUpdateAPI(app)
}

// Log telemetry JSON summaries to a file, one per line
function serveTelemetryAPI (app) {
  app.post('/desktop/telemetry', bodyParser.json(), function (req, res) {
    console.log('Saving telemetry from ' + req.ip)

    var summary = req.body
    summary.ip = req.ip
    var summaryJSON = JSON.stringify(req.body)

    var today = new Date().toISOString().substring(0, 10) // YYYY-MM-DD
    var telemetryPath = path.join(config.logPath, 'telemetry', today + '.log')

    fs.appendFile(telemetryPath, summaryJSON + '\n', function (err) {
      if (err) {
        console.error('Error saving telemetry', err)
        res.status(500)
      }
      res.end()
    })
  })
}

// Save electron process crash reports (from Crashpad), each in its own file
function serveCrashReportsAPI (app) {
  var crashReportsPath = path.join(config.logPath, 'crash-reports')
  var upload = multer({ dest: crashReportsPath }).single('upload_file_minidump')

  app.post('/desktop/crash-report', upload, function (req, res) {
    req.body.filename = req.file.filename
    var crashLog = JSON.stringify(req.body, undefined, 2)

    fs.writeFile(req.file.path + '.json', crashLog, function (err) {
      if (err) return console.error('Error saving crash report: ' + err.message)
      console.log('Saved crash report:\n\t' + crashLog)
    })

    res.end()
  })
}

// This lets us send a message to all WebTorrent Desktop users
function serveAnnouncementsAPI (app) {
  app.get('/desktop/announcement', function (req, res) {
    res.status(204).end()
  })
}

// Tell the auto updaters when new version is available
function serveUpdateAPI (app) {
  // Deprecated: WebTorrent Desktop v0.0.0 - 0.2.0 use this update URL
  app.get('/app/update/?*', function (req, res) {
    res.redirect(301, req.url.replace('/app/', '/desktop/'))
  })

  // WebTorrent Desktop OS X auto-update endpoint
  app.get('/desktop/update', function (req, res) {
    var version = req.query.version
    logUpdateCheck({
      date: (new Date()).toString(),
      platform: req.query.platform,
      version: version,
      ip: req.ip
    })
    if (!semver.valid(version) || semver.lt(version, APP_VERSION)) {
      // Update is required. Send update JSON.
      // Response format docs: https://github.com/Squirrel/Squirrel.Mac#update-json-format
      res.status(200).send({
        name: 'WebTorrent v' + APP_VERSION,
        url: `${RELEASE_PATH}/v${APP_VERSION}/WebTorrent-v${APP_VERSION}-darwin.zip`,
        version: APP_VERSION
      })
    } else {
      // No update required. User is on latest app version.
      res.status(204).end()
    }
  })

  // WebTorrent Desktop Windows auto-update endpoint
  app.get('/desktop/update/*', function (req, res) {
    var pathname = url.parse(req.url).pathname
    var file = pathname.replace(/^\/desktop\/update\//i, '')
    var fileVersion
    if (file === 'RELEASES') {
      fileVersion = APP_VERSION
      logUpdateCheck({
        date: (new Date()).toString(),
        platform: req.query.platform,
        version: req.query.version,
        ip: req.ip
      })
    } else {
      var match = /-(\d+\.\d+\.\d+)-/.exec(file)
      fileVersion = match && match[1]
    }
    if (!fileVersion) {
      return res.status(404).end()
    }
    var redirectURL = `${RELEASE_PATH}/v${fileVersion}/${file}`
    res.redirect(302, redirectURL)
  })
}

function logUpdateCheck (log) {
  console.log('UPDATE CHECK: ' + JSON.stringify(log))
}

<commit_msg>Fix logging bug<commit_after>// WebTorrent Desktop server API
// - Tell auto-updaters the latest version
// - Log crash reports
// - Log telemetry
module.exports = { serve }

const bodyParser = require('body-parser')
const config = require('../config')
const fs = require('fs')
const multer = require('multer')
const path = require('path')
const semver = require('semver')
const url = require('url')

var APP_VERSION = require('webtorrent-desktop/package.json').version
var RELEASE_PATH = 'https://github.com/feross/webtorrent-desktop/releases/download'

function serve (app) {
  serveTelemetryAPI(app)
  serveCrashReportsAPI(app)
  serveAnnouncementsAPI(app)
  serveUpdateAPI(app)
}

// Log telemetry JSON summaries to a file, one per line
function serveTelemetryAPI (app) {
  app.post('/desktop/telemetry', bodyParser.json(), function (req, res) {
    console.log('Saving telemetry from ' + req.ip)

    var summary = req.body
    summary.ip = req.ip
    var summaryJSON = JSON.stringify(summary)

    var today = new Date().toISOString().substring(0, 10) // YYYY-MM-DD
    var telemetryPath = path.join(config.logPath, 'telemetry', today + '.log')

    fs.appendFile(telemetryPath, summaryJSON + '\n', function (err) {
      if (err) {
        console.error('Error saving telemetry', err)
        res.status(500)
      }
      res.end()
    })
  })
}

// Save electron process crash reports (from Crashpad), each in its own file
function serveCrashReportsAPI (app) {
  var crashReportsPath = path.join(config.logPath, 'crash-reports')
  var upload = multer({ dest: crashReportsPath }).single('upload_file_minidump')

  app.post('/desktop/crash-report', upload, function (req, res) {
    req.body.filename = req.file.filename
    var crashLog = JSON.stringify(req.body, undefined, 2)

    fs.writeFile(req.file.path + '.json', crashLog, function (err) {
      if (err) return console.error('Error saving crash report: ' + err.message)
      console.log('Saved crash report:\n\t' + crashLog)
    })

    res.end()
  })
}

// This lets us send a message to all WebTorrent Desktop users
function serveAnnouncementsAPI (app) {
  app.get('/desktop/announcement', function (req, res) {
    res.status(204).end()
  })
}

// Tell the auto updaters when new version is available
function serveUpdateAPI (app) {
  // Deprecated: WebTorrent Desktop v0.0.0 - 0.2.0 use this update URL
  app.get('/app/update/?*', function (req, res) {
    res.redirect(301, req.url.replace('/app/', '/desktop/'))
  })

  // WebTorrent Desktop OS X auto-update endpoint
  app.get('/desktop/update', function (req, res) {
    var version = req.query.version
    logUpdateCheck({
      date: (new Date()).toString(),
      platform: req.query.platform,
      version: version,
      ip: req.ip
    })
    if (!semver.valid(version) || semver.lt(version, APP_VERSION)) {
      // Update is required. Send update JSON.
      // Response format docs: https://github.com/Squirrel/Squirrel.Mac#update-json-format
      res.status(200).send({
        name: 'WebTorrent v' + APP_VERSION,
        url: `${RELEASE_PATH}/v${APP_VERSION}/WebTorrent-v${APP_VERSION}-darwin.zip`,
        version: APP_VERSION
      })
    } else {
      // No update required. User is on latest app version.
      res.status(204).end()
    }
  })

  // WebTorrent Desktop Windows auto-update endpoint
  app.get('/desktop/update/*', function (req, res) {
    var pathname = url.parse(req.url).pathname
    var file = pathname.replace(/^\/desktop\/update\//i, '')
    var fileVersion
    if (file === 'RELEASES') {
      fileVersion = APP_VERSION
      logUpdateCheck({
        date: (new Date()).toString(),
        platform: req.query.platform,
        version: req.query.version,
        ip: req.ip
      })
    } else {
      var match = /-(\d+\.\d+\.\d+)-/.exec(file)
      fileVersion = match && match[1]
    }
    if (!fileVersion) {
      return res.status(404).end()
    }
    var redirectURL = `${RELEASE_PATH}/v${fileVersion}/${file}`
    res.redirect(302, redirectURL)
  })
}

function logUpdateCheck (log) {
  console.log('UPDATE CHECK: ' + JSON.stringify(log))
}

<|endoftext|>