<commit_before>#!/usr/bin/env node
const pkg = require('../package.json');
const childProcess = require('child_process');
const fs = require('fs');
const path = require('path');
const walk = require('walk');
const prompt = require('prompt');
const colors = require('colors/safe');

let title = '';
let description = '';
let template = '';

let startTime = 0;

// --------------------------------------------------------------- AUX functions
function bash(script, onSuccess) {
    childProcess.exec(script, (error) => {
        if (error) {
            return console.log(error);
        }
        return onSuccess();
    });
}

function clearFolder(onComplete) {
    bash(`rm -rf ${title}`, () => {
        onComplete();
    });
}

function createDirectory(onComplete) {
    bash(`mkdir ${title}`, () => {
        onComplete();
    });
}

function copyTemplate(onComplete) {
    const templatePath = path.join(__dirname, '..', 'kickjs-templates', template);

    if (fs.existsSync(templatePath)) {
        bash(`cp -R ${templatePath}/ ${process.cwd()}/${title}`, () => {
            onComplete();
        });
    } else {
        console.log(colors.red('template not found'), colors.gray(templatePath));
    }
}

function parseFile(file) {
    fs.readFile(file, 'utf8', (err1, data) => {
        if (err1) return console.logt(err1);

        const result = data
            .replace(/__TITLE__/g, title.replace(/ /g, '-'))
            .replace(/__DESCRIPTION__/g, description);

        fs.writeFile(file, result, 'utf8', (err2) => {
            if (err2) {
                console.log(err2);
            }
            return false;
        });
        return false;
    });
}

function updateFileReferences(onComplete) {
    const walker = walk.walk(`./${title}`, {
        followLinks: false,
        filters: ['node_modules'],
    });

    walker.on('file', (root, fileStats, next) => {
        parseFile(`${root}/${fileStats.name}`);
        next();
    });

    walker.on('end', () => {
        onComplete();
    });
}

function end() {
    console.log('');
    console.log(colors.gray('completed in'), colors.green(`${Number(Date.now() - startTime)}ms`));
}

// ------------------------------------------------------------------------ INIT
function init() {
    startTime = Date.now();

    clearFolder(() => {
        createDirectory(() => {
            copyTemplate(() => {
                updateFileReferences(() => {
                    end();
                });
            });
        });
    });
}

// HERE
const step1 = {
    title: {
        pattern: /^[a-zA-Z0-9\s-]+$/,
        message: 'Name must be letters, numbers, spaces or dashes.',
        required: true,
    },
    description: {
        required: false,
    },
};

const step2 = {
    template: {
        pattern: /^[0-9\s]+$/,
        message: 'Only numbers are allowed.',
        required: true,
    },
};

console.log('');
console.log(colors.cyan('kickjs'), pkg.version);
console.log(colors.gray('Please enter your project details:'));

prompt.start();
prompt.message = '';
prompt.get({
    properties: step1,
}, (err, result1) => {
    if (!err) {
        title = result1.title;
        description = result1.description;

        console.log('');
        console.log(colors.gray('Please select the template:'));
        console.log(colors.cyan('(1)'), colors.gray('default'), colors.cyan('(2)'), colors.gray('react'));
        prompt.get({ properties: step2 }, (error, result2) => {
            switch (result2.template) {
                case '1':
                    template = 'default';
                    break;
                case '2':
                    template = 'react';
                    break;
                default:
                    console.log(colors.red('invalid template:'), colors.gray('using default template'));
                    template = 'default';

            }
            init();
        });
    }
});
<commit_msg>adding electron option<commit_after>#!/usr/bin/env node
const pkg = require('../package.json');
const childProcess = require('child_process');
const fs = require('fs');
const path = require('path');
const walk = require('walk');
const prompt = require('prompt');
const colors = require('colors/safe');

let title = '';
let description = '';
let template = '';

let startTime = 0;

// --------------------------------------------------------------- AUX functions
function bash(script, onSuccess) {
    childProcess.exec(script, (error) => {
        if (error) {
            return console.log(error);
        }
        return onSuccess();
    });
}

function clearFolder(onComplete) {
    bash(`rm -rf ${title}`, () => {
        onComplete();
    });
}

function createDirectory(onComplete) {
    bash(`mkdir ${title}`, () => {
        onComplete();
    });
}

function copyTemplate(onComplete) {
    const templatePath = path.join(__dirname, '..', 'kickjs-templates', template);

    if (fs.existsSync(templatePath)) {
        bash(`cp -R ${templatePath}/ ${process.cwd()}/${title}`, () => {
            onComplete();
        });
    } else {
        console.log(colors.red('template not found'), colors.gray(templatePath));
    }
}

function parseFile(file) {
    fs.readFile(file, 'utf8', (err1, data) => {
        if (err1) return console.logt(err1);

        const result = data
            .replace(/__TITLE__/g, title.replace(/ /g, '-'))
            .replace(/__DESCRIPTION__/g, description);

        fs.writeFile(file, result, 'utf8', (err2) => {
            if (err2) {
                console.log(err2);
            }
            return false;
        });
        return false;
    });
}

function updateFileReferences(onComplete) {
    const walker = walk.walk(`./${title}`, {
        followLinks: false,
        filters: ['node_modules'],
    });

    walker.on('file', (root, fileStats, next) => {
        parseFile(`${root}/${fileStats.name}`);
        next();
    });

    walker.on('end', () => {
        onComplete();
    });
}

function end() {
    console.log('');
    console.log(colors.gray('completed in'), colors.green(`${Number(Date.now() - startTime)}ms`));
}

// ------------------------------------------------------------------------ INIT
function init() {
    startTime = Date.now();

    clearFolder(() => {
        createDirectory(() => {
            copyTemplate(() => {
                updateFileReferences(() => {
                    end();
                });
            });
        });
    });
}

// HERE
const step1 = {
    title: {
        pattern: /^[a-zA-Z0-9\s-]+$/,
        message: 'Name must be letters, numbers, spaces or dashes.',
        required: true,
    },
    description: {
        required: false,
    },
};

const step2 = {
    template: {
        pattern: /^[0-9\s]+$/,
        message: 'Only numbers are allowed.',
        required: true,
    },
};

console.log('');
console.log(colors.cyan('kickjs'), pkg.version);
console.log(colors.gray('Please enter your project details:'));

prompt.start();
prompt.message = '';
prompt.get({
    properties: step1,
}, (err, result1) => {
    if (!err) {
        title = result1.title;
        description = result1.description;

        console.log('');
        console.log(colors.gray('Please select the template:'));
        console.log(colors.cyan('(1)'), colors.gray('default'), colors.cyan('(2)'), colors.gray('react'), colors.cyan('(3)'), colors.gray('electron/react'));
        prompt.get({ properties: step2 }, (error, result2) => {
            switch (result2.template) {
                case '1':
                    template = 'default';
                    break;
                case '2':
                    template = 'react';
                    break;
                case '2':
                    template = 'electron';
                    break;
                default:
                    console.log(colors.red('invalid template:'), colors.gray('using default template'));
                    template = 'default';

            }
            init();
        });
    }
});
<|endoftext|>


