<commit_before>/**
 * Module dependencies
 */
var neo4j = require('./neo4j-lib');

exports.initialize = function initializeSchema(schema, callback) {
    schema.client = new neo4j.GraphDatabase(schema.settings.url);
    schema.adapter = new Neo4j(schema.client);
};

function Neo4j(client) {
    this._models = {};
    this.client = client;
    this.cache = {};
}

Neo4j.prototype.define = function defineModel(descr) {
    this.mixClassMethods(descr.model, descr.properties);
    this.mixInstanceMethods(descr.model.prototype, descr.properties);
    this._models[descr.model.modelName] = descr;
};

Neo4j.prototype.createIndexHelper = function (class, indexName) {
    var db = this.client;
    var method = 'findBy' + indexName[0].toUpperCase() + indexName.substr(1);
    class[method] = function (value, cb) {
        db.getIndexedNode(class.modelName, indexName, value, function (err, node) {
            if (err) return cb(err);
            if (node) {
                node.data.id = node.id;
                cb(null, new class(node.data));
            } else {
                cb(null, null);
            }
        });
    };
};

Neo4j.prototype.mixClassMethods = function mixClassMethods(class, properties) {
    var neo = this;

    Object.keys(properties).forEach(function (name) {
        if (properties[name].index) {
            neo.createIndexHelper(class, name);
        }
    });

    /**
     * @param from - id of object to check relation from
     * @param to - id of object to check relation to
     * @param type - type of relation
     * @param direction - all | incoming | outgoing
     * @param cb - callback (err, rel || false)
     */
    class.relationshipExists = function relationshipExists(from, to, type, direction, cb) {
        neo.node(from, function (err, node) {
            if (err) return cb(err);
            node._getRelationships(direction, type, function (err, rels) {
                if (err) return cb(err);
                var found = false;
                if (rels && rels.forEach) {
                    rels.forEach(function (r) {
                        if (r.start.id === from && r.end.id === to) {
                            found = true;
                        }
                    });
                }
                cb(err, found);
            });
        });
    };

    class.createRelationshipTo = function createRelationshipTo(id1, id2, type, data, cb) {
        var fromNode, toNode;
        neo.node(id1, function (err, node) {
            if (err) return cb(err);
            fromNode = node;
            ok();
        });
        neo.node(id2, function (err, node) {
            if (err) return cb(err);
            toNode = node;
            ok();
        });
        function ok() {
            if (fromNode && toNode) {
                fromNode.createRelationshipTo(toNode, type, cleanup(data), cb);
            }
        }
    };

    class.createRelationshipFrom = function createRelationshipFrom(id1, id2, type, data, cb) {
        class.createRelationshipTo(id2, id1, type, data, cb);
    }

    // only create relationship if it is not exists
    class.ensureRelationshipTo = function (id1, id2, type, data, cb) {
        class.relationshipExists(id1, id2, type, 'outgoing', function (err, exists) {
            if (err) return cb(err);
            if (exists) return cb(null);
            class.createRelationshipTo(id1, id2, type, data, cb);
        });
    }
};

Neo4j.prototype.mixInstanceMethods = function mixInstanceMethods(proto) {
    var neo = this;

    /**
     * @param obj - Object or id of object to check relation with
     * @param type - type of relation
     * @param cb - callback (err, rel || false)
     */
    proto.isInRelationWith = function isInRelationWith(obj, type, direction, cb) {
        this.constructor.relationshipExists(this.id, obj.id || obj, type, 'all', cb);
    };
};

Neo4j.prototype.node = function find(id, callback) {
    if (this.cache[id]) {
        callback(null, this.cache[id]);
    } else {
        this.client.getNodeById(id, function (err, node) {
            this.cache[id] = node;
            callback(err, node);
        }.bind(this));
    }
};

Neo4j.prototype.create = function create(model, data, callback) {
    data.nodeType = model;
    var node = this.client.createNode();
    node.data = cleanup(data);
    node.save(function (err) {
        if (err) {
            return callback(err);
        }
        this.cache[node.id] = node;
        node.index(model, 'id', node.id, function (err) {
            if (err) return callback(err);
            this.updateIndexes(model, node, function (err) {
                if (err) return callback(err);
                callback(null, node.id);
            });
        }.bind(this));
    }.bind(this));
};

Neo4j.prototype.updateIndexes = function updateIndexes(model, node, cb) {
    var props = this._models[model].properties;
    var wait = 1;
    Object.keys(props).forEach(function (key) {
        if (props[key].index) {
            wait += 1;
            node.index(model, key, node.data[key], done);
        }
    });

    done();

    var error = false;
    function done(err) {
        error = error || err;
        if (--wait === 0) {
            cb(error);
        }
    }
};

Neo4j.prototype.save = function save(model, data, callback) {
    this.node(data.id, function (err, node) {
        if (err) return callback(err);
        node.data = cleanup(data);
        node.save(callback);
    });
};

Neo4j.prototype.exists = function exists(model, id, callback) {
    delete this.cache[id];
    this.node(id, callback);
};

Neo4j.prototype.find = function find(model, id, callback) {
    delete this.cache[id];
    this.node(id, function (err, node) {
        if (node && node.data) {
            node.data.id = id;
        }
        callback(err, this.readFromDb(model, node && node.data));
    }.bind(this));
};

Neo4j.prototype.readFromDb = function readFromDb(model, data) {
    if (!data) return data;
    var res = {};
    var props = this._models[model].properties;
    Object.keys(data).forEach(function (key) {
        if (props[key] && props[key].type.name === 'Date') {
            res[key] = new Date(data[key]);
        } else {
            res[key] = data[key];
        }
    });
    return res;
};

Neo4j.prototype.destroy = function destroy(model, id, callback) {
    var force = true;
    this.node(id, function (err, node) {
        if (err) return callback(err);
        node.delete(function (err) {
            if (err) return callback(err);
            delete this.cache[id];
        }.bind(this), force);
    });
};

Neo4j.prototype.all = function all(model, filter, callback) {
    this.client.queryNodeIndex(model, 'id:*', function (err, nodes) {
        callback(err, filter && nodes ? nodes.filter(applyFilter(filter)) : nodes);
    });
};

function applyFilter(filter) {
    if (typeof filter === 'function') {
        return filter;
    }
    var keys = Object.keys(filter);
    return function (obj) {
        var pass = true;
        keys.forEach(function (key) {
            if (!test(filter[key], obj.data[key])) {
                pass = false;
            }
        });
        return pass;
    }

    function test(example, value) {
        if (typeof value === 'string' && example && example.constructor.name === 'RegExp') {
            return value.match(example);
        }
        // not strict equality
        return example == value;
    }
}

Neo4j.prototype.destroyAll = function destroyAll(model, callback) {
    var wait, error = null;
    this.all(model, null, function (err, collection) {
        if (err) return callback(err);
        wait = collection.length;
        collection && collection.forEach && collection.forEach(function (node) {
            node.delete(done, true);
        });
    });

    function done(err) {
        error = error || err;
        if (--wait === 0) {
            callback(error);
        }
    }
};

Neo4j.prototype.count = function count(model, callback) {
    this.all(model, null, function (err, collection) {
        callback(err, collection ? collection.length : 0);
    });
};

Neo4j.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
    data.id = id;
    this.node(id, function (err, node) {
        this.save(model, merge(node.data, data), cb);
    }.bind(this));
};

function cleanup(data) {
    if (!data) return null;
    var res = {};
    Object.keys(data).forEach(function (key) {
        var v = data[key];
        if (v === null) {
            // skip
            // console.log('skip null', key);
        } else if (v && v.constructor.name === 'Array' && v.length === 0) {
            // skip
            // console.log('skip blank array', key);
        } else if (typeof v !== 'undefined') {
            res[key] = v;
        }
    });
    return res;
}

function merge(base, update) {
    Object.keys(update).forEach(function (key) {
        base[key] = update[key];
    });
    return base;
}
<commit_msg>Update neo4j: safe callbacks, update indexes on save<commit_after>/**
 * Module dependencies
 */
var neo4j = require('./neo4j-lib');

exports.initialize = function initializeSchema(schema, callback) {
    schema.client = new neo4j.GraphDatabase(schema.settings.url);
    schema.adapter = new Neo4j(schema.client);
};

function Neo4j(client) {
    this._models = {};
    this.client = client;
    this.cache = {};
}

Neo4j.prototype.define = function defineModel(descr) {
    this.mixClassMethods(descr.model, descr.properties);
    this.mixInstanceMethods(descr.model.prototype, descr.properties);
    this._models[descr.model.modelName] = descr;
};

Neo4j.prototype.createIndexHelper = function (class, indexName) {
    var db = this.client;
    var method = 'findBy' + indexName[0].toUpperCase() + indexName.substr(1);
    class[method] = function (value, cb) {
        db.getIndexedNode(class.modelName, indexName, value, function (err, node) {
            if (err) return cb(err);
            if (node) {
                node.data.id = node.id;
                cb(null, new class(node.data));
            } else {
                cb(null, null);
            }
        });
    };
};

Neo4j.prototype.mixClassMethods = function mixClassMethods(class, properties) {
    var neo = this;

    Object.keys(properties).forEach(function (name) {
        if (properties[name].index) {
            neo.createIndexHelper(class, name);
        }
    });

    /**
     * @param from - id of object to check relation from
     * @param to - id of object to check relation to
     * @param type - type of relation
     * @param direction - all | incoming | outgoing
     * @param cb - callback (err, rel || false)
     */
    class.relationshipExists = function relationshipExists(from, to, type, direction, cb) {
        neo.node(from, function (err, node) {
            if (err) return cb(err);
            node._getRelationships(direction, type, function (err, rels) {
                if (err && cb) return cb(err);
                if (err && !cb) throw err;
                var found = false;
                if (rels && rels.forEach) {
                    rels.forEach(function (r) {
                        if (r.start.id === from && r.end.id === to) {
                            found = true;
                        }
                    });
                }
                cb  && cb(err, found);
            });
        });
    };

    class.createRelationshipTo = function createRelationshipTo(id1, id2, type, data, cb) {
        var fromNode, toNode;
        neo.node(id1, function (err, node) {
            if (err && cb) return cb(err);
            if (err && !cb) throw err;
            fromNode = node;
            ok();
        });
        neo.node(id2, function (err, node) {
            if (err && cb) return cb(err);
            if (err && !cb) throw err;
            toNode = node;
            ok();
        });
        function ok() {
            if (fromNode && toNode) {
                fromNode.createRelationshipTo(toNode, type, cleanup(data), cb);
            }
        }
    };

    class.createRelationshipFrom = function createRelationshipFrom(id1, id2, type, data, cb) {
        class.createRelationshipTo(id2, id1, type, data, cb);
    }

    // only create relationship if it is not exists
    class.ensureRelationshipTo = function (id1, id2, type, data, cb) {
        class.relationshipExists(id1, id2, type, 'outgoing', function (err, exists) {
            if (err && cb) return cb(err);
            if (err && !cb) throw err;
            if (exists) return cb && cb(null);
            class.createRelationshipTo(id1, id2, type, data, cb);
        });
    }
};

