<commit_before>module.exports = function(app) {

	app.models.complexStat.find(function(error, instances){
		var n=instances.length;
		if(n>0){
			var n=instances.length;
			for(var i=0; i<n; ++i){
				var instance=instances[i];

				var fId=setInterval(function(){

					// set proper date
					var now = new Date();
					var millis=now.getTime();
					millis-=instance.period;
					var gtDate=new Date(millis);

					// get data with proper date
					app.models.Data.find({"where":{"and":[{"sensorId":instance.sensorId},{"date":{"gt":gtDate}}]}},function(err, dataInstances){
						if(dataInstances.length<1){
							console.log("no data found");
							return;
						}

						// compute data average
						var sum=0;
						for(var i=0; i<dataInstances.length; ++i){
							sum+=dataInstances[i][instance.itemType];
						}

						// update array of complexStat instance
						if(!instance.data){
							instance.data=[];
						}
						instance.data.push({"avg":sum/dataInstances.length,"date":now});
						console.log("Average: "+" "+instance.itemType+": "+(sum/dataInstances.length)+", for stat: "+instance.id);
						instance.updateAttribute("data",instance.data,function(err, newInst){if(err){console.log(err)}})
					})
				}, instance.repeat);

				// save interval object to array
				app.models.complexStat.intervObjs[instance.id]=fId;
			}
		}
	});

};<commit_msg>complexStat generation process is restarted after server restart<commit_after>module.exports = function(app) {

	app.models.complexStat.find(function(error, instances){
		var n=instances.length;
		if(n>0){
			for(var i=0; i<n; ++i){
				var instance=instances[i];

				var fId=setInterval(function(){

					// set proper date
					var now = new Date();
					var millis=now.getTime();
					millis-=instance.period;
					var gtDate=new Date(millis);

					// get data with proper date
					app.models.Data.find({"where":{"and":[{"sensorId":instance.sensorId},{"date":{"gt":gtDate}}]}},function(err, dataInstances){
						if(dataInstances.length<1){
							console.log("no data found");
							return;
						}

						// compute data average
						var sum=0;
						for(var i=0; i<dataInstances.length; ++i){
							sum+=dataInstances[i][instance.itemType];
						}

						// update array of complexStat instance
						if(!instance.data){
							instance.data=[];
						}
						instance.data.push({"avg":sum/dataInstances.length,"date":now});
						console.log("Average: "+" "+instance.itemType+": "+(sum/dataInstances.length)+", for stat: "+instance.id);
						instance.updateAttribute("data",instance.data,function(err, newInst){if(err){console.log(err)}})
					})
				}, instance.repeat);

				// save interval object to array
				app.models.complexStat.intervObjs[instance.id]=fId;
			}
		}
	});

};<|endoftext|>


<commit_before>;(function(factory) {
    if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
        factory(require("knockout"));
    } else if (typeof define === "function" && define.amd) {
        define(["knockout"], factory);
    } else {
        factory(ko);
    }
}(function(ko) {
    var defaultProvider = new ko.bindingProvider(); // default provider will have parseBindingsString
    var existingProvider = ko.bindingProvider.instance;

    var pattern = /\{\{.*?}}/g;

    // simple fast match
    function hasTextToInterpolate(node) {
        return node.nodeType === 3 && node.nodeValue.indexOf("{{") > -1;
    }

    function hasInterpolationAttribute(node) {
        return node.attributes && node.attributes["data-koset"];
    }

    function getValueOfExpression(rawExpression, bindingContext, node) {
        var expression = rawExpression.replace("{{", "").replace("}}", "");
        // take advantage of existing KO functionality to parse/evaluate binding expression
        return ko.unwrap(defaultProvider.parseBindingsString("x:" + expression, bindingContext, node).x);
    }

    function processInterpolationAttribute(node, bindingContext) {
        var bindingValues = defaultProvider.parseBindingsString(node.attributes["data-koset"].value, bindingContext, node);
        if (bindingValues.hasOwnProperty("visible") && !ko.unwrap(bindingValues.visible)){
            node.style.display = "none";
        }
        if (bindingValues.hasOwnProperty("if") && !ko.unwrap(bindingValues["if"])){
            node.innerHTML = "";
        }
        if (bindingValues.hasOwnProperty("value")){
            node.value = ko.unwrap(bindingValues.value);
        }
        if (bindingValues.hasOwnProperty("attr")){
            Object.keys(bindingValues.attr).forEach(function(attrName){
                node.setAttribute(attrName, bindingValues.attr[attrName]);
            });
        }
    }

    ko.bindingProvider.interpolate = {
        nodeHasBindings: function(node) {
            return hasTextToInterpolate(node) || hasInterpolationAttribute(node) || existingProvider.nodeHasBindings(node);
        },
        getBindingAccessors: function(node, bindingContext) {
            if (hasTextToInterpolate(node)) {
                node.nodeValue = node.nodeValue.replace(pattern, function(match) {
                    return getValueOfExpression(match, bindingContext, node);
                });

                return;
            } else if (hasInterpolationAttribute(node)) {
                processInterpolationAttribute(node, bindingContext);
            }

            return existingProvider.getBindingAccessors(node, bindingContext);
        }
    };
}));
<commit_msg>Support older browsers that don't have Object.keys<commit_after>;(function(factory) {
    if (typeof require === "function" && typeof exports === "object" && typeof module === "object") {
        factory(require("knockout"));
    } else if (typeof define === "function" && define.amd) {
        define(["knockout"], factory);
    } else {
        factory(ko);
    }
}(function(ko) {
    var defaultProvider = new ko.bindingProvider(); // default provider will have parseBindingsString
    var existingProvider = ko.bindingProvider.instance;

    var pattern = /\{\{.*?}}/g;

    // simple fast match
    function hasTextToInterpolate(node) {
        return node.nodeType === 3 && node.nodeValue.indexOf("{{") > -1;
    }

    function hasInterpolationAttribute(node) {
        return node.attributes && node.attributes["data-koset"];
    }

    function getValueOfExpression(rawExpression, bindingContext, node) {
        var expression = rawExpression.replace("{{", "").replace("}}", "");
        // take advantage of existing KO functionality to parse/evaluate binding expression
        return ko.unwrap(defaultProvider.parseBindingsString("x:" + expression, bindingContext, node).x);
    }

    function processInterpolationAttribute(node, bindingContext) {
        var bindingValues = defaultProvider.parseBindingsString(node.attributes["data-koset"].value, bindingContext, node);
        if (bindingValues.hasOwnProperty("visible") && !ko.unwrap(bindingValues.visible)) {
            node.style.display = "none";
        }
        if (bindingValues.hasOwnProperty("if") && !ko.unwrap(bindingValues["if"])) {
            node.innerHTML = "";
        }
        if (bindingValues.hasOwnProperty("value")) {
            node.value = ko.unwrap(bindingValues.value);
        }
        if (bindingValues.hasOwnProperty("attr")) {
            ko.utils.objectForEach(bindingValues.attr, function(name, value) {
                node.setAttribute(name, value);
            });
        }
    }

    ko.bindingProvider.interpolate = {
        nodeHasBindings: function(node) {
            return hasTextToInterpolate(node) || hasInterpolationAttribute(node) || existingProvider.nodeHasBindings(node);
        },
        getBindingAccessors: function(node, bindingContext) {
            if (hasTextToInterpolate(node)) {
                node.nodeValue = node.nodeValue.replace(pattern, function(match) {
                    return getValueOfExpression(match, bindingContext, node);
                });

                return;
            } else if (hasInterpolationAttribute(node)) {
                processInterpolationAttribute(node, bindingContext);
            }

            return existingProvider.getBindingAccessors(node, bindingContext);
        }
    };
}));
<|endoftext|>


<commit_before>// Primary Node.js server file

/**
 * Initializes the web server and starts it listening on the given port
 */
var run = function(port) {
	/*
	 * Load all dependencies
	 */
	var express = require('express');
	var app = express();

	/**
	 * Enables static serving of .css and .js files from the server/view folder. Static
	 * files are set to remain cached by the client for one full day.
	 */
	var loadStaticServing = function(app) {
		var oneDay = 86400*1000;

		// Makes sure content will be compressed when sent
		app.use(express.compress());

		// Uncomment to use cached version (eventually)
		// app.use(express.static(process.cwd() + "/view", {maxAge: oneDay}));

		// Uncached version
		app.use(express.static(process.cwd() + "/view"));
	};

	/**
	 * Initializes the functions to handle certain specific requests. Used for serving up
	 * dynamic content.
	 */
	var loadRoutes = function(app) {
		app.get('/', homepage);

		app.post('/github/pull', updateRepository);
	};

	/**
	 * Dynamically populates the contents of the homepage. Used in place of an index.html
	 * file.
	 */
	var homepage = function(req, res) {
		res.send('BYU Class wiki, served direct to you from Node.js! Testing webHook and endpoint. test_one');
	};

	/**
	 * Runs a bash script that pulls from the github repository and reloads the server
	 */
	var updateRepository = function(req, res) {
		var spawnOne = require('child_process').spawn;
		var spawnTwo = require('child_process').spawn;

		console.log('Pulling the latest code from github');
		res.send('Please verify server has run update.sh');
		spawnOne('sudo ./update.sh');
		spawnTwo('sudo ./restart.sh');

	};

	loadStaticServing(app);
	loadRoutes(app);

	app.listen(port);

	console.log('Server listening on port ' + port);
};

exports.run = run;
<commit_msg>Update server.js<commit_after>// Primary Node.js server file

/**
 * Initializes the web server and starts it listening on the given port
 */
