<commit_before>"use strict";

console.log('tab-content-script');

/*
    For now, huge parts are copy/pasted from previous scripts.
    Priority to getting something working
    TODO : when getting back to TS, clean this up

 */

// SimpleGraph

var SimpleGraph = (function () {
    function SimpleGraph() {
        this.nodes = new Set();
        this.edges = new Set();
    }
    SimpleGraph.prototype.toJSON = function () {
        var rootIndices = [];
        var nodes = [];

        var getIndex = (function () {
            var wm = new WeakMap();

            return function (n) {
                var index = wm.get(n);
                var serializableNode;

                if (index === undefined) {
                    index = nodes.length;
                    serializableNode = { outgoingEdges: [] };

                    if (n.callable)
                        serializableNode.class = 'function';

                    if (n.root)
                        serializableNode.class = 'root';

                    if (n.callee)
                        serializableNode.class = 'scope';

                    nodes[index] = serializableNode;
                    wm.set(n, index);
                }

                return index;
            };
        })();

        this.roots.forEach(function (r) {
            return getIndex(r);
        });
        rootIndices = [];
        nodes.forEach(function (root, i) {
            return rootIndices.push(i);
        });

        this.edges.forEach(function (e) {
            var label;
            var data = e.data;

            var serializedEdge = {
                to: getIndex(e.to)
            };

            if (data.dataProperty)
                serializedEdge.label = data.dataProperty;
            if (data.getter)
                serializedEdge.label = '[[Getter]] ' + data.getter;
            if (data.setter)
                serializedEdge.label = '[[Setter]] ' + data.setter;
            if (data.variable)
                serializedEdge.label = data.variable;

            if (data.variable)
                serializedEdge.class = 'variable';
            if (data.type === 'parent-scope')
                serializedEdge.class = 'parent-scope';
            if (data.type === 'lexical-scope')
                serializedEdge.class = 'lexical-scope';

            var from = nodes[getIndex(e.from)];
            from.outgoingEdges.push(serializedEdge);
        });

        var serializable = {
            rootIndices: rootIndices,
            nodes: nodes
        };

        console.log('JSON.stringify(serializable).length', JSON.stringify(serializable).length);

        return serializable;
    };
    return SimpleGraph;
})();

// ConnectedGraph

"use strict";
var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var ConnectedGraphVertex = (function () {
    function ConnectedGraphVertex(data) {
        this.data = data;
        Object.freeze(this);
    }
    return ConnectedGraphVertex;
})();

var ConnectedGraphEdge = (function () {
    function ConnectedGraphEdge(from, to, data) {
        this.from = from;
        this.to = to;
        this.data = data;
        Object.freeze(this);
    }
    ConnectedGraphEdge.sameData = function (data1, data2) {
        return Object.keys(data1).length === Object.keys(data2).length && Object.keys(data1).every(function (prop) {
            return Object.is(data1[prop], data2[prop]);
        });
    };
    return ConnectedGraphEdge;
})();

var ConnectedGraph = (function () {
    function ConnectedGraph(roots) {
        this.roots = roots;
    }
    ConnectedGraph.prototype.addEdge = function (from, to, data) {
        var allEdges = ConnectedGraph.allEdges;

        var fromEdges = allEdges.get(from);

        var addedEdge;

        if (fromEdges) {
            var fromEdgesIt = fromEdges.values();
            var iter = fromEdgesIt.next();

            while (!iter.done && !addedEdge) {
                var candidate = iter.value;

                if (candidate.from == from && candidate.to == to && ConnectedGraphEdge.sameData(candidate.data, data)) {
                    addedEdge = candidate;
                    break;
                }

                iter = fromEdgesIt.next();
            }
        }

        if (!addedEdge) {
            addedEdge = new ConnectedGraphEdge(from, to, data);

            var fromSet = allEdges.get(from);
            if (!fromSet) {
                fromSet = new Set();
                allEdges.set(from, fromSet);
            }
            fromSet.add(addedEdge);

            var toSet = allEdges.get(to);
            if (!toSet) {
                toSet = new Set();
                allEdges.set(to, toSet);
            }
            toSet.add(addedEdge);
        }

        var addedEdgeGraphSet = ConnectedGraph.edge2graph.get(addedEdge);
        if (!addedEdgeGraphSet) {
            addedEdgeGraphSet = new Set();
            ConnectedGraph.edge2graph.set(addedEdge, addedEdgeGraphSet);
        }

        addedEdgeGraphSet.add(this);

        return addedEdge;
    };

    ConnectedGraph.prototype.getOutgoingEdges = function (n) {
        var s = new Set();

        var candidates = ConnectedGraph.allEdges.get(n);
        var candidatesIt = candidates.values();
        var iter = candidatesIt.next();

        while (!iter.done) {
            var candidateEdge = iter.value;

            if (ConnectedGraph.edge2graph.get(candidateEdge).has(this) && candidateEdge.from === n) {
                s.add(candidateEdge);
            }

            iter = candidatesIt.next();
        }

        return s;
    };

    ConnectedGraph.prototype.getIncomingEdges = function (n) {
        var s = new Set();

        var candidates = ConnectedGraph.allEdges.get(n);
        var candidatesIt = candidates.values();
        var iter = candidatesIt.next();

        while (!iter.done) {
            var candidateEdge = iter.value;

            if (ConnectedGraph.edge2graph.get(candidateEdge).has(this) && candidateEdge.to === n) {
                s.add(candidateEdge);
            }

            iter = candidatesIt.next();
        }

        return s;
    };
    ConnectedGraph.allEdges = new WeakMap();

    ConnectedGraph.edge2graph = new WeakMap();
    return ConnectedGraph;
})();

var DifferenceGraph = (function (_super) {
    __extends(DifferenceGraph, _super);
    function DifferenceGraph(from, to) {
        throw 'TODO';
        _super.call(this, from.roots);
    }
    return DifferenceGraph;
})(ConnectedGraph);

// traverseGraph

var addDebuggerToGlobal = Components.utils.import("resource://gre/modules/jsdebugger.jsm").addDebuggerToGlobal;
addDebuggerToGlobal(this);

// var ConnectedGraphVertex = ConnectedGraphImports.ConnectedGraphVertex;
// var ConnectedGraphEdge = ConnectedGraphImports.ConnectedGraphEdge;
// var ConnectedGraph = ConnectedGraphImports.ConnectedGraph;

Debugger.Object.prototype.toString = function () {
    var object = this;
    var jsonableCopy = {};

    object.getOwnPropertyNames().forEach(function (prop) {
        var desc = object.getOwnPropertyDescriptor(prop);
        jsonableCopy[prop] = desc.value;
    });

    return JSON.stringify(jsonableCopy);
};
Debugger.Object.prototype.toJSON = Debugger.Object.prototype.toString;

var dbg = new Debugger();
dbg.uncaughtExceptionHook = function (e) {
    console.error('uncaughtExceptionHook', e, e.stack);
};

Debugger.Object.prototype.byPath = function (path) {
    return path.split('.').reduce(function (acc, curr) {
        if (acc) {
            var desc = acc.getOwnPropertyDescriptor(curr);
            if (!desc || !desc.value)
                return undefined;
            else
                return desc.value;
        } else
            return undefined;
    }, this);
};

function traverseGraph(window, graph) {
    console.log('traverse');
    var globalDebugObject = dbg.addDebuggee(window);

    var done = new Set();
    var todo = new Set();

    var windowProxyDebuggeeObject = globalDebugObject.getOwnPropertyDescriptor('window').value;
    windowProxyDebuggeeObject.root = true;

    todo.add(windowProxyDebuggeeObject);

    graph.roots = new Set([windowProxyDebuggeeObject]);

    var debuggeeObjectPrototype = windowProxyDebuggeeObject.byPath('Object.prototype');

    function hasDefaultPrototype(func, proto) {
        var protoProps = proto.getOwnPropertyNames();

        try  {
            var constructor = proto.getOwnPropertyDescriptor('constructor').value;
        } catch (e) {
            console.error('constructor is not a data property', proto.getOwnPropertyDescriptor('constructor'), e);
            return false;
        }
        return protoProps.length === 1 && constructor === func && proto.proto === debuggeeObjectPrototype;
    }

    while (todo.size !== 0) {
        var todoIt = todo.values();

        while (true) {
            var next = todoIt.next();

            if (next.done)
                break;

            var inspected = next.value;
            todo.delete(inspected);
            done.add(inspected);

            graph.nodes.add(inspected);

            if (inspected instanceof Debugger.Object) {
                var inspectedObj = inspected;

                var props = inspectedObj.getOwnPropertyNames();

                props.forEach(function (p) {
                    var desc = inspectedObj.getOwnPropertyDescriptor(p);
                    var details;

                    var value = desc.value;

                    if (value instanceof Debugger.Object) {
                        details = { dataProperty: p };

                        if ((p === 'prototype' && inspectedObj.callable && hasDefaultPrototype(inspectedObj, value)) || (p === 'constructor' && value.callable && hasDefaultPrototype(value, inspectedObj))) {
                            details.defaultPrototype = true;
                        }

                        graph.edges.add({ from: inspectedObj, to: value, data: details });

                        if (!done.has(value)) {
                            todo.add(value);
                        }
                    } else {
                        var get = desc.get;
                        if (get instanceof Debugger.Object) {
                            graph.edges.add({ from: inspectedObj, to: get, data: { getter: p } });

                            if (!done.has(get)) {
                                todo.add(get);
                            }
                        }
                        var set = desc.set;
                        if (set instanceof Debugger.Object) {
                            graph.edges.add({ from: inspectedObj, to: set, data: { setter: p } });

                            if (!done.has(set)) {
                                todo.add(set);
                            }
                        }
                    }
                });

                var environment = inspectedObj.environment;
                if (environment instanceof Debugger.Environment) {
                    graph.edges.add({ from: inspectedObj, to: environment, data: { type: "lexical-scope" } });

                    if (!done.has(environment)) {
                        todo.add(environment);
                    }
                }
            }

            if (inspected instanceof Debugger.Environment) {
                var inspectedEnv = inspected;

                var parent = inspectedEnv.parent;
                if (parent instanceof Debugger.Environment) {
                    graph.edges.add({ from: inspectedEnv, to: parent, data: { type: "parent-scope" } });
                    if (!done.has(parent)) {
                        todo.add(parent);
                    }
                }

                var variableNames = inspectedEnv.names();
                variableNames.forEach(function (v) {
                    if (v === 'arguments')
                        return;

                    try  {
                        var value = inspectedEnv.getVariable(v);
                    } catch (e) {
                        console.error('inspected.getVariable error', v, e);
                        return;
                    }

                    if (value instanceof Debugger.Object) {
                        var details = { variable: v };

                        graph.edges.add({ from: inspectedEnv, to: value, data: details });

                        if (!done.has(value)) {
                            todo.add(value);
                        }
                    }
                });
            }
        }
    }
}

/*console.time('preScriptGraph');
var preScriptGraph = new SimpleGraph();
traverseGraph(content, preScriptGraph);
console.timeEnd('preScriptGraph');

console.log('graph sizes', preScriptGraph.nodes.size, 'nodes', preScriptGraph.edges.size, 'edges')*/<commit_msg>A graph is created in the tab-content-script<commit_after>"use strict";

console.log('tab-content-script');

/*
    For now, huge parts are copy/pasted from previous scripts.
    Priority to getting something working
    TODO : when getting back to TS, clean this up

 */

// SimpleGraph

