<commit_before>var config = require(process.env.HOME + "/.jsiidConfig.js");
console.log("read configuration:");
console.log(config);

var net = require("net");

var createListener = function() {
    var listener = net.createServer(function (socket) {
        socket.on('data', function(data) {
            console.log('got data:' + data);
        });
    });

    listener.listen(config.listenPort, config.listenAddr);
};

var handleLine = function(line, server) {
    var tokens = line.split(' ');

    if (line === "")
        return;

    console.log(server.name + ': ' + line);

    if(tokens[0] === "PING") {
        console.log('got PING, sending PONG to ' + tokens[1].substr(1));
        client.send("PONG " + tokens[1].substr(1));
    } else if (tokens[0][0] === ":") {
        var prefix = tokens[0].substr(1);
        var nick = prefix.substr(0, prefix.indexOf('!'));
        var cmd = tokens[1];
        var chan = tokens[2];

        if(prefix === server.serverName) {
            tokens.shift(); tokens.shift(); tokens.shift();
            console.log("Server msg: " + tokens.join(' '));
        } else if(cmd === "PRIVMSG") {
            tokens.shift(); tokens.shift(); tokens.shift();
            var msg = tokens.join(' ').substr(1);

            console.log("PRIVMSG " + chan + ': ' + nick + ': ' + msg);
        } else if (cmd === "JOIN") {
            console.log("JOIN " + chan + ': ' + nick);
        } else if (cmd === "PART") {
            console.log("PART " + chan + ': ' + nick);
        } else if (cmd === "001") {
            server.serverName = prefix;
            console.log("serverName changed to " + server.serverName);
        } else {
            console.log("got unknown msg from " + nick + ": " + line);
        }
    } else {
        console.log("got unknown msg on " + server.name + ": " + line);
    }
};

var ircConnect = function(server) {
    var buffer = "";

    var client = net.connect({
        "port": server.port,
        "host": server.address
    }, function() {
        console.log('connected to irc server');

        var passString = "";
        if(server.password)
            passString = "PASS " + server.password + "\r\n";

        client.write(passString +
                     "NICK " + (server.nick || config.nick) + "\r\n" +
                     "USER " + (server.nick || config.nick) + " " +
                     "localhost " + server.address + " :" +
                     (server.nick || config.nick) + "\r\n");

    });

    client.send = function(data) {
        console.log("sending data: " + data);
        client.write(data);
    };

    client.on('data', function(data) {
        buffer += data.toString('utf8');
        var lastNL = buffer.lastIndexOf('\n');

        // have we received at least one whole line? else wait for more data
        if(lastNL !== -1) {
            var recvdLines = buffer.substr(0, lastNL + 1).split('\r\n');
            buffer = buffer.substr(lastNL + 1);

            for(var i = 0; i < recvdLines.length; i++) {
                handleLine(recvdLines[i], server);
            }
        }
    });
    client.on('end', function() {
        console.log('disconnected from irc');
    });
};

createListener();

for(var i = 0; i < config.servers.length; i++)
    ircConnect(config.servers[i]);
<commit_msg>send all messages through recvdIrcMsg/sendIrcMsg<commit_after>var config = require(process.env.HOME + "/.jsiidConfig.js");
console.log("read configuration:");
console.log(config);

var net = require("net");

var createListener = function() {
    var listener = net.createServer(function (socket) {
        socket.on('data', function(data) {
            console.log('got data:' + data);
        });
    });

    listener.listen(config.listenPort, config.listenAddr);
};

var recvdIrcMsg = function(serverName, cmd, chan, nick, msg) {
    console.log("recvdIrcMsg(" + serverName + ", " + cmd + ", " + chan + ", " + nick + ", " + msg + ")");
};

var sendIrcMsg = function(serverName, cmd, chan, nick, msg) {
};

var chans = {};
var servers = {};

var handleIrcLine = function(line, server, ircServer) {
    var tokens = line.split(' ');

    if (line === "")
        return;

    //console.log(server.name + ': ' + line);
    if(tokens[0] === "PING") {
        console.log('got PING, sending PONG to ' + tokens[1].substr(1));
        ircServer.send("PONG " + tokens[1].substr(1));
    } else if (tokens[0][0] === ":") {
        var prefix = tokens[0].substr(1);
        var nick = prefix.substr(0, prefix.indexOf('!'));
        var cmd = tokens[1];
        var chan = tokens[2];

        if(prefix === server.serverLongName) {
            tokens.shift(); tokens.shift(); tokens.shift();
            recvdIrcMsg(server.name, "message", server.name, server.name, tokens.join(' '));
        } else if(cmd === "PRIVMSG") {
            tokens.shift(); tokens.shift(); tokens.shift();
            var msg = tokens.join(' ').substr(1);

            recvdIrcMsg(server.name, "message", chan, nick, msg);
        } else if (cmd === "JOIN") {
            recvdIrcMsg(server.name, "join", chan, nick, null);
        } else if (cmd === "PART") {
            recvdIrcMsg(server.name, "part", chan, nick, null);
        } else if (cmd === "001") {
            server.serverLongName = prefix;
            console.log("serverLongName changed to " + server.serverLongName);
        } else {
            console.log("got unknown msg from " + nick + ": " + line);
        }
    } else {
        console.log("got unknown msg on " + server.name + ": " + line);
    }
};

var ircConnect = function(serverConfig) {
    var buffer = "";

    var ircServer = net.connect({
        "port": serverConfig.port,
        "host": serverConfig.address
    }, function() {
        console.log('connected to irc server');

        var passString = "";
        if(serverConfig.password)
            passString = "PASS " + serverConfig.password + "\r\n";

        ircServer.write(passString +
                     "NICK " + (serverConfig.nick || config.nick) + "\r\n" +
                     "USER " + (serverConfig.nick || config.nick) + " " +
                     "localhost " + serverConfig.address + " :" +
                     (serverConfig.nick || config.nick) + "\r\n");

    });

    ircServer.send = function(data) {
        console.log("sending data: " + data);
        ircServer.write(data);
    };

    ircServer.on('data', function(data) {
        buffer += data.toString('utf8');
        var lastNL = buffer.lastIndexOf('\n');

        // have we received at least one whole line? else wait for more data
        if(lastNL !== -1) {
            var recvdLines = buffer.substr(0, lastNL + 1).split('\r\n');
            buffer = buffer.substr(lastNL + 1);

            for(var i = 0; i < recvdLines.length; i++) {
                handleIrcLine(recvdLines[i], serverConfig, ircServer);
            }
        }
    });
    ircServer.on('end', function() {
        console.log('disconnected from irc');
    });

    ircServer.config = serverConfig;

    ircServers[server.name] = ircServer;
};

createListener();

for(var i = 0; i < config.servers.length; i++)
    ircConnect(config.servers[i]);
<|endoftext|>


