<commit_before>'use strict';

if (typeof THREE === 'undefined') {
	var THREE = require('./three/CanvasRenderer.js');
	// this is a modified helvetiker
	THREE.FontUtils.loadFace(require('./three/font/helvetiker_regular.typeface.js'));
}

var child_process = require('child_process');
var async = require('async');

function ThreeDTexter(canvas, rgb2gif) {

	this.api = {version: 0.1};

	var opts = this.opts = {
		camera: null,
		group: null,
		scene:  null,
		renderer: null,
		text: {
			canvas: null,
			options: {
				size: 100,
				height: 50,
				hover: 10,
				curveSegments: 5,
				bevelThickness: 4,
				bevelSize: 2,
				bevelEnabled: false,
				font: 'helvetiker',
				weight: 'normal',
				style: 'normal',
				textColor: 0x3f6375,
				sideColor: 0xb85dd4
			}
		},
		wavePosition: 0,
		waveAngle: Math.PI / 6,
		rotationRate: Math.PI / 60,
		rotating: false,
		numFrames: 23,
		delay: 84,
		axis: 'wave'
	};

	var exports = {};

	this.setup = function(){
		opts.camera = new THREE.PerspectiveCamera( 60, 2, 50, 2000 );
		opts.camera.position.set( 0, 0, 500 );
		opts.scene = new THREE.Scene();

		var ambientLight = new THREE.AmbientLight(0xffffff);
		opts.scene.add(ambientLight);

		var dirLight = new THREE.DirectionalLight(0xffffff, 0.9);
		dirLight.position.set(0.25, 1, 0).normalize();
		opts.scene.add(dirLight);
	}

	this.drawTextInternal = function(text, text_options){

		if (text_options != null){
			for (var opt in text_options){
				opts.text.options[opt] = text_options[opt];
			}
		}

		// material
		this.makeMaterial();

		var materials = [opts.text.options.sideMaterial, opts.text.options.textMaterial];
		var material = new THREE.MeshFaceMaterial(materials);

		// text
		if (opts.axis == 'wave' || opts.axis == 'spin') {
			var width = 0;
			var text3d = new THREE.Object3D();

			THREE.FontUtils.size = opts.text.options.size;
			THREE.FontUtils.divisions = opts.text.options.curveSegments;

			THREE.FontUtils.face = opts.text.options.font;
			THREE.FontUtils.weight = opts.text.options.weight;
			THREE.FontUtils.style = opts.text.options.style;

			for (var i = 0; i < text.length; i++) {

				var offset = THREE.FontUtils.drawText(text[i]).offset;

				if (text[i] == ' ') {
					width += offset * 2;

					continue;
				}

				var letter3d = new THREE.TextGeometry(text[i], opts.text.options);
				letter3d.computeBoundingBox();

				letter3d.applyMatrix(new THREE.Matrix4().makeTranslation(
					-0.5 * (letter3d.boundingBox.max.x - letter3d.boundingBox.min.x), 0,
					-opts.text.options.height / 2) );

				opts.verticalOffset = -0.5 * (letter3d.boundingBox.max.y - letter3d.boundingBox.min.y);

				var mesh = new THREE.Mesh(letter3d,  material);
				mesh.position.x = width + 0.5 * (letter3d.boundingBox.max.x - letter3d.boundingBox.min.x);

				width += offset * 2;

				for (var face in mesh.geometry.faces) {
					if (mesh.geometry.faces[face].normal.z != 0) {
						mesh.geometry.faces[face].materialIndex = 1;
					}
				}

				text3d.add(mesh);
			}

			opts.width = Math.min(Math.max(0.5 * width, 500), 1000);

			text3d.translateX(-0.5 * width);
			opts.mesh = text3d;

			this.setAxis(opts.axis);

			opts.text.canvas = text3d;
		} else {
			var text3d = new THREE.TextGeometry(text, opts.text.options);
			text3d.computeBoundingBox();
			text3d.computeVertexNormals();

			var triangleAreaHeuristics = 0.1 * ( opts.text.options.height * opts.text.options.size );

			for ( var i = 0; i < text3d.faces.length; i ++ ) {

				var face = text3d.faces[ i ];

				if ( face.materialIndex == 1 ) {

					for ( var j = 0; j < face.vertexNormals.length; j ++ ) {
						face.vertexNormals[ j ].z = 0;
						face.vertexNormals[ j ].normalize();
					}

					var va = text3d.vertices[ face.a ];
					var vb = text3d.vertices[ face.b ];
					var vc = text3d.vertices[ face.c ];

					var s = THREE.GeometryUtils.triangleArea( va, vb, vc );

					if ( s > triangleAreaHeuristics ) {
						for ( var j = 0; j < face.vertexNormals.length; j ++ ) {
							face.vertexNormals[ j ].copy( face.normal );
						}
					}
				}
			}

			var centerOffset = -THREE.FontUtils.drawText(text).offset;

			opts.width = Math.min(Math.max(0.5 * (text3d.boundingBox.max.x - text3d.boundingBox.min.x), 500), 1000);

			opts.mesh = new THREE.Mesh(text3d,  material);

			opts.mesh.position.x = centerOffset;

			for (var face in opts.mesh.geometry.faces) {
				if (opts.mesh.geometry.faces[face].normal.z != 0) {
					opts.mesh.geometry.faces[face].materialIndex = 1;
				}
			}

			this.setAxis(opts.axis);

			opts.text.canvas = opts.mesh;
		}

		return text;
	};

	this.makeMaterial = function(){
		opts.text.options.textMaterial = new THREE.MeshPhongMaterial({
			color: opts.text.options.textColor,
			shading: THREE.FlatShading,
			specular: 0x222222,
			shininess: 50,
			ambient: opts.text.options.textColor,
			overdraw: 0.4
		});
		opts.text.options.sideMaterial = new THREE.MeshPhongMaterial({
			color: opts.text.options.sideColor,
			shading: THREE.SmoothShading,
			specular: 0x222222,
			shininess: 50,
			ambient: opts.text.options.sideColor,
			overdraw: 0.4
		});
	};

	this.setAxis = function(axis) {
		if (axis == 'x') {
			opts.camera.position.set(0, 0, opts.width);

			opts.mesh.position.y = -opts.text.options.size / 2;
			opts.mesh.position.z = -opts.text.options.height / 2;
		} else if (axis == 'y') {
			opts.camera.position.set(0, opts.text.options.size / 2, opts.width);

			opts.mesh.position.y = 0;
			opts.mesh.position.z = -opts.text.options.height / 2;

		} else if (axis == 'wave') {
			opts.camera.position.set(0, opts.text.options.size / 2, opts.width);

			for (var i = 0; i < opts.mesh.children.length; i++) {
				opts.mesh.children[i].position.y = opts.text.options.size * Math.sin(opts.wavePosition + opts.waveAngle * i);
			}
		} else if (axis == 'spin') {
			opts.camera.position.set(0, opts.text.options.size / 2, opts.width);

			for (var i = 0; i < opts.mesh.children.length; i++) {
				opts.mesh.children[i].rotation.y = 0;
			}
		}
	}

	var self = this;

	this.setupCanvas = function(){

		opts.group = new THREE.Object3D();
		opts.scene.add(opts.group);

		opts.canvas = canvas;
		opts['rgb2gif'] = rgb2gif;

		opts.renderer = new THREE.CanvasRenderer({
			canvas: canvas,
			alpha: true
		});
	};

	var render = this.render = function(){
		opts.renderer.render( opts.scene, opts.camera );
	};

	this.api.serve = function(gifsicle, width, height){
		opts.mesh.rotation.x = 0;
		opts.mesh.rotation.y = 0;

		opts.wavePosition = 0;
		if (opts.axis == 'wave') {
			for (var i = 0; i < opts.mesh.children.length; i++) {
				opts.mesh.children[i].position.y = opts.text.options.size * Math.sin(opts.wavePosition + opts.waveAngle * i);
			}
		} else if (opts.axis == 'spin') {
			for (var i = 0; i < opts.mesh.children.length; i++) {
				opts.mesh.children[i].rotation.y = 0;
			}
		}

		var numFrames = opts.numFrames;
		var dAngle;

		if (opts.axis == 'x' || opts.axis == 'y' || opts.axis == 'spin') {
			dAngle = Math.PI / (numFrames + 1);
		} else if (opts.axis = 'wave') {
			dAngle = 2 * Math.PI / (numFrames + 1);
		}

		if (opts.axis == 'y') {
			opts.group.rotation.y = -Math.PI / 2;
		}

		gifsicle.setMaxListeners(numFrames + 1);

		function run_capture(frame, callback){
			var value = startValue + frame * dAngle;

			if (opts.axis == 'x') {
				opts.group.rotation.x = value;
			} else if (opts.axis == 'y') {
				opts.group.rotation.y = value;
			} else if (opts.axis == 'wave') {
				opts.wavePosition = value;

				for (var i = 0; i < opts.mesh.children.length; i++) {
					opts.mesh.children[i].position.y = opts.text.options.size * Math.sin(opts.wavePosition + opts.waveAngle * i);
				}
			} else if (opts.axis == 'spin') {
				for (var i = 0; i < opts.mesh.children.length; i++) {
					opts.mesh.children[i].rotation.y = value;
				}
			}

			render();

			var encoder = child_process.spawn(opts['rgb2gif'], ['-s', width, height], {
				stdio: ['pipe', 'pipe', process.stderr]});
			// don't close the gifsicle input stream when this gif is done
			encoder.stdout.pipe(gifsicle.stdin, { end: frame <= 0 });

			var data = opts.canvas.getContext('2d').getImageData(0, 0, width, height).data;
			var pixels = new Buffer(width * height * 3);

			var count = 0;
			for (var i = 0; i < height; i++) {
				for (var j = 0; j < width; j++) {
					var b = (i * width * 4) + j * 4;
					pixels.writeUInt8(data[b], count++, true);
					pixels.writeUInt8(data[b+1], count++, true);
					pixels.writeUInt8(data[b+2], count++, true);
				}
			}
			encoder.stdin.write(pixels);

			callback();
		}

		var startValue = 0;

		if (opts.axis == 'x') {
			startValue = opts.group.rotation.x;
		} else if (opts.axis == 'y') {
			startValue = opts.group.rotation.y;
		} else if (opts.axis == 'wave') {
			startValue = opts.wavePosition;
		} else if (opts.axis == 'spin') {
			for (var i = 0; i < opts.mesh.children.length; i++) {
				startValue = opts.mesh.children[i].rotation.y;
				break;
			}
		}

		var frames = [];

		for (var frame = 0; frame <= numFrames + 1; frame++) {
			frames.push(frame);
		}

		async.each(frames, run_capture);
	}

	this.reset = function() {
		opts.group.rotation.x = 0;
		opts.group.rotation.y = 0;
	}

	this.stop = function() {
		self.reset();
		opts.rotating = false;

		render();
	}

	// actually init
	this.setup();
	this.setupCanvas();

	this.api.setText = function(text, options){
		opts.group.remove(opts.text.canvas);
		if (text != null && text.length > 0) {
			self.drawTextInternal(text, options);
			opts.group.add(opts.text.canvas);
		}
	}
	this.api.setTextOption = function(option, value){
		self.opts.text.options[option] = value;
	}
	this.api.getTextOption = function(option){
		return self.opts.text.options[option];
	}
	this.api.getTextOptions = function(){
		return self.opts.text.options;
	}
	this.api.setColor = function(front, side, background, opaque) {
		opts.text.options.textColor = front;
		opts.text.options.sideColor = side;

		if (opaque) {
			opts.renderer.setClearColor(background, 1);
		} else {
			opts.renderer.setClearColor(0xffffff, 0);
		}
	}
	this.api.isAnimating = function() {
		return opts.rotating;
	}
	this.api.setAxis = function(axis) {
		self.reset();

		opts.axis = axis;
	}

	return self;
};