var SimpleGraph = (function () {
    function SimpleGraph() {
        this.nodes = new Set();
        this.edges = new Set();
    }
    SimpleGraph.prototype.toJSON = function () {
        var rootIndices = [];
        var nodes = [];

        var getIndex = (function () {
            var wm = new WeakMap();

            return function (n) {
                var index = wm.get(n);
                var serializableNode;

                if (index === undefined) {
                    index = nodes.length;
                    serializableNode = { outgoingEdges: [] };

                    if (n.callable)
                        serializableNode.class = 'function';

                    if (n.root)
                        serializableNode.class = 'root';

                    if (n.callee)
                        serializableNode.class = 'scope';

                    nodes[index] = serializableNode;
                    wm.set(n, index);
                }

                return index;
            };
        })();

        this.roots.forEach(function (r) {
            return getIndex(r);
        });
        rootIndices = [];
        nodes.forEach(function (root, i) {
            return rootIndices.push(i);
        });

        this.edges.forEach(function (e) {
            var label;
            var data = e.data;

            var serializedEdge = {
                to: getIndex(e.to)
            };

            if (data.dataProperty)
                serializedEdge.label = data.dataProperty;
            if (data.getter)
                serializedEdge.label = '[[Getter]] ' + data.getter;
            if (data.setter)
                serializedEdge.label = '[[Setter]] ' + data.setter;
            if (data.variable)
                serializedEdge.label = data.variable;

            if (data.variable)
                serializedEdge.class = 'variable';
            if (data.type === 'parent-scope')
                serializedEdge.class = 'parent-scope';
            if (data.type === 'lexical-scope')
                serializedEdge.class = 'lexical-scope';

            var from = nodes[getIndex(e.from)];
            from.outgoingEdges.push(serializedEdge);
        });

        var serializable = {
            rootIndices: rootIndices,
            nodes: nodes
        };

        console.log('JSON.stringify(serializable).length', JSON.stringify(serializable).length);

        return serializable;
    };
    return SimpleGraph;
})();

// ConnectedGraph

"use strict";
var __extends = this.__extends || function (d, b) {
    for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    __.prototype = b.prototype;
    d.prototype = new __();
};
var ConnectedGraphVertex = (function () {
    function ConnectedGraphVertex(data) {
        this.data = data;
        Object.freeze(this);
    }
    return ConnectedGraphVertex;
})();

var ConnectedGraphEdge = (function () {
    function ConnectedGraphEdge(from, to, data) {
        this.from = from;
        this.to = to;
        this.data = data;
        Object.freeze(this);
    }
    ConnectedGraphEdge.sameData = function (data1, data2) {
        return Object.keys(data1).length === Object.keys(data2).length && Object.keys(data1).every(function (prop) {
            return Object.is(data1[prop], data2[prop]);
        });
    };
    return ConnectedGraphEdge;
})();

var ConnectedGraph = (function () {
    function ConnectedGraph(roots) {
        this.roots = roots;
    }
    ConnectedGraph.prototype.addEdge = function (from, to, data) {
        var allEdges = ConnectedGraph.allEdges;

        var fromEdges = allEdges.get(from);

        var addedEdge;

        if (fromEdges) {
            var fromEdgesIt = fromEdges.values();
            var iter = fromEdgesIt.next();

            while (!iter.done && !addedEdge) {
                var candidate = iter.value;

                if (candidate.from == from && candidate.to == to && ConnectedGraphEdge.sameData(candidate.data, data)) {
                    addedEdge = candidate;
                    break;
                }

                iter = fromEdgesIt.next();
            }
        }

        if (!addedEdge) {
            addedEdge = new ConnectedGraphEdge(from, to, data);

            var fromSet = allEdges.get(from);
            if (!fromSet) {
                fromSet = new Set();
                allEdges.set(from, fromSet);
            }
            fromSet.add(addedEdge);

            var toSet = allEdges.get(to);
            if (!toSet) {
                toSet = new Set();
                allEdges.set(to, toSet);
            }
            toSet.add(addedEdge);
        }

        var addedEdgeGraphSet = ConnectedGraph.edge2graph.get(addedEdge);
        if (!addedEdgeGraphSet) {
            addedEdgeGraphSet = new Set();
            ConnectedGraph.edge2graph.set(addedEdge, addedEdgeGraphSet);
        }

        addedEdgeGraphSet.add(this);

        return addedEdge;
    };

    ConnectedGraph.prototype.getOutgoingEdges = function (n) {
        var s = new Set();

        var candidates = ConnectedGraph.allEdges.get(n);
        var candidatesIt = candidates.values();
        var iter = candidatesIt.next();

        while (!iter.done) {
            var candidateEdge = iter.value;

            if (ConnectedGraph.edge2graph.get(candidateEdge).has(this) && candidateEdge.from === n) {
                s.add(candidateEdge);
            }

            iter = candidatesIt.next();
        }

        return s;
    };

    ConnectedGraph.prototype.getIncomingEdges = function (n) {
        var s = new Set();

        var candidates = ConnectedGraph.allEdges.get(n);
        var candidatesIt = candidates.values();
        var iter = candidatesIt.next();

        while (!iter.done) {
            var candidateEdge = iter.value;

            if (ConnectedGraph.edge2graph.get(candidateEdge).has(this) && candidateEdge.to === n) {
                s.add(candidateEdge);
            }

            iter = candidatesIt.next();
        }

        return s;
    };
    ConnectedGraph.allEdges = new WeakMap();

    ConnectedGraph.edge2graph = new WeakMap();
    return ConnectedGraph;
})();

var DifferenceGraph = (function (_super) {
    __extends(DifferenceGraph, _super);
    function DifferenceGraph(from, to) {
        throw 'TODO';
        _super.call(this, from.roots);
    }
    return DifferenceGraph;
})(ConnectedGraph);

// traverseGraph

var addDebuggerToGlobal = Components.utils.import("resource://gre/modules/jsdebugger.jsm").addDebuggerToGlobal;
addDebuggerToGlobal(this);

// var ConnectedGraphVertex = ConnectedGraphImports.ConnectedGraphVertex;
// var ConnectedGraphEdge = ConnectedGraphImports.ConnectedGraphEdge;
// var ConnectedGraph = ConnectedGraphImports.ConnectedGraph;

Debugger.Object.prototype.toString = function () {
    var object = this;
    var jsonableCopy = {};

    object.getOwnPropertyNames().forEach(function (prop) {
        var desc = object.getOwnPropertyDescriptor(prop);
        jsonableCopy[prop] = desc.value;
    });

    return JSON.stringify(jsonableCopy);
};
Debugger.Object.prototype.toJSON = Debugger.Object.prototype.toString;

var dbg = new Debugger();
dbg.uncaughtExceptionHook = function (e) {
    console.error('uncaughtExceptionHook', e, e.stack);
};

Debugger.Object.prototype.byPath = function (path) {
    return path.split('.').reduce(function (acc, curr) {
        if (acc) {
            var desc = acc.getOwnPropertyDescriptor(curr);
            if (!desc || !desc.value)
                return undefined;
            else
                return desc.value;
        } else
            return undefined;
    }, this);
};

function traverseGraph(window, graph) {
    console.log('traverse');
    var globalDebugObject = dbg.addDebuggee(window);

    var done = new Set();
    var todo = new Set();

    var windowProxyDebuggeeObject = globalDebugObject.getOwnPropertyDescriptor('window').get.call(globalDebugObject).return;
    windowProxyDebuggeeObject.root = true;

    todo.add(windowProxyDebuggeeObject);

    graph.roots = new Set([windowProxyDebuggeeObject]);

    var debuggeeObjectPrototype = windowProxyDebuggeeObject.byPath('Object.prototype');

    function hasDefaultPrototype(func, proto) {
        var protoProps = proto.getOwnPropertyNames();

        try  {
            var constructor = proto.getOwnPropertyDescriptor('constructor').value;
        } catch (e) {
            console.error('constructor is not a data property', proto.getOwnPropertyDescriptor('constructor'), e);
            return false;
        }
        return protoProps.length === 1 && constructor === func && proto.proto === debuggeeObjectPrototype;
    }

    while (todo.size !== 0) {
        var todoIt = todo.values();

        while (true) {
            var next = todoIt.next();

            if (next.done)
                break;

            var inspected = next.value;
            todo.delete(inspected);
            done.add(inspected);

            graph.nodes.add(inspected);

            if (inspected instanceof Debugger.Object) {
                var inspectedObj = inspected;

                var props = inspectedObj.getOwnPropertyNames();

                props.forEach(function (p) {
                    var desc = inspectedObj.getOwnPropertyDescriptor(p);
                    var details;

                    var value = desc.value;

                    if (value instanceof Debugger.Object) {
                        details = { dataProperty: p };

                        if ((p === 'prototype' && inspectedObj.callable && hasDefaultPrototype(inspectedObj, value)) || (p === 'constructor' && value.callable && hasDefaultPrototype(value, inspectedObj))) {
                            details.defaultPrototype = true;
                        }

                        graph.edges.add({ from: inspectedObj, to: value, data: details });

                        if (!done.has(value)) {
                            todo.add(value);
                        }
                    } else {
                        var get = desc.get;
                        if (get instanceof Debugger.Object) {
                            graph.edges.add({ from: inspectedObj, to: get, data: { getter: p } });

                            if (!done.has(get)) {
                                todo.add(get);
                            }
                        }
                        var set = desc.set;
                        if (set instanceof Debugger.Object) {
                            graph.edges.add({ from: inspectedObj, to: set, data: { setter: p } });

                            if (!done.has(set)) {
                                todo.add(set);
                            }
                        }
                    }
                });

                var environment = inspectedObj.environment;
                if (environment instanceof Debugger.Environment) {
                    graph.edges.add({ from: inspectedObj, to: environment, data: { type: "lexical-scope" } });

                    if (!done.has(environment)) {
                        todo.add(environment);
                    }
                }
            }

            if (inspected instanceof Debugger.Environment) {
                var inspectedEnv = inspected;

                var parent = inspectedEnv.parent;
                if (parent instanceof Debugger.Environment) {
                    graph.edges.add({ from: inspectedEnv, to: parent, data: { type: "parent-scope" } });
                    if (!done.has(parent)) {
                        todo.add(parent);
                    }
                }

                var variableNames = inspectedEnv.names();
                variableNames.forEach(function (v) {
                    if (v === 'arguments')
                        return;

                    try  {
                        var value = inspectedEnv.getVariable(v);
                    } catch (e) {
                        console.error('inspected.getVariable error', v, e);
                        return;
                    }

                    if (value instanceof Debugger.Object) {
                        var details = { variable: v };

                        graph.edges.add({ from: inspectedEnv, to: value, data: details });

                        if (!done.has(value)) {
                            todo.add(value);
                        }
                    }
                });
            }
        }
    }
}

var tabGlobal = content;

console.time('preScriptGraph');
var preScriptGraph = new SimpleGraph();
traverseGraph(tabGlobal, preScriptGraph);
console.timeEnd('preScriptGraph');

console.log('graph sizes', preScriptGraph.nodes.size, 'nodes', preScriptGraph.edges.size, 'edges')<|endoftext|>


<commit_before>var PlayState = new Kiwi.State('PlayState');

/**
* The PlayState in the core state that is used in the game.
*
* It is the state where majority of the functionality occurs 'in-game' occurs.
*
*
* @class playState
* @extends State
* @constructor
*/