<commit_before>;(function(global) {       // IIFE for legacy non-module usage
'use strict'

var tagNameRegex = /^([a-z1-6]+)(?:\:([a-z]+))?/    // matches 'input' or 'input:text'
var propsRegex = /((?:#|\.|@)[\w-]+)|(\[.*?\])/g    // matches all further properties
var attrRegex = /\[([\w-]+)(?:=([^\]]+))?\]/        // matches '[foo=bar]' or '[foo]'

// Error subclass to throw for parsing errors
function ParseError(input) {
    this.message = input
    this.stack = new Error().stack
}
ParseError.prototype = Object.create(Error.prototype)
ParseError.prototype.name = 'JSnoXParseError'

// A simple module-level cache for parseTagSpec().
// Subsequent re-parsing of the same input string will be pulled
// from this cache for an increase in performance.
var specCache = {}

// Convert a tag specification string into an object
// eg. 'input:checkbox#foo.bar[name=asdf]' produces the output:
// {
//   tagName: 'input',
//   props: {
//     type: 'checkbox',
//     id: 'foo',
//     className: 'bar',
//     name: 'asdf'
//   }
// }
function parseTagSpec(specString) {
    if (!specString || !specString.match) throw new ParseError(specString)
    if (specCache[specString]) return specCache[specString]

    // Parse tagName, and optional type attribute
    var tagMatch = specString.match(tagNameRegex)
    if (!tagMatch) throw new ParseError(specString)

    // Provide the specString as a default key, which can always be overridden
    // by the props hash (for when two siblings have the same specString)
    var tagName = tagMatch[1]
    var props = { key: specString }
    var classes = []
    if (tagMatch[2]) props.type = tagMatch[2]
    else if (tagName === 'button') props.type = 'button' // Saner default for <button>

    var matches = specString.match(propsRegex)
    matches && matches.forEach(function getRegexMatches(str) {
        if (!str) return
        else if (str[0] === '#') props.id = str.slice(1)
        else if (str[0] === '@') props.ref = str.slice(1)
        else if (str[0] === '.') classes.push(str.slice(1))
        else if (str[0] === '[') {
            var match = str.match(attrRegex)
            if (match) props[match[1]] = match[2] || true    // If no attr value given, use true
        }
    })
    if (classes.length) props.className = classes.join(' ')

    var spec = {
        tagName: tagName,
        props: props
    }

    specCache[specString] = spec
    return spec
}

// Merge two objects, producing a new object with their properties
//
// Note:
// * the className property is treated as a special case and is merged
// * arguments are assumed to be object literals, which is why there are
//   no hasOwnProperty() checks (see af/JSnoX/issues/3)
function extend(obj1, obj2) {
    var output = {}
    obj1 = obj1 || {}
    obj2 = obj2 || {}

    for (var k in obj1) output[k] = obj1[k]
    for (var l in obj2) output[l] = obj2[l]

    // className is a special case: we want to return the combination
    // of strings if both objects contain className
    var combinedClass = (typeof obj1.className === 'string') &&
                        (typeof obj2.className === 'string') &&
                        [obj1.className, obj2.className].join(' ')
    output.className = combinedClass || obj1.className || obj2.className

    return output
}

// Main exported function.
// Returns a "client", which is a function that can be used to compose
// ReactElement trees directly.
function jsnox(React) {
    var client = function jsnoxClient(componentType, props, children) {
        // Throw an error if too many arguments were passed in
        // (this can happen if you forget to wrap children in an array literal):
        if (arguments.length > 3) {
            var args = [].slice.call(arguments)
            throw new ParseError('Too many jsnox args (expected 3 max). Got: ' + args)
        }

        // Handle case where props arg is not specified (it's optional)
        if (Array.isArray(props) || typeof props !== 'object') {
            children = props
            props = null
        }

        if (typeof componentType === 'function') {
            // For custom components, attempt to provide a default "key" prop.
            // This can prevent the "Each child in an array should have a
            // unique key prop" warning when the element doesn't have any
            // siblings of the same type. Provide a displayName for your custom
            // components to make this more useful (and help with debugging).
            var fakeKey = componentType.displayName || 'customElement'
            props = props || {}
            if (!props.key) props.key = fakeKey
        } else {
            // Parse the provided string into a hash of props
            // If componentType is invalid (undefined, empty string, etc),
            // parseTagSpec should throw.
            var spec = parseTagSpec(componentType)
            componentType = spec.tagName
            props = extend(spec.props, props)
        }

        return React.createElement(componentType, props, children)
    }
    client.ParseError = ParseError
    return client
}

// Export for CommonJS, or else add a global jsnox variable:
if (typeof(module) !== 'undefined') module.exports = jsnox
else global.jsnox = jsnox

}(this))
<commit_msg>Added ability to enable auto key generation by adding a trailing ^ to the specString. Removed auto key generation entirely from custom components. Left in ability to trigger auto key generation for all specString declared components at construction-time to ease migration.<commit_after>;(function(global) {       // IIFE for legacy non-module usage
'use strict'

var tagNameRegex = /^([a-z1-6]+)(?:\:([a-z]+))?/    // matches 'input' or 'input:text'
var propsRegex = /((?:#|\.|@)[\w-]+)|(\[.*?\])/g    // matches all further properties
var attrRegex = /\[([\w-]+)(?:=([^\]]+))?\]/        // matches '[foo=bar]' or '[foo]'
var autoKeyGenRegex = /\^$/                         // matches 'anything^'

// Error subclass to throw for parsing errors
function ParseError(input) {
    this.message = input
    this.stack = new Error().stack
}
ParseError.prototype = Object.create(Error.prototype)
ParseError.prototype.name = 'JSnoXParseError'

// A simple module-level cache for parseTagSpec().
// Subsequent re-parsing of the same input string will be pulled
// from this cache for an increase in performance.
var specCache = {}

// Convert a tag specification string into an object
// eg. 'input:checkbox#foo.bar[name=asdf]' produces the output:
// {
//   tagName: 'input',
//   props: {
//     type: 'checkbox',
//     id: 'foo',
//     className: 'bar',
//     name: 'asdf'
//   }
// }
function parseTagSpec(specString, autoKeyGen) {
    if (!specString || !specString.match) throw new ParseError(specString)
    if (specCache[specString]) return specCache[specString]

    // Parse tagName, and optional type attribute
    var tagMatch = specString.match(tagNameRegex)
    if (!tagMatch) throw new ParseError(specString)
    var tagName = tagMatch[1]
    var props = {}
    var classes = []
    if (autoKeyGen || specString.match(autoKeyGenRegex)) {
        props.key = specString
    }
    if (tagMatch[2]) props.type = tagMatch[2]
    else if (tagName === 'button') props.type = 'button' // Saner default for <button>

    var matches = specString.match(propsRegex)
    matches && matches.forEach(function getRegexMatches(str) {
        if (!str) return
        else if (str[0] === '#') props.id = str.slice(1)
        else if (str[0] === '@') props.ref = str.slice(1)
        else if (str[0] === '.') classes.push(str.slice(1))
        else if (str[0] === '[') {
            var match = str.match(attrRegex)
            if (match) props[match[1]] = match[2] || true    // If no attr value given, use true
        }
    })
    if (classes.length) props.className = classes.join(' ')

    var spec = {
        tagName: tagName,
        props: props
    }

    specCache[specString] = spec
    return spec
}

// Merge two objects, producing a new object with their properties
//
// Note:
// * the className property is treated as a special case and is merged
// * arguments are assumed to be object literals, which is why there are
//   no hasOwnProperty() checks (see af/JSnoX/issues/3)
function extend(obj1, obj2) {
    var output = {}
    obj1 = obj1 || {}
    obj2 = obj2 || {}

    for (var k in obj1) output[k] = obj1[k]
    for (var l in obj2) output[l] = obj2[l]

    // className is a special case: we want to return the combination
    // of strings if both objects contain className
    var combinedClass = (typeof obj1.className === 'string') &&
                        (typeof obj2.className === 'string') &&
                        [obj1.className, obj2.className].join(' ')
    output.className = combinedClass || obj1.className || obj2.className

    return output
}

// Main exported function.
// Returns a "client", which is a function that can be used to compose
// ReactElement trees directly.
function jsnox(React) {
    var client = function jsnoxClient(componentType, props, children) {
        // Throw an error if too many arguments were passed in
        // (this can happen if you forget to wrap children in an array literal):
        if (arguments.length > 3) {
            var args = [].slice.call(arguments)
            throw new ParseError('Too many jsnox args (expected 3 max). Got: ' + args)
        }

        // Handle case where props arg is not specified (it's optional)
        if (Array.isArray(props) || typeof props !== 'object') {
            children = props
            props = null
        }

        if (typeof componentType !== 'function') {
            // Parse the provided string into a hash of props
            // If componentType is invalid (undefined, empty string, etc),
            // parseTagSpec should throw.
            var spec = parseTagSpec(componentType, autoKeyGen)
            componentType = spec.tagName
            props = extend(spec.props, props)
        }

        return React.createElement(componentType, props, children)
    }
    client.ParseError = ParseError
    return client
}

// Export for CommonJS, or else add a global jsnox variable:
if (typeof(module) !== 'undefined') module.exports = jsnox
else global.jsnox = jsnox

}(this))
<|endoftext|>


<commit_before>(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        root.jsqry = factory();
    }
}(this, function (undefined) {
    var fn = {};
    var jsqry = {
        first: first,
        query: query,
        cache: true,
        ast_cache: {},
        fn: fn,
        parse: parse,
        printAst: printAst
    };

    var TYPE_PATH = 1;
    var TYPE_CALL = 2;
    var TYPE_FILTER = 3;
    var TYPE_SUPER_FILTER = 4;
    var TYPE_MAP = 5;

    var SUB_TYPE_FUNC = 1;
    var SUB_TYPE_INDEX = 2;

    function printAst(ast) {
        var res = [];
        for (var i = 0; i < ast.length; i++) {
            var e = ast[i];
            var t = e.type;
            var v = e.val;
            if (t === TYPE_CALL)
                v = e.call + ',' + v;
            res.push((t === TYPE_PATH ? 'p' : t === TYPE_FILTER ? 'f' : t === TYPE_SUPER_FILTER ? 'F' : t === TYPE_MAP ? 'm' : 'c') + '(' + v + ')')
        }
        return res.join(' ');
    }

    function defined(v) {
        return v !== undefined;
    }

    function is_arr(obj) {
        if (obj == null) return false;
        return defined(obj.length) && typeof obj !== 'string';
    }

    function func_token(token) {
        token.sub_type = SUB_TYPE_FUNC;
        token.func = Function('_,i,args', 'return ' + token.val);
    }

    var allowedPathLetter = /[A-Za-z0-9_]/;
    function parse(expr, arg_idx0) {
        var cached;
        if (jsqry.cache && (cached = jsqry.ast_cache[expr]))
            return cached;

        var expr0 = expr;
        arg_idx0 = arg_idx0 || 0;
        var arg_idx = arg_idx0;
        var ast = [];
        var token = {type: TYPE_PATH, val: ''};
        var depth_filter = 0; // nesting of []
        var depth_super_filter = 0; // nesting of [[]]
        var depth_map = 0; // nesting of {}
        var depth_call = 0; // nesting of ()

        function start_new_tok(tok_type) {
            var val = token.val = token.val.trim();
            if (token.call)
                token.call = token.call.trim();
            var type = token.type;
            if (tok_type === null && (type === TYPE_FILTER || type === TYPE_MAP || type === TYPE_CALL))
                throw 'Not closed ' + (type === TYPE_FILTER ? '[' : type === TYPE_MAP ? '{' : type === TYPE_CALL ? '(' : 'wtf');
            if (!val && type === TYPE_CALL) // handle 's()'
                val = token.val = '_';
            if (val) { // handle prev token
                ast.push(token);
                if (type === TYPE_FILTER) {
                    if (val.indexOf('_') >= 0 || val.indexOf('i') >= 0) { // function
                        func_token(token)
                    } else { // index/slice
                        token.sub_type = SUB_TYPE_INDEX;
                        var idx = val.split(':');
                        token.index = idx;
                        for (var j = 0; j < idx.length; j++) {
                            idx[j] = parseInt(idx[j])
                        }
                    }
                } else if (type === TYPE_SUPER_FILTER) {
                    var _ast = jsqry.parse(val, arg_idx);
                    arg_idx += _ast.args_count;
                    token.func = function (e, i, args) {
                        var res = _query_ast(e, _ast, args);
                        for (var j=0; j<res.length;j++)
                            if (res[j])
                                return true;
                        return false;
                    };
                } else if (type === TYPE_MAP || type === TYPE_CALL && token.call) {
                    func_token(token);
                }
            }
            token = {type: tok_type, val: ''};
        }

        for (var i = 0; i < expr.length; i++) {
            var l = expr[i], next = expr[i + 1];
            if (l === '.') {
                if (token.type === TYPE_PATH) {
                    if (next === '.' || !defined(next))
                        throw '. at wrong position';
                    start_new_tok(TYPE_PATH);
                } else
                    token.val += l;
            } else if (l === '?') {
                if (token.type !== TYPE_FILTER && token.type !== TYPE_SUPER_FILTER && token.type !== TYPE_MAP)
                    throw '? at wrong position';
                if (next === '?') {
                    token.val += l;
                    i++;
                } else
                    token.val += 'args[' + arg_idx++ + ']';
            } else if (l === '[') {
                if (depth_filter === 0 && token.type === TYPE_PATH)
                    start_new_tok(TYPE_FILTER);
                else
                    token.val += l;
                depth_filter++;
            } else if (l === ']') {
                if (token.type === TYPE_PATH)
                    throw '] without [';
                if (token.type === TYPE_FILTER && --depth_filter === 0)
                    start_new_tok(TYPE_PATH);
                else
                    token.val += l;
            } else if (l === '<' && next === '<') {
                i++;
                if (depth_super_filter === 0 && token.type === TYPE_PATH)
                    start_new_tok(TYPE_SUPER_FILTER);
                else
                    token.val += l;
                depth_super_filter++;
            } else if (l === '>' && next === '>') {
                i++;
                if (token.type === TYPE_PATH)
                    throw '>> without <<';
                if (token.type === TYPE_SUPER_FILTER && --depth_super_filter === 0)
                    start_new_tok(TYPE_PATH);
                else
                    token.val += l;
            } else if (l === '{') {
                if (depth_map === 0 && token.type === TYPE_PATH)
                    start_new_tok(TYPE_MAP);
                else
                    token.val += l;
                depth_map++;
            } else if (l === '}') {
                if (token.type === TYPE_PATH)
                    throw '} without {';
                if (token.type === TYPE_MAP && --depth_map === 0)
                    start_new_tok(TYPE_PATH);
                else
                    token.val += l;
            } else if (l === '(') {
                if (depth_call === 0 && token.type === TYPE_PATH) {
                    token.call = token.val;
                    token.val = '';
                    token.type = TYPE_CALL
                } else
                    token.val += l;
                depth_call++;
            } else if (l === ')') {
                if (token.type === TYPE_PATH)
                    throw ') without (';
                if (token.type === TYPE_CALL && --depth_call === 0)
                    start_new_tok(TYPE_PATH);
                else
                    token.val += l;
            } else {
                if (token.type === TYPE_PATH && !allowedPathLetter.test(l))
                    throw 'disallowed letter in path';
                token.val += l;
            }
        }

        start_new_tok(null);//close

        ast.args_count = arg_idx - arg_idx0;

        if (jsqry.cache)
            jsqry.ast_cache[expr0] = ast;
        return ast;
    }

    function first(obj, expr) {
        var res = query.apply(null, arguments);
        return res.length ? res[0] : null;
    }

    function query(obj, expr) {
        var args = Array.prototype.slice.call(arguments, 2);
        var ast = jsqry.parse(expr);
        if (args.length !== ast.args_count)
            throw 'Wrong args count';
        return _query_ast(obj, ast, args);
    }

    function _query_ast(obj, ast, args) {
        if (!obj)
            return [];
        if (!is_arr(obj))
            obj = [obj];

        for (var i = 0; i < ast.length; i++) {
            obj = exec(obj, ast[i], args)
        }

        return obj;
    }

    function norm_idx(is_from, idx, len, step) {
        if (isNaN(idx))
            idx = is_from
                ? (step > 0 ? 0 : -1)
                : (step > 0 ? len : -len - 1);
        if (idx < 0)
            idx += len;
        return idx;
    }

    function calc_index(list, index) {
        // console.info('idx', list, index)
        var res = [];
        var idx_cnt = index.length;
        var len = list.length;
        if (idx_cnt === 1) {
            var val = list[norm_idx(1, index[0], len)];
            if (defined(val))
                res.push(val);
        } else if (idx_cnt >= 2) {
            var step = idx_cnt === 3 ? index[2] : 1;
            if (isNaN(step)) step = 1;
            var from = norm_idx(1, index[0], len, step);
            var to = norm_idx(0, index[1], len, step);
            for (var i = from; step > 0 ? i < to : i > to; i += step) {
                val = list[i];
                if (defined(val))
                    res.push(val);
            }
        }
        return res;
    }

    function sortFn(a, b) {
        return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0
    }

    fn.s = function (pairs, res) {
        pairs.sort(sortFn);
        for (var i = 0; i < pairs.length; i++) {
            res.push(pairs[i][0]);
        }
    };
    fn.u = function (pairs, res) {
        var exists = {};
        for (var i = 0; i < pairs.length; i++) {
            var p = pairs[i];
            if (!exists[p[1]]) {
                exists[p[1]] = 1;
                res.push(p[0]);
            }
        }
    };
    fn.g = function (pairs, res) {
        var groups = {};
        for (var i = 0; i < pairs.length; i++) {
            var p = pairs[i];
            var group = groups[p[1]];
            if (!group)
                group = groups[p[1]] = [p[1], []];
            group[1].push(p[0])
        }
        for (var k in groups) {
            var g = groups[k];
            res.push([g[0], g[1]]);
        }
    };
    function exec(data, token, args) {
        // console.log('Exec', data, token);
        var res = [];

        function _applyFunc() {
            for (i = 0; i < data.length; i++) {
                v = data[i];
                if (token.func(v, i, args)) {
                    res.push(v);
                }
            }
        }

        if (token.type === TYPE_PATH) {
            for (var i = 0; i < data.length; i++) {
                var v = (data[i] || {})[token.val];
                if (!defined(v) && 'it' === token.val)
                    v = data[i];
                if (is_arr(v)) {
                    for (var j = 0; j < v.length; j++) {
                        res.push(v[j]);
                    }
                } else if (defined(v) && v !== null)
                    res.push(v);
            }
        } else if (token.type === TYPE_FILTER) {
            if (token.sub_type === SUB_TYPE_FUNC)
                _applyFunc();
            else if (token.sub_type === SUB_TYPE_INDEX)
                res = calc_index(data, token.index);
        } else if (token.type === TYPE_SUPER_FILTER) {
            _applyFunc();
        } else if (token.type === TYPE_MAP) {
            for (i = 0; i < data.length; i++) {
                res.push(token.func(data[i], i, args));
            }
        } else if (token.type === TYPE_CALL) {
            var fname = token.call;
            var f = fn[fname];
            if (!f)
                throw 'not valid call: "' + fname + '"';
            var pairs = [];
            for (i = 0; i < data.length; i++) {
                v = data[i];
                pairs.push([v, token.func ? token.func(v, i, args) : v]);
            }
            f(pairs, res);
        }

        return res;
    }

    return jsqry;
}));
<commit_msg>rename super filter -> nested filter<commit_after>(function (root, factory) {
    if (typeof define === 'function' && define.amd) {
        // AMD. Register as an anonymous module.
        define([], factory);
    } else if (typeof module === 'object' && module.exports) {
        // Node. Does not work with strict CommonJS, but
        // only CommonJS-like environments that support module.exports,
        // like Node.
        module.exports = factory();
    } else {
        // Browser globals (root is window)
        root.jsqry = factory();
    }
}(this, function (undefined) {
    var fn = {};
    var jsqry = {
        first: first,
        query: query,
        cache: true,
        ast_cache: {},
        fn: fn,
        parse: parse,
        printAst: printAst
    };

    var TYPE_PATH = 1;
    var TYPE_CALL = 2;
    var TYPE_FILTER = 3;
    var TYPE_NESTED_FILTER = 4;
    var TYPE_MAP = 5;

    var SUB_TYPE_FUNC = 1;
    var SUB_TYPE_INDEX = 2;

    function printAst(ast) {
        var res = [];
        for (var i = 0; i < ast.length; i++) {
            var e = ast[i];
            var t = e.type;
            var v = e.val;
            if (t === TYPE_CALL)
                v = e.call + ',' + v;
            res.push((t === TYPE_PATH ? 'p' : t === TYPE_FILTER ? 'f' : t === TYPE_NESTED_FILTER ? 'F' : t === TYPE_MAP ? 'm' : 'c') + '(' + v + ')')
        }
        return res.join(' ');
    }

    function defined(v) {
        return v !== undefined;
    }

    function is_arr(obj) {
        if (obj == null) return false;
        return defined(obj.length) && typeof obj !== 'string';
    }

    function func_token(token) {
        token.sub_type = SUB_TYPE_FUNC;
        token.func = Function('_,i,args', 'return ' + token.val);
    }

    var allowedPathLetter = /[A-Za-z0-9_]/;
    function parse(expr, arg_idx0) {
        var cached;
        if (jsqry.cache && (cached = jsqry.ast_cache[expr]))
            return cached;

        var expr0 = expr;
        arg_idx0 = arg_idx0 || 0;
        var arg_idx = arg_idx0;
        var ast = [];
        var token = {type: TYPE_PATH, val: ''};
        var depth_filter = 0; // nesting of []
        var depth_super_filter = 0; // nesting of [[]]
        var depth_map = 0; // nesting of {}
        var depth_call = 0; // nesting of ()

        function start_new_tok(tok_type) {
            var val = token.val = token.val.trim();
            if (token.call)
                token.call = token.call.trim();
            var type = token.type;
            if (tok_type === null && (type === TYPE_FILTER || type === TYPE_MAP || type === TYPE_CALL))
                throw 'Not closed ' + (type === TYPE_FILTER ? '[' : type === TYPE_MAP ? '{' : type === TYPE_CALL ? '(' : 'wtf');
            if (!val && type === TYPE_CALL) // handle 's()'
                val = token.val = '_';
            if (val) { // handle prev token
                ast.push(token);
                if (type === TYPE_FILTER) {
                    if (val.indexOf('_') >= 0 || val.indexOf('i') >= 0) { // function
                        func_token(token)
                    } else { // index/slice
                        token.sub_type = SUB_TYPE_INDEX;
                        var idx = val.split(':');
                        token.index = idx;
                        for (var j = 0; j < idx.length; j++) {
                            idx[j] = parseInt(idx[j])
                        }
                    }
                } else if (type === TYPE_NESTED_FILTER) {
                    var _ast = jsqry.parse(val, arg_idx);
                    arg_idx += _ast.args_count;
                    token.func = function (e, i, args) {
                        var res = _query_ast(e, _ast, args);
                        for (var j=0; j<res.length;j++)
                            if (res[j])
                                return true;
                        return false;
                    };
                } else if (type === TYPE_MAP || type === TYPE_CALL && token.call) {
                    func_token(token);
                }
            }
            token = {type: tok_type, val: ''};
        }

        for (var i = 0; i < expr.length; i++) {
            var l = expr[i], next = expr[i + 1];
            if (l === '.') {
                if (token.type === TYPE_PATH) {
                    if (next === '.' || !defined(next))
                        throw '. at wrong position';
                    start_new_tok(TYPE_PATH);
                } else
                    token.val += l;
            } else if (l === '?') {
                if (token.type !== TYPE_FILTER && token.type !== TYPE_NESTED_FILTER && token.type !== TYPE_MAP)
                    throw '? at wrong position';
                if (next === '?') {
                    token.val += l;
                    i++;
                } else
                    token.val += 'args[' + arg_idx++ + ']';
            } else if (l === '[') {
                if (depth_filter === 0 && token.type === TYPE_PATH)
                    start_new_tok(TYPE_FILTER);
                else
                    token.val += l;
                depth_filter++;
            } else if (l === ']') {
                if (token.type === TYPE_PATH)
                    throw '] without [';
                if (token.type === TYPE_FILTER && --depth_filter === 0)
                    start_new_tok(TYPE_PATH);
                else
                    token.val += l;
            } else if (l === '<' && next === '<') {
                i++;
                if (depth_super_filter === 0 && token.type === TYPE_PATH)
                    start_new_tok(TYPE_NESTED_FILTER);
                else
                    token.val += l;
                depth_super_filter++;
            } else if (l === '>' && next === '>') {
                i++;
                if (token.type === TYPE_PATH)
                    throw '>> without <<';
                if (token.type === TYPE_NESTED_FILTER && --depth_super_filter === 0)
                    start_new_tok(TYPE_PATH);
                else
                    token.val += l;
            } else if (l === '{') {
                if (depth_map === 0 && token.type === TYPE_PATH)
                    start_new_tok(TYPE_MAP);
                else
                    token.val += l;
                depth_map++;
            } else if (l === '}') {
                if (token.type === TYPE_PATH)
                    throw '} without {';
                if (token.type === TYPE_MAP && --depth_map === 0)
                    start_new_tok(TYPE_PATH);
                else
                    token.val += l;
            } else if (l === '(') {
                if (depth_call === 0 && token.type === TYPE_PATH) {
                    token.call = token.val;
                    token.val = '';
                    token.type = TYPE_CALL
                } else
                    token.val += l;
                depth_call++;
            } else if (l === ')') {
                if (token.type === TYPE_PATH)
                    throw ') without (';
                if (token.type === TYPE_CALL && --depth_call === 0)
                    start_new_tok(TYPE_PATH);
                else
                    token.val += l;
            } else {
                if (token.type === TYPE_PATH && !allowedPathLetter.test(l))
                    throw 'disallowed letter in path';
                token.val += l;
            }
        }

        start_new_tok(null);//close

        ast.args_count = arg_idx - arg_idx0;

        if (jsqry.cache)
            jsqry.ast_cache[expr0] = ast;
        return ast;
    }

    function first(obj, expr) {
        var res = query.apply(null, arguments);
        return res.length ? res[0] : null;
    }

    function query(obj, expr) {
        var args = Array.prototype.slice.call(arguments, 2);
        var ast = jsqry.parse(expr);
        if (args.length !== ast.args_count)
            throw 'Wrong args count';
        return _query_ast(obj, ast, args);
    }

    function _query_ast(obj, ast, args) {
        if (!obj)
            return [];
        if (!is_arr(obj))
            obj = [obj];

        for (var i = 0; i < ast.length; i++) {
            obj = exec(obj, ast[i], args)
        }

        return obj;
    }

    function norm_idx(is_from, idx, len, step) {
        if (isNaN(idx))
            idx = is_from
                ? (step > 0 ? 0 : -1)
                : (step > 0 ? len : -len - 1);
        if (idx < 0)
            idx += len;
        return idx;
    }

    function calc_index(list, index) {
        // console.info('idx', list, index)
        var res = [];
        var idx_cnt = index.length;
        var len = list.length;
        if (idx_cnt === 1) {
            var val = list[norm_idx(1, index[0], len)];
            if (defined(val))
                res.push(val);
        } else if (idx_cnt >= 2) {
            var step = idx_cnt === 3 ? index[2] : 1;
            if (isNaN(step)) step = 1;
            var from = norm_idx(1, index[0], len, step);
            var to = norm_idx(0, index[1], len, step);
            for (var i = from; step > 0 ? i < to : i > to; i += step) {
                val = list[i];
                if (defined(val))
                    res.push(val);
            }
        }
        return res;
    }

    function sortFn(a, b) {
        return a[1] > b[1] ? 1 : a[1] < b[1] ? -1 : 0
    }

    fn.s = function (pairs, res) {
        pairs.sort(sortFn);
        for (var i = 0; i < pairs.length; i++) {
            res.push(pairs[i][0]);
        }
    };
    fn.u = function (pairs, res) {
        var exists = {};
        for (var i = 0; i < pairs.length; i++) {
            var p = pairs[i];
            if (!exists[p[1]]) {
                exists[p[1]] = 1;
                res.push(p[0]);
            }
        }
    };
    fn.g = function (pairs, res) {
        var groups = {};
        for (var i = 0; i < pairs.length; i++) {
            var p = pairs[i];
            var group = groups[p[1]];
            if (!group)
                group = groups[p[1]] = [p[1], []];
            group[1].push(p[0])
        }
        for (var k in groups) {
            var g = groups[k];
            res.push([g[0], g[1]]);
        }
    };
    function exec(data, token, args) {
        // console.log('Exec', data, token);
        var res = [];

        function _applyFunc() {
            for (i = 0; i < data.length; i++) {
                v = data[i];
                if (token.func(v, i, args)) {
                    res.push(v);
                }
            }
        }

        if (token.type === TYPE_PATH) {
            for (var i = 0; i < data.length; i++) {
                var v = (data[i] || {})[token.val];
                if (!defined(v) && 'it' === token.val)
                    v = data[i];
                if (is_arr(v)) {
                    for (var j = 0; j < v.length; j++) {
                        res.push(v[j]);
                    }
                } else if (defined(v) && v !== null)
                    res.push(v);
            }
        } else if (token.type === TYPE_FILTER) {
            if (token.sub_type === SUB_TYPE_FUNC)
                _applyFunc();
            else if (token.sub_type === SUB_TYPE_INDEX)
                res = calc_index(data, token.index);
        } else if (token.type === TYPE_NESTED_FILTER) {
            _applyFunc();
        } else if (token.type === TYPE_MAP) {
            for (i = 0; i < data.length; i++) {
                res.push(token.func(data[i], i, args));
            }
        } else if (token.type === TYPE_CALL) {
            var fname = token.call;
            var f = fn[fname];
            if (!f)
                throw 'not valid call: "' + fname + '"';
            var pairs = [];
            for (i = 0; i < data.length; i++) {
                v = data[i];
                pairs.push([v, token.func ? token.func(v, i, args) : v]);
            }
            f(pairs, res);
        }

        return res;
    }

    return jsqry;
}));
<|endoftext|>