<commit_before>/**
 * Copyright 2013 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
RED.nodes = function() {

    var node_defs = {};
    var nodes = [];
    var configNodes = {};
    var links = [];
    var defaultWorkspace;
    var workspaces = {};

    function registerType(nt,def) {
        node_defs[nt] = def;
        // TODO: too tightly coupled into palette UI
        RED.palette.add(nt,def);
    }

    function getID() {
        return (1+Math.random()*4294967295).toString(16);
    }

    function getType(type) {
        return node_defs[type];
    }

    function addNode(n) {
        if (n._def.category == "config") {
            configNodes[n.id] = n;
            RED.sidebar.config.refresh();
        } else {
            n.dirty = true;
            nodes.push(n);
            var updatedConfigNode = false;
            for (var d in n._def.defaults) {
                var property = n._def.defaults[d];
                if (property.type) {
                    var type = getType(property.type)
                    if (type && type.category == "config") {
                        var configNode = configNodes[n[d]];
                        if (configNode) {
                            updatedConfigNode = true;
                            configNode.users.push(n);
                        }
                    }
                }
            }
            if (updatedConfigNode) {
                RED.sidebar.config.refresh();
            }
        }
    }
    function addLink(l) {
        links.push(l);
    }
    function addConfig(c) {
        configNodes[c.id] = c;
    }

    function getNode(id) {
        if (id in configNodes) {
            return configNodes[id];
        } else {
            for (var n in nodes) {
                if (nodes[n].id == id) {
                    return nodes[n];
                }
            }
        }
        return null;
    }

    function removeNode(id) {
        var removedLinks = [];
        if (id in configNodes) {
            delete configNodes[id];
            RED.sidebar.config.refresh();
        } else {
            var node = getNode(id);
            if (node) {
                nodes.splice(nodes.indexOf(node),1);
                removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
                removedLinks.map(function(l) {links.splice(links.indexOf(l), 1); });
            }
            var updatedConfigNode = false;
            for (var d in node._def.defaults) {
                var property = node._def.defaults[d];
                if (property.type) {
                    var type = getType(property.type)
                    if (type && type.category == "config") {
                        var configNode = configNodes[node[d]];
                        if (configNode) {
                            updatedConfigNode = true;
                            var users = configNode.users;
                            users.splice(users.indexOf(node),1);
                        }
                    }
                }
            }
            if (updatedConfigNode) {
                RED.sidebar.config.refresh();
            }
        }
        return removedLinks;
    }

    function removeLink(l) {
        var index = links.indexOf(l);
        if (index != -1) {
            links.splice(index,1);
        }
    }

    function refreshValidation() {
        for (var n in nodes) {
            RED.editor.validateNode(nodes[n]);
        }
    }

    function addWorkspace(ws) {
        workspaces[ws.id] = ws;
    }
    function getWorkspace(id) {
        return workspaces[id];
    }
    function removeWorkspace(id) {
        delete workspaces[id];
        var removedNodes = [];
        var removedLinks = [];
        for (var n in nodes) {
            var node = nodes[n];
            if (node.z == id) {
                removedNodes.push(node);
            }
        }
        for (var n in removedNodes) {
            var rmlinks = removeNode(removedNodes[n].id);
            removedLinks = removedLinks.concat(rmlinks);
        }
        return {nodes:removedNodes,links:removedLinks};
    }

    function getAllFlowNodes(node) {
        var visited = {};
        visited[node.id] = true;
        var nns = [node];
        var stack = [node];
        while(stack.length != 0) {
            var n = stack.shift();
            var childLinks = links.filter(function(d) { return (d.source === n) || (d.target === n);});
            for (var i in childLinks) {
                var child = (childLinks[i].source === n)?childLinks[i].target:childLinks[i].source;
                if (!visited[child.id]) {
                    visited[child.id] = true;
                    nns.push(child);
                    stack.push(child);
                }
            }
        }
        return nns;
    }

    /**
     * Converts a node to an exportable JSON Object
     **/
    function convertNode(n) {
        var node = {};
        node.id = n.id;
        node.type = n.type;
        for (var d in n._def.defaults) {
            node[d] = n[d];
        }
        if (n._def.category != "config") {
            node.x = n.x;
            node.y = n.y;
            node.z = n.z;
            node.wires = [];
            for(var i=0;i<n.outputs;i++) {
                node.wires.push([]);
            }
            var wires = links.filter(function(d){return d.source === n;});
            for (var i in wires) {
                var w = wires[i];
                node.wires[w.sourcePort].push(w.target.id);
            }
        }
        return node;
    }

    /**
     * Converts the current node selection to an exportable JSON Object
     **/
    function createExportableNodeSet(set) {
        var nns = [];
        var exportedConfigNodes = {};
        for (var n in set) {
            var node = set[n].n;
            var convertedNode = RED.nodes.convertNode(node);
            for (var d in node._def.defaults) {
                if (node._def.defaults[d].type && node[d] in configNodes) {
                    var confNode = configNodes[node[d]];
                    var exportable = getType(node._def.defaults[d].type).exportable;
                    if ((exportable == null || exportable)) {
                        if (!(node[d] in exportedConfigNodes)) {
                            exportedConfigNodes[node[d]] = true;
                            nns.unshift(RED.nodes.convertNode(confNode));
                        }
                    } else {
                        convertedNode[d] = "";
                    }
                }
            }

            nns.push(convertedNode);
        }
        return nns;
    }

    //TODO: rename this (createCompleteNodeSet)
    function createCompleteNodeSet() {
        var nns = [];
        for (var i in workspaces) {
            nns.push(workspaces[i]);
        }
        for (var i in configNodes) {
            nns.push(convertNode(configNodes[i]));
        }
        for (var i in nodes) {
            var node = nodes[i];
            nns.push(convertNode(node));
        }
        return nns;
    }

    function importNodes(newNodesObj,createNewIds) {
        try {
            var newNodes;
            if (typeof newNodesObj === "string") {
                if (newNodesObj == "") {
                    return;
                }
                newNodes = JSON.parse(newNodesObj);
            } else {
                newNodes = newNodesObj;
            }

            if (!$.isArray(newNodes)) {
                newNodes = [newNodes];
            }
            var unknownTypes = [];
            for (var i in newNodes) {
                var n = newNodes[i];
                // TODO: remove workspace in next release+1
                if (n.type != "workspace" && n.type != "tab" && !getType(n.type)) {
                    // TODO: get this UI thing out of here! (see below as well)
                    n.name = n.type;
                    n.type = "unknown";
                    if (unknownTypes.indexOf(n.name)==-1) {
                        unknownTypes.push(n.name);
                    }
                }
            }
            if (unknownTypes.length > 0) {
                var typeList = "

"+unknownTypes.join("

")+"

";
                var type = "type"+(unknownTypes.length > 1?"s":"");
                RED.notify("Imported unrecognised "+type+":"+typeList,"error",false,10000);
                //"DO NOT DEPLOY while in this state.
Either, add missing types to Node-RED, restart and then reload page,
or delete unknown "+n.name+", rewire as required, and then deploy.","error");
            }

            for (var i in newNodes) {
                var n = newNodes[i];
                // TODO: remove workspace in next release+1
                if (n.type === "workspace" || n.type === "tab") {
                    if (n.type === "workspace") {
                        n.type = "tab";
                    }
                    if (defaultWorkspace == null) {
                        defaultWorkspace = n;
                    }
                    addWorkspace(n);
                    RED.view.addWorkspace(n);
                }
            }
            if (defaultWorkspace == null) {
                defaultWorkspace = { type:"tab", id:getID(), label:"Sheet 1" };
                addWorkspace(defaultWorkspace);
                RED.view.addWorkspace(defaultWorkspace);
            }

            var node_map = {};
            var new_nodes = [];
            var new_links = [];

            for (var i in newNodes) {
                var n = newNodes[i];
                // TODO: remove workspace in next release+1
                if (n.type !== "workspace" && n.type !== "tab") {
                    var def = getType(n.type);
                    if (def && def.category == "config") {
                        if (!RED.nodes.node(n.id)) {
                            var configNode = {id:n.id,type:n.type,users:[]};
                            for (var d in def.defaults) {
                                configNode[d] = n[d];
                            }
                            configNode.label = def.label;
                            configNode._def = def;
                            RED.nodes.add(configNode);
                        }
                    } else {
                        var node = {x:n.x,y:n.y,z:n.z,type:0,wires:n.wires,changed:false};
                        if (createNewIds) {
                            node.z = RED.view.getWorkspace();
                            node.id = getID();
                        } else {
                            node.id = n.id;
                            if (node.z == null || !workspaces[node.z]) {
                                node.z = RED.view.getWorkspace();
                            }
                        }
                        node.type = n.type;
                        node._def = def;
                        if (!node._def) {
                            node._def = {
                                color:"#fee",
                                defaults: {},
                                label: "unknown: "+n.type,
                                labelStyle: "node_label_italic",
                                outputs: n.outputs||n.wires.length
                            }
                        }
                        node.outputs = n.outputs||node._def.outputs;

                        for (var d in node._def.defaults) {
                            node[d] = n[d];
                        }

                        addNode(node);
                        RED.editor.validateNode(node);
                        node_map[n.id] = node;
                        new_nodes.push(node);
                    }
                }
            }
            for (var i in new_nodes) {
                var n = new_nodes[i];
                for (var w1 in n.wires) {
                    var wires = (n.wires[w1] instanceof Array)?n.wires[w1]:[n.wires[w1]];
                    for (var w2 in wires) {
                        if (wires[w2] in node_map) {
                            var link = {source:n,sourcePort:w1,target:node_map[wires[w2]]};
                            addLink(link);
                            new_links.push(link);
                        }
                    }
                }
                delete n.wires;
            }
            return [new_nodes,new_links];
        } catch(error) {
            //TODO: get this UI thing out of here! (see above as well)
            RED.notify("Error: "+error,"error");
            return null;
        }

    }

    return {
        registerType: registerType,
        getType: getType,
        convertNode: convertNode,
        add: addNode,
        addLink: addLink,
        remove: removeNode,
        removeLink: removeLink,
        addWorkspace: addWorkspace,
        removeWorkspace: removeWorkspace,
        workspace: getWorkspace,
        eachNode: function(cb) {
            for (var n in nodes) {
                cb(nodes[n]);
            }
        },
        eachLink: function(cb) {
            for (var l in links) {
                cb(links[l]);
            }
        },
        eachConfig: function(cb) {
            for (var id in configNodes) {
                cb(configNodes[id]);
            }
        },
        node: getNode,
        import: importNodes,
        refreshValidation: refreshValidation,
        getAllFlowNodes: getAllFlowNodes,
        createExportableNodeSet: createExportableNodeSet,
        createCompleteNodeSet: createCompleteNodeSet,
        id: getID,
        nodes: nodes, // TODO: exposed for d3 vis
        links: links  // TODO: exposed for d3 vis
    };
}();
<commit_msg>Import unknown config node breaks layout Fixes #211<commit_after>/**
 * Copyright 2013 IBM Corp.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 **/