/**
* This create method is executed when Kiwi Game reaches the boot stage of the game loop.
* @method create
* @public
*/
PlayState.create = function () {

    //Switch the background colour back to white from purple
    this.game.stage.color = 'ffffff';

    //Variables relating to the state of the game
    this.gameStarted = false;
    this.gameEnded = false;

    //Values pertaining to physics based logic
    this.gravity = 1;
    this.xSpeed = 3;
    this.ySpeed = 0;
    this.maxYSpeed = 16;

    this.flapSpeed = -16;
    this.pipeDistance = 400;
    this.pipeGap = 260;

    //The starting coordinates of the bird.
    this.startX = (this.game.stage.width / 2) - 46
    this.startY = (this.game.stage.height / 2) - 64;

    //Background image
    this.bg = new Kiwi.GameObjects.Sprite(this, this.textures.background, 0, 0);
    this.addChild(this.bg);

    //Obstacles
    this.pipes = [];
    for (var j = 0; j < 3; j++) {
        var topPipe = new Kiwi.GameObjects.Sprite(this, this.textures.pipe, j * this.pipeDistance + 400 + this.game.stage.width, -Math.random() * 300 - 400);
        this.addChild(topPipe);
        topPipe.transform.rotation += Math.PI;
        this.pipes.push(topPipe);

        var bottomPipe = new Kiwi.GameObjects.Sprite(this, this.textures.pipe, j * this.pipeDistance + 400 + this.game.stage.width, topPipe.transform.y + topPipe.height + this.pipeGap);
        this.addChild(bottomPipe);
        bottomPipe.passed = false;
        bottomPipe.myTop = topPipe;
        this.pipes.push(bottomPipe);
    }

    //Scrolling floor
    this.tileWidth = 37;
    this.tiles = [];
    var tileCount = Math.ceil(this.game.stage.width / this.tileWidth);
    for (var i = 0; i <= tileCount; i++) {
        var t = new Kiwi.GameObjects.Sprite(this, this.textures.ground, i * this.tileWidth, this.game.stage.height - 128);
        this.addChild(t);
        this.tiles.push(t);
    }

    //Flapper
    this.bird = new Kiwi.GameObjects.Sprite(this, this.textures.bird, this.startX, this.startY);
    this.bird.animation.add('flap', [0, 1, 2], 0.1, true);
    this.bird.animation.play('flap');
    this.addChild(this.bird);

    this.birdWidth = this.bird.width;
    this.birdHeight = this.bird.height;

    //Input event for the flapper
    this.game.input.onDown.add(this.flap, this);

    //create, then hide buttons
    this.buttonX = this.game.stage.width / 2 - 107
    this.restartBtn = new Kiwi.GameObjects.Sprite(this, this.textures.restart, -217, this.game.stage.height / 2 - 150, true);
    this.addChild(this.restartBtn);
    this.restartBtn.input.onDown.add(this.restartGame, this);

    this.shareBtn = new Kiwi.GameObjects.Sprite(this, this.textures.share, -217, this.game.stage.height / 2 - 50, true);
    this.addChild(this.shareBtn);
    this.shareBtn.input.onDown.add(this.shareGame, this);

    //Score
    this.score = 0;
    this.scoreText = new Kiwi.GameObjects.Textfield(this, '0', 50, 50, '#FFF');
    this.addChild(this.scoreText);
}

/**
* This method is executed when the player resets the game.
* @method restartGame
* @public
*/
PlayState.restartGame = function () {
    this.gameStarted = false;
    this.gameEnded = false;
    this.score = 0;
    this.scoreText.text = this.score;

    for (var p in this.pipes) {
        var pipe = this.pipes[p];
        pipe.transform.x += 400 + this.game.stage.width;
        if (pipe.transform.rotation == 0) pipe.passed = false;
    }

    this.bird.transform.x = this.startX;
    this.bird.transform.y = this.startY;
    this.bird.transform.rotation = 0;

    this.restartBtn.transform.x = -217;
    this.shareBtn.transform.x = -217;
}

/**
* This method is executed when the user presses the share game button.
* @method shareGame
* @public
*/
PlayState.shareGame = function () {
    //Custom code relating to how you want to 'share' the game will need to go here.
    //Right now we are just going to redirect the user to kiwi.js.org :P
    setTimeout(function() {
      window.open("http://google.com");
     }, 100);
}

/**
* This method is executed when the user clicks.
* @method flap
* @public
*/
PlayState.flap = function () {
    this.gameStarted = true;
    this.ySpeed = this.flapSpeed;
}

/**
* This method is the main update loop. Move scrolling items here
* @method update
* @public
*/
PlayState.update = function () {
    Kiwi.State.prototype.update.call(this);
    if (this.gameStarted) {
        //update bird y speed and check collisions
        if (this.bird.transform.y < this.game.stage.height) {
            this.bird.transform.y += this.ySpeed;
            if (this.ySpeed < this.maxYSpeed) this.ySpeed += this.gravity;
            if (this.bird.transform.y < 0) this.bird.transform.y = 0;
            if (this.bird.transform.y > 704){
                this.killBird();
                return;
            }
        }
        //update bird rotation based on speed (in radians)
        if (this.ySpeed > 14) {
            this.bird.transform.rotation = Math.PI / 2;
        } else if (this.ySpeed > 6) {
            this.bird.transform.rotation = Math.PI / 6;
        } else {
            this.bird.transform.rotation = -Math.PI / 6;
        }
    }

    //move tiles
    if (!this.gameEnded) {
        for (var t in this.tiles) {
            var tile = this.tiles[t];
            tile.transform.x -= this.xSpeed;
            if (tile.transform.x <= -this.tileWidth) tile.transform.x += this.tileWidth * this.tiles.length;
        }
        if (this.gameStarted) {
            //move pipes
            for (var p in this.pipes) {
                var pipe = this.pipes[p];
                pipe.transform.x -= this.xSpeed;
                if (pipe.transform.rotation == 0) {
                    if (pipe.transform.x < -pipe.width) {
                        pipe.transform.x += this.pipeDistance * 3;
                        pipe.passed = false;
                        pipe.myTop.transform.x = pipe.transform.x;
                        var rand = -Math.random() * 300 - 400;
                        pipe.myTop.transform.y = rand;
                        pipe.transform.y = pipe.myTop.transform.y + pipe.myTop.height + this.pipeGap;
                    }

                    if (pipe.transform.x < this.bird.transform.x && !pipe.passed) {
                        this.score++;
                        this.scoreText.text = this.score;
                        console.log('score:', this.score);
                        pipe.passed = true;
                    }
                }

                if (this.checkCollision(pipe)) {
                    this.killBird();
                    return;
                }
            }
        }
    }
}

/**
* This method checks to see if the bird is colliding with a given pipe.
* @method checkCollision
* @public
* @param pipe{Sprite} The pipe to check colliding with the bird.
*/
PlayState.checkCollision = function (pipe) {
    if (this.bird.transform.x + this.birdWidth > pipe.transform.x) {
        if (this.bird.transform.x < pipe.transform.x + pipe.width) {
            if (this.bird.transform.y + this.birdHeight > pipe.transform.y) {
                if (this.bird.transform.y < pipe.transform.y + pipe.height) {
                    return true;
                }
            }
        }
    }
    return false;
}

/**
* This method is executed when the bird collides with a pipe.
* @method killBird
* @public
*/
PlayState.killBird = function () {
    if (this.gameEnded) return;

    this.gameEnded = true;

    this.shareBtn.transform.x = this.buttonX;
    this.restartBtn.transform.x = this.buttonX;
}
<commit_msg>update<commit_after>var PlayState = new Kiwi.State('PlayState');

/**
* The PlayState in the core state that is used in the game.
*
* It is the state where majority of the functionality occurs 'in-game' occurs.
*
*
* @class playState
* @extends State
* @constructor
*/

/**
* This create method is executed when Kiwi Game reaches the boot stage of the game loop.
* @method create
* @public
*/
PlayState.create = function () {

    //Switch the background colour back to white from purple
    this.game.stage.color = 'ffffff';

    //Variables relating to the state of the game
    this.gameStarted = false;
    this.gameEnded = false;

    //Values pertaining to physics based logic
    this.gravity = 1;
    this.xSpeed = 3;
    this.ySpeed = 0;
    this.maxYSpeed = 16;

    this.flapSpeed = -16;
    this.pipeDistance = 400;
    this.pipeGap = 260;

    //The starting coordinates of the bird.
    this.startX = (this.game.stage.width / 2) - 46
    this.startY = (this.game.stage.height / 2) - 64;

    //Background image
    this.bg = new Kiwi.GameObjects.Sprite(this, this.textures.background, 0, 0);
    this.addChild(this.bg);

    //Obstacles
    this.pipes = [];
    for (var j = 0; j < 3; j++) {
        var topPipe = new Kiwi.GameObjects.Sprite(this, this.textures.pipe, j * this.pipeDistance + 400 + this.game.stage.width, -Math.random() * 300 - 400);
        this.addChild(topPipe);
        topPipe.transform.rotation += Math.PI;
        this.pipes.push(topPipe);

        var bottomPipe = new Kiwi.GameObjects.Sprite(this, this.textures.pipe, j * this.pipeDistance + 400 + this.game.stage.width, topPipe.transform.y + topPipe.height + this.pipeGap);
        this.addChild(bottomPipe);
        bottomPipe.passed = false;
        bottomPipe.myTop = topPipe;
        this.pipes.push(bottomPipe);
    }

    //Scrolling floor
    this.tileWidth = 37;
    this.tiles = [];
    var tileCount = Math.ceil(this.game.stage.width / this.tileWidth);
    for (var i = 0; i <= tileCount; i++) {
        var t = new Kiwi.GameObjects.Sprite(this, this.textures.ground, i * this.tileWidth, this.game.stage.height - 128);
        this.addChild(t);
        this.tiles.push(t);
    }

    //Flapper
    this.bird = new Kiwi.GameObjects.Sprite(this, this.textures.bird, this.startX, this.startY);
    this.bird.animation.add('flap', [0, 1, 2], 0.1, true);
    this.bird.animation.play('flap');
    this.addChild(this.bird);

    this.birdWidth = this.bird.width;
    this.birdHeight = this.bird.height;

    //Input event for the flapper
    this.game.input.onDown.add(this.flap, this);

    //create, then hide buttons
    this.buttonX = this.game.stage.width / 2 - 107
    this.restartBtn = new Kiwi.GameObjects.Sprite(this, this.textures.restart, -217, this.game.stage.height / 2 - 150, true);
    this.addChild(this.restartBtn);
    this.restartBtn.input.onDown.add(this.restartGame, this);

    this.shareBtn = new Kiwi.GameObjects.Sprite(this, this.textures.share, -217, this.game.stage.height / 2 - 50, true);
    this.addChild(this.shareBtn);
    this.shareBtn.input.onDown.add(this.shareGame, this);

    //Score
    this.score = 0;
    this.scoreText = new Kiwi.GameObjects.Textfield(this, '0', 50, 50, '#FFF');
    this.addChild(this.scoreText);
}

/**
* This method is executed when the player resets the game.
* @method restartGame
* @public
*/
PlayState.restartGame = function () {
    this.gameStarted = false;
    this.gameEnded = false;
    this.score = 0;
    this.scoreText.text = this.score;

    for (var p in this.pipes) {
        var pipe = this.pipes[p];
        pipe.transform.x += 400 + this.game.stage.width;
        if (pipe.transform.rotation == 0) pipe.passed = false;
    }

    this.bird.transform.x = this.startX;
    this.bird.transform.y = this.startY;
    this.bird.transform.rotation = 0;

    this.restartBtn.transform.x = -217;
    this.shareBtn.transform.x = -217;
}