Neo4j.prototype.mixInstanceMethods = function mixInstanceMethods(proto) {
    var neo = this;

    /**
     * @param obj - Object or id of object to check relation with
     * @param type - type of relation
     * @param cb - callback (err, rel || false)
     */
    proto.isInRelationWith = function isInRelationWith(obj, type, direction, cb) {
        this.constructor.relationshipExists(this.id, obj.id || obj, type, 'all', cb);
    };
};

Neo4j.prototype.node = function find(id, callback) {
    if (this.cache[id]) {
        callback(null, this.cache[id]);
    } else {
        this.client.getNodeById(id, function (err, node) {
            this.cache[id] = node;
            callback(err, node);
        }.bind(this));
    }
};

Neo4j.prototype.create = function create(model, data, callback) {
    data.nodeType = model;
    var node = this.client.createNode();
    node.data = cleanup(data);
    node.save(function (err) {
        if (err) {
            return callback(err);
        }
        this.cache[node.id] = node;
        node.index(model, 'id', node.id, function (err) {
            if (err) return callback(err);
            this.updateIndexes(model, node, function (err) {
                if (err) return callback(err);
                callback(null, node.id);
            });
        }.bind(this));
    }.bind(this));
};

Neo4j.prototype.updateIndexes = function updateIndexes(model, node, cb) {
    var props = this._models[model].properties;
    var wait = 1;
    Object.keys(props).forEach(function (key) {
        if (props[key].index) {
            wait += 1;
            node.index(model, key, node.data[key], done);
        }
    });

    done();

    var error = false;
    function done(err) {
        error = error || err;
        if (--wait === 0) {
            cb(error);
        }
    }
};

Neo4j.prototype.save = function save(model, data, callback) {
    var self = this;
    this.node(data.id, function (err, node) {
        if (err) return callback(err);
        node.data = cleanup(data);
        node.save(function (err) {
            if (err) return callback(err);
            self.updateIndexes(model, node, function (err) {
                if (err) return console.log(err);
                callback(null);
            });
        });
    });
};

Neo4j.prototype.exists = function exists(model, id, callback) {
    delete this.cache[id];
    this.node(id, callback);
};

Neo4j.prototype.find = function find(model, id, callback) {
    delete this.cache[id];
    this.node(id, function (err, node) {
        if (node && node.data) {
            node.data.id = id;
        }
        callback(err, this.readFromDb(model, node && node.data));
    }.bind(this));
};

Neo4j.prototype.readFromDb = function readFromDb(model, data) {
    if (!data) return data;
    var res = {};
    var props = this._models[model].properties;
    Object.keys(data).forEach(function (key) {
        if (props[key] && props[key].type.name === 'Date') {
            res[key] = new Date(data[key]);
        } else {
            res[key] = data[key];
        }
    });
    return res;
};

Neo4j.prototype.destroy = function destroy(model, id, callback) {
    var force = true;
    this.node(id, function (err, node) {
        if (err) return callback(err);
        node.delete(function (err) {
            if (err) return callback(err);
            delete this.cache[id];
        }.bind(this), force);
    });
};

Neo4j.prototype.all = function all(model, filter, callback) {
    this.client.queryNodeIndex(model, 'id:*', function (err, nodes) {
        callback(err, filter && nodes ? nodes.filter(applyFilter(filter)) : nodes);
    });
};

function applyFilter(filter) {
    if (typeof filter === 'function') {
        return filter;
    }
    var keys = Object.keys(filter);
    return function (obj) {
        var pass = true;
        keys.forEach(function (key) {
            if (!test(filter[key], obj.data[key])) {
                pass = false;
            }
        });
        return pass;
    }

    function test(example, value) {
        if (typeof value === 'string' && example && example.constructor.name === 'RegExp') {
            return value.match(example);
        }
        // not strict equality
        return example == value;
    }
}

Neo4j.prototype.destroyAll = function destroyAll(model, callback) {
    var wait, error = null;
    this.all(model, null, function (err, collection) {
        if (err) return callback(err);
        wait = collection.length;
        collection && collection.forEach && collection.forEach(function (node) {
            node.delete(done, true);
        });
    });

    function done(err) {
        error = error || err;
        if (--wait === 0) {
            callback(error);
        }
    }
};

Neo4j.prototype.count = function count(model, callback) {
    this.all(model, null, function (err, collection) {
        callback(err, collection ? collection.length : 0);
    });
};

Neo4j.prototype.updateAttributes = function updateAttributes(model, id, data, cb) {
    data.id = id;
    this.node(id, function (err, node) {
        this.save(model, merge(node.data, data), cb);
    }.bind(this));
};

function cleanup(data) {
    if (!data) return null;
    var res = {};
    Object.keys(data).forEach(function (key) {
        var v = data[key];
        if (v === null) {
            // skip
            // console.log('skip null', key);
        } else if (v && v.constructor.name === 'Array' && v.length === 0) {
            // skip
            // console.log('skip blank array', key);
        } else if (typeof v !== 'undefined') {
            res[key] = v;
        }
    });
    return res;
}

function merge(base, update) {
    Object.keys(update).forEach(function (key) {
        base[key] = update[key];
    });
    return base;
}
<|endoftext|>


