<commit_before>function MurderPlayers(){
	this.canRepeat = true;
	this.playerList = [];  //what players are already in the medium when i trigger?
	this.murderers = [];

	this.trigger = function(playerList){
		this.playerList = playerList;
		this.murderers = [];
		//select a random player. if they've been triggered, random chance of going murderMode if enemies (based on how triggered.)
		this.player = getRandomElementFromArray(availablePlayers);
		for(var i = 0; i<availablePlayers.length; i++){
			if(availablePlayers[i].murderMode){
				this.murderers.push(availablePlayers[i]);
			}
		}

		return this.murderers.length > null;
	}

	this.renderContent = function(div){
		div.append("
"+this.contentForRender(div));
	}

	this.friendsOfVictimHateYou = function(victim, murderer, livePlayers){
		//just, fuck that guy.
		var ret = "";
		for(var i = 0; i<livePlayers.length; i++){
			var p = livePlayers[i];
			if(p != murderer && p != victim){
				var rm = p.getRelationshipWith(murderer);
				var rv = p.getRelationshipWith(victim);
				//more they liked the victim, the more they hate you.
				if(rv.type() == rv.goodBig){
					rm.value = -20;
					ret += " The " + p.htmlTitle() + " is enraged that their crush was killed. ";
				}else if(rv.type() == rv.badBig && p.isTroll){
					rm.value = -20;
					ret += " The " + p.htmlTitle() + " is enraged that their spades crush was killed. ";
				}else if(rv.type() == rv.badBig && !p.isTroll){
					rm.increase();
					ret += " The " + p.htmlTitle() + " is pretty happy that their enemy was killed. ";
				}else if(rv.value > 0){  //iff i actually liked the guy.
					for(var j = 0; j< rv.value; j++){
						rm.decrease();
					}
					ret += " The " + p.htmlTitle() + " is pretty pissed that their friend was killed. ";
				}
			}
		}
		return ret;

	}

	//not necessarily murder mode player, could be self defense.
	this.renderMurder = function(div,murderer, victim){
		var divID = (div.attr("id")) + "_" + victim.chatHandle;
		var canvasHTML = "
<canvas id='canvas" + divID+"' width='" +canvasWidth + "' height="+canvasHeight + "'>  </canvas>";
		div.append(canvasHTML);
		var canvas = document.getElementById("canvas"+ divID);

		var pSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(pSpriteBuffer,murderer,1000)

		var dSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(dSpriteBuffer,victim,1000)

		copyTmpCanvasToRealCanvasAtPos(canvas, pSpriteBuffer,-100,0)
		copyTmpCanvasToRealCanvasAtPos(canvas, dSpriteBuffer,100,0)

	}

	//diamond faces murderer, calms them the hell down and hug bumps are shared.
	this.renderDiamonds = function(div, murderer, diamond){
		var divID = (div.attr("id")) + "_" + diamond.chatHandle;
		var canvasHTML = "
<canvas id='canvas" + divID+"' width='" +canvasWidth + "' height="+canvasHeight + "'>  </canvas>";
		div.append(canvasHTML);
		var canvas = document.getElementById("canvas"+ divID);

		var pSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(pSpriteBuffer,murderer,1000)

		var dSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSpriteTurnways(dSpriteBuffer,diamond,1000)

		var x = 100;
		if(murderer.isTroll == true || diamond.isTroll == true){  //humans have regular romance, but if even one is a troll, this is romance.
			var diSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
			drawDiamond(diSpriteBuffer,1000)
			x = 50; //stand closer cause romance
			copyTmpCanvasToRealCanvasAtPos(canvas, diSpriteBuffer,75,0)
		}
		copyTmpCanvasToRealCanvasAtPos(canvas, pSpriteBuffer,-100,0)
		copyTmpCanvasToRealCanvasAtPos(canvas, dSpriteBuffer,x,0)
	}

	//random Auspistice settles their shit down.  this will probably be pretty rare.
	this.renderClubs = function(div, murderer, victim, club){
		alert("clubs)")
		var divID = (div.attr("id")) + "_" + club.chatHandle;
		var canvasHTML = "
<canvas id='canvas" + divID+"' width='" +canvasWidth + "' height="+canvasHeight + "'>  </canvas>";
		div.append(canvasHTML);
		var canvas = document.getElementById("canvas"+ divID);

		var pSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(pSpriteBuffer,murderer,1000)

		var vSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(vSpriteBuffer,victim,1000)

		var dSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSpriteTurnways(dSpriteBuffer,club,1000)  //facing non-middle leafs

		if(murderer.isTroll == true || club.isTroll == true || club.isTroll == true){  //humans have regular romance, but if even one is a troll, this is romance.
			var diSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
			drawClub(diSpriteBuffer,1000) //Auspisticism
			copyTmpCanvasToRealCanvasAtPos(canvas, diSpriteBuffer,375,50)
		}
		copyTmpCanvasToRealCanvasAtPos(canvas, pSpriteBuffer,-100,0)
		copyTmpCanvasToRealCanvasAtPos(canvas, vSpriteBuffer,100,0)
		copyTmpCanvasToRealCanvasAtPos(canvas, dSpriteBuffer,400,0)
	}

	this.contentForRender = function(div){
		var livePlayers = this.playerList; //just because they are alive doesn't mean they are in the medium
		for(var i = 0; i<this.murderers.length; i++){
			var m = this.murderers[i];
			var worstEnemy = m.getWorstEnemyFromList(availablePlayers);
			var living = findLivingPlayers(players)
			removeFromArray(worstEnemy, living)
			var ausp = getRandomElementFromArray(living)
			if(ausp == worstEnemy || ausp == m){
				ausp = null;
			}
			//var notEnemy = m.getWorstEnemyFromList(availablePlayers);
			removeFromArray(m, availablePlayers);
			var ret = "";
			if(worstEnemy && worstEnemy.dead == false){
				removeFromArray(worstEnemy, availablePlayers);
				//if blood player is at all competant, can talk down murder mode player.
				if(worstEnemy.aspect == "Blood" && worstEnemy.power > 2){
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += ", but instead the Bloody Thing happens and the " + m.htmlTitle() + " is calmed down, and hug bumps are shared. ";
					m.murderMode = false;
					worstEnemy.checkBloodBoost(livePlayers);
					m.triggerLevel = 1;
					this.renderDiamonds(div, m, worstEnemy);
					//don't hate your new diamond buddy
					var r = m.getRelationshipWith(worstEnemy);
					r.value = 1;
					return ret; //don't try to murder. (and also blood powers stop any other potential murders);
				}
				var r = worstEnemy.getRelationshipWith(m)
				if(r.type() == r.goodBig ){
					//moiralligance.
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += ", but instead gets talked down hardcore. Shit is downright tender.";
					m.murderMode = false;
					m.triggerLevel = 1;
					this.renderDiamonds(div, m, worstEnemy);
					var r = m.getRelationshipWith(worstEnemy);
					r.value = 1;
				}else if(ausp != null && r.type() == r.badBig){  //they hate you back....
					///auspitism, but who is middle leaf?
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += "(who hates them back just as much), but instead is interupted by the " + ausp.htmlTitle() + ", who convinces everyone to settle their shit down. ";
					m.murderMode = false;
					m.triggerLevel = 1;
					this.renderClubs(div, m, worstEnemy,ausp);
					var r = m.getRelationshipWith(ausp); //neutral to middle leaf, but unchanged about each other.
					r.value = 1;
					var r2 = worstEnemy.getRelationshipWith(ausp);
					r2.value = 1;

				}else if(worstEnemy.power < m.power*2){  //more likely to kill enemy than be killed. element of surprise
					m.increasePower();

					worstEnemy.causeOfDeath = "fighting the " + m.htmlTitle();
					ret += " The " + m.htmlTitle() + " brutally murders that asshole, the " + worstEnemy.htmlTitle() +". ";
					ret += this.friendsOfVictimHateYou(worstEnemy, m, livePlayers);
					worstEnemy.dead = true;
					var r = worstEnemy.getRelationshipWith(m);
					r.value = -10; //you are not happy with murderer
					m.victimBlood = worstEnemy.bloodColor;
					this.renderMurder(div, m, worstEnemy)
				}else{
					worstEnemy.increasePower();

					m.causeOfDeath = "being put down like a rabid dog by " + worstEnemy.htmlTitle()
					ret += " The " + m.htmlTitle() + " attempts to brutally murders that asshole, the " + worstEnemy.htmlTitle();
					ret += ",but instead gets murdered first, in self-defense. ";
					m.dead = true;
					var r = worstEnemy.getRelationshipWith(m);
					r.value = -10; //you are not happy with murderer
					worstEnemy.victimBlood = m.bloodColor;
					this.renderMurder(div,worstEnemy, m);
				}
			}else{
				ret += " The " + m.htmlTitle() + " can't find anybody they hate enough to murder. They calm down a little. ";
				m.triggerLevel += -1;
			}
		}
		removeFromArray(m, availablePlayers);
		return ret;
	}

	this.content = function(){
		var livePlayers = this.playerList; //just because they are alive doesn't mean they are in the medium
		for(var i = 0; i<this.murderers.length; i++){
			var m = this.murderers[i];
			var worstEnemy = m.getWorstEnemyFromList(livePlayers);
			removeFromArray(m, availablePlayers);
			var ret = "";
			if(worstEnemy && worstEnemy.dead == false){
				removeFromArray(worstEnemy, availablePlayers);
				//if blood player is at all competant, can talk down murder mode player.
				if(worstEnemy.aspect == "Blood" && worstEnemy.power > 2){
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += ", but instead the Bloody Thing happens and the " + m.htmlTitle() + " is calmed down, and hug bumps are shared. ";
					m.murderMode = false;
					worstEnemy.checkBloodBoost(livePlayers);
					m.triggerLevel = 1;
					return ret; //don't try to murder. (and also blood powers stop any other potential murders);
				}

				var r = worstEnemy.getRelationshipWith(m)
				if(r.type() == r.goodBig ){
					//moiralligance.
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += ", but instead gets talked down hardcore. Shit is downright tender.";
					m.murderMode = false;
					m.triggerLevel = 1;
					this.renderDiamonds(div, m, worstEnemy);
				}else if(worstEnemy.power < m.power*2){  //more likely to kill enemy than be killed. element of surprise
					m.increasePower();

					worstEnemy.causeOfDeath = "fighting the " + m.htmlTitle();
					ret += " The " + m.htmlTitle() + " brutally murders that asshole, the " + worstEnemy.htmlTitle() +". ";
					ret += this.friendsOfVictimHateYou(worstEnemy, m, livePlayers);
					worstEnemy.dead = true;
					m.victimBlood = worstEnemy.bloodColor;
				}else{
					worstEnemy.increasePower();

					m.causeOfDeath = "being put down like a rabid dog by " + worstEnemy.htmlTitle()
					ret += " The " + m.htmlTitle() + " attempts to brutally murders that asshole, the " + worstEnemy.htmlTitle();
					ret += ",but instead gets murdered first, in self-defense. ";
					m.dead = true;
					worstEnemy.victimBlood = m.bloodColor;
				}
			}else{
				ret += " The " + m.htmlTitle() + " can't find anybody they hate enough to murder. They calm down a little. ";
				m.triggerLevel += -1;
			}
		}
		removeFromArray(m, availablePlayers);
		return ret;
	}
}<commit_msg>debugging<commit_after>function MurderPlayers(){
	this.canRepeat = true;
	this.playerList = [];  //what players are already in the medium when i trigger?
	this.murderers = [];

	this.trigger = function(playerList){
		this.playerList = playerList;
		this.murderers = [];
		//select a random player. if they've been triggered, random chance of going murderMode if enemies (based on how triggered.)
		this.player = getRandomElementFromArray(availablePlayers);
		for(var i = 0; i<availablePlayers.length; i++){
			if(availablePlayers[i].murderMode){
				this.murderers.push(availablePlayers[i]);
			}
		}

		return this.murderers.length > null;
	}

	this.renderContent = function(div){
		div.append("
"+this.contentForRender(div));
	}

	this.friendsOfVictimHateYou = function(victim, murderer, livePlayers){
		//just, fuck that guy.
		var ret = "";
		for(var i = 0; i<livePlayers.length; i++){
			var p = livePlayers[i];
			if(p != murderer && p != victim){
				var rm = p.getRelationshipWith(murderer);
				var rv = p.getRelationshipWith(victim);
				//more they liked the victim, the more they hate you.
				if(rv.type() == rv.goodBig){
					rm.value = -20;
					ret += " The " + p.htmlTitle() + " is enraged that their crush was killed. ";
				}else if(rv.type() == rv.badBig && p.isTroll){
					rm.value = -20;
					ret += " The " + p.htmlTitle() + " is enraged that their spades crush was killed. ";
				}else if(rv.type() == rv.badBig && !p.isTroll){
					rm.increase();
					ret += " The " + p.htmlTitle() + " is pretty happy that their enemy was killed. ";
				}else if(rv.value > 0){  //iff i actually liked the guy.
					for(var j = 0; j< rv.value; j++){
						rm.decrease();
					}
					ret += " The " + p.htmlTitle() + " is pretty pissed that their friend was killed. ";
				}
			}
		}
		return ret;

	}

	//not necessarily murder mode player, could be self defense.
	this.renderMurder = function(div,murderer, victim){
		var divID = (div.attr("id")) + "_" + victim.chatHandle;
		var canvasHTML = "
<canvas id='canvas" + divID+"' width='" +canvasWidth + "' height="+canvasHeight + "'>  </canvas>";
		div.append(canvasHTML);
		var canvas = document.getElementById("canvas"+ divID);

		var pSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(pSpriteBuffer,murderer,1000)

		var dSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(dSpriteBuffer,victim,1000)

		copyTmpCanvasToRealCanvasAtPos(canvas, pSpriteBuffer,-100,0)
		copyTmpCanvasToRealCanvasAtPos(canvas, dSpriteBuffer,100,0)

	}

	//diamond faces murderer, calms them the hell down and hug bumps are shared.
	this.renderDiamonds = function(div, murderer, diamond){
		var divID = (div.attr("id")) + "_" + diamond.chatHandle;
		var canvasHTML = "
<canvas id='canvas" + divID+"' width='" +canvasWidth + "' height="+canvasHeight + "'>  </canvas>";
		div.append(canvasHTML);
		var canvas = document.getElementById("canvas"+ divID);

		var pSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(pSpriteBuffer,murderer,1000)

		var dSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSpriteTurnways(dSpriteBuffer,diamond,1000)

		var x = 100;
		if(murderer.isTroll == true || diamond.isTroll == true){  //humans have regular romance, but if even one is a troll, this is romance.
			var diSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
			drawDiamond(diSpriteBuffer,1000)
			x = 50; //stand closer cause romance
			copyTmpCanvasToRealCanvasAtPos(canvas, diSpriteBuffer,75,0)
		}
		copyTmpCanvasToRealCanvasAtPos(canvas, pSpriteBuffer,-100,0)
		copyTmpCanvasToRealCanvasAtPos(canvas, dSpriteBuffer,x,0)
	}

	//random Auspistice settles their shit down.  this will probably be pretty rare.
	this.renderClubs = function(div, murderer, victim, club){
		//alert("clubs)")
		var divID = (div.attr("id")) + "_" + club.chatHandle;
		var canvasHTML = "
<canvas id='canvas" + divID+"' width='" +canvasWidth + "' height="+canvasHeight + "'>  </canvas>";
		div.append(canvasHTML);
		var canvas = document.getElementById("canvas"+ divID);

		var pSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(pSpriteBuffer,murderer,1000)

		var vSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSprite(vSpriteBuffer,victim,1000)

		var dSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
		drawSpriteTurnways(dSpriteBuffer,club,1000)  //facing non-middle leafs

		if(murderer.isTroll == true || club.isTroll == true || club.isTroll == true){  //humans have regular romance, but if even one is a troll, this is romance.
			var diSpriteBuffer = getBufferCanvas(document.getElementById("sprite_template"));
			drawClub(diSpriteBuffer,1000) //Auspisticism
			copyTmpCanvasToRealCanvasAtPos(canvas, diSpriteBuffer,375,50)
		}
		copyTmpCanvasToRealCanvasAtPos(canvas, pSpriteBuffer,-100,0)
		copyTmpCanvasToRealCanvasAtPos(canvas, vSpriteBuffer,100,0)
		copyTmpCanvasToRealCanvasAtPos(canvas, dSpriteBuffer,400,0)
	}

	this.contentForRender = function(div){
		var livePlayers = this.playerList; //just because they are alive doesn't mean they are in the medium
		for(var i = 0; i<this.murderers.length; i++){
			var m = this.murderers[i];
			var worstEnemy = m.getWorstEnemyFromList(availablePlayers);
			var living = findLivingPlayers(players)
			removeFromArray(worstEnemy, living)
			var ausp = getRandomElementFromArray(living)
			if(ausp == worstEnemy || ausp == m){
				ausp = null;
			}
			//var notEnemy = m.getWorstEnemyFromList(availablePlayers);
			removeFromArray(m, availablePlayers);
			var ret = "";
			if(worstEnemy && worstEnemy.dead == false){
				removeFromArray(worstEnemy, availablePlayers);
				//if blood player is at all competant, can talk down murder mode player.
				if(worstEnemy.aspect == "Blood" && worstEnemy.power > 2){
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += ", but instead the Bloody Thing happens and the " + m.htmlTitle() + " is calmed down, and hug bumps are shared. ";
					m.murderMode = false;
					worstEnemy.checkBloodBoost(livePlayers);
					m.triggerLevel = 1;
					this.renderDiamonds(div, m, worstEnemy);
					//don't hate your new diamond buddy
					var r = m.getRelationshipWith(worstEnemy);
					r.value = 1;
					return ret; //don't try to murder. (and also blood powers stop any other potential murders);
				}
				var r = worstEnemy.getRelationshipWith(m)
				if(r.type() == r.goodBig ){
					//moiralligance.
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += ", but instead gets talked down hardcore. Shit is downright tender.";
					m.murderMode = false;
					m.triggerLevel = 1;
					this.renderDiamonds(div, m, worstEnemy);
					var r = m.getRelationshipWith(worstEnemy);
					r.value = 1;
				}else if(ausp != null && r.type() == r.badBig){  //they hate you back....
					///auspitism, but who is middle leaf?
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += "(who hates them back just as much), but instead is interupted by the " + ausp.htmlTitle() + ", who convinces everyone to settle their shit down. ";
					m.murderMode = false;
					m.triggerLevel = 1;
					this.renderClubs(div, m, worstEnemy,ausp);
					var r = m.getRelationshipWith(ausp); //neutral to middle leaf, but unchanged about each other.
					r.value = 1;
					var r2 = worstEnemy.getRelationshipWith(ausp);
					r2.value = 1;

				}else if(worstEnemy.power < m.power*2){  //more likely to kill enemy than be killed. element of surprise
					m.increasePower();

					worstEnemy.causeOfDeath = "fighting the " + m.htmlTitle();
					ret += " The " + m.htmlTitle() + " brutally murders that asshole, the " + worstEnemy.htmlTitle() +". ";
					ret += this.friendsOfVictimHateYou(worstEnemy, m, livePlayers);
					worstEnemy.dead = true;
					var r = worstEnemy.getRelationshipWith(m);
					r.value = -10; //you are not happy with murderer
					m.victimBlood = worstEnemy.bloodColor;
					this.renderMurder(div, m, worstEnemy)
				}else{
					worstEnemy.increasePower();

					m.causeOfDeath = "being put down like a rabid dog by " + worstEnemy.htmlTitle()
					ret += " The " + m.htmlTitle() + " attempts to brutally murders that asshole, the " + worstEnemy.htmlTitle();
					ret += ",but instead gets murdered first, in self-defense. ";
					m.dead = true;
					var r = worstEnemy.getRelationshipWith(m);
					r.value = -10; //you are not happy with murderer
					worstEnemy.victimBlood = m.bloodColor;
					this.renderMurder(div,worstEnemy, m);
				}
			}else{
				ret += " The " + m.htmlTitle() + " can't find anybody they hate enough to murder. They calm down a little. ";
				m.triggerLevel += -1;
			}
		}
		removeFromArray(m, availablePlayers);
		return ret;
	}

	this.content = function(){
		var livePlayers = this.playerList; //just because they are alive doesn't mean they are in the medium
		for(var i = 0; i<this.murderers.length; i++){
			var m = this.murderers[i];
			var worstEnemy = m.getWorstEnemyFromList(livePlayers);
			removeFromArray(m, availablePlayers);
			var ret = "";
			if(worstEnemy && worstEnemy.dead == false){
				removeFromArray(worstEnemy, availablePlayers);
				//if blood player is at all competant, can talk down murder mode player.
				if(worstEnemy.aspect == "Blood" && worstEnemy.power > 2){
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += ", but instead the Bloody Thing happens and the " + m.htmlTitle() + " is calmed down, and hug bumps are shared. ";
					m.murderMode = false;
					worstEnemy.checkBloodBoost(livePlayers);
					m.triggerLevel = 1;
					return ret; //don't try to murder. (and also blood powers stop any other potential murders);
				}

				var r = worstEnemy.getRelationshipWith(m)
				if(r.type() == r.goodBig ){
					//moiralligance.
					ret += " The " + m.htmlTitle() + " attempts to murder that asshole, the " + worstEnemy.htmlTitle();
					ret += ", but instead gets talked down hardcore. Shit is downright tender.";
					m.murderMode = false;
					m.triggerLevel = 1;
					this.renderDiamonds(div, m, worstEnemy);
				}else if(worstEnemy.power < m.power*2){  //more likely to kill enemy than be killed. element of surprise
					m.increasePower();

					worstEnemy.causeOfDeath = "fighting the " + m.htmlTitle();
					ret += " The " + m.htmlTitle() + " brutally murders that asshole, the " + worstEnemy.htmlTitle() +". ";
					ret += this.friendsOfVictimHateYou(worstEnemy, m, livePlayers);
					worstEnemy.dead = true;
					m.victimBlood = worstEnemy.bloodColor;
				}else{
					worstEnemy.increasePower();

					m.causeOfDeath = "being put down like a rabid dog by " + worstEnemy.htmlTitle()
					ret += " The " + m.htmlTitle() + " attempts to brutally murders that asshole, the " + worstEnemy.htmlTitle();
					ret += ",but instead gets murdered first, in self-defense. ";
					m.dead = true;
					worstEnemy.victimBlood = m.bloodColor;
				}
			}else{
				ret += " The " + m.htmlTitle() + " can't find anybody they hate enough to murder. They calm down a little. ";
				m.triggerLevel += -1;
			}
		}
		removeFromArray(m, availablePlayers);
		return ret;
	}
}<|endoftext|>


<commit_before>/** @jsx React.DOM */

// Constants
var Events = require('../Events');
var debug = require('../Helpers').debug;

// Global variables
var store = require('../store');
var flux = require('../flux/dispatcher');

function DEBUG(text) {
    return debug('Similarity Component - ' + text);
}

// Algorithm

// TODO make this threshold a parameter
const TIME_SIMILAR_THRESHOLD = 1000 * 60 * 60 * 24 * 2; // 48 hours
function findRedundantPairs(operations) {
    DEBUG('Running findRedundantPairs algorithm...');
    DEBUG('Input: ' + operations.length + ' operations');
    var similar = [];

    function areSimilarOperations(a, b) {
        if (a.amount != b.amount)
            return false;
        var datediff = Math.abs(+a.date - +b.date);
        return datediff <= TIME_SIMILAR_THRESHOLD;
    }

    // O(n log n)
    function sortCriteria(a,b) { return a.amount - b.amount; }
    var sorted = operations.slice().sort(sortCriteria);
    for (var i = 0; i < operations.length; ++i) {
        if (i + 1 >= operations.length)
            continue;

        var op = sorted[i];
        var next = sorted[i+1];
        if (areSimilarOperations(op, next))
            similar.push([op, next]);
    }

    DEBUG(similar.length + ' pairs of similar operations found');
    return similar;
}

// Components
var SimilarityItemComponent = React.createClass({

    _deleteOperation: function() {
        flux.dispatch({
            type: Events.DELETE_OPERATION,
            operation: this.props.operation
        });
    },

    render: function() {
        return (

                {this.props.operation.date.toString()}
                {this.props.operation.title}
                {this.props.operation.amount}
                x

        );
    }
});

var SimilarityPairComponent = React.createClass({

    render: function() {
        return (

                <SimilarityItemComponent operation={this.props.a} />
                <SimilarityItemComponent operation={this.props.b} />

        );
    }
});

module.exports = React.createClass({

    getInitialState: function() {
        return {
            pairs: []
        };
    },

    _cb: function() {
        this.setState({
            pairs: findRedundantPairs(store.operations)
        });
    },

    componentDidMount: function() {
        store.subscribeMaybeGet(Events.OPERATIONS_LOADED, this._cb);
    },

    componentWillUnmount: function() {
        store.removeListener(Events.OPERATIONS_LOADED, this._cb);
    },

    render: function() {
        var pairs = this.state.pairs;
        if (pairs.length === 0) {
            return (

No similar operations found.

            )
        }

        var sim = pairs.map(function (p) {
            var key = p[0].id.toString() + p[1].id.toString();
            return (<SimilarityPairComponent key={key} a={p[0]} b={p[1]}  />)
        });
        return (

Similarities

                    {sim}

)
    }
});

<commit_msg>Fixes #8: automatically transfer category of deleted similar operation.<commit_after>/** @jsx React.DOM */

// Constants
var Events = require('../Events');
var assert = require('../Helpers').assert;
var debug = require('../Helpers').debug;

// Global variables
var store = require('../store');
var flux = require('../flux/dispatcher');

function DEBUG(text) {
    return debug('Similarity Component - ' + text);
}

// Algorithm

// TODO make this threshold a parameter
const TIME_SIMILAR_THRESHOLD = 1000 * 60 * 60 * 24 * 1.5; // 36 hours
function findRedundantPairs(operations) {
    DEBUG('Running findRedundantPairs algorithm...');
    DEBUG('Input: ' + operations.length + ' operations');
    var similar = [];

    function areSimilarOperations(a, b) {
        if (a.amount != b.amount)
            return false;
        var datediff = Math.abs(+a.date - +b.date);
        return datediff <= TIME_SIMILAR_THRESHOLD;
    }

    // O(n log n)
    function sortCriteria(a,b) { return a.amount - b.amount; }
    var sorted = operations.slice().sort(sortCriteria);
    for (var i = 0; i < operations.length; ++i) {
        if (i + 1 >= operations.length)
            continue;

        var op = sorted[i];
        var next = sorted[i+1];
        if (areSimilarOperations(op, next))
            similar.push([op, next]);
    }

    DEBUG(similar.length + ' pairs of similar operations found');
    return similar;
}

// Components
var SimilarityItemComponent = React.createClass({

    render: function() {
        return (

                {this.props.operation.date.toString()}
                {this.props.operation.title}
                {this.props.operation.amount}
                Category: {store.categoryToLabel(this.props.operation.categoryId)}
                Imported on: {new Date(this.props.operation.dateImport).toLocaleString()}
                x

        );
    }
});

var SimilarityPairComponent = React.createClass({

    render: function() {

        var that = this;
        function makeOndelete(id) {
            return function() {
                assert(id === 'a' || id === 'b');
                var toDelete = that.props[id];
                var toKeep = that.props[(id === 'a') ? 'b' : 'a'];

                // If the one to delete had a category and the one to keep
                // doesn't, automatically transfer category.
                if (toDelete.categoryId !== -1 && toKeep.categoryId === -1) {
                    var catId = toDelete.categoryId;
                    flux.dispatch({
                        type: Events.OPERATION_CATEGORY_CHANGED,
                        operationId: toKeep.id,
                        categoryId: catId
                    });
                }

                flux.dispatch({
                    type: Events.DELETE_OPERATION,
                    operation: toDelete
                });
            }
        }

        return (

                <SimilarityItemComponent operation={this.props.a} ondelete={makeOndelete('a')} />
                <SimilarityItemComponent operation={this.props.b} ondelete={makeOndelete('b')} />

        );
    }
});

module.exports = React.createClass({

    getInitialState: function() {
        return {
            pairs: []
        };
    },

    _cb: function() {
        this.setState({
            pairs: findRedundantPairs(store.operations)
        });
    },

    componentDidMount: function() {
        store.subscribeMaybeGet(Events.OPERATIONS_LOADED, this._cb);
    },

    componentWillUnmount: function() {
        store.removeListener(Events.OPERATIONS_LOADED, this._cb);
    },

    render: function() {
        var pairs = this.state.pairs;
        if (pairs.length === 0) {
            return (

No similar operations found.

            )
        }

        var sim = pairs.map(function (p) {
            var key = p[0].id.toString() + p[1].id.toString();
            return (<SimilarityPairComponent key={key} a={p[0]} b={p[1]}  />)
        });
        return (

Similarities

                    {sim}

)
    }
});

<|endoftext|>


<commit_before>var cacheName = 'snap-pwa';
var filesToCache = [
    'snap.html',
    'src/morphic.js',
    'src/symbols.js',
    'src/widgets.js',
    'src/blocks.js',
    'src/threads.js',
    'src/objects.js',
    'src/scenes.js',
    'src/gui.js',
    'src/paint.js',
    'src/lists.js',
    'src/byob.js',
    'src/tables.js',
    'src/sketch.js',
    'src/video.js',
    'src/maps.js',
    'src/extensions.js',
    'src/xml.js',
    'src/store.js',
    'src/locale.js',
    'src/cloud.js',
    'src/api.js',
    'src/sha512.js',
    'src/FileSaver.min.js'
];

/* Start the service worker and cache all of the app's content */
self.addEventListener('install', function(e) {
  e.waitUntil(
    caches.open(cacheName).then(function(cache) {
      return cache.addAll(filesToCache);
    })
  );
});

/* Serve cached content when offline */
self.addEventListener('fetch', function(e) {
  e.respondWith(
    caches.match(e.request).then(function(response) {
      return response || fetch(e.request);
    })
  );
});
<commit_msg>make sure to cache libraries and media in pwa<commit_after>var cacheName = 'snap-pwa',
    filesToCache = [
        'snap.html',

        // program
        'src/morphic.js',
        'src/symbols.js',
        'src/widgets.js',
        'src/blocks.js',
        'src/threads.js',
        'src/objects.js',
        'src/scenes.js',
        'src/gui.js',
        'src/paint.js',
        'src/lists.js',
        'src/byob.js',
        'src/tables.js',
        'src/sketch.js',
        'src/video.js',
        'src/maps.js',
        'src/extensions.js',
        'src/xml.js',
        'src/store.js',
        'src/locale.js',
        'src/cloud.js',
        'src/api.js',
        'src/sha512.js',
        'src/FileSaver.min.js',

        // translations
        'locale/lang-ar.js',
        'locale/lang-bg.js',
        'locale/lang-bn.js',
        'locale/lang-ca.js',
        'locale/lang-ca_VA.js',
        'locale/lang-cs.js',
        'locale/lang-de.js',
        'locale/lang-dk.js',
        'locale/lang-el.js',
        'locale/lang-eo.js',
        'locale/lang-es.js',
        'locale/lang-et.js',
        'locale/lang-eu.js',
        'locale/lang-fi.js',
        'locale/lang-fr.js',
        'locale/lang-gl.js',
        'locale/lang-he.js',
        'locale/lang-hi.js',
        'locale/lang-hr.js',
        'locale/lang-hu.js',
        'locale/lang-ia.js',
        'locale/lang-id.js',
        'locale/lang-it.js',
        'locale/lang-ja_HIRA.js',
        'locale/lang-ja.js',
        'locale/lang-kn.js',
        'locale/lang-ko.js',
        'locale/lang-ml.js',
        'locale/lang-nl.js',
        'locale/lang-no.js',
        'locale/lang-pl.js',
        'locale/lang-pt_BR.js',
        'locale/lang-pt.js',
        'locale/lang-ro.js',
        'locale/lang-ru.js',
        'locale/lang-si.js',
        'locale/lang-sk.js',
        'locale/lang-sv.js',
        'locale/lang-ta.js',
        'locale/lang-te.js',
        'locale/lang-tr.js',
        'locale/lang-ua.js',
        'locale/lang-zh_CN.js',
        'locale/lang-zh_TW.js',

        //libraries
        'libraries/LIBRARIES',

        'libraries/animation_module.xml',
        'libraries/apl.xml',
        'libraries/audioComp_module.xml',
        'libraries/bar-charts.xml',
        'libraries/biginteger.js',
        'libraries/bignumbers.xml',
        'libraries/bignums.js',
        'libraries/cases.xml',
        'libraries/colors.xml',
        'libraries/Eisenbergification.xml',
        'libraries/frequency_distribution_module.xml',
        'libraries/httpBlocks.xml',
        'libraries/HummingbirdBlocks.xml',
        'libraries/iteration-composition.xml',
        'libraries/leap-library.xml',
        'libraries/list-utilities.xml',
        'libraries/localstorage_module.xml',
        'libraries/make-variables.xml',
        'libraries/maps_module.xml',
        'libraries/parallel_module.xml',
        'libraries/pixel_module.xml',
        'libraries/schemeNumber.js',
        'libraries/serial_module.xml',
        'libraries/speech_module.xml',
        'libraries/stream-tools.xml',
        'libraries/strings.xml',
        'libraries/textCostumes_module.xml',
        'libraries/try-catch.xml',
        'libraries/variadic-reporters.xml',
        'libraries/word-sentence.xml',

        //costumes
        'Costumes/COSTUMES',

        'Costumes/abby-a.svg',
        'Costumes/abby-b.svg',
        'Costumes/abby-c.svg',
        'Costumes/abby-d.svg',
        'Costumes/airplane2.png',
        'Costumes/alonzo.png',
        'Costumes/Alonzo3D.png',
        'Costumes/alonzo.svg',
        'Costumes/amon.gif',
        'Costumes/anina_pop_down.png',
        'Costumes/anina_pop_front.png',
        'Costumes/anina_pop_L_arm.png',
        'Costumes/anina_pop_left.png',
        'Costumes/anina_pop_R_arm.png',
        'Costumes/anina_pop_right.png',
        'Costumes/anina_pop_stand.png',
        'Costumes/anina_R_cross.png',
        'Costumes/anina_stance.png',
        'Costumes/anina_top_freeze.png',
        'Costumes/anina_top_L_step.png',
        'Costumes/anina_top_R_step.png',
        'Costumes/anina_top_stand.png',
        'Costumes/anna01.png',
        'Costumes/anna02.png',
        'Costumes/anna03.png',
        'Costumes/anna04.png',
        'Costumes/anna05.png',
        'Costumes/anna06.png',
        'Costumes/anna07b.png',
        'Costumes/anna07c.png',
        'Costumes/anna07.png',
        'Costumes/anna08.png',
        'Costumes/anna09.png',
        'Costumes/anna10.png',
        'Costumes/anna11.png',
        'Costumes/anna12.png',
        'Costumes/anna-a.png',
        'Costumes/anna-b.png',
        'Costumes/apple.svg',
        'Costumes/arrow1-a.svg',
        'Costumes/arrow1-b.svg',
        'Costumes/arrow1-c.svg',
        'Costumes/arrow1-d.svg',
        'Costumes/avery-a.svg',
        'Costumes/avery-b.svg',
        'Costumes/avery_walking-a.svg',
        'Costumes/avery_walking-b.svg',
        'Costumes/avery_walking-c.svg',
        'Costumes/avery_walking-d.svg',
        'Costumes/AZ_pop_down.png',
        'Costumes/AZ_pop_front.png',
        'Costumes/AZ_pop_L_arm.png',
        'Costumes/AZ_pop_left.png',
        'Costumes/AZ_pop_R_arm.png',
        'Costumes/AZ_pop_right.png',
        'Costumes/AZ_pop_stand.png',
        'Costumes/AZ_stance.png',
        'Costumes/AZ_top_freeze.png',
        'Costumes/AZ_top_L_step.png',
        'Costumes/AZ_top_R_cross.png',
        'Costumes/AZ_top_R_step.png',
        'Costumes/AZ_top_stand.png',
        'Costumes/ball-a.svg',
        'Costumes/ball-b.svg',
        'Costumes/ball-c.svg',
        'Costumes/ball-d.svg',
        'Costumes/ballerina-a.svg',
        'Costumes/ballerina-b.svg',
        'Costumes/ballerina-c.svg',
        'Costumes/ballerina-d.svg',
        'Costumes/ball-e.svg',
        'Costumes/balloon1-a.svg',
        'Costumes/balloon1-b.svg',
        'Costumes/balloon1-c.svg',
        'Costumes/ball-soccer.svg',
        'Costumes/bananas.svg',
        'Costumes/baseball.svg',
        'Costumes/basketball.svg',
        'Costumes/bass.svg',
        'Costumes/bat1-a_.svg',
        'Costumes/bat1-b_.svg',
        'Costumes/bat2-a_.svg',
        'Costumes/bat2-b_.svg',
        'Costumes/beachball.svg',
        'Costumes/bear2-a.svg',
        'Costumes/bear2-b.svg',
        'Costumes/beetle.svg',
        'Costumes/bell1.svg',
        'Costumes/bells-a.svg',
        'Costumes/bells-b.svg',
        'Costumes/bowl-a.svg',
        'Costumes/bowtie-a.svg',
        'Costumes/bowtie-b.svg',
        'Costumes/boy1-standing.gif',
        'Costumes/boy1-walking.gif',
        'Costumes/boy2.gif',
        'Costumes/boy3.gif',
        'Costumes/building-a.svg',
        'Costumes/building-b.svg',
        'Costumes/building-c.svg',
        'Costumes/building-d.svg',
        'Costumes/building-e.svg',
        'Costumes/building-f.svg',
        'Costumes/building-g.svg',
        'Costumes/building-h.svg',
        'Costumes/building-i.svg',
        'Costumes/building-j.svg',
        'Costumes/bus.png',
        'Costumes/butterfly1-a.svg',
        'Costumes/butterfly1-b_.svg',
        'Costumes/butterfly2_.svg',
        'Costumes/butterfly3_.svg',
        'Costumes/button1.svg',
        'Costumes/button2-a.svg',
        'Costumes/button2-b.svg',
        'Costumes/button3-a.svg',
        'Costumes/button3-b.svg',
        'Costumes/button4-a.svg',
        'Costumes/button4-b.svg',
        'Costumes/button5-a.svg',
        'Costumes/button5-b.svg',
        'Costumes/cake-a.svg',
        'Costumes/cake-b.svg',
        'Costumes/calvrett_jumping.png',
        'Costumes/calvrett_thinking.png',
        'Costumes/candle1-a.svg',
        'Costumes/candle1-b.svg',
        'Costumes/candles1.svg',
        'Costumes/candles2.svg',
        'Costumes/car-bug.png',
        'Costumes/cassy-a.png',
        'Costumes/cassy-b.png',
        'Costumes/cassy-c.png',
        'Costumes/cassy_dance-a.png',
        'Costumes/cassy_dance-b.png',
        'Costumes/cassy_dance-c.png',
        'Costumes/cassy_dance-d.png',
        'Costumes/cassy-d.png',
        'Costumes/cat2.gif',
        'Costumes/cat2.svg',
        'Costumes/cat3.png',
        'Costumes/cat4.png',
        'Costumes/cat5.gif',
        'Costumes/catherine-a.png',
        'Costumes/catherine-b.png',
        'Costumes/catherine-c.png',
        'Costumes/catherine-d.png',
        'Costumes/champ99-a.png',
        'Costumes/champ99-b.png',
        'Costumes/champ99-c.png',
        'Costumes/champ99-d.png',
        'Costumes/champ99-e.png',
        'Costumes/champ99-f.png',
        'Costumes/champ99-g.png',
        'Costumes/cheesy-puffs.png',
        'Costumes/cloud-a.svg',
        'Costumes/cloud-b.svg',
        'Costumes/cloud-c.svg',
        'Costumes/cloud-d.svg',
        'Costumes/cloud.svg',
        'Costumes/cm_pop_L_arm.png',
        'Costumes/cm_pop_R_arm.png',
        'Costumes/cm_top_L_cross.png',
        'Costumes/cm_top_L_leg.png',
        'Costumes/cm_top_R_cross.png',
        'Costumes/cm_top_ready.png',
        'Costumes/cm_top_R_leg.png',
        'Costumes/cm_top_stand.png',
        'Costumes/convertible1.png',
        'Costumes/convertible2.png',
        'Costumes/convertible3.svg',
        'Costumes/cowbell.svg',
        'Costumes/crab-a.svg',
        'Costumes/crab-b.svg',
        'Costumes/creature1-a.svg',
        'Costumes/creature1-b.svg',
        'Costumes/creature1-c.svg',
        'Costumes/cymbal-a.svg',
        'Costumes/cymbal-b.svg',
        'Costumes/dan-a.png',
        'Costumes/dan-b.png',
        'Costumes/dani-a.svg',
        'Costumes/dani-b.svg',
        'Costumes/dani-c.svg',
        'Costumes/dee-a.svg',
        'Costumes/dee-b.svg',
        'Costumes/dee-c.svg',
        'Costumes/dee-d.svg',
        'Costumes/dee-e.svg',
        'Costumes/devin-a.svg',
        'Costumes/devin-b.svg',
        'Costumes/devin-c.svg',
        'Costumes/devin-d.svg',
        'Costumes/dinosaur1-a.svg',
        'Costumes/dinosaur1-b.svg',
        'Costumes/dinosaur1-c.svg',
        'Costumes/dinosaur1-d.svg',
        'Costumes/dinosaur1-e.svg',
        'Costumes/dinosaur1-f.svg',
        'Costumes/dinosaur1-g.svg',
        'Costumes/dinosaur2-a.svg',
        'Costumes/dinosaur2-b.svg',
        'Costumes/dinosaur3.svg',
        'Costumes/diver1.svg',
        'Costumes/diver2.svg',
        'Costumes/dm_freeze.png',
        'Costumes/dm_pop_down.png',
        'Costumes/dm_pop_front.png',
        'Costumes/dm_pop_L_arm.png',
        'Costumes/dm_pop_left.png',
        'Costumes/dm_pop_R_arm.png',
        'Costumes/dm_pop_right.png',
        'Costumes/dm_pop_stand.png',
        'Costumes/dm_stance.svg',
        'Costumes/dm_top_L_leg.png',
        'Costumes/dm_top_R_leg.png',
        'Costumes/dm_top_stand.png',
        'Costumes/dog1-a.svg',
        'Costumes/dog1-b.svg',
        'Costumes/dog2-a.svg',
        'Costumes/dog2-b.svg',
        'Costumes/dog2-c.svg',
        'Costumes/dog_puppy_back.png',
        'Costumes/dog_puppy_right.png',
        'Costumes/dog_puppy_side.png',
        'Costumes/dog_puppy_sit.png',
        'Costumes/donut.svg',
        'Costumes/dove1-a.svg',
        'Costumes/dove1-b.svg',
        'Costumes/dove2-a.svg',
        'Costumes/dove2-b.svg',
        'Costumes/dragon1-a.svg',
        'Costumes/dragon1-b.png',
        'Costumes/dragon1-b.svg',
        'Costumes/dragon2.gif',
        'Costumes/drum1-a.svg',
        'Costumes/drum1-b.svg',
        'Costumes/drum2-a.svg',
        'Costumes/drum2-b.svg',
        'Costumes/drum_bass-a.svg',
        'Costumes/drum_bass-b.svg',
        'Costumes/drums_conga-a.svg',
        'Costumes/drums_conga-b.svg',
        'Costumes/drum_snare-a.svg',
        'Costumes/drum_snare-b.svg',
        'Costumes/duck.svg',
        'Costumes/earth.svg',
        'Costumes/elephant-a_.svg',
        'Costumes/elephant-b_.svg',
        'Costumes/fire_hydrant.png',
        'Costumes/fish1.svg',
        'Costumes/fish2.svg',
        'Costumes/fish3.svg',
        'Costumes/flower_shape.svg',
        'Costumes/football_running.png',
        'Costumes/football_standing.png',
        'Costumes/fortunecookie.png',
        'Costumes/fox.svg',
        'Costumes/frog.svg',
        'Costumes/fruit_platter.png',
        'Costumes/fruitsalad.svg',
        'Costumes/ghost1_.svg',
        'Costumes/ghost2-a.svg',
        'Costumes/ghost2-b.svg',
        'Costumes/ghoul-a.svg',
        'Costumes/ghoul-b.svg',
        'Costumes/gift-a.svg',
        'Costumes/gift-b.svg',
        'Costumes/girl1-standing.gif',
        'Costumes/girl1-walking.gif',
        'Costumes/girl2-shouting.gif',
        'Costumes/girl2-standing.gif',
        'Costumes/girl3-basketball.gif',
        'Costumes/girl3-running.gif',
        'Costumes/girl3-standing.gif',
        'Costumes/glasses.svg',
        'Costumes/glass_water-a.svg',
        'Costumes/glass_water-b.svg',
        'Costumes/green_flag.svg',
        'Costumes/guitar_bass.svg',
        'Costumes/guitar_electric.svg',
        'Costumes/guitar.svg',
        'Costumes/hannah-a.png',
        'Costumes/hannah-b.png',
        'Costumes/hannah-c.png',
        'Costumes/hat_beanie.svg',
        'Costumes/hat_party2-a.svg',
        'Costumes/Hat.svg',
        'Costumes/hat_winter.svg',
        'Costumes/hat_wizard.svg',
        'Costumes/headband.svg',
        'Costumes/heart_code.svg',
        'Costumes/heart_face.svg',
        'Costumes/heart_love_it.svg',
        'Costumes/heart_purple.svg',
        'Costumes/heart_red.svg',
        'Costumes/heart_smile.svg',
        'Costumes/heart_sweet.svg',
        'Costumes/helicopter.png',
        'Costumes/hippo1-a.svg',
        'Costumes/hippo1-b.svg',
        'Costumes/holly1.svg',
        'Costumes/holly2.svg',
        'Costumes/home_button.svg',
        'Costumes/horse1-a.svg',
        'Costumes/horse1-b.svg',
        'Costumes/jaime-a.png',
        'Costumes/jaime-b.png',
        'Costumes/jaime_walking-a.png',
        'Costumes/jaime_walking-b.png',
        'Costumes/jaime_walking-c.png',
        'Costumes/jaime_walking-d.png',
        'Costumes/jaime_walking-e.png',
        'Costumes/jay.gif',
        'Costumes/jeans-a.svg',
        'Costumes/jeans-b.svg',
        'Costumes/jodi.gif',
        'Costumes/jo_pop_down.png',
        'Costumes/jo_pop_front.png',
        'Costumes/jo_pop_L_arm.png',
        'Costumes/jo_pop_left.png',
        'Costumes/jo_pop_R_arm.png',
        'Costumes/jo_pop_right.png',
        'Costumes/jo_pop_stand.png',
        'Costumes/jo_stance.png',
        'Costumes/jo_top_L_cross.png',
        'Costumes/jo_top_L_leg.png',
        'Costumes/jo_top_R_cross.png',
        'Costumes/jo_top_R_leg.png',
        'Costumes/jo_top_stand.png',
        'Costumes/keyboard-a.svg',
        'Costumes/keyboard-b.svg',
        'Costumes/keyboard-c.svg',
        'Costumes/keyboard-d.svg',
        'Costumes/key.svg',
        'Costumes/khalid-a.png',
        'Costumes/Khalid-b.png',
        'Costumes/khalid-c.png',
        'Costumes/khalid-d.png',
        'Costumes/knight.svg',
        'Costumes/ladybug2-a.svg',
        'Costumes/ladybug2-b.svg',
        'Costumes/ladybug2.svg',
        'Costumes/lamp.png',
        'Costumes/laptop.svg',
        'Costumes/lb_pop_down.png',
        'Costumes/lb_pop_front.png',
        'Costumes/lb_pop_L_arm.png',
        'Costumes/lb_pop_left.png',
        'Costumes/lb_pop_R_arm.png',
        'Costumes/lb_pop_right.png',
        'Costumes/lb_pop_stand.png',
        'Costumes/lb_stance.png',
        'Costumes/lb_top_L_cross.png',
        'Costumes/lb_top_L_leg.png',
        'Costumes/lb_top_R_cross.png',
        'Costumes/lb_top_R_leg.png',
        'Costumes/lb_top_stand.png',
        'Costumes/lightning.svg',
        'Costumes/lion-a.svg',
        'Costumes/lion-b.svg',
        'Costumes/lioness.svg',
        'Costumes/lorenz01.png',
        'Costumes/lorenz02.png',
        'Costumes/lorenz03.png',
        'Costumes/lorenz04.png',
        'Costumes/lorenz05.png',
        'Costumes/lorenz06.png',
        'Costumes/lorenz07b.png',
        'Costumes/lorenz07.png',
        'Costumes/magiccarpet.png',
        'Costumes/magicwand.svg',
        'Costumes/marble-building.png',
        'Costumes/marissa-crouching.gif',
        'Costumes/marissa.gif',
        'Costumes/marissa-sitting.gif',
        'Costumes/maya.png',
        'Costumes/microphonestand.svg',
        'Costumes/microphone.svg',
        'Costumes/monkey1-a.svg',
        'Costumes/monkey1-b.svg',
        'Costumes/monkey2-a.svg',
        'Costumes/monkey2-b.svg',
        'Costumes/monkey2-c.svg',
        'Costumes/mori.png',
        'Costumes/mouse1-a.svg',
        'Costumes/mouse1-b.svg',
        'Costumes/muffin-a.svg',
        'Costumes/muffin-b.svg',
        'Costumes/octopus-a.svg',
        'Costumes/octopus-b.svg',
        'Costumes/orange2-a.svg',
        'Costumes/orange2-b.svg',
        'Costumes/orange2-c.svg',
        'Costumes/orange.svg',
        'Costumes/paddle.svg',
        'Costumes/palmtree.gif',
        'Costumes/parrot2-a.svg',
        'Costumes/parrot2-b.svg',
        'Costumes/parrot-a.svg',
        'Costumes/parrot-b.svg',
        'Costumes/partyhat1.svg',
        'Costumes/paul.gif',
        'Costumes/pencil-a.svg',
        'Costumes/pencil-b.svg',
        'Costumes/penguin1.svg',
        'Costumes/penguin1_talk-a.svg',
        'Costumes/penguin1_talk-b.svg',
        'Costumes/penguin2.svg',
        'Costumes/penguin2_talk-a.svg',
        'Costumes/penguin2_talk-b.svg',
        'Costumes/penguin3-a.svg',
        'Costumes/penguin3-b.svg',
        'Costumes/penguin3-c.svg',
        'Costumes/piano.svg',
        'Costumes/planet2.svg',
        'Costumes/princess.svg',
        'Costumes/prince.svg',
        'Costumes/rainbow.svg',
        'Costumes/referee.gif',
        'Costumes/reindeer.svg',
        'Costumes/robot1.svg',
        'Costumes/rocks.svg',
        'Costumes/rory.png',
        'Costumes/ruby-a.png',
        'Costumes/ruby-b.png',
        'Costumes/sail-boat.png',
        'Costumes/sam.gif',
        'Costumes/saxophone-a.svg',
        'Costumes/saxophone-b.svg',
        'Costumes/scarf1.svg',
        'Costumes/scarf2.svg',
        'Costumes/shark-a_.svg',
        'Costumes/shark-b_.svg',
        'Costumes/shark-c_.svg',
        'Costumes/shirt2-a2.svg',
        'Costumes/shirt2-a.svg',
        'Costumes/shirt-a.svg',
        'Costumes/shirt_blouse.svg',
        'Costumes/shirt-b.svg',
        'Costumes/shirt_collar-a.svg',
        'Costumes/shirt_collar-b.svg',
        'Costumes/shirt_collar-c.svg',
        'Costumes/shoes1.svg',
        'Costumes/shoes2.svg',
        'Costumes/Singer1.svg',
        'Costumes/skates.svg',
        'Costumes/sl_pop_L_arm.png',
        'Costumes/sl_pop_R_arm.png',
        'Costumes/sl_top_L_cross.png',
        'Costumes/sl_top_L_leg.png',
        'Costumes/sl_top_R_cross.png',
        'Costumes/sl_top_ready.png',
        'Costumes/sl_top_R_leg.png',
        'Costumes/sl_top_stand.png',
        'Costumes/snowflake.svg',
        'Costumes/snowman.svg',
        'Costumes/spaceship-a.svg',
        'Costumes/spaceship-b.svg',
        'Costumes/speaker.svg',
        'Costumes/squirrel1.png',
        'Costumes/star1.svg',
        'Costumes/star2.svg',
        'Costumes/star3-a.svg',
        'Costumes/star3-b.svg',
        'Costumes/starfish-a.svg',
        'Costumes/starfish-b_.svg',
        'Costumes/stop.svg',
        'Costumes/street-cleaner-mit.png',
        'Costumes/sunglasses1.svg',
        'Costumes/sunglasses2.svg',
        'Costumes/sun.svg',
        'Costumes/tabla-a.svg',
        'Costumes/tabla-b.svg',
        'Costumes/taco-a.svg',
        'Costumes/taco-b.svg',
        'Costumes/tennisball.png',
        'Costumes/trampoline.png',
        'Costumes/tree1.svg',
        'Costumes/tree2.svg',
        'Costumes/tree-lights-a.svg',
        'Costumes/tree-lights-b.svg',
        'Costumes/trees-a.svg',
        'Costumes/trees-b.svg',
        'Costumes/trombone-a.svg',
        'Costumes/trombone-b.svg',
        'Costumes/trumpet-a2.svg',
        'Costumes/trumpet-a.svg',
        'Costumes/ukulele.svg',
        'Costumes/umbrella.png',
        'Costumes/unicorn1.png',
        'Costumes/unicorn.svg',
        'Costumes/vest-a.svg',
        'Costumes/vest-b.svg',
        'Costumes/wanda.svg',
        'Costumes/watermelon-a.svg',
        'Costumes/watermelon-b.svg',
        'Costumes/watermelon-c.svg',
        'Costumes/witch.svg',
        'Costumes/wizard1.svg',
        'Costumes/wizard2.svg',
        'Costumes/wizard.svg',

        // Backgrounds
        'Backgrounds/BACKGROUNDS',

        'Backgrounds/atom_playground.jpg',
        'Backgrounds/bedroom1.gif',
        'Backgrounds/bedroom2.gif',
        'Backgrounds/berkeley_mural.jpg',
        'Backgrounds/brick-wall-and-stairs.jpg',
        'Backgrounds/brick-wall1.jpg',
        'Backgrounds/brick-wall2.jpg',
        'Backgrounds/desert.gif',
        'Backgrounds/night_city_with_street.gif',
        'Backgrounds/party_room.jpg',
        'Backgrounds/pathway.jpg',
        'Backgrounds/xy-grid.gif',

        // Sounds
        'Sounds/SOUNDS',

        'Sounds/Cat.mp3',
        'Sounds/Chord.wav',
        'Sounds/Dog1.wav',
        'Sounds/Dog2.wav',
        'Sounds/FingerSnap.wav',
        'Sounds/Kitten.wav',
        'Sounds/Laugh-female.wav',
        'Sounds/Laugh-male1.wav',
        'Sounds/Laugh-male2.wav',
        'Sounds/Laugh-male3.mp3',
        'Sounds/Meow.wav',
        'Sounds/Pop.wav',

        // Examples
        'Examples/EXAMPLES',

        'Examples/animal-game.xml',
        'Examples/Codification.xml',
        'Examples/copter.xml',
        'Examples/count-change.xml',
        'Examples/icecream-visual.xml',
        'Examples/JSfunctions.xml',
        'Examples/live-tree.xml',
        'Examples/swimmer.xml',
        'Examples/tree.xml',
        'Examples/vee.xml',
    ];

/* Start the service worker and cache all of the app's content */
self.addEventListener('install', function(e) {
    e.waitUntil(
        caches.open(cacheName).then(function(cache) {
            return cache.addAll(filesToCache);
        })
    );
});

self.addEventListener('activate', (evt) => {
    evt.waitUntil(
        caches.keys().then((keyList) => {
            return Promise.all(keyList.map((key) => {
                if (key !== cacheName) {
                    return caches.delete(key);
                }
            }));
        })
    );
    self.clients.claim();
});

/* Serve cached content when offline */
self.addEventListener('fetch', function(e) {
    e.respondWith(
        caches.match(e.request).then(function(response) {
            return response || fetch(e.request);
        })
    );
});
<|endoftext|>


<commit_before>const CACHE_NAME = 'neutron-v1';
const urlsToCache = [
  '/index.html',
  '/styles/main.css',
  '/styles/bootstrap.min.css',
  '/images/3246305.jpg',
  '/index.19fb4943df0cf427704a.bundle.js',
  '/manifest.1487ea393e348f6eea30.bundle.js',
  '/scripts/loadsw.js',
  '/scripts/bootstrap.min.js',
  '/scripts/jquery-3.1.1.slim.min.js',
  '/scripts/tether.min.js',
];

self.addEventListener('install', function(event) {
  // Perform install steps
  console.log('Installing SW!');
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(urlsToCache);
      })
  );
});