<commit_before>// Morse constants
var INTER_CHARACTER = 2.5  // Time between letters
var INTER_WORD = 3.5  // Time between words
var RAMP = 0.010

function wpmToElementDuration(wpm) {
  // Based on CODEX (60000 ms per minute / W * 60 dit values in CODEX)
  return 1.0 / wpm;
};

var Keyer = function(audioSink) {
  // Keyer configuration
  this.speed = 25;  // in wpm
  this.elementDuration = wpmToElementDuration(this.speed);
  this.audioSink = audioSink;

  // Message sending state
  // Largest time at which we've scheduled an audio event
  this.latestScheduledEventTime = 0;

  // Signal chain
  this.voiceOsc = context.createOscillator();
  this.voiceOsc.type = 'sine';
  this.voiceOsc.frequency.value = 500;
  this.voiceOsc.start();
  // envelopeGain control is used to generate keying envelope
  this.envelopeGain = context.createGain();
  this.envelopeGain.gain.value = 0.0;
  this.monitorGain = context.createGain();
  this.monitorGain.gain.value = 1.0;

  this.voiceOsc.connect(this.envelopeGain);
  this.envelopeGain.connect(this.monitorGain);
  this.monitorGain.connect(this.audioSink);

};

Keyer.prototype.setPitch = function(pitch) {
  this.voiceOsc.frequency.value = pitch;
};