RED.nodes = function() {

    var node_defs = {};
    var nodes = [];
    var configNodes = {};
    var links = [];
    var defaultWorkspace;
    var workspaces = {};

    function registerType(nt,def) {
        node_defs[nt] = def;
        // TODO: too tightly coupled into palette UI
        RED.palette.add(nt,def);
    }

    function getID() {
        return (1+Math.random()*4294967295).toString(16);
    }

    function getType(type) {
        return node_defs[type];
    }

    function addNode(n) {
        if (n._def.category == "config") {
            configNodes[n.id] = n;
            RED.sidebar.config.refresh();
        } else {
            n.dirty = true;
            nodes.push(n);
            var updatedConfigNode = false;
            for (var d in n._def.defaults) {
                var property = n._def.defaults[d];
                if (property.type) {
                    var type = getType(property.type)
                    if (type && type.category == "config") {
                        var configNode = configNodes[n[d]];
                        if (configNode) {
                            updatedConfigNode = true;
                            configNode.users.push(n);
                        }
                    }
                }
            }
            if (updatedConfigNode) {
                RED.sidebar.config.refresh();
            }
        }
    }
    function addLink(l) {
        links.push(l);
    }
    function addConfig(c) {
        configNodes[c.id] = c;
    }

    function getNode(id) {
        if (id in configNodes) {
            return configNodes[id];
        } else {
            for (var n in nodes) {
                if (nodes[n].id == id) {
                    return nodes[n];
                }
            }
        }
        return null;
    }

    function removeNode(id) {
        var removedLinks = [];
        if (id in configNodes) {
            delete configNodes[id];
            RED.sidebar.config.refresh();
        } else {
            var node = getNode(id);
            if (node) {
                nodes.splice(nodes.indexOf(node),1);
                removedLinks = links.filter(function(l) { return (l.source === node) || (l.target === node); });
                removedLinks.map(function(l) {links.splice(links.indexOf(l), 1); });
            }
            var updatedConfigNode = false;
            for (var d in node._def.defaults) {
                var property = node._def.defaults[d];
                if (property.type) {
                    var type = getType(property.type)
                    if (type && type.category == "config") {
                        var configNode = configNodes[node[d]];
                        if (configNode) {
                            updatedConfigNode = true;
                            var users = configNode.users;
                            users.splice(users.indexOf(node),1);
                        }
                    }
                }
            }
            if (updatedConfigNode) {
                RED.sidebar.config.refresh();
            }
        }
        return removedLinks;
    }

    function removeLink(l) {
        var index = links.indexOf(l);
        if (index != -1) {
            links.splice(index,1);
        }
    }

    function refreshValidation() {
        for (var n in nodes) {
            RED.editor.validateNode(nodes[n]);
        }
    }

    function addWorkspace(ws) {
        workspaces[ws.id] = ws;
    }
    function getWorkspace(id) {
        return workspaces[id];
    }
    function removeWorkspace(id) {
        delete workspaces[id];
        var removedNodes = [];
        var removedLinks = [];
        for (var n in nodes) {
            var node = nodes[n];
            if (node.z == id) {
                removedNodes.push(node);
            }
        }
        for (var n in removedNodes) {
            var rmlinks = removeNode(removedNodes[n].id);
            removedLinks = removedLinks.concat(rmlinks);
        }
        return {nodes:removedNodes,links:removedLinks};
    }

    function getAllFlowNodes(node) {
        var visited = {};
        visited[node.id] = true;
        var nns = [node];
        var stack = [node];
        while(stack.length != 0) {
            var n = stack.shift();
            var childLinks = links.filter(function(d) { return (d.source === n) || (d.target === n);});
            for (var i in childLinks) {
                var child = (childLinks[i].source === n)?childLinks[i].target:childLinks[i].source;
                if (!visited[child.id]) {
                    visited[child.id] = true;
                    nns.push(child);
                    stack.push(child);
                }
            }
        }
        return nns;
    }

    /**
     * Converts a node to an exportable JSON Object
     **/
    function convertNode(n) {
        var node = {};
        node.id = n.id;
        node.type = n.type;
        for (var d in n._def.defaults) {
            node[d] = n[d];
        }
        if (n._def.category != "config") {
            node.x = n.x;
            node.y = n.y;
            node.z = n.z;
            node.wires = [];
            for(var i=0;i<n.outputs;i++) {
                node.wires.push([]);
            }
            var wires = links.filter(function(d){return d.source === n;});
            for (var i in wires) {
                var w = wires[i];
                node.wires[w.sourcePort].push(w.target.id);
            }
        }
        return node;
    }

    /**
     * Converts the current node selection to an exportable JSON Object
     **/
    function createExportableNodeSet(set) {
        var nns = [];
        var exportedConfigNodes = {};
        for (var n in set) {
            var node = set[n].n;
            var convertedNode = RED.nodes.convertNode(node);
            for (var d in node._def.defaults) {
                if (node._def.defaults[d].type && node[d] in configNodes) {
                    var confNode = configNodes[node[d]];
                    var exportable = getType(node._def.defaults[d].type).exportable;
                    if ((exportable == null || exportable)) {
                        if (!(node[d] in exportedConfigNodes)) {
                            exportedConfigNodes[node[d]] = true;
                            nns.unshift(RED.nodes.convertNode(confNode));
                        }
                    } else {
                        convertedNode[d] = "";
                    }
                }
            }

            nns.push(convertedNode);
        }
        return nns;
    }

    //TODO: rename this (createCompleteNodeSet)
    function createCompleteNodeSet() {
        var nns = [];
        for (var i in workspaces) {
            nns.push(workspaces[i]);
        }
        for (var i in configNodes) {
            nns.push(convertNode(configNodes[i]));
        }
        for (var i in nodes) {
            var node = nodes[i];
            nns.push(convertNode(node));
        }
        return nns;
    }

    function importNodes(newNodesObj,createNewIds) {
        try {
            var newNodes;
            if (typeof newNodesObj === "string") {
                if (newNodesObj == "") {
                    return;
                }
                newNodes = JSON.parse(newNodesObj);
            } else {
                newNodes = newNodesObj;
            }

            if (!$.isArray(newNodes)) {
                newNodes = [newNodes];
            }
            var unknownTypes = [];
            for (var i=0;i<newNodes.length;i++) {
                var n = newNodes[i];
                // TODO: remove workspace in next release+1
                if (n.type != "workspace" && n.type != "tab" && !getType(n.type)) {
                    // TODO: get this UI thing out of here! (see below as well)
                    n.name = n.type;
                    n.type = "unknown";
                    if (unknownTypes.indexOf(n.name)==-1) {
                        unknownTypes.push(n.name);
                    }
                    if (n.x == null && n.y == null) {
                        // config node - remove it
                        newNodes.splice(i,1);
                        i--;
                    }
                }
            }
            if (unknownTypes.length > 0) {
                var typeList = "

"+unknownTypes.join("

")+"

";
                var type = "type"+(unknownTypes.length > 1?"s":"");
                RED.notify("Imported unrecognised "+type+":"+typeList,"error",false,10000);
                //"DO NOT DEPLOY while in this state.
Either, add missing types to Node-RED, restart and then reload page,
or delete unknown "+n.name+", rewire as required, and then deploy.","error");
            }

            for (var i in newNodes) {
                var n = newNodes[i];
                // TODO: remove workspace in next release+1
                if (n.type === "workspace" || n.type === "tab") {
                    if (n.type === "workspace") {
                        n.type = "tab";
                    }
                    if (defaultWorkspace == null) {
                        defaultWorkspace = n;
                    }
                    addWorkspace(n);
                    RED.view.addWorkspace(n);
                }
            }
            if (defaultWorkspace == null) {
                defaultWorkspace = { type:"tab", id:getID(), label:"Sheet 1" };
                addWorkspace(defaultWorkspace);
                RED.view.addWorkspace(defaultWorkspace);
            }

            var node_map = {};
            var new_nodes = [];
            var new_links = [];

            for (var i in newNodes) {
                var n = newNodes[i];
                // TODO: remove workspace in next release+1
                if (n.type !== "workspace" && n.type !== "tab") {
                    var def = getType(n.type);
                    if (def && def.category == "config") {
                        if (!RED.nodes.node(n.id)) {
                            var configNode = {id:n.id,type:n.type,users:[]};
                            for (var d in def.defaults) {
                                configNode[d] = n[d];
                            }
                            configNode.label = def.label;
                            configNode._def = def;
                            RED.nodes.add(configNode);
                        }
                    } else {
                        var node = {x:n.x,y:n.y,z:n.z,type:0,wires:n.wires,changed:false};
                        if (createNewIds) {
                            node.z = RED.view.getWorkspace();
                            node.id = getID();
                        } else {
                            node.id = n.id;
                            if (node.z == null || !workspaces[node.z]) {
                                node.z = RED.view.getWorkspace();
                            }
                        }
                        node.type = n.type;
                        node._def = def;
                        if (!node._def) {
                            node._def = {
                                color:"#fee",
                                defaults: {},
                                label: "unknown: "+n.type,
                                labelStyle: "node_label_italic",
                                outputs: n.outputs||n.wires.length
                            }
                        }
                        node.outputs = n.outputs||node._def.outputs;

                        for (var d in node._def.defaults) {
                            node[d] = n[d];
                        }

                        addNode(node);
                        RED.editor.validateNode(node);
                        node_map[n.id] = node;
                        new_nodes.push(node);
                    }
                }
            }
            for (var i in new_nodes) {
                var n = new_nodes[i];
                for (var w1 in n.wires) {
                    var wires = (n.wires[w1] instanceof Array)?n.wires[w1]:[n.wires[w1]];
                    for (var w2 in wires) {
                        if (wires[w2] in node_map) {
                            var link = {source:n,sourcePort:w1,target:node_map[wires[w2]]};
                            addLink(link);
                            new_links.push(link);
                        }
                    }
                }
                delete n.wires;
            }
            return [new_nodes,new_links];
        } catch(error) {
            //TODO: get this UI thing out of here! (see above as well)
            RED.notify("Error: "+error,"error");
            return null;
        }

    }

    return {
        registerType: registerType,
        getType: getType,
        convertNode: convertNode,
        add: addNode,
        addLink: addLink,
        remove: removeNode,
        removeLink: removeLink,
        addWorkspace: addWorkspace,
        removeWorkspace: removeWorkspace,
        workspace: getWorkspace,
        eachNode: function(cb) {
            for (var n in nodes) {
                cb(nodes[n]);
            }
        },
        eachLink: function(cb) {
            for (var l in links) {
                cb(links[l]);
            }
        },
        eachConfig: function(cb) {
            for (var id in configNodes) {
                cb(configNodes[id]);
            }
        },
        node: getNode,
        import: importNodes,
        refreshValidation: refreshValidation,
        getAllFlowNodes: getAllFlowNodes,
        createExportableNodeSet: createExportableNodeSet,
        createCompleteNodeSet: createCompleteNodeSet,
        id: getID,
        nodes: nodes, // TODO: exposed for d3 vis
        links: links  // TODO: exposed for d3 vis
    };
}();
<|endoftext|>