/**
* This method is executed when the user presses the share game button.
* @method shareGame
* @public
*/
PlayState.shareGame = function () {
    //Custom code relating to how you want to 'share' the game will need to go here.
    //Right now we are just going to redirect the user to kiwi.js.org :P
    setTimeout(function() { window.open('https://twitter.com/intent/tweet?original_referer=http%3A%2F%2Ftheoria24.github.io%2FFlappyMiyu%2F&ref_src=twsrc%5Etfw&text=%E7%B5%90%E6%9E%9C%E3%81%AF' + this.score + '%E5%9B%9E%EF%BC%81%0D%0A%0D%0AFlappy+Miyu&tw_p=tweetbutton&url=http%3A%2F%2Ftheoria24.github.io%2FFlappyMiyu%2F') }, 100);
}

/**
* This method is executed when the user clicks.
* @method flap
* @public
*/
PlayState.flap = function () {
    this.gameStarted = true;
    this.ySpeed = this.flapSpeed;
}

/**
* This method is the main update loop. Move scrolling items here
* @method update
* @public
*/
PlayState.update = function () {
    Kiwi.State.prototype.update.call(this);
    if (this.gameStarted) {
        //update bird y speed and check collisions
        if (this.bird.transform.y < this.game.stage.height) {
            this.bird.transform.y += this.ySpeed;
            if (this.ySpeed < this.maxYSpeed) this.ySpeed += this.gravity;
            if (this.bird.transform.y < 0) this.bird.transform.y = 0;
            if (this.bird.transform.y > 704){
                this.killBird();
                return;
            }
        }
        //update bird rotation based on speed (in radians)
        if (this.ySpeed > 14) {
            this.bird.transform.rotation = Math.PI / 2;
        } else if (this.ySpeed > 6) {
            this.bird.transform.rotation = Math.PI / 6;
        } else {
            this.bird.transform.rotation = -Math.PI / 6;
        }
    }

    //move tiles
    if (!this.gameEnded) {
        for (var t in this.tiles) {
            var tile = this.tiles[t];
            tile.transform.x -= this.xSpeed;
            if (tile.transform.x <= -this.tileWidth) tile.transform.x += this.tileWidth * this.tiles.length;
        }
        if (this.gameStarted) {
            //move pipes
            for (var p in this.pipes) {
                var pipe = this.pipes[p];
                pipe.transform.x -= this.xSpeed;
                if (pipe.transform.rotation == 0) {
                    if (pipe.transform.x < -pipe.width) {
                        pipe.transform.x += this.pipeDistance * 3;
                        pipe.passed = false;
                        pipe.myTop.transform.x = pipe.transform.x;
                        var rand = -Math.random() * 300 - 400;
                        pipe.myTop.transform.y = rand;
                        pipe.transform.y = pipe.myTop.transform.y + pipe.myTop.height + this.pipeGap;
                    }

                    if (pipe.transform.x < this.bird.transform.x && !pipe.passed) {
                        this.score++;
                        this.scoreText.text = this.score;
                        console.log('score:', this.score);
                        pipe.passed = true;
                    }
                }

                if (this.checkCollision(pipe)) {
                    this.killBird();
                    return;
                }
            }
        }
    }
}

/**
* This method checks to see if the bird is colliding with a given pipe.
* @method checkCollision
* @public
* @param pipe{Sprite} The pipe to check colliding with the bird.
*/
PlayState.checkCollision = function (pipe) {
    if (this.bird.transform.x + this.birdWidth > pipe.transform.x) {
        if (this.bird.transform.x < pipe.transform.x + pipe.width) {
            if (this.bird.transform.y + this.birdHeight > pipe.transform.y) {
                if (this.bird.transform.y < pipe.transform.y + pipe.height) {
                    return true;
                }
            }
        }
    }
    return false;
}

/**
* This method is executed when the bird collides with a pipe.
* @method killBird
* @public
*/
PlayState.killBird = function () {
    if (this.gameEnded) return;

    this.gameEnded = true;

    this.shareBtn.transform.x = this.buttonX;
    this.restartBtn.transform.x = this.buttonX;
}
<|endoftext|>


<commit_before>'use strict'

process.env.BABEL_ENV = 'renderer'

const path = require('path')
const pkg = require('./app/package.json')
const settings = require('./config.js')
const webpack = require('webpack')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

let rendererConfig = {
  devtool: '#eval-source-map',
  entry: {
    renderer: path.join(__dirname, 'app/src/renderer/main.js')
  },
  externals: Object.keys(pkg.dependencies || {}),
  module: {
    rules: [
      {
        test: /\.css$/,
        loader: ExtractTextPlugin.extract({
          fallbackLoader: 'style-loader',
          loader: 'css-loader'
        })
      },
      {
        test: /\.html$/,
        loader: 'vue-html-loader'
      },
      {
        test: /\.js$/,
        loader: 'babel-loader',
        include: [ path.resolve(__dirname, 'app/src/renderer') ],
        exclude: /node_modules/
      },
      {
        test: /\.json$/,
        loader: 'json-loader'
      },
      {
        test: /\.node$/,
        loader: 'node-loader'
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        options: {
          loaders: {
            sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
            scss: 'vue-style-loader!css-loader!sass-loader'
          }
        }
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        loader: 'url-loader',
        query: {
          limit: 10000,
          name: 'imgs/[name].[ext]'
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        loader: 'url-loader',
        query: {
          limit: 10000,
          name: 'fonts/[name].[ext]'
        }
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('styles.css'),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: './app/index.ejs',
      appModules: process.env.NODE_ENV !== 'production'
        ? path.resolve(__dirname, 'app/node_modules')
        : false,
    }),
    new webpack.NoEmitOnErrorsPlugin()
  ],
  output: {
    filename: '[name].js',
    libraryTarget: 'commonjs2',
    path: path.join(__dirname, 'app/dist')
  },
  resolve: {
    alias: {
      'components': path.join(__dirname, 'app/src/renderer/components'),
      'renderer': path.join(__dirname, 'app/src/renderer')
    },
    extensions: ['.js', '.vue', '.json', '.css', '.node'],
    modules: [
      path.join(__dirname, 'app/node_modules'),
      path.join(__dirname, 'node_modules')
    ]
  },
  target: 'electron-renderer'
}

{{#if eslint}}
if (process.env.NODE_ENV !== 'production') {
  /**
   * Apply ESLint
   */
  if (settings.eslint) {
    rendererConfig.module.rules.push(
      {
        test: /\.(js|vue)$/,
        loader: 'eslint-loader',
        enforce: 'pre',
        exclude: /node_modules/,
        options: { formatter: require('eslint-friendly-formatter') }
      }
    )
  }
}
{{/if}}

/**
 * Adjust rendererConfig for production settings
 */
if (process.env.NODE_ENV === 'production') {
  rendererConfig.devtool = ''

  rendererConfig.plugins.push(
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"production"'
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  )
}

module.exports = rendererConfig
<commit_msg>:hammer: update webpack config to use `use`<commit_after>'use strict'

process.env.BABEL_ENV = 'renderer'

const path = require('path')
const pkg = require('./app/package.json')
const settings = require('./config.js')
const webpack = require('webpack')

const ExtractTextPlugin = require('extract-text-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

let rendererConfig = {
  devtool: '#eval-source-map',
  entry: {
    renderer: path.join(__dirname, 'app/src/renderer/main.js')
  },
  externals: Object.keys(pkg.dependencies || {}),
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ExtractTextPlugin.extract({
          fallback: 'style-loader',
          use: 'css-loader'
        })
      },
      {
        test: /\.html$/,
        use: 'vue-html-loader'
      },
      {
        test: /\.js$/,
        use: 'babel-loader',
        include: [ path.resolve(__dirname, 'app/src/renderer') ],
        exclude: /node_modules/
      },
      {
        test: /\.json$/,
        use: 'json-loader'
      },
      {
        test: /\.node$/,
        use: 'node-loader'
      },
      {
        test: /\.vue$/,
        use: {
          loader: 'vue-loader',
          options: {
            loaders: {
              sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax=1',
              scss: 'vue-style-loader!css-loader!sass-loader'
            }
          }
        }
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          query: {
            limit: 10000,
            name: 'imgs/[name].[ext]'
          }
        }
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
        use: {
          loader: 'url-loader',
          query: {
            limit: 10000,
            name: 'fonts/[name].[ext]'
          }
        }
      }
    ]
  },
  plugins: [
    new ExtractTextPlugin('styles.css'),
    new HtmlWebpackPlugin({
      filename: 'index.html',
      template: './app/index.ejs',
      appModules: process.env.NODE_ENV !== 'production'
        ? path.resolve(__dirname, 'app/node_modules')
        : false,
    }),
    new webpack.NoEmitOnErrorsPlugin()
  ],
  output: {
    filename: '[name].js',
    libraryTarget: 'commonjs2',
    path: path.join(__dirname, 'app/dist')
  },
  resolve: {
    alias: {
      'components': path.join(__dirname, 'app/src/renderer/components'),
      'renderer': path.join(__dirname, 'app/src/renderer')
    },
    extensions: ['.js', '.vue', '.json', '.css', '.node'],
    modules: [
      path.join(__dirname, 'app/node_modules'),
      path.join(__dirname, 'node_modules')
    ]
  },
  target: 'electron-renderer'
}