this.addEventListener('activate', function(event) {
  const cacheWhitelist = [CACHE_NAME];

  event.waitUntil(
    caches.keys().then(function(keyList) {
      return Promise.all(keyList.map(function(key) {
        if (cacheWhitelist.indexOf(key) === -1) {
          return caches.delete(key);
        }
      }));
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Cache hit - return response
        if (response) {
          return response;
        }

        // IMPORTANT: Clone the request. Since we are consuming this
        // once by cache and once by the browser for fetch, we need
        // to clone the response.
        var fetchRequest = event.request.clone();

        return fetch(fetchRequest).then(
          function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              return response;
            }

            // We want the browser to consume the response
            // as well as the cache consuming the response, we need
            // to clone it so we have two streams.
            var responseToCache = response.clone();

            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });

            return response;
          }
        );
      })
    );
});
<commit_msg>Updated main Service Worker.<commit_after>const cacheVersion = '1.0.0';
const staticCacheName = `musale-v${cacheVersion}`;
const filesToCache = [
  './',
  '/(index)',
  '/styles/main.css',
  '/styles/bootstrap.min.css',
  '/images/3246305.jpg',
  '/images/001.svg',
  '/images/002.png',
  '/images/003.png',
  '/images/004.jpg',
  '/images/005.jpg',
  '/index.bundle.js',
  '/manifest.bundle.js',
  '/scripts/loadsw.js',
  '/scripts/bootstrap.min.js',
  '/scripts/jquery-3.1.1.slim.min.js',
  '/scripts/tether.min.js',
  'https://farm6.staticflickr.com/5510/14338202952_93595258ff_z.jpg',
  'https://fonts.gstatic.com/s/raleway/v11/yQiAaD56cjx1AooMTSghGfY6323mHUZFJMgTvxaG2iE.woff2',
  'https://fonts.gstatic.com/s/raleway/v11/0dTEPzkLWceF7z0koJaX1A.woff2',
  'https://placehold.it/355x250',
];