<commit_before>'use strict';
/**
 * src/mario.js
 *
 * Creates the Mario object
 *
*/
//The frames in the sprite sheet is 16x16px
//mario_wjlfy5.png

window.onload = function() {

var canvas = document.getElementById('game');
canvas.width = 640;
canvas.height = 480;
var marioImage = new Image();
marioImage.src = 'assets/mario_wjlfy5_large.png';
var rightPressed = false;
var leftPressed = false;
var upPressed = false;

document.addEventListener('keydown', keyDownHandler, false);
document.addEventListener('keyup', keyUpHandler, false);

function keyDownHandler(e) {
    if (e.keyCode == 39) {
        rightPressed = true;
    }
    else if (e.keyCode == 37) {
        leftPressed = true;
    }

    else if (e.keyCode == 38) {
        upPressed = true;
    }
}

function keyUpHandler(e) {
    if (e.keyCode == 39) {
        rightPressed = false;
    }
    else if (e.keyCode == 37) {
        leftPressed = false;
    }
    else if (e.keyCode == 38) {
        upPressed = false;
    }
}

function sprite (options) {
    var that = {},
        frameIndex = 0,
        tickCount = 0,
        ticksPerFrame = options.ticksPerFrame || 0,
        numberOfFrames = options.numberOfFrames || 1;

    that.context = options.context;
    that.width = options.width;
    that.height = options.height;
    that.image = options.image;
    that.x = options.x;
    that.y = options.y;
    that.xVelocity = options.xVelocity;
    that.yVelocity = options.yVelocity;
    // that.left = options.left;
    // that.right = options.right;
    that.topIndex = options.topIndex;

    that.render = function () {
        // Clear the canvas
        that.context.clearRect(0, 0, canvas.width, canvas.height);
        // Draw the animation
        that.context.drawImage (
            that.image,
            frameIndex * that.width / numberOfFrames,
            that.topIndex,
            that.width / numberOfFrames,
            that.height,
            that.x,
            that.y,
            that.width / numberOfFrames,
            that.height);
    };

    that.loop = options.loop;

//     that.update = function() {
//         tickCount += 1;

//         if (tickCount > ticksPerFrame) {
//             tickCount = 0;
//             if (frameIndex < numberOfFrames -1) {
//                 frameIndex += 1;
//             }
//             else if (that.loop) {
//                 frameIndex = 1;
//             }
//             else {
//                 frameIndex = 1;
//             }
//         }
// };
    that.runRight = function() {
        tickCount += 1;
        that.topIndex = 0;
        if (tickCount > ticksPerFrame) {
            tickCount = 0;
            if (frameIndex < numberOfFrames -1) {
                frameIndex += 1;
            }
            else if (that.loop) {
                frameIndex = 1;
            }
            else {
                frameIndex = 1;
            }
        }

    };

    that.runLeft = function() {
        tickCount += 1;
        that.topIndex = 128;

        if (tickCount > ticksPerFrame) {
            tickCount = 0;
            if (frameIndex < numberOfFrames -1) {
                frameIndex += 1;
            }
            else if (that.loop) {
                frameIndex = 1;
            }
            else {
                frameIndex = 1;
            }
        }

    };

    that.jump = function() {
        frameIndex = 5;
    };
    that.move = function() {
        if (rightPressed === true && that.x < canvas.width - that.width / numberOfFrames) {
            that.x += xVelocity;
            that.runRight();
            // that.right = true;
            // that.left = false;
        }
        else if (leftPressed === true && that.x > 0) {
            that.x -= xVelocity;
            that.runLeft();
            // that.right = false;
            // that.left = true;
        }

        else if (upPressed === true) {
            that.jump();
        }
        else  {
            frameIndex = 0;
        }
    };

    return that;
}

var mario = sprite({
    context: canvas.getContext('2d'),
    width: 512,
    height: 128,
    topIndex: 0,
    image: marioImage,
    numberOfFrames: 4,
    ticksPerFrame: 8,
    x: 20,
    y: canvas.height - 148,
    xVelocity: 3,
    yVelocity: 0,
    // right: true,
    // left: false,
});

function gameLoop () {
    window.requestAnimationFrame(gameLoop);

    mario.render();
    mario.move();
}

// marioImage.addEventListener('load', gameLoop());
marioImage.addEventListener('load', gameLoop);

};
<commit_msg>Add reference, add gravity, change velo var names<commit_after>'use strict';
/**
 * src/mario.js
 *
 * Creates the Mario object
 *
*/
//The frames in the sprite sheet is 16x16px
//mario_wjlfy5.png
        // context.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh)
        // img Source image object
        // sx  Source x
        // sy  Source y
        // sw  Source width
        // sh  Source height
        // dx  Destination x
        // dy  Destination y
        // dw  Destination width
        // dh  Destination height

window.onload = function() {

var canvas = document.getElementById('game');
canvas.width = 640;
canvas.height = 480;
var marioImage = new Image();
marioImage.src = 'assets/mario_wjlfy5_large.png';
var rightPressed = false;
var leftPressed = false;
var upPressed = false;

document.addEventListener('keydown', keyDownHandler, false);
document.addEventListener('keyup', keyUpHandler, false);

function keyDownHandler(e) {
    if (e.keyCode == 39) {
        rightPressed = true;
    }
    else if (e.keyCode == 37) {
        leftPressed = true;
    }

    else if (e.keyCode == 38) {
        upPressed = true;
    }
}

function keyUpHandler(e) {
    if (e.keyCode == 39) {
        rightPressed = false;
    }
    else if (e.keyCode == 37) {
        leftPressed = false;
    }
    else if (e.keyCode == 38) {
        upPressed = false;
    }
}

function sprite (options) {
    var that = {},
        frameIndex = 0,
        tickCount = 0,
        ticksPerFrame = options.ticksPerFrame || 0,
        numberOfFrames = options.numberOfFrames || 1;

    that.context = options.context;
    that.width = options.width;
    that.height = options.height;
    that.image = options.image;
    that.x = options.x;
    that.y = options.y;
    that.xVelocity = options.xVelocity;
    that.yVelocity = options.yVelocity;
    that.gravity = options.gravity;
    // that.left = options.left;
    // that.right = options.right;
    that.topIndex = options.topIndex;

    that.render = function () {
        // Clear the canvas
        that.context.clearRect(0, 0, canvas.width, canvas.height);
        // Draw the animation
        that.context.drawImage (
            that.image,
            frameIndex * that.width / numberOfFrames,
            that.topIndex,
            that.width / numberOfFrames,
            that.height,
            that.x,
            that.y,
            that.width / numberOfFrames,
            that.height);
    };

    that.loop = options.loop;

//     that.update = function() {
//         tickCount += 1;

//         if (tickCount > ticksPerFrame) {
//             tickCount = 0;
//             if (frameIndex < numberOfFrames -1) {
//                 frameIndex += 1;
//             }
//             else if (that.loop) {
//                 frameIndex = 1;
//             }
//             else {
//                 frameIndex = 1;
//             }
//         }
// };
    that.runRight = function() {
        tickCount += 1;
        that.topIndex = 0;
        if (tickCount > ticksPerFrame) {
            tickCount = 0;
            if (frameIndex < numberOfFrames -1) {
                frameIndex += 1;
            }
            else if (that.loop) {
                frameIndex = 1;
            }
            else {
                frameIndex = 1;
            }
        }

    };

    that.runLeft = function() {
        tickCount += 1;
        that.topIndex = 128;

        if (tickCount > ticksPerFrame) {
            tickCount = 0;
            if (frameIndex < numberOfFrames -1) {
                frameIndex += 1;
            }
            else if (that.loop) {
                frameIndex = 1;
            }
            else {
                frameIndex = 1;
            }
        }

    };

    that.jump = function() {
        frameIndex = 5;
    };
    that.move = function() {
        if (rightPressed === true && that.x < canvas.width - that.width / numberOfFrames) {
            that.x += that.xVelocity;
            that.runRight();
            // that.right = true;
            // that.left = false;
        }
        else if (leftPressed === true && that.x > 0) {
            that.x -= that.xVelocity;
            that.runLeft();
            // that.right = false;
            // that.left = true;
        }

        else if (upPressed === true) {
            that.jump();
        }
        else  {
            frameIndex = 0;
        }
    };

    return that;
}

var mario = sprite({
    context: canvas.getContext('2d'),
    width: 512,
    height: 128,
    topIndex: 0,
    image: marioImage,
    numberOfFrames: 4,
    ticksPerFrame: 8,
    x: 20,
    y: canvas.height - 148,
    xVelocity: 3,
    yVelocity: 0,
    // right: true,
    // left: false,
});

function gameLoop () {
    window.requestAnimationFrame(gameLoop);

    mario.render();
    mario.move();
}

// marioImage.addEventListener('load', gameLoop());
marioImage.addEventListener('load', gameLoop);

};
<|endoftext|>