<commit_before>window.onload = function() {
	var innerWidth = window.innerWidth;
	var innerHeight = window.innerHeight;
	var gameRatio = innerWidth/innerHeight;
	var game = new Phaser.Game(Math.ceil(480*gameRatio), 480, Phaser.CANVAS);
	var ninja;
	var ninjaGravity = 800;
	var ninjaJumpPower;
	var score=0;
	var scoreText;
     var topScore;
     var powerBar;
     var powerTween;
     var placedPoles;
	var poleGroup;
	var poleGroup;
    var obstacleGroup;
     var lowerObstacleInterval = game.rnd.between(2000,5000);
     var upperObstacleInterval = game.rnd.between(7000,9000);
     var ballObstacleInterval = game.rnd.between(10000,10000);
	var platforms;
     var minPoleGap = 100;
     var maxPoleGap = 300;
     var ninjaJumping;
     var ninjaFallingDown;
     var obstacleSpeed = -200;
     var poleSpeed = -300;
     var play = function(game){}
     play.prototype = {
		preload:function(){
			game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
			game.scale.setScreenSize(true);
			game.load.image("ninja", "ninja.png");
			game.load.image("ball", "ball.png");
			game.load.image("pole", "pole.png");
			game.load.image("ground","floor.png");
             game.load.image("powerbar", "powerbar.png");
             game.load.spritesheet('dude', 'assets/dude.png', 58, 87);
               game.load.image("powerbar", "powerbar.png");
            game.load.image("person1","person1.png");
            game.load.image("person2","sonic.png");
            game.load.image("couch","couch.png");
            game.load.image("test","bullet1.png");
            game.load.image("background", "background.png");
		},
		create:function(){
			ninjaJumping = false;
			ninjaFallingDown = false;
			score = 0;
			placedPoles = 0;
			poleGroup = game.add.group();
            obstacleGroup = game.add.group();
			topScore = localStorage.getItem("topFlappyScore")==null?0:localStorage.getItem("topFlappyScore");
			scoreText = game.add.text(10,10,"-",{
				font:"bold 16px Arial"
			});
			updateScore();
			game.stage.backgroundColor = "#87CEEB";
            //background = game.add.tileSprite(0, 0, 1000, 600, "background");
			game.physics.startSystem(Phaser.Physics.ARCADE);
			ninja = game.add.sprite(game.width/2 - game.width/4,0,"dude");
			ninja.anchor.set(0.5);
			ninja.lastPole = 1;
			game.physics.arcade.enable(ninja);
			ninja.body.gravity.y = ninjaGravity;
			game.input.onDown.add(prepareToJump, this);

			addPole(80);
			game.time.events.loop(lowerObstacleInterval, addObstacleL);
            game.time.events.loop(upperObstacleInterval, addObstacleH);
            game.time.events.loop(ballObstacleInterval, addObstacleBall);
            ninja.animations.add('right', [1, 2, 3, 4, 5], 15, true);
            ninja.scale.setTo(.65,.65);
			addObstacleL();
            addObstacleH();
			platforms = game.add.group();
			//  We will enable physics for any object that is created in this group
			platforms.enableBody = true;
			// Here we create the ground.
			var ground = platforms.create(0, game.world.height - 64, 'ground');
			//  Scale it to fit the width of the game (the original sprite is 400x32 in size)
			ground.scale.setTo(3, 3);
			//  This stops it from falling away when you jump on it
			ground.body.immovable = true;
		},
		update:function(){
			//game.physics.arcade.collide(ninja, poleGroup, checkLanding);
            game.physics.arcade.collide(ninja, obstacleGroup, die);
			game.physics.arcade.collide(ninja, platforms, onGround);
            game.physics.arcade.collide(obstacleGroup, platforms, bounce);
			if(ninja.y>game.height){
				die();
			}
			ninja.animations.play('right');
			if(score % 5) {
				increaseObstacleSpeed();
			}
			if(score % 50) {
				increaseObstacleCount();
			}
		}
	}
     game.state.add("Play",play);
     game.state.start("Play");
	function bounce(item,platform){
		item.body.velocity.y = -1 * this.startheight;
	}
	function updateScore(){
		scoreText.text = "Score: "+score+"\nBest: "+topScore;
	}
	function prepareToJump(){
		if(ninja.body.velocity.y==0){
	          powerBar = game.add.sprite(ninja.x,ninja.y-50,"powerbar");
	          powerBar.width = 0;
	          powerTween = game.add.tween(powerBar).to({
			   width:100
			}, 1000, "Linear",true);
	          game.input.onDown.remove(prepareToJump, this);
	          game.input.onUp.add(jump, this);
          }
	}
     function jump(){
          ninjaJumpPower= -powerBar.width*3-100
          powerBar.destroy();
          game.tweens.removeAll();
          ninja.body.velocity.y = ninjaJumpPower*2;
          ninjaJumping = true;
          powerTween.stop();
          game.input.onUp.remove(jump, this);
     }
     function addNewPoles(){
     	var maxPoleX = 0;
		poleGroup.forEach(function(item) {
			maxPoleX = Math.max(item.x,maxPoleX)
		});
		var nextPolePosition = maxPoleX + game.rnd.between(minPoleGap,maxPoleGap);
		addPole(nextPolePosition);
	}
	function addPole(poleX){
		if(poleX<game.width*2){
			placedPoles++;
			var pole = new Pole(game,poleX,game.rnd.between(250,380));
			game.add.existing(pole);
	          pole.anchor.set(0.5,0);
			poleGroup.add(pole);
			var nextPolePosition = poleX + game.rnd.between(minPoleGap,maxPoleGap);
			addPole(nextPolePosition);
		}
	}
    function addObstacleL(){
        var obstacleNumber = game.rnd.between(1,2);
		if (obstacleNumber == 2) {
            var obstacle = new Obstacle(game,1000,game.world.height - 55, obstacleNumber);
            game.add.existing(obstacle);
            obstacleGroup.add(obstacle);
            var obstacle2 = new Obstacle(game,960,game.world.height - 57, obstacleNumber + 1);
            game.add.existing(obstacle2);
            obstacleGroup.add(obstacle2);
        } else {
            var obstacle = new Obstacle(game,1000,game.world.height - 95, obstacleNumber);
            game.add.existing(obstacle);
            obstacleGroup.add(obstacle);
        }
	}
    function addObstacleH(){
        var obstacleNumber = 4/*game.rnd.between(1,2)*/;
		var obstacle = new Obstacle(game,1500,game.rnd.between(150, 250), obstacleNumber);
		game.add.existing(obstacle);
		obstacleGroup.add(obstacle);
	}
    function addObstacleBall(){
        //var obstacleNumber = game.rnd.between(1,2);
        //if (2 == obstacleNumber) {
            var obstacle = new Obstacle(game,1000,game.world.height-50,5);
            game.add.existing(obstacle);
            obstacleGroup.add(obstacle);
    }
	function increaseObstacleCount() {

	}
	function increaseObstacleSpeed() {
		if(obstacleSpeed > -600) {
			obstacleSpeed -= .2;
			poleSpeed -= .2;
		}
	}
	function die(){
		localStorage.setItem("topFlappyScore",Math.max(score,topScore));
		game.state.start("Play");
		obstacleSpeed = -200;
		poleSpeed = -300;
	}
	function onGround(n,g) {
		if(n.y <= g.y + n.y/2) {
			if(Math.abs(border)>20){
				var border = n.x-g.x
				n.body.velocity.x=border*2;
				n.body.velocity.y=-200;
			}
			if(ninjaJumping){
               	ninjaJumping = false;
               	game.input.onDown.add(prepareToJump, this);
          	}
		}
	}
	function checkLanding(n,p){
		if(p.y>=n.y+n.height/2){
			var border = n.x-p.x
			if(Math.abs(border)>20){
				n.body.velocity.x=border*2;
				n.body.velocity.y=-200;
			}
			var poleDiff = p.poleNumber-n.lastPole;
			if(poleDiff>0){
				score+= Math.pow(2,poleDiff);
				updateScore();
				n.lastPole= p.poleNumber;
			}
			if(ninjaJumping){
               	ninjaJumping = false;
               	game.input.onDown.add(prepareToJump, this);
          	}
		}
		else{
			ninjaFallingDown = true;
			poleGroup.forEach(function(item) {
				item.body.velocity.x = 0;
			});
		}
	}
	Pole = function (game, x, y) {
		Phaser.Sprite.call(this, game, x, y, "pole");
		game.physics.enable(this, Phaser.Physics.ARCADE);
          this.body.immovable = true;
          this.poleNumber = placedPoles;
	};
	Pole.prototype = Object.create(Phaser.Sprite.prototype);
	Pole.prototype.constructor = Pole;
	Pole.prototype.update = function() {
          // if(ninjaJumping && !ninjaFallingDown){
               this.body.velocity.x = poleSpeed;
          // }
          // else{
          //      this.body.velocity.x = 0
          // }
		if(this.x<-this.width){
			this.destroy();
			addNewPoles();
		}
	}
    Obstacle = function (game, x, y, obstacleNumber, startheight) {
		if (obstacleNumber == 1) {
            Phaser.Sprite.call(this, game, x, y - 10, "couch");
        } else if (obstacleNumber == 2) {
            Phaser.Sprite.call(this, game, x, y - 50, "person1");
        } else if (obstacleNumber == 3) {
            Phaser.Sprite.call(this, game, x, y - 50, "person2");
        } else if (obstacleNumber == 4) {
            Phaser.Sprite.call(this, game, x, y, "test");
        } else if (obstacleNumber == 5) {
            startheight = y-(75*game.rnd.between(1,3));
            Phaser.Sprite.call(this, game, x, startheight,"ball");

        }
        if(obstacleNumber==5)
        {
            game.physics.enable(this, Phaser.Physics.ARCADE);
            this.body.gravity.y = 500;
            this.body.immovable = false;
            this.body.velocity.x = obstacleSpeed;
            this.giveScore = true;
        }
        else
        {
            game.physics.enable(this, Phaser.Physics.ARCADE);
		    this.body.immovable = true;
            this.body.velocity.x = obstacleSpeed;
            this.giveScore = true;
        }
	};

	Obstacle.prototype = Object.create(Phaser.Sprite.prototype);
	Obstacle.prototype.constructor = Obstacle;

	Obstacle.prototype.update = function() {
		if(this.x+this.width<ninja.x && this.giveScore){
			score++;
			updateScore();
			this.giveScore = false;
		}
		if(this.x<-this.width){
			this.destroy();
		}
	};
}<commit_msg>Revert "yes"<commit_after>window.onload = function() {
	var innerWidth = window.innerWidth;
	var innerHeight = window.innerHeight;
	var gameRatio = innerWidth/innerHeight;
	var game = new Phaser.Game(Math.ceil(480*gameRatio), 480, Phaser.CANVAS);
	var ninja;
	var ninjaGravity = 800;
	var ninjaJumpPower;
	var score=0;
	var scoreText;
     var topScore;
     var powerBar;
     var powerTween;
     var placedPoles;
	var poleGroup;
	var poleGroup;
    var obstacleGroup;
     var lowerObstacleInterval = game.rnd.between(2000,5000);
     var upperObstacleInterval = game.rnd.between(7000,9000);
     var ballObstacleInterval = game.rnd.between(10000,10000);
	var platforms;
     var minPoleGap = 100;
     var maxPoleGap = 300;
     var ninjaJumping;
     var ninjaFallingDown;
     var obstacleSpeed = -200;
     var poleSpeed = -300;
     var play = function(game){}
     play.prototype = {
		preload:function(){
			game.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL;
			game.scale.setScreenSize(true);
			game.load.image("ninja", "ninja.png");
			game.load.image("ball", "ball.png");
			game.load.image("pole", "pole.png");
			game.load.image("ground","floor.png");
             game.load.image("powerbar", "powerbar.png");
             game.load.spritesheet('dude', 'assets/dude.png', 58, 87);
               game.load.image("powerbar", "powerbar.png");
            game.load.image("person1","person1.png");
            game.load.image("person2","sonic.png");
            game.load.image("couch","couch.png");
            game.load.image("test","bullet1.png");
            game.load.image("background", "background.png");
		},
		create:function(){
			ninjaJumping = false;
			ninjaFallingDown = false;
			score = 0;
			placedPoles = 0;
			poleGroup = game.add.group();
            obstacleGroup = game.add.group();
			topScore = localStorage.getItem("topFlappyScore")==null?0:localStorage.getItem("topFlappyScore");
			scoreText = game.add.text(10,10,"-",{
				font:"bold 16px Arial"
			});
			updateScore();
			game.stage.backgroundColor = "#87CEEB";
            //background = game.add.tileSprite(0, 0, 1000, 600, "background");
			game.physics.startSystem(Phaser.Physics.ARCADE);
			ninja = game.add.sprite(game.width/2 - game.width/4,0,"dude");
			ninja.anchor.set(0.5);
			ninja.lastPole = 1;
			game.physics.arcade.enable(ninja);
			ninja.body.gravity.y = ninjaGravity;
			game.input.onDown.add(prepareToJump, this);

			ball = game.add.sprite(game.width/2,0,"ball");
			game.physics.arcade.enable(ball);
			ball.body.gravity.y = 800;

			addPole(80);
			game.time.events.loop(lowerObstacleInterval, addObstacleL);
            game.time.events.loop(upperObstacleInterval, addObstacleH);
            game.time.events.loop(ballObstacleInterval, addObstacleBall);
            ninja.animations.add('right', [1, 2, 3, 4, 5], 15, true);
            ninja.scale.setTo(.65,.65);
			addObstacleL();
            addObstacleH();
            addObstacleBall();
			platforms = game.add.group();
			//  We will enable physics for any object that is created in this group
			platforms.enableBody = true;
			// Here we create the ground.
			var ground = platforms.create(0, game.world.height - 64, 'ground');
			//  Scale it to fit the width of the game (the original sprite is 400x32 in size)
			ground.scale.setTo(3, 3);
			//  This stops it from falling away when you jump on it
			ground.body.immovable = true;
		},
		update:function(){
			//game.physics.arcade.collide(ninja, poleGroup, checkLanding);
            game.physics.arcade.collide(ninja, obstacleGroup, die);
			game.physics.arcade.collide(ninja, platforms, onGround);
			game.physics.arcade.collide(ball, platforms, bounce);
            game.physics.arcade.collide(obstacleGroup, platforms, bounce);
			if(ninja.y>game.height){
				die();
			}
			ninja.animations.play('right');
			if(score % 5) {
				increaseObstacleSpeed();
			}
			if(score % 50) {
				increaseObstacleCount();
			}
		}
	}
     game.state.add("Play",play);
     game.state.start("Play");
	function bounce(item,platform){
		item.body.velocity.y = -1 * this.startheight;
	}
	function updateScore(){
		scoreText.text = "Score: "+score+"\nBest: "+topScore;
	}
	function prepareToJump(){
		if(ninja.body.velocity.y==0){
	          powerBar = game.add.sprite(ninja.x,ninja.y-50,"powerbar");
	          powerBar.width = 0;
	          powerTween = game.add.tween(powerBar).to({
			   width:100
			}, 1000, "Linear",true);
	          game.input.onDown.remove(prepareToJump, this);
	          game.input.onUp.add(jump, this);
          }
	}
     function jump(){
          ninjaJumpPower= -powerBar.width*3-100
          powerBar.destroy();
          game.tweens.removeAll();
          ninja.body.velocity.y = ninjaJumpPower*2;
          ninjaJumping = true;
          powerTween.stop();
          game.input.onUp.remove(jump, this);
     }
     function addNewPoles(){
     	var maxPoleX = 0;
		poleGroup.forEach(function(item) {
			maxPoleX = Math.max(item.x,maxPoleX)
		});
		var nextPolePosition = maxPoleX + game.rnd.between(minPoleGap,maxPoleGap);
		addPole(nextPolePosition);
	}
	function addPole(poleX){
		if(poleX<game.width*2){
			placedPoles++;
			var pole = new Pole(game,poleX,game.rnd.between(250,380));
			game.add.existing(pole);
	          pole.anchor.set(0.5,0);
			poleGroup.add(pole);
			var nextPolePosition = poleX + game.rnd.between(minPoleGap,maxPoleGap);
			addPole(nextPolePosition);
		}
	}
    function addObstacleL(){
        var obstacleNumber = game.rnd.between(1,2);
		if (obstacleNumber == 2) {
            var obstacle = new Obstacle(game,1000,game.world.height - 55, obstacleNumber);
            game.add.existing(obstacle);
            obstacleGroup.add(obstacle);
            var obstacle2 = new Obstacle(game,960,game.world.height - 57, obstacleNumber + 1);
            game.add.existing(obstacle2);
            obstacleGroup.add(obstacle2);
        } else {
            var obstacle = new Obstacle(game,1000,game.world.height - 95, obstacleNumber);
            game.add.existing(obstacle);
            obstacleGroup.add(obstacle);
        }
	}
    function addObstacleH(){
        var obstacleNumber = 4/*game.rnd.between(1,2)*/;
		var obstacle = new Obstacle(game,1500,game.rnd.between(150, 250), obstacleNumber);
		game.add.existing(obstacle);
		obstacleGroup.add(obstacle);
	}
    function addObstacleBall(){
        //var obstacleNumber = game.rnd.between(1,2);
        //if (2 == obstacleNumber) {
            var obstacle = new Obstacle(game,1000,game.world.height-50,5);
            game.add.existing(obstacle);
            obstacleGroup.add(obstacle);
    }
	function increaseObstacleCount() {

	}
	function increaseObstacleSpeed() {
		if(obstacleSpeed > -600) {
			obstacleSpeed -= .2;
			poleSpeed -= .2;
		}
	}
	function die(){
		localStorage.setItem("topFlappyScore",Math.max(score,topScore));
		game.state.start("Play");
		obstacleSpeed = -200;
		poleSpeed = -300;
	}
	function onGround(n,g) {
		if(n.y <= g.y + n.y/2) {
			if(Math.abs(border)>20){
				var border = n.x-g.x
				n.body.velocity.x=border*2;
				n.body.velocity.y=-200;
			}
			if(ninjaJumping){
               	ninjaJumping = false;
               	game.input.onDown.add(prepareToJump, this);
          	}
		}
	}
	function checkLanding(n,p){
		if(p.y>=n.y+n.height/2){
			var border = n.x-p.x
			if(Math.abs(border)>20){
				n.body.velocity.x=border*2;
				n.body.velocity.y=-200;
			}
			var poleDiff = p.poleNumber-n.lastPole;
			if(poleDiff>0){
				score+= Math.pow(2,poleDiff);
				updateScore();
				n.lastPole= p.poleNumber;
			}
			if(ninjaJumping){
               	ninjaJumping = false;
               	game.input.onDown.add(prepareToJump, this);
          	}
		}
		else{
			ninjaFallingDown = true;
			poleGroup.forEach(function(item) {
				item.body.velocity.x = 0;
			});
		}
	}
	Pole = function (game, x, y) {
		Phaser.Sprite.call(this, game, x, y, "pole");
		game.physics.enable(this, Phaser.Physics.ARCADE);
          this.body.immovable = true;
          this.poleNumber = placedPoles;
	};
	Pole.prototype = Object.create(Phaser.Sprite.prototype);
	Pole.prototype.constructor = Pole;
	Pole.prototype.update = function() {
          // if(ninjaJumping && !ninjaFallingDown){
               this.body.velocity.x = poleSpeed;
          // }
          // else{
          //      this.body.velocity.x = 0
          // }
		if(this.x<-this.width){
			this.destroy();
			addNewPoles();
		}
	}
    Obstacle = function (game, x, y, obstacleNumber, startheight) {
		if (obstacleNumber == 1) {
            Phaser.Sprite.call(this, game, x, y - 10, "couch");
        } else if (obstacleNumber == 2) {
            Phaser.Sprite.call(this, game, x, y - 50, "person1");
        } else if (obstacleNumber == 3) {
            Phaser.Sprite.call(this, game, x, y - 50, "person2");
        } else if (obstacleNumber == 4) {
            Phaser.Sprite.call(this, game, x, y, "test");
        } else if (obstacleNumber == 5) {
            startheight = y-(75*game.rnd.between(1,3));
            Phaser.Sprite.call(this, game, x, startheight,"ball");

        }
        if(obstacleNumber==5)
        {
            game.physics.enable(this, Phaser.Physics.ARCADE);
            this.body.gravity.y = 500;
            this.body.immovable = false;
            this.body.velocity.x = obstacleSpeed;
            this.giveScore = true;
        }
        else
        {
            game.physics.enable(this, Phaser.Physics.ARCADE);
		    this.body.immovable = true;
            this.body.velocity.x = obstacleSpeed;
            this.giveScore = true;
        }
	};

	Obstacle.prototype = Object.create(Phaser.Sprite.prototype);
	Obstacle.prototype.constructor = Obstacle;

	Obstacle.prototype.update = function() {
		if(this.x+this.width<ninja.x && this.giveScore){
			score++;
			updateScore();
			this.giveScore = false;
		}
		if(this.x<-this.width){
			this.destroy();
		}
	};
}<|endoftext|>