this.addEventListener('install', function(event) {
  event.waitUntil(caches.open(staticCacheName).then(function(cache) {
    return cache.addAll(filesToCache);
  }));
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request).then(function(response) {
      return response || fetch(event.request);
    })
  );
});

self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.filter(function(cacheName) {
          return cacheName.startsWith('musale-v') &&
                 cacheName != staticCacheName;
        }).map(function(cacheName) {
          return caches.delete(cacheName);
        })
      );
    })
  );
});
<|endoftext|>


<commit_before>var cacheName = 'tools';
var cacheFiles = [
  '/',
  '/index.html',
  '/tools.html',
  '/calc.html',
  '/hypothesis.html',
  '/utm.html',
  '/dencoder.html',
  '/check.html',
  '/test.html'
];

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(cacheName)
    .then(function(cache) {
      return cache.addAll(cacheFiles);
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Grab the asset from SW cache.
        if (response) {
          return response;
        }
        return fetch(event.request);
    }).catch(function() {
      // Can't access the network return an offline page from the cache
      return caches.match('/tools.html');
    })
  );
});

// Empty out any caches that don’t match the ones listed.
self.addEventListener('activate', function(event) {
  var cacheWhitelist = ['tools'];
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});<commit_msg>ServiceWorker<commit_after>var cacheName = 'tools';
var cacheFiles = [
  '/',
  '/index.html',
  '/tools.html',
  '/calc.html',
  '/hypothesis.html',
  '/utm.html',
  '/dencoder.html',
  '/check.html'
];

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(cacheName)
    .then(function(cache) {
      return cache.addAll(cacheFiles);
    })
  );
});

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
      .then(function(response) {
        // Grab the asset from SW cache.
        if (response) {
          return response;
        }
        return fetch(event.request);
    }).catch(function() {
      // Can't access the network return an offline page from the cache
      return caches.match('/tools.html');
    })
  );
});