var create = function(canvas, rgb2gif) {
	return new ThreeDTexter(canvas, rgb2gif);
}

module.exports = create;<commit_msg>Create buffer only once.<commit_after>'use strict';

if (typeof THREE === 'undefined') {
	var THREE = require('./three/CanvasRenderer.js');
	// this is a modified helvetiker
	THREE.FontUtils.loadFace(require('./three/font/helvetiker_regular.typeface.js'));
}

var child_process = require('child_process');
var async = require('async');

function ThreeDTexter(canvas, rgb2gif) {

	this.api = {version: 0.1};

	var opts = this.opts = {
		camera: null,
		group: null,
		scene:  null,
		renderer: null,
		text: {
			canvas: null,
			options: {
				size: 100,
				height: 50,
				hover: 10,
				curveSegments: 5,
				bevelThickness: 4,
				bevelSize: 2,
				bevelEnabled: false,
				font: 'helvetiker',
				weight: 'normal',
				style: 'normal',
				textColor: 0x3f6375,
				sideColor: 0xb85dd4
			}
		},
		wavePosition: 0,
		waveAngle: Math.PI / 6,
		rotationRate: Math.PI / 60,
		rotating: false,
		numFrames: 23,
		delay: 84,
		axis: 'wave'
	};

	var exports = {};

	this.setup = function(){
		opts.camera = new THREE.PerspectiveCamera( 60, 2, 50, 2000 );
		opts.camera.position.set( 0, 0, 500 );
		opts.scene = new THREE.Scene();

		var ambientLight = new THREE.AmbientLight(0xffffff);
		opts.scene.add(ambientLight);

		var dirLight = new THREE.DirectionalLight(0xffffff, 0.9);
		dirLight.position.set(0.25, 1, 0).normalize();
		opts.scene.add(dirLight);
	}

	this.drawTextInternal = function(text, text_options){

		if (text_options != null){
			for (var opt in text_options){
				opts.text.options[opt] = text_options[opt];
			}
		}

		// material
		this.makeMaterial();

		var materials = [opts.text.options.sideMaterial, opts.text.options.textMaterial];
		var material = new THREE.MeshFaceMaterial(materials);

		// text
		if (opts.axis == 'wave' || opts.axis == 'spin') {
			var width = 0;
			var text3d = new THREE.Object3D();

			THREE.FontUtils.size = opts.text.options.size;
			THREE.FontUtils.divisions = opts.text.options.curveSegments;

			THREE.FontUtils.face = opts.text.options.font;
			THREE.FontUtils.weight = opts.text.options.weight;
			THREE.FontUtils.style = opts.text.options.style;

			for (var i = 0; i < text.length; i++) {

				var offset = THREE.FontUtils.drawText(text[i]).offset;

				if (text[i] == ' ') {
					width += offset * 2;

					continue;
				}

				var letter3d = new THREE.TextGeometry(text[i], opts.text.options);
				letter3d.computeBoundingBox();

				letter3d.applyMatrix(new THREE.Matrix4().makeTranslation(
					-0.5 * (letter3d.boundingBox.max.x - letter3d.boundingBox.min.x), 0,
					-opts.text.options.height / 2) );

				opts.verticalOffset = -0.5 * (letter3d.boundingBox.max.y - letter3d.boundingBox.min.y);

				var mesh = new THREE.Mesh(letter3d,  material);
				mesh.position.x = width + 0.5 * (letter3d.boundingBox.max.x - letter3d.boundingBox.min.x);

				width += offset * 2;

				for (var face in mesh.geometry.faces) {
					if (mesh.geometry.faces[face].normal.z != 0) {
						mesh.geometry.faces[face].materialIndex = 1;
					}
				}

				text3d.add(mesh);
			}

			opts.width = Math.min(Math.max(0.5 * width, 500), 1000);

			text3d.translateX(-0.5 * width);
			opts.mesh = text3d;

			this.setAxis(opts.axis);

			opts.text.canvas = text3d;
		} else {
			var text3d = new THREE.TextGeometry(text, opts.text.options);
			text3d.computeBoundingBox();
			text3d.computeVertexNormals();

			var triangleAreaHeuristics = 0.1 * ( opts.text.options.height * opts.text.options.size );

			for ( var i = 0; i < text3d.faces.length; i ++ ) {

				var face = text3d.faces[ i ];

				if ( face.materialIndex == 1 ) {

					for ( var j = 0; j < face.vertexNormals.length; j ++ ) {
						face.vertexNormals[ j ].z = 0;
						face.vertexNormals[ j ].normalize();
					}

					var va = text3d.vertices[ face.a ];
					var vb = text3d.vertices[ face.b ];
					var vc = text3d.vertices[ face.c ];

					var s = THREE.GeometryUtils.triangleArea( va, vb, vc );

					if ( s > triangleAreaHeuristics ) {
						for ( var j = 0; j < face.vertexNormals.length; j ++ ) {
							face.vertexNormals[ j ].copy( face.normal );
						}
					}
				}
			}

			var centerOffset = -THREE.FontUtils.drawText(text).offset;

			opts.width = Math.min(Math.max(0.5 * (text3d.boundingBox.max.x - text3d.boundingBox.min.x), 500), 1000);

			opts.mesh = new THREE.Mesh(text3d,  material);

			opts.mesh.position.x = centerOffset;

			for (var face in opts.mesh.geometry.faces) {
				if (opts.mesh.geometry.faces[face].normal.z != 0) {
					opts.mesh.geometry.faces[face].materialIndex = 1;
				}
			}

			this.setAxis(opts.axis);

			opts.text.canvas = opts.mesh;
		}

		return text;
	};

	this.makeMaterial = function(){
		opts.text.options.textMaterial = new THREE.MeshPhongMaterial({
			color: opts.text.options.textColor,
			shading: THREE.FlatShading,
			specular: 0x222222,
			shininess: 50,
			ambient: opts.text.options.textColor,
			overdraw: 0.4
		});
		opts.text.options.sideMaterial = new THREE.MeshPhongMaterial({
			color: opts.text.options.sideColor,
			shading: THREE.SmoothShading,
			specular: 0x222222,
			shininess: 50,
			ambient: opts.text.options.sideColor,
			overdraw: 0.4
		});
	};

	this.setAxis = function(axis) {
		if (axis == 'x') {
			opts.camera.position.set(0, 0, opts.width);

			opts.mesh.position.y = -opts.text.options.size / 2;
			opts.mesh.position.z = -opts.text.options.height / 2;
		} else if (axis == 'y') {
			opts.camera.position.set(0, opts.text.options.size / 2, opts.width);

			opts.mesh.position.y = 0;
			opts.mesh.position.z = -opts.text.options.height / 2;

		} else if (axis == 'wave') {
			opts.camera.position.set(0, opts.text.options.size / 2, opts.width);

			for (var i = 0; i < opts.mesh.children.length; i++) {
				opts.mesh.children[i].position.y = opts.text.options.size * Math.sin(opts.wavePosition + opts.waveAngle * i);
			}
		} else if (axis == 'spin') {
			opts.camera.position.set(0, opts.text.options.size / 2, opts.width);

			for (var i = 0; i < opts.mesh.children.length; i++) {
				opts.mesh.children[i].rotation.y = 0;
			}
		}
	}

	var self = this;

	this.setupCanvas = function(){

		opts.group = new THREE.Object3D();
		opts.scene.add(opts.group);

		opts.canvas = canvas;
		opts['rgb2gif'] = rgb2gif;

		opts.renderer = new THREE.CanvasRenderer({
			canvas: canvas,
			alpha: true
		});
	};

	var render = this.render = function(){
		opts.renderer.render( opts.scene, opts.camera );
	};

	this.api.serve = function(gifsicle, width, height){
		var pixels = new Buffer(width * height * 3);

		opts.mesh.rotation.x = 0;
		opts.mesh.rotation.y = 0;

		opts.wavePosition = 0;
		if (opts.axis == 'wave') {
			for (var i = 0; i < opts.mesh.children.length; i++) {
				opts.mesh.children[i].position.y = opts.text.options.size * Math.sin(opts.wavePosition + opts.waveAngle * i);
			}
		} else if (opts.axis == 'spin') {
			for (var i = 0; i < opts.mesh.children.length; i++) {
				opts.mesh.children[i].rotation.y = 0;
			}
		}

		var numFrames = opts.numFrames;
		var dAngle;

		if (opts.axis == 'x' || opts.axis == 'y' || opts.axis == 'spin') {
			dAngle = Math.PI / (numFrames + 1);
		} else if (opts.axis = 'wave') {
			dAngle = 2 * Math.PI / (numFrames + 1);
		}

		if (opts.axis == 'y') {
			opts.group.rotation.y = -Math.PI / 2;
		}

		gifsicle.setMaxListeners(numFrames + 1);

		function run_capture(frame, callback){
			var value = startValue + frame * dAngle;

			if (opts.axis == 'x') {
				opts.group.rotation.x = value;
			} else if (opts.axis == 'y') {
				opts.group.rotation.y = value;
			} else if (opts.axis == 'wave') {
				opts.wavePosition = value;

				for (var i = 0; i < opts.mesh.children.length; i++) {
					opts.mesh.children[i].position.y = opts.text.options.size * Math.sin(opts.wavePosition + opts.waveAngle * i);
				}
			} else if (opts.axis == 'spin') {
				for (var i = 0; i < opts.mesh.children.length; i++) {
					opts.mesh.children[i].rotation.y = value;
				}
			}

			render();

			var encoder = child_process.spawn(opts['rgb2gif'], ['-s', width, height], {
				stdio: ['pipe', 'pipe', process.stderr]});
			// don't close the gifsicle input stream when this gif is done
			encoder.stdout.pipe(gifsicle.stdin, { end: frame <= 0 });

			var data = opts.canvas.getContext('2d').getImageData(0, 0, width, height).data;

			var count = 0;
			for (var i = 0; i < height; i++) {
				for (var j = 0; j < width; j++) {
					var b = (i * width * 4) + j * 4;
					pixels.writeUInt8(data[b], count++, true);
					pixels.writeUInt8(data[b+1], count++, true);
					pixels.writeUInt8(data[b+2], count++, true);
				}
			}
			encoder.stdin.write(pixels);

			callback();
		}

		var startValue = 0;

		if (opts.axis == 'x') {
			startValue = opts.group.rotation.x;
		} else if (opts.axis == 'y') {
			startValue = opts.group.rotation.y;
		} else if (opts.axis == 'wave') {
			startValue = opts.wavePosition;
		} else if (opts.axis == 'spin') {
			for (var i = 0; i < opts.mesh.children.length; i++) {
				startValue = opts.mesh.children[i].rotation.y;
				break;
			}
		}

		var frames = [];

		for (var frame = 0; frame <= numFrames + 1; frame++) {
			frames.push(frame);
		}

		async.each(frames, run_capture);
	}

	this.reset = function() {
		opts.group.rotation.x = 0;
		opts.group.rotation.y = 0;
	}

	this.stop = function() {
		self.reset();
		opts.rotating = false;

		render();
	}

	// actually init
	this.setup();
	this.setupCanvas();

	this.api.setText = function(text, options){
		opts.group.remove(opts.text.canvas);
		if (text != null && text.length > 0) {
			self.drawTextInternal(text, options);
			opts.group.add(opts.text.canvas);
		}
	}
	this.api.setTextOption = function(option, value){
		self.opts.text.options[option] = value;
	}
	this.api.getTextOption = function(option){
		return self.opts.text.options[option];
	}
	this.api.getTextOptions = function(){
		return self.opts.text.options;
	}
	this.api.setColor = function(front, side, background, opaque) {
		opts.text.options.textColor = front;
		opts.text.options.sideColor = side;

		if (opaque) {
			opts.renderer.setClearColor(background, 1);
		} else {
			opts.renderer.setClearColor(0xffffff, 0);
		}
	}
	this.api.isAnimating = function() {
		return opts.rotating;
	}
	this.api.setAxis = function(axis) {
		self.reset();

		opts.axis = axis;
	}

	return self;
};