Keyer.prototype.setMonitorGain = function(gain) {
  this.monitorGain.gain.value = gain;
};

Keyer.prototype.setSpeed = function(wpm) {
  this.speed = wpm;
  this.elementDuration = wpmToElementDuration(this.speed);
};

Keyer.prototype.isSending = function() {
  console.log("this.latestScheduledEventTime = " + this.latestScheduledEventTime);
  console.log("context.currentTime = " + context.currentTime);
  return (this.latestScheduledEventTime > context.currentTime);
};

Keyer.prototype.abortMessage = function() {
  console.log("STOP SENDING");
  //this.envelopeGain.gain.cancelScheduledValues(context.currentTime);
  this.envelopeGain.gain.cancelScheduledValues(this.startTime);
  this.envelopeGain.gain.linearRampToValueAtTime(0.0, context.currentTime + RAMP);
  this.latestScheduledEventTime = 0.0;

};

/*
 Send the given text.
 */
Keyer.prototype.send = function(text) {
  var self = this

  // Send morse
  var timeOffset = context.currentTime
  this.startTime = timeOffset

  // Morse sending functions
  function dot(gainNode, elementDuration) {
    // Send a dot
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(1.0, timeOffset);
    timeOffset += elementDuration;
    gainNode.linearRampToValueAtTime(1.0, timeOffset);

    // Inter-element space
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);
    timeOffset += elementDuration;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);

    // Remember this time
    self.latestScheduledEventTime = timeOffset;
  }

  function dash(gainNode, elementDuration) {
    // Send a dash
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(1.0, timeOffset);
    timeOffset += 3 * elementDuration;
    gainNode.linearRampToValueAtTime(1.0, timeOffset);

    // Inter-element space
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);
    timeOffset += elementDuration;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);

    // Remember this time
    self.latestScheduledEventTime = timeOffset;
  }

  function letter_space(gainNode, elementDuration) {
    // Wait INTER_CHARACTER units
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);
    timeOffset += INTER_CHARACTER * elementDuration;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);

    // Remember this time
    self.latestScheduledEventTime = timeOffset;
  }

  function word_space(gainNode, elementDuration) {
    // Wait INTER_WORD units
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);
    timeOffset += INTER_WORD * elementDuration;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);

    // Remember this time
    self.latestScheduledEventTime = timeOffset;
  }

  console.log("Sending " + text);

  // Convert text to string representing morse dots and dashes
  var morseLetters = []
  for (var i = 0, len = text.length; i < len; i++) {
    morseLetters.push(toMorse(text[i]));
  }
  morseString = morseLetters.join("S");

  this.envelopeGain.gain.linearRampToValueAtTime(0, timeOffset);

  // TODO(ggood) instead of scheduling all of the events here, only
  // schedule up to, say, 500 milliseconds into the future, and schedule
  // a callback in which we will schedule another 500 ms, etc.
  for (var i = 0, len = morseString.length; i < len; i++) {
    switch (morseString[i]) {
      case ".":
        dot(this.envelopeGain.gain, this.elementDuration);
        break;
      case "-":
        dash(this.envelopeGain.gain, this.elementDuration);
        break;
      case "S":
        letter_space(this.envelopeGain.gain, this.elementDuration);
        break;
      case "W":
        word_space(this.envelopeGain.gain, this.elementDuration);
        break;
      default:
        break;
    }
  }

  function toMorse(char) {
    var morseMap = {
      "a": ".-",
      "b": "-...",
      "c": "-.-.",
      "d": "-..",
      "e": ".",
      "f": "..-.",
      "g": "--.",
      "h": "....",
      "i": "..",
      "j": ".---",
      "k": "-.-",
      "l": ".-..",
      "m": "--",
      "n": "-.",
      "o": "---",
      "p": ".--.",
      "q": "--.-",
      "r": ".-.",
      "s": "...",
      "t": "-",
      "u": "..-",
      "v": "...-",
      "w": ".--",
      "x": "-..-",
      "y": "-.--",
      "z": "--..",
      "0": "-----",
      "1": ".----",
      "2": "..---",
      "3": "...--",
      "4": "....-",
      "5": ".....",
      "6": "-....",
      "7": "--...",
      "8": "---..",
      "9": "----.",
      "?": "..--..",
      "/": "-..-.",
      ".": ".-.-.-",
      ",": "--..--",
      " ": "W",
    }
    char = char.toLowerCase()
    if (char in morseMap) {
      return morseMap[char];
    } else {
      return "";
    }
  }
}
<commit_msg>Implement cancel.<commit_after>/*

 A morse code keyer, based on HTML5 audio.

 Gordon Good velo27 [at] yahoo [dot] com

 License: None; use as you wish

 Limitations:
   - Schedules all audio events up front. This means the speed cannot
     be changed after the send method is called.

 */