// Empty out any caches that don’t match the ones listed.
self.addEventListener('activate', function(event) {
  var cacheWhitelist = ['tools'];
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});<|endoftext|>


<commit_before>var CACHE_NAME = 'citybookV5';

var cityBookUrls = [
  './',
  '/static/bundle.js'
];

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(cityBookUrls);
      })
  );
});

self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (CACHE_NAME !== cacheName) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
  return self.clients.claim();
});

// Add an event listener for when the browser fetches
self.addEventListener('fetch', function(event) {
  // Respond to the event with a promise
  event.respondWith(
    // Check if we have the file in our cache
    caches.match(event.request)
      .then(function(response) {
        // If we find it, return it
        if (response) {
          return response;
        }

        // If we can't find the file, we clone the request
        var fetchRequest = event.request.clone();

        // Return the request we need to make
        return fetch(fetchRequest).then(
          function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              // If not, we just return it
              return response;
            }
            // Clone the response to put in the cache
            var responseToCache = response.clone();

            // Add the cloned resource to our cache
            caches.open(CACHE_NAME)
              .then(function(cache) {
                cache.put(event.request, responseToCache);
              });

            return response;
          }
        );
      })
    );
});
<commit_msg>Update serviceworker with spreadsheet cache<commit_after>var CITYBOOK_CACHE = 'citybookV9';
var SPREADSHEET_CACHE = 'spreadsheetV1';