var create = function(canvas, rgb2gif) {
	return new ThreeDTexter(canvas, rgb2gif);
}

module.exports = create;<|endoftext|>


<commit_before>"use strict";

var lint = require("mocha-eslint");

lint(["model","notification","render","routes","views"], {formatter:"stylish",timeout:5000});

<commit_msg>Timeout for ESLint<commit_after>"use strict";

var lint = require("mocha-eslint");

lint(["model","notification","render","routes","views"], {formatter:"stylish",timeout:15000});

<|endoftext|>


<commit_before>(function()
{
	//Our RAG indicator styles
	freeboard.addStyle('.rag-light', "border-radius:50%;width:22px;height:22px;border:2px solid #3d3d3d;margin-top:5px;float:left;background-color:#222;margin-right:10px;");
	freeboard.addStyle('.rag-light.red', "background-color:#D90000;box-shadow: 0px 0px 15px #D90000;border-color:#FDF1DF;");
	freeboard.addStyle('.rag-light.amber', "background-color:#E49B00;box-shadow: 0px 0px 15px #E49B00;border-color:#FDF1DF;");
	freeboard.addStyle('.rag-light.green', "background-color:#00B60E;box-shadow: 0px 0px 15px #00B60E;border-color:#FDF1DF;");
	freeboard.addStyle('.rag-text', "margin-top:10px;");
    //Flashing status for the light
	freeboard.addStyle('.red-flash', "animation: red-flash 1000ms infinite;")
	freeboard.addStyle('.amber-flash', "animation: amber-flash 1000ms infinite;")
	freeboard.addStyle('.green-flash', "animation: green-flash 1000ms infinite;")
	//Dim status for the light
	freeboard.addStyle('.dim', "opacity: 0.6;");

	//Keyframes for the css flashing
	//Unless we use a library for adding keyframes to the DOM, this hack will have to suffice
	var greenRule = "@keyframes green-flash {0% {background-color: #2A2A2A; box-shadow: 0px 0px 15px #2A2A2A;} 100% {background-color: #00B60E; box-shadow: 0px 0px 15px #00B60E;}}";
	var amberRule = "@keyframes amber-flash {0% {background-color: #2A2A2A; box-shadow: 0px 0px 15px #2A2A2A;} 100% {background-color: #E49B00; box-shadow: 0px 0px 15px #E49B00;}}";
	var redRule   = "@keyframes red-flash   {0% {background-color: #2A2A2A; box-shadow: 0px 0px 15px #2A2A2A;} 100% {background-color: #D90000; box-shadow: 0px 0px 15px #D90000;}}";

	//Add them to our CSS
	var style = document.createElement('style');
    style.innerHTML = greenRule + amberRule + redRule;
    document.head.appendChild(style);

	var ragWidget = function (settings) {
        var self = this;
        var titleElement = $('

');
        var stateElement = $('

');
        var indicatorElement = $('

');
        var currentSettings = settings;

		//store our calculated values in an object
		var stateObject = {};

		//array of our values: 0=Green, 2=Amber, 3=Red
		var stateArray = ["green", "amber", "red"];

		function updateState() {
			//Remove all classes from our indicator light
			indicatorElement
				.removeClass('red')
				.removeClass('amber')
				.removeClass('green')
				.removeClass('green-flash')
				.removeClass('amber-flash')
				.removeClass('red-flash')
				.removeClass('dim')

			var ragValue = _.isUndefined(stateObject.value) ? -1 : stateObject.value;
			//If we have a valid value set, continue
			if (stateArray[stateObject.value]) {
				indicatorElement.addClass(stateArray[stateObject.value]);
				var indicatorText = stateArray[stateObject.value] + '_text';
				//Get our Indicator Type
				stateElement.html((_.isUndefined(stateObject[indicatorText]) ? "" : stateObject[indicatorText]));
				var indicatorType = (_.isUndefined(stateObject.indicator_type) ? "" : stateObject.indicator_type.toLowerCase());

				switch (indicatorType) {
					case 'dim' :
						indicatorElement.addClass('dim');
						break;
					case 'flash' :
						var indicatorTypeClass = stateArray[stateObject.value] + '-flash';
						indicatorElement.addClass(indicatorTypeClass);
						break;
					default:
						//this is normal
				}
			} else {
				stateElement.html('Error');
			}

        }

        this.render = function (element) {
            $(element).append(titleElement).append(indicatorElement).append(stateElement);
        }

        this.onSettingsChanged = function (newSettings) {
            currentSettings = newSettings;
            titleElement.html((_.isUndefined(newSettings.title) ? "" : newSettings.title));
            updateState();
        }

        this.onCalculatedValueChanged = function (settingName, newValue) {
            //whenever a calculated value changes, store them in the variable 'stateObject'
			stateObject[settingName] = newValue;
            updateState();
        }

        this.onDispose = function () {
        }

        this.getHeight = function () {
            return 1;
        }

        this.onSettingsChanged(settings);
    };

    freeboard.loadWidgetPlugin({
        type_name: "ragIndicator",
        display_name: "RAG Indicator",
        settings: [
            {
                name: "title",
                display_name: "Title",
                type: "text"
            },
            {
                name: "value",
                display_name: "Value (G=0, A=1, R=2)",
                type: "calculated"
            },
			{
                name: "green_text",
                display_name: "Green Text",
                type: "calculated"
            },
            {
                name: "amber_text",
                display_name: "Amber Text",
                type: "calculated"
            },
			{
                name: "red_text",
                display_name: "Red Text",
                type: "calculated"
            },
			{
                name: "indicator_type",
                display_name: "Type (Normal, Dim, Flash)",
                type: "calculated"
            }

        ],
        newInstance: function (settings, newInstanceCallback) {
            newInstanceCallback(new ragWidget(settings));
        }
    });
}());
<commit_msg>Update widget.ragIndicator.js<commit_after>(function()
{
	//Our RAG indicator styles
	freeboard.addStyle('.rag-light', "border-radius:50%;width:22px;height:22px;border:2px solid #3d3d3d;margin-top:5px;float:left;background-color:#222;margin-right:10px;");
	freeboard.addStyle('.rag-light.red', "background-color:#D90000;box-shadow: 0px 0px 15px #D90000;border-color:#FDF1DF;");
	freeboard.addStyle('.rag-light.amber', "background-color:#E49B00;box-shadow: 0px 0px 15px #E49B00;border-color:#FDF1DF;");
	freeboard.addStyle('.rag-light.green', "background-color:#00B60E;box-shadow: 0px 0px 15px #00B60E;border-color:#FDF1DF;");
	freeboard.addStyle('.rag-text', "margin-top:10px;");
    //Flashing status for the light
	freeboard.addStyle('.red-flash', "animation: red-flash 500ms infinite alternate;")
	freeboard.addStyle('.amber-flash', "animation: amber-flash 500ms infinite alternate;")
	freeboard.addStyle('.green-flash', "animation: green-flash 500ms infinite alternate;")
	//Dim status for the light
	freeboard.addStyle('.dim', "opacity: 0.6;");

	var ragWidget = function (settings) {
        var self = this;
        var titleElement = $('

');
        var stateElement = $('

');
        var indicatorElement = $('

');
        var currentSettings = settings;

		//define our keyframes for our flashing lights
		$.keyframe.define([{
			name: 'green-flash',
			'0%': {'background-color': '#2A2A2A', 'box-shadow': '0px 0px 0px #2A2A2A'},
			'100%': {'background-color': '#00B60E', 'box-shadow': '0px 0px 15px #00B60E'}

		}]);
		$.keyframe.define([{
			name: 'amber-flash',
			'0%': {'background-color': '#2A2A2A', 'box-shadow': '0px 0px 0px #2A2A2A'},
			'100%': {'background-color': '#E49B00', 'box-shadow': '0px 0px 15px #E49B00'}

		}]);
		$.keyframe.define([{
			name: 'red-flash',
			'0%': {'background-color': '#2A2A2A', 'box-shadow': '0px 0px 0px #2A2A2A'},
			'100%': {'background-color': '#D90000', 'box-shadow': '0px 0px 15px #D90000'}

		}]);

		//store our calculated values in an object
		var stateObject = {};

		//array of our values: 0=Green, 2=Amber, 3=Red
		var stateArray = ["green", "amber", "red"];

		function updateState() {

			//Remove all classes from our indicator light
			indicatorElement
				.removeClass('red')
				.removeClass('amber')
				.removeClass('green')
				.removeClass('green-flash')
				.removeClass('amber-flash')
				.removeClass('red-flash')
				.removeClass('dim')

			var ragValue = _.isUndefined(stateObject.value) ? -1 : stateObject.value;
			//If we have a valid value set, continue
			if (stateArray[stateObject.value]) {
				indicatorElement.addClass(stateArray[stateObject.value]);
				var indicatorText = stateArray[stateObject.value] + '_text';
				//Get our Indicator Type
				stateElement.html((_.isUndefined(stateObject[indicatorText]) ? "" : stateObject[indicatorText]));
				var indicatorType = (_.isUndefined(stateObject.indicator_type) ? "" : stateObject.indicator_type.toLowerCase());

				switch (indicatorType) {
					case 'dim' :
						indicatorElement.addClass('dim');
						break;
					case 'flash' :
						var indicatorTypeClass = stateArray[stateObject.value] + '-flash';
						indicatorElement.addClass(indicatorTypeClass);
						break;
					default:
						//this is normal
				}
			} else {
				//stateElement.html('Error');
			}

        }

        this.render = function (element) {
            $(element).append(titleElement).append(indicatorElement).append(stateElement);
        }

        this.onSettingsChanged = function (newSettings) {
            currentSettings = newSettings;
            titleElement.html((_.isUndefined(newSettings.title) ? "" : newSettings.title));
            updateState();
        }

        this.onCalculatedValueChanged = function (settingName, newValue) {
            //whenever a calculated value changes, store them in the variable 'stateObject'
			stateObject[settingName] = newValue;
            updateState();
        }

        this.onDispose = function () {
        }

        this.getHeight = function () {
            return 1;
        }

        this.onSettingsChanged(settings);
    };

    freeboard.loadWidgetPlugin({
        type_name: "ragIndicator",
        display_name: "RAG Indicator",
		external_scripts: [
			"plugins/thirdparty/jquery.keyframes.min.js"
		],
        settings: [
            {
                name: "title",
                display_name: "Title",
                type: "text"
            },
            {
                name: "value",
                display_name: "Value (G=0, A=1, R=2)",
                type: "calculated"
            },
			{
                name: "green_text",
                display_name: "Green Text",
                type: "calculated"
            },
            {
                name: "amber_text",
                display_name: "Amber Text",
                type: "calculated"
            },
			{
                name: "red_text",
                display_name: "Red Text",
                type: "calculated"
            },
			{
                name: "indicator_type",
                display_name: "Type (Normal, Dim, Flash)",
                type: "calculated"
            }

        ],
        newInstance: function (settings, newInstanceCallback) {
            newInstanceCallback(new ragWidget(settings));
        }
    });
}());
<|endoftext|>


<commit_before>const fs = require('fs');
const path = require('path');
const {promisify} = require('util');
const schedule = require('node-schedule');
const {sortBy} = require('lodash');
const moment = require('moment');
const {unlock} = require('../achievements');

class Counter {
    constructor(name) {
        this.name = name;
        this.map = new Map();
        this.load();
    }

    add(key, cnt = 1) {
        if (this.map.has(key)) {
            this.map.set(key, this.map.get(key) + cnt);
        } else {
            this.map.set(key, cnt);
        }

        this.save();
    }

    clear() {
        this.map = new Map();
        this.save();
    }

    entries() {
        const keys = Array.from(this.map.keys());
        const sortedKeys = sortBy(keys, (key) => this.map.get(key)).reverse();
        return sortedKeys.map((key) => [key, this.map.get(key)]);
    }

    async save() {
        const filePath = path.join(__dirname, `${this.name}.json`);
        await promisify(fs.writeFile)(filePath, JSON.stringify(Array.from(this.map.entries())));
    }

    async load() {
        const filePath = path.join(__dirname, `${this.name}.json`);

        const exists = await new Promise((resolve) => {
            fs.access(filePath, fs.constants.F_OK, (error) => {
                resolve(!Boolean(error));
            });
        });

        if (exists) {
            const data = await promisify(fs.readFile)(filePath);
            this.map = new Map(JSON.parse(data));
        } else {
            this.map = new Map();
        }
    }
}

function count(haystack, needle) {
    return haystack.split(needle).length - 1;
}

function numToEmoji(num) {
    switch(num) {
        case 0:
            return 'zero';
        case 1:
            return 'one';
        case 2:
            return 'two';
        case 3:
            return 'three';
        case 4:
            return 'four';
        case 5:
            return 'five';
        case 6:
            return 'six';
        case 7:
            return 'seven';
        case 8:
            return 'eight';
        case 9:
            return 'nine';
        case 10:
            return 'keycap_ten';
        default:
            return 'vsonline';
    }
}

module.exports = (clients) => {
    const { rtmClient: rtm, webClient: slack } = clients;

    const sushiCounter = new Counter('sushi');
    const suspendCounter = new Counter('suspend');

    rtm.on('message', async (message) => {
        const { channel, text, user, ts: timestamp } = message;
        if (!text) {
            return;
        }

        let rtext = text;
        rtext = rtext.
            replace(/鮨/g, 'すし').
            replace(/(su|zu|ス|ズ|ず|寿|壽)/gi, 'す').
            replace(/(sh?i|ci|し|シ|司|\u{0328})/giu, 'し');

        rtext = rtext.
            replace(/(ca|(ke|け|ケ)(i|ぃ|い|ｨ|ィ|ｲ|イ|e|ぇ|え|ｪ|ェ|ｴ|エ|-|ー))(ki|ke|き|キ)/gi, 'ケーキ');

        rtext = rtext.
            replace(/akouryyy/gi, 'akkoury').
            replace(/akouryy/gi, '').
            replace(/kk/gi, 'k').
            replace(/rr/gi, 'r').
            replace(/y/gi, 'yy');

        if (count(rtext, 'すし')) {
            const cnt = count(rtext, 'すし');
            await slack.reactions.add({name: 'sushi', channel, timestamp});
            if (channel.startsWith('C')) {
                unlock(user, 'get-sushi');
                if (moment().utcOffset(9).day() === 3) {
                    unlock(user, 'wednesday-sushi');
                }
            }
            if(cnt >= 2) {
                if (channel.startsWith('C')) {
                    unlock(user, 'get-multiple-sushi');
                    if (cnt > 10) {
                        unlock(user, 'get-infinite-sushi');
                    }
                }
                await slack.reactions.add({name: 'x', channel, timestamp});
                await slack.reactions.add({name: numToEmoji(cnt), channel, timestamp});
            }
            sushiCounter.add(user, cnt);
        }
        if (rtext.includes("ケーキ")) {
            slack.reactions.add({name: 'cake', channel, timestamp});
        }
        if (rtext.includes("殺") || rtext.includes("死")|| rtext.includes(":korosuzo:")) {
            const cnt = count(rtext, '殺') + count(rtext, '死') + count(rtext, ':korosuzo:');
            if (channel.startsWith('C')) {
                unlock(user, 'freezing');
            }
            await slack.reactions.add({name: 'no_good', channel, timestamp});
            await slack.reactions.add({name: 'cookies146', channel, timestamp});
            if(cnt >= 2) {
                await slack.reactions.add({name: 'x', channel, timestamp});
                await slack.reactions.add({name: numToEmoji(cnt), channel, timestamp});
            }
            suspendCounter.add(user, cnt);
        }
        if (rtext.includes("akouryy")) {
            slack.reactions.add({name: 'no_good', channel, timestamp});
            slack.reactions.add({name: 'akouryy', channel, timestamp});
        }

        const stars = ["欲し", "干し", "ほし", "星", "★", "☆"];
        for(const star of stars) {
            if (text.includes(star)) {
                slack.reactions.add({name: 'grapes', channel, timestamp});
                break;
            }
        }
    });

    schedule.scheduleJob('0 19 * * 0', async () => {
        const {members} = await slack.users.list();

        await slack.chat.postMessage({
            channel: process.env.CHANNEL_SANDBOX,
            username: 'sushi-bot',
            text: '今週の凍結ランキング',
            icon_emoji: ':cookies146:',
            attachments: suspendCounter.entries().map(([user, count], index) => {
                const member = members.find(({id}) => id === user);
                if (!member) {
                    return null;
                }
                const name = member.profile.display_name || member.name;
                if (index === 0) {
                    unlock(user, 'freezing-master');
                }

                return {
                    author_name: `${index + 1}位: ${name} (${count}回)`,
                    author_icon: member.profile.image_24,
                };
            }).filter((attachment) => attachment !== null),
        });

        suspendCounter.clear();

        await slack.chat.postMessage({
            channel: process.env.CHANNEL_SANDBOX,
            username: 'sushi-bot',
            text: '今週の寿司ランキング',
            icon_emoji: ':sushi:',
            attachments: sushiCounter.entries().map(([user, count], index) => {
                const member = members.find(({id}) => id === user);
                if (!member) {
                    return null;
                }
                const name = member.profile.display_name || member.name;

                return {
                    author_name: `${index + 1}位: ${name} (${count}回)`,
                    author_icon: member.profile.image_24,
                };
            }).filter((attachment) => attachment !== null),
        });

        sushiCounter.clear();
    });
};<commit_msg>Update index.js<commit_after>const fs = require('fs');
const path = require('path');
const {promisify} = require('util');
const schedule = require('node-schedule');
const {sortBy} = require('lodash');
const moment = require('moment');
const {unlock} = require('../achievements');

class Counter {
    constructor(name) {
        this.name = name;
        this.map = new Map();
        this.load();
    }

    add(key, cnt = 1) {
        if (this.map.has(key)) {
            this.map.set(key, this.map.get(key) + cnt);
        } else {
            this.map.set(key, cnt);
        }

        this.save();
    }

    clear() {
        this.map = new Map();
        this.save();
    }

    entries() {
        const keys = Array.from(this.map.keys());
        const sortedKeys = sortBy(keys, (key) => this.map.get(key)).reverse();
        return sortedKeys.map((key) => [key, this.map.get(key)]);
    }

    async save() {
        const filePath = path.join(__dirname, `${this.name}.json`);
        await promisify(fs.writeFile)(filePath, JSON.stringify(Array.from(this.map.entries())));
    }

    async load() {
        const filePath = path.join(__dirname, `${this.name}.json`);

        const exists = await new Promise((resolve) => {
            fs.access(filePath, fs.constants.F_OK, (error) => {
                resolve(!Boolean(error));
            });
        });

        if (exists) {
            const data = await promisify(fs.readFile)(filePath);
            this.map = new Map(JSON.parse(data));
        } else {
            this.map = new Map();
        }
    }
}

function count(haystack, needle) {
    return haystack.split(needle).length - 1;
}

function numToEmoji(num) {
    switch(num) {
        case 0:
            return 'zero';
        case 1:
            return 'one';
        case 2:
            return 'two';
        case 3:
            return 'three';
        case 4:
            return 'four';
        case 5:
            return 'five';
        case 6:
            return 'six';
        case 7:
            return 'seven';
        case 8:
            return 'eight';
        case 9:
            return 'nine';
        case 10:
            return 'keycap_ten';
        default:
            return 'vsonline';
    }
}

module.exports = (clients) => {
    const { rtmClient: rtm, webClient: slack } = clients;

    const sushiCounter = new Counter('sushi');
    const suspendCounter = new Counter('suspend');

    rtm.on('message', async (message) => {
        const { channel, text, user, ts: timestamp } = message;
        if (!text) {
            return;
        }

        let rtext = text;
        rtext = rtext.
            replace(/鮨/g, 'すし').
            replace(/(su|zu|ス|ズ|ず|寿|壽)/gi, 'す').
            replace(/(sh?i|ci|し|シ|司|\u{0328})/giu, 'し');

        rtext = rtext.
            replace(/(ca|(ke|け|ケ)(i|ぃ|い|ｨ|ィ|ｲ|イ|e|ぇ|え|ｪ|ェ|ｴ|エ|-|ー))(ki|ke|き|キ)/gi, 'ケーキ');

        rtext = rtext.
            replace(/akouryyy/gi, 'akkoury').
            replace(/akouryy/gi, '').
            replace(/kk/gi, 'k').
            replace(/rr/gi, 'r').
            replace(/y/gi, 'yy');

        if (count(rtext, 'すし')) {
            const cnt = count(rtext, 'すし');
            await slack.reactions.add({name: 'sushi', channel, timestamp});
            if (channel.startsWith('C')) {
                unlock(user, 'get-sushi');
                if (moment().utcOffset(9).day() === 3) {
                    unlock(user, 'wednesday-sushi');
                }
            }
            if(cnt >= 2) {
                if (channel.startsWith('C')) {
                    unlock(user, 'get-multiple-sushi');
                    if (cnt > 10) {
                        unlock(user, 'get-infinite-sushi');
                    }
                }
                await slack.reactions.add({name: 'x', channel, timestamp});
                await slack.reactions.add({name: numToEmoji(cnt), channel, timestamp});
            }
            sushiCounter.add(user, cnt);
        }
        if (rtext.includes("ケーキ")) {
            slack.reactions.add({name: 'cake', channel, timestamp});
        }
        if (rtext.includes("殺") || rtext.includes("死")|| rtext.includes(":koroすzo:")) {
            const cnt = count(rtext, '殺') + count(rtext, '死') + count(rtext, ':koroすzo:');
            if (channel.startsWith('C')) {
                unlock(user, 'freezing');
            }
            await slack.reactions.add({name: 'no_good', channel, timestamp});
            await slack.reactions.add({name: 'cookies146', channel, timestamp});
            if(cnt >= 2) {
                await slack.reactions.add({name: 'x', channel, timestamp});
                await slack.reactions.add({name: numToEmoji(cnt), channel, timestamp});
            }
            suspendCounter.add(user, cnt);
        }
        if (rtext.includes("akouryy")) {
            slack.reactions.add({name: 'no_good', channel, timestamp});
            slack.reactions.add({name: 'akouryy', channel, timestamp});
        }

        const stars = ["欲し", "干し", "ほし", "星", "★", "☆"];
        for(const star of stars) {
            if (text.includes(star)) {
                slack.reactions.add({name: 'grapes', channel, timestamp});
                break;
            }
        }
    });

    schedule.scheduleJob('0 19 * * 0', async () => {
        const {members} = await slack.users.list();

        await slack.chat.postMessage({
            channel: process.env.CHANNEL_SANDBOX,
            username: 'sushi-bot',
            text: '今週の凍結ランキング',
            icon_emoji: ':cookies146:',
            attachments: suspendCounter.entries().map(([user, count], index) => {
                const member = members.find(({id}) => id === user);
                if (!member) {
                    return null;
                }
                const name = member.profile.display_name || member.name;
                if (index === 0) {
                    unlock(user, 'freezing-master');
                }

                return {
                    author_name: `${index + 1}位: ${name} (${count}回)`,
                    author_icon: member.profile.image_24,
                };
            }).filter((attachment) => attachment !== null),
        });

        suspendCounter.clear();

        await slack.chat.postMessage({
            channel: process.env.CHANNEL_SANDBOX,
            username: 'sushi-bot',
            text: '今週の寿司ランキング',
            icon_emoji: ':sushi:',
            attachments: sushiCounter.entries().map(([user, count], index) => {
                const member = members.find(({id}) => id === user);
                if (!member) {
                    return null;
                }
                const name = member.profile.display_name || member.name;

                return {
                    author_name: `${index + 1}位: ${name} (${count}回)`,
                    author_icon: member.profile.image_24,
                };
            }).filter((attachment) => attachment !== null),
        });

        sushiCounter.clear();
    });
};<|endoftext|>


<commit_before>/**
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership.  The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 'License'); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */

var Q = require('q');
var shell = require('shelljs');
var superspawn = require('cordova-common').superspawn;
var events = require('cordova-common').events;
var depls = require('dependency-ls');
var path = require('path');
var fs = require('fs');
var CordovaError = require('cordova-common').CordovaError;
var isUrl = require('is-url');

/*
 * A function that npm installs a module from npm or a git url
 *
 * @param {String} target   the packageID or git url
 * @param {String} dest     destination of where to install the module
 * @param {Object} opts     [opts={save:true}] options to pass to fetch module
 *
 * @return {String|Promise}    Returns string of the absolute path to the installed module.
 *
 */
module.exports = function(target, dest, opts) {
    var fetchArgs = opts.link ? ['link'] : ['install'];
    opts = opts || {};
    var tree1;

    //check if npm is installed
    return isNpmInstalled()
    .then(function() {
        if(dest && target) {
            //add target to fetchArgs Array
            fetchArgs.push(target);

            //append node_modules to dest if it doesn't come included
            if (path.basename(dest) !== 'node_modules') {
                dest = path.resolve(path.join(dest, 'node_modules'));
            }
            //create dest if it doesn't exist
            if(!fs.existsSync(dest)) {
                shell.mkdir('-p', dest);
            }
        } else return Q.reject(new CordovaError('Need to supply a target and destination'));

        //set the directory where npm install will be run
        opts.cwd = dest;

        //if user added --save flag, pass it to npm install command
        if(opts.save) {
            events.emit('verbose', 'saving');
            fetchArgs.push('--save');
        }

        //Grab json object of installed modules before npm install
        return depls(dest);
    })
    .then(function(depTree) {
        tree1 = depTree;

        //install new module
        return superspawn.spawn('npm', fetchArgs, opts);
    })
    .then(function(output) {
        //Grab object of installed modules after npm install
        return depls(dest);
    })
    .then(function(depTree2) {
        var tree2 = depTree2;

        //getJsonDiff will fail if the module already exists in node_modules.
        //Need to use trimID in that case.
        //This could happen on a platform update.
        var id = getJsonDiff(tree1, tree2) || trimID(target);

        return getPath(id, dest);
    })
    .fail(function(err){
        return Q.reject(new CordovaError(err));
    });
};

/*
 * Takes two JSON objects and returns the key of the new property as a string.
 * If a module already exists in node_modules, the diff will be blank.
 * cordova-fetch will use trimID in that case.
 *
 * @param {Object} obj1     json object representing installed modules before latest npm install
 * @param {Object} obj2     json object representing installed modules after latest npm install
 *
 * @return {String}         String containing the key value of the difference between the two objects
 *
 */
function getJsonDiff(obj1, obj2) {
    var result = '';

    //regex to filter out peer dependency warnings from result
    var re = /UNMET PEER DEPENDENCY/;

    for (var key in obj2) {
        //if it isn't a unmet peer dependency, continue
        if (key.search(re) === -1) {
            if(obj2[key] != obj1[key]) result = key;
        }
    }
    return result;
}

/*
 * Takes the specified target and returns the moduleID
 * If the git repoName is different than moduleID, then the
 * output from this function will be incorrect. This is the
 * backup way to get ID. getJsonDiff is the preferred way to
 * get the moduleID of the installed module.
 *
 * @param {String} target    target that was passed into cordova-fetch.
 *                           can be moduleID, moduleID@version or gitURL
 *
 * @return {String} ID       moduleID without version.
 */
function trimID(target) {
    var parts;
    //If GITURL, set target to repo name
    if (isUrl(target)) {
        //strip away .git and everything that follows
        var strippedTarget = target.split('.git');
        var re = /.*\/(.*)/;
        //Grabs everything in url after last `/`
        parts = strippedTarget[0].match(re);

        target = parts[1];
    }

    //If local path exists, set target to final directory
    if (fs.existsSync(target)) {
        target = path.basename(target);
    }

    //strip away everything after '@'
    //also support scoped packages
    if(target.indexOf('@') != -1) {
        parts = target.split('@');
        if (parts.length > 1 && parts[0] === '') {
            //scoped package
            target = '@' + parts[1];
        } else {
            target = parts[0];
        }
    }

    return target;
}

/*
 * Takes the moduleID and destination and returns an absolute path to the module
 *
 * @param {String} id       the packageID
 * @param {String} dest     destination of where to fetch the modules
 *
 * @return {String|Error}  Returns the absolute url for the module or throws a error
 *
 */

function getPath(id, dest) {
    var finalDest = path.resolve(path.join(dest, id));

    //Sanity check it exists
    if(fs.existsSync(finalDest)){
        return finalDest;
    } else return Q.reject(new CordovaError('Failed to get absolute path to installed module'));
}

/*
 * Checks to see if npm is installed on the users system
 * @return {Promise|Error} Returns true or a cordova error.
 */

function isNpmInstalled() {
    if(!shell.which('npm')) {
        return Q.reject(new CordovaError('"npm" command line tool is not installed: make sure it is accessible on your PATH.'));
    }
    return Q();
}

/*
 * A function that deletes the target from node_modules and runs npm uninstall
 *
 * @param {String} target   the packageID
 * @param {String} dest     destination of where to uninstall the module from
 * @param {Object} opts     [opts={save:true}] options to pass to npm uninstall
 *
 * @return {Promise|Error}    Returns a promise with the npm uninstall output or an error.
 *
 */
module.exports.uninstall = function(target, dest, opts) {
    var fetchArgs = ['uninstall'];
    opts = opts || {};

    //check if npm is installed on the system
    return isNpmInstalled()
    .then(function() {
        if(dest && target) {
            //add target to fetchArgs Array
            fetchArgs.push(target);
        } else return Q.reject(new CordovaError('Need to supply a target and destination'));

        //set the directory where npm uninstall will be run
        opts.cwd = dest;

        //if user added --save flag, pass it to npm uninstall command
        if(opts.save) {
            fetchArgs.push('--save');
        }

        //run npm uninstall, this will remove dependency
        //from package.json if --save was used.
        return superspawn.spawn('npm', fetchArgs, opts);
    })
    .then(function(res) {
        var pluginDest = path.join(dest, 'node_modules', target);
        if(fs.existsSync(pluginDest)) {
            shell.rm('-rf', pluginDest);
        }
        return res;
    })
    .fail(function(err) {
        return Q.reject(new CordovaError(err));
    });
};
<commit_msg>CB-12786: Improve logic for searching plugin id in case of module already exists in node_modules<commit_after>/**
 Licensed to the Apache Software Foundation (ASF) under one
 or more contributor license agreements.  See the NOTICE file
 distributed with this work for additional information
 regarding copyright ownership.  The ASF licenses this file
 to you under the Apache License, Version 2.0 (the
 'License'); you may not use this file except in compliance
 with the License.  You may obtain a copy of the License at

 http://www.apache.org/licenses/LICENSE-2.0

 Unless required by applicable law or agreed to in writing,
 software distributed under the License is distributed on an
 'AS IS' BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 KIND, either express or implied.  See the License for the
 specific language governing permissions and limitations
 under the License.
 */

var Q = require('q');
var shell = require('shelljs');
var superspawn = require('cordova-common').superspawn;
var events = require('cordova-common').events;
var depls = require('dependency-ls');
var path = require('path');
var fs = require('fs');
var CordovaError = require('cordova-common').CordovaError;
var isUrl = require('is-url');

/*
 * A function that npm installs a module from npm or a git url
 *
 * @param {String} target   the packageID or git url
 * @param {String} dest     destination of where to install the module
 * @param {Object} opts     [opts={save:true}] options to pass to fetch module
 *
 * @return {String|Promise}    Returns string of the absolute path to the installed module.
 *
 */
module.exports = function(target, dest, opts) {
    var fetchArgs = opts.link ? ['link'] : ['install'];
    opts = opts || {};
    var tree1;

    //check if npm is installed
    return isNpmInstalled()
    .then(function() {
        if(dest && target) {
            //add target to fetchArgs Array
            fetchArgs.push(target);

            //append node_modules to dest if it doesn't come included
            if (path.basename(dest) !== 'node_modules') {
                dest = path.resolve(path.join(dest, 'node_modules'));
            }
            //create dest if it doesn't exist
            if(!fs.existsSync(dest)) {
                shell.mkdir('-p', dest);
            }
        } else return Q.reject(new CordovaError('Need to supply a target and destination'));

        //set the directory where npm install will be run
        opts.cwd = dest;

        //if user added --save flag, pass it to npm install command
        if(opts.save) {
            events.emit('verbose', 'saving');
            fetchArgs.push('--save');
        }

        //Grab json object of installed modules before npm install
        return depls(dest);
    })
    .then(function(depTree) {
        tree1 = depTree;

        //install new module
        return superspawn.spawn('npm', fetchArgs, opts);
    })
    .then(function(output) {
        //Grab object of installed modules after npm install
        return depls(dest);
    })
    .then(function(depTree2) {
        var tree2 = depTree2;

        //getJsonDiff will fail if the module already exists in node_modules.
        //Need to use trimID in that case.
        //This could happen on a platform update.
        var id = getJsonDiff(tree1, tree2) || trimID(target);

        return getPath(id, dest);
    })
    .fail(function(err){
        return Q.reject(new CordovaError(err));
    });
};

/*
 * Takes two JSON objects and returns the key of the new property as a string.
 * If a module already exists in node_modules, the diff will be blank.
 * cordova-fetch will use trimID in that case.
 *
 * @param {Object} obj1     json object representing installed modules before latest npm install
 * @param {Object} obj2     json object representing installed modules after latest npm install
 *
 * @return {String}         String containing the key value of the difference between the two objects
 *
 */
function getJsonDiff(obj1, obj2) {
    var result = '';

    //regex to filter out peer dependency warnings from result
    var re = /UNMET PEER DEPENDENCY/;

    for (var key in obj2) {
        //if it isn't a unmet peer dependency, continue
        if (key.search(re) === -1) {
            if(obj2[key] != obj1[key]) result = key;
        }
    }
    return result;
}

/*
 * Takes the specified target and returns the moduleID
 * If the git repoName is different than moduleID, then the
 * output from this function will be incorrect. This is the
 * backup way to get ID. getJsonDiff is the preferred way to
 * get the moduleID of the installed module.
 *
 * @param {String} target    target that was passed into cordova-fetch.
 *                           can be moduleID, moduleID@version or gitURL
 *
 * @return {String} ID       moduleID without version.
 */
function trimID(target) {
    var parts;
    //If GITURL, set target to repo name
    if (isUrl(target)) {
        //strip away .git and everything that follows
        var strippedTarget = target.split('.git');
        var re = /.*\/(.*)/;
        //Grabs everything in url after last `/`
        parts = strippedTarget[0].match(re);

        target = parts[1];
    }

    // If local path exists, try to get plugin id from package.json or set target to final directory
    if (fs.existsSync(target)) {
        var pluginId, pkgJsonPath = path.join(target, 'package.json');

        if (fs.existsSync(pkgJsonPath)) {
            pluginId = JSON.parse(fs.readFileSync(pkgJsonPath)).name;
        }

        target = pluginId ? pluginId : path.basename(target);
    }

    //strip away everything after '@'
    //also support scoped packages
    if(target.indexOf('@') != -1) {
        parts = target.split('@');
        if (parts.length > 1 && parts[0] === '') {
            //scoped package
            target = '@' + parts[1];
        } else {
            target = parts[0];
        }
    }

    return target;
}

/*
 * Takes the moduleID and destination and returns an absolute path to the module
 *
 * @param {String} id       the packageID
 * @param {String} dest     destination of where to fetch the modules
 *
 * @return {String|Error}  Returns the absolute url for the module or throws a error
 *
 */

function getPath(id, dest) {
    var finalDest = path.resolve(path.join(dest, id));

    //Sanity check it exists
    if(fs.existsSync(finalDest)){
        return finalDest;
    } else return Q.reject(new CordovaError('Failed to get absolute path to installed module'));
}

/*
 * Checks to see if npm is installed on the users system
 * @return {Promise|Error} Returns true or a cordova error.
 */

function isNpmInstalled() {
    if(!shell.which('npm')) {
        return Q.reject(new CordovaError('"npm" command line tool is not installed: make sure it is accessible on your PATH.'));
    }
    return Q();
}

/*
 * A function that deletes the target from node_modules and runs npm uninstall
 *
 * @param {String} target   the packageID
 * @param {String} dest     destination of where to uninstall the module from
 * @param {Object} opts     [opts={save:true}] options to pass to npm uninstall
 *
 * @return {Promise|Error}    Returns a promise with the npm uninstall output or an error.
 *
 */
module.exports.uninstall = function(target, dest, opts) {
    var fetchArgs = ['uninstall'];
    opts = opts || {};

    //check if npm is installed on the system
    return isNpmInstalled()
    .then(function() {
        if(dest && target) {
            //add target to fetchArgs Array
            fetchArgs.push(target);
        } else return Q.reject(new CordovaError('Need to supply a target and destination'));

        //set the directory where npm uninstall will be run
        opts.cwd = dest;

        //if user added --save flag, pass it to npm uninstall command
        if(opts.save) {
            fetchArgs.push('--save');
        }

        //run npm uninstall, this will remove dependency
        //from package.json if --save was used.
        return superspawn.spawn('npm', fetchArgs, opts);
    })
    .then(function(res) {
        var pluginDest = path.join(dest, 'node_modules', target);
        if(fs.existsSync(pluginDest)) {
            shell.rm('-rf', pluginDest);
        }
        return res;
    })
    .fail(function(err) {
        return Q.reject(new CordovaError(err));
    });
};
<|endoftext|>


<commit_before>const mongoose = require('mongoose');
const MODULES_PATH = './../modules/';
const MODEL_PATH = 'users/';
const MODEL = 'user_model';
const Model = require(MODULES_PATH + MODEL_PATH + MODEL);

const Returns = [
  {'save': Object}
, {'insert': Object}
, {'create': Object}
, {'update': Object}
, {'remove': Object}
];

function testReturn(action, data) {
  console.log('action', action, data)
};

// Create: save
// Verifica se veio como Object
// Roda o teste primitivo para Object
// Deve retornar o mesmo objeto do Schema acrescido de:
// _id
// __v
// Verificar cada valor persistido

// var saveReturn = { __v: 0,
//   _id: "",
//   created_at: "",
//   category: '""',
//   price: "",
//   alcohol: "",
//   description: "",
//   name: "" }

// Retrieve: find
// armazena o count() da coleção
// Verifica se veio como Array
// Roda o teste primitivo para Array
// Verifica a quantidade de registros retornados

// Update: update
// retorna um INTEIRO de quantos objetos foram atualizados
// se retorno === 0 então não atualizou nada

<commit_msg>Validador do delete do mongoose - ideia<commit_after>const mongoose = require('mongoose');
const MODULES_PATH = './../modules/';
const MODEL_PATH = 'users/';
const MODEL = 'user_model';
const Model = require(MODULES_PATH + MODEL_PATH + MODEL);

const Returns = [
  {'save': Object}
, {'insert': Object}
, {'create': Object}
, {'update': Object}
, {'remove': Object}
];

function testReturn(action, data) {
  console.log('action', action, data)
};

// Create: save
// Verifica se veio como Object
// Roda o teste primitivo para Object
// Deve retornar o mesmo objeto do Schema acrescido de:
// _id
// __v
// Verificar cada valor persistido

// var saveReturn = { __v: 0,
//   _id: "",
//   created_at: "",
//   category: '""',
//   price: "",
//   alcohol: "",
//   description: "",
//   name: "" }

// Retrieve: find
// armazena o count() da coleção
// Verifica se veio como Array
// Roda o teste primitivo para Array
// Verifica a quantidade de registros retornados

// Update: update
// retorna um INTEIRO de quantos objetos foram atualizados
// se retorno === 0 então não atualizou nada

// Delete: remove
// retorna um INTEIRO de quantos objetos foram removidos
// se retorno === 0 então não removeu nada

<|endoftext|>


<commit_before>/**
 * Created by Freddy Snijder on 15/05/14.
 */

(function() {
    var NS      = null;
    var DataMap = null;

    var __isNode = (typeof module !== 'undefined' && typeof module.exports !== 'undefined');
    if (__isNode) {
        require("./../extensions/string.ext.js");

        DataMap = require("../data-structures/data-map.js").DataMap;

        NS = exports;
    } else {
        //Add to Visionscapers namespace
        NS = window["__VI__"] || window;

        DataMap = NS.DataMap;
    }

    //using underscore.js _ as base object
    //changing and augmenting it where we want to

    NS.UtilsBase = {};
    NS.UtilsBase.addTo = function (utils, log) {

        if (typeof(log) != "object") {
            console.warn("UtilsBase : no logging object provided, using browser console logger");
            log = console;
        }

        if ((typeof(utils) != "object") && (typeof(utils) != "function")) {
            log.error("UtilsBase", "no valid utils object given, unable to extend");
            return;
        }

        //Using these functions (in the particular way as used below) to ensure that Webstorm (or other IDE) can find
        // the method definition, while still providing feedback when a method already exists

        var _mustNOTexist = function (name) {
            if ((utils[name] !== null) && (utils[name] !== undefined)) {
                log.warn("UtilsBase", "property or method {0} already exists, not overwriting".fmt(name));
            }
        };
        var _mustExist = function (name) {
            if ((utils[name] === null) || (utils[name] === undefined)) {
                log.error("UtilsBase", "property or method {0} does not exists, will not be available".fmt(name));
            }
        };

        _mustNOTexist("_mustNOTexist");
        utils._mustNOTexist = utils._mustNOTexist || _mustNOTexist;

        _mustNOTexist("_mustExist");
        utils._mustExist = utils._mustExist || _mustExist;

        /**************************************************
         *
         * Register utils component
         *
         **************************************************/

        //Different util components are registered here
        //This allows us to check in a simple way if certain functionality is available
        _mustNOTexist("_utilsComponents");
        utils._utilsComponents = utils._utilsComponents || {
            base: true
        };

        /**************************************************
         *
         * END Register utils component
         *
         **************************************************/

        _mustNOTexist("def");
        utils.def = utils.def || function (v) {
            return ((v !== null) && (v !== undefined));
        };

        _mustNOTexist("obj");
        _mustExist("isObject");
        utils.obj = utils.obj || utils.isObject;

        _mustNOTexist("bool");
        _mustExist("isBoolean");
        utils.bool = utils.bool || utils.isBoolean;

        _mustNOTexist("number");
        _mustExist("isNumber");
        utils.number = utils.number || utils.isNumber;

        _mustNOTexist("string");
        _mustExist("isString");
        utils.string = utils.string || utils.isString;

        _mustNOTexist("array");
        _mustExist("isArray");
        utils.array = utils.array || utils.isArray;

        _mustNOTexist("func");
        _mustExist("isFunction");
        utils.func = utils.func || utils.isFunction;

        _mustNOTexist("date");
        _mustExist("isDate");
        utils.date = utils.date || utils.isDate;

        _mustNOTexist("empty");
        _mustExist("isEmpty");
        utils.empty = utils.empty || utils.isEmpty;

        _mustNOTexist("class");
        utils.class = utils.class || function (C) {
            return utils.func(C) && (C === C.prototype.constructor);
        };

        _mustNOTexist("equals");
        /**
         *
         * Returns true if v1 and v2 are equal else false.
         *
         * For objects the values of its own properties are compared using ===.
         * For arrays the item values are compared using ===.
         *
         * This function can also compare DataMap structures
         *
         * So for both objects and arrays the equality assessment is only done one level deep.
         *
         * @returns {boolean}
         *
         */
        utils.equals = utils.equals || function (v1, v2) {
            var isDef   = utils.def(v1);
            var isDef2  = utils.def(v2);

            if (!isDef && !isDef2) {
                return true;
            }

            var valType     = (typeof v1);
            var isArray     = utils.array(v1);
            var isDataMap   = v1 instanceof DataMap;
            var isEqual = (isDef === isDef2) &&
                          (valType === (typeof v2)) &&
                          (isArray === utils.array(v2)) &&
                          (isDataMap === (v2 instanceof DataMap));

            if (!isEqual) {
                return isEqual;
            }

            if (valType === "object") {
                var val1    = null;
                var val2    = null;

                var i       = null;

                if (!isArray && !isDataMap) {
                    var propertiesV1 = Object.getOwnPropertyNames(v1);
                    var propertiesV2 = Object.getOwnPropertyNames(v2);

                    isEqual = propertiesV1.length == propertiesV2.length;
                    if (!isEqual) {
                        return isEqual;
                    }

                    for (i = 0; i < propertiesV1.length; i++) {
                        val1 = v1[propertiesV1[i]];
                        val2 = v2[propertiesV1[i]];
                        isEqual = isEqual && (val1 === val2);
                        if (!isEqual) {
                            return isEqual;
                        }
                    }

                    return isEqual;
                } else if (isDataMap) {
                    var propertiesV1 = v1.getAllKeys();
                    var propertiesV2 = v2.getAllKeys();

                    isEqual = propertiesV1.length == propertiesV2.length;
                    if (!isEqual) {
                        return isEqual;
                    }

                    for (i = 0; i < propertiesV1.length; i++) {
                        val1 = v1.get(propertiesV1[i]);
                        val2 = v2.get(propertiesV1[i]);
                        isEqual = isEqual && (val1 === val2);
                        if (!isEqual) {
                            return isEqual;
                        }
                    }

                    return isEqual;
                } else {
                    //Array

                    isEqual = (v1.length == v2.length);
                    if (!isEqual) {
                        return isEqual;
                    }

                    for (i = 0; i < v1.length; i++) {
                        val1 = v1[i];
                        val2 = v2[i];
                        isEqual = isEqual && (val1 === val2);
                        if (!isEqual) {
                            return isEqual;
                        }
                    }

                    return isEqual;
                }
            }

            isEqual = (v1 === v2);
            return isEqual;
        };

        _mustNOTexist("ensureFunc");
        utils.ensureFunc = utils.ensureFunc || function (f, funcName) {
            var sureFunc = f;
            if (!utils.func(sureFunc)) {
                sureFunc = function() {};
                if (utils.def(funcName)) {
                    log.error("Utils::endureFunc : [{0}] is not a function, providing stand-in function".fmt(funcName));
                }
            }

            return sureFunc;
        };

        _mustNOTexist("now");
        utils.now = utils.now || function () {
            return (new Date()).getTime();
        };

        _mustNOTexist("get");
        utils.get = utils.get || function (obj, path, objName) {
            var me      = "Utils::get";
            var value    = null;

            var describe = !utils.empty(objName);

            if (!utils.obj(obj)) {
                if (describe) {
                    log.error(me, "object [{0}] is invalid, can't get property [{1}]".fmt(objName, path));
                }
                return value;
            }

            if (!utils.string(path) || utils.empty(path)) {
                if (describe) {
                    log.error(me, "path to property is invalid, can't get property of [{0}] object".fmt(objName));
                }
                return value;
            }

            var props = path.split(".");
            var numProps = props.length;
            var prop = null;

            var pathTravelled = "";

            var value = obj;
            for (var idx = 0; idx < numProps; idx++) {
                prop = props[idx];

                if (utils.obj(value)) {
                    value = value[prop];
                } else {
                    if (describe) {
                        log.warn(me, "[{0}] of object [{1}] is not an object, unable to get property [{2}]".fmt(
                                pathTravelled,
                                objName,
                                path
                        ));
                    }

                    value = null;
                    break;
                }

                if (describe) {
                    pathTravelled += ((idx > 0) ? '.' : '') + prop;
                }
            }

            return value;
        };

        _mustNOTexist("set");
        utils.set = utils.set || function (obj, path, value, objName) {
            var me = "utils::set";
            var success = false;

            var describe = !utils.empty(objName);

            if (!utils.obj(obj)) {
                if (describe) {
                    log.error(me, "object [{0}] is invalid, can't set property [{1}]".fmt(objName, path));
                }
                return success;
            }

            if (!utils.string(path) || utils.empty(path)) {
                if (describe) {
                    log.error(me, "path to property is invalid, can't set property of [{0}] object".fmt(objName));
                }
                return success;
            }

            var props = path.split(".");
            var numProps = props.length;
            var prop = null;

            var pathTravelled = "";

            var targetObj = obj;
            for (var idx = 0; idx < numProps; idx++) {
                prop = props[idx];

                if (utils.obj(targetObj)) {
                    if (idx < numProps - 1) {
                        targetObj = targetObj[prop];
                    } else {
                        success = true;
                        targetObj[prop] = value;
                    }
                } else {
                    if (describe) {
                        log.warn(me, "[{0}] of object [{1}] is not an object, unable to set property [{2}]".fmt(
                                pathTravelled,
                                objName,
                                path
                        ));
                    }

                    break;
                }

                if (describe) {
                    pathTravelled += ((idx > 0) ? '.' : '') + prop;
                }
            }

            return success;
        };

        _mustNOTexist("stringify");
        utils.stringify = utils.stringify || function(obj, replacer, space) {
            var me  = "Utils::stringify";

            if (!utils.def(space)) {
                space = 4;
            }

            var s   = null;
            try {
                s = JSON.stringify.call(JSON, obj, replacer, space);
            } catch(e) {
                log.error(me, "Unable to stringify object : ", utils.get(e, "message"));
                s = "[Unable to stringify object]";
            }

            return s;
        };

        _mustNOTexist("_parsableToNumber");
        utils.parsableToNumber = utils.parsableToNumber || function(number) {
            return !isNaN(number);
        };
    };

})();<commit_msg>Tiny spelling fix<commit_after>/**
 * Created by Freddy Snijder on 15/05/14.
 */

(function() {
    var NS      = null;
    var DataMap = null;

    var __isNode = (typeof module !== 'undefined' && typeof module.exports !== 'undefined');
    if (__isNode) {
        require("./../extensions/string.ext.js");

        DataMap = require("../data-structures/data-map.js").DataMap;

        NS = exports;
    } else {
        //Add to Visionscapers namespace
        NS = window["__VI__"] || window;

        DataMap = NS.DataMap;
    }

    //using underscore.js _ as base object
    //changing and augmenting it where we want to

    NS.UtilsBase = {};
    NS.UtilsBase.addTo = function (utils, log) {

        if (typeof(log) != "object") {
            console.warn("UtilsBase : no logging object provided, using browser console logger");
            log = console;
        }

        if ((typeof(utils) != "object") && (typeof(utils) != "function")) {
            log.error("UtilsBase", "no valid utils object given, unable to extend");
            return;
        }

        //Using these functions (in the particular way as used below) to ensure that Webstorm (or other IDE) can find
        // the method definition, while still providing feedback when a method already exists

        var _mustNOTexist = function (name) {
            if ((utils[name] !== null) && (utils[name] !== undefined)) {
                log.warn("UtilsBase", "property or method {0} already exists, not overwriting".fmt(name));
            }
        };
        var _mustExist = function (name) {
            if ((utils[name] === null) || (utils[name] === undefined)) {
                log.error("UtilsBase", "property or method {0} does not exists, will not be available".fmt(name));
            }
        };

        _mustNOTexist("_mustNOTexist");
        utils._mustNOTexist = utils._mustNOTexist || _mustNOTexist;

        _mustNOTexist("_mustExist");
        utils._mustExist = utils._mustExist || _mustExist;

        /**************************************************
         *
         * Register utils component
         *
         **************************************************/

        //Different util components are registered here
        //This allows us to check in a simple way if certain functionality is available
        _mustNOTexist("_utilsComponents");
        utils._utilsComponents = utils._utilsComponents || {
            base: true
        };

        /**************************************************
         *
         * END Register utils component
         *
         **************************************************/

        _mustNOTexist("def");
        utils.def = utils.def || function (v) {
            return ((v !== null) && (v !== undefined));
        };

        _mustNOTexist("obj");
        _mustExist("isObject");
        utils.obj = utils.obj || utils.isObject;

        _mustNOTexist("bool");
        _mustExist("isBoolean");
        utils.bool = utils.bool || utils.isBoolean;

        _mustNOTexist("number");
        _mustExist("isNumber");
        utils.number = utils.number || utils.isNumber;

        _mustNOTexist("string");
        _mustExist("isString");
        utils.string = utils.string || utils.isString;

        _mustNOTexist("array");
        _mustExist("isArray");
        utils.array = utils.array || utils.isArray;

        _mustNOTexist("func");
        _mustExist("isFunction");
        utils.func = utils.func || utils.isFunction;

        _mustNOTexist("date");
        _mustExist("isDate");
        utils.date = utils.date || utils.isDate;

        _mustNOTexist("empty");
        _mustExist("isEmpty");
        utils.empty = utils.empty || utils.isEmpty;

        _mustNOTexist("class");
        utils.class = utils.class || function (C) {
            return utils.func(C) && (C === C.prototype.constructor);
        };

        _mustNOTexist("equals");
        /**
         *
         * Returns true if v1 and v2 are equal else false.
         *
         * For objects the values of its own properties are compared using ===.
         * For arrays the item values are compared using ===.
         *
         * This function can also compare DataMap structures
         *
         * So for both objects and arrays the equality assessment is only done one level deep.
         *
         * @returns {boolean}
         *
         */
        utils.equals = utils.equals || function (v1, v2) {
            var isDef   = utils.def(v1);
            var isDef2  = utils.def(v2);

            if (!isDef && !isDef2) {
                return true;
            }

            var valType     = (typeof v1);
            var isArray     = utils.array(v1);
            var isDataMap   = v1 instanceof DataMap;
            var isEqual = (isDef === isDef2) &&
                          (valType === (typeof v2)) &&
                          (isArray === utils.array(v2)) &&
                          (isDataMap === (v2 instanceof DataMap));

            if (!isEqual) {
                return isEqual;
            }

            if (valType === "object") {
                var val1    = null;
                var val2    = null;

                var i       = null;

                if (!isArray && !isDataMap) {
                    var propertiesV1 = Object.getOwnPropertyNames(v1);
                    var propertiesV2 = Object.getOwnPropertyNames(v2);

                    isEqual = propertiesV1.length == propertiesV2.length;
                    if (!isEqual) {
                        return isEqual;
                    }

                    for (i = 0; i < propertiesV1.length; i++) {
                        val1 = v1[propertiesV1[i]];
                        val2 = v2[propertiesV1[i]];
                        isEqual = isEqual && (val1 === val2);
                        if (!isEqual) {
                            return isEqual;
                        }
                    }

                    return isEqual;
                } else if (isDataMap) {
                    var propertiesV1 = v1.getAllKeys();
                    var propertiesV2 = v2.getAllKeys();

                    isEqual = propertiesV1.length == propertiesV2.length;
                    if (!isEqual) {
                        return isEqual;
                    }

                    for (i = 0; i < propertiesV1.length; i++) {
                        val1 = v1.get(propertiesV1[i]);
                        val2 = v2.get(propertiesV1[i]);
                        isEqual = isEqual && (val1 === val2);
                        if (!isEqual) {
                            return isEqual;
                        }
                    }

                    return isEqual;
                } else {
                    //Array

                    isEqual = (v1.length == v2.length);
                    if (!isEqual) {
                        return isEqual;
                    }

                    for (i = 0; i < v1.length; i++) {
                        val1 = v1[i];
                        val2 = v2[i];
                        isEqual = isEqual && (val1 === val2);
                        if (!isEqual) {
                            return isEqual;
                        }
                    }

                    return isEqual;
                }
            }

            isEqual = (v1 === v2);
            return isEqual;
        };

        _mustNOTexist("ensureFunc");
        utils.ensureFunc = utils.ensureFunc || function (f, funcName) {
            var sureFunc = f;
            if (!utils.func(sureFunc)) {
                sureFunc = function() {};
                if (utils.def(funcName)) {
                    log.error("Utils::ensureFunc : [{0}] is not a function, providing stand-in function".fmt(funcName));
                }
            }

            return sureFunc;
        };

        _mustNOTexist("now");
        utils.now = utils.now || function () {
            return (new Date()).getTime();
        };

        _mustNOTexist("get");
        utils.get = utils.get || function (obj, path, objName) {
            var me      = "Utils::get";
            var value    = null;

            var describe = !utils.empty(objName);

            if (!utils.obj(obj)) {
                if (describe) {
                    log.error(me, "object [{0}] is invalid, can't get property [{1}]".fmt(objName, path));
                }
                return value;
            }

            if (!utils.string(path) || utils.empty(path)) {
                if (describe) {
                    log.error(me, "path to property is invalid, can't get property of [{0}] object".fmt(objName));
                }
                return value;
            }

            var props = path.split(".");
            var numProps = props.length;
            var prop = null;

            var pathTravelled = "";

            var value = obj;
            for (var idx = 0; idx < numProps; idx++) {
                prop = props[idx];

                if (utils.obj(value)) {
                    value = value[prop];
                } else {
                    if (describe) {
                        log.warn(me, "[{0}] of object [{1}] is not an object, unable to get property [{2}]".fmt(
                                pathTravelled,
                                objName,
                                path
                        ));
                    }

                    value = null;
                    break;
                }

                if (describe) {
                    pathTravelled += ((idx > 0) ? '.' : '') + prop;
                }
            }

            return value;
        };

        _mustNOTexist("set");
        utils.set = utils.set || function (obj, path, value, objName) {
            var me = "utils::set";
            var success = false;

            var describe = !utils.empty(objName);

            if (!utils.obj(obj)) {
                if (describe) {
                    log.error(me, "object [{0}] is invalid, can't set property [{1}]".fmt(objName, path));
                }
                return success;
            }

            if (!utils.string(path) || utils.empty(path)) {
                if (describe) {
                    log.error(me, "path to property is invalid, can't set property of [{0}] object".fmt(objName));
                }
                return success;
            }

            var props = path.split(".");
            var numProps = props.length;
            var prop = null;

            var pathTravelled = "";

            var targetObj = obj;
            for (var idx = 0; idx < numProps; idx++) {
                prop = props[idx];

                if (utils.obj(targetObj)) {
                    if (idx < numProps - 1) {
                        targetObj = targetObj[prop];
                    } else {
                        success = true;
                        targetObj[prop] = value;
                    }
                } else {
                    if (describe) {
                        log.warn(me, "[{0}] of object [{1}] is not an object, unable to set property [{2}]".fmt(
                                pathTravelled,
                                objName,
                                path
                        ));
                    }

                    break;
                }

                if (describe) {
                    pathTravelled += ((idx > 0) ? '.' : '') + prop;
                }
            }

            return success;
        };

        _mustNOTexist("stringify");
        utils.stringify = utils.stringify || function(obj, replacer, space) {
            var me  = "Utils::stringify";

            if (!utils.def(space)) {
                space = 4;
            }

            var s   = null;
            try {
                s = JSON.stringify.call(JSON, obj, replacer, space);
            } catch(e) {
                log.error(me, "Unable to stringify object : ", utils.get(e, "message"));
                s = "[Unable to stringify object]";
            }

            return s;
        };

        _mustNOTexist("_parsableToNumber");
        utils.parsableToNumber = utils.parsableToNumber || function(number) {
            return !isNaN(number);
        };
    };

})();<|endoftext|>


<commit_before>#!/usr/bin/env node

'use strict';

let fs = require('fs'),
  Promise = require('bluebird'),
  path = require('path'),
  hartopage = require('../../lib/index');

Promise.promisifyAll(fs);

module.exports = {
  getPages: function(harFile) {
    return fs.readFileAsync(path.resolve(harFile))
      .then(JSON.parse)
      .then(hartopage.convert)
      .then((pages) => {
        return pages;
      })
      .catch((e) => {
        console.error('Error fetching page(s)', e);
      })
  }
};
<commit_msg>Fail tests if error occurs, don't just log.<commit_after>#!/usr/bin/env node

'use strict';

let fs = require('fs'),
  Promise = require('bluebird'),
  path = require('path'),
  hartopage = require('../../lib/index');

Promise.promisifyAll(fs);

module.exports = {
  getPages: function(harFile) {
    return fs.readFileAsync(path.resolve(harFile))
      .then(JSON.parse)
      .then(hartopage.convert)
      .then((pages) => {
        return pages;
      })
      .catch((e) => {
        console.error('Error fetching page(s)', e);
        throw e;
      })
  }
};
<|endoftext|>


<commit_before>describe("HtmlOutput", function() {
	var TermState = Terminal.TermState;
	var HtmlOutput = Terminal.output.HtmlOutput;

	function newTerminal(w, h) {
		var t = new TermState({rows:h, columns:w}), tw = new Terminal(t);
		t.setMode("crlf", true);
		return tw;
	}

	it("basic write test", function() {
		var t = newTerminal();
		var r = new HtmlOutput(t.state);
		t.write("\x1b[31mHello\x1b[m World");

		expect(r.toString()).to.contain("Hello World
");
	});
});
<commit_msg>test: fix html_output test<commit_after>describe("HtmlOutput", function() {
	var TermState = Terminal.TermState;
	var HtmlOutput = Terminal.output.HtmlOutput;

	function newTerminal(w, h) {
		var t = new TermState({rows:h, columns:w}), tw = new Terminal(t);
		t.setMode("crlf", true);
		return tw;
	}

	it("basic write test", function() {
		var t = newTerminal();
		var r = new HtmlOutput(t.state);
		t.write("\x1b[31mHello\x1b[m World");

		expect(r.toString()).to.contain("Hello World
");
	});
});
<|endoftext|>