var run = function(port) {
	/*
	 * Load all dependencies
	 */
	var express = require('express');
	var app = express();

	/**
	 * Enables static serving of .css and .js files from the server/view folder. Static
	 * files are set to remain cached by the client for one full day.
	 */
	var loadStaticServing = function(app) {
		var oneDay = 86400*1000;

		// Makes sure content will be compressed when sent
		app.use(express.compress());

		// Uncomment to use cached version (eventually)
		// app.use(express.static(process.cwd() + "/view", {maxAge: oneDay}));

		// Uncached version
		app.use(express.static(process.cwd() + "/view"));
	};

	/**
	 * Initializes the functions to handle certain specific requests. Used for serving up
	 * dynamic content.
	 */
	var loadRoutes = function(app) {
		app.get('/', homepage);

		app.post('/github/pull', updateRepository);
	};

	/**
	 * Dynamically populates the contents of the homepage. Used in place of an index.html
	 * file.
	 */
	var homepage = function(req, res) {
		res.send('BYU Class wiki, served direct to you from Node.js! Testing webHook and endpoint. test_two');
	};

	/**
	 * Runs a bash script that pulls from the github repository and reloads the server
	 */
	var updateRepository = function(req, res) {
		var spawnOne = require('child_process').spawn;
		var spawnTwo = require('child_process').spawn;

		console.log('Pulling the latest code from github');
		res.send('Please verify server has run update.sh');
		spawnOne('sudo ./update.sh');
		spawnTwo('sudo ./restart.sh');

	};

	loadStaticServing(app);
	loadRoutes(app);

	app.listen(port);

	console.log('Server listening on port ' + port);
};

exports.run = run;
<|endoftext|>


<commit_before>/**
 * Comments controller
 */
var mongoose = require('mongoose');
var Question = mongoose.model('Question');

/**
 * Add a comment to a question
 * @param  {[type]} req Request
 * @param  {[type]} res Response
 * @return {[type]}
 */
exports.commentQuestion = function (req, res) {
	var questionId = req.params.id;
	var user = req.user;
	var comment = req.body
	Question.findOne({_id: questionId}).exec(function (err, question) {
		if (!question) {
			res.status(400);
			return res.send({
				reason: err.toString()
			});
		}
		if (!question.comments) {
			question.comments = [];
		}
		comment.author = req.user._id;
		question.comments.push(comment);
		question.save(function (err) {
			if (err) {
				res.status(400);
				return res.send({
					reason: err.toString()
				});
			}
			question.populateQuestion().then(function () {
				return res.send(question);
			});
		});
	});
};

/**
 * Delete a comment
 * @param  {[type]} req Request
 * @param  {[type]} res Response
 * @return {[type]}
 */
exports.deleteComment = function (req, res) {
	var questionId = req.params.id;
	var commentId = req.params.commentId;
	Question.findOne({_id: questionId}).exec(function (err, question) {
		if (!question) {
			res.status(400);
			return res.send({
				reason: 'This question does not exist'
			});
		}
		var comment = question.comments.id(commentId);
		if (!comment) {
			res.status(400);
			return res.send({
				reason: 'This comment does not exist'
			});
		}
		comment.remove();
		question.save(function (err) {
			if (err) {
				res.status(400);
				return res.send({
					reason: err.toString()
				});
			}
			question.populateQuestion().then(function () {
				return res.send(question);
			});
		});
	});
};

/**
 * Upvote a comment
 * @param  {[type]} req Request
 * @param  {[type]} res Response
 * @return {[type]}
 */
exports.upvoteComment = function (req, res) {
	var questionId = req.params.id;
	var commentId = req.params.commentId;
	Question.findOne({_id: questionId}).exec(function (err, question) {
		if (!question) {
			res.status(400);
			return res.send({
				reason: 'This question does not exist'
			});
		}
		var comment = question.comments.id(commentId);
		if (!comment) {
			res.status(400);
			return res.send({
				reason: 'This comment does not exist'
			});
		}
		for (var i = 0; i < req.user.commentUpvotes.length; i++) {
			if (req.user.commentUpvotes[i].equals(commentId)) {
				res.status(400);
				return res.send({
					reason: 'You already voted for this comment'
				});
			}
		}
		req.user.commentUpvotes.push(commentId);
		req.user.save(function (err) {
			if (err) {
				res.status(400);
				return res.send({
					reason: err.toString()
				});
			}
			comment.upvotes = comment.upvotes + 1;
			question.save(function (err) {
				if (err) {
					res.status(400);
					return res.send({
						reason: err.toString()
					});
				}
				question.populateQuestion().then(function () {
					return res.send(question);
				});
			});
		});
	});
};<commit_msg>Comment length server-side validation<commit_after>/**
 * Comments controller
 */
var mongoose = require('mongoose');
var Question = mongoose.model('Question');

/**
 * Add a comment to a question
 * @param  {[type]} req Request
 * @param  {[type]} res Response
 * @return {[type]}
 */
exports.commentQuestion = function (req, res) {
	var questionId = req.params.id;
	var user = req.user;
	var comment = req.body
	if (comment.text && comment.text.length > 1000) {
		res.status(400);
		return res.send({
			reason: 'Your comment is too long (1000 characters maximum)'
		});
	}
	Question.findOne({_id: questionId}).exec(function (err, question) {
		if (!question) {
			res.status(400);
			return res.send({
				reason: err.toString()
			});
		}
		if (!question.comments) {
			question.comments = [];
		}
		comment.author = req.user._id;
		question.comments.push(comment);
		question.save(function (err) {
			if (err) {
				res.status(400);
				return res.send({
					reason: err.toString()
				});
			}
			question.populateQuestion().then(function () {
				return res.send(question);
			});
		});
	});
};

/**
 * Delete a comment
 * @param  {[type]} req Request
 * @param  {[type]} res Response
 * @return {[type]}
 */
exports.deleteComment = function (req, res) {
	var questionId = req.params.id;
	var commentId = req.params.commentId;
	Question.findOne({_id: questionId}).exec(function (err, question) {
		if (!question) {
			res.status(400);
			return res.send({
				reason: 'This question does not exist'
			});
		}
		var comment = question.comments.id(commentId);
		if (!comment) {
			res.status(400);
			return res.send({
				reason: 'This comment does not exist'
			});
		}
		comment.remove();
		question.save(function (err) {
			if (err) {
				res.status(400);
				return res.send({
					reason: err.toString()
				});
			}
			question.populateQuestion().then(function () {
				return res.send(question);
			});
		});
	});
};

/**
 * Upvote a comment
 * @param  {[type]} req Request
 * @param  {[type]} res Response
 * @return {[type]}
 */
exports.upvoteComment = function (req, res) {
	var questionId = req.params.id;
	var commentId = req.params.commentId;
	Question.findOne({_id: questionId}).exec(function (err, question) {
		if (!question) {
			res.status(400);
			return res.send({
				reason: 'This question does not exist'
			});
		}
		var comment = question.comments.id(commentId);
		if (!comment) {
			res.status(400);
			return res.send({
				reason: 'This comment does not exist'
			});
		}
		for (var i = 0; i < req.user.commentUpvotes.length; i++) {
			if (req.user.commentUpvotes[i].equals(commentId)) {
				res.status(400);
				return res.send({
					reason: 'You already voted for this comment'
				});
			}
		}
		req.user.commentUpvotes.push(commentId);
		req.user.save(function (err) {
			if (err) {
				res.status(400);
				return res.send({
					reason: err.toString()
				});
			}
			comment.upvotes = comment.upvotes + 1;
			question.save(function (err) {
				if (err) {
					res.status(400);
					return res.send({
						reason: err.toString()
					});
				}
				question.populateQuestion().then(function () {
					return res.send(question);
				});
			});
		});
	});
};<|endoftext|>


<commit_before>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2013, Olivier BIOT
 * http://www.melonjs.org
 *
 * Tile QT 0.7.x format
 * http://www.mapeditor.org/
 *
 */