var cityBookUrls = [
  './',
  '/static/bundle.js'
];

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CITYBOOK_CACHE)
      .then(function(cache) {
        console.log('Opened cache');
        return cache.addAll(cityBookUrls);
      })
  );
});

self.addEventListener('activate', function(event) {
  event.waitUntil(
    caches.keys().then(function(cacheNames) {
      return Promise.all(
        cacheNames.map(function(cacheName) {
          if (CITYBOOK_CACHE !== cacheName && SPREADSHEET_CACHE !== cacheName) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
  return self.clients.claim();
});

// Add an event listener for when the browser fetches
self.addEventListener('fetch', function(event) {
  console.log('fetch event happened');
  var dataUrl = 'https://spreadsheets.google.com';

  if(event.request.url.indexOf(dataUrl) > -1){
    console.log('fetching from google');
    event.respondWith(
      caches.open(SPREADSHEET_CACHE).then(function(cache) {
        return fetch(event.request).then(function(response){
          cache.put(event.request.url, response.clone());
          return response;
        });
      })
    );
  } else {
    // Respond to the event with a promise
    event.respondWith(
      // Check if we have the file in our cache
      caches.match(event.request)
      .then(function(response) {
        // If we find it, return it
        if (response) {
          return response;
        }

        // If we can't find the file, we clone the request
        var fetchRequest = event.request.clone();

        // Return the request we need to make
        return fetch(fetchRequest).then(
          function(response) {
            // Check if we received a valid response
            if(!response || response.status !== 200 || response.type !== 'basic') {
              // If not, we just return it
              return response;
            }
            // Clone the response to put in the cache
            var responseToCache = response.clone();

            // Add the cloned resource to our cache
            caches.open(CITYBOOK_CACHE)
            .then(function(cache) {
              cache.put(event.request, responseToCache);
            });

            return response;
          }
        );
      })
    );
  }
});
<|endoftext|>


<commit_before>import React from 'react';
import {PropTypes} from 'prop-types';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';

class TeamVotePage extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.saveVote = this.saveVote.bind(this);
  }

  saveVote() {
    alert('call save vote!');
  }

  render() {
    return (

{this.props.team.name} - Voting

          {this.props.categories && this.props.categories.map(c =>

{c.name}

                  <input type="radio" name={c.id + "vote"} id={c.id + "_vote_1"} autoComplete="off" />1

                  <input type="radio" name={c.id + "vote"} id={c.id + "_vote_1"} autoComplete="off" />2

                  <input type="radio" name={c.id + "vote"} id={c.id + "_vote_1"} autoComplete="off" />3

                  <input type="radio" name={c.id + "vote"} id={c.id + "_vote_1"} autoComplete="off" />4

                  <input type="radio" name={c.id + "vote"} id={c.id + "_vote_1"} autoComplete="off" />5

          )}

          <input className="btn btn-primary" type="submit" value="Save" onClick={this.saveVote} />

    );
  }
}

TeamVotePage.propTypes = {
  categories: PropTypes.array.isRequired,
  eventId: PropTypes.string.isRequired,
  team: PropTypes.object.isRequired
};

function getEventById(events, eventId) {
  const filteredEvents = events.filter(e => e.id === eventId);
  if (filteredEvents.length) { return filteredEvents[0]; }
  return {};
}

function getInitialEvent() {
  let categories = [{id: 0, name: '', weight: 0.0}];
  let teams = [{id: 0, description: '', members: []}]
  return {id: '', title: '', startDate: '', endDate: '', categories: categories, teams: teams};
}

const mapStateToProps = (state, ownProps) => {
  debugger;
  const eventId = ownProps.match.params.event_id; // from /vote/<event_id>/team/<team_id>
  const teamId = ownProps.match.params.team_id; // from /vote/<event_id>/team/<team_id>
  let event = getInitialEvent();
  let team = event.teams[0];
  if (eventId && state.events.length) {
    event = getEventById(state.events, eventId);
    team = event.teams.filter(t => t._id === teamId)[0];
  }

  return {
    team: team,
    categories: event.categories,
    eventId: eventId
  };
};

// const mapDispatchToProps = (dispatch, ownProps) => {
//   return {
//     actions: bindActionCreators(actions, dispatch)
//   };
// }

export default connect(mapStateToProps)(TeamVotePage);<commit_msg>- Getting Checked values from bootstrap radio buttons<commit_after>import React from 'react';
import {PropTypes} from 'prop-types';
import { connect } from 'react-redux';
import {bindActionCreators} from 'redux';
import jquery from 'jquery';

class TeamVotePage extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.state = {
      categories: props.categories
    };

    this.saveVote = this.saveVote.bind(this);
  }

  saveVote() {
    debugger;
    for (let i = 0; i < this.props.categories.length; i++) {
      let radio = jquery('[name=' + i + 'vote]:checked');
      console.log(radio.val());
    }
  }

  render() {
    return (

{this.props.team.name} - Voting

          {this.props.categories && this.props.categories.map(c =>

{c.name}

                  <input type="radio" name={c.id + "vote"} value="1" autoComplete="off" />1

                  <input type="radio" name={c.id + "vote"} value="2" autoComplete="off" />2

                  <input type="radio" name={c.id + "vote"} value="3" autoComplete="off" />3

                  <input type="radio" name={c.id + "vote"} value="4" autoComplete="off" />4

                  <input type="radio" name={c.id + "vote"} value="5" autoComplete="off" />5

          )}

          <input className="btn btn-primary" type="submit" value="Save" onClick={this.saveVote} />

    );
  }
}

TeamVotePage.propTypes = {
  categories: PropTypes.array.isRequired,
  eventId: PropTypes.string.isRequired,
  team: PropTypes.object.isRequired
};

function getEventById(events, eventId) {
  const filteredEvents = events.filter(e => e.id === eventId);
  if (filteredEvents.length) { return filteredEvents[0]; }
  return {};
}

function getInitialEvent() {
  let categories = [{id: 0, name: '', weight: 0.0}];
  let teams = [{id: 0, description: '', members: []}];
  return {id: '', title: '', startDate: '', endDate: '', categories: categories, teams: teams};
}

const mapStateToProps = (state, ownProps) => {
  debugger;
  const eventId = ownProps.match.params.event_id; // from /vote/<event_id>/team/<team_id>
  const teamId = ownProps.match.params.team_id; // from /vote/<event_id>/team/<team_id>
  let event = getInitialEvent();
  let team = event.teams[0];
  if (eventId && state.events.length) {
    event = getEventById(state.events, eventId);
    team = event.teams.filter(t => t._id === teamId)[0];
  }

  return {
    team: team,
    categories: event.categories,
    eventId: eventId
  };
};

// const mapDispatchToProps = (dispatch, ownProps) => {
//   return {
//     actions: bindActionCreators(actions, dispatch)
//   };
// }

export default connect(mapStateToProps)(TeamVotePage);<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import {Button, TextField, SimpleSwitch} from 'ui/admin'
import FileDrop from '../FileDrop'
import TypePicker from '../TypePicker'
import config from 'gen/config'
import _t from 'util/i18n'
import ContentEditable from './ContentEditable'
import {withStyles} from 'ui/admin'

const styles = theme => ({
    editor: {
        border: '1px solid ' + theme.palette.grey['200'],
        padding: theme.spacing.unit,
        margin: theme.spacing.unit * 3 + ' 0',
        maxHeight: 100,
        overflow: 'auto'
    }
})

class GenericForm extends React.Component {
    constructor(props) {
        super(props)
        this.state = this.getInitalState(props)
    }

    shouldComponentUpdate(props, state) {
        return props.fields !== this.props.fields || state !== this.state
    }

    componentWillReceiveProps(props) {
        if (props.fields !== this.props.fields) {
            this.setState(this.getInitalState(props))
        }
    }

    componentDidMount() {
        this.setValidateState(this.state)
    }

    setValidateState(state) {
        if (this.props.onValidate) {
            this.setState({isValid: this.validate(state)})
        }
    }

    validate(state) {
        let theState

        if (state) {
            theState = state
        } else {
            theState = this.state
        }

        const {fields, onValidate} = this.props

        const fieldErrors = {}
        Object.keys(fields).forEach(k => {
            const field = fields[k]
            if (field.required) {

                if (field.reference) {
                    let fieldValue = theState.fields[k]
                    if (fieldValue && fieldValue.length) {
                        fieldValue = fieldValue[0]
                    }
                    if (!fieldValue || !fieldValue._id) {
                        fieldErrors[k] = _t('GenericForm.validation.required')
                    }
                } else {
                    if (field.localized) {
                        config.LANGUAGES.forEach(lang => {
                            const newKey = k + '_localized'
                            if (!theState.fields[newKey] || !theState.fields[newKey][lang]) {
                                fieldErrors[newKey + '.' + lang] = _t('GenericForm.validation.required')
                            }
                        })
                    } else {
                        if (!theState.fields[k] || theState.fields[k].trim() === '') {
                            fieldErrors[k] = _t('GenericForm.validation.required')
                        }
                    }
                }
            }
        })
        if (Object.keys(fieldErrors).length || Object.keys(this.state.fieldErrors).length) {
            this.setState({fieldErrors})
        }

        if (Object.keys(fieldErrors).length) {
            return false
        }

        if (onValidate) {
            return onValidate(theState.fields)
        }
        return true
    }

    getInitalState = (props) => {
        const initalState = {fields: {}, fieldErrors: {}, isValid: true}
        Object.keys(props.fields).map(k => {
            const item = props.fields[k]
            let v
            if (props.values) {
                v = props.values[k]
            } else {
                // value must be null instead of undefined
                v = item.value === undefined ? null : item.value
            }
            initalState.fields[k] = v
            if (item.localized) {
                v = props.values ? props.values[k + '_localized'] : null
                initalState.fields[k + '_localized'] = v ? Object.assign({}, v) : null
            }
        })
        return initalState
    }

    reset = () => {
        this.setState(this.getInitalState(this.props))
        this.setValidateState(this.state)
    }

    handleInputChange = (e) => {
        const target = e.target
        const value = target.type === 'checkbox' ? target.checked : target.value
        const name = target.name
        this.setState((prevState) => {
            const newState = Object.assign({}, {fields: {}}, prevState)
            const path = name.split('.')
            if (path.length == 2) {
                if (!newState.fields[path[0]]) {
                    newState.fields[path[0]] = {}
                }
                newState.fields[path[0]][path[1]] = value
            } else {
                newState.fields[name] = value
            }
            if (this.props.onChange) {
                this.props.onChange({name, value})
            }
            newState.isValid = this.validate(newState)
            return newState
        })
    }

    onAddClick = () => {
        if (this.props.onClick)
            this.props.onClick(this.state.fields)
        this.setState(this.getInitalState(this.props))
    }

    render() {
        const {fields, onKeyDown, primaryButton, caption, autoFocus, classes} = this.props
        return (
            <form>
                {
                    Object.keys(fields).map((k, i) => {
                        const o = fields[k],
                            value = this.state.fields[k]

                        const uitype = o.uitype || 'text'

                        if (uitype === 'editor' || uitype === 'jseditor') {
                            let highlight, json
                            if( uitype === 'jseditor'){
                                highlight = 'js'
                            }else
                            if (value) {
                                // detect type
                                try {
                                    json = JSON.stringify(JSON.parse(value), null, 4)
                                    highlight = 'json'
                                } catch (e) {

                                }
                            }
                            return <ContentEditable className={classes.editor} highlight={highlight}
                                                    onChange={(v) => this.handleInputChange({
                                                        target: {
                                                            name: k,
                                                            value: v
                                                        }
                                                    })}
                                                    key={k}
                                                    setHtml={false}>{json ? json : value}</ContentEditable>

                        }
                        if (uitype === 'image') {
                            return <FileDrop key={k}/>
                        } else if (uitype === 'type_picker') {
                            return <TypePicker value={(value ? (value.constructor === Array ? value : [value]) : null)}
                                               error={!!this.state.fieldErrors[k]}
                                               helperText={this.state.fieldErrors[k]}
                                               onChange={this.handleInputChange} key={k}
                                               name={k}
                                               label={o.label}
                                               multi={o.multi}
                                               field={o.pickerField}
                                               type={o.type} placeholder={o.placeholder}/>
                        } else if (uitype === 'select') {

                            //TODO: implement
                        } else if (o.type === 'Boolean') {

                            return <SimpleSwitch key={k} label={o.placeholder} name={k}
                                                 onChange={this.handleInputChange} checked={value ? true : false}/>

                        } else {
                            if (o.localized) {

                                return config.LANGUAGES.reduce((a, l) => {
                                    const valueLocalized = this.state.fields[k + '_localized']
                                    const fieldName = k + '_localized.' + l
                                    a.push(<TextField key={fieldName}
                                                      error={!!this.state.fieldErrors[fieldName]}
                                                      helperText={this.state.fieldErrors[fieldName]}
                                                      label={o.label}
                                                      fullWidth={o.fullWidth}
                                                      type={uitype}
                                                      placeholder={o.placeholder + ' [' + l + ']'}
                                                      value={(valueLocalized && valueLocalized[l] ? valueLocalized[l] : '')}
                                                      name={fieldName}
                                                      onKeyDown={(e) => {
                                                          onKeyDown && onKeyDown(e, valueLocalized[l])
                                                      }}
                                                      onChange={this.handleInputChange}/>)
                                    return a
                                }, [])
                            } else {
                                return <TextField autoFocus={autoFocus && i === 0} error={!!this.state.fieldErrors[k]}
                                                  key={k}
                                                  label={o.label}
                                                  helperText={this.state.fieldErrors[k]}
                                                  fullWidth={o.fullWidth}
                                                  type={uitype}
                                                  placeholder={o.placeholder}
                                                  value={value || ''}
                                                  name={k}
                                                  onKeyDown={(e) => {
                                                      onKeyDown && onKeyDown(e, value)
                                                  }}
                                                  onChange={this.handleInputChange}/>
                            }

                        }
                    })
                }
                {primaryButton != false ?
                    <Button color="primary" variant="raised" disabled={!this.state.isValid}
                            onClick={this.onAddClick}>{caption || 'Add'}</Button>
                    : ''}
            </form>
        )
    }
}

GenericForm.propTypes = {
    fields: PropTypes.object.isRequired,
    values: PropTypes.object,
    onClick: PropTypes.func,
    onKeyDown: PropTypes.func,
    onValidate: PropTypes.func,
    caption: PropTypes.string,
    primaryButton: PropTypes.bool,
    classes: PropTypes.object.isRequired,
    autoFocus: PropTypes.bool
}

export default withStyles(styles)(GenericForm)<commit_msg>Small improvments<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import {Button, TextField, SimpleSwitch} from 'ui/admin'
import FileDrop from '../FileDrop'
import TypePicker from '../TypePicker'
import config from 'gen/config'
import _t from 'util/i18n'
import ContentEditable from './ContentEditable'
import {withStyles} from 'ui/admin'

const styles = theme => ({
    editor: {
        border: '1px solid ' + theme.palette.grey['200'],
        padding: theme.spacing.unit,
        margin: theme.spacing.unit * 3 + 'px 0',
        maxHeight: 200,
        overflow: 'auto'
    }
})

class GenericForm extends React.Component {
    constructor(props) {
        super(props)
        this.state = this.getInitalState(props)
    }

    shouldComponentUpdate(props, state) {
        return props.fields !== this.props.fields || state !== this.state
    }

    componentWillReceiveProps(props) {
        if (props.fields !== this.props.fields) {
            this.setState(this.getInitalState(props))
        }
    }

    componentDidMount() {
        this.setValidateState(this.state)
    }

    setValidateState(state) {
        if (this.props.onValidate) {
            this.setState({isValid: this.validate(state)})
        }
    }

    validate(state) {
        let theState

        if (state) {
            theState = state
        } else {
            theState = this.state
        }

        const {fields, onValidate} = this.props

        const fieldErrors = {}
        Object.keys(fields).forEach(k => {
            const field = fields[k]
            if (field.required) {

                if (field.reference) {
                    let fieldValue = theState.fields[k]
                    if (fieldValue && fieldValue.length) {
                        fieldValue = fieldValue[0]
                    }
                    if (!fieldValue || !fieldValue._id) {
                        fieldErrors[k] = _t('GenericForm.validation.required')
                    }
                } else {
                    if (field.localized) {
                        config.LANGUAGES.forEach(lang => {
                            const newKey = k + '_localized'
                            if (!theState.fields[newKey] || !theState.fields[newKey][lang]) {
                                fieldErrors[newKey + '.' + lang] = _t('GenericForm.validation.required')
                            }
                        })
                    } else {
                        if (!theState.fields[k] || theState.fields[k].trim() === '') {
                            fieldErrors[k] = _t('GenericForm.validation.required')
                        }
                    }
                }
            }
        })
        if (Object.keys(fieldErrors).length || Object.keys(this.state.fieldErrors).length) {
            this.setState({fieldErrors})
        }

        if (Object.keys(fieldErrors).length) {
            return false
        }

        if (onValidate) {
            return onValidate(theState.fields)
        }
        return true
    }

    getInitalState = (props) => {
        const initalState = {fields: {}, fieldErrors: {}, isValid: true}
        Object.keys(props.fields).map(k => {
            const item = props.fields[k]
            let v
            if (props.values) {
                v = props.values[k]
            } else {
                // value must be null instead of undefined
                v = item.value === undefined ? null : item.value
            }
            initalState.fields[k] = v
            if (item.localized) {
                v = props.values ? props.values[k + '_localized'] : null
                initalState.fields[k + '_localized'] = v ? Object.assign({}, v) : null
            }
        })
        return initalState
    }

    reset = () => {
        this.setState(this.getInitalState(this.props))
        this.setValidateState(this.state)
    }

    handleInputChange = (e) => {
        const target = e.target
        const value = target.type === 'checkbox' ? target.checked : target.value
        const name = target.name
        this.setState((prevState) => {
            const newState = Object.assign({}, {fields: {}}, prevState)
            const path = name.split('.')
            if (path.length == 2) {
                if (!newState.fields[path[0]]) {
                    newState.fields[path[0]] = {}
                }
                newState.fields[path[0]][path[1]] = value
            } else {
                newState.fields[name] = value
            }
            if (this.props.onChange) {
                this.props.onChange({name, value})
            }
            newState.isValid = this.validate(newState)
            return newState
        })
    }

    onAddClick = () => {
        if (this.props.onClick)
            this.props.onClick(this.state.fields)
        this.setState(this.getInitalState(this.props))
    }

    render() {
        const {fields, onKeyDown, primaryButton, caption, autoFocus, classes} = this.props
        return (
            <form>
                {
                    Object.keys(fields).map((k, i) => {
                        const o = fields[k],
                            value = this.state.fields[k]

                        const uitype = o.uitype || 'text'

                        if (uitype === 'editor' || uitype === 'jseditor') {
                            let highlight, json
                            if( uitype === 'jseditor'){
                                highlight = 'js'
                            }else
                            if (value) {
                                // detect type
                                try {
                                    json = JSON.stringify(JSON.parse(value), null, 4)
                                    highlight = 'json'
                                } catch (e) {

                                }
                            }
                            return <div className={classes.editor}><ContentEditable highlight={highlight}
                                                    onChange={(v) => this.handleInputChange({
                                                        target: {
                                                            name: k,
                                                            value: v
                                                        }
                                                    })}
                                                    key={k} setHtml={false}>{json ? json : value}</ContentEditable>
                            </div>

                        }
                        if (uitype === 'image') {
                            return <FileDrop key={k}/>
                        } else if (uitype === 'type_picker') {
                            return <TypePicker value={(value ? (value.constructor === Array ? value : [value]) : null)}
                                               error={!!this.state.fieldErrors[k]}
                                               helperText={this.state.fieldErrors[k]}
                                               onChange={this.handleInputChange} key={k}
                                               name={k}
                                               label={o.label}
                                               multi={o.multi}
                                               field={o.pickerField}
                                               type={o.type} placeholder={o.placeholder}/>
                        } else if (uitype === 'select') {

                            //TODO: implement
                        } else if (o.type === 'Boolean') {

                            return <SimpleSwitch key={k} label={o.placeholder} name={k}
                                                 onChange={this.handleInputChange} checked={value ? true : false}/>

                        } else {
                            if (o.localized) {

                                return config.LANGUAGES.reduce((a, l) => {
                                    const valueLocalized = this.state.fields[k + '_localized']
                                    const fieldName = k + '_localized.' + l
                                    a.push(<TextField key={fieldName}
                                                      error={!!this.state.fieldErrors[fieldName]}
                                                      helperText={this.state.fieldErrors[fieldName]}
                                                      label={o.label}
                                                      fullWidth={o.fullWidth}
                                                      type={uitype}
                                                      placeholder={o.placeholder + ' [' + l + ']'}
                                                      value={(valueLocalized && valueLocalized[l] ? valueLocalized[l] : '')}
                                                      name={fieldName}
                                                      onKeyDown={(e) => {
                                                          onKeyDown && onKeyDown(e, valueLocalized[l])
                                                      }}
                                                      onChange={this.handleInputChange}/>)
                                    return a
                                }, [])
                            } else {
                                return <TextField autoFocus={autoFocus && i === 0} error={!!this.state.fieldErrors[k]}
                                                  key={k}
                                                  label={o.label}
                                                  helperText={this.state.fieldErrors[k]}
                                                  fullWidth={o.fullWidth}
                                                  type={uitype}
                                                  placeholder={o.placeholder}
                                                  value={value || ''}
                                                  name={k}
                                                  onKeyDown={(e) => {
                                                      onKeyDown && onKeyDown(e, value)
                                                  }}
                                                  onChange={this.handleInputChange}/>
                            }

                        }
                    })
                }
                {primaryButton != false ?
                    <Button color="primary" variant="raised" disabled={!this.state.isValid}
                            onClick={this.onAddClick}>{caption || 'Add'}</Button>
                    : ''}
            </form>
        )
    }
}

GenericForm.propTypes = {
    fields: PropTypes.object.isRequired,
    values: PropTypes.object,
    onClick: PropTypes.func,
    onKeyDown: PropTypes.func,
    onValidate: PropTypes.func,
    caption: PropTypes.string,
    primaryButton: PropTypes.bool,
    classes: PropTypes.object.isRequired,
    autoFocus: PropTypes.bool
}

export default withStyles(styles)(GenericForm)<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';

import { getRoutes } from '../actions/route';
// components
import Route from '../components/routes/Route';

class TruckContainer extends Component {
  componentWillMount(){
    this.props.getRoutes();
  }
  render() {
    const routes = this.props.routes.map((route, index) => <NavLink key={index} to={`/dashboard/routes/${route.id}`}>
        <Route {...route} />
      </NavLink>)
    return (

Routes Page

        {routes}

    );
  }
}

function mapStateToProps(state){
  return {
    routes: state.routes
  }
}

export default connect(mapStateToProps, {getRoutes})(TruckContainer);<commit_msg>fix for new reducer<commit_after>import React, { Component } from 'react';
import { connect } from 'react-redux';
import { NavLink } from 'react-router-dom';

import { getRoutes } from '../actions/route';
// components
import Route from '../components/routes/Route';

class TruckContainer extends Component {
  componentWillMount(){
    this.props.getRoutes();
  }
  render() {
    const routes = this.props.routes.map((route, index) => <NavLink key={index} to={`/dashboard/routes/${route.id}`}>
        <Route {...route} />
      </NavLink>)
    return (

All Routes

        {routes}

    );
  }
}

function mapStateToProps(state){
  return {
    routes: state.routes.routes
  }
}

export default connect(mapStateToProps, {getRoutes})(TruckContainer);<|endoftext|>