<commit_before>function standard_deviation(power, median, cv, multiplier) {
    /**
     * Return the standard deviation for a given lms parameters and multiplier.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param multiplier {Number}: the standard deviation to be retrieved.
     * @return {Number}
     */
    return median * Math.pow(1 + power * cv * multiplier, 1 / power);
}

function standard_deviation_3_pos(power, median, cv) {
    /**
     * Return the value of +3 standard deviations for a given lms.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @return {Number}
     */
    return standard_deviation(power, median, cv, 3);
}

function standard_deviation_3_neg(power, median, cv) {
    /**
     * Return the value of -3 standard deviations for a given lms.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @return {Number}
     */
    return standard_deviation(power, median, cv, -3);
}

function standard_deviation_2_pos(power, median, cv) {
    /**
     * Return the value of +2 standard deviations for a given lms.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @return {Number}
     */
    return standard_deviation(power, median, cv, 2);
}

function standard_deviation_2_neg(power, median, cv) {
    /**
     * Return the value of -2 standard deviations for a given lms.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @return {Number}
     */
    return standard_deviation(power, median, cv, -2);
}

function zscore_individual(measure, power, median, cv) {
    /**
     * Return the individual z score for a given measure and lms parameters.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param measure {Number}: the measured value.
     * @return {Number}
     */
    var correct_median = Math.pow(measure / median, power) - 1;
    var deviation = cv * power;
    return correct_median / deviation;
}

function zscore_fix(zscore, measure, power, median, cv) {
    /**
     * Return the fixed z score for scores less than -3 or greate than +3.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param zscore {Number}: the individual z score obtained.
     * @param measure {Number}: the measured value.
     * @return {Number}
     */
    if (Math.abs(zscore) <= 3) {
        return zscore;
    }

    var constant = null, deviation = null, deltadeviation = null;
    if (zscore > 3) {
        constant = 3;
        deviation = standard_deviation_3_pos(power, median, cv);
        deltadeviation = deviation - standard_deviation_2_pos(power, median, cv);
    } else {
        constant = -3;
        deviation = standard_deviation_3_neg(power, median, cv);
        deltadeviation = standard_deviation_2_neg(power, median, cv) - deviation;
    }

    return constant + (measure - deviation) / deltadeviation;
}

function to_zscore(measure, power, median, cv) {
    /**
     * Convert a given measure with lms parameters to z score.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param measure {Number}: the measured value.
     * @return {Number}
     */
    return zscore_fix(
        zscore_individual(measure, power, median, cv),
        measure,
        power,
        median,
        cv
    );
}

function to_measure(zscore, power, median, cv) {
    /**
     * Convert a given z score with lms parameters to a measure. The estimative
     * is only valid for -3 <= zscore <= 3.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param zscore {Number}: a given z score.
     * @return {Number}
     */
    return standard_deviation(power, median, cv, zscore);
}

/**
 * Testing
 */
function precision(value, decimal) {
    decimal = !isNaN(decimal) ? decimal : 4;
    return (value).toFixed(decimal);
}

var measures = [
    [30, -1.7862, 16.9392, 0.11070, 3.35],
    [14, -1.3529, 20.4951, 0.12579, -3.80],
    [19, -1.6318, 16.0490, 0.10038, 1.47]
];

measures.forEach(function (list) {
    var score = to_zscore(list[0], list[1], list[2], list[3]);
    console.log(
        precision((to_measure(score, list[1], list[2], list[3]))),
        list[0],
        precision((score)),
        list[4]);
});
<commit_msg>Update methods signature to receive hashs.<commit_after>function standard_deviation(options) {
    /**
     * Return the standard deviation for a given lms parameters and multiplier.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param multiplier {Number}: the standard deviation to be retrieved.
     * @return {Number}
     */
    var multiplier = options.multiplier,
        lms = options.lms;
    var variance = 1 + lms.power * lms.cv * multiplier;
    return lms.median * Math.pow(variance, 1 / lms.power);
}

function standard_deviation_3_pos(lms) {
    /**
     * Return the value of +3 standard deviations for a given lms.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @return {Number}
     */
    return standard_deviation({multiplier: 3, lms: lms});
}

function standard_deviation_3_neg(lms) {
    /**
     * Return the value of -3 standard deviations for a given lms.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @return {Number}
     */
    return standard_deviation({multiplier: -3, lms: lms});
}

function standard_deviation_2_pos(lms) {
    /**
     * Return the value of +2 standard deviations for a given lms.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @return {Number}
     */
    return standard_deviation({multiplier: 2, lms: lms});
}

function standard_deviation_2_neg(lms) {
    /**
     * Return the value of -2 standard deviations for a given lms.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @return {Number}
     */
    return standard_deviation({multiplier: -2, lms: lms});
}

function zscore_individual(options) {
    /**
     * Return the individual z score for a given measure and lms parameters.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param measure {Number}: the measured value.
     * @return {Number}
     */
    var measure = options.measure,
        lms = options.lms
    var correct_median = Math.pow(measure / lms.median, lms.power) - 1,
        deviation = lms.cv * lms.power;
    return correct_median / deviation;
}

function zscore_fix(options) {
    /**
     * Return the fixed z score for scores less than -3 or greate than +3.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param zscore {Number}: the individual z score obtained.
     * @param measure {Number}: the measured value.
     * @return {Number}
     */
    var zscore = options.zscore,
        measure = options.measure,
        lms = options.lms;

    if (Math.abs(zscore) <= 3) {
        return zscore;
    }

    var constant = null, deviation = null, deltadeviation = null;
    if (zscore > 3) {
        constant = 3;
        deviation = standard_deviation_3_pos(lms);
        deltadeviation = deviation - standard_deviation_2_pos(lms);
    } else {
        constant = -3;
        deviation = standard_deviation_3_neg(lms);
        deltadeviation = standard_deviation_2_neg(lms) - deviation;
    }

    return constant + (measure - deviation) / deltadeviation;
}

function to_zscore(options) {
    /**
     * Convert a given measure with lms parameters to z score.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param measure {Number}: the measured value.
     * @return {Number}
     */
    options.zscore = zscore_individual(options);
    return zscore_fix(options);
}

function to_measure(options) {
    /**
     * Convert a given z score with lms parameters to a measure. The estimative
     * is only valid for -3 <= zscore <= 3.
     * @param lms {Hash}: a dictionary containing the lms values:
     *     'power': the Box-Cox power (L),
     *     'median': the median value (M),
     *     'cv': the coefficient of variation (S).
     * @param zscore {Number}: a given z score.
     * @return {Number}
     */
    options.multiplier = options.zscore
    return standard_deviation(options);
}

/**
 * Testing
 */
function precision(value, decimal) {
    decimal = !isNaN(decimal) ? decimal : 4;
    return (value).toFixed(decimal);
}

var measures = [
    {measure: 30, lms: {power: -1.7862, median: 16.9392, cv: 0.11070}, expec: 3.35},
    {measure: 14, lms: {power: -1.3529, median: 20.4951, cv: 0.12579}, expec: -3.80},
    {measure: 19, lms: {power: -1.6318, median: 16.0490, cv: 0.10038}, expec: 1.47}
];

measures.forEach(function (options) {
    options.zscore = to_zscore(options);
    console.log(
        precision((to_measure(options))),
        options.measure,
        precision((score)),
        options.expec
    );
});
<|endoftext|>


<commit_before>
/*!
 * socket.io-node
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var http = require('http')
  , https = require('https')
  , fs = require('fs')
  , url = require('url')
  , util = require('./util')
  , store = require('./store')
  , transports = require('./transports')
  , Logger = require('./logger')
  , Socket = require('./socket')
  , MemoryStore = require('./stores/memory')
  , SocketNamespace = require('./namespace');

/**
 * Export the constructor.
 */

exports = module.exports = Manager;

/**
 * Default transports.
 */

var defaultTransports = exports.defaultTransports = [
    'websocket'
  , 'flashsocket'
  , 'htmlfile'
  , 'xhr-polling'
  , 'jsonp-polling'
];

/**
 * Inherited defaults.
 */

var parent = module.parent.exports
  , protocol = parent.protocol
  , clientVersion = parent.clientVersion;

/**
 * Manager constructor.
 *
 * @param {HTTPServer} server
 * @param {Object} options, optional
 * @api public
 */

function Manager (server) {
  this.server = server;
  this.namespaces = {};
  this.sockets = this.for('');
  this.settings = {
      origins: '*:*'
    , log: true
    , store: new MemoryStore
    , logger: new Logger
    , heartbeats: true
    , resource: '/socket.io'
    , transports: defaultTransports
    , authorization: false
    , 'log level': 3
    , 'close timeout': 25
    , 'heartbeat timeout': 15
    , 'heartbeat interval': 20
    , 'polling duration': 20
    , 'flash policy server': true
    , 'destroy upgrade': true
  };

  // reset listeners
  this.oldListeners = server.listeners('request');
  server.removeAllListeners('request');

  var self = this;

  server.on('request', function (req, res) {
    self.handleRequest(req, res);
  });

  server.on('upgrade', function (req, socket, head) {
    self.handleUpgrade(req, socket, head);
  });

  this.log.info('socket.io started');
};

/**
 * Store accessor shortcut.
 *
 * @api public
 */

Manager.prototype.__defineGetter__('store', function () {
  var store = this.get('store');
  store.manager = this;
  return store;
});