{{#if eslint}}
if (process.env.NODE_ENV !== 'production') {
  /**
   * Apply ESLint
   */
  if (settings.eslint) {
    rendererConfig.module.rules.push(
      {
        test: /\.(js|vue)$/,
        enforce: 'pre',
        exclude: /node_modules/,
        use: {
          loader: 'eslint-loader',
          options: {
            formatter: require('eslint-friendly-formatter')
          }
        }
      }
    )
  }
}
{{/if}}

/**
 * Adjust rendererConfig for production settings
 */
if (process.env.NODE_ENV === 'production') {
  rendererConfig.devtool = ''

  rendererConfig.plugins.push(
    new webpack.DefinePlugin({
      'process.env.NODE_ENV': '"production"'
    }),
    new webpack.LoaderOptionsPlugin({
      minimize: true
    }),
    new webpack.optimize.UglifyJsPlugin({
      compress: {
        warnings: false
      }
    })
  )
}

module.exports = rendererConfig
<|endoftext|>


<commit_before>import Base from '../Base'
import Grid from './Grid'

/**
 * Component responsible for blocks management of image,
 * responsible for querying image and show / hide or animate
 * when required
 */
class Blocks extends Base {
  constructor(parent, renderer) {
    super(parent)

    const rootEl = this.getFromEnv('root')
    const blocksEl = document.createElement('div')

    // Append child to rootEl
    rootEl.appendChild(blocksEl)

    // Add renderer to store
    this.addToStore('renderer', renderer)
    // Add blocks node to store
    this.addToStore('blocksEl', blocksEl)
    // Initialize grid for the block instance
    this.addToStore('grid', new Grid(this, blocksEl))
  }
}

export default Blocks
<commit_msg>function added to customize blocks nodeelement<commit_after>import Base from '../Base'
import Grid from './Grid'

function customizeBlockEl(el, config) {
  const blocksEl = el
  blocksEl.style.height = `${config.height}px`
  blocksEl.style.width = `${config.width}px`
  blocksEl.style.position = 'absolute'
  blocksEl.style.top = '0px'
  blocksEl.style.left = '0px'
}

/**
 * Component responsible for blocks management of image,
 * responsible for querying image and show / hide or animate
 * when required
 */
class Blocks extends Base {
  constructor(parent, renderer) {
    super(parent)

    const rootEl = this.getFromEnv('root')
    const blocksEl = document.createElement('div')

    // Append child to rootEl
    rootEl.appendChild(blocksEl)

    customizeBlockEl(blocksEl, this.getFromEnv('config'))

    // Add renderer to store
    this.addToStore('renderer', renderer)
    // Add blocks node to store
    this.addToStore('blocksEl', blocksEl)
    // Initialize grid for the block instance
    this.addToStore('grid', new Grid(this, blocksEl))
  }
}

export default Blocks
<|endoftext|>


<commit_before>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 *
 */

if (typeof define !== 'function') {
	var define = require('amdefine')(module);
}
define(["require", "./errors", "./utils"], function(require, errors, utils) {
	"use strict";
	var Disallow = function() {
		var restrictions = {};
		for (var i in arguments)
			restrictions[arguments[i]] = deep.forbidden();
		return restrictions;
	};
	var AllowOnly = function() {
		return {
			inner: {},
			allowable: utils.argToArr.call(arguments),
			_deep_compiler_: true,
			_deep_allow_only_: true,
			_up: function() { // apply arguments (up) on inner-layer : so merge
				// console.log("allow only up : ", arguments);
				var res = this.inner;
				for (var i = 0, len = arguments.length; i < len; ++i) {
					var argi = arguments[i];
					if (argi._deep_allow_only_) {
						res = utils.up(argi.inner, res);
						this.allowable = utils.up(argi.allowable, this.allowable);
					} else
						res = utils.up(argi, res);
				}
				this.inner = res;
				return this;
			},
			_bottom: function() { // apply arguments (bottom) on this : so apply restrictions

				// console.log("allow only bottom : ", arguments);
				var res = this.inner,
					toKeep = null;
				for (var len = arguments.length - 1; len >= 0; --len) {
					var argi = arguments[len];
					if (argi._deep_allow_only_) {
						res = utils.bottom(argi.inner, res);
						this.allowable = utils.up(argi.allowable, this.allowable);
					} else
						res = utils.bottom(argi, res);
				}
				if (res._deep_restrictable_) {
					var toRemove = utils.removeInside(res._deep_restrictable_.slice(), this.allowable);
					for (var j = 0, lenj = toRemove.length; j < lenj; ++j)
						res[toRemove[j]] = deep.forbidden();
				} else {
					if (!toKeep) {
						toKeep = {};
						for (var l = 0, lenl = this.allowable.length; l < lenl; ++l)
							toKeep[this.allowable[l]] = true;
					}
					for (var k in res)
						if (typeof res[k] === 'function' && !toKeep[k])
							res[k] = deep.forbidden();
				}
				return res;
			}
		};
	};
	return {
		Disallow: Disallow,
		AllowOnly: AllowOnly,
		forbidden: function(message) {
			return function(any, options) {
				return errors.Forbidden(message);
			};
		}
	};
});<commit_msg>restrictions : compiler aup/abottom<commit_after>/**
 * @author Gilles Coomans <gilles.coomans@gmail.com>
 *
 */

if (typeof define !== 'function') {
	var define = require('amdefine')(module);
}
define(["require", "./errors", "./utils", "./compiler"], function(require, errors, utils, compiler) {
	"use strict";
	var Disallow = function() {
		var restrictions = {};
		for (var i in arguments)
			restrictions[arguments[i]] = deep.forbidden();
		return restrictions;
	};
	var AllowOnly = function() {
		return {
			inner: {},
			allowable: utils.argToArr.call(arguments),
			_deep_compiler_: true,
			_deep_allow_only_: true,
			_up: function() { // apply arguments (up) on inner-layer : so merge
				var res = this.inner;
				for (var i = 0, len = arguments.length; i < len; ++i) {
					var argi = arguments[i];
					if (argi._deep_allow_only_) {
						res = compiler.aup(argi.inner, res);
						this.allowable = compiler.aup(argi.allowable, this.allowable);
					} else
						res = compiler.aup(argi, res);
				}
				this.inner = res;
				return this;
			},
			_bottom: function() { // apply arguments (bottom) on this : so apply restrictions

				var res = this.inner,
					toKeep = null;
				for (var len = arguments.length - 1; len >= 0; --len) {
					var argi = arguments[len];
					if (argi._deep_allow_only_) {
						res = compiler.abottom(argi.inner, res);
						this.allowable = compiler.aup(argi.allowable, this.allowable);
					} else
						res = compiler.abottom(argi, res);
				}
				if (res._deep_restrictable_) {
					var toRemove = utils.removeInside(res._deep_restrictable_.slice(), this.allowable);
					for (var j = 0, lenj = toRemove.length; j < lenj; ++j)
						res[toRemove[j]] = deep.forbidden();
				} else {
					if (!toKeep) {
						toKeep = {};
						for (var l = 0, lenl = this.allowable.length; l < lenl; ++l)
							toKeep[this.allowable[l]] = true;
					}
					//console.log("not restrictable res ", res, toKeep);
					for (var k in res)
						if (typeof res[k] === 'function' && !toKeep[k])
						{
							res[k] = deep.forbidden();
						}
				}
				//console.log("RES : ", res);
				return res;
			}
		};
	};
	return {
		Disallow: Disallow,
		AllowOnly: AllowOnly,
		forbidden: function(message) {
			return function(any, options) {
				return errors.Forbidden(message);
			};
		}
	};
});<|endoftext|>


<commit_before>/*jshint camelcase: false */
'use strict';

/**
 * Review server that listens to GitHub notifications.
 * (C) 2015 Alex Fernández.
 */

// requires
require('prototypes');
var fs = require('fs');
var Log = require('log');
var http = require('http');
var testing = require('testing');
var trello = require('./trello.js');

// globals
var log = new Log('info');

// constants
var FUNCTIONS = {
	created: 'createComment',
	opened: 'openPullRequest',
	closed: 'closePullRequest',
	reopened: 'reopenPullRequest',
};

/**
 * Start a review server. Options can contain:
 *	- token: consumer token for Trello.
 *	- key: app key for Trello.
 *	- secret: part of the URL to invoke.
 *	- port: the port to use.
 *	- quiet: do not log messages.
 *	- debug: log debug messages.
 * Other arguments:
 *	- callback: invoked after the server has started.
 */
exports.start = function(options, callback)
{
	var server = new ReviewServer(options);
	return server.start(callback);
};

function testStartServer(callback)
{
	var options = {
		port: 10530,
	};
	var server = exports.start(options, function(error)
	{
		testing.check(error, 'Could not start server', callback);
		server.close(function(error)
		{
			testing.check(error, 'Could not stop server', callback);
			testing.success(callback);
		});
	});
}

/**
 * A review server, with the given options, see below on start().
 */
function ReviewServer(options)
{
	// self-reference
	var self = this;

	// attributes
	var board = new trello.Board(options);

	// init
	if (options.quiet)
	{
		log.level = 'notice';
	}
	if (options.debug)
	{
		log.level = 'debug';
	}

	/**
	 * Start the server.
	 * An optional callback will be called after the server has started.
	 */
	self.start = function(callback)
	{
		var server = http.createServer(listen);
		server.on('error', function(error)
		{
			if (error.code == 'EADDRINUSE')
			{
				return callback('Port ' + options.port + ' in use, please free it and retry again');
			}
			return callback('Could not start server on port ' + options.port + ': ' + error);
		});
		server.listen(options.port, function()
		{
			log.info('Listening on port %s', options.port);
			if (callback)
			{
				callback();
			}
		});
		return server;
	};

	/**
	 * Listen to an incoming request.
	 */
	function listen(request, response)
	{
		var body = '';
		request.on('data', function(data)
		{
			body += data.toString();
		});
		request.on('error', function(error)
		{
			log.error('Could not listen to request: %s', error);
		});
		request.on('end', function()
		{
			end(request.url, body, response);
		});
	}

	/**
	 * End the response now.
	 */
	function end(url, body, response)
	{
		if (!url.contains(options.secret))
		{
			var code = options.error || 500;
			response.writeHead(code);
			response.end('ERROR');
			return;
		}
		response.end('OK');
		var json;
		try
		{
			json = JSON.parse(body);
		}
		catch(exception)
		{
			log.info('Invalid message received: %s', body.substring(0, 20));
			return;
		}
		log.debug('Got message to %s: %s', url, JSON.stringify(json, null, '\t'));
		analyze(json);
	}

	function analyze(info)
	{
		if (!info.action || !info.repository)
		{
			return log.info('Missing action/repository in message: %s / %s', info.action, info.repository);
		}
		var operationName = FUNCTIONS[info.action];
		if (!operationName)
		{
			return handleUnknownAction(info);
		}
		var operation = self[operationName];
		operation(info);
	}

	self.createComment = function(info)
	{
		// create comment in card
		var repoName = info.repository.name;
		var sender = info.sender.login;
		var title = '[' + repoName + '] ' + info.issue.title;
		var body = info.sender.login + ': ' + info.comment.body + '\n\n[View on GitHub](' + info.comment.html_url + ')';
		if (!body.contains('+1') && !body.contains('-1'))
		{
			return log.info('Comment created by %s on %s: %s', sender, title, body);
		}
		board.findCard(title, function(error, card)
		{
			if (error)
			{
				return log.error('Could not find card %s: %s', title, error);
			}
			if (!card)
			{
				return log.info('Could not find card for %s', title);
			}
			board.addComment(card.id, body, function(error)
			{
				if (error)
				{
					return log.error('Could not add comment to %s: %s', title, error);
				}
				log.info('Comment %s added to %s', body, title);
				reviewPullRequest(card);
			});
		});
	};

	function reviewPullRequest(card)
	{
		board.readComments(card.id, function(error, comments)
		{
			if (!comments.length)
			{
				return;
			}
			var destination;
			var labels = 'orange';
			if (card.idList == options.inProgress)
			{
				destination = options.underReview;
			}
			var score = computeScore(comments);
			if (score >= 2)
			{
				destination = options.reviewed;
				labels = 'green';
			}
			else if (score < 0)
			{
				destination = options.blocked;
				labels = 'red';
			}
			else if (card.idList == options.blocked)
			{
				destination = options.underReview;
			}
			var params = {
				name: getNameWithScore(card.name, score),
				labels: labels,
			};
			board.modifyCard(card.id, params, function(error)
			{
				if (error)
				{
					log.error('Could not rename card to %s: %s', params.name, error);
				}
				else
				{
					log.info('Card renamed to %s with labels %s', params.name, labels);
				}
				if (!destination)
				{
					return;
				}
				board.moveCard(card.id, destination, function(error)
				{
					if (error)
					{
						log.error('Could not move card %s: %s', card.name, error);
					}
					else
					{
						log.info('Card %s moved to %s', card.name, destination);
					}
				});
			});
		});
	}

	self.openPullRequest = function(info)
	{
		var title = getTitle(info);
		if (!title)
		{
			return;
		}
		var link = '[View on GitHub](' + info.pull_request.html_url + ')\n\n';
		var description = link + info.pull_request.body;
		var username = info.pull_request.user.login;
		board.createCard(title, description, options.inProgress, function(error)
		{
			if (error)
			{
				return log.error('Could not create card: %s', error);
			}
			return log.info('Created card for %s by %s', title, username);
		});
	};

	function getTitle(info)
	{
		if (!info.pull_request)
		{
			return log.info('Missing pull request to open');
		}
		var repoName = info.repository.name;
		return '[' + repoName + '] ' + info.pull_request.title;
	}

	self.closePullRequest = function(info)
	{
		var title = getTitle(info);
		if (!title)
		{
			return;
		}
		var destination = 'cancelled';
		if (info.pull_request.merged)
		{
			destination = 'merged';
		}
		var listId = options[destination];
		board.moveCard(title, listId, function(error)
		{
			if (error)
			{
				return log.error('Could not move closed card %s to %s: %s', title, destination, error);
			}
			return log.info('Moved card for %s to %s', title, destination);
		});
	};

	self.reopenPullRequest = function(info)
	{
		var title = getTitle(info);
		if (!title)
		{
			return;
		}
		board.moveCard(title, options.inProgress, function(error)
		{
			if (error)
			{
				return log.error('Could not move reopened card %s: %s', title, error);
			}
			return log.info('Moved card for %s to in progress', title);
		});
	};

	function handleUnknownAction(info)
	{
		var filename = __dirname + '/../samples/' + info.action + '-sample.json';
		fs.writeFile(filename, JSON.stringify(info, null, '\t'), function(error)
		{
			if (error)
			{
				return log.error('Could not write action %s to file %s: %s', info.action, filename, error);
			}
			log.info('Received unknown action %s, written to %s', info.action, filename);
		});
	}
}

function computeScore(comments)
{
	var score = 0;
	var vetos = 0;
	var voted = {};
	comments.forEach(function(comment)
	{
		var text = comment.text.substringUpTo('\n');
		if (!text.contains(':'))
		{
			return;
		}
		var author = text.substringUpTo(':');
		if (author in voted)
		{
			return;
		}
		log.debug('%s votes %s', author, text.substringFrom(':'));
		if (text.contains('-'))
		{
			var veto = parseFloat(text.substringFrom('-'));
			vetos += veto;
			voted[author] = -veto;
		}
		if (text.contains('+'))
		{
			var vote = parseFloat(text.substringFrom('+'));
			score += Math.min(vote, 1);
			voted[author] = vote;
		}
	});
	log.info('Score: %s, vetos: %s, tally: %s', score, vetos, JSON.stringify(voted, null, '\t'));
	if (vetos > 0)
	{
		return -vetos;
	}
	return score;
}

function testComputeScore(callback)
{
	var comments = [{
		text: 'alexfernandez: +1',
	}, {
		text: 'alexfernandez: +2',
	}];
	testing.assertEquals(computeScore(comments), 1, 'Two +x from the same dev', callback);
	comments.push({text: 'cmdrTaco: -1'});
	testing.assertEquals(computeScore(comments), -1, 'One -1', callback);
	comments.push({text: 'starryEyed: +1'});
	testing.assertEquals(computeScore(comments), -1, 'Still -1', callback);
	comments.unshift({text: 'cmdrTaco: +1'});
	testing.assertEquals(computeScore(comments), +3, '+1 supersedes -1', callback);
	testing.success(callback);
}

function getNameWithScore(name, score)
{
	var original = name;
	if (name.contains(' (') && name.endsWith(')'))
	{
		original = name.substringUpToLast(' (');
	}
	var text = String(score);
	if (score > 0)
	{
		text = '+' + score;
	}
	return original + ' (' + text + ')';
}

function testNameWithScore(callback)
{
	var name = '[test] Test PR';
	var withScore = getNameWithScore(name, 2);
	testing.assertEquals('[test] Test PR (+2)', withScore, 'Invalid name +2', callback);
	withScore = getNameWithScore(withScore, -0.5);
	testing.assertEquals('[test] Test PR (-0.5)', withScore, 'Invalid name -0.5', callback);
	testing.success(callback);
}

/**
 * Run the tests.
 */
exports.test = function(callback)
{
	testing.run([
		testStartServer,
		testComputeScore,
		testNameWithScore,
	], 5000, callback);
};

// start server if invoked directly
if (__filename == process.argv[1])
{
	exports.test(testing.show);
}

<commit_msg>Don't move from merged.<commit_after>/*jshint camelcase: false */
'use strict';

/**
 * Review server that listens to GitHub notifications.
 * (C) 2015 Alex Fernández.
 */

// requires
require('prototypes');
var fs = require('fs');
var Log = require('log');
var http = require('http');
var testing = require('testing');
var trello = require('./trello.js');

// globals
var log = new Log('info');

// constants
var FUNCTIONS = {
	created: 'createComment',
	opened: 'openPullRequest',
	closed: 'closePullRequest',
	reopened: 'reopenPullRequest',
};

/**
 * Start a review server. Options can contain:
 *	- token: consumer token for Trello.
 *	- key: app key for Trello.
 *	- secret: part of the URL to invoke.
 *	- port: the port to use.
 *	- quiet: do not log messages.
 *	- debug: log debug messages.
 * Other arguments:
 *	- callback: invoked after the server has started.
 */
exports.start = function(options, callback)
{
	var server = new ReviewServer(options);
	return server.start(callback);
};

function testStartServer(callback)
{
	var options = {
		port: 10530,
	};
	var server = exports.start(options, function(error)
	{
		testing.check(error, 'Could not start server', callback);
		server.close(function(error)
		{
			testing.check(error, 'Could not stop server', callback);
			testing.success(callback);
		});
	});
}

/**
 * A review server, with the given options, see below on start().
 */
function ReviewServer(options)
{
	// self-reference
	var self = this;

	// attributes
	var board = new trello.Board(options);

	// init
	if (options.quiet)
	{
		log.level = 'notice';
	}
	if (options.debug)
	{
		log.level = 'debug';
	}

	/**
	 * Start the server.
	 * An optional callback will be called after the server has started.
	 */
	self.start = function(callback)
	{
		var server = http.createServer(listen);
		server.on('error', function(error)
		{
			if (error.code == 'EADDRINUSE')
			{
				return callback('Port ' + options.port + ' in use, please free it and retry again');
			}
			return callback('Could not start server on port ' + options.port + ': ' + error);
		});
		server.listen(options.port, function()
		{
			log.info('Listening on port %s', options.port);
			if (callback)
			{
				callback();
			}
		});
		return server;
	};

	/**
	 * Listen to an incoming request.
	 */
	function listen(request, response)
	{
		var body = '';
		request.on('data', function(data)
		{
			body += data.toString();
		});
		request.on('error', function(error)
		{
			log.error('Could not listen to request: %s', error);
		});
		request.on('end', function()
		{
			end(request.url, body, response);
		});
	}

	/**
	 * End the response now.
	 */
	function end(url, body, response)
	{
		if (!url.contains(options.secret))
		{
			var code = options.error || 500;
			response.writeHead(code);
			response.end('ERROR');
			return;
		}
		response.end('OK');
		var json;
		try
		{
			json = JSON.parse(body);
		}
		catch(exception)
		{
			log.info('Invalid message received: %s', body.substring(0, 20));
			return;
		}
		log.debug('Got message to %s: %s', url, JSON.stringify(json, null, '\t'));
		analyze(json);
	}

	function analyze(info)
	{
		if (!info.action || !info.repository)
		{
			return log.info('Missing action/repository in message: %s / %s', info.action, info.repository);
		}
		var operationName = FUNCTIONS[info.action];
		if (!operationName)
		{
			return handleUnknownAction(info);
		}
		var operation = self[operationName];
		operation(info);
	}

	self.createComment = function(info)
	{
		// create comment in card
		var repoName = info.repository.name;
		var sender = info.sender.login;
		var title = '[' + repoName + '] ' + info.issue.title;
		var body = info.sender.login + ': ' + info.comment.body + '\n\n[View on GitHub](' + info.comment.html_url + ')';
		if (!body.contains('+1') && !body.contains('-1'))
		{
			return log.info('Comment created by %s on %s: %s', sender, title, body);
		}
		board.findCard(title, function(error, card)
		{
			if (error)
			{
				return log.error('Could not find card %s: %s', title, error);
			}
			if (!card)
			{
				return log.info('Could not find card for %s', title);
			}
			board.addComment(card.id, body, function(error)
			{
				if (error)
				{
					return log.error('Could not add comment to %s: %s', title, error);
				}
				log.info('Comment %s added to %s', body, title);
				reviewPullRequest(card);
			});
		});
	};

	function reviewPullRequest(card)
	{
		board.readComments(card.id, function(error, comments)
		{
			if (!comments.length)
			{
				return;
			}
			var destination;
			var labels = 'orange';
			if (card.idList == options.inProgress)
			{
				destination = options.underReview;
			}
			var score = computeScore(comments);
			if (score >= 2)
			{
				destination = options.reviewed;
				labels = 'green';
			}
			else if (score < 0)
			{
				destination = options.blocked;
				labels = 'red';
			}
			else if (card.idList == options.blocked)
			{
				destination = options.underReview;
			}
			var params = {
				name: getNameWithScore(card.name, score),
				labels: labels,
			};
			board.modifyCard(card.id, params, function(error)
			{
				if (error)
				{
					log.error('Could not rename card to %s: %s', params.name, error);
				}
				else
				{
					log.info('Card renamed to %s with labels %s', params.name, labels);
				}
				if (!destination || card.idList == options.merged)
				{
					return;
				}
				board.moveCard(card.id, destination, function(error)
				{
					if (error)
					{
						log.error('Could not move card %s: %s', card.name, error);
					}
					else
					{
						log.info('Card %s moved to %s', card.name, destination);
					}
				});
			});
		});
	}

	self.openPullRequest = function(info)
	{
		var title = getTitle(info);
		if (!title)
		{
			return;
		}
		var link = '[View on GitHub](' + info.pull_request.html_url + ')\n\n';
		var description = link + info.pull_request.body;
		var username = info.pull_request.user.login;
		board.createCard(title, description, options.inProgress, function(error)
		{
			if (error)
			{
				return log.error('Could not create card: %s', error);
			}
			return log.info('Created card for %s by %s', title, username);
		});
	};

	function getTitle(info)
	{
		if (!info.pull_request)
		{
			return log.info('Missing pull request to open');
		}
		var repoName = info.repository.name;
		return '[' + repoName + '] ' + info.pull_request.title;
	}

	self.closePullRequest = function(info)
	{
		var title = getTitle(info);
		if (!title)
		{
			return;
		}
		var destination = 'cancelled';
		if (info.pull_request.merged)
		{
			destination = 'merged';
		}
		var listId = options[destination];
		board.moveCard(title, listId, function(error)
		{
			if (error)
			{
				return log.error('Could not move closed card %s to %s: %s', title, destination, error);
			}
			return log.info('Moved card for %s to %s', title, destination);
		});
	};

	self.reopenPullRequest = function(info)
	{
		var title = getTitle(info);
		if (!title)
		{
			return;
		}
		board.moveCard(title, options.inProgress, function(error)
		{
			if (error)
			{
				return log.error('Could not move reopened card %s: %s', title, error);
			}
			return log.info('Moved card for %s to in progress', title);
		});
	};

	function handleUnknownAction(info)
	{
		var filename = __dirname + '/../samples/' + info.action + '-sample.json';
		fs.writeFile(filename, JSON.stringify(info, null, '\t'), function(error)
		{
			if (error)
			{
				return log.error('Could not write action %s to file %s: %s', info.action, filename, error);
			}
			log.info('Received unknown action %s, written to %s', info.action, filename);
		});
	}
}

function computeScore(comments)
{
	var score = 0;
	var vetos = 0;
	var voted = {};
	comments.forEach(function(comment)
	{
		var text = comment.text.substringUpTo('\n');
		if (!text.contains(':'))
		{
			return;
		}
		var author = text.substringUpTo(':');
		if (author in voted)
		{
			return;
		}
		log.debug('%s votes %s', author, text.substringFrom(':'));
		if (text.contains('-'))
		{
			var veto = parseFloat(text.substringFrom('-'));
			vetos += veto;
			voted[author] = -veto;
		}
		if (text.contains('+'))
		{
			var vote = parseFloat(text.substringFrom('+'));
			score += Math.min(vote, 1);
			voted[author] = vote;
		}
	});
	log.info('Score: %s, vetos: %s, tally: %s', score, vetos, JSON.stringify(voted, null, '\t'));
	if (vetos > 0)
	{
		return -vetos;
	}
	return score;
}

function testComputeScore(callback)
{
	var comments = [{
		text: 'alexfernandez: +1',
	}, {
		text: 'alexfernandez: +2',
	}];
	testing.assertEquals(computeScore(comments), 1, 'Two +x from the same dev', callback);
	comments.push({text: 'cmdrTaco: -1'});
	testing.assertEquals(computeScore(comments), -1, 'One -1', callback);
	comments.push({text: 'starryEyed: +1'});
	testing.assertEquals(computeScore(comments), -1, 'Still -1', callback);
	comments.unshift({text: 'cmdrTaco: +1'});
	testing.assertEquals(computeScore(comments), +3, '+1 supersedes -1', callback);
	testing.success(callback);
}

function getNameWithScore(name, score)
{
	var original = name;
	if (name.contains(' (') && name.endsWith(')'))
	{
		original = name.substringUpToLast(' (');
	}
	var text = String(score);
	if (score > 0)
	{
		text = '+' + score;
	}
	return original + ' (' + text + ')';
}

function testNameWithScore(callback)
{
	var name = '[test] Test PR';
	var withScore = getNameWithScore(name, 2);
	testing.assertEquals('[test] Test PR (+2)', withScore, 'Invalid name +2', callback);
	withScore = getNameWithScore(withScore, -0.5);
	testing.assertEquals('[test] Test PR (-0.5)', withScore, 'Invalid name -0.5', callback);
	testing.success(callback);
}

/**
 * Run the tests.
 */
exports.test = function(callback)
{
	testing.run([
		testStartServer,
		testComputeScore,
		testNameWithScore,
	], 5000, callback);
};

// start server if invoked directly
if (__filename == process.argv[1])
{
	exports.test(testing.show);
}

<|endoftext|>


<commit_before>/*!
 * express
 * Copyright(c) 2009-2013 TJ Holowaychuk
 * Copyright(c) 2013 Roman Shtylman
 * Copyright(c) 2014-2015 Douglas Christopher Wilson
 * MIT Licensed
 */

'use strict';

/**
 * Module dependencies.
 * @private
 */

var pathRegexp = require('path-to-regexp');
var debug = require('debug')('express:router:layer');

/**
 * Module variables.
 * @private
 */

var hasOwnProperty = Object.prototype.hasOwnProperty;

/**
 * Module exports.
 * @public
 */

module.exports = Layer;

function Layer(path, options, fn) {
  if (!(this instanceof Layer)) {
    return new Layer(path, options, fn);
  }

  debug('new %s', path);
  var opts = options || {};

  this.handle = fn;
  this.name = fn.name || '<anonymous>';
  this.params = undefined;
  this.path = undefined;
  this.regexp = pathRegexp(path, this.keys = [], opts);

  if (path === '/' && opts.end === false) {
    this.regexp.fast_slash = true;
  }
}

/**
 * Handle the error for the layer.
 *
 * @param {Error} error
 * @param {Request} req
 * @param {Response} res
 * @param {function} next
 * @api private
 */

Layer.prototype.handle_error = function handle_error(error, req, res, next) {
  var fn = this.handle;

  if (fn.length !== 4) {
    // not a standard error handler
    return next(error);
  }

  try {
    fn(error, req, res, next);
  } catch (err) {
    next(err);
  }
};

/**
 * Handle the request for the layer.
 *
 * @param {Request} req
 * @param {Response} res
 * @param {function} next
 * @api private
 */

Layer.prototype.handle_request = function handle(req, res, next) {
  var fn = this.handle;

  if (fn.length > 3) {
    // not a standard request handler
    return next();
  }

  try {
    fn(req, res, next);
  } catch (err) {
    next(err);
  }
};

/**
 * Check if this route matches `path`, if so
 * populate `.params`.
 *
 * @param {String} path
 * @return {Boolean}
 * @api private
 */

Layer.prototype.match = function match(path) {
  if (path == null) {
    // no path, nothing matches
    this.params = undefined;
    this.path = undefined;
    return false;
  }

  if (this.regexp.fast_slash) {
    // fast path non-ending match for / (everything matches)
    this.params = {};
    this.path = '';
    return true;
  }

  var m = this.regexp.exec(path);

  if (!m) {
    this.params = undefined;
    this.path = undefined;
    return false;
  }

  // store values
  this.params = {};
  this.path = m[0];

  var keys = this.keys;
  var params = this.params;

  for (var i = 1; i < m.length; i++) {
    var key = keys[i - 1];
    var prop = key.name;
    var val = decode_param(m[i]);

    if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
      params[prop] = val;
    }
  }

  return true;
};

/**
 * Decode param value.
 *
 * @param {string} val
 * @return {string}
 * @private
 */

function decode_param(val) {
  if (typeof val !== 'string' || val.length === 0) {
    return val;
  }

  try {
    return decodeURIComponent(val);
  } catch (err) {
    if (err instanceof URIError) {
      err.message = 'Failed to decode param \'' + val + '\'';
      err.status = err.statusCode = 400;
    }

    throw err;
  }
}
<commit_msg>lint: consolidate layer match failure path<commit_after>/*!
 * express
 * Copyright(c) 2009-2013 TJ Holowaychuk
 * Copyright(c) 2013 Roman Shtylman
 * Copyright(c) 2014-2015 Douglas Christopher Wilson
 * MIT Licensed
 */

'use strict';

/**
 * Module dependencies.
 * @private
 */

var pathRegexp = require('path-to-regexp');
var debug = require('debug')('express:router:layer');

/**
 * Module variables.
 * @private
 */

var hasOwnProperty = Object.prototype.hasOwnProperty;

/**
 * Module exports.
 * @public
 */

module.exports = Layer;

function Layer(path, options, fn) {
  if (!(this instanceof Layer)) {
    return new Layer(path, options, fn);
  }

  debug('new %s', path);
  var opts = options || {};

  this.handle = fn;
  this.name = fn.name || '<anonymous>';
  this.params = undefined;
  this.path = undefined;
  this.regexp = pathRegexp(path, this.keys = [], opts);

  if (path === '/' && opts.end === false) {
    this.regexp.fast_slash = true;
  }
}

/**
 * Handle the error for the layer.
 *
 * @param {Error} error
 * @param {Request} req
 * @param {Response} res
 * @param {function} next
 * @api private
 */

Layer.prototype.handle_error = function handle_error(error, req, res, next) {
  var fn = this.handle;

  if (fn.length !== 4) {
    // not a standard error handler
    return next(error);
  }

  try {
    fn(error, req, res, next);
  } catch (err) {
    next(err);
  }
};

/**
 * Handle the request for the layer.
 *
 * @param {Request} req
 * @param {Response} res
 * @param {function} next
 * @api private
 */

Layer.prototype.handle_request = function handle(req, res, next) {
  var fn = this.handle;

  if (fn.length > 3) {
    // not a standard request handler
    return next();
  }

  try {
    fn(req, res, next);
  } catch (err) {
    next(err);
  }
};

/**
 * Check if this route matches `path`, if so
 * populate `.params`.
 *
 * @param {String} path
 * @return {Boolean}
 * @api private
 */

Layer.prototype.match = function match(path) {
  var match

  if (path != null) {
    if (this.regexp.fast_slash) {
      // fast path non-ending match for / (everything matches)
      this.params = {}
      this.path = ''
      return true
    }

    // match the path
    match = this.regexp.exec(path)
  }

  if (!match) {
    this.params = undefined;
    this.path = undefined;
    return false;
  }

  // store values
  this.params = {};
  this.path = match[0]

  var keys = this.keys;
  var params = this.params;

  for (var i = 1; i < match.length; i++) {
    var key = keys[i - 1];
    var prop = key.name;
    var val = decode_param(match[i])

    if (val !== undefined || !(hasOwnProperty.call(params, prop))) {
      params[prop] = val;
    }
  }

  return true;
};

/**
 * Decode param value.
 *
 * @param {string} val
 * @return {string}
 * @private
 */

function decode_param(val) {
  if (typeof val !== 'string' || val.length === 0) {
    return val;
  }

  try {
    return decodeURIComponent(val);
  } catch (err) {
    if (err instanceof URIError) {
      err.message = 'Failed to decode param \'' + val + '\'';
      err.status = err.statusCode = 400;
    }

    throw err;
  }
}
<|endoftext|>


<commit_before>module.exports = function(crowi, app) {
  'use strict'

  var slackHelper = require('../util/slack')(crowi),
    Page = crowi.model('Page'),
    User = crowi.model('User'),
    actions = {}

  var api = (actions.api = {})

  function fetchPage(link) {}

  api.handleEvent = function(req, res) {
    if (req.body.type != null && req.body.type == 'url_verification') {
      verifyChallenge(req, res)
      return
    }

    let event = req.body.event
    switch (event.type) {
      case 'link_shared':
        unfurl(req, res)
        break
      default:
        break
    }
  }

  function verifyChallenge(req, res) {
    res.send(req.body.challenge)
  }

  function unfurl(req, res) {
    const https = require('https')
    const HOST = 'slack.com'
    const PATH = '/api/chat.unfurl'

    const link = req.body.event.links[0]
    const channel = req.body.event.channel
    const url = require('url').parse(link.url, true)

    var pagePath = url.path || null
    var pageId = url.query.page_id || null // TODO: handling
    var revisionId = url.query.revision_id || null

    User.findAllUsers()
      .then(function(users) {
        return Page.findPage(pagePath, users[0], revisionId)
      })
      .then(function(pageData) {
        let unfurls = {}
        unfurls[link.url] = {
          title: pageData.path,
          text: slackHelper.prepareAttachmentTextForCreate(pageData),
        }

        let config = crowi.getConfig()
        let token = config.notification['slack:token']
        let postData = {
          token: token,
          channel: channel,
          ts: req.body.event.message_ts,
          unfurls: encodeURIComponent(JSON.stringify(unfurls)),
        }

        let postDataStr = JSON.stringify(postData)

        let options = {
          host: HOST,
          port: 443,
          path: PATH + '?token=' + postData['token'] + '&channel=' + postData['channel'] + '&ts=' + postData['ts'] + '&unfurls=' + postData['unfurls'],
          method: 'POST',
          headers: {
            'Content-Type': 'application/json;charset=utf-8',
          },
        }

        let slackReq = https.request(options, slackRes => {
          slackRes.setEncoding('utf8')
        })
        slackReq.on('error', e => {
          console.error('failed to send a request to Slack: ' + e.message)
        })
        slackReq.end()
        res.send(200)
      })
      .catch(function(err) {
        console.error('failed in fetching page: ' + err)
        res.send(404)
      })
  }

  return actions
}
<commit_msg>Use crowi.slack<commit_after>module.exports = function(crowi, app) {
  'use strict'

  var slack = crowi.slack,
    Page = crowi.model('Page'),
    User = crowi.model('User'),
    actions = {}

  var api = (actions.api = {})

  function fetchPage(link) {}

  api.handleEvent = function(req, res) {
    if (req.body.type != null && req.body.type == 'url_verification') {
      verifyChallenge(req, res)
      return
    }

    let event = req.body.event
    switch (event.type) {
      case 'link_shared':
        unfurl(req, res)
        break
      default:
        break
    }
  }

  function verifyChallenge(req, res) {
    res.send(req.body.challenge)
  }

  function unfurl(req, res) {
    const https = require('https')
    const HOST = 'slack.com'
    const PATH = '/api/chat.unfurl'

    const link = req.body.event.links[0]
    const channel = req.body.event.channel
    const url = require('url').parse(link.url, true)

    var pagePath = url.path || null
    var pageId = url.query.page_id || null // TODO: handling
    var revisionId = url.query.revision_id || null

    User.findAllUsers()
      .then(function(users) {
        return Page.findPage(pagePath, users[0], revisionId)
      })
      .then(function(pageData) {
        let unfurls = {}
        unfurls[link.url] = {
          title: pageData.path,
          text: slack.prepareAttachmentTextForCreate(pageData),
        }

        let config = crowi.getConfig()
        let token = config.notification['slack:token']
        let postData = {
          token: token,
          channel: channel,
          ts: req.body.event.message_ts,
          unfurls: encodeURIComponent(JSON.stringify(unfurls)),
        }

        let postDataStr = JSON.stringify(postData)

        let options = {
          host: HOST,
          port: 443,
          path: PATH + '?token=' + postData['token'] + '&channel=' + postData['channel'] + '&ts=' + postData['ts'] + '&unfurls=' + postData['unfurls'],
          method: 'POST',
          headers: {
            'Content-Type': 'application/json;charset=utf-8',
          },
        }

        let slackReq = https.request(options, slackRes => {
          slackRes.setEncoding('utf8')
        })
        slackReq.on('error', e => {
          console.error('failed to send a request to Slack: ' + e.message)
        })
        slackReq.end()
        res.send(200)
      })
      .catch(function(err) {
        console.error('failed in fetching page: ' + err)
        res.send(404)
      })
  }

  return actions
}
<|endoftext|>


<commit_before>/*
 * Script tag fetch
 *
 * When load.metadata.scriptLoad is true, we load via script tag injection.
 */
(function() {

  if (typeof document != 'undefined')
    var head = document.getElementsByTagName('head')[0];

  var curSystem;

  // if doing worker executing, this is set to the load record being executed
  var workerLoad = null;

  // interactive mode handling method courtesy RequireJS
  var ieEvents = head && (function() {
    var s = document.createElement('script');
    var isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]';
    return s.attachEvent && !(s.attachEvent.toString && s.attachEvent.toString().indexOf('[native code') < 0) && !isOpera;
  })();

  // IE interactive-only part
  // we store loading scripts array as { script: <script>, load: {...} }
  var interactiveLoadingScripts = [];
  var interactiveScript = null;
  function getInteractiveScriptLoad() {
    if (interactiveScript && interactiveScript.readyState === 'interactive')
      return interactiveScript;

    for (var i = 0; i < interactiveLoadingScripts.length; i++)
      if (interactiveLoadingScripts[i].script.readyState == 'interactive') {
        interactiveScript = interactiveLoadingScripts[i].script;
        return interactiveLoadingScripts[i].load;
      }
  }

  // System.register, System.registerDynamic, AMD define pipeline
  // this is called by the above methods when they execute
  // we then run the reduceRegister_ collection function either immediately
  // if we are in IE and know the currently executing script (interactive)
  // or later if we need to wait for the synchronous load callback to know the script
  var loadingCnt = 0;
  var registerQueue = [];
  hook('pushRegister_', function(pushRegister) {
    return function(register) {
      // if using eval-execution then skip
      if (pushRegister.call(this, register))
        return false;

      // if using worker execution, then we're done
      if (workerLoad)
        this.reduceRegister_(workerLoad, register);

      // detect if we know the currently executing load (IE)
      // if so, immediately call reduceRegister
      else if (ieEvents)
        this.reduceRegister_(getInteractiveScriptLoad(), register);

      // otherwise, add to our execution queue
      // to call reduceRegister on sync script load event
      else if (loadingCnt)
        registerQueue.push(register);

      // if we're not currently loading anything though
      // then do the reduction against a null load
      // (out of band named define or named register)
      // note even in non-script environments, this catch is used
      else
        this.reduceRegister_(null, register);

      return true;
    };
  });

  function webWorkerImport(loader, load) {
    return new Promise(function(resolve, reject) {
      if (load.metadata.integrity)
        reject(new Error('Subresource integrity checking is not supported in web workers.'));

      workerLoad = load;
      try {
        importScripts(load.address);
      }
      catch(e) {
        workerLoad = null;
        reject(e);
      }
      workerLoad = null;

      // if nothing registered, then something went wrong
      if (!load.metadata.entry)
        reject(new Error(load.address + ' did not call System.register or AMD define'));

      resolve('');
    });
  }

  // override fetch to use script injection
  hook('fetch', function(fetch) {
    return function(load) {
      var loader = this;

      if (!load.metadata.scriptLoad || (!isBrowser && !isWorker))
        return fetch.call(this, load);

      if (isWorker)
        return webWorkerImport(loader, load);

      return new Promise(function(resolve, reject) {
        var s = document.createElement('script');

        s.async = true;

        if (load.metadata.integrity)
          s.setAttribute('integrity', load.metadata.integrity);

        if (ieEvents) {
          s.attachEvent('onreadystatechange', complete);
          interactiveLoadingScripts.push({
            script: s,
            load: load
          });
        }
        else {
          s.addEventListener('load', complete, false);
          s.addEventListener('error', error, false);
        }

        loadingCnt++;

        curSystem = __global.System;

        s.src = load.address;
        head.appendChild(s);

        function complete(evt) {
          if (s.readyState && s.readyState != 'loaded' && s.readyState != 'complete')
            return;

          loadingCnt--;

          // complete call is sync on execution finish
          // (in ie already done reductions)
          if (!interactiveScript && !registerQueue.length) {
            loader.reduceRegister_(load);
          }
          else if (!ieEvents) {
            for (var i = 0; i < registerQueue.length; i++)
              loader.reduceRegister_(load, registerQueue[i]);
            registerQueue = [];
          }
          else {
            interactiveScript = null;
          }

          cleanup();

          // if nothing registered, then something went wrong
          if (!load.metadata.entry && !load.metadata.bundle)
            reject(new Error(load.name + ' did not call System.register or AMD define'));

          resolve('');
        }

        function error(evt) {
          cleanup();
          reject(new Error('Unable to load script ' + load.address));
        }

        function cleanup() {
          __global.System = curSystem;

          if (s.detachEvent) {
            s.detachEvent('onreadystatechange', complete);
            for (var i = 0; i < interactiveLoadingScripts.length; i++)
              if (interactiveLoadingScripts[i].script == s)
                interactiveLoadingScripts.splice(i, 1);
          }
          else {
            s.removeEventListener('load', complete, false);
            s.removeEventListener('error', error, false);
          }

          head.removeChild(s);
        }
      });
    };
  });
})();
<commit_msg>fixes IE global fallback bug<commit_after>/*
 * Script tag fetch
 *
 * When load.metadata.scriptLoad is true, we load via script tag injection.
 */