<commit_before>(function($){
  var Profile = Backbone.Model.extend({
    defaults: {
      //default to our fearless leader Gabe
      steam_id:"76561197960287930",
      avatar_full:"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/c5/c5d56249ee5d28a07db4ac9f7f60af961fab5426_full.jpg",
      avatar_medium:"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/c5/c5d56249ee5d28a07db4ac9f7f60af961fab5426_medium.jpg",
      persona_name:"Rabscuttle",
      real_name:"Gabe",
      game_count:0,
      games:[]
    }
  })

  var List = Backbone.Collection.extend({
    model: Profile
  })

  var ProfileView = Backbone.View.extend({
    tagName:'div',
    initialize: function(){
      _.bindAll(this,'render', 'update_element', 'get_friends', 'unrender_friends', 'unrender_chosen')
      this.model.bind('change', this.update_element)
      this.collection = new List()
      this.collection.bind('add', this.append_friend)
      this.render()
    },

    render: function(){
      var html = "

"
        +this.model.get('persona_name')
        +"
"
        +(this.model.get('real_name') ==null?"":this.model.get('real_name'))
        +"

"
      $(this.el).html(html)
      $(this.el).addClass("lefty")
      $(this.el).attr('id', this.model.get('steam_id'))
      $(this.el).addClass("steamify bordered")
      return this
    },
    update_element: function(){
      this.unrender_friends()
      this.unrender_chosen()
      this.collection.reset()
      $("div#user_info").append(this.render().el)
      this.get_friends()
    },
    get_friends: function(){
      var self = this
      if(this.model.get('steam_id') != this.model.defaults.steam_id){
        $.getJSON(window.location+"api/v1/friends", {steam_id:this.model.get('steam_id')}).done(function(data){
          if(data.success == true){
            var friends_ids = []
            data.friends.forEach(function(friend){
              friends_ids[friends_ids.length] = friend.steam_id
            })
            $.getJSON(window.location+"api/v1/profiles", {steam_ids:friends_ids.join(",")}).done(function(data){
              if(data.success){
                self.collection.reset()
                self.unrender_friends()
                data.profiles.forEach(function(profile){
                  var friend_profile = new Profile()
                  friend_profile.set(profile)
                  self.collection.add(friend_profile)
                })
                $('input#search_friends').removeClass('hidden')
                $('div#num_friends').html("Showing "+self.collection.length+"/"+self.collection.length+" friends")
              }
            })
          }
        })
      }else{
        $('div#num_friends').html("")
      }
    },
    append_friend: function(friend){
      var friendView = new ProfileView({model:friend})
      $('div#friends', this.el).last().append(friendView.render().el)
    },
    unrender_friends: function(){
      $('div#friends').empty()
      $('input#search_friends').val("")
      $('div#num_friends').html("
Loading friends...
")
    },
    unrender_chosen: function(){
      $('div#user_info').empty()
    }
  })

  var MainView = Backbone.View.extend({
    el: $("body"),
    events: {
      'click button#find':'find_user',
      'keyup input#search_friends':'filter_friends',
      'click div.steamify':'choose_friends',
      'mousedown div.steamify':'click_div',
      'mouseup div.steamify':'unclick_div',
      'click button#compare':'compare_games',
      'click button#reset':'reset'
    },

    initialize: function(){
      _.bindAll(this, 'render', 'find_user', 'filter_friends', 'load_library', 'choose_friends', 'compare_games', 'reset', 'click_div', 'unclick_div')
      this.current_profile_model = new Profile()
      this.current_profile_view = new ProfileView({model:this.current_profile_model})
      this.chosen_friends = new List()
      this.chosen_friends.bind('add', this.append_chosen)
      this.render()
    },
    render: function(){
      $(this.el).append("

<input id='search_friends' class='hidden' placeholder='Search within friends' />

")
      $('div#title', this.el).append("
Let's play!
")
      $('div#find_user', this.el).append("
<input class='form-control' id='user' placeholder='steam id or custom url'/>

<button id='find'>Find me!</button><button id='reset' class='hidden'>Go Back</button>

<button id='compare'>Find games!</button>

")
      $('div#user_info').append(this.current_profile_view.render().el)
    },

    find_user: function(){
      $('div#compare_button').addClass('hidden')
      this.chosen_friends.reset()
      var user_input = $('#user').val()
      var currentModel = this.current_profile_model
      var self = this
      var updateModel = function(data){
        if(data.success == true){
          currentModel.set(data.profile)
          self.load_library()
        }
      }
      if(user_input.length == 17 && user_input.search(/[0-9]{17}/) == 0) { //raw id input
        $.getJSON(window.location+"api/v1/profile", {steam_id:this.steam_id}).done(updateModel)
      } else{
        $.getJSON(window.location+"api/v1/steam_id", {vanity_url:user_input}).done(function(data){
          if(data.success == true){
            $.getJSON(window.location+"api/v1/profile", {steam_id:data['steam_id']}).done(updateModel)
          }
        })
      }
    },
    load_library: function(){
      var self = this
      $.getJSON(window.location+"api/v1/games", {steam_id:self.current_profile_model.get("steam_id")}).done(function(data){
        if(data.success == true){
          self.current_profile_model.set(data,{silent:true})
        }
      })
    },
    filter_friends: function(event){
      var friend_to_find = $('input#search_friends').val().toUpperCase()
      var current_profile = this.current_profile_view
      var shown_counter = 0
      current_profile.collection.forEach(function(item){
        var name = item.get('persona_name').toUpperCase()
        if(friend_to_find != "" && name.indexOf(friend_to_find) == -1){
          $("div#"+item.get('steam_id'), "div#friends").addClass("hidden")
        }else{
          $("div#"+item.get('steam_id'), "div#friends").removeClass("hidden")
          shown_counter += 1
        }
      })
      $("div#num_friends", this.el).html("Showing "+shown_counter+"/"+current_profile.collection.length+" friends")

    },
    click_div: function(event){
      $(event.currentTarget).css('border-color', '#3498db')
    },
    unclick_div: function(event){
      setTimeout(function(){$(event.currentTarget).css('border-color', '#27ae60')}, 150)
    },
    choose_friends: function(event){
      var self = this
      if($('div#user_info').find('div#'+event.currentTarget.id).length == 0){
        if(event.currentTarget.id != this.current_profile_model.get('steam_id')){
          $.getJSON(window.location+"api/v1/profile", {steam_id:event.currentTarget.id}).done(function(data){
            if(data.success == true){
              var chosen_one_profile = new Profile()
              chosen_one_profile.set(data.profile)
              $.getJSON(window.location+"api/v1/games", {steam_id:chosen_one_profile.get('steam_id')}).done(function(data){
                if(data.success == true){
                  chosen_one_profile.set(data)
                  self.chosen_friends.add(chosen_one_profile)
                  $('div#compare_button', 'div#find_user').removeClass('hidden')
                }
              })
            }
          })
        }
      }
    },
    append_chosen: function(friend){
      var friendView = new ProfileView({model:friend})
      $('div#user_info').append(friendView.render().el)
    },
    compare_games: function(){
      $('button#find').addClass('hidden')
      $('button#reset').removeClass('hidden')
      $('div#friends_div').addClass("hidden")
      $('div#common_games').removeClass('hidden')
      $('div#message', 'div#common_games').html("
Loading common games...
")
      $('div#message', 'div#common_games').removeClass('hidden')
      $('div#compare_button').addClass('hidden')
      var my_games = this.current_profile_model.get('games')
      var common = $.map(my_games, function(element, index){
        return element.app_id
      })
      _(this.chosen_friends.models).each(function(friend){
        var friends_games = friend.get('games')
        friends_games = $.map(friends_games, function(element, index){
          return element.app_id
        })
        common = $.grep(common, function(element){
          return friends_games.indexOf(element) != -1
        })
      }, this)
      common = shuffleArray(common)
      var total = common.length
      $('div#message', 'div#common_games').html("
0 out of "+total+" games loaded
")
      common.forEach(function(app_id){
        $.getJSON(window.location+"api/v1/game_info", {app_id:app_id}).done(function(data){
          if(data.success == true){
            if(data.game.is_multiplayer == true){
              $('div#games', 'div#common_games').append("

"+data.game.title+"

"+data.game.image+"

")
            }
          }
          $('div#message', 'div#common_games').html("
"+(common.length-total)+" out of "+common.length+" games loaded
")
          total -= 1
          if(total <= 0){
            $('div#message', 'div#common_games').addClass("hidden")
          }
        })
      })
    },
    reset: function(){
      $('button#reset').addClass('hidden')
      $('button#find').removeClass('hidden')
      $('div#friends_div').removeClass('hidden')
      $('div#common_games').addClass('hidden')
      $('div#games', 'div#common_games').empty()
      $('input#search_friends').addClass('hidden')
      $('input#search_friends').val("")
      this.filter_friends()
      $('input#user').val("")
      this.current_profile_model.clear({silent:true}).set(this.current_profile_model.defaults)
      this.chosen_friends.reset()
    }
  })

  var mainView = new MainView()

//checks for an enter press on the user input so trigger the button click.
  $("input#user").keyup(function(event){
    if(event.keyCode == 13){
        $("#find").click();
    }
});

})(jQuery)

//used to shuffle the common games so that we don't always get the same order.
function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
}
<commit_msg>Removing the no-longer-existing outline class<commit_after>(function($){
  var Profile = Backbone.Model.extend({
    defaults: {
      //default to our fearless leader Gabe
      steam_id:"76561197960287930",
      avatar_full:"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/c5/c5d56249ee5d28a07db4ac9f7f60af961fab5426_full.jpg",
      avatar_medium:"https://steamcdn-a.akamaihd.net/steamcommunity/public/images/avatars/c5/c5d56249ee5d28a07db4ac9f7f60af961fab5426_medium.jpg",
      persona_name:"Rabscuttle",
      real_name:"Gabe",
      game_count:0,
      games:[]
    }
  })

  var List = Backbone.Collection.extend({
    model: Profile
  })

  var ProfileView = Backbone.View.extend({
    tagName:'div',
    initialize: function(){
      _.bindAll(this,'render', 'update_element', 'get_friends', 'unrender_friends', 'unrender_chosen')
      this.model.bind('change', this.update_element)
      this.collection = new List()
      this.collection.bind('add', this.append_friend)
      this.render()
    },

    render: function(){
      var html = "

"
        +this.model.get('persona_name')
        +"
"
        +(this.model.get('real_name') ==null?"":this.model.get('real_name'))
        +"

"
      $(this.el).html(html)
      $(this.el).addClass("lefty")
      $(this.el).attr('id', this.model.get('steam_id'))
      $(this.el).addClass("steamify bordered")
      return this
    },
    update_element: function(){
      this.unrender_friends()
      this.unrender_chosen()
      this.collection.reset()
      $("div#user_info").append(this.render().el)
      this.get_friends()
    },
    get_friends: function(){
      var self = this
      if(this.model.get('steam_id') != this.model.defaults.steam_id){
        $.getJSON(window.location+"api/v1/friends", {steam_id:this.model.get('steam_id')}).done(function(data){
          if(data.success == true){
            var friends_ids = []
            data.friends.forEach(function(friend){
              friends_ids[friends_ids.length] = friend.steam_id
            })
            $.getJSON(window.location+"api/v1/profiles", {steam_ids:friends_ids.join(",")}).done(function(data){
              if(data.success){
                self.collection.reset()
                self.unrender_friends()
                data.profiles.forEach(function(profile){
                  var friend_profile = new Profile()
                  friend_profile.set(profile)
                  self.collection.add(friend_profile)
                })
                $('input#search_friends').removeClass('hidden')
                $('div#num_friends').html("Showing "+self.collection.length+"/"+self.collection.length+" friends")
              }
            })
          }
        })
      }else{
        $('div#num_friends').html("")
      }
    },
    append_friend: function(friend){
      var friendView = new ProfileView({model:friend})
      $('div#friends', this.el).last().append(friendView.render().el)
    },
    unrender_friends: function(){
      $('div#friends').empty()
      $('input#search_friends').val("")
      $('div#num_friends').html("
Loading friends...
")
    },
    unrender_chosen: function(){
      $('div#user_info').empty()
    }
  })

  var MainView = Backbone.View.extend({
    el: $("body"),
    events: {
      'click button#find':'find_user',
      'keyup input#search_friends':'filter_friends',
      'click div.steamify':'choose_friends',
      'mousedown div.steamify':'click_div',
      'mouseup div.steamify':'unclick_div',
      'click button#compare':'compare_games',
      'click button#reset':'reset'
    },

    initialize: function(){
      _.bindAll(this, 'render', 'find_user', 'filter_friends', 'load_library', 'choose_friends', 'compare_games', 'reset', 'click_div', 'unclick_div')
      this.current_profile_model = new Profile()
      this.current_profile_view = new ProfileView({model:this.current_profile_model})
      this.chosen_friends = new List()
      this.chosen_friends.bind('add', this.append_chosen)
      this.render()
    },
    render: function(){
      $(this.el).append("

<input id='search_friends' class='hidden' placeholder='Search within friends' />

")
      $('div#title', this.el).append("
Let's play!
")
      $('div#find_user', this.el).append("
<input class='form-control' id='user' placeholder='steam id or custom url'/>

<button id='find'>Find me!</button><button id='reset' class='hidden'>Go Back</button>

<button id='compare'>Find games!</button>

")
      $('div#user_info').append(this.current_profile_view.render().el)
    },

    find_user: function(){
      $('div#compare_button').addClass('hidden')
      this.chosen_friends.reset()
      var user_input = $('#user').val()
      var currentModel = this.current_profile_model
      var self = this
      var updateModel = function(data){
        if(data.success == true){
          currentModel.set(data.profile)
          self.load_library()
        }
      }
      if(user_input.length == 17 && user_input.search(/[0-9]{17}/) == 0) { //raw id input
        $.getJSON(window.location+"api/v1/profile", {steam_id:this.steam_id}).done(updateModel)
      } else{
        $.getJSON(window.location+"api/v1/steam_id", {vanity_url:user_input}).done(function(data){
          if(data.success == true){
            $.getJSON(window.location+"api/v1/profile", {steam_id:data['steam_id']}).done(updateModel)
          }
        })
      }
    },
    load_library: function(){
      var self = this
      $.getJSON(window.location+"api/v1/games", {steam_id:self.current_profile_model.get("steam_id")}).done(function(data){
        if(data.success == true){
          self.current_profile_model.set(data,{silent:true})
        }
      })
    },
    filter_friends: function(event){
      var friend_to_find = $('input#search_friends').val().toUpperCase()
      var current_profile = this.current_profile_view
      var shown_counter = 0
      current_profile.collection.forEach(function(item){
        var name = item.get('persona_name').toUpperCase()
        if(friend_to_find != "" && name.indexOf(friend_to_find) == -1){
          $("div#"+item.get('steam_id'), "div#friends").addClass("hidden")
        }else{
          $("div#"+item.get('steam_id'), "div#friends").removeClass("hidden")
          shown_counter += 1
        }
      })
      $("div#num_friends", this.el).html("Showing "+shown_counter+"/"+current_profile.collection.length+" friends")

    },
    click_div: function(event){
      $(event.currentTarget).css('border-color', '#3498db')
    },
    unclick_div: function(event){
      setTimeout(function(){$(event.currentTarget).css('border-color', '#27ae60')}, 150)
    },
    choose_friends: function(event){
      var self = this
      if($('div#user_info').find('div#'+event.currentTarget.id).length == 0){
        if(event.currentTarget.id != this.current_profile_model.get('steam_id')){
          $.getJSON(window.location+"api/v1/profile", {steam_id:event.currentTarget.id}).done(function(data){
            if(data.success == true){
              var chosen_one_profile = new Profile()
              chosen_one_profile.set(data.profile)
              $.getJSON(window.location+"api/v1/games", {steam_id:chosen_one_profile.get('steam_id')}).done(function(data){
                if(data.success == true){
                  chosen_one_profile.set(data)
                  self.chosen_friends.add(chosen_one_profile)
                  $('div#compare_button', 'div#find_user').removeClass('hidden')
                }
              })
            }
          })
        }
      }
    },
    append_chosen: function(friend){
      var friendView = new ProfileView({model:friend})
      $('div#user_info').append(friendView.render().el)
    },
    compare_games: function(){
      $('button#find').addClass('hidden')
      $('button#reset').removeClass('hidden')
      $('div#friends_div').addClass("hidden")
      $('div#common_games').removeClass('hidden')
      $('div#message', 'div#common_games').html("
Loading common games...
")
      $('div#message', 'div#common_games').removeClass('hidden')
      $('div#compare_button').addClass('hidden')
      var my_games = this.current_profile_model.get('games')
      var common = $.map(my_games, function(element, index){
        return element.app_id
      })
      _(this.chosen_friends.models).each(function(friend){
        var friends_games = friend.get('games')
        friends_games = $.map(friends_games, function(element, index){
          return element.app_id
        })
        common = $.grep(common, function(element){
          return friends_games.indexOf(element) != -1
        })
      }, this)
      common = shuffleArray(common)
      var total = common.length
      $('div#message', 'div#common_games').html("
0 out of "+total+" games loaded
")
      common.forEach(function(app_id){
        $.getJSON(window.location+"api/v1/game_info", {app_id:app_id}).done(function(data){
          if(data.success == true){
            if(data.game.is_multiplayer == true){
              $('div#games', 'div#common_games').append("

"+data.game.title+"

"+data.game.image+"

")
            }
          }
          $('div#message', 'div#common_games').html("
"+(common.length-total)+" out of "+common.length+" games loaded
")
          total -= 1
          if(total <= 0){
            $('div#message', 'div#common_games').addClass("hidden")
          }
        })
      })
    },
    reset: function(){
      $('button#reset').addClass('hidden')
      $('button#find').removeClass('hidden')
      $('div#friends_div').removeClass('hidden')
      $('div#common_games').addClass('hidden')
      $('div#games', 'div#common_games').empty()
      $('input#search_friends').addClass('hidden')
      $('input#search_friends').val("")
      this.filter_friends()
      $('input#user').val("")
      this.current_profile_model.clear({silent:true}).set(this.current_profile_model.defaults)
      this.chosen_friends.reset()
    }
  })

  var mainView = new MainView()

//checks for an enter press on the user input so trigger the button click.
  $("input#user").keyup(function(event){
    if(event.keyCode == 13){
        $("#find").click();
    }
});

})(jQuery)

//used to shuffle the common games so that we don't always get the same order.
function shuffleArray(array) {
    for (var i = array.length - 1; i > 0; i--) {
        var j = Math.floor(Math.random() * (i + 1));
        var temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }
    return array;
}
<|endoftext|>


<commit_before>/*jslint node: true*/

"use strict";

var url = require("url"),
    lodash = require("lodash"),
    q = require("q"),
    site = require("../scraper").site;

module.exports = function archiver(spec) {
    var getDb = function getDb() {
            return spec.db;
        },

        getRecipeIds = function getRecipeIds() {
            return q(getDb().
                allDocs().
                then(function (result) {
                    return result.
                        rows.
                        map(function (row) {
                            return row.id;
                        });
                }));
        },

        putRecipe = function putRecipe(id, recipe, image) {
            var db = getDb();
            return q(db.
                put(lodash.merge({retrieved: new Date()}, recipe), id).
                then(function (result) {
                    db.putAttachment(
                        result.id,
                        "image",
                        result.rev,
                        image.buffer,
                        image.contentType
                    );
                }));
        },

        idify = function idify(recipeUrl) {
            var path = url.
                parse(recipeUrl).
                pathname.
                replace(/\/$/, "");
            if (path.length === 0) {
                return undefined;
            }
            return path.substr(path.lastIndexOf("/") + 1);
        },

        createTask = function createTask(recipesPage, recipeUrl) {
            return function () {
                return recipesPage.
                    createRecipePage(recipeUrl).
                    then(function (recipePage) {
                        return recipePage.
                            createRecipeImage().
                            then(function (recipeImage) {
                                return [recipePage.getRecipe(), recipeImage.toBuffer()];
                            });
                    }).
                    spread(function (recipe, image) {
                        putRecipe(idify(recipeUrl), recipe, image);
                    });
            };
        },

        createQueue = function createQueue() {
            var recipesPage = site.createRecipesPage();
            return q.
                all([recipesPage.getRecipeUrls(), getRecipeIds()]).
                spread(function (recipeUrls, recipeIds) {
                    return recipeUrls.
                        filter(function (recipeUrl) {
                            return !lodash.contains(recipeIds, idify(recipeUrl));
                        }).
                        map(function (recipeUrl) {
                            return createTask(recipesPage, recipeUrl);
                        });
                });
        },

        processQueue = function processQueue(queue) {
            var func = queue.shift();
            return func().then(function () {
                if (queue.length === 0) {
                    return;
                }
                return processQueue(queue);
            });
        },

        archiveRecipes = function archiveRecipes() {
            return createQueue().then(processQueue);
        },

        initialise = function initialise() {
            return {archiveRecipes: archiveRecipes};
        };

    return initialise();
};
<commit_msg>Added type field to recipe documents<commit_after>/*jslint node: true*/

"use strict";

var url = require("url"),
    lodash = require("lodash"),
    q = require("q"),
    site = require("../scraper").site;

module.exports = function archiver(spec) {
    var getDb = function getDb() {
            return spec.db;
        },

        getRecipeIds = function getRecipeIds() {
            return q(getDb().
                allDocs().
                then(function (result) {
                    return result.
                        rows.
                        map(function (row) {
                            return row.id;
                        });
                }));
        },

        putRecipe = function putRecipe(id, recipe, image) {
            var db = getDb();
            return q(db.
                put(lodash.merge({type: "recipe", retrieved: new Date()}, recipe), id).
                then(function (result) {
                    db.putAttachment(
                        result.id,
                        "image",
                        result.rev,
                        image.buffer,
                        image.contentType
                    );
                }));
        },

        idify = function idify(recipeUrl) {
            var path = url.
                parse(recipeUrl).
                pathname.
                replace(/\/$/, "");
            if (path.length === 0) {
                return undefined;
            }
            return path.substr(path.lastIndexOf("/") + 1);
        },

        createTask = function createTask(recipesPage, recipeUrl) {
            return function () {
                return recipesPage.
                    createRecipePage(recipeUrl).
                    then(function (recipePage) {
                        return recipePage.
                            createRecipeImage().
                            then(function (recipeImage) {
                                return [recipePage.getRecipe(), recipeImage.toBuffer()];
                            });
                    }).
                    spread(function (recipe, image) {
                        putRecipe(idify(recipeUrl), recipe, image);
                    });
            };
        },

        createQueue = function createQueue() {
            var recipesPage = site.createRecipesPage();
            return q.
                all([recipesPage.getRecipeUrls(), getRecipeIds()]).
                spread(function (recipeUrls, recipeIds) {
                    return recipeUrls.
                        filter(function (recipeUrl) {
                            return !lodash.contains(recipeIds, idify(recipeUrl));
                        }).
                        map(function (recipeUrl) {
                            return createTask(recipesPage, recipeUrl);
                        });
                });
        },

        processQueue = function processQueue(queue) {
            var func = queue.shift();
            return func().then(function () {
                if (queue.length === 0) {
                    return;
                }
                return processQueue(queue);
            });
        },

        archiveRecipes = function archiveRecipes() {
            return createQueue().then(processQueue);
        },

        initialise = function initialise() {
            return {archiveRecipes: archiveRecipes};
        };

    return initialise();
};
<|endoftext|>


<commit_before>'use strict';

/**
 * Configuration options for {@link Postgres}.
 * @typedef {Object} Postgres~Config
 * @property {String} [bin=postgres]
 * @property {String} [conf]
 * @property {(Number|String)} [port=5432]
 * @property {String} datadir
 * @property {String} shutdown
 */

/**
 * Invoked when an operation (i.e. {@link Postgres#open}) completes.
 * @callback Postgres~callback
 * @argument {Error} err
 */

/**
 * Emitted when a PostgreSQL server prints to stdout.
 * @event Postgres#stdout
 */

/**
 * Emitted when attempting to start a PostgreSQL server.
 * @event Postgres#opening
 */

/**
 * Emitted when a PostgreSQL server becomes ready to service requests.
 * @event Postgres#open
 */

/**
 * Emitted when attempting to stop a PostgreSQL server.
 * @event Postgres#closing
 */

/**
 * Emitted once a PostgreSQL server has stopped.
 * @event Postgres#close
 */

const childprocess = require('child_process');
const events = require('events');
const PromiseQueue = require('promise-queue');

/**
 * A collection of regualar expressions used by {@link Postgres.parseData} to
 * parse stdout and stderr messages.
 * @see Postgres.parseData
 * @readonly
 * @private
 * @type {Object.<String,RegExp>}
 */
const regExp = {
  terminalMessage: /ready\sto\saccept|already\sin\suse|denied|fatal|postgres:/i,
  errorMessage: /^(?:fatal|postgres):\s+(.*)/i,
  multipleWhiteSpace: /\s\s+/g,
  nonAlpha: /[^a-z]/ig,
  newline: /\r?\n/
};

/**
 * Start and stop a local PostgreSQL server like a boss.
 * @class
 */
class Postgres extends events.EventEmitter {

  /**
   * Get a function that takes chunks of stdin data, aggregates it, and passes
   * it in complete lines, one by one, to a given {@link Postgres~callback}.
   * @argument {Postgres~callback} callback
   * @return {Function}
   */
  static getTextLineAggregator(callback) {
    let buffer = '';

    return (data) => {
      const fragments = data.toString().split(regExp.newline);
      const lines = fragments.slice(0, fragments.length - 1);

      // If there was an unended line in the previous dump, complete it by
      // the first section.
      lines[0] = buffer + lines[0];

      // If there is an unended line in this dump, store it to be completed by
      // the next. This assumes there will be a terminating newline character
      // at some point. Generally, this is a safe assumption.
      buffer = fragments[fragments.length - 1];

      for (let line of lines) {
        callback(line);
      }
    };
  }

  /**
   * Populate a given {@link Postgres~Config} with values from a
   * given {@link Postgres~Config}.
   * @protected
   * @argument {Postgres~Config} source
   * @argument {Postgres~Config} target
   * @return {Postgres~Config}
   */
  static parseConfig(source, target) {
    if (target == null) {
      target = Object.create(null);
    }

    if (typeof source === 'string') {
      target.datadir = source;

      return target;
    }

    if (source == null || typeof source !== 'object') {
      return target;
    }

    if (source.bin != null) {
      target.bin = source.bin;
    }

    if (source.shutdown != null) {
      target.shutdown = source.shutdown;
    }

    if (source.conf != null) {
      target.conf = source.conf;

      return target;
    }

    if (source.datadir != null) {
      target.datadir = source.datadir;
    }

    if (source.port != null) {
      target.port = source.port;
    }

    return target;
  }

  /**
   * Parse process flags for PostgreSQL from a given {@link Postgres~Config}.
   * @protected
   * @argument {Postgres~Config} config
   * @return {Array.<String>}
   */
  static parseFlags(config) {
    if (config.conf != null) {
      return ['-c', `config_file=${config.conf}`];
    }

    const flags = [];

    if (config.datadir != null) {
      flags.push('-D', config.datadir);
    }

    if (config.port != null) {
      flags.push('-p', config.port);
    }

    return flags;
  }

  /**
   * Parse Redis server output for terminal messages.
   * @protected
   * @argument {String} string
   * @return {Object}
   */
  static parseData(string) {
    const matches = regExp.terminalMessage.exec(string);

    if (matches === null) {
      return null;
    }

    const result = {
      err: null,
      key: matches
        .pop()
        .replace(regExp.nonAlpha, '')
        .toLowerCase()
    };

    switch (result.key) {
      case 'readytoaccept':
        break;

      case 'alreadyinuse':
        result.err = new Error('Address already in use');
        result.err.code = -1;

        break;

      case 'denied':
        result.err = new Error('Permission denied');
        result.err.code = -2;

        break;

      case 'postgres':
      case 'fatal': {
        const matches = regExp.errorMessage.exec(string);

        result.err = new Error(
          matches === null ? string : matches.pop()
        );
        result.err.code = -3;

        break;
      }
    }

    return result;
  }

  /**
   * Start a given {@linkcode server}.
   * @protected
   * @fires Postgres#stdout
   * @fires Postgres#opening
   * @fires Postgres#open
   * @fires Postgres#closing
   * @fires Postgres#close
   * @argument {Postgres} server
   * @return {Promise}
   */
  static open(server) {
    if (server.isOpening) {
      return server.openPromise;
    }

    server.isOpening = true;
    server.isClosing = false;
    server.openPromise = server.promiseQueue.add(() => {
      if (server.isClosing || server.isRunning) {
        server.isOpening = false;

        return Promise.resolve(null);
      }

      return new Promise((resolve, reject) => {
        /**
         * A listener for the current server process' stdout that resolves or
         * rejects the current {@link Promise} when done.
         * @see Postgres.getTextLineAggregator
         * @see Postgres.parseData
         * @argument {Buffer} buffer
         * @return {undefined}
         */
        const dataListener = Postgres.getTextLineAggregator((string) => {
          const result = Postgres.parseData(string);

          if (result === null) {
            return;
          }

          server.process.stdout.removeListener('data', dataListener);
          server.process.stderr.removeListener('data', dataListener);

          server.isOpening = false;

          if (result.err === null) {
            server.isRunning = true;

            server.emit('open');
            resolve(null);
          }
          else {
            server.isClosing = true;

            server.emit('closing');
            server.process.once('close', () => reject(result.err));
          }
        });

        /**
         * A listener to close the server when the current process exits.
         * @return {undefined}
         */
        const exitListener = () => {
          // istanbul ignore next
          server.close();
        };

        /**
         * Get a text line aggregator that emits a given {@linkcode event}
         * for the current server.
         * @see Postgres.getTextLineAggregator
         * @argument {String} event
         * @return {Function}
         */
        const getDataPropagator = (event) =>
          Postgres.getTextLineAggregator((line) => server.emit(event, line));

        server.emit('opening');

        const flags = Postgres.parseFlags(server.config);

        flags.push('-c', `unix_socket_directories=${__dirname}`);

        server.process = childprocess.spawn(server.config.bin, flags);

        server.process.stderr.on('data', dataListener);
        server.process.stderr.on('data', getDataPropagator('stdout'));
        server.process.stdout.on('data', dataListener);
        server.process.stdout.on('data', getDataPropagator('stdout'));
        server.process.on('close', () => {
          server.process = null;
          server.isRunning = false;
          server.isClosing = false;

          process.removeListener('exit', exitListener);
          server.emit('close');
        });
        process.on('exit', exitListener);
      });
    });

    return server.openPromise;
  }

  /**
   * Stop a given {@linkcode server}.
   * @protected
   * @fires Postgres#closing
   * @argument {Postgres} server
   * @return {Promise}
   */
  static close(server) {
    if (server.isClosing) {
      return server.closePromise;
    }

    server.isClosing = true;
    server.isOpening = false;
    server.closePromise = server.promiseQueue.add(() => {
      if (server.isOpening || !server.isRunning) {
        server.isClosing = false;

        return Promise.resolve(null);
      }

      return new Promise((resolve) => {
        server.emit('closing');
        server.process.once('close', () => resolve(null));

        let signal = server.config.shutdown;

        switch (server.config.shutdown) {
          case 'smart':
            signal = 'SIGTERM';

            break;

          case 'fast':
            signal = 'SIGINT';

            break;

          case 'immediate':
            signal = 'SIGQUIT';

            break;
        }

        server.process.kill(signal);
      });
    });

    return server.closePromise;
  }

  /**
   * Construct a new {@link Postgres}.
   * @argument {(Number|String|Postgres~Config)} [configOrDataDir]
   * A number or string that is a port or an object for configuration.
   */
  constructor(configOrDataDir) {
    super();

    /**
     * Configuration options.
     * @protected
     * @type {Postgres~Config}
     */
    this.config = Postgres.parseConfig(configOrDataDir, {
      bin: 'postgres',
      conf: null,
      port: 5432,
      datadir: null,
      shutdown: 'fast'
    });

    /**
     * The current process.
     * @protected
     * @type {ChildProcess}
     */
    this.process = null;

    /**
     * The last {@link Promise} returned by {@link Postgres#open}.
     * @protected
     * @type {Promise}
     */
    this.openPromise = Promise.resolve(null);

    /**
     * The last {@link Promise} returned by {@link Postgres#close}.
     * @protected
     * @type {Promise}
     */
    this.closePromise = Promise.resolve(null);

    /**
     * A serial queue of open and close promises.
     * @protected
     * @type {PromiseQueue}
     */
    this.promiseQueue = new PromiseQueue(1);

    /**
     * Determine if the instance is closing a PostgreSQL server; {@linkcode true}
     * while a process is being, or about to be, killed until the
     * contained PostgreSQL server either closes or errs.
     * @readonly
     * @type {Boolean}
     */
    this.isClosing = false;

    /**
     * Determine if the instance is starting a PostgreSQL server; {@linkcode true}
     * while a process is spawning, or about tobe spawned, until the
     * contained PostgreSQL server either starts or errs.
     * @readonly
     * @type {Boolean}
     */
    this.isRunning = false;

    /**
     * Determine if the instance is running a PostgreSQL server; {@linkcode true}
     * once a process has spawned and the contained PostgreSQL server is ready
     * to service requests.
     * @readonly
     * @type {Boolean}
     */
    this.isOpening = false;
  }

  /**
   * Open the server.
   * @argument {Postgres~callback} [callback]
   * @return {Promise}
   */
  open(callback) {
    const promise = Postgres.open(this);

    return typeof callback === 'function'
      ? promise
        .then((v) => callback(null, v))
        .catch((e) => callback(e, null))
      : promise;
  }

  /**
   * Close the server.
   * @argument {Postgres~callback} [callback]
   * @return {Promise}
   */
  close(callback) {
    const promise = Postgres.close(this);

    return typeof callback === 'function'
      ? promise
        .then((v) => callback(null, v))
        .catch((e) => callback(e, null))
      : promise;
  }
}

module.exports = exports = Postgres;
<commit_msg>Fix terminal message regexp<commit_after>'use strict';

/**
 * Configuration options for {@link Postgres}.
 * @typedef {Object} Postgres~Config
 * @property {String} [bin=postgres]
 * @property {String} [conf]
 * @property {(Number|String)} [port=5432]
 * @property {String} datadir
 * @property {String} shutdown
 */

/**
 * Invoked when an operation (i.e. {@link Postgres#open}) completes.
 * @callback Postgres~callback
 * @argument {Error} err
 */

/**
 * Emitted when a PostgreSQL server prints to stdout.
 * @event Postgres#stdout
 */

/**
 * Emitted when attempting to start a PostgreSQL server.
 * @event Postgres#opening
 */

/**
 * Emitted when a PostgreSQL server becomes ready to service requests.
 * @event Postgres#open
 */

/**
 * Emitted when attempting to stop a PostgreSQL server.
 * @event Postgres#closing
 */

/**
 * Emitted once a PostgreSQL server has stopped.
 * @event Postgres#close
 */

const childprocess = require('child_process');
const events = require('events');
const PromiseQueue = require('promise-queue');

/**
 * A collection of regualar expressions used by {@link Postgres.parseData} to
 * parse stdout and stderr messages.
 * @see Postgres.parseData
 * @readonly
 * @private
 * @type {Object.<String,RegExp>}
 */
const regExp = {
  terminalMessage: /ready\sto\saccept|already\sin\suse|denied|fatal|postgres(?::|\s)/i,
  errorMessage: /^(?:fatal|postgres):\s+(.*)/i,
  multipleWhiteSpace: /\s\s+/g,
  nonAlpha: /[^a-z]/ig,
  newline: /\r?\n/
};

/**
 * Start and stop a local PostgreSQL server like a boss.
 * @class
 */
class Postgres extends events.EventEmitter {

  /**
   * Get a function that takes chunks of stdin data, aggregates it, and passes
   * it in complete lines, one by one, to a given {@link Postgres~callback}.
   * @argument {Postgres~callback} callback
   * @return {Function}
   */
  static getTextLineAggregator(callback) {
    let buffer = '';

    return (data) => {
      const fragments = data.toString().split(regExp.newline);
      const lines = fragments.slice(0, fragments.length - 1);

      // If there was an unended line in the previous dump, complete it by
      // the first section.
      lines[0] = buffer + lines[0];

      // If there is an unended line in this dump, store it to be completed by
      // the next. This assumes there will be a terminating newline character
      // at some point. Generally, this is a safe assumption.
      buffer = fragments[fragments.length - 1];

      for (let line of lines) {
        callback(line);
      }
    };
  }

  /**
   * Populate a given {@link Postgres~Config} with values from a
   * given {@link Postgres~Config}.
   * @protected
   * @argument {Postgres~Config} source
   * @argument {Postgres~Config} target
   * @return {Postgres~Config}
   */
  static parseConfig(source, target) {
    if (target == null) {
      target = Object.create(null);
    }

    if (typeof source === 'string') {
      target.datadir = source;

      return target;
    }

    if (source == null || typeof source !== 'object') {
      return target;
    }

    if (source.bin != null) {
      target.bin = source.bin;
    }

    if (source.shutdown != null) {
      target.shutdown = source.shutdown;
    }

    if (source.conf != null) {
      target.conf = source.conf;

      return target;
    }

    if (source.datadir != null) {
      target.datadir = source.datadir;
    }

    if (source.port != null) {
      target.port = source.port;
    }

    return target;
  }

  /**
   * Parse process flags for PostgreSQL from a given {@link Postgres~Config}.
   * @protected
   * @argument {Postgres~Config} config
   * @return {Array.<String>}
   */
  static parseFlags(config) {
    if (config.conf != null) {
      return ['-c', `config_file=${config.conf}`];
    }

    const flags = [];

    if (config.datadir != null) {
      flags.push('-D', config.datadir);
    }

    if (config.port != null) {
      flags.push('-p', config.port);
    }

    return flags;
  }

  /**
   * Parse Redis server output for terminal messages.
   * @protected
   * @argument {String} string
   * @return {Object}
   */
  static parseData(string) {
    const matches = regExp.terminalMessage.exec(string);

    if (matches === null) {
      return null;
    }

    const result = {
      err: null,
      key: matches
        .pop()
        .replace(regExp.nonAlpha, '')
        .toLowerCase()
    };

    switch (result.key) {
      case 'readytoaccept':
        break;

      case 'alreadyinuse':
        result.err = new Error('Address already in use');
        result.err.code = -1;

        break;

      case 'denied':
        result.err = new Error('Permission denied');
        result.err.code = -2;

        break;

      case 'postgres':
      case 'fatal': {
        const matches = regExp.errorMessage.exec(string);

        result.err = new Error(
          matches === null ? string : matches.pop()
        );
        result.err.code = -3;

        break;
      }
    }

    return result;
  }

  /**
   * Start a given {@linkcode server}.
   * @protected
   * @fires Postgres#stdout
   * @fires Postgres#opening
   * @fires Postgres#open
   * @fires Postgres#closing
   * @fires Postgres#close
   * @argument {Postgres} server
   * @return {Promise}
   */
  static open(server) {
    if (server.isOpening) {
      return server.openPromise;
    }

    server.isOpening = true;
    server.isClosing = false;
    server.openPromise = server.promiseQueue.add(() => {
      if (server.isClosing || server.isRunning) {
        server.isOpening = false;

        return Promise.resolve(null);
      }

      return new Promise((resolve, reject) => {
        /**
         * A listener for the current server process' stdout that resolves or
         * rejects the current {@link Promise} when done.
         * @see Postgres.getTextLineAggregator
         * @see Postgres.parseData
         * @argument {Buffer} buffer
         * @return {undefined}
         */
        const dataListener = Postgres.getTextLineAggregator((string) => {
          const result = Postgres.parseData(string);

          if (result === null) {
            return;
          }

          server.process.stdout.removeListener('data', dataListener);
          server.process.stderr.removeListener('data', dataListener);

          server.isOpening = false;

          if (result.err === null) {
            server.isRunning = true;

            server.emit('open');
            resolve(null);
          }
          else {
            server.isClosing = true;

            server.emit('closing');
            server.process.once('close', () => reject(result.err));
          }
        });

        /**
         * A listener to close the server when the current process exits.
         * @return {undefined}
         */
        const exitListener = () => {
          // istanbul ignore next
          server.close();
        };

        /**
         * Get a text line aggregator that emits a given {@linkcode event}
         * for the current server.
         * @see Postgres.getTextLineAggregator
         * @argument {String} event
         * @return {Function}
         */
        const getDataPropagator = (event) =>
          Postgres.getTextLineAggregator((line) => server.emit(event, line));

        server.emit('opening');

        const flags = Postgres.parseFlags(server.config);

        flags.push('-c', `unix_socket_directories=${__dirname}`);

        server.process = childprocess.spawn(server.config.bin, flags);

        server.process.stderr.on('data', dataListener);
        server.process.stderr.on('data', getDataPropagator('stdout'));
        server.process.stdout.on('data', dataListener);
        server.process.stdout.on('data', getDataPropagator('stdout'));
        server.process.on('close', () => {
          server.process = null;
          server.isRunning = false;
          server.isClosing = false;

          process.removeListener('exit', exitListener);
          server.emit('close');
        });
        process.on('exit', exitListener);
      });
    });

    return server.openPromise;
  }

  /**
   * Stop a given {@linkcode server}.
   * @protected
   * @fires Postgres#closing
   * @argument {Postgres} server
   * @return {Promise}
   */
  static close(server) {
    if (server.isClosing) {
      return server.closePromise;
    }

    server.isClosing = true;
    server.isOpening = false;
    server.closePromise = server.promiseQueue.add(() => {
      if (server.isOpening || !server.isRunning) {
        server.isClosing = false;

        return Promise.resolve(null);
      }

      return new Promise((resolve) => {
        server.emit('closing');
        server.process.once('close', () => resolve(null));

        let signal = server.config.shutdown;

        switch (server.config.shutdown) {
          case 'smart':
            signal = 'SIGTERM';

            break;

          case 'fast':
            signal = 'SIGINT';

            break;

          case 'immediate':
            signal = 'SIGQUIT';

            break;
        }

        server.process.kill(signal);
      });
    });

    return server.closePromise;
  }

  /**
   * Construct a new {@link Postgres}.
   * @argument {(Number|String|Postgres~Config)} [configOrDataDir]
   * A number or string that is a port or an object for configuration.
   */
  constructor(configOrDataDir) {
    super();

    /**
     * Configuration options.
     * @protected
     * @type {Postgres~Config}
     */
    this.config = Postgres.parseConfig(configOrDataDir, {
      bin: 'postgres',
      conf: null,
      port: 5432,
      datadir: null,
      shutdown: 'fast'
    });

    /**
     * The current process.
     * @protected
     * @type {ChildProcess}
     */
    this.process = null;

    /**
     * The last {@link Promise} returned by {@link Postgres#open}.
     * @protected
     * @type {Promise}
     */
    this.openPromise = Promise.resolve(null);

    /**
     * The last {@link Promise} returned by {@link Postgres#close}.
     * @protected
     * @type {Promise}
     */
    this.closePromise = Promise.resolve(null);

    /**
     * A serial queue of open and close promises.
     * @protected
     * @type {PromiseQueue}
     */
    this.promiseQueue = new PromiseQueue(1);

    /**
     * Determine if the instance is closing a PostgreSQL server; {@linkcode true}
     * while a process is being, or about to be, killed until the
     * contained PostgreSQL server either closes or errs.
     * @readonly
     * @type {Boolean}
     */
    this.isClosing = false;

    /**
     * Determine if the instance is starting a PostgreSQL server; {@linkcode true}
     * while a process is spawning, or about tobe spawned, until the
     * contained PostgreSQL server either starts or errs.
     * @readonly
     * @type {Boolean}
     */
    this.isRunning = false;

    /**
     * Determine if the instance is running a PostgreSQL server; {@linkcode true}
     * once a process has spawned and the contained PostgreSQL server is ready
     * to service requests.
     * @readonly
     * @type {Boolean}
     */
    this.isOpening = false;
  }

  /**
   * Open the server.
   * @argument {Postgres~callback} [callback]
   * @return {Promise}
   */
  open(callback) {
    const promise = Postgres.open(this);

    return typeof callback === 'function'
      ? promise
        .then((v) => callback(null, v))
        .catch((e) => callback(e, null))
      : promise;
  }

  /**
   * Close the server.
   * @argument {Postgres~callback} [callback]
   * @return {Promise}
   */
  close(callback) {
    const promise = Postgres.close(this);

    return typeof callback === 'function'
      ? promise
        .then((v) => callback(null, v))
        .catch((e) => callback(e, null))
      : promise;
  }
}

module.exports = exports = Postgres;
<|endoftext|>


<commit_before>'use strict';

var vm = require('vm');
var formidable = require('formidable');

module.exports = {
    post: function (req, res) {

        var sandbox = {
            result: '',
            code  : 'return "";',
            errors: []
        };

        if (req.query.json) {
            try {
                sandbox.json = JSON.parse(req.query.json);
            } catch (e) {
                res.status(400);
                sandbox.errors.push(e.toString());
            }
        }

        sandbox.code = req.query.code;

        console.log(sandbox);

        var code = 'result = (function () { ' + sandbox.code + ' }());';

        try {
            vm.runInNewContext(code, sandbox);
        } catch (e) {
            res.status(400);
            sandbox.errors.push(e.toString());
        }

        res.json(sandbox);
    }
};<commit_msg>remove debug code<commit_after>'use strict';

var vm = require('vm');
var formidable = require('formidable');

module.exports = {
    post: function (req, res) {

        var sandbox = {
            result: '',
            code  : 'return "";',
            errors: []
        };

        if (req.query.json) {
            try {
                sandbox.json = JSON.parse(req.query.json);
            } catch (e) {
                res.status(400);
                sandbox.errors.push(e.toString());
            }
        }

        sandbox.code = req.query.code;

        var code = 'result = (function () { ' + sandbox.code + ' }());';

        try {
            vm.runInNewContext(code, sandbox);
        } catch (e) {
            res.status(400);
            sandbox.errors.push(e.toString());
        }

        res.json(sandbox);
    }
};<|endoftext|>