/**
 * Logger accessor.
 *
 * @api public
 */

Manager.prototype.__defineGetter__('log', function () {
  if (this.disabled('log')) return;

  var logger = this.get('logger');
  logger.level = this.set('log level');

  return logger;
});

/**
 * Get settings.
 *
 * @api public
 */

Manager.prototype.get = function (key) {
  return this.settings[key];
};

/**
 * Set settings
 *
 * @api public
 */

Manager.prototype.set = function (key, value) {
  if (arguments.length == 1) return this.get(key);
  this.settings[key] = value;
  return this;
};

/**
 * Enable a setting
 *
 * @api public
 */

Manager.prototype.enable = function (key) {
  this.settings[key] = true;
  return this;
};

/**
 * Disable a setting
 *
 * @api public
 */

Manager.prototype.disable = function (key) {
  this.settings[key] = false;
  return this;
};

/**
 * Checks if a setting is enabled
 *
 * @api public
 */

Manager.prototype.enabled = function (key) {
  return !!this.settings[key];
};

/**
 * Checks if a setting is disabled
 *
 * @api public
 */

Manager.prototype.disabled = function (key) {
  return !this.settings[key];
};

/**
 * Configure callbacks.
 *
 * @api public
 */

Manager.prototype.configure = function (env, fn) {
  if ('function' == typeof env) {
    env();
  } else if (env == process.env.NODE_ENV) {
    fn();
  }

  return this;
};

/**
 * Handles an HTTP request.
 *
 * @api private
 */

Manager.prototype.handleRequest = function (req, res) {
  var data = this.checkRequest(req);

  if (!data) {
    this.log.debug('ignoring request outside socket.io namespace');

    for (var i = 0, l = this.oldListeners.length; i < l; i++)
      this.oldListeners[i].call(this, req, res);

    return;
  }

  if (!data.transport && !data.protocol) {
    if (data.path == '/socket.io.js') {
      this.handleClientRequest(req, res);
    } else {
      res.writeHead(200);
      res.end('Welcome to socket.io.');

      this.log.info('unhandled socket.io url');
    }

    return;
  }

  if (data.protocol != protocol) {
    res.writeHead(500);
    res.end('Protocol version not supported.');

    this.log.info('client protocol version unsupported');
  } else {
    if (data.id) {
      this.handleHTTPRequest(data, req, res);
    } else {
      this.handleHandshake(data, req, res);
    }
  }
};

/**
 * Handles an HTTP Upgrade.
 *
 * @api private
 */

Manager.prototype.handleUpgrade = function (req, socket, head) {
  var data = this.checkRequest(req)
    , self = this;

  if (!data) {
    if (this.enabled('destroy upgrade')) {
      socket.end();
      this.log.debug('destroying non-socket.io upgrade');
    }

    return;
  }

  req.head = head;
  this.handleClient(data, req);
};

/**
 * Handles a normal handshaken HTTP request (eg: long-polling)
 *
 * @api private
 */

Manager.prototype.handleHTTPRequest = function (data, req, res) {
  req.res = res;
  this.handleClient(data, req);
};

/**
 * Intantiantes a new client.
 *
 * @api private
 */

Manager.prototype.handleClient = function (data, req) {
  var socket = req.socket
    , newTransport = false
    , self = this;

  if (undefined != data.query.disconnect) {
    self.log.debug('handling disconnection url');
    self.store.disconnect(data.id, true);
    return;
  }

  if (!~this.get('transports').indexOf(data.transport)) {
    this.log.warn('unknown transport: "' + data.transport + '"');
    req.connection.end();
    return;
  }

  var transport = new transports[data.transport](this, data);
  transport.pause();
  transport.request = req;

  if (!transport.open) {
    this.log.debug('transport not writeable, not subscribing');
    return;
  }

  if (req.socket.__ioTransport) {
    // if the request comes through a validated socket, avoid roundtrips
    transport.resume();
    return;
  }

  this.store.isHandshaken(data.id, function (err, handshaken) {
    if (err || !handshaken) {
      if (err) console.error(err);
      transport.error('client not handshaken');
      return;
    }

    self.store.client(data.id).count(function (err, count) {
      if (count == 1) {
        // initialize the socket for all namespaces
        for (var i in self.namespaces) {
          self.namespaces[i].socket(data.id, true);
        }

        // handle packets for the client (all namespaces)
        self.store.on('message:' + data.id, function (packet) {
          self.log.info('manager received client packet');
          self.handlePacket(data.id, packet);
        });
      }

      req.socket.__ioTransport = transport;
      transport.resume();
    });
  });
};

/**
 * Serves the client.
 *
 * @api private
 */

Manager.prototype.handleClientRequest = function (req, res) {
  var self = this;

  function serve () {
    if (!self.clientLength)
      self.clientLength = Buffer.byteLength(self.client);

    var headers = {
        'Content-Type': 'application/javascript'
      , 'Content-Length': self.clientLength
    };

    if (self.clientEtag)
      headers.ETag = self.clientEtag;

    res.writeHead(200, headers);
    res.end(self.client);

    self.log.debug('served client');
  };

  if (!this.client) {
    if (this.get('browser client')) {
      this.client = this.get('browser client');
      this.clientEtag = this.get('browser client etag');

      this.log.debug('caching custom client');

      serve();
    } else {
      var self = this;

      fs.readFile(__dirname + '/client/socket.io.min.js', function (err, data) {
        if (err) {
          res.writeHead(500);
          res.end('Error serving socket.io client.');

          self.log.warn('Can\'t cache socket.io client');
          return;
        }

        self.client = data.toString();
        self.clientEtag = clientVersion;
        self.log.debug('caching', clientVersion, 'client');

        serve();
      });
    }
  }
};

/**
 * Handles a handshake request.
 *
 * @api private
 */

Manager.prototype.handleHandshake = function (data, req, res) {
  var self = this;

  function writeErr (status, message) {
    if (data.query.jsonp) {
      res.writeHead(200);
      res.end('io.j[' + data.query.jsonp + '](new Error(' + message + '));');
    } else {
      res.writeHead(status);
      res.end(message);
    }
  };

  function error (err) {
    writeErr(500, 'handshake error');
    self.log.warn('handshake error ' + err);
  };

  if (!this.verifyOrigin(req)) {
    writeErr(403, 'handshake bad origin');
    return;
  }

  this.authorize(data, function (err, authorized) {
    if (err) return error(err);

    self.log.info('handshake ' + (authorized ? 'authorized' : 'unauthorized'));

    if (authorized) {
      self.store.handshake(data, function (err, id) {
        if (err) return error(err);

        var hs = [
            id
          , self.get('heartbeat timeout') || ''
          , self.get('close timeout') || ''
          , self.transports(data).join(',')
        ].join(':');

        if (data.query.jsonp)
          hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');';

        res.writeHead(200);
        res.end(hs);
      });
    } else {
      writeErr(403, 'handshake unauthorized');
    }
  })
};

/**
 * Verifies the origin of a request.
 *
 * @api private
 */

Manager.prototype.verifyOrigin = function (request) {
  var origin = request.headers.origin
    , origins = this.get('origins');

  if (origin === 'null') origin = '*';

  if (origins.indexOf('*:*') !== -1) {
    return true;
  }

  if (origin) {
    try {
      var parts = url.parse(origin);

      return
        ~origins.indexOf(parts.host + ':' + parts.port) ||
        ~origins.indexOf(parts.host + ':*') ||
        ~origins.indexOf('*:' + parts.port);
    } catch (ex) {}
  }

  return false;
};

/**
 * Handles an incoming packet.
 *
 * @api private
 */

Manager.prototype.handlePacket = function (sessid, packet) {
  this.for(packet.endpoint || '').handlePacket(sessid, packet);
};

/**
 * Performs authentication.
 *
 * @param Object client request data
 * @api private
 */

Manager.prototype.authorize = function (data, fn) {
  if (this.get('authorization')) {
    var self = this;

    this.get('authorization').call(this, data, function (err, authorized) {
      self.log.debug('client ' + authorized ? 'authorized' : 'unauthorized');
      fn(err, authorized);
    });
  } else {
    this.log.debug('client authorized');
    fn(null, true);
  }

  return this;
};

/**
 * Retrieves the transports adviced to the user.
 *
 * @api private
 */

Manager.prototype.transports = function (data) {
  var transp = this.get('transports')
    , ret = [];

  for (var i = 0, l = transp.length; i < l; i++) {
    var transport = transp[i];

    if (transport) {
      if (!transport.checkClient || transport.checkClient(data)) {
        ret.push(transport);
      }
    }
  }

  return ret;
};

/**
 * Checks whether a request is a socket.io one.
 *
 * @return {Object} a client request data object or `false`
 * @api private
 */

var regexp = /^\/([^\/]+)\/?([^\/]+)?\/?([^\/]+)?\/?$/

Manager.prototype.checkRequest = function (req) {
  var resource = this.get('resource');

  if (req.url.substr(0, resource.length) == resource) {
    var uri = url.parse(req.url.substr(resource.length), true)
      , path = uri.pathname || ''
      , pieces = path.match(regexp);

    // client request data
    var data = {
        query: uri.query || {}
      , headers: req.headers
      , request: req
      , path: path
    };

    if (pieces) {
      data.protocol = Number(pieces[1]);
      data.transport = pieces[2];
      data.id = pieces[3];
    };

    return data;
  }

  return false;
};

/**
 * Declares a socket namespace
 */