(function() {

  if (typeof document != 'undefined')
    var head = document.getElementsByTagName('head')[0];

  var curSystem;

  // if doing worker executing, this is set to the load record being executed
  var workerLoad = null;

  // interactive mode handling method courtesy RequireJS
  var ieEvents = head && (function() {
    var s = document.createElement('script');
    var isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]';
    return s.attachEvent && !(s.attachEvent.toString && s.attachEvent.toString().indexOf('[native code') < 0) && !isOpera;
  })();

  // IE interactive-only part
  // we store loading scripts array as { script: <script>, load: {...} }
  var interactiveLoadingScripts = [];
  var interactiveScript;
  function getInteractiveScriptLoad() {
    if (interactiveScript && interactiveScript.script.readyState === 'interactive')
      return interactiveScript.load;

    for (var i = 0; i < interactiveLoadingScripts.length; i++)
      if (interactiveLoadingScripts[i].script.readyState == 'interactive') {
        interactiveScript = interactiveLoadingScripts[i];
        return interactiveScript.load;
      }
  }

  // System.register, System.registerDynamic, AMD define pipeline
  // this is called by the above methods when they execute
  // we then run the reduceRegister_ collection function either immediately
  // if we are in IE and know the currently executing script (interactive)
  // or later if we need to wait for the synchronous load callback to know the script
  var loadingCnt = 0;
  var registerQueue = [];
  hook('pushRegister_', function(pushRegister) {
    return function(register) {
      // if using eval-execution then skip
      if (pushRegister.call(this, register))
        return false;

      // if using worker execution, then we're done
      if (workerLoad)
        this.reduceRegister_(workerLoad, register);

      // detect if we know the currently executing load (IE)
      // if so, immediately call reduceRegister
      else if (ieEvents)
        this.reduceRegister_(getInteractiveScriptLoad(), register);

      // otherwise, add to our execution queue
      // to call reduceRegister on sync script load event
      else if (loadingCnt)
        registerQueue.push(register);

      // if we're not currently loading anything though
      // then do the reduction against a null load
      // (out of band named define or named register)
      // note even in non-script environments, this catch is used
      else
        this.reduceRegister_(null, register);

      return true;
    };
  });

  function webWorkerImport(loader, load) {
    return new Promise(function(resolve, reject) {
      if (load.metadata.integrity)
        reject(new Error('Subresource integrity checking is not supported in web workers.'));

      workerLoad = load;
      try {
        importScripts(load.address);
      }
      catch(e) {
        workerLoad = null;
        reject(e);
      }
      workerLoad = null;

      // if nothing registered, then something went wrong
      if (!load.metadata.entry)
        reject(new Error(load.address + ' did not call System.register or AMD define'));

      resolve('');
    });
  }

  // override fetch to use script injection
  hook('fetch', function(fetch) {
    return function(load) {
      var loader = this;

      if (!load.metadata.scriptLoad || (!isBrowser && !isWorker))
        return fetch.call(this, load);

      if (isWorker)
        return webWorkerImport(loader, load);

      return new Promise(function(resolve, reject) {
        var s = document.createElement('script');

        s.async = true;

        if (load.metadata.integrity)
          s.setAttribute('integrity', load.metadata.integrity);

        if (ieEvents) {
          s.attachEvent('onreadystatechange', complete);
          interactiveLoadingScripts.push({
            script: s,
            load: load
          });
        }
        else {
          s.addEventListener('load', complete, false);
          s.addEventListener('error', error, false);
        }

        loadingCnt++;

        curSystem = __global.System;

        s.src = load.address;
        head.appendChild(s);

        function complete(evt) {
          if (s.readyState && s.readyState != 'loaded' && s.readyState != 'complete')
            return;

          loadingCnt--;

          // complete call is sync on execution finish
          // (in ie already done reductions)
          if (!load.metadata.entry && !registerQueue.length) {
            loader.reduceRegister_(load);
          }
          else if (!ieEvents) {
            for (var i = 0; i < registerQueue.length; i++)
              loader.reduceRegister_(load, registerQueue[i]);
            registerQueue = [];
          }

          cleanup();

          // if nothing registered, then something went wrong
          if (!load.metadata.entry && !load.metadata.bundle)
            reject(new Error(load.name + ' did not call System.register or AMD define'));

          resolve('');
        }

        function error(evt) {
          cleanup();
          reject(new Error('Unable to load script ' + load.address));
        }

        function cleanup() {
          __global.System = curSystem;

          if (s.detachEvent) {
            s.detachEvent('onreadystatechange', complete);
            for (var i = 0; i < interactiveLoadingScripts.length; i++)
              if (interactiveLoadingScripts[i].script == s) {
                if (interactiveScript.script == s)
                  interactiveScript = null;
                interactiveLoadingScripts.splice(i, 1);
              }
          }
          else {
            s.removeEventListener('load', complete, false);
            s.removeEventListener('error', error, false);
          }

          head.removeChild(s);
        }
      });
    };
  });
})();
<|endoftext|>