(function (TMXConstants) {

    /**
     * TMX Object Group

     * contains the object group definition as defined in Tiled.

     * note : object group definition is translated into the virtual `me.game.world` using `me.Container`.
     * @see me.Container
     * @class
     * @extends Object
     * @memberOf me
     * @constructor
     */
    me.TMXObjectGroup = Object.extend({
        init : function (name, tmxObjGroup, tilesets, z) {
            /**
             * group name
             * @public
             * @type String
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.name = null;

            /**
             * group width
             * @public
             * @type Number
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.width = 0;

            /**
             * group height
             * @public
             * @type Number
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.height = 0;

            /**
             * group z order
             * @public
             * @type Number
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.z = 0;

            /**
             * group objects list definition
             * @see me.TMXObject
             * @public
             * @type Array
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.objects = [];
            var self = this;
            this.name    = name;
            this.width   = tmxObjGroup[TMXConstants.TMX_TAG_WIDTH];
            this.height  = tmxObjGroup[TMXConstants.TMX_TAG_HEIGHT];
            this.z       = z;
            this.objects = [];

            var visible = typeof(tmxObjGroup[TMXConstants.TMX_TAG_VISIBLE]) !== "undefined" ? tmxObjGroup[TMXConstants.TMX_TAG_VISIBLE] : true;

            this.opacity = (visible === true) ? (+tmxObjGroup[TMXConstants.TMX_TAG_OPACITY] || 1.0).clamp(0.0, 1.0) : 0;

            // check if we have any user-defined properties
            me.TMXUtils.applyTMXProperties(this, tmxObjGroup);

            // parse all objects
            // (under `objects` for XML converted map, under `object` for native json map)
            var _objects = tmxObjGroup.objects || tmxObjGroup.object;
            if (Array.isArray(_objects) === true) {
                // JSON native format
                _objects.forEach(function (tmxObj) {
                    self.objects.push(new me.TMXObject(tmxObj, tilesets, z));
                });
            } else {
                self.objects.push(new me.TMXObject(_objects, tilesets, z));
            }
        },

        /**
         * reset function
         * @ignore
         * @function
         */

        destroy : function () {
            // clear all allocated objects
            this.objects = null;
        },

        /**
         * return the object count
         * @ignore
         * @function
         */
        getObjectCount : function () {
            return this.objects.length;
        },

        /**
         * returns the object at the specified index
         * @ignore
         * @function
         */
        getObjectByIndex : function (idx) {
            return this.objects[idx];
        }
    });

    /**
     * a TMX Object defintion, as defined in Tiled.

     * note : object definition are translated into the virtual `me.game.world` using `me.Entity`.
     * @see me.Entity
     * @class
     * @extends Object
     * @memberOf me
     * @constructor
     */
    me.TMXObject = Object.extend({
        init :  function (tmxObj, tilesets, z) {

            /**
             * object point list (for Polygon and PolyLine)
             * @public
             * @type Vector2d[]
             * @name points
             * @memberOf me.TMXObject
             */
            this.points = undefined;
            /**
             * object name
             * @public
             * @type String
             * @name name
             * @memberOf me.TMXObject
             */
            this.name = tmxObj[TMXConstants.TMX_TAG_NAME];
            /**
             * object x position
             * @public
             * @type Number
             * @name x
             * @memberOf me.TMXObject
             */
            this.x = +tmxObj[TMXConstants.TMX_TAG_X];
            /**
             * object y position
             * @public
             * @type Number
             * @name y
             * @memberOf me.TMXObject
             */
            this.y = +tmxObj[TMXConstants.TMX_TAG_Y];
            /**
             * object z order
             * @public
             * @type Number
             * @name z
             * @memberOf me.TMXObject
             */
            this.z = +z;

            /**
             * object width
             * @public
             * @type Number
             * @name width
             * @memberOf me.TMXObject
             */
            this.width = +tmxObj[TMXConstants.TMX_TAG_WIDTH] || 0;

            /**
             * object height
             * @public
             * @type Number
             * @name height
             * @memberOf me.TMXObject
             */
            this.height = +tmxObj[TMXConstants.TMX_TAG_HEIGHT] || 0;

            /**
             * object gid value
             * when defined the object is a tiled object
             * @public
             * @type Number
             * @name gid
             * @memberOf me.TMXObject
             */
            this.gid = +tmxObj[TMXConstants.TMX_TAG_GID] || null;

            /**
             * object type
             * @public
             * @type String
             * @name type
             * @memberOf me.TMXObject
             */
            this.type = tmxObj[TMXConstants.TMX_TAG_TYPE];

            /**
             * The rotation of the object in radians clockwise (defaults to 0)
             * @public
             * @type Number
             * @name rotation
             * @memberOf me.TMXObject
             */
            this.rotation = Number.prototype.degToRad(+(tmxObj[TMXConstants.TMX_ROTATION] || 0));

            /*
             * if true, the object is an Ellipse
             * @public
             * @type Boolean
             * @name isEllipse
             * @memberOf me.TMXObject
             */
            this.isEllipse = false;

            /**
             * if true, the object is a Polygon
             * @public
             * @type Boolean
             * @name isPolygon
             * @memberOf me.TMXObject
             */
            this.isPolygon = false;
            /**
             * if true, the object is a PolyLine
             * @public
             * @type Boolean
             * @name isPolyLine
             * @memberOf me.TMXObject
             */
            this.isPolyLine = false;

            // check if the object has an associated gid
            if (typeof this.gid === "number") {
                this.setImage(this.gid, tilesets);
            }
            else {
                if (typeof(tmxObj[TMXConstants.TMX_TAG_ELLIPSE]) !== "undefined") {
                    this.isEllipse = true;
                }
                else {
                    var points = tmxObj[TMXConstants.TMX_TAG_POLYGON];
                    if (typeof(points) !== "undefined") {
                        this.isPolygon = true;
                    }
                    else {
                        points = tmxObj[TMXConstants.TMX_TAG_POLYLINE];
                        if (typeof(points) !== "undefined") {
                            this.isPolyLine = true;
                        }
                    }
                    if (typeof(points) !== "undefined") {
                        this.points = [];
                        if (typeof(points.points) !== "undefined") {
                            // get a point array
                            points = points.points.split(" ");
                            // and normalize them into an array of vectors
                            for (var i = 0, v; i < points.length; i++) {
                                v = points[i].split(",");
                                this.points.push(new me.Vector2d(+v[0], +v[1]));
                            }
                        }
                        else {
                            // already an object (native json format)
                            var self = this;
                            points.forEach(function (point) {
                                self.points.push(new me.Vector2d(+point.x, +point.y));
                            });
                        }
                    }
                }
            }

            // Adjust the Position to match Tiled
            me.game.tmxRenderer.adjustPosition(this);

            // set the object properties
            me.TMXUtils.applyTMXProperties(this, tmxObj);
        },

        /**
         * set the object image (for Tiled Object)
         * @ignore
         * @function
         */
        setImage : function (gid, tilesets) {
            // get the corresponding tileset
            var tileset = tilesets.getTilesetByGid(this.gid);

            // set width and height equal to tile size
            this.width = tileset.tilewidth;
            this.height = tileset.tileheight;

            // force spritewidth size
            this.spritewidth = this.width;

            // the object corresponding tile

            var tmxTile = new me.Tile(this.x, this.y, tileset.tilewidth, tileset.tileheight, this.gid);

            // get the corresponding tile into our object
            this.image = tileset.getTileImage(tmxTile);

            // set a generic name if not defined
            if (typeof (this.name) === "undefined") {
                this.name = "TileObject";
            }
        },

        /**
         * return a list of shapes for a TMX object
         * @name getTMXShapes
         * @memberOf me.TMXObject
         * @private
         * @function
         * @return {me.Polygon[]|me.Line[]|me.Ellipse[]} a list of shape objects
         */
        getTMXShapes : function () {

            // add an ellipse shape
            if (this.isEllipse === true) {
                // ellipse coordinates are the center position, so set default to the corresonding radius
                return [ new me.Ellipse(this.width / 2, this.height / 2, this.width, this.height) ];
            }

            // add a polygon
            if (this.isPolygon === true) {
                return [ (new me.Polygon(0, 0, this.points)).rotate(this.rotation) ];
            }

            // add a polyline
            if (this.isPolyLine === true) {
                var p = this.points;
                var segments = p.length - 1;
                var lines = [];
                for (var i = 0; i < segments; i++) {
                    lines.push((new me.Line(0, 0, [ p[i], p[i + 1] ])).rotate(this.rotation));
                }
                return lines;
            }

            // it's a rectangle, returns a polygon object anyway
            return [ (new me.Polygon(
                0, 0, [
                    new me.Vector2d(), new me.Vector2d(this.width, 0),
                    new me.Vector2d(this.width, this.height), new me.Vector2d(0, this.height)
                ]
            )).rotate(this.rotation) ];
        },
        /**
         * getObjectPropertyByName
         * @ignore
         * @function
         */
        getObjectPropertyByName : function (name) {
            return this[name];
        }
    });
})(me.TMXConstants);
<commit_msg>[#542] attempt at fixing polyline/line rotation support<commit_after>/*
 * MelonJS Game Engine
 * Copyright (C) 2011 - 2013, Olivier BIOT
 * http://www.melonjs.org
 *
 * Tile QT 0.7.x format
 * http://www.mapeditor.org/
 *
 */
(function (TMXConstants) {

    /**
     * TMX Object Group

     * contains the object group definition as defined in Tiled.

     * note : object group definition is translated into the virtual `me.game.world` using `me.Container`.
     * @see me.Container
     * @class
     * @extends Object
     * @memberOf me
     * @constructor
     */
    me.TMXObjectGroup = Object.extend({
        init : function (name, tmxObjGroup, tilesets, z) {
            /**
             * group name
             * @public
             * @type String
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.name = null;

            /**
             * group width
             * @public
             * @type Number
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.width = 0;

            /**
             * group height
             * @public
             * @type Number
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.height = 0;

            /**
             * group z order
             * @public
             * @type Number
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.z = 0;

            /**
             * group objects list definition
             * @see me.TMXObject
             * @public
             * @type Array
             * @name name
             * @memberOf me.TMXObjectGroup
             */
            this.objects = [];
            var self = this;
            this.name    = name;
            this.width   = tmxObjGroup[TMXConstants.TMX_TAG_WIDTH];
            this.height  = tmxObjGroup[TMXConstants.TMX_TAG_HEIGHT];
            this.z       = z;
            this.objects = [];

            var visible = typeof(tmxObjGroup[TMXConstants.TMX_TAG_VISIBLE]) !== "undefined" ? tmxObjGroup[TMXConstants.TMX_TAG_VISIBLE] : true;

            this.opacity = (visible === true) ? (+tmxObjGroup[TMXConstants.TMX_TAG_OPACITY] || 1.0).clamp(0.0, 1.0) : 0;

            // check if we have any user-defined properties
            me.TMXUtils.applyTMXProperties(this, tmxObjGroup);

            // parse all objects
            // (under `objects` for XML converted map, under `object` for native json map)
            var _objects = tmxObjGroup.objects || tmxObjGroup.object;
            if (Array.isArray(_objects) === true) {
                // JSON native format
                _objects.forEach(function (tmxObj) {
                    self.objects.push(new me.TMXObject(tmxObj, tilesets, z));
                });
            } else {
                self.objects.push(new me.TMXObject(_objects, tilesets, z));
            }
        },

        /**
         * reset function
         * @ignore
         * @function
         */

        destroy : function () {
            // clear all allocated objects
            this.objects = null;
        },

        /**
         * return the object count
         * @ignore
         * @function
         */
        getObjectCount : function () {
            return this.objects.length;
        },

        /**
         * returns the object at the specified index
         * @ignore
         * @function
         */
        getObjectByIndex : function (idx) {
            return this.objects[idx];
        }
    });

    /**
     * a TMX Object defintion, as defined in Tiled.

     * note : object definition are translated into the virtual `me.game.world` using `me.Entity`.
     * @see me.Entity
     * @class
     * @extends Object
     * @memberOf me
     * @constructor
     */
    me.TMXObject = Object.extend({
        init :  function (tmxObj, tilesets, z) {

            /**
             * object point list (for Polygon and PolyLine)
             * @public
             * @type Vector2d[]
             * @name points
             * @memberOf me.TMXObject
             */
            this.points = undefined;
            /**
             * object name
             * @public
             * @type String
             * @name name
             * @memberOf me.TMXObject
             */
            this.name = tmxObj[TMXConstants.TMX_TAG_NAME];
            /**
             * object x position
             * @public
             * @type Number
             * @name x
             * @memberOf me.TMXObject
             */
            this.x = +tmxObj[TMXConstants.TMX_TAG_X];
            /**
             * object y position
             * @public
             * @type Number
             * @name y
             * @memberOf me.TMXObject
             */
            this.y = +tmxObj[TMXConstants.TMX_TAG_Y];
            /**
             * object z order
             * @public
             * @type Number
             * @name z
             * @memberOf me.TMXObject
             */
            this.z = +z;

            /**
             * object width
             * @public
             * @type Number
             * @name width
             * @memberOf me.TMXObject
             */
            this.width = +tmxObj[TMXConstants.TMX_TAG_WIDTH] || 0;

            /**
             * object height
             * @public
             * @type Number
             * @name height
             * @memberOf me.TMXObject
             */
            this.height = +tmxObj[TMXConstants.TMX_TAG_HEIGHT] || 0;

            /**
             * object gid value
             * when defined the object is a tiled object
             * @public
             * @type Number
             * @name gid
             * @memberOf me.TMXObject
             */
            this.gid = +tmxObj[TMXConstants.TMX_TAG_GID] || null;

            /**
             * object type
             * @public
             * @type String
             * @name type
             * @memberOf me.TMXObject
             */
            this.type = tmxObj[TMXConstants.TMX_TAG_TYPE];

            /**
             * The rotation of the object in radians clockwise (defaults to 0)
             * @public
             * @type Number
             * @name rotation
             * @memberOf me.TMXObject
             */
            this.rotation = Number.prototype.degToRad(+(tmxObj[TMXConstants.TMX_ROTATION] || 0));

            /*
             * if true, the object is an Ellipse
             * @public
             * @type Boolean
             * @name isEllipse
             * @memberOf me.TMXObject
             */
            this.isEllipse = false;

            /**
             * if true, the object is a Polygon
             * @public
             * @type Boolean
             * @name isPolygon
             * @memberOf me.TMXObject
             */
            this.isPolygon = false;
            /**
             * if true, the object is a PolyLine
             * @public
             * @type Boolean
             * @name isPolyLine
             * @memberOf me.TMXObject
             */
            this.isPolyLine = false;

            // check if the object has an associated gid
            if (typeof this.gid === "number") {
                this.setImage(this.gid, tilesets);
            }
            else {
                if (typeof(tmxObj[TMXConstants.TMX_TAG_ELLIPSE]) !== "undefined") {
                    this.isEllipse = true;
                }
                else {
                    var points = tmxObj[TMXConstants.TMX_TAG_POLYGON];
                    if (typeof(points) !== "undefined") {
                        this.isPolygon = true;
                    }
                    else {
                        points = tmxObj[TMXConstants.TMX_TAG_POLYLINE];
                        if (typeof(points) !== "undefined") {
                            this.isPolyLine = true;
                        }
                    }
                    if (typeof(points) !== "undefined") {
                        this.points = [];
                        if (typeof(points.points) !== "undefined") {
                            // get a point array
                            points = points.points.split(" ");
                            // and normalize them into an array of vectors
                            for (var i = 0, v; i < points.length; i++) {
                                v = points[i].split(",");
                                this.points.push(new me.Vector2d(+v[0], +v[1]));
                            }
                        }
                        else {
                            // already an object (native json format)
                            var self = this;
                            points.forEach(function (point) {
                                self.points.push(new me.Vector2d(+point.x, +point.y));
                            });
                        }
                    }
                }
            }

            // Adjust the Position to match Tiled
            me.game.tmxRenderer.adjustPosition(this);

            // set the object properties
            me.TMXUtils.applyTMXProperties(this, tmxObj);
        },

        /**
         * set the object image (for Tiled Object)
         * @ignore
         * @function
         */
        setImage : function (gid, tilesets) {
            // get the corresponding tileset
            var tileset = tilesets.getTilesetByGid(this.gid);

            // set width and height equal to tile size
            this.width = tileset.tilewidth;
            this.height = tileset.tileheight;

            // force spritewidth size
            this.spritewidth = this.width;

            // the object corresponding tile

            var tmxTile = new me.Tile(this.x, this.y, tileset.tilewidth, tileset.tileheight, this.gid);

            // get the corresponding tile into our object
            this.image = tileset.getTileImage(tmxTile);

            // set a generic name if not defined
            if (typeof (this.name) === "undefined") {
                this.name = "TileObject";
            }
        },

        /**
         * return a list of shapes for a TMX object
         * @name getTMXShapes
         * @memberOf me.TMXObject
         * @private
         * @function
         * @return {me.Polygon[]|me.Line[]|me.Ellipse[]} a list of shape objects
         */
        getTMXShapes : function () {

            // add an ellipse shape
            if (this.isEllipse === true) {
                // ellipse coordinates are the center position, so set default to the corresonding radius
                return [ new me.Ellipse(this.width / 2, this.height / 2, this.width, this.height) ];
            }

            // add a polygon
            if (this.isPolygon === true) {
                return [ (new me.Polygon(0, 0, this.points)).rotate(this.rotation) ];
            }

            // add a polyline
            if (this.isPolyLine === true) {
                var p = this.points;
                var segments = p.length - 1;
                var lines = [];
                for (var i = 0; i < segments; i++) {
                    if (this.rotation !== 0) {
                        p[i].rotate(this.rotation);
                    }
                    lines.push(new me.Line(0, 0, [ p[i], p[i + 1] ]));
                }
                if (this.rotation !== 0) {
                    //apply rotation to the last point
                    var last = lines.length - 1;
                    lines[last].points[1].rotate(this.rotation);
                    lines[last].recalc().updateBounds();
                }
                return lines;
            }

            // it's a rectangle, returns a polygon object anyway
            return [ (new me.Polygon(
                0, 0, [
                    new me.Vector2d(), new me.Vector2d(this.width, 0),
                    new me.Vector2d(this.width, this.height), new me.Vector2d(0, this.height)
                ]
            )).rotate(this.rotation) ];
        },
        /**
         * getObjectPropertyByName
         * @ignore
         * @function
         */
        getObjectPropertyByName : function (name) {
            return this[name];
        }
    });
})(me.TMXConstants);
<|endoftext|>


<commit_before>var moment = require('moment');

var refetch = function(server) {
    console.log('Started running...');

    // Find all flights between now and 24 hours from now, and update their expected time of arrival/departure
    server.plugins.models.user.find({
        // Only flights that haven't landed yet
        'flight.arrival.date': {
            $lt: moment().toDate()
        },
        // Only flights that leave after yesterday
        'flight.departure.date': {
            $gt: moment().subtract(10, 'days').toDate()
        }
    }, function(err, result) {
        if(err) {
            console.log("Error:");
            console.log(err);
            return;
        }

        console.log('Found ' + result.length + ' hits');

        for(var i = 0; i < result.length; i++) {
            // Dereference the i
            (function(i) {
                console.log(result[i]);

                var flightNumber = result[i].flight.number;
                var departureDate = result[i].flight.departure.date;

                server.plugins.flightinfo.get(flightNumber, departureDate, function(newInfo) {
                    var changed = false;

                    // More than a minute difference in departure
                    if (Math.abs(moment(result[i].flight.departure.date).diff(moment(newInfo.departureTime))) > 60*1000) {
                        // Update the model
                        result[i].flight.departure.date = newInfo.departureTime;
                        changed = true;
                    }

                    // More than a minute difference in arrival
                    if (Math.abs(moment(result[i].flight.arrival.date).diff(moment(newInfo.arrivalTime))) > 60*1000) {
                        // Update the model
                        result[i].flight.arrival.date = newInfo.arrivalTime;
                        changed = true;
                    }

                    // If you're gonna arrive within the next hour, we should notify Uber!
                    if(moment(result[i].flight.arrival.date).isBefore(moment().add(1, 'hours')) &&
                        moment(result[i].flight.arrival.date).isAfter(moment().add(30, 'minutes'))) {
                        var user = result[i];
                        var params = {
                                        start_latitude: user.flight.arrival.location.latitude,
                                        start_longitude: user.flight.arrival.location.longitude,
                                        end_latitude: user.flight.destinationAddress.latitude,
                                        end_longitude: user.flight.destinationAddress.longitude,
                                        access_token: user.access_token
                                      }
                        server.plugins.uber.request(params,function(err, response){

                        });
                    }

                    // If we updated the records, we should probably update the model
                    if(changed) {
                        result[i].save();
                    }
                });
            })(i);
        }
    });
};

// Run every 10 seconds
// Production would probably run once an hour ;-)
var interval = 10 * 1000;
var start = function(server) {
    setInterval(function() {
        refetch(server);
    }, interval);
};

module.exports = {
    start: start
};
<commit_msg>Uber order cab going to airport<commit_after>var moment = require('moment');

var refetch = function (server) {
    console.log('Started running...');

    // Find all flights between now and 24 hours from now, and update their expected time of arrival/departure
    server.plugins.models.user.find({
        // Only flights that haven't landed yet
        'flight.arrival.date': {
            $lt: moment().toDate()
        },
        // Only flights that leave after yesterday
        'flight.departure.date': {
            $gt: moment().subtract(10, 'days').toDate()
        }
    }, function (err, result) {
        if (err) {
            console.log("Error:");
            console.log(err);
            return;
        }

        console.log('Found ' + result.length + ' hits');

        for (var i = 0; i < result.length; i++) {
            // Dereference the i
            (function (i) {
                console.log(result[i]);

                var flightNumber = result[i].flight.number;
                var departureDate = result[i].flight.departure.date;

                server.plugins.flightinfo.get(flightNumber, departureDate, function (newInfo) {
                    var changed = false;

                    // More than a minute difference in departure
                    if (Math.abs(moment(result[i].flight.departure.date).diff(moment(newInfo.departureTime))) > 60 * 1000) {
                        // Update the model
                        result[i].flight.departure.date = newInfo.departureTime;
                        changed = true;
                    }

                    // More than a minute difference in arrival
                    if (Math.abs(moment(result[i].flight.arrival.date).diff(moment(newInfo.arrivalTime))) > 60 * 1000) {
                        // Update the model
                        result[i].flight.arrival.date = newInfo.arrivalTime;
                        changed = true;
                    }

                    // If you're gonna arrive within the next hour, we should notify Uber!
                    if (moment(result[i].flight.arrival.date).isBefore(moment().add(1, 'hours')) &&
                        moment(result[i].flight.arrival.date).isAfter(moment().add(30, 'minutes'))) {

                        var user = result[i];
                        var params = {
                            start_latitude: user.flight.arrival.location.latitude,
                            start_longitude: user.flight.arrival.location.longitude,
                            end_latitude: user.flight.destinationAddress.latitude,
                            end_longitude: user.flight.destinationAddress.longitude,
                            access_token: user.access_token
                        };
                        server.plugins.uber.request(params, function (err, response) {
                            if(err) {
                                console.log('Hickup talking to Uber (1)');
                                console.log(err);
                            }
                        });
                    }

                    if (moment(result[i].flight.departure.date).isBefore(moment().subtract(150, 'minutes')) &&
                        moment(result[i].flight.departure.date).isAfter(moment().subtract(180, 'minutes'))) {

                        var user = result[i];
                        var params = {
                            start_latitude: user.flight.originAddress.location.latitude,
                            start_longitude: user.flight.originAddress.location.longitude,
                            end_latitude: user.flight.departure.location.latitude,
                            end_longitude: user.flight.departure.location.longitude,
                            access_token: user.access_token
                        };
                        server.plugins.uber.request(params, function (err, response) {
                            if(err) {
                                console.log('Hickup talking to Uber (2)');
                                console.log(err);
                            }
                        });
                    }

                    // If we updated the records, we should probably update the model
                    if (changed) {
                        result[i].save();
                    }
                });
            })(i);
        }
    });
};

// Run every 10 seconds
// Production would probably run once an hour ;-)
var interval = 10 * 1000;
var start = function (server) {
    setInterval(function () {
        refetch(server);
    }, interval);
};

module.exports = {
    start: start
};
<|endoftext|>


<commit_before>import express from 'express';

import * as recipeController from '../../controllers/recipes';
import * as reviewController from '../../controllers/reviews';
import * as voteController from '../../controllers/votes';
import * as auth from '../../middleware/auth';

const user = express.Router();

user.use('*', auth.default);

user.post('/', recipeController.createRecipe);
user.get('/', recipeController.getAllRecipes);

user.put('/:recipeId', recipeController.modifyRecipe);
user.delete('/:recipeId', recipeController.deleteRecipe);

user.post('/:recipeId/reviews', reviewController.postReview);
user.get('/:recipeId/reviews', reviewController.getReviews);

user.post('/:recipeId/upvotes', voteController.upvoteRecipe);
user.post('/:recipeId/downvotes', voteController.downvoteRecipe);

export default user;
<commit_msg>Assign getUserUpvotes and getUserDownvotes routes<commit_after>import express from 'express';

import * as recipeController from '../../controllers/recipes';
import * as reviewController from '../../controllers/reviews';
import * as voteController from '../../controllers/votes';
import * as auth from '../../middleware/auth';

const user = express.Router();

user.use('*', auth.default);

user.post('/', recipeController.createRecipe);
user.get('/', recipeController.getAllRecipes);

user.put('/:recipeId', recipeController.modifyRecipe);
user.delete('/:recipeId', recipeController.deleteRecipe);

user.post('/:recipeId/reviews', reviewController.postReview);
user.get('/:recipeId/reviews', reviewController.getReviews);

user.post('/:recipeId/upvotes', voteController.upvoteRecipe);
user.post('/:recipeId/downvotes', voteController.downvoteRecipe);

user.get('/:recipeId/upvotes', voteController.getUserUpvotes);
user.get('/:recipeId/downvotes', voteController.getUserDownvotes);

export default user;
<|endoftext|>


<commit_before>/**
 * Rich Text Editor
 */
'use strict';

(function (document, CKEDITOR) {
    const cfg = {
        customConfig: '',
        disableNativeSpellChecker: true,
        extraAllowedContent: 'article section(*)',
        filebrowserBrowseUrl: '/file/browser',
        format_tags: 'p;h2;h3',
        height: '30rem',
        language: 'de',
        removeDialogTabs: 'link:advanced;link:target',
        stylesSet: false,
        toolbar: [
            {
                name: 'all',
                items: [
                    'Undo',
                    'Redo',
                    'Format',
                    'Bold',
                    'Italic',
                    'Underline',
                    'RemoveFormat',
                    'Link',
                    'Unlink',
                    'BulletedList',
                    'NumberedList',
                    'Blockquote',
                    'Detail',
                    'Media',
                    'Table',
                    'HorizontalRule',
                    'ShowBlocks'
                ]
            }
        ]
    };

    document.addEventListener('DOMContentLoaded', function () {
        Array.prototype.forEach.call(document.querySelectorAll('textarea[data-type=rte]'), function (item) {
            CKEDITOR.replace(item, cfg);
        });
    });
})(document, CKEDITOR);
<commit_msg>Remove underline<commit_after>/**
 * Rich Text Editor
 */
'use strict';

(function (document, CKEDITOR) {
    const cfg = {
        customConfig: '',
        disableNativeSpellChecker: true,
        extraAllowedContent: 'article section(*)',
        filebrowserBrowseUrl: '/file/browser',
        format_tags: 'p;h2;h3',
        height: '30rem',
        language: 'de',
        removeDialogTabs: 'link:advanced;link:target',
        stylesSet: false,
        toolbar: [
            {
                name: 'all',
                items: [
                    'Undo',
                    'Redo',
                    'Format',
                    'Bold',
                    'Italic',
                    'RemoveFormat',
                    'Link',
                    'Unlink',
                    'BulletedList',
                    'NumberedList',
                    'Blockquote',
                    'Detail',
                    'Media',
                    'Table',
                    'HorizontalRule',
                    'ShowBlocks'
                ]
            }
        ]
    };

    document.addEventListener('DOMContentLoaded', function () {
        Array.prototype.forEach.call(document.querySelectorAll('textarea[data-type=rte]'), function (item) {
            CKEDITOR.replace(item, cfg);
        });
    });
})(document, CKEDITOR);
<|endoftext|>


<commit_before>import { isFunction } from '~'
import SimpleMap from '~/simple-map'

const delegatedEvents = new SimpleMap()

const unbubbleEvents = {
  onmousemove: 1,
  ontouchmove: 1,
  onmouseleave: 1,
  onmouseenter: 1,
  onload: 1,
  onunload: 1,
  onscroll: 1,
  onfocus: 1,
  onblur: 1,
  onrowexit: 1,
  onbeforeunload: 1,
  onstop: 1,
  ondragdrop: 1,
  ondragenter: 1,
  ondragexit: 1,
  ondraggesture: 1,
  ondragover: 1,
  oncontextmenu: 1,
  onerror: 1,
  onabort: 1,
  oncanplay: 1,
  oncanplaythrough: 1,
  ondurationchange: 1,
  onemptied: 1,
  onended: 1,
  onloadeddata: 1,
  onloadedmetadata: 1,
  onloadstart: 1,
  onencrypted: 1,
  onpause: 1,
  onplay: 1,
  onplaying: 1,
  onprogress: 1,
  onratechange: 1,
  onseeking: 1,
  onseeked: 1,
  onstalled: 1,
  onsuspend: 1,
  ontimeupdate: 1,
  onvolumechange: 1,
  onwaiting: 1
}

class EventHook {
  type = 'EventHook'
  constructor (eventName, handler) {
    this.eventName = getEventName(eventName)
    this.handler = handler
  }

  hook (node, prop, prev) {
    if (prev && prev.type === 'EventHook' &&
      prev.handler === this.handler &&
      prev.eventName === this.eventName) {
      return
    }
    const eventName = this.eventName
    let delegatedRoots = delegatedEvents.get(eventName)
    if (unbubbleEvents[eventName] === 1) {
      if (!delegatedRoots) {
        delegatedRoots = new SimpleMap()
      }
      const event = attachEventToNode(node, eventName, delegatedRoots)
      delegatedEvents.set(eventName, delegatedRoots)
      if (isFunction(this.handler)) {
        delegatedRoots.set(node, {
          eventHandler: this.handler,
          event
        })
      }
    } else {
      if (!delegatedRoots) {
        delegatedRoots = {
          items: new SimpleMap()
        }
        delegatedRoots.event = attachEventToDocument(document, eventName, delegatedRoots)
        delegatedEvents.set(eventName, delegatedRoots)
      }
      if (isFunction(this.handler)) {
        delegatedRoots.items.set(node, this.handler)
      }
    }
  }

  unhook (node, prop, next) {
    if (next && next.type === 'EventHook' &&
      next.handler === this.handler &&
      next.eventName === next.eventName) {
      return
    }
    const eventName = this.eventName
    let delegatedRoots = delegatedEvents.get(eventName)
    if (unbubbleEvents[eventName] === 1 && delegatedRoots) {
      let event = delegatedRoots.get(node)
      node.removeEventListener(parseEventName(eventName), event.event, false)
      delegatedRoots.remove(node)
      if (delegatedRoots.size() === 0) {
        delegatedEvents.remove(eventName)
      }
    } else if (delegatedRoots && delegatedRoots.items) {
      let items = delegatedRoots.items
      if (items.remove(node) && items.size() === 0) {
        document.removeEventListener(parseEventName(eventName), delegatedRoots.event, false)
        delegatedEvents.remove(eventName)
      }
    }
  }
}

function getEventName (name) {
  if (name === 'onDoubleClick') {
    name = 'ondblclick'
  } else if (name === 'onTouchTap') {
    name = 'onclick'
  }
  return name.toLowerCase()
}

function parseEventName (name) {
  return name.substr(2)
}

function stopPropagation () {
  this.cancelBubble = true
  this.stopImmediatePropagation()
}

function dispatchEvent (event, target, items, count, eventData) {
  const eventsToTrigger = items.get(target)
  if (eventsToTrigger) {
    count--
    eventData.currentTarget = target
    eventsToTrigger(event)
    if (event.cancelBubble) {
      return
    }
  }
  if (count > 0) {
    const parentDom = target.parentNode
    if (parentDom === null || (event.type === 'click' && parentDom.nodeType === 1 && parentDom.disabled)) {
      return
    }
    dispatchEvent(event, parentDom, items, count, eventData)
  }
}

function attachEventToDocument (doc, eventName, delegatedRoots) {
  const eventHandler = (event) => {
    const count = delegatedRoots.items.size()
    if (count > 0) {
      const eventData = {
        currentTarget: event.target
      }
      Object.defineProperties(event, {
        currentTarget: {
          configurable: true,
          get () {
            return eventData.currentTarget
          }
        },
        stopPropagation: {
          value: stopPropagation
        }
      })
      dispatchEvent(event, event.target, delegatedRoots.items, count, eventData)
    }
  }
  doc.addEventListener(parseEventName(eventName), eventHandler, false)
  return eventHandler
}

function attachEventToNode (node, eventName, delegatedRoots) {
  const eventHandler = (event) => {
    const eventToTrigger = delegatedRoots.get(node)
    if (eventToTrigger && eventToTrigger.eventHandler) {
      const eventData = {
        currentTarget: event.target
      }
      Object.defineProperties(event, {
        currentTarget: {
          configurable: true,
          get () {
            return eventData.currentTarget
          }
        }
      })
      eventData.currentTarget = event.target
      eventToTrigger.eventHandler(event)
    }
  }
  node.addEventListener(parseEventName(eventName), eventHandler, false)
  return eventHandler
}

export default EventHook
<commit_msg>fix:非冒泡事件的currentTarget设定有误<commit_after>import { isFunction } from '~'
import SimpleMap from '~/simple-map'

const delegatedEvents = new SimpleMap()

const unbubbleEvents = {
  onmousemove: 1,
  ontouchmove: 1,
  onmouseleave: 1,
  onmouseenter: 1,
  onload: 1,
  onunload: 1,
  onscroll: 1,
  onfocus: 1,
  onblur: 1,
  onrowexit: 1,
  onbeforeunload: 1,
  onstop: 1,
  ondragdrop: 1,
  ondragenter: 1,
  ondragexit: 1,
  ondraggesture: 1,
  ondragover: 1,
  oncontextmenu: 1,
  onerror: 1,
  onabort: 1,
  oncanplay: 1,
  oncanplaythrough: 1,
  ondurationchange: 1,
  onemptied: 1,
  onended: 1,
  onloadeddata: 1,
  onloadedmetadata: 1,
  onloadstart: 1,
  onencrypted: 1,
  onpause: 1,
  onplay: 1,
  onplaying: 1,
  onprogress: 1,
  onratechange: 1,
  onseeking: 1,
  onseeked: 1,
  onstalled: 1,
  onsuspend: 1,
  ontimeupdate: 1,
  onvolumechange: 1,
  onwaiting: 1
}

class EventHook {
  type = 'EventHook'
  constructor (eventName, handler) {
    this.eventName = getEventName(eventName)
    this.handler = handler
  }

  hook (node, prop, prev) {
    if (prev && prev.type === 'EventHook' &&
      prev.handler === this.handler &&
      prev.eventName === this.eventName) {
      return
    }
    const eventName = this.eventName
    let delegatedRoots = delegatedEvents.get(eventName)
    if (unbubbleEvents[eventName] === 1) {
      if (!delegatedRoots) {
        delegatedRoots = new SimpleMap()
      }
      const event = attachEventToNode(node, eventName, delegatedRoots)
      delegatedEvents.set(eventName, delegatedRoots)
      if (isFunction(this.handler)) {
        delegatedRoots.set(node, {
          eventHandler: this.handler,
          event
        })
      }
    } else {
      if (!delegatedRoots) {
        delegatedRoots = {
          items: new SimpleMap()
        }
        delegatedRoots.event = attachEventToDocument(document, eventName, delegatedRoots)
        delegatedEvents.set(eventName, delegatedRoots)
      }
      if (isFunction(this.handler)) {
        delegatedRoots.items.set(node, this.handler)
      }
    }
  }

  unhook (node, prop, next) {
    if (next && next.type === 'EventHook' &&
      next.handler === this.handler &&
      next.eventName === next.eventName) {
      return
    }
    const eventName = this.eventName
    let delegatedRoots = delegatedEvents.get(eventName)
    if (unbubbleEvents[eventName] === 1 && delegatedRoots) {
      let event = delegatedRoots.get(node)
      node.removeEventListener(parseEventName(eventName), event.event, false)
      delegatedRoots.remove(node)
      if (delegatedRoots.size() === 0) {
        delegatedEvents.remove(eventName)
      }
    } else if (delegatedRoots && delegatedRoots.items) {
      let items = delegatedRoots.items
      if (items.remove(node) && items.size() === 0) {
        document.removeEventListener(parseEventName(eventName), delegatedRoots.event, false)
        delegatedEvents.remove(eventName)
      }
    }
  }
}

function getEventName (name) {
  if (name === 'onDoubleClick') {
    name = 'ondblclick'
  } else if (name === 'onTouchTap') {
    name = 'onclick'
  }
  return name.toLowerCase()
}

function parseEventName (name) {
  return name.substr(2)
}

function stopPropagation () {
  this.cancelBubble = true
  this.stopImmediatePropagation()
}

function dispatchEvent (event, target, items, count, eventData) {
  const eventsToTrigger = items.get(target)
  if (eventsToTrigger) {
    count--
    eventData.currentTarget = target
    eventsToTrigger(event)
    if (event.cancelBubble) {
      return
    }
  }
  if (count > 0) {
    const parentDom = target.parentNode
    if (parentDom === null || (event.type === 'click' && parentDom.nodeType === 1 && parentDom.disabled)) {
      return
    }
    dispatchEvent(event, parentDom, items, count, eventData)
  }
}

function attachEventToDocument (doc, eventName, delegatedRoots) {
  const eventHandler = (event) => {
    const count = delegatedRoots.items.size()
    if (count > 0) {
      const eventData = {
        currentTarget: event.target
      }
      Object.defineProperties(event, {
        currentTarget: {
          configurable: true,
          get () {
            return eventData.currentTarget
          }
        },
        stopPropagation: {
          value: stopPropagation
        }
      })
      dispatchEvent(event, event.target, delegatedRoots.items, count, eventData)
    }
  }
  doc.addEventListener(parseEventName(eventName), eventHandler, false)
  return eventHandler
}

function attachEventToNode (node, eventName, delegatedRoots) {
  const eventHandler = (event) => {
    const eventToTrigger = delegatedRoots.get(node)
    if (eventToTrigger && eventToTrigger.eventHandler) {
      const eventData = {
        currentTarget: node
      }
      Object.defineProperties(event, {
        currentTarget: {
          configurable: true,
          get () {
            return eventData.currentTarget
          }
        }
      })
      eventToTrigger.eventHandler(event)
    }
  }
  node.addEventListener(parseEventName(eventName), eventHandler, false)
  return eventHandler
}

export default EventHook
<|endoftext|>


<commit_before>import _ from 'underscore';
import console from '../lib/helpers/consoleHelpers.js';

class MetadataProvider {

    /**
     * Validates a field metadata
     * @param metadata
     * @private
     */
    validateFieldMetadata(metadata) {
        if (!metadata) throw Error('metadata should not be null or undefined');
        if (!metadata.name) throw Error('metadata\'s "name" property is required');
        if (!metadata.type) throw Error('metadata\'s "type" property is required');
    }

    /**
     * Gets a raw entity from the given schema. No processing.
     * @param schema
     * @param entityName
     * @returns {*}
     */
    getEntity(schema, entityName) {
        if (schema === null || schema === undefined) {
            throw new Error(`Parameter should not be not or undefined. Parameter name: schema`);
        }

        if (schema.entities === undefined || schema.entities === null) {
            throw new Error('Parameter should not be null or undefined. Parameter: ' + schema.entity);
        }

        if (entityName === null || entityName === undefined) {
            throw new Error(`Parameter should not be not or undefined. Parameter name: entityName`);
        }
        let entity = _.find(schema.entities, e => e.name === entityName);
        if (!entity) {
            throw new Error(`Could not find entity. Entity name: ${entityName}`);
        }
        return entity;
    }

    /**
     * Gets a raw layout from the given entity. No processing.
     * @param entity
     * @param layoutName
     * @returns {*}
     */
    getLayout(entity, layoutName) {
        if (entity === null || entity === undefined) {
            throw new Error(`Parameter should not be not or undefined. Parameter name: entity`);
        }
        let layout = _.find(entity.layouts, l => l.name === layoutName);
        if (!layout) {
            throw new Error(`Could not find layout. Layout name: ${layoutName}`);
        }
        return layout;
    }

    /**
     * Gets a raw entity and a raw layout from the given schema.
     * @param schema
     * @param entityName
     * @param layoutName
     * @returns {{entity: *, layout: *}}
     */
    getEntityAndLayout(schema, entityName, layoutName) {

        let entity = this.getEntity(schema, entityName);
        let layout = this.getLayout(entity, layoutName);

        return {
            entity: entity,
            layout: layout
        }
    }

    /**
     * Internal method for merging entity and layout fields
     * @param schema
     * @param entity
     * @param layout
     * @param prefix
     * @param partialResult
     * @return {Number}
     */
    getFieldsInternal(schema, entity, layout, partialResult) {

        if(!entity) {
            throw Error('Paramater is fucked');
        }

        if (!partialResult) {
            partialResult = [];
        }

        let thisGroupFields = [];

        if (!layout.fields && !layout.groups) {
            throw Error('a layout can either have fields or groups. Never both.');
        }

        if (layout.groups) {
            for (let i = 0; i < layout.groups.length; i++) {
                thisGroupFields = _.union(thisGroupFields, this.getFieldsInternal(schema, entity, layout.groups[i], partialResult));
            }
        }
        else if (layout.fields) {

            for (let i = 0; i < layout.fields.length; i++) {

                let groupField = layout.fields[i];
                let existingEntityProperty = _.find(entity.fields, field => field.name == groupField.name);

                if (!existingEntityProperty) {
                    throw Error(`cannot find entity field. Field: ${groupField.name}. Group: ${layout}`);
                }

                let field = _.extend({}, existingEntityProperty, groupField);
                this.validateFieldMetadata(field);

                thisGroupFields.push(field);

                if (field.type == 'entity') {
                    if (!field.entityName) {
                        throw Error('when a field is of type \'entity\', it needs to specify an \'entityName\'')
                    }
                    if (!field.layoutName) {
                        throw Error('when a field is of type \'entity\', it needs to specify a \'layoutName\'');
                    }

                    let entityAndLayout = this.getEntityAndLayout(schema, field.entityName, field.layoutName);
                    field.layout = this.processLayout(schema, entityAndLayout.entity, entityAndLayout.layout);
                    field.fields = this.getFieldsInternal(schema, entityAndLayout.entity, entityAndLayout.layout, partialResult);
                }
            }
        }
        else {
            throw Error('a layout must have either fields or groups.');
        }
        return _.union(partialResult, thisGroupFields);

    }

    /**
     * Merges the given field collection
     * @param schema
     * @param entity
     * @param layout
     * @external https://github.com/gearz-lab/react-metaform/blob/master/docs-md/MetadataProvider.md
     */
    getFields(schema, entity, layout) {
        entity = typeof entity === 'string' ? this.getEntity(schema, entity) : entity;
        layout = typeof layout === 'string' ? this.getLayout(entity, layout) : layout;

        return this.getFieldsInternal(schema, entity, layout);
    }

    /**
     * Creates a clone of the given layout-group that maintains only the hierarchy and the 'name' property
     * for fields
     * @param layoutGroup
     * @returns {Object}
     */
    processLayoutGroup(layoutGroup) {

        let layoutGroupClone = {};

        if (layoutGroup.fields) {
            layoutGroupClone.fields = [];
            for (let i = 0; i < layoutGroup.fields.length; i++) {
                layoutGroupClone.fields.push({ name: layoutGroup.fields[i].name });
            }
        }
        else if (layoutGroup.groups) {
            layoutGroupClone.groups = [];
            for (let i = 0; i < layoutGroup.groups.length; i++) {
                layoutGroup.groups.push(this.processLayoutGroup(layoutGroup.groups[i]));
            }
        }

        return layoutGroupClone;
    }

    processLayout(schema, entity, layout) {
        entity = typeof entity === 'string' ? this.getEntity(schema, entity) : entity;
        layout = typeof layout === 'string' ? this.getLayout(entity, layout) : layout;

        return this.processLayoutGroup(layout);
    }
}

export default new MetadataProvider();
<commit_msg>MetadataProvider.getFields now supports array fields<commit_after>import _ from 'underscore';
import console from '../lib/helpers/consoleHelpers.js';

class MetadataProvider {

    /**
     * Validates a field metadata
     * @param metadata
     * @private
     */
    validateFieldMetadata(metadata) {
        if (!metadata) throw Error('metadata should not be null or undefined');
        if (!metadata.name) throw Error('metadata\'s "name" property is required');
        if (!metadata.type) throw Error('metadata\'s "type" property is required');
    }

    /**
     * Gets a raw entity from the given schema. No processing.
     * @param schema
     * @param entityName
     * @returns {*}
     */
    getEntity(schema, entityName) {
        if (schema === null || schema === undefined) {
            throw new Error(`Parameter should not be not or undefined. Parameter name: schema`);
        }

        if (schema.entities === undefined || schema.entities === null) {
            throw new Error('Parameter should not be null or undefined. Parameter: ' + schema.entity);
        }

        if (entityName === null || entityName === undefined) {
            throw new Error(`Parameter should not be not or undefined. Parameter name: entityName`);
        }
        let entity = _.find(schema.entities, e => e.name === entityName);
        if (!entity) {
            throw new Error(`Could not find entity. Entity name: ${entityName}`);
        }
        return entity;
    }

    /**
     * Gets a raw layout from the given entity. No processing.
     * @param entity
     * @param layoutName
     * @returns {*}
     */
    getLayout(entity, layoutName) {
        if (entity === null || entity === undefined) {
            throw new Error(`Parameter should not be not or undefined. Parameter name: entity`);
        }
        let layout = _.find(entity.layouts, l => l.name === layoutName);
        if (!layout) {
            throw new Error(`Could not find layout. Layout name: ${layoutName}`);
        }
        return layout;
    }

    /**
     * Gets a raw entity and a raw layout from the given schema.
     * @param schema
     * @param entityName
     * @param layoutName
     * @returns {{entity: *, layout: *}}
     */
    getEntityAndLayout(schema, entityName, layoutName) {

        let entity = this.getEntity(schema, entityName);
        let layout = this.getLayout(entity, layoutName);

        return {
            entity: entity,
            layout: layout
        }
    }

    /**
     * Internal method for merging entity and layout fields
     * @param schema
     * @param entity
     * @param layout
     * @param prefix
     * @param partialResult
     * @return {Number}
     */
    getFieldsInternal(schema, entity, layout, partialResult) {

        if(!entity) {
            throw Error('Paramater is fucked');
        }

        if (!partialResult) {
            partialResult = [];
        }

        let thisGroupFields = [];

        if (!layout.fields && !layout.groups) {
            throw Error('a layout can either have fields or groups. Never both.');
        }

        if (layout.groups) {
            for (let i = 0; i < layout.groups.length; i++) {
                thisGroupFields = _.union(thisGroupFields, this.getFieldsInternal(schema, entity, layout.groups[i], partialResult));
            }
        }
        else if (layout.fields) {

            for (let i = 0; i < layout.fields.length; i++) {

                let groupField = layout.fields[i];
                let existingEntityProperty = _.find(entity.fields, field => field.name == groupField.name);

                if (!existingEntityProperty) {
                    throw Error(`cannot find entity field. Field: ${groupField.name}. Group: ${layout}`);
                }

                let field = _.extend({}, existingEntityProperty, groupField);
                this.validateFieldMetadata(field);

                thisGroupFields.push(field);

                if (field.type == 'entity') {
                    if (!field.entityName) {
                        throw Error('when a field is of type \'entity\', it needs to specify an \'entityName\'')
                    }
                    if (!field.layoutName) {
                        throw Error('when a field is of type \'entity\', it needs to specify a \'layoutName\'');
                    }

                    let entityAndLayout = this.getEntityAndLayout(schema, field.entityName, field.layoutName);
                    field.layout = this.processLayout(schema, entityAndLayout.entity, entityAndLayout.layout);
                    field.fields = this.getFieldsInternal(schema, entityAndLayout.entity, entityAndLayout.layout, partialResult);
                }

                if(field.type == 'array') {
                    if(!field.arrayType) {
                        throw Error('when a field is of type \'array\', it needs to specify an \'arrayType\'');
                    }

                    if(field.arrayType != 'entity') {
                        throw Error('only entity arrays are currently supported');
                    }

                    if(!field.entityType) {
                        throw Error('when a field is of type \'array\' and arrayType is \'entity\', it needs to specify an \'entityType\'');
                    }

                    if (!field.layoutName) {
                        throw Error('when a field is of type \'entity\', it needs to specify a \'layoutName\'');
                    }

                    let entityAndLayout = this.getEntityAndLayout(schema, field.entityType, field.layoutName);
                    field.layout = this.processLayout(schema, entityAndLayout.entity, entityAndLayout.layout);
                    field.fields = this.getFieldsInternal(schema, entityAndLayout.entity, entityAndLayout.layout, partialResult);
                }
            }
        }
        else {
            throw Error('a layout must have either fields or groups.');
        }
        return _.union(partialResult, thisGroupFields);

    }

    /**
     * Merges the given field collection
     * @param schema
     * @param entity
     * @param layout
     * @external https://github.com/gearz-lab/react-metaform/blob/master/docs-md/MetadataProvider.md
     */
    getFields(schema, entity, layout) {
        entity = typeof entity === 'string' ? this.getEntity(schema, entity) : entity;
        layout = typeof layout === 'string' ? this.getLayout(entity, layout) : layout;

        return this.getFieldsInternal(schema, entity, layout);
    }

    /**
     * Creates a clone of the given layout-group that maintains only the hierarchy and the 'name' property
     * for fields
     * @param layoutGroup
     * @returns {Object}
     */
    processLayoutGroup(layoutGroup) {

        let layoutGroupClone = {};

        if (layoutGroup.fields) {
            layoutGroupClone.fields = [];
            for (let i = 0; i < layoutGroup.fields.length; i++) {
                layoutGroupClone.fields.push({ name: layoutGroup.fields[i].name });
            }
        }
        else if (layoutGroup.groups) {
            layoutGroupClone.groups = [];
            for (let i = 0; i < layoutGroup.groups.length; i++) {
                layoutGroup.groups.push(this.processLayoutGroup(layoutGroup.groups[i]));
            }
        }

        return layoutGroupClone;
    }

    processLayout(schema, entity, layout) {
        entity = typeof entity === 'string' ? this.getEntity(schema, entity) : entity;
        layout = typeof layout === 'string' ? this.getLayout(entity, layout) : layout;

        return this.processLayoutGroup(layout);
    }
}

export default new MetadataProvider();
<|endoftext|>


<commit_before>'use strict';

var halfPI = Math.PI / 2;
var twoPI = Math.PI * 2;

module.exports = function waveformer(config) {

    var style = config.style || 'fill', // 'fill' or 'line'
        shape = config.shape || 'linear', // 'circular' or 'linear'
        color = config.color || 0,
        bgColor = config.bgColor,
        lineWidth = config.lineWidth || 1,
        percent = config.percent || 1,
        originX = config.x || 0,
        originY = config.y || 0,
        transform = config.transform,
        canvas = config.canvas,
        width = config.width || (canvas && canvas.width),
        height = config.height || (canvas && canvas.height),
        ctx, currentColor, waveform, length, i, value, x, y,
        radius, innerRadius, centerX, centerY;

    if(!canvas && !config.context) {
      canvas = document.createElement('canvas');
      width = width || canvas.width;
      height = height || canvas.height;
      canvas.width = height;
      canvas.height = height;
    }

    if(shape === 'circular') {
      radius = config.radius || Math.min(height / 2, width / 2),
      innerRadius = config.innerRadius || radius / 2;
      centerX = originX + width / 2;
      centerY = originY + height / 2;
    }

    ctx = config.context || canvas.getContext('2d');

    var clear = function() {
      if(bgColor) {
          ctx.fillStyle = bgColor;
          ctx.fillRect(originX, originY, width, height);
      } else {
          ctx.clearRect(originX, originY, width, height);
      }

      ctx.lineWidth = lineWidth;

      currentColor = null;

      if(typeof color !== 'function') {
        ctx.strokeStyle = color;
        ctx.beginPath();
      }
    };

    var updateColor = function(position, length, value) {
      if(typeof color === 'function') {
        var newColor = color(position, length, value);
        if(newColor !== currentColor) {
          currentColor = newColor;
          ctx.stroke();
          ctx.strokeStyle = currentColor;
          ctx.beginPath();
        }
      }
    };

    var getValue = function(value) {
      if(typeof transform === 'function') {
        return transform(value);
      }
      return value;
    };

    var getWaveform = function(value, length) {
      if(value && typeof value.waveform === 'function') {
        return value.waveform(length);
      }
      if(value) {
        return value;
      }
      if(config.waveform) {
        return config.waveform;
      }
      if(config.sound) {
        return config.sound.waveform(length);
      }
      return null;
    };

    var update = function(wave) {

      clear();

      if(shape === 'circular') {

        waveform = getWaveform(wave, 360);
        length = Math.floor(waveform.length * percent);

        var step = twoPI / length,
            angle, magnitude, sine, cosine;

        for (i = 0; i < length; i++) {
          value = getValue(waveform[i]);
          updateColor(i, length, value);

          angle = i * step - halfPI;
          cosine = Math.cos(angle);
          sine = Math.sin(angle);

          if(style === 'fill') {
            x = centerX + innerRadius * cosine;
            y = centerY + innerRadius * sine;
            ctx.moveTo(x, y);
          }

          magnitude = innerRadius + (radius - innerRadius) * value;
          x = centerX + magnitude * cosine;
          y = centerY + magnitude * sine;

          if(style === 'line' && i === 0) {
            ctx.moveTo(x, y);
          }

          ctx.lineTo(x, y);
        }

        if(style === 'line') {
          ctx.closePath();
        }
      }
      else {

        waveform = getWaveform(wave, width);
        length = Math.min(waveform.length, width - lineWidth / 2);
        length = Math.floor(length * percent);

        for(i = 0; i < length; i++) {
          value = getValue(waveform[i]);
          updateColor(i, length, value);

          if(style === 'line' && i > 0) {
            ctx.lineTo(x, y);
          }

          x = originX + i;
          y = originY + height - Math.round(height * value);
          y = Math.floor(Math.min(y, originY + height - lineWidth / 2));

          if(style === 'fill') {
            ctx.moveTo(x, y);
            ctx.lineTo(x, originY + height);
          } else {
            ctx.lineTo(x, y);
          }
        }
      }
      ctx.stroke();
    };

    update.canvas = canvas;

    if(config.waveform || config.sound) {
      update();
    }

    return update;
};
<commit_msg>Passes position and length to waveform transform fn<commit_after>'use strict';

var halfPI = Math.PI / 2;
var twoPI = Math.PI * 2;

module.exports = function waveformer(config) {

    var style = config.style || 'fill', // 'fill' or 'line'
        shape = config.shape || 'linear', // 'circular' or 'linear'
        color = config.color || 0,
        bgColor = config.bgColor,
        lineWidth = config.lineWidth || 1,
        percent = config.percent || 1,
        originX = config.x || 0,
        originY = config.y || 0,
        transform = config.transform,
        canvas = config.canvas,
        width = config.width || (canvas && canvas.width),
        height = config.height || (canvas && canvas.height),
        ctx, currentColor, waveform, length, i, value, x, y,
        radius, innerRadius, centerX, centerY;

    if(!canvas && !config.context) {
      canvas = document.createElement('canvas');
      width = width || canvas.width;
      height = height || canvas.height;
      canvas.width = height;
      canvas.height = height;
    }

    if(shape === 'circular') {
      radius = config.radius || Math.min(height / 2, width / 2),
      innerRadius = config.innerRadius || radius / 2;
      centerX = originX + width / 2;
      centerY = originY + height / 2;
    }

    ctx = config.context || canvas.getContext('2d');

    var clear = function() {
      if(bgColor) {
          ctx.fillStyle = bgColor;
          ctx.fillRect(originX, originY, width, height);
      } else {
          ctx.clearRect(originX, originY, width, height);
      }

      ctx.lineWidth = lineWidth;

      currentColor = null;

      if(typeof color !== 'function') {
        ctx.strokeStyle = color;
        ctx.beginPath();
      }
    };

    var updateColor = function(position, length, value) {
      if(typeof color === 'function') {
        var newColor = color(position, length, value);
        if(newColor !== currentColor) {
          currentColor = newColor;
          ctx.stroke();
          ctx.strokeStyle = currentColor;
          ctx.beginPath();
        }
      }
    };

    var getValue = function(value, position, length) {
      if(typeof transform === 'function') {
        return transform(value, position, length);
      }
      return value;
    };

    var getWaveform = function(value, length) {
      if(value && typeof value.waveform === 'function') {
        return value.waveform(length);
      }
      if(value) {
        return value;
      }
      if(config.waveform) {
        return config.waveform;
      }
      if(config.sound) {
        return config.sound.waveform(length);
      }
      return null;
    };

    var update = function(wave) {

      clear();

      if(shape === 'circular') {

        waveform = getWaveform(wave, 360);
        length = Math.floor(waveform.length * percent);

        var step = twoPI / length,
            angle, magnitude, sine, cosine;

        for (i = 0; i < length; i++) {
          value = getValue(waveform[i], i, length);
          updateColor(i, length, value);

          angle = i * step - halfPI;
          cosine = Math.cos(angle);
          sine = Math.sin(angle);

          if(style === 'fill') {
            x = centerX + innerRadius * cosine;
            y = centerY + innerRadius * sine;
            ctx.moveTo(x, y);
          }

          magnitude = innerRadius + (radius - innerRadius) * value;
          x = centerX + magnitude * cosine;
          y = centerY + magnitude * sine;

          if(style === 'line' && i === 0) {
            ctx.moveTo(x, y);
          }

          ctx.lineTo(x, y);
        }

        if(style === 'line') {
          ctx.closePath();
        }
      }
      else {

        waveform = getWaveform(wave, width);
        length = Math.min(waveform.length, width - lineWidth / 2);
        length = Math.floor(length * percent);

        for(i = 0; i < length; i++) {
          value = getValue(waveform[i], i, length);
          updateColor(i, length, value);

          if(style === 'line' && i > 0) {
            ctx.lineTo(x, y);
          }

          x = originX + i;
          y = originY + height - Math.round(height * value);
          y = Math.floor(Math.min(y, originY + height - lineWidth / 2));

          if(style === 'fill') {
            ctx.moveTo(x, y);
            ctx.lineTo(x, originY + height);
          } else {
            ctx.lineTo(x, y);
          }
        }
      }
      ctx.stroke();
    };

    update.canvas = canvas;

    if(config.waveform || config.sound) {
      update();
    }

    return update;
};
<|endoftext|>


<commit_before>ngapp.service('recordTreeElementService', function(errorService) {
    this.buildFunctions = function(scope) {
        let uneditableValueTypes = [xelib.vtUnknown, xelib.vtArray, xelib.vtStruct];

        // scope functions
        scope.addElement = function(node, index) {
            errorService.try(function() {
                let handle = node.handles[index],
                    record = index ? scope.overrides[index - 1] : scope.record;
                if (handle) {
                    // append element to array
                    xelib.AddElement(handle, '.');
                } else {
                    // create element in struct
                    handle = node.parent ? node.parent.handles[index] : record;
                    if (!handle) return; // this should never happen
                    xelib.AddElement(handle, node.label);
                }
                scope.reload(); // TODO? This is kind of greedy, but it's simple
                scope.$root.$broadcast('recordUpdated', record);
            });
        };

        scope.editElement = function(node, index) {
            if (uneditableValueTypes.contains(node.value_type)) return;
            scope.targetNode = node;
            scope.targetIndex = index - 1;
            scope.toggleEditModal(true);
        };

        scope.deleteElement = function(node) {
            errorService.try(function() {
                let handle = node.handles[scope.focusedIndex - 1];
                xelib.RemoveElement(handle);
                xelib.Release(handle);
            });
        };

        scope.deleteElements = function() {
            scope.selectedNodes.forEach(scope.deleteElement);
            scope.reload(); // TODO? This is kind of greedy, but it's simple
        };

        scope.canPaste = function(asOverride) {
            return false;
        };
    }
});<commit_msg>fixed some bugs with creating/deleting elements on the record view<commit_after>ngapp.service('recordTreeElementService', function(errorService) {
    this.buildFunctions = function(scope) {
        let uneditableValueTypes = [xelib.vtUnknown, xelib.vtArray, xelib.vtStruct];

        // scope functions
        scope.addElement = function(node, index) {
            errorService.try(function() {
                let handle = node.handles[index],
                    record = index ? scope.overrides[index - 1] : scope.record;
                if (handle) {
                    // append element to array
                    xelib.AddElement(handle, '.');
                } else {
                    // create element in struct
                    handle = node.parent ? node.parent.handles[index] : record;
                    if (!handle) return; // this should never happen
                    let path = node.label.indexOf(' - ') == 4 ? node.label.substr(0, 4) : node.label;
                    xelib.AddElement(handle, path);
                }
                scope.reload(); // TODO? This is kind of greedy, but it's simple
                scope.$root.$broadcast('recordUpdated', record);
            });
        };

        scope.editElement = function(node, index) {
            if (uneditableValueTypes.contains(node.value_type)) return;
            scope.targetNode = node;
            scope.targetIndex = index - 1;
            scope.toggleEditModal(true);
        };

        scope.deleteElement = function(node) {
            errorService.try(function() {
                let handle = node.handles[scope.focusedIndex - 1];
                xelib.RemoveElement(handle);
                //xelib.Release(handle);
            });
        };

        scope.deleteElements = function() {
            scope.selectedNodes.forEach(scope.deleteElement);
            scope.clearSelection(true);
            scope.reload(); // TODO? This is kind of greedy, but it's simple
        };

        scope.canPaste = function(asOverride) {
            return false;
        };
    }
});<|endoftext|>