Manager.prototype.for = function (nsp) {
  if (this.namespaces[nsp]) {
    return this.namespaces[nsp];
  }

  return this.namespaces[nsp] = new SocketNamespace(this, nsp);
};
<commit_msg>Fixed old listeners calls.<commit_after>
/*!
 * socket.io-node
 * Copyright(c) 2011 LearnBoost <dev@learnboost.com>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var http = require('http')
  , https = require('https')
  , fs = require('fs')
  , url = require('url')
  , util = require('./util')
  , store = require('./store')
  , transports = require('./transports')
  , Logger = require('./logger')
  , Socket = require('./socket')
  , MemoryStore = require('./stores/memory')
  , SocketNamespace = require('./namespace');

/**
 * Export the constructor.
 */

exports = module.exports = Manager;

/**
 * Default transports.
 */

var defaultTransports = exports.defaultTransports = [
    'websocket'
  , 'flashsocket'
  , 'htmlfile'
  , 'xhr-polling'
  , 'jsonp-polling'
];

/**
 * Inherited defaults.
 */

var parent = module.parent.exports
  , protocol = parent.protocol
  , clientVersion = parent.clientVersion;

/**
 * Manager constructor.
 *
 * @param {HTTPServer} server
 * @param {Object} options, optional
 * @api public
 */

function Manager (server) {
  this.server = server;
  this.namespaces = {};
  this.sockets = this.for('');
  this.settings = {
      origins: '*:*'
    , log: true
    , store: new MemoryStore
    , logger: new Logger
    , heartbeats: true
    , resource: '/socket.io'
    , transports: defaultTransports
    , authorization: false
    , 'log level': 3
    , 'close timeout': 25
    , 'heartbeat timeout': 15
    , 'heartbeat interval': 20
    , 'polling duration': 20
    , 'flash policy server': true
    , 'destroy upgrade': true
  };

  // reset listeners
  this.oldListeners = server.listeners('request');
  server.removeAllListeners('request');

  var self = this;

  server.on('request', function (req, res) {
    self.handleRequest(req, res);
  });

  server.on('upgrade', function (req, socket, head) {
    self.handleUpgrade(req, socket, head);
  });

  this.log.info('socket.io started');
};

/**
 * Store accessor shortcut.
 *
 * @api public
 */

Manager.prototype.__defineGetter__('store', function () {
  var store = this.get('store');
  store.manager = this;
  return store;
});

/**
 * Logger accessor.
 *
 * @api public
 */

Manager.prototype.__defineGetter__('log', function () {
  if (this.disabled('log')) return;

  var logger = this.get('logger');
  logger.level = this.set('log level');

  return logger;
});

/**
 * Get settings.
 *
 * @api public
 */

Manager.prototype.get = function (key) {
  return this.settings[key];
};

/**
 * Set settings
 *
 * @api public
 */

Manager.prototype.set = function (key, value) {
  if (arguments.length == 1) return this.get(key);
  this.settings[key] = value;
  return this;
};

/**
 * Enable a setting
 *
 * @api public
 */

Manager.prototype.enable = function (key) {
  this.settings[key] = true;
  return this;
};

/**
 * Disable a setting
 *
 * @api public
 */

Manager.prototype.disable = function (key) {
  this.settings[key] = false;
  return this;
};

/**
 * Checks if a setting is enabled
 *
 * @api public
 */

Manager.prototype.enabled = function (key) {
  return !!this.settings[key];
};

/**
 * Checks if a setting is disabled
 *
 * @api public
 */

Manager.prototype.disabled = function (key) {
  return !this.settings[key];
};

/**
 * Configure callbacks.
 *
 * @api public
 */

Manager.prototype.configure = function (env, fn) {
  if ('function' == typeof env) {
    env();
  } else if (env == process.env.NODE_ENV) {
    fn();
  }

  return this;
};

/**
 * Handles an HTTP request.
 *
 * @api private
 */

Manager.prototype.handleRequest = function (req, res) {
  var data = this.checkRequest(req);

  if (!data) {
    this.log.debug('ignoring request outside socket.io namespace');

    for (var i = 0, l = this.oldListeners.length; i < l; i++)
      this.oldListeners[i].call(this.server, req, res);

    return;
  }

  if (!data.transport && !data.protocol) {
    if (data.path == '/socket.io.js') {
      this.handleClientRequest(req, res);
    } else {
      res.writeHead(200);
      res.end('Welcome to socket.io.');

      this.log.info('unhandled socket.io url');
    }

    return;
  }

  if (data.protocol != protocol) {
    res.writeHead(500);
    res.end('Protocol version not supported.');

    this.log.info('client protocol version unsupported');
  } else {
    if (data.id) {
      this.handleHTTPRequest(data, req, res);
    } else {
      this.handleHandshake(data, req, res);
    }
  }
};

/**
 * Handles an HTTP Upgrade.
 *
 * @api private
 */

Manager.prototype.handleUpgrade = function (req, socket, head) {
  var data = this.checkRequest(req)
    , self = this;

  if (!data) {
    if (this.enabled('destroy upgrade')) {
      socket.end();
      this.log.debug('destroying non-socket.io upgrade');
    }

    return;
  }

  req.head = head;
  this.handleClient(data, req);
};

/**
 * Handles a normal handshaken HTTP request (eg: long-polling)
 *
 * @api private
 */

Manager.prototype.handleHTTPRequest = function (data, req, res) {
  req.res = res;
  this.handleClient(data, req);
};

/**
 * Intantiantes a new client.
 *
 * @api private
 */

Manager.prototype.handleClient = function (data, req) {
  var socket = req.socket
    , newTransport = false
    , self = this;

  if (undefined != data.query.disconnect) {
    self.log.debug('handling disconnection url');
    self.store.disconnect(data.id, true);
    return;
  }

  if (!~this.get('transports').indexOf(data.transport)) {
    this.log.warn('unknown transport: "' + data.transport + '"');
    req.connection.end();
    return;
  }

  var transport = new transports[data.transport](this, data);
  transport.pause();
  transport.request = req;

  if (!transport.open) {
    this.log.debug('transport not writeable, not subscribing');
    return;
  }

  if (req.socket.__ioTransport) {
    // if the request comes through a validated socket, avoid roundtrips
    transport.resume();
    return;
  }

  this.store.isHandshaken(data.id, function (err, handshaken) {
    if (err || !handshaken) {
      if (err) console.error(err);
      transport.error('client not handshaken');
      return;
    }

    self.store.client(data.id).count(function (err, count) {
      if (count == 1) {
        // initialize the socket for all namespaces
        for (var i in self.namespaces) {
          self.namespaces[i].socket(data.id, true);
        }

        // handle packets for the client (all namespaces)
        self.store.on('message:' + data.id, function (packet) {
          self.log.info('manager received client packet');
          self.handlePacket(data.id, packet);
        });
      }

      req.socket.__ioTransport = transport;
      transport.resume();
    });
  });
};

/**
 * Serves the client.
 *
 * @api private
 */

Manager.prototype.handleClientRequest = function (req, res) {
  var self = this;

  function serve () {
    if (!self.clientLength)
      self.clientLength = Buffer.byteLength(self.client);

    var headers = {
        'Content-Type': 'application/javascript'
      , 'Content-Length': self.clientLength
    };

    if (self.clientEtag)
      headers.ETag = self.clientEtag;

    res.writeHead(200, headers);
    res.end(self.client);

    self.log.debug('served client');
  };

  if (!this.client) {
    if (this.get('browser client')) {
      this.client = this.get('browser client');
      this.clientEtag = this.get('browser client etag');

      this.log.debug('caching custom client');

      serve();
    } else {
      var self = this;

      fs.readFile(__dirname + '/client/socket.io.min.js', function (err, data) {
        if (err) {
          res.writeHead(500);
          res.end('Error serving socket.io client.');

          self.log.warn('Can\'t cache socket.io client');
          return;
        }

        self.client = data.toString();
        self.clientEtag = clientVersion;
        self.log.debug('caching', clientVersion, 'client');

        serve();
      });
    }
  }
};

/**
 * Handles a handshake request.
 *
 * @api private
 */

Manager.prototype.handleHandshake = function (data, req, res) {
  var self = this;

  function writeErr (status, message) {
    if (data.query.jsonp) {
      res.writeHead(200);
      res.end('io.j[' + data.query.jsonp + '](new Error(' + message + '));');
    } else {
      res.writeHead(status);
      res.end(message);
    }
  };

  function error (err) {
    writeErr(500, 'handshake error');
    self.log.warn('handshake error ' + err);
  };

  if (!this.verifyOrigin(req)) {
    writeErr(403, 'handshake bad origin');
    return;
  }

  this.authorize(data, function (err, authorized) {
    if (err) return error(err);

    self.log.info('handshake ' + (authorized ? 'authorized' : 'unauthorized'));

    if (authorized) {
      self.store.handshake(data, function (err, id) {
        if (err) return error(err);

        var hs = [
            id
          , self.get('heartbeat timeout') || ''
          , self.get('close timeout') || ''
          , self.transports(data).join(',')
        ].join(':');

        if (data.query.jsonp)
          hs = 'io.j[' + data.query.jsonp + '](' + JSON.stringify(hs) + ');';

        res.writeHead(200);
        res.end(hs);
      });
    } else {
      writeErr(403, 'handshake unauthorized');
    }
  })
};

/**
 * Verifies the origin of a request.
 *
 * @api private
 */