// Morse constants
var INTER_CHARACTER = 2.5  // Time between letters
var INTER_WORD = 3.5  // Time between words
var RAMP = 0.010

function wpmToElementDuration(wpm) {
  // Convert a words-per-minute value to an element duration, expressed
  // in seconds.
  // Based on CODEX (60000 ms per minute / W * 60 dit values in CODEX)
  return 1.0 / wpm;
};

var Keyer = function(audioSink) {
  // Keyer configuration
  this.speed = 25;  // in wpm
  this.elementDuration = wpmToElementDuration(this.speed);
  this.audioSink = audioSink;

  // Message sending state
  // Largest time at which we've scheduled an audio event
  this.latestScheduledEventTime = 0;

  // Signal chain; oscillator -> gain (keying) -> gain (monitor volume)
  this.voiceOsc = context.createOscillator();
  this.voiceOsc.type = 'sine';
  this.voiceOsc.frequency.value = 500;
  this.voiceOsc.start();
  // envelopeGain control is used to generate keying envelope
  this.envelopeGain = context.createGain();
  this.envelopeGain.gain.value = 0.0;
  this.monitorGain = context.createGain();
  this.monitorGain.gain.value = 1.0;

  this.voiceOsc.connect(this.envelopeGain);
  this.envelopeGain.connect(this.monitorGain);
  this.monitorGain.connect(this.audioSink);

};

Keyer.prototype.setPitch = function(pitch) {
  this.voiceOsc.frequency.value = pitch;
};

Keyer.prototype.setMonitorGain = function(gain) {
  this.monitorGain.gain.value = gain;
};

Keyer.prototype.setSpeed = function(wpm) {
  this.speed = wpm;
  this.elementDuration = wpmToElementDuration(this.speed);
};

Keyer.prototype.isSending = function() {
  return (this.latestScheduledEventTime > context.currentTime);
};

Keyer.prototype.abortMessage = function() {
  this.envelopeGain.gain.cancelScheduledValues(this.startTime);
  this.envelopeGain.gain.linearRampToValueAtTime(0.0, context.currentTime + RAMP);
  this.latestScheduledEventTime = 0.0;

};

/*
 Send the given text.
 */
Keyer.prototype.send = function(text) {
  var self = this

  // Send morse
  var timeOffset = context.currentTime
  this.startTime = timeOffset

  // Morse sending functions
  function dot(gainNode, elementDuration) {
    // Send a dot
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(1.0, timeOffset);
    timeOffset += elementDuration;
    gainNode.linearRampToValueAtTime(1.0, timeOffset);

    // Inter-element space
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);
    timeOffset += elementDuration;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);

    // Remember this time
    self.latestScheduledEventTime = timeOffset;
  }

  function dash(gainNode, elementDuration) {
    // Send a dash
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(1.0, timeOffset);
    timeOffset += 3 * elementDuration;
    gainNode.linearRampToValueAtTime(1.0, timeOffset);

    // Inter-element space
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);
    timeOffset += elementDuration;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);

    // Remember this time
    self.latestScheduledEventTime = timeOffset;
  }

  function letter_space(gainNode, elementDuration) {
    // Wait INTER_CHARACTER units
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);
    timeOffset += INTER_CHARACTER * elementDuration;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);

    // Remember this time
    self.latestScheduledEventTime = timeOffset;
  }

  function word_space(gainNode, elementDuration) {
    // Wait INTER_WORD units
    timeOffset += RAMP;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);
    timeOffset += INTER_WORD * elementDuration;
    gainNode.linearRampToValueAtTime(0.0, timeOffset);

    // Remember this time
    self.latestScheduledEventTime = timeOffset;
  }

  // Convert text to string representing morse dots and dashes
  var morseLetters = []
  for (var i = 0, len = text.length; i < len; i++) {
    morseLetters.push(toMorse(text[i]));
  }
  morseString = morseLetters.join("S");

  this.envelopeGain.gain.linearRampToValueAtTime(0, timeOffset);

  // TODO(ggood) instead of scheduling all of the events here, only
  // schedule up to, say, 500 milliseconds into the future, and schedule
  // a callback in which we will schedule another 500 ms, etc.
  for (var i = 0, len = morseString.length; i < len; i++) {
    switch (morseString[i]) {
      case ".":
        dot(this.envelopeGain.gain, this.elementDuration);
        break;
      case "-":
        dash(this.envelopeGain.gain, this.elementDuration);
        break;
      case "S":
        letter_space(this.envelopeGain.gain, this.elementDuration);
        break;
      case "W":
        word_space(this.envelopeGain.gain, this.elementDuration);
        break;
      default:
        break;
    }
  }

  function toMorse(char) {
    var morseMap = {
      "a": ".-",
      "b": "-...",
      "c": "-.-.",
      "d": "-..",
      "e": ".",
      "f": "..-.",
      "g": "--.",
      "h": "....",
      "i": "..",
      "j": ".---",
      "k": "-.-",
      "l": ".-..",
      "m": "--",
      "n": "-.",
      "o": "---",
      "p": ".--.",
      "q": "--.-",
      "r": ".-.",
      "s": "...",
      "t": "-",
      "u": "..-",
      "v": "...-",
      "w": ".--",
      "x": "-..-",
      "y": "-.--",
      "z": "--..",
      "0": "-----",
      "1": ".----",
      "2": "..---",
      "3": "...--",
      "4": "....-",
      "5": ".....",
      "6": "-....",
      "7": "--...",
      "8": "---..",
      "9": "----.",
      "?": "..--..",
      "/": "-..-.",
      ".": ".-.-.-",
      ",": "--..--",
      " ": "W",
    }
    char = char.toLowerCase()
    if (char in morseMap) {
      return morseMap[char];
    } else {
      return "";
    }
  }
}
<|endoftext|>


<commit_before>"use strict"

var Vnode = require("../render/vnode")

var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g
var selectorCache = {}
function hyperscript(selector) {
	if (selector == null || typeof selector !== "string" && typeof selector !== "function" && typeof selector.view !== "function") {
		throw Error("The selector must be either a string or a component.");
	}

	if (typeof selector === "string" && selectorCache[selector] === undefined) {
		var match, tag, classes = [], attributes = {}
		while (match = selectorParser.exec(selector)) {
			var type = match[1], value = match[2]
			if (type === "" && value !== "") tag = value
			else if (type === "#") attributes.id = value
			else if (type === ".") classes.push(value)
			else if (match[3][0] === "[") {
				var attrValue = match[6]
				if (attrValue) attrValue = attrValue.replace(/\\(["'])/g, "$1").replace(/\\\\/g, "\\")
				if (match[4] === "class") classes.push(attrValue)
				else attributes[match[4]] = attrValue || true
			}
		}
		if (classes.length > 0) attributes.className = classes.join(" ")
		selectorCache[selector] = function(attrs, children) {
			var hasAttrs = false, childList, text
			var className = attrs.className || attrs.class
			for (var key in attributes) attrs[key] = attributes[key]
			if (className !== undefined) {
				if (attrs.class !== undefined) {
					attrs.class = undefined
					attrs.className = className
				}
				if (attributes.className !== undefined) attrs.className = attributes.className + " " + className
			}
			for (var key in attrs) {
				if (key !== "key") {
					hasAttrs = true
					break
				}
			}
			if (Array.isArray(children) && children.length == 1 && children[0] != null && children[0].tag === "#") text = children[0].children
			else childList = children

			return Vnode(tag || "div", attrs.key, hasAttrs ? attrs : undefined, childList, text, undefined)
		}
	}
	var attrs, children, childrenIndex
	if (arguments[1] == null || typeof arguments[1] === "object" && arguments[1].tag === undefined && !Array.isArray(arguments[1])) {
		attrs = arguments[1]
		childrenIndex = 2
	}
	else childrenIndex = 1
	if (arguments.length === childrenIndex + 1) {
		children = Array.isArray(arguments[childrenIndex]) ? arguments[childrenIndex] : [arguments[childrenIndex]]
	}
	else {
		children = []
		for (var i = childrenIndex; i < arguments.length; i++) children.push(arguments[i])
	}

	if (typeof selector === "string") return selectorCache[selector](attrs || {}, Vnode.normalizeChildren(children))

	return Vnode(selector, attrs && attrs.key, attrs || {}, Vnode.normalizeChildren(children), undefined, undefined)
}

module.exports = hyperscript
<commit_msg>Optimize memory for selector cache<commit_after>"use strict"

var Vnode = require("../render/vnode")

var selectorParser = /(?:(^|#|\.)([^#\.\[\]]+))|(\[(.+?)(?:\s*=\s*("|'|)((?:\\["'\]]|.)*?)\5)?\])/g
var selectorCache = {}
var hasOwn = {}.hasOwnProperty

function compileSelector(selector) {
	var match, tag = "div", classes = [], attrs = {}
	while (match = selectorParser.exec(selector)) {
		var type = match[1], value = match[2]
		if (type === "" && value !== "") tag = value
		else if (type === "#") attrs.id = value
		else if (type === ".") classes.push(value)
		else if (match[3][0] === "[") {
			var attrValue = match[6]
			if (attrValue) attrValue = attrValue.replace(/\\(["'])/g, "$1").replace(/\\\\/g, "\\")
			if (match[4] === "class") classes.push(attrValue)
			else attrs[match[4]] = attrValue || true
		}
	}
	if (classes.length > 0) attrs.className = classes.join(" ")
	return selectorCache[selector] = {tag: tag, attrs: attrs}
}

function execSelector(state, attrs, children) {
	var hasAttrs = false, childList, text
	var className = attrs.className || attrs.class

	for (var key in state.attrs) {
		if (hasOwn.call(state.attrs, key)) {
			attrs[key] = state.attrs[key]
		}
	}

	if (className != null) {
		if (attrs.class != null) {
			attrs.class = undefined
			attrs.className = className
		}

		if (state.attrs.className != null) {
			attrs.className = state.attrs.className + " " + className
		}
	}

	for (var key in attrs) {
		if (hasOwn.call(attrs, key) && key !== "key") {
			hasAttrs = true
			break
		}
	}

	if (Array.isArray(children) && children.length === 1 && children[0] != null && children[0].tag === "#") {
		text = children[0].children
	} else {
		childList = children
	}

	return Vnode(state.tag, attrs.key, hasAttrs ? attrs : undefined, childList, text)
}

function hyperscript(selector) {
	// Because sloppy mode sucks
	var attrs = arguments[1], start = 2, children

	if (selector == null || typeof selector !== "string" && typeof selector !== "function" && typeof selector.view !== "function") {
		throw Error("The selector must be either a string or a component.");
	}

	if (typeof selector === "string") {
		var cached = selectorCache[selector] || compileSelector(selector)
	}

	if (!attrs) {
		attrs = {}
	} else if (typeof attrs !== "object" || attrs.tag != null || Array.isArray(attrs)) {
		attrs = {}
		start = 1
	}

	if (arguments.length === start + 1) {
		children = arguments[start]
		if (!Array.isArray(children)) children = [children]
	} else {
		children = []
		while (start < arguments.length) children.push(arguments[start++])
	}

	var normalized = Vnode.normalizeChildren(children)

	if (typeof selector === "string") {
		return execSelector(cached, attrs, normalized)
	} else {
		return Vnode(selector, attrs.key, attrs, normalized)
	}
}

module.exports = hyperscript
<|endoftext|>


<commit_before>/*The file to interface with the beam API */

//run 'npm i -S beam-client-node' to get these two things
const BeamClient = require('beam-client-node');
const BeamSocket = require('beam-client-node/lib/ws');
const config = require('./config.json');
const spawn = require('child_process').spawn;

const debug = config.debug;

let userInfo;
let channelId = -1;

const client = new BeamClient();

//OAuth gives permision for all following actions
client.use('oauth',{
  tokens:{
    access: config.OAuth,
    expires: Date.now() + (365 * 24 *60 *60 *1000)
  },
});

//get following channel and join its chat
client.request('GET', 'users/current')
.then(response => {
    if(debug) console.log(response.body);
    userInfo = response.body;
    return client.request('GET','users/'+userInfo.id+'/follows');
})
.then(response =>{
  //TODO modify to join all followed channels
  if(debug){
    return client.chat.join(userInfo.channel.id);
  }else{
    if(response.body[0]){
      channelId = response.body[0].id;
      console.log("Joining",response.body[0].name);
      return client.chat.join(channelId);
    }else{
      return client.chat.join(userInfo.channel.id);
    }
  }
})
.then(response => {
    const body = response.body;
    if(debug) console.log(body);
    if(!body.roles.includes('Mod') && !body.roles.includes('Owner')){
      console.log("Cannot moderate this chat");
      return;
    }
    if(!debug && channelId !== -1){
      return createChatSocket(userInfo.id, channelId, body.endpoints, body.authkey);
    }else{
      return createChatSocket(userInfo.id, userInfo.channel.id, body.endpoints, body.authkey);
    }
})
.catch(error => {
      console.log("Something went wrong:", error);
});

/**
 * Creates a beam chat socket and sets up listeners to various chat events.
 * @param {number} userId The user to authenticate as
 * @param {number} channelId The channel id to join
 * @param {any} endpoints An endpoints array from a beam.chat.join call.
 * @param {any} authkey An authentication key from a beam.chat.join call.
 * @returns {Promise.<>}
 */
function createChatSocket (userId, channelId, endpoints, authkey) {
    const socket = new BeamSocket(endpoints).boot();

    socket.auth(channelId, userId, authkey)
    .then(() => {
        if(debug) console.log('You are now authenticated!');
        // Send a chat message
        console.log("Joined chatroom");
        return socket.call('msg', ['BOOTING UP...']);
    })
    .catch(error => {
        console.log('Oh no! An error occurred!', error);
    });

    // Listen to chat messages, note that you will also receive your own!
    socket.on('ChatMessage', data => {
        if(debug) console.log('We got a ChatMessage packet!');
        if(debug) console.log(data);
        if(debug) console.log(data.message); // lets take a closer look
        var roles = data.user_roles;
        if(!roles.includes('Mod') && !roles.includes('Owner')){
          moderate(socket,data);
        }
        commands(socket,data,roles);

    });

    // Listen to socket errors, you'll need to handle these!
    socket.on('error', error => {
        console.error('Socket error', error);
    });
}

function moderate(socket,messageData){
  //This is how to send the data to be processed by the python
  var moderator = spawn('python3', ['hammer.py']);

  if(debug) console.log("In moderate function");
  var msgArr = messageToString(messageData.message.message);
  var msg = msgArr[0];
  var hasLink = msgArr[1]; //TODO make link handler
  var toPython = messageData.user_name + " " + msg;
  if(debug) console.log("Input to python:", toPython);
  moderator.stdin.write(toPython);
  moderator.stdin.end();

  moderator.stdout.on('data', function(data){
    var pythonOut = data.toString().trim();
    if(debug) console.log("From python:",pythonOut);
    var action = pythonOut.split(" ")[0];
    var user = pythonOut.split(" ")[1];
    var indexOfSpace1 = pythonOut.indexOf(" ");
    var indexOfSpace2 = pythonOut.indexOf(" ",indexOfSpace1+1);
    var response = pythonOut.substr(indexOfSpace2);
    if(indexOfSpace2 === -1){
      response = "";
    }
    if(debug){
      console.log("User is:", user);
      console.log("Action to take:",action);
      console.log("Response is: ","@"+user+": "+response);
    }
    //Parse the actions and take action if needed
    if(action === "timeout"){
      timeout(socket,user,response,msg);
    }else if(action === "ban"){
      ban(socket,user,response,msg);
    }else if(action === "purge"){
      purge(socket,user,response,msg);
    }else if(action === "nothing"){
      if(debug){console.log("No action to take");}
      //THIS SPACE INTENTIONALLY LEFT BLANK
    }
  });

  moderator.stdout.on('end', function(){
    if(debug) console.log("Finished moderate parse");
  });
}

function ban(socket,user,response,msg){ //TODO check that the call completed successfully
  if(debug){
    console.log("Need to ban",user);
  }else{
    socket.call('timeout',[user,config.banDuration]); //need to timeout for 1 to unban
    if(!config.silentBans) socket.call('msg',["@"+user+": "+response]);
    console.log("Banning",user,"for message:",msg);
  }
}

function purge(socket,user,response,msg){ //TODO check that the call completed successfully
  if(debug){
    console.log("Need to purge",user);
  }else{
    socket.call('purge',[user]);
    if(!config.silentBans) socket.call('msg',["@"+user+": "+response]);
    console.log("Purging",user,"for message:",msg);
  }
}

//To unban, use a duration of 1 with this function
function timeout(socket,user,response,msg,duration){ //TODO check that the call completed successfully
  if(debug){
    console.log("Need to timeout",user);
  }else{
    if(duration){
      socket.call('timeout',[user,duration]);
    }else{
      socket.call('timeout',[user,config.timeoutDuration]);
    }
    if(!config.silentBans) socket.call('msg',["@"+user+": "+response]);
    console.log("Timing out",user,"for message:",msg);
  }
}

function unban(socket,user){
  timeout(socket,user,"You have been unbanned", "<TO UNBAN>",1);
}

function messageToString(array){
  var result = "";
  var hasLink = false;
  for(var index in array){
    var element = array[index];
    result += element.text;
    if(element.type === "link"){
      hasLink = true;
    }
  }
  if(debug) console.log("messageToString is:", result);
  return [result, hasLink];
}

function commands(socket,messageData,roles){
  if(debug) console.log("In commands function");
  var msg = messageToString(messageData.message.message)[0];
  var role = "Normal";
  var username = messageData.user_name;

  //Send command to python script
  if(msg.charAt(0) != '!'){
    return;
  }else{
    role = parseRoles(roles);
    var handleCmds = spawn('python3', ['centurion.py']);
    var toPython = username + " " + role + " " + msg;
    if(debug) console.log("Input to python:", toPython);
    handleCmds.stdin.write(toPython);
    handleCmds.stdin.end();

    handleCmds.stdout.on('data', function(data){
      var pythonOut = data.toString().trim();
      if(debug) console.log("From python:",pythonOut);
      var action = pythonOut.split(" ")[0];
      var user = pythonOut.split(" ")[1];
      var indexOfSpace1 = pythonOut.indexOf(" ");
      var indexOfSpace2 = pythonOut.indexOf(" ",indexOfSpace1+1);
      var response = pythonOut.substr(indexOfSpace2);
      if(indexOfSpace2 === -1){
        response = "";
      }
      if(debug){
        console.log("User is:", user);
        console.log("Action to take:",action);
        console.log("Response is: ","@"+user+": "+response);
      }
      //Parse the actions and take action if needed
      if(action === "timeout"){
        timeout(socket,user,response,msg);
      }else if(action === "ban"){
        ban(socket,user,response,msg);
      }else if(action === "purge"){
        purge(socket,user,response,msg);
      }else if(action === "respond"){
        socket.call('msg', [response]);
      }else if(action === "unban"){
        unban(socket,user);
      }else if(action === "nothing"){
        if(debug){console.log("No action to take");}
        //THIS SPACE INTENTIONALLY LEFT BLANK
      }
    });

    handleCmds.stdout.on('end', function(){
      if(debug) console.log("Finished moderate parse");
    });
  }

}

function parseRoles(roleArr){
  var result = "Normal";
  for(var index in roleArr){
    var role = roleArr[index];
    //TODO parse the remaining Mixer roles'
    if(role === "Owner"){
      result = "Caster";
    }else if(role === "Mod" && result !== "Caster"){
      result = "Mod";
    }else if(role == "User" && result !== "Caster" && result !== "Mod"){
      result = "Normal";
    }
  }
  return result;
}
<commit_msg>added new module toggles<commit_after>/*The file to interface with the beam API */

//run 'npm i -S beam-client-node' to get these two things
const BeamClient = require('beam-client-node');
const BeamSocket = require('beam-client-node/lib/ws');
const config = require('./config.json');
const spawn = require('child_process').spawn;

const debug = config.debug;
const moderationModule = config.moderationOn;
const commandModule = config.commandsOn;

let userInfo;
let channelId = -1;

const client = new BeamClient();

//OAuth gives permision for all following actions
client.use('oauth',{
  tokens:{
    access: config.OAuth,
    expires: Date.now() + (365 * 24 *60 *60 *1000)
  },
});

//get following channel and join its chat
client.request('GET', 'users/current')
.then(response => {
    if(debug) console.log(response.body);
    userInfo = response.body;
    return client.request('GET','users/'+userInfo.id+'/follows');
})
.then(response =>{
  //TODO modify to join all followed channels
  if(debug){
    return client.chat.join(userInfo.channel.id);
  }else{
    if(response.body[0]){
      channelId = response.body[0].id;
      console.log("Joining",response.body[0].name);
      return client.chat.join(channelId);
    }else{
      return client.chat.join(userInfo.channel.id);
    }
  }
})
.then(response => {
    const body = response.body;
    if(debug) console.log(body);
    if(!body.roles.includes('Mod') && !body.roles.includes('Owner')){
      console.log("Cannot moderate this chat");
      return;
    }
    if(!debug && channelId !== -1){
      return createChatSocket(userInfo.id, channelId, body.endpoints, body.authkey);
    }else{
      return createChatSocket(userInfo.id, userInfo.channel.id, body.endpoints, body.authkey);
    }
})
.catch(error => {
      console.log("Something went wrong:", error);
});

/**
 * Creates a beam chat socket and sets up listeners to various chat events.
 * @param {number} userId The user to authenticate as
 * @param {number} channelId The channel id to join
 * @param {any} endpoints An endpoints array from a beam.chat.join call.
 * @param {any} authkey An authentication key from a beam.chat.join call.
 * @returns {Promise.<>}
 */
function createChatSocket (userId, channelId, endpoints, authkey) {
    const socket = new BeamSocket(endpoints).boot();

    socket.auth(channelId, userId, authkey)
    .then(() => {
        if(debug) console.log('You are now authenticated!');
        // Send a chat message
        console.log("Joined chatroom");
        return socket.call('msg', ['BOOTING UP...']);
    })
    .catch(error => {
        console.log('Oh no! An error occurred!', error);
    });

    // Listen to chat messages, note that you will also receive your own!
    socket.on('ChatMessage', data => {
        if(debug) console.log('We got a ChatMessage packet!');
        if(debug) console.log(data);
        if(debug) console.log(data.message); // lets take a closer look
        var roles = data.user_roles;
        if(moderationModule && !roles.includes('Mod') && !roles.includes('Owner')){
          moderate(socket,data);
        }
        if(commandModule){
          commands(socket,data,roles);
        }
    });

    // Listen to socket errors, you'll need to handle these!
    socket.on('error', error => {
        console.error('Socket error', error);
    });
}

function moderate(socket,messageData){
  //This is how to send the data to be processed by the python
  var moderator = spawn('python3', ['hammer.py']);

  if(debug) console.log("In moderate function");
  var msgArr = messageToString(messageData.message.message);
  var msg = msgArr[0];
  var hasLink = msgArr[1]; //TODO make link handler
  var toPython = messageData.user_name + " " + msg;
  if(debug) console.log("Input to python:", toPython);
  moderator.stdin.write(toPython);
  moderator.stdin.end();

  moderator.stdout.on('data', function(data){
    var pythonOut = data.toString().trim();
    if(debug) console.log("From python:",pythonOut);
    var action = pythonOut.split(" ")[0];
    var user = pythonOut.split(" ")[1];
    var indexOfSpace1 = pythonOut.indexOf(" ");
    var indexOfSpace2 = pythonOut.indexOf(" ",indexOfSpace1+1);
    var response = pythonOut.substr(indexOfSpace2);
    if(indexOfSpace2 === -1){
      response = "";
    }
    if(debug){
      console.log("User is:", user);
      console.log("Action to take:",action);
      console.log("Response is: ","@"+user+": "+response);
    }
    //Parse the actions and take action if needed
    if(action === "timeout"){
      timeout(socket,user,response,msg);
    }else if(action === "ban"){
      ban(socket,user,response,msg);
    }else if(action === "purge"){
      purge(socket,user,response,msg);
    }else if(action === "nothing"){
      if(debug){console.log("No action to take");}
      //THIS SPACE INTENTIONALLY LEFT BLANK
    }
  });

  moderator.stdout.on('end', function(){
    if(debug) console.log("Finished moderate parse");
  });
}

function ban(socket,user,response,msg){ //TODO check that the call completed successfully
  if(debug){
    console.log("Need to ban",user);
  }else{
    socket.call('timeout',[user,config.banDuration]); //need to timeout for 1 to unban
    if(!config.silentBans) socket.call('msg',["@"+user+": "+response]);
    console.log("Banning",user,"for message:",msg);
  }
}

function purge(socket,user,response,msg){ //TODO check that the call completed successfully
  if(debug){
    console.log("Need to purge",user);
  }else{
    socket.call('purge',[user]);
    if(!config.silentBans) socket.call('msg',["@"+user+": "+response]);
    console.log("Purging",user,"for message:",msg);
  }
}

//To unban, use a duration of 1 with this function
function timeout(socket,user,response,msg,duration){ //TODO check that the call completed successfully
  if(debug){
    console.log("Need to timeout",user);
  }else{
    if(duration){
      socket.call('timeout',[user,duration]);
    }else{
      socket.call('timeout',[user,config.timeoutDuration]);
    }
    if(!config.silentBans) socket.call('msg',["@"+user+": "+response]);
    console.log("Timing out",user,"for message:",msg);
  }
}

function unban(socket,user){
  timeout(socket,user,"You have been unbanned", "<TO UNBAN>",1);
}

function messageToString(array){
  var result = "";
  var hasLink = false;
  for(var index in array){
    var element = array[index];
    result += element.text;
    if(element.type === "link"){
      hasLink = true;
    }
  }
  if(debug) console.log("messageToString is:", result);
  return [result, hasLink];
}

function commands(socket,messageData,roles){
  if(debug) console.log("In commands function");
  var msg = messageToString(messageData.message.message)[0];
  var role = "Normal";
  var username = messageData.user_name;

  //Send command to python script
  if(msg.charAt(0) != '!'){
    return;
  }else{
    role = parseRoles(roles);
    var handleCmds = spawn('python3', ['centurion.py']);
    var toPython = username + " " + role + " " + msg;
    if(debug) console.log("Input to python:", toPython);
    handleCmds.stdin.write(toPython);
    handleCmds.stdin.end();

    handleCmds.stdout.on('data', function(data){
      var pythonOut = data.toString().trim();
      if(debug) console.log("From python:",pythonOut);
      var action = pythonOut.split(" ")[0];
      var user = pythonOut.split(" ")[1];
      var indexOfSpace1 = pythonOut.indexOf(" ");
      var indexOfSpace2 = pythonOut.indexOf(" ",indexOfSpace1+1);
      var response = pythonOut.substr(indexOfSpace2);
      if(indexOfSpace2 === -1){
        response = "";
      }
      if(debug){
        console.log("User is:", user);
        console.log("Action to take:",action);
        console.log("Response is: ","@"+user+": "+response);
      }
      //Parse the actions and take action if needed
      if(action === "timeout"){
        timeout(socket,user,response,msg);
      }else if(action === "ban"){
        ban(socket,user,response,msg);
      }else if(action === "purge"){
        purge(socket,user,response,msg);
      }else if(action === "respond"){
        socket.call('msg', [response]);
      }else if(action === "unban"){
        unban(socket,user);
      }else if(action === "nothing"){
        if(debug){console.log("No action to take");}
        //THIS SPACE INTENTIONALLY LEFT BLANK
      }
    });

    handleCmds.stdout.on('end', function(){
      if(debug) console.log("Finished moderate parse");
    });
  }

}

function parseRoles(roleArr){
  var result = "Normal";
  for(var index in roleArr){
    var role = roleArr[index];
    //TODO parse the remaining Mixer roles'
    if(role === "Owner"){
      result = "Caster";
    }else if(role === "Mod" && result !== "Caster"){
      result = "Mod";
    }else if(role == "User" && result !== "Caster" && result !== "Mod"){
      result = "Normal";
    }
  }
  return result;
}
<|endoftext|>


<commit_before>/*The file to interface with the beam API */

//run 'npm i -S beam-client-node' to get these two things
const BeamClient = require('beam-client-node');
const BeamSocket = require('beam-client-node/lib/ws');
const config = require('./config.json');
const spawn = require('child_process').spawn;

const debug = false;

let userInfo;

const client = new BeamClient();

//OAuth gives permision for all following actions
client.user('oauth',{
  tokens:{
    access: config.OAuth,
    expires: Date.now() + (365 * 24 *60 *60 *1000)
  },
});

client.request('GET', 'users/current')
.then(response => {
    console.log(response.body);
    userInfo = response.body;
    return client.chat.join(response.body.channel.id);
})
.then(response => {
    const body = response.body;
    console.log(body);
    return createChatSocket(userInfo.id, userInfo.channel.id, body.endpoints, body.authkey);
})
.catch(error => {
      console.log("Something went wrong:", error);
});

/**
 * Creates a beam chat socket and sets up listeners to various chat events.
 * @param {number} userId The user to authenticate as
 * @param {number} channelId The channel id to join
 * @param {any} endpoints An endpoints array from a beam.chat.join call.
 * @param {any} authkey An authentication key from a beam.chat.join call.
 * @returns {Promise.<>}
 */
function createChatSocket (userId, channelId, endpoints, authkey) {
    const socket = new BeamSocket(endpoints).boot();

    socket.auth(channelId, userId, authkey)
    .then(() => {
        console.log('You are now authenticated!');
        // Send a chat message
        return socket.call('msg', ['Hello world!']);
    })
    .catch(error => {
        console.log('Oh no! An error occurred!', error);
    });

    // Listen to chat messages, note that you will also receive your own!
    socket.on('ChatMessage', data => {
        console.log('We got a ChatMessage packet!');
        console.log(data);
        console.log(data.message); // lets take a closer look

        moderate(data);
    });

    // Listen to socket errors, you'll need to handle these!
    socket.on('error', error => {
        console.error('Socket error', error);
    });
}

function moderate(data){
  //This is how to send the data to be processed by the python
  var moderator = spawn('python', ['hammer.py']);
  moderator.stdin.write(JSON.stringify(data.message));
  moderator.stdin.end();

  moderator.stdout.on('data', function(data){
    if(data === "timeout"){
      if(debug) console.log("Need to timeout");
      //TODO
    }else if(data === "ban"){
      if(debug) console.log("Need to ban");
      //TODO
    }else if(data === "purge"){
      if(debug) console.log("Need to purge");
      //TODO
    }else if(data === "nothing"){
      if(debug) console.log("No action to take");
      //THIS SPAE INTINTIONALLY LEFT BLANK
    }
  });

  moderator.stdout.on('end', function(){
    return;
  });
}
<commit_msg>fixed typo<commit_after>/*The file to interface with the beam API */

//run 'npm i -S beam-client-node' to get these two things
const BeamClient = require('beam-client-node');
const BeamSocket = require('beam-client-node/lib/ws');
const config = require('./config.json');
const spawn = require('child_process').spawn;

const debug = false;

let userInfo;

const client = new BeamClient();

//OAuth gives permision for all following actions
client.use('oauth',{
  tokens:{
    access: config.OAuth,
    expires: Date.now() + (365 * 24 *60 *60 *1000)
  },
});

client.request('GET', 'users/current')
.then(response => {
    console.log(response.body);
    userInfo = response.body;
    return client.chat.join(response.body.channel.id);
})
.then(response => {
    const body = response.body;
    console.log(body);
    return createChatSocket(userInfo.id, userInfo.channel.id, body.endpoints, body.authkey);
})
.catch(error => {
      console.log("Something went wrong:", error);
});

/**
 * Creates a beam chat socket and sets up listeners to various chat events.
 * @param {number} userId The user to authenticate as
 * @param {number} channelId The channel id to join
 * @param {any} endpoints An endpoints array from a beam.chat.join call.
 * @param {any} authkey An authentication key from a beam.chat.join call.
 * @returns {Promise.<>}
 */
function createChatSocket (userId, channelId, endpoints, authkey) {
    const socket = new BeamSocket(endpoints).boot();

    socket.auth(channelId, userId, authkey)
    .then(() => {
        console.log('You are now authenticated!');
        // Send a chat message
        return socket.call('msg', ['Hello world!']);
    })
    .catch(error => {
        console.log('Oh no! An error occurred!', error);
    });

    // Listen to chat messages, note that you will also receive your own!
    socket.on('ChatMessage', data => {
        console.log('We got a ChatMessage packet!');
        console.log(data);
        console.log(data.message); // lets take a closer look

        moderate(data);
    });

    // Listen to socket errors, you'll need to handle these!
    socket.on('error', error => {
        console.error('Socket error', error);
    });
}

function moderate(data){
  //This is how to send the data to be processed by the python
  var moderator = spawn('python', ['hammer.py']);
  moderator.stdin.write(JSON.stringify(data.message));
  moderator.stdin.end();

  moderator.stdout.on('data', function(data){
    if(data === "timeout"){
      if(debug) console.log("Need to timeout");
      //TODO
    }else if(data === "ban"){
      if(debug) console.log("Need to ban");
      //TODO
    }else if(data === "purge"){
      if(debug) console.log("Need to purge");
      //TODO
    }else if(data === "nothing"){
      if(debug) console.log("No action to take");
      //THIS SPAE INTINTIONALLY LEFT BLANK
    }
  });

  moderator.stdout.on('end', function(){
    return;
  });
}
<|endoftext|>


<commit_before><commit_msg>Only resolve deepest contact for each collision<commit_after><|endoftext|>


<commit_before><commit_msg>Remove console.log<commit_after><|endoftext|>


<commit_before><commit_msg>Fix failure display bug<commit_after><|endoftext|>


<commit_before><commit_msg>Slate configuration for Hailo<commit_after><|endoftext|>


<commit_before><commit_msg>- some cleanup<commit_after><|endoftext|>


<commit_before><commit_msg>continue lazy sequence implementation<commit_after><|endoftext|>


<commit_before><commit_msg>add useful physics debug method<commit_after><|endoftext|>


<commit_before><commit_msg>Enable to add markdown file<commit_after><|endoftext|>


<commit_before><commit_msg>fix(setConfig): 修复返回undefined时报错<commit_after><|endoftext|>


<commit_before><commit_msg>removed the THREE import from the player class<commit_after><|endoftext|>


<commit_before><commit_msg>Better jsdoc for return value<commit_after><|endoftext|>


<commit_before><commit_msg>Added `left: 50%` & `translate(-50%, -50%)`. Fixed #833. (#834)<commit_after><|endoftext|>


<commit_before><commit_msg>Update datatable lengthMenu to display more data<commit_after><|endoftext|>


<commit_before><commit_msg>Add tests for naming things<commit_after><|endoftext|>