Manager.prototype.verifyOrigin = function (request) {
  var origin = request.headers.origin
    , origins = this.get('origins');

  if (origin === 'null') origin = '*';

  if (origins.indexOf('*:*') !== -1) {
    return true;
  }

  if (origin) {
    try {
      var parts = url.parse(origin);

      return
        ~origins.indexOf(parts.host + ':' + parts.port) ||
        ~origins.indexOf(parts.host + ':*') ||
        ~origins.indexOf('*:' + parts.port);
    } catch (ex) {}
  }

  return false;
};

/**
 * Handles an incoming packet.
 *
 * @api private
 */

Manager.prototype.handlePacket = function (sessid, packet) {
  this.for(packet.endpoint || '').handlePacket(sessid, packet);
};

/**
 * Performs authentication.
 *
 * @param Object client request data
 * @api private
 */

Manager.prototype.authorize = function (data, fn) {
  if (this.get('authorization')) {
    var self = this;

    this.get('authorization').call(this, data, function (err, authorized) {
      self.log.debug('client ' + authorized ? 'authorized' : 'unauthorized');
      fn(err, authorized);
    });
  } else {
    this.log.debug('client authorized');
    fn(null, true);
  }

  return this;
};

/**
 * Retrieves the transports adviced to the user.
 *
 * @api private
 */

Manager.prototype.transports = function (data) {
  var transp = this.get('transports')
    , ret = [];

  for (var i = 0, l = transp.length; i < l; i++) {
    var transport = transp[i];

    if (transport) {
      if (!transport.checkClient || transport.checkClient(data)) {
        ret.push(transport);
      }
    }
  }

  return ret;
};

/**
 * Checks whether a request is a socket.io one.
 *
 * @return {Object} a client request data object or `false`
 * @api private
 */

var regexp = /^\/([^\/]+)\/?([^\/]+)?\/?([^\/]+)?\/?$/

Manager.prototype.checkRequest = function (req) {
  var resource = this.get('resource');

  if (req.url.substr(0, resource.length) == resource) {
    var uri = url.parse(req.url.substr(resource.length), true)
      , path = uri.pathname || ''
      , pieces = path.match(regexp);

    // client request data
    var data = {
        query: uri.query || {}
      , headers: req.headers
      , request: req
      , path: path
    };

    if (pieces) {
      data.protocol = Number(pieces[1]);
      data.transport = pieces[2];
      data.id = pieces[3];
    };

    return data;
  }

  return false;
};

/**
 * Declares a socket namespace
 */

Manager.prototype.for = function (nsp) {
  if (this.namespaces[nsp]) {
    return this.namespaces[nsp];
  }

  return this.namespaces[nsp] = new SocketNamespace(this, nsp);
};
<|endoftext|>


<commit_before>
var fetch = require('isomorphic-fetch');
var bindActionCreators = require('redux').bindActionCreators;

var createAction = require('./store').createAction;

function normalizeOptions(defaults, overrides) {
  if (typeof defaults === 'string') {
    defaults = { url: defaults };
  }
  if (typeof overrides === 'string') {
    overrides = { url: overrides };
  }
  return Object.assign({}, defaults, overrides);
}

function generateHandlers(actions, dispatch) {
  var defaults = {
    requestWillStart: function () {},
    responseWasReceived: function (data) { return data; },
    errorWasReceived: function (error) { throw error; }
  };
  var overrides = bindActionCreators(actions, dispatch);
  return Object.assign({}, defaults, overrides);
}

function composeFetchAction(actions, defaults) {
  return function (overrides) {
    var options = normalizeOptions(defaults, overrides);
    return function (dispatch) {
      var handlers = generateHandlers(actions, dispatch);
      handlers.requestWillStart();
      return fetch(options.url, options)
      .then(function (response) {
        if (response.status >= 200 && response.status <= 304) {
          return response.json();
        }
        else {
          throw Object.assign(
            new Error(response.statusText),
            { response: response }
          );
        }
      })
      .then(handlers.responseWasReceived)
      .catch(handlers.errorWasReceived);
    };
  };
}

exports.createFetchAction = function (key, defaults) {
  var update = createAction(key);
  var actions = {
    requestWillStart: function () {
      return update({'$merge': {
        loaded: false,
        loading: true
      }});
    },
    responseWasReceived: function (data) {
      return update({'$merge': {
        loaded: true,
        loading: false,
        error: false,
        data: data
      }});
    },
    errorWasReceived: function (error) {
      return update({'$merge': {
        loaded: false,
        loading: false,
        error: error.message
      }});
    }
  };
  return composeFetchAction(actions, defaults);
};

exports.composeFetchAction = composeFetchAction;
<commit_msg>finalizing fetch/redux integration, make it mockable<commit_after>
var fetch = require('isomorphic-fetch');
var Redux = require('redux');

var createAction = require('./store').createAction;

var customOptions = ['url', 'onStart', 'onSuccess', 'onError'];
var mocks = {};

function isString(object) {
  return (typeof object === 'string');
}

function processOptions(defaults, overrides) {
  return Object.assign(
    {},
    isString(defaults) ? { url: defaults } : defaults,
    isString(overrides) ? { url: overrides } : overrides
  );
}

function filterOptions(options) {
  return Object.keys(options).reduce(function (result, key) {
    if (customOptions.indexOf(key) !== -1) {
      result[key] = options.key;
    }
    return result;
  }, {});
}

function doFetch(options, updates) {
  updates.onStart();
  return Promise.resolve().then(function () {
    if (options.url in mocks) {
      return mocks[options.url](options);
    }
    else {
      return fetch(options.url, filterOptions(options))
      .then(function (response) {
        if (response.status >= 200 && response.status <= 304) {
          return response.json();
        }
        else {
          throw Object.assign(
            new Error(response.statusText),
            { response: response }
          );
        }
      });
    }
  })
  .then(updates.onSuccess)
  .catch(updates.onError);
}

exports.createFetchAction = function (key, defaults) {
  var update = createAction(key);
  return function (overrides) {
    var options = processOptions(defaults, overrides);
    var bindUpdates = Redux.bindActionCreators.bind(Redux, {
      onStart: options.onStart || function () {
        return update({'$merge': {
          loaded: false,
          loading: true
        }});
      },
      onSuccess: options.onSuccess || function (data) {
        return update({'$merge': {
          loaded: true,
          loading: false,
          error: false,
          data: data
        }});
      },
      onError: options.onError || function (error) {
        return update({'$merge': {
          loaded: false,
          loading: false,
          error: error.message
        }});
      }
    });
    return function (dispatch) {
      return doFetch(options, bindUpdates(dispatch));
    };
  };
};

exports.mockFetch = function (url, value) {
  if (typeof value === 'undefined') {
    delete mocks[url];
  }
  else {
    mocks[url] = function (options) {
      if (typeof value === 'function') {
        return value(options);
      }
      else {
        return Promise.resolve(value);
      }
    };
  }
};
<|endoftext|>


<commit_before>/**
 * Kit is module by modules
 *
 * @module telekit/kit
 * @author Denis Maslennikov <mrdenniska@gmail.com> (nofach.com)
 * @license MIT
 */

/** Dependencies */
const teleapi = require('teleapi');

const Context = require('./context.js');
const Client = require('./client/index.js');
const Basic = require('./basic.js');

/** Implementation */
class Telekit extends Basic {
    constructor(options) {
        super();

        /** Create API instance with help of teleapi */
        const API = teleapi(options.token);

        /** Options */
        this.options = options;

        /** Global Context */
        this.context = Context(this);

        /** Client for Telegram Bot API */
        this.client = Client(API, this.options);
        if (this.client) this.client.on('update', this.fetch.bind(this));

        /** Global Telegram Bot API */
        this.api = API;
    }

    handle(update, info) {
        this.context.update = update[info.name];

        this.emit('beforeUpdate', this.context, info);

        if (this.update) this.update(this.context);
        this.emit('update', this.context, info);

        this.dispatch('update', this.context, info).then(() => {
            if (this[info.name]) this[info.name](this.context);
            this.emit(info.name, this.context);

            return this.dispatch(info.name, this.context);
        }).then(() => {
            this.emit('afterUpdate', this.context, info);
        });
    }
}

/** Exports */
module.exports = Telekit;
<commit_msg>telekit: now context is required only API.<commit_after>/**
 * Kit is module by modules
 *
 * @module telekit/kit
 * @author Denis Maslennikov <mrdenniska@gmail.com> (nofach.com)
 * @license MIT
 */

/** Dependencies */
const teleapi = require('teleapi');

const Context = require('./context.js');
const Client = require('./client/index.js');
const Basic = require('./basic.js');

/** Implementation */
class Telekit extends Basic {
    constructor(options) {
        super();

        /** Create API instance with help of teleapi */
        const API = teleapi(options.token);

        /** Options */
        this.options = options;

        /** Global Context */
        this.context = Context(API);

        /** Client for Telegram Bot API */
        this.client = Client(API, this.options);
        if (this.client) this.client.on('update', this.fetch.bind(this));

        /** Global Telegram Bot API */
        this.api = API;
    }

    handle(update, info) {
        this.context.update = update[info.name];

        this.emit('beforeUpdate', this.context, info);

        if (this.update) this.update(this.context);
        this.emit('update', this.context, info);

        this.dispatch('update', this.context, info).then(() => {
            if (this[info.name]) this[info.name](this.context);
            this.emit(info.name, this.context);

            return this.dispatch(info.name, this.context);
        }).then(() => {
            this.emit('afterUpdate', this.context, info);
        });
    }
}

/** Exports */
module.exports = Telekit;
<|endoftext|>