<commit_before>var Clock = (function() {
  function Clock(minutes) {
    this.minutes = minutes;
  };

  Clock.prototype.minutes = {
    session: 25,
    breaks: 5
  };
  Clock.prototype.seconds = 60;
  Clock.prototype.paused = true;
  Clock.prototype.power = false;

  Clock.prototype.init = function() {
    this.power = true;
    this.displayTime(this.minutes, "currentTime");
    this.displayTime(this.minutes, "configureTime");

  };
  Clock.prototype.displayTime = function(time, element) {
    var element = document.getElementById(element);
    element.innerHTML = time;
  };
  Clock.prototype.togglePaused = function() {
    this.paused = !this.paused;
  };
  Clock.prototype.addAMinute = function() {
    if(this.paused) {
      this.minutes++;
      this.seconds = 0;

      if(this.power == true) {
        this.displayTime(this.minutes, "currentTime");
      }
      this.displayTime(this.minutes, "configureTime");
    }

  };
  Clock.prototype.minusAMinute = function() {
    if(this.paused) {
      if(this.minutes === 1) {
        return this.minutes;
      }
      this.minutes--;
      this.seconds = 0;

      if(this.power == true) {
        this.displayTime(this.minutes, "currentTime");
      }
      this.displayTime(this.minutes, "configureTime");
    }

  };
  Clock.prototype.switchConfigure = function(clock) {
    var minus = document.getElementById("minus");
    var plus = document.getElementById("plus");
    var session = document.getElementById("session");
    var breaks = document.getElementById("break");

    if(clock == "session") {
      minus.setAttribute("onclick", "session.minusAMinute()");
      plus.setAttribute("onclick", "session.addAMinute()");

      session.setAttribute("style", "background-color: #00cf9e; color: #f9f9f9;");
      breaks.setAttribute("style", "background-color: #f9f9f9; color: #00cf9e; border: 5px solid #00cf9e;");

      this.displayTime(this.minutes, "configureTime");
    }
    else if(clock == "breaks") {
      minus.setAttribute("onclick", "breaks.minusAMinute()");
      plus.setAttribute("onclick", "breaks.addAMinute()");

      session.setAttribute("style", "background-color: #f9f9f9; color: #00cf9e; border: 5px solid #00cf9e;");
      breaks.setAttribute("style", "background-color: #00cf9e; color: #f9f9f9;");

      this.displayTime(this.minutes, "configureTime");
    }
  }
  Clock.prototype.countDown = function() {
    var clock = this;

    if(clock.seconds === 60) {
      clock.seconds = 0;
    }
    if(!this.paused) {
      var countdown = setInterval(function() {
        if(clock.paused) {
          clearInterval(countdown);
        }

        if(clock.minutes === 0 && clock.seconds <= 1) {
          clock.togglePaused();
          clock.power = false;
          clearInterval(countdown);
        }
        if(clock.minutes <= 1) {
          clock.minutes = 0;
        }
        if(clock.seconds < 1) {
          clock.minutes--;
          clock.seconds = 60;
        }

        clock.seconds--;

        clock.displayTime(clock.minutes + ":" + clock.seconds, "currentTime");

      }, 1000);
    }
  }
  return Clock;
})();
var session = new Clock(25);
var breaks = new Clock(5);

session.init();
module.exports = Clock;
<commit_msg>fix 1 minute error<commit_after>var Clock = (function() {
  function Clock(minutes) {
    this.minutes = minutes;
  };

  Clock.prototype.minutes = {
    session: 25,
    breaks: 5
  };
  Clock.prototype.seconds = 60;
  Clock.prototype.paused = true;
  Clock.prototype.power = false;

  Clock.prototype.init = function() {
    this.power = true;
    this.displayTime(this.minutes, "currentTime");
    this.displayTime(this.minutes, "configureTime");

  };
  Clock.prototype.displayTime = function(time, element) {
    var element = document.getElementById(element);
    element.innerHTML = time;
  };
  Clock.prototype.togglePaused = function() {
    this.paused = !this.paused;
  };
  Clock.prototype.addAMinute = function() {
    if(this.paused) {
      this.minutes++;
      this.seconds = 0;

      if(this.power == true) {
        this.displayTime(this.minutes, "currentTime");
      }
      this.displayTime(this.minutes, "configureTime");
    }

  };
  Clock.prototype.minusAMinute = function() {
    if(this.paused) {
      if(this.minutes === 1) {
        return this.minutes;
      }
      this.minutes--;
      this.seconds = 0;

      if(this.power == true) {
        this.displayTime(this.minutes, "currentTime");
      }
      this.displayTime(this.minutes, "configureTime");
    }

  };
  Clock.prototype.switchConfigure = function(clock) {
    var minus = document.getElementById("minus");
    var plus = document.getElementById("plus");
    var session = document.getElementById("session");
    var breaks = document.getElementById("break");

    if(clock == "session") {
      minus.setAttribute("onclick", "session.minusAMinute()");
      plus.setAttribute("onclick", "session.addAMinute()");

      session.setAttribute("style", "background-color: #00cf9e; color: #f9f9f9;");
      breaks.setAttribute("style", "background-color: #f9f9f9; color: #00cf9e; border: 5px solid #00cf9e;");

      this.displayTime(this.minutes, "configureTime");
    }
    else if(clock == "breaks") {
      minus.setAttribute("onclick", "breaks.minusAMinute()");
      plus.setAttribute("onclick", "breaks.addAMinute()");

      session.setAttribute("style", "background-color: #f9f9f9; color: #00cf9e; border: 5px solid #00cf9e;");
      breaks.setAttribute("style", "background-color: #00cf9e; color: #f9f9f9;");

      this.displayTime(this.minutes, "configureTime");
    }
  }
  Clock.prototype.countDown = function() {
    var clock = this;

    if(!this.paused) {
      var countdown = setInterval(function() {
        if(clock.paused) {
          clearInterval(countdown);
        }
        if(clock.minutes === 0 && clock.seconds <= 1) {
          clock.togglePaused();
          clock.power = false;
          clearInterval(countdown);
        }

        if(clock.minutes === 1) {
          clock.minutes = 0;
          clock.seconds = 60;;
        }

        if(clock.seconds < 1) {
          clock.minutes--;
          clock.seconds = 60;
        }

        clock.seconds--;

        clock.displayTime(clock.minutes + ":" + clock.seconds, "currentTime");

      }, 1000);
    }
  }
  return Clock;
})();
var session = new Clock(25);
var breaks = new Clock(5);

session.init();
module.exports = Clock;
<|endoftext|>


<commit_before>$(document).ready(function() {

    $('.newfield').click(function(event) {
        event.preventDefault();
        addField($(this).attr('target'));
    });

    $('.edit').click(function() {
        $.ajax({
            url: "/itemdata/edit",
            data: {'name':$(this).attr('attr'), 'index': $(this).attr('item')},
            type: "POST",
            success: function (data) {
                insertFields(data);
            }
        });
    });

    function addField(field) {
        var target = 'form .'+ field;
        var newField = $(target).clone();
        newField.attr('name', field)
        newField.attr('class', field + $('form input[name="'+ field + '"]').length)
        newField.val('');
        $(target).parent().append(newField);
    }

    function insertFields(data) {
        var dataKeys = Object.keys(data);
        for (var i = 0; i < dataKeys.length; i++) {
            if (typeof(data[dataKeys[i]]) === 'string') {
                if (typeof(data[dataKeys[i]]) === 'object') {

                } else {
                    var field = $('form').find('[name=' + dataKeys[i] + ']');
                    field.val(data[dataKeys[i]]);
                }
            }
            else if (typeof(data[dataKeys[i]]) === 'object') {
                var keys = Object.keys(data[dataKeys[i]]);
                var subData = data[dataKeys[i]];
                for (var j = 0; j < keys.length; j++) {
                    var name = '[name="sub' + keys[j] + ',' + dataKeys[i] + '"]';
                    var field = $('form').find(name);
                    field.val(subData[keys[j]]);
                }
            }
        }
    }

});<commit_msg>Keep attr target consistent<commit_after>$(document).ready(function() {

    $('.newfield').click(function(event) {
        event.preventDefault();
        addField($(this).attr('target'));
    });

    $('.edit').click(function() {
        $.ajax({
            url: "/itemdata/edit",
            data: {'name':$(this).attr('attr'), 'index': $(this).attr('item')},
            type: "POST",
            success: function (data) {
                insertFields(data);
            }
        });
    });

    function addField(field) {
        var target = 'form .'+ field;
        var newField = $(target).clone();
        newField.attr('name', $(target).attr('name'))
        newField.attr('class', field + $('form input[name="'+ $(target).attr('name') + '"]').length)
        newField.val('');
        $(target).parent().append(newField);
    }

    function insertFields(data) {
        var dataKeys = Object.keys(data);
        for (var i = 0; i < dataKeys.length; i++) {
            if (typeof(data[dataKeys[i]]) === 'string') {
                if (typeof(data[dataKeys[i]]) === 'object') {

                } else {
                    var field = $('form').find('[name=' + dataKeys[i] + ']');
                    field.val(data[dataKeys[i]]);
                }
            }
            else if (typeof(data[dataKeys[i]]) === 'object') {
                var keys = Object.keys(data[dataKeys[i]]);
                var subData = data[dataKeys[i]];
                for (var j = 0; j < keys.length; j++) {
                    var name = '[name="sub' + keys[j] + ',' + dataKeys[i] + '"]';
                    var field = $('form').find(name);
                    field.val(subData[keys[j]]);
                }
            }
        }
    }

});<|endoftext|>


<commit_before>var globalStartTime = Date.now();
var resource = {
  earth : [],
  mars : [],
  moon : []
}

//earth와 관련된 모든 리소스를 담고, 순서대로 출력
for(var i =0; i < 7; i++){
  	resource.earth[i] = new Image();
  	resource.earth[i].src = "/images/planet/blue/"+(i+1)+".png";
}

for(var i = 0; i < 18; i++){
  	resource.mars[i] = new Image();
  	resource.mars[i].src = "/images/planet/red/"+(i+1)+".png";
}

for(var i = 0; i< 11; i++){
	resource.moon[i] = new Image();
	resource.moon[i].src = "/images/planet/gray/"+(i+1)+".png";
}

function Game(blue, red){
  var canvas = document.getElementsByTagName('canvas')[0];
  var ctx = canvas.getContext("2d");
  var blueWorker = new Worker("/code/" + blue);
  var redWorker = new Worker("/code/" + red);

  var PlanetframNum = 1;
  this.spaceShip = new Image();
  this.spaceShip.src = 'images/settle_1.png';

  var that = this;

  //map
  this.node = _map.map(function(item, index){
    var node = new Node(item.x, item.y, item.r, item.num, index);
    node.team = item.team;
    return node;
  });

  //just for Army
  this.army = [];

  //listener
  blueWorker.onmessage = function(msg){
    if(msg.data.debug)
      console.log(msg.data.debug);
    else
      that.command("blue", msg.data);
  }
  redWorker.onmessage = function(msg){
    that.command("red", msg.data);
  }

  var dt = 0;
  var curTime = Date.now();
  function loop(){
    var oldTime = curTime;
    curTime = Date.now();
    dt = curTime - oldTime;

    blueWorker.postMessage(that.makeInfo("blue"));
    redWorker.postMessage(that.makeInfo("red"));

    that.draw(ctx, dt);

    that.run(dt);

    setTimeout(loop, 0);
  }
  setTimeout(loop, 0);
  this.initScore();
}
Game.prototype.draw = function(ctx, dt){
  var that = this;
  //clear all
  ctx.clearRect(0,0,800,600);

  //draw map
  this.node.forEach(function(node){
    node.draw(ctx, dt);
  });
  //draw army
  this.army.forEach(function(army){
    army.draw(ctx, that.spaceShip);
  });
}
Game.prototype.run = function(dt){
  //calc regen to map
  this.node.forEach(function(node){
    node.run(dt)
  });

  //move Army
  this.army = this.army.filter(function(army){
    return army.run(dt);
  });
  var red = 0;
  var blue = 0;

  //calc score
  this.node.forEach(function(ele){
    if(ele.team === "red"){
      red += ele.num;
    } else if(ele.team === "blue"){
      blue += ele.num;
    }
  });
  this.army.forEach(function(ele){
    if(ele.team === "red"){
      red += ele.num;
    } else if(ele.team === "blue"){
      blue += ele.num;
    }
  });
  this.updateScore(red, blue);
  this.matchResultCheck(red,blue);
}
Game.prototype.command = function(team, data){
  if(data.from == data.to)
    return;
  data.send = parseInt(data.send);
  if(data.send <= 0 )
    return;

  var from = this.node[data.from];
  if(team != from.team){
    return;
  }
  if(from.num < data.send){
    return;
  }

  var to = this.node[data.to];

  this.army.push(new Army(from, to, data.send, team));
}
Game.prototype.makeInfo = function(team){

  return {
    map : this.node.map(function(node){
      return node.info();
    }),
    army : this.army.map(function(army){
      return army.info();
    }),
    team : team
  };
}
Game.prototype.initScore = function(){
  this.redScore = document.getElementById("redScore");
  this.blueScore = document.getElementById("blueScore");
}
Game.prototype.updateScore = function(red, blue){
  this.redScore.innerText = red;
  this.blueScore.innerText = blue;
};
Game.prototype.matchResultCheck = function(red, blue){
  if(globalStartTime+5*60*1000<Date.now()){
    console.log("Time over, draw");
    //Draw
  }
  var redPlanetNum = 0;
  var bluePlanetNum = 0;
  this.node.forEach(function(item){
    if(item.team == "red"){
      redPlanetNum++;
    }else if(item.team == "blue"){
      bluePlanetNum++;
    }
  });
  if(redPlanetNum==0&&red==0){
    console.log("Blue Wins!");
    //blue win
  }else if(bluePlanetNum==0&&blue==0){
    console.log("Red Wins!");
    //red win
  }//자기 행성이 없으면서 스코어도 없으면 GG

};

function Node(x, y, r, num, id){
  this.x = x;
  this.y = y;
  this.r = r;
  this.num = num || 0;
  this.id = id;
  this.regenCount = 0;

  //for animation
  var pick = Math.random();
  this.type = pick < 0.6 ? pick < 0.3? "mars": "moon": "earth";
  this.animateTime  = 0;
  //rotationPeriod 1000ms ~ 5000ms
  this.rotationPeriod = parseInt(Math.random()*4000) + 1000;
}
Node.prototype.run = function(dt){
  this.regenCount += dt * this.r;
  if(this.regenCount > 50000){
    this.regenCount = 0;

    if(!this.team){
      return;
    }
    if(this.r > this.num){
      this.num += 1;
    } else if(this.r < this.num){
      this.num -= 1;
    }
  }
}
Node.prototype.draw = function(ctx, dt){
  ctx.save();

  ctx.beginPath();
  ctx.arc(this.x, this.y, this.r*1, 0, Math.PI*2, true);
  ctx.closePath();
  ctx.strokeStyle = "white";
  ctx.stroke();

  if(this.team == "red") ctx.fillStyle = "rgba(255,0,0,0.8)";
  if(this.team == "blue") ctx.fillStyle = "rgba(0,0,255,0.8)";
  if(!this.team) ctx.fillStyle = "rgba(200, 200,200,0.6)";

  ctx.beginPath();
  var start = -Math.PI/2;
  var end = (this.num > this.r ? 1 : this.num/this.r) * (Math.PI*3/2)//(Math.PI*2-0.6);

  var space = this.r * 1.1 > this.r + 5 ? this.r * 1.1 : this.r + 5;
  ctx.arc(this.x, this.y, space, start, start+end, false);
  ctx.arc(this.x, this.y, space + 5, start+end, start, true);
  ctx.closePath();
  ctx.fill();

  //over
  if(this.num > this.r){
    ctx.beginPath();
    ctx.arc(this.x, this.y, space +5, -(Math.PI), -(Math.PI/2), false);
    ctx.arc(this.x, this.y, space+10, -(Math.PI/2), -(Math.PI), true);
    ctx.closePath();
    ctx.fillStyle = "green";
    ctx.fill();
  }

  ctx.textAlign = "center";
  ctx.fillStyle = "white";
  ctx.fillText("" + this.num + "/" + this.r, this.x, this.y + this.r + 10);

  switch(this.type){
    case "earth" :
	var index = parseInt(this.animateTime/(this.rotationPeriod/resource.earth.length)) || 0;
	var img = resource.earth[index];
	ctx.drawImage(img, this.x - this.r, this.y-this.r, this.r*2, this.r*2);
	break;
    case "mars":
    	var index = parseInt(this.animateTime/(this.rotationPeriod/resource.mars.length)) || 0;
    	var img = resource.mars[index];
      	ctx.drawImage(img, this.x - this.r, this.y-this.r, this.r*2, this.r*2);
      	break;
    case "moon":
    	var index = parseInt(this.animateTime/(this.rotationPeriod/resource.moon.length)) || 0;
    	var img = resource.moon[index];
      	ctx.drawImage(img, this.x - this.r, this.y-this.r, this.r*2, this.r*2);
    break;
  }
  this.animateTime += dt;
  this.animateTime = this.animateTime % this.rotationPeriod;

  ctx.restore();
}
Node.prototype.add = function(army){
  if(this.team == army.team){
    this.num += army.num;
  } else {
    this.num -= army.num;
    if(this.num < 0){
      this.num = -this.num;
      this.team = army.team;
    }
  }
}
Node.prototype.info = function(){
  return {
    x : this.x,
    y : this.y,
    team : this.team,
    num : this.num,
    size : this.r,
    id : this.id
  }
}

var ARMY_SPEED = 1;

function Army(from, to, num, team){
  this.x = from.x;
  this.y = from.y;

  var dx = from.x - to.x;
  var dy = from.y - to.y;

  var len = Math.sqrt(dx * dx + dy * dy);

  this.vx = -dx/len * ARMY_SPEED;
  this.vy = -dy/len * ARMY_SPEED;

  this.team = team;

  this.num = num;
  from.num -= num;

  this.to = to;

  var f = dx < 0;
  this._check = function(){
    var f2 = this.x - to.x < 0;
    return !((f && f2) ||(!f && !f2));
  }
}
Army.prototype.run  = function(dt){
  this.x += this.vx * dt / 10;
  this.y += this.vy * dt / 10;

  if(this.check()){
    this.to.add(this);
    return false;
  }
  return true;
}
Army.prototype.draw  = function(ctx, img){
  ctx.save();

  ctx.beginPath();
  ctx.arc(this.x, this.y, this.num + 10, 0, Math.PI*2,true);
  ctx.closePath();
  //ctx.strokeStyle = this.team;
  //ctx.stroke();
  if(this.team == "red") ctx.fillStyle = "rgba(255,0,0,0.2)";
  if(this.team == "blue") ctx.fillStyle = "rgba(0,0,255,0.4)";
  if(!this.team) ctx.fillStyle = "rgba(200, 200,200,0.2)";
  ctx.fill();

  ctx.save();

  ctx.translate(this.x, this.y);
  //TODO 적절하게 앵글 조절할것
  var angle = Math.atan(this.vx/-this.vy) + (this.vy <= 0 ? 0 : Math.PI);
  ctx.rotate(angle);
  ctx.translate(-this.x, -this.y);

  var size = this.num + 20;
  ctx.drawImage(img, this.x - size/2, this.y - size/2, size, size);

  ctx.restore();

  ctx.fillStyle = "white";
  ctx.textAlign = "center";
  ctx.fillText(this.num, this.x, this.y + this.num + 20);

  ctx.restore();
}
Army.prototype.info = function(){
  return {
    x : this.x,
    y : this.y,
    num : this.num,
    to : this.to.id,
    team : this.team
  }
}
Army.prototype.check = function(){
  return ((this.to.x - this.x) * this.vx <= 0 && (this.to.y - this.y) * this.vy <= 0);
}
//gittest<commit_msg>fix moon<commit_after>var globalStartTime = Date.now();
var resource = {
  earth : [],
  mars : [],
  moon : []
}

//earth와 관련된 모든 리소스를 담고, 순서대로 출력
for(var i =0; i < 7; i++){
  	resource.earth[i] = new Image();
  	resource.earth[i].src = "/images/planet/blue/"+(i+1)+".png";
}

for(var i = 0; i < 18; i++){
  	resource.mars[i] = new Image();
  	resource.mars[i].src = "/images/planet/red/"+(i+1)+".png";
}

for(var i = 0; i< 10; i++){
	resource.moon[i] = new Image();
	resource.moon[i].src = "/images/planet/gray/"+(i+1)+".png";
}

function Game(blue, red){
  var canvas = document.getElementsByTagName('canvas')[0];
  var ctx = canvas.getContext("2d");
  var blueWorker = new Worker("/code/" + blue);
  var redWorker = new Worker("/code/" + red);

  var PlanetframNum = 1;
  this.spaceShip = new Image();
  this.spaceShip.src = 'images/settle_1.png';

  var that = this;

  //map
  this.node = _map.map(function(item, index){
    var node = new Node(item.x, item.y, item.r, item.num, index);
    node.team = item.team;
    return node;
  });

  //just for Army
  this.army = [];

  //listener
  blueWorker.onmessage = function(msg){
    if(msg.data.debug)
      console.log(msg.data.debug);
    else
      that.command("blue", msg.data);
  }
  redWorker.onmessage = function(msg){
    that.command("red", msg.data);
  }

  var dt = 0;
  var curTime = Date.now();
  function loop(){
    var oldTime = curTime;
    curTime = Date.now();
    dt = curTime - oldTime;

    blueWorker.postMessage(that.makeInfo("blue"));
    redWorker.postMessage(that.makeInfo("red"));

    that.draw(ctx, dt);

    that.run(dt);

    setTimeout(loop, 0);
  }
  setTimeout(loop, 0);
  this.initScore();
}
Game.prototype.draw = function(ctx, dt){
  var that = this;
  //clear all
  ctx.clearRect(0,0,800,600);

  //draw map
  this.node.forEach(function(node){
    node.draw(ctx, dt);
  });
  //draw army
  this.army.forEach(function(army){
    army.draw(ctx, that.spaceShip);
  });
}
Game.prototype.run = function(dt){
  //calc regen to map
  this.node.forEach(function(node){
    node.run(dt)
  });

  //move Army
  this.army = this.army.filter(function(army){
    return army.run(dt);
  });
  var red = 0;
  var blue = 0;

  //calc score
  this.node.forEach(function(ele){
    if(ele.team === "red"){
      red += ele.num;
    } else if(ele.team === "blue"){
      blue += ele.num;
    }
  });
  this.army.forEach(function(ele){
    if(ele.team === "red"){
      red += ele.num;
    } else if(ele.team === "blue"){
      blue += ele.num;
    }
  });
  this.updateScore(red, blue);
  this.matchResultCheck(red,blue);
}
Game.prototype.command = function(team, data){
  if(data.from == data.to)
    return;
  data.send = parseInt(data.send);
  if(data.send <= 0 )
    return;

  var from = this.node[data.from];
  if(team != from.team){
    return;
  }
  if(from.num < data.send){
    return;
  }

  var to = this.node[data.to];

  this.army.push(new Army(from, to, data.send, team));
}
Game.prototype.makeInfo = function(team){

  return {
    map : this.node.map(function(node){
      return node.info();
    }),
    army : this.army.map(function(army){
      return army.info();
    }),
    team : team
  };
}
Game.prototype.initScore = function(){
  this.redScore = document.getElementById("redScore");
  this.blueScore = document.getElementById("blueScore");
}
Game.prototype.updateScore = function(red, blue){
  this.redScore.innerText = red;
  this.blueScore.innerText = blue;
};
Game.prototype.matchResultCheck = function(red, blue){
  if(globalStartTime+5*60*1000<Date.now()){
    console.log("Time over, draw");
    //Draw
  }
  var redPlanetNum = 0;
  var bluePlanetNum = 0;
  this.node.forEach(function(item){
    if(item.team == "red"){
      redPlanetNum++;
    }else if(item.team == "blue"){
      bluePlanetNum++;
    }
  });
  if(redPlanetNum==0&&red==0){
    console.log("Blue Wins!");
    //blue win
  }else if(bluePlanetNum==0&&blue==0){
    console.log("Red Wins!");
    //red win
  }//자기 행성이 없으면서 스코어도 없으면 GG

};

function Node(x, y, r, num, id){
  this.x = x;
  this.y = y;
  this.r = r;
  this.num = num || 0;
  this.id = id;
  this.regenCount = 0;

  //for animation
  var pick = Math.random();
  this.type = pick < 0.6 ? pick < 0.3? "mars": "moon": "earth";
  this.animateTime  = 0;
  //rotationPeriod 1000ms ~ 5000ms
  this.rotationPeriod = parseInt(Math.random()*4000) + 1000;
}
Node.prototype.run = function(dt){
  this.regenCount += dt * this.r;
  if(this.regenCount > 50000){
    this.regenCount = 0;

    if(!this.team){
      return;
    }
    if(this.r > this.num){
      this.num += 1;
    } else if(this.r < this.num){
      this.num -= 1;
    }
  }
}
Node.prototype.draw = function(ctx, dt){
  ctx.save();

  ctx.beginPath();
  ctx.arc(this.x, this.y, this.r*1, 0, Math.PI*2, true);
  ctx.closePath();
  ctx.strokeStyle = "white";
  ctx.stroke();

  if(this.team == "red") ctx.fillStyle = "rgba(255,0,0,0.8)";
  if(this.team == "blue") ctx.fillStyle = "rgba(0,0,255,0.8)";
  if(!this.team) ctx.fillStyle = "rgba(200, 200,200,0.6)";

  ctx.beginPath();
  var start = -Math.PI/2;
  var end = (this.num > this.r ? 1 : this.num/this.r) * (Math.PI*3/2)//(Math.PI*2-0.6);

  var space = this.r * 1.1 > this.r + 5 ? this.r * 1.1 : this.r + 5;
  ctx.arc(this.x, this.y, space, start, start+end, false);
  ctx.arc(this.x, this.y, space + 5, start+end, start, true);
  ctx.closePath();
  ctx.fill();

  //over
  if(this.num > this.r){
    ctx.beginPath();
    ctx.arc(this.x, this.y, space +5, -(Math.PI), -(Math.PI/2), false);
    ctx.arc(this.x, this.y, space+10, -(Math.PI/2), -(Math.PI), true);
    ctx.closePath();
    ctx.fillStyle = "green";
    ctx.fill();
  }

  ctx.textAlign = "center";
  ctx.fillStyle = "white";
  ctx.fillText("" + this.num + "/" + this.r, this.x, this.y + this.r + 10);

  switch(this.type){
    case "earth" :
	var index = parseInt(this.animateTime/(this.rotationPeriod/resource.earth.length)) || 0;
	var img = resource.earth[index];
	ctx.drawImage(img, this.x - this.r, this.y-this.r, this.r*2, this.r*2);
	break;
    case "mars":
    	var index = parseInt(this.animateTime/(this.rotationPeriod/resource.mars.length)) || 0;
    	var img = resource.mars[index];
      	ctx.drawImage(img, this.x - this.r, this.y-this.r, this.r*2, this.r*2);
      	break;
    case "moon":
    	var index = parseInt(this.animateTime/(this.rotationPeriod/resource.moon.length)) || 0;
    	var img = resource.moon[index];
      	ctx.drawImage(img, this.x - this.r, this.y-this.r, this.r*2, this.r*2);
    break;
  }
  this.animateTime += dt;
  this.animateTime = this.animateTime % this.rotationPeriod;

  ctx.restore();
}
Node.prototype.add = function(army){
  if(this.team == army.team){
    this.num += army.num;
  } else {
    this.num -= army.num;
    if(this.num < 0){
      this.num = -this.num;
      this.team = army.team;
    }
  }
}
Node.prototype.info = function(){
  return {
    x : this.x,
    y : this.y,
    team : this.team,
    num : this.num,
    size : this.r,
    id : this.id
  }
}

var ARMY_SPEED = 1;

function Army(from, to, num, team){
  this.x = from.x;
  this.y = from.y;

  var dx = from.x - to.x;
  var dy = from.y - to.y;

  var len = Math.sqrt(dx * dx + dy * dy);

  this.vx = -dx/len * ARMY_SPEED;
  this.vy = -dy/len * ARMY_SPEED;

  this.team = team;

  this.num = num;
  from.num -= num;

  this.to = to;

  var f = dx < 0;
  this._check = function(){
    var f2 = this.x - to.x < 0;
    return !((f && f2) ||(!f && !f2));
  }
}
Army.prototype.run  = function(dt){
  this.x += this.vx * dt / 10;
  this.y += this.vy * dt / 10;

  if(this.check()){
    this.to.add(this);
    return false;
  }
  return true;
}
Army.prototype.draw  = function(ctx, img){
  ctx.save();

  ctx.beginPath();
  ctx.arc(this.x, this.y, this.num + 10, 0, Math.PI*2,true);
  ctx.closePath();
  //ctx.strokeStyle = this.team;
  //ctx.stroke();
  if(this.team == "red") ctx.fillStyle = "rgba(255,0,0,0.2)";
  if(this.team == "blue") ctx.fillStyle = "rgba(0,0,255,0.4)";
  if(!this.team) ctx.fillStyle = "rgba(200, 200,200,0.2)";
  ctx.fill();

  ctx.save();

  ctx.translate(this.x, this.y);
  //TODO 적절하게 앵글 조절할것
  var angle = Math.atan(this.vx/-this.vy) + (this.vy <= 0 ? 0 : Math.PI);
  ctx.rotate(angle);
  ctx.translate(-this.x, -this.y);

  var size = this.num + 20;
  ctx.drawImage(img, this.x - size/2, this.y - size/2, size, size);

  ctx.restore();

  ctx.fillStyle = "white";
  ctx.textAlign = "center";
  ctx.fillText(this.num, this.x, this.y + this.num + 20);

  ctx.restore();
}
Army.prototype.info = function(){
  return {
    x : this.x,
    y : this.y,
    num : this.num,
    to : this.to.id,
    team : this.team
  }
}
Army.prototype.check = function(){
  return ((this.to.x - this.x) * this.vx <= 0 && (this.to.y - this.y) * this.vy <= 0);
}
//gittest<|endoftext|>


<commit_before>const equationEditor = document.querySelector('.equationEditor')
const latexEditor = document.querySelector('.latexEditor')
const MQ = MathQuill.getInterface(2)

$('.newEquation').mousedown(e => {
    e.preventDefault()
    if(!hasAnswerFocus())
        return
    pasteHtmlAtCaret('
lol
 ')
    newEquation($('.equationPlaceholder'))
})

function newEquation(placeholder) {
    const img = placeholder.prev()
    img.hide()
    $('.mathToolbar').show()
    placeholder.replaceWith($('.math'))
    mathField.latex('')
    setTimeout(() => mathField.focus(), 0)
}
initToolbar()
$('.mathToolbar').hide()
$('.answer').on('mousedown', '.result', e => {
    const img = $(e.target)
    img.hide()
	$('.mathToolbar').show()
    img.after($('.math'))
    const latex = img.prop('alt')
	mathField.reflow()
    mathField.latex(latex)
	setTimeout(() => mathField.focus(), 0)
})

$('.math .close').mousedown(e => {
	e.preventDefault()
    let math = $(e.target).parents('.math')
    const img = math.prev()
    if(latexEditor.value.trim() === '') {
	    img.remove()
    } else {
        img.show()
        img.prop('src', '/math.svg?latex=' +  encodeURIComponent(latexEditor.value))
        img.prop('alt', latexEditor.value)
    }
    $('.outerPlaceholder').html(math)
    $('.mathToolbar').hide()
})
const mathField = MQ.MathField(equationEditor, {
	spaceBehavesLikeTab: true,
	handlers:            {
		edit: () => latexEditor.value = mathField.latex()
	}
});
latexEditor.addEventListener('keyup', () => {
	setTimeout(() => mathField.latex(latexEditor.value), 0)
})

$('.answer').get(0).focus()

function initToolbar() {
	const actions = [
		{action: '\\sqrt', label: '\\sqrt{\\square}'},
		{action: '^', label: '\\square^{\\square}'},
		{action: '\\frac', label: '\\frac{\\square}{\\square}'},
		{action: '\\int', label: '\\int_{\\square}^{\\square}'},
		{action: '\\neq', label: '\\neq'},
		{action: '\\lim_', label: '\\lim_{\\square}'},
		{action: '\\to', label: '\\to'},
		{action: '\\overrightarrow', label: '\\overrightarrow{\\square}'}
	]

	const tags = [
		{action: 'x', label: 'Xalaindeksi'},
		{action: 'x', label: 'Xyläindeksi'},
		{action: 'italic', label: 'Kursiivi'}
	]
	$('.tags .list').append(tags.map(o => $(`<button id="${o.action}">${o.label}</button>`)))
	$('.mathToolbar').append(actions.map(o => $(`<button id="${o.action}" title="${o.label}">${o.label}</button>`)))
	const buttons = $('.mathToolbar button')
	buttons.mousedown(e => {
		e.preventDefault()
		const symbol = e.currentTarget.id
		mathField.typedText(symbol)
		if(symbol.startsWith('\\')) mathField.keystroke('Tab')
		setTimeout(() => mathField.focus(), 0)
	})
	buttons.map((i, elem) => MQ.StaticMath(elem))
}
const chars = [
	'°', '≡',
	'⌐', '×', '«', '»', '…', '∫', '¬', '√', 'ƒ', '≈', '‹', '›', '∙', '‰', '¹', '²', '³', '½', '¼', '¾', '←', '↑', '→', '↓', '↔', '↕', '↨', '≠', 'Ø', '∞', '±', '≤', '≥', 'µ', '∂', '∑', '∏', 'Ω', '∆', 'ı', 'Ð',
	'ð', 'Þ', 'þ', 'Γ', 'Θ', 'Φ', 'α', 'δ', 'ε', 'σ', 'τ', 'φ', '∩', 'Ω', 'ω', 'Д', 'Ф'
]

const $characters = $('.toolbar .characters')

$characters.find('.list').append(chars.map(char => $(`<span class="button">${char}</span>`)))
$('.toolbar .button').mousedown(e => {
	const innerText = e.currentTarget.innerText
	if($('.equationEditor').hasClass('mq-focused')) {
		mathField.typedText(innerText)
	} else {
		pasteHtmlAtCaret(innerText)
	}
	e.preventDefault()
	return false
})

$('.tags button').mousedown(e => {
	pasteHtmlAtCaret(e.currentTarget.id)
	e.preventDefault()
	return false
})
$('.toggle').mousedown(e => {
	$(e.target.parentNode).find('.list').toggle()
	e.preventDefault()
	return false
})

function hasAnswerFocus(sel) {
    return (sel || window.getSelection()).anchorNode.parentElement.classList.contains('answer')
}

function pasteHtmlAtCaret(html) {
	let sel;
	let range;
	if(window.getSelection) {
		sel = window.getSelection()
		if(sel.getRangeAt && hasAnswerFocus(sel)) {
			range = sel.getRangeAt(0)
			range.deleteContents()
			const el = document.createElement("div")
			el.innerHTML = html
			let frag = document.createDocumentFragment(), node, lastNode
			while((node = el.firstChild)) {
				lastNode = frag.appendChild(node)
			}
			range.insertNode(frag)
			if(lastNode) {
				range = range.cloneRange()
				range.setStartAfter(lastNode)
				range.collapse(true)
				sel.removeAllRanges()
				sel.addRange(range)
			}
		}
	}
}
<commit_msg>Use appropriate delta character<commit_after>const equationEditor = document.querySelector('.equationEditor')
const latexEditor = document.querySelector('.latexEditor')
const MQ = MathQuill.getInterface(2)

$('.newEquation').mousedown(e => {
    e.preventDefault()
    if(!hasAnswerFocus())
        return
    pasteHtmlAtCaret('
lol
 ')
    newEquation($('.equationPlaceholder'))
})

function newEquation(placeholder) {
    const img = placeholder.prev()
    img.hide()
    $('.mathToolbar').show()
    placeholder.replaceWith($('.math'))
    mathField.latex('')
    setTimeout(() => mathField.focus(), 0)
}
initToolbar()
$('.mathToolbar').hide()
$('.answer').on('mousedown', '.result', e => {
    const img = $(e.target)
    img.hide()
	$('.mathToolbar').show()
    img.after($('.math'))
    const latex = img.prop('alt')
	mathField.reflow()
    mathField.latex(latex)
	setTimeout(() => mathField.focus(), 0)
})

$('.math .close').mousedown(e => {
	e.preventDefault()
    let math = $(e.target).parents('.math')
    const img = math.prev()
    if(latexEditor.value.trim() === '') {
	    img.remove()
    } else {
        img.show()
        img.prop('src', '/math.svg?latex=' +  encodeURIComponent(latexEditor.value))
        img.prop('alt', latexEditor.value)
    }
    $('.outerPlaceholder').html(math)
    $('.mathToolbar').hide()
})
const mathField = MQ.MathField(equationEditor, {
	spaceBehavesLikeTab: true,
	handlers:            {
		edit: () => latexEditor.value = mathField.latex()
	}
});
latexEditor.addEventListener('keyup', () => {
	setTimeout(() => mathField.latex(latexEditor.value), 0)
})

$('.answer').get(0).focus()

function initToolbar() {
	const actions = [
		{action: '\\sqrt', label: '\\sqrt{\\square}'},
		{action: '^', label: '\\square^{\\square}'},
		{action: '\\frac', label: '\\frac{\\square}{\\square}'},
		{action: '\\int', label: '\\int_{\\square}^{\\square}'},
		{action: '\\neq', label: '\\neq'},
		{action: '\\lim_', label: '\\lim_{\\square}'},
		{action: '\\to', label: '\\to'},
		{action: '\\overrightarrow', label: '\\overrightarrow{\\square}'}
	]

	const tags = [
		{action: 'x', label: 'Xalaindeksi'},
		{action: 'x', label: 'Xyläindeksi'},
		{action: 'italic', label: 'Kursiivi'}
	]
	$('.tags .list').append(tags.map(o => $(`<button id="${o.action}">${o.label}</button>`)))
	$('.mathToolbar').append(actions.map(o => $(`<button id="${o.action}" title="${o.label}">${o.label}</button>`)))
	const buttons = $('.mathToolbar button')
	buttons.mousedown(e => {
		e.preventDefault()
		const symbol = e.currentTarget.id
		mathField.typedText(symbol)
		if(symbol.startsWith('\\')) mathField.keystroke('Tab')
		setTimeout(() => mathField.focus(), 0)
	})
	buttons.map((i, elem) => MQ.StaticMath(elem))
}
const chars = [
	'°', '≡',
	'⌐', '×', '«', '»', '…', '∫', '¬', '√', 'ƒ', '≈', '‹', '›', '∙', '‰', '¹', '²', '³', '½', '¼', '¾', '←', '↑', '→', '↓', '↔', '↕', '↨', '≠', 'Ø', '∞', '±', '≤', '≥', 'µ', '∂', '∑', '∏', 'Ω', 'Δ', 'ı', 'Ð',
	'ð', 'Þ', 'þ', 'Γ', 'Θ', 'Φ', 'α', 'δ', 'ε', 'σ', 'τ', 'φ', '∩', 'Ω', 'ω', 'Д', 'Ф'
]

const $characters = $('.toolbar .characters')

$characters.find('.list').append(chars.map(char => $(`<span class="button">${char}</span>`)))
$('.toolbar .button').mousedown(e => {
	const innerText = e.currentTarget.innerText
	if($('.equationEditor').hasClass('mq-focused')) {
		mathField.typedText(innerText)
	} else {
		pasteHtmlAtCaret(innerText)
	}
	e.preventDefault()
	return false
})

$('.tags button').mousedown(e => {
	pasteHtmlAtCaret(e.currentTarget.id)
	e.preventDefault()
	return false
})
$('.toggle').mousedown(e => {
	$(e.target.parentNode).find('.list').toggle()
	e.preventDefault()
	return false
})

function hasAnswerFocus(sel) {
    return (sel || window.getSelection()).anchorNode.parentElement.classList.contains('answer')
}

function pasteHtmlAtCaret(html) {
	let sel;
	let range;
	if(window.getSelection) {
		sel = window.getSelection()
		if(sel.getRangeAt && hasAnswerFocus(sel)) {
			range = sel.getRangeAt(0)
			range.deleteContents()
			const el = document.createElement("div")
			el.innerHTML = html
			let frag = document.createDocumentFragment(), node, lastNode
			while((node = el.firstChild)) {
				lastNode = frag.appendChild(node)
			}
			range.insertNode(frag)
			if(lastNode) {
				range = range.cloneRange()
				range.setStartAfter(lastNode)
				range.collapse(true)
				sel.removeAllRanges()
				sel.addRange(range)
			}
		}
	}
}
<|endoftext|>


<commit_before>// # fields component

/*
Render a field to edit the values of an object with static properties.
*/

'use strict';

import createReactClass from 'create-react-class';
import cx from 'classnames';

import _ from '../../undash';
import FieldMixin from '../../mixins/field';

/** @jsx jsx */
import jsx from '../../jsx';

export default createReactClass({
  displayName: 'Fields',

  mixins: [FieldMixin],

  onChangeField: function(key, newValue, info) {
    if (!key) {
      const parentPath = this.props.config.fieldValuePath(this.props.field);
      const childPath = this.props.config
        .fieldValuePath(info.field)
        .slice(parentPath.length);
      key = childPath[0];
      if (key) {
        newValue = newValue[key];
      }
    }
    if (key) {
      const newObjectValue = _.extend({}, this.props.field.value);
      newObjectValue[key] = newValue;
      this.onBubbleValue(newObjectValue, info);
    }
  },

  render: function() {
    return this.renderWithConfig();
  },

  renderDefault: function() {
    const config = this.props.config;
    const field = this.props.field;

    const fields = config.createChildFields(field);

    // Want to move to fieldset with legend, but doing a little backward-compatible
    // hacking here, only converting child `fields` without keys.
    const isGroup = !!(field.parent && !field.key);

    console.log(isGroup, field);

    const classes = _.extend({}, this.props.classes);

    if (isGroup) {
      classes['child-fields-group'] = true;
    }

    const legend = !isGroup ? null : (
      <legend>{config.fieldLabel(field)}</legend>
    );

    const help = !isGroup
      ? null
      : config.createElement('help', {
          config,
          field,
        });

    const content = fields.map(
      function(childField, i) {
        const key = childField.key || i;
        return config.createFieldElement({
          key: key || i,
          field: childField,
          onChange: this.onChangeField.bind(this, childField.key),
          onAction: this.onBubbleAction,
        });
      }.bind(this)
    );

    return config.createElement(
      'field',
      {
        config,
        field,
        plain: isGroup || this.props.plain,
      },
      <fieldset
        renderWith={this.renderWith('FieldBody')}
        className={cx(classes)}
      >
        {legend}
        {help}
        {content}
      </fieldset>
    );
  },
});
<commit_msg>Fix bug with detecting fields without keys<commit_after>// # fields component

/*
Render a field to edit the values of an object with static properties.
*/

'use strict';

import createReactClass from 'create-react-class';
import cx from 'classnames';

import _ from '../../undash';
import FieldMixin from '../../mixins/field';

/** @jsx jsx */
import jsx from '../../jsx';

export default createReactClass({
  displayName: 'Fields',

  mixins: [FieldMixin],

  onChangeField: function(key, newValue, info) {
    if (!key) {
      const parentPath = this.props.config.fieldValuePath(this.props.field);
      const childPath = this.props.config
        .fieldValuePath(info.field)
        .slice(parentPath.length);
      key = childPath[0];
      if (key) {
        newValue = newValue[key];
      }
    }
    if (key) {
      const newObjectValue = _.extend({}, this.props.field.value);
      newObjectValue[key] = newValue;
      this.onBubbleValue(newObjectValue, info);
    }
  },

  render: function() {
    return this.renderWithConfig();
  },

  renderDefault: function() {
    const config = this.props.config;
    const field = this.props.field;

    const fields = config.createChildFields(field);

    // Want to move to fieldset with legend, but doing a little backward-compatible
    // hacking here, only converting child `fields` without keys.
    const isGroup = !!((field.parent && field.key === '') || field.key == null);

    const classes = _.extend({}, this.props.classes);

    if (isGroup) {
      classes['child-fields-group'] = true;
    }

    const legend = !isGroup ? null : (
      <legend>{config.fieldLabel(field)}</legend>
    );

    const help = !isGroup
      ? null
      : config.createElement('help', {
          config,
          field,
        });

    const content = fields.map(
      function(childField, i) {
        const key = childField.key || i;
        return config.createFieldElement({
          key: key || i,
          field: childField,
          onChange: this.onChangeField.bind(this, childField.key),
          onAction: this.onBubbleAction,
        });
      }.bind(this)
    );

    return config.createElement(
      'field',
      {
        config,
        field,
        plain: isGroup || this.props.plain,
      },
      <fieldset
        renderWith={this.renderWith('FieldBody')}
        className={cx(classes)}
      >
        {legend}
        {help}
        {content}
      </fieldset>
    );
  },
});
<|endoftext|>


<commit_before>// neural network random art generator

// settings

// actual size of generated image
var sizeh  = 32*5;
var sizew = sizeh;
var sizeImage = sizeh*sizew;

var nH, nW, nImage;
var mask;

// settings of nnet:
var networkSize = 16;
var nHidden = 8;
var nOut = 3; // r, g, b layers

// support variables:
var img;
var img2;
var G = new R.Graph(false);

var initModel = function() {
  "use strict";

  var model = [];
  var i;

  var randomSize = 1.0;

  // define the model below:
  model.w_in = R.RandMat(networkSize, 3, 0, randomSize); // x, y, and bias

  for (i = 0; i < nHidden; i++) {
    model['w_'+i] = R.RandMat(networkSize, networkSize, 0, randomSize);
  }

  model.w_out = R.RandMat(nOut, networkSize, 0, randomSize); // output layer

  return model;
};

var forwardNetwork = function(G, model, x_, y_) {
  // x_, y_ is a normal javascript float, will be converted to a mat object below
  // G is a graph to amend ops to
  var x = new R.Mat(3, 1); // input
  var i;
  x.set(0, 0, x_);
  x.set(1, 0, y_);
  x.set(2, 0, 1.0); // bias.
  var out;
  out = G.tanh(G.mul(model.w_in, x));
  for (i = 0; i < nHidden; i++) {
    out = G.tanh(G.mul(model['w_'+i], out));
  }
  out = G.sigmoid(G.mul(model.w_out, out));
  return out;
};

function getColorAt(model, x, y) {
  // function that returns a color given coordintes (x, y)
  // (x, y) are scaled to -0.5 -> 0.5 for image recognition later
  // but it can be behond the +/- 0.5 for generation above and beyond
  // recognition limits
  var r, g, b;
  var out = forwardNetwork(G, model, x, y);

  r = out.w[0]*255.0;
  g = out.w[1]*255.0;
  b = out.w[2]*255.0;

  return color(r, g, b);
}

function genImage(img, model) {
  var i, j, m, n;
  img.loadPixels();
  for (i = 0, m=img.width; i < m; i++) {
    for (j = 0, n=img.height; j < n; j++) {
      img.set(i, j, getColorAt(model, i/sizeh-0.5,j/sizew-0.5));
    }
  }
  img.updatePixels();
}

function setup() {

  "use strict";
  var myCanvas;

  myCanvas = createCanvas(710, 400, WEBGL);
  nW = Math.max(Math.floor(sizew/sizew), 1);
  nH = Math.max(Math.floor(sizeh/sizeh), 1);
  nImage = nH*nW;
  mask = R.zeros(nImage);

  //img.resize(320*1.0, 320*1.0);

  //img.save('genart.png','png');

  //noLoop();
  img = createImage(sizeh, sizew);
  model = initModel();
  genImage(img, model);
  frameRate(30);
}

function getRandomLocation() {
  var i, result=0, r;
  for (i=0;i<nImage;i++) {
    result += mask[i];
  }
  if (result === nImage) {
    mask = R.zeros(nImage);
  }
  do {
    r = R.randi(0, nImage);
  } while (mask[r] !== 0);
  mask[r] = 1;
  return r;
}

function draw() {
	var n = getRandomLocation();
	var row = Math.floor(n/nW);
	var col = n % nW;
	background(255);

	var locX = mouseX - height / 2;
	var locY = mouseY - width / 2;
	ambientLight(60, 60, 60);
	pointLight(255, 255, 255, locX, locY, 100);

	push();
	rotateZ(frameCount * 0.01);
	rotateX(frameCount * 0.01);
	rotateY(frameCount * 0.01);
	texture(img);
	box(80);
	pop();
}
<commit_msg>Updated art.<commit_after>// neural network random art generator

// settings

// actual size of generated image
var sizeh  = 32*5;
var sizew = sizeh;
var sizeImage = sizeh*sizew;

var nH, nW, nImage;
var mask;

// settings of nnet:
var networkSize = 16;
var nHidden = 8;
var nOut = 3; // r, g, b layers

// support variables:
var img;
var img2;
var G = new R.Graph(false);

var initModel = function() {
  "use strict";

  var model = [];
  var i;

  var randomSize = 1.0;

  // define the model below:
  model.w_in = R.RandMat(networkSize, 3, 0, randomSize); // x, y, and bias

  for (i = 0; i < nHidden; i++) {
    model['w_'+i] = R.RandMat(networkSize, networkSize, 0, randomSize);
  }

  model.w_out = R.RandMat(nOut, networkSize, 0, randomSize); // output layer

  return model;
};

var forwardNetwork = function(G, model, x_, y_) {
  // x_, y_ is a normal javascript float, will be converted to a mat object below
  // G is a graph to amend ops to
  var x = new R.Mat(3, 1); // input
  var i;
  x.set(0, 0, x_);
  x.set(1, 0, y_);
  x.set(2, 0, 1.0); // bias.
  var out;
  out = G.tanh(G.mul(model.w_in, x));
  for (i = 0; i < nHidden; i++) {
    out = G.tanh(G.mul(model['w_'+i], out));
  }
  out = G.sigmoid(G.mul(model.w_out, out));
  return out;
};

function getColorAt(model, x, y) {
  // function that returns a color given coordintes (x, y)
  // (x, y) are scaled to -0.5 -> 0.5 for image recognition later
  // but it can be behond the +/- 0.5 for generation above and beyond
  // recognition limits
  var r, g, b;
  var out = forwardNetwork(G, model, x, y);

  r = out.w[0]*255.0;
  g = out.w[1]*255.0;
  b = out.w[2]*255.0;

  return color(r, g, b);
}

function genImage(img, model) {
  var i, j, m, n;
  img.loadPixels();
  for (i = 0, m=img.width; i < m; i++) {
    for (j = 0, n=img.height; j < n; j++) {
      img.set(i, j, getColorAt(model, i/sizeh-0.5,j/sizew-0.5));
    }
  }
  img.updatePixels();
}

function setup() {

  "use strict";
  var myCanvas;

  myCanvas = createCanvas(710, 400, WEBGL);
  nW = Math.max(Math.floor(sizew/sizew), 1);
  nH = Math.max(Math.floor(sizeh/sizeh), 1);
  nImage = nH*nW;
  mask = R.zeros(nImage);

  //img.resize(320*1.0, 320*1.0);

  //img.save('genart.png','png');

  //noLoop();
  img = createImage(sizeh, sizew);
  model = initModel();
  genImage(img, model);
  frameRate(30);
}

function getRandomLocation() {
  var i, result=0, r;
  for (i=0;i<nImage;i++) {
    result += mask[i];
  }
  if (result === nImage) {
    mask = R.zeros(nImage);
  }
  do {
    r = R.randi(0, nImage);
  } while (mask[r] !== 0);
  mask[r] = 1;
  return r;
}

function draw() {
	var n = getRandomLocation();
	var row = Math.floor(n/nW);
	var col = n % nW;
	background(255);

	var locX = mouseX - height / 2;
	var locY = mouseY - width / 2;
	push();
	rotateZ(frameCount * 0.01);
	rotateX(frameCount * 0.01);
	rotateY(frameCount * 0.01);
	texture(img);
	box(80);
	pop();
}
<|endoftext|>


<commit_before>/*
 * checkmark
 *
 * Copyright (c) 2014 Radko Dinev <radko.dinev@gmail.com> (https://github.com/radkodinev)
 * Licensed under the MIT license
 */

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define([], factory);
  } else if (typeof exports === 'object') {
    // For CommonJS-like environments that support module.exports, e.g. Node.
    module.exports = factory();
  } else {
    // Browser globals (root is window)
    root.Checkmark = factory();
  }
}(this, function() {

  return function ctr(targetCount, callback) {
    if (typeof targetCount !== "number") {
      throw new Error("First argument is expected to be a positive integer number");
    }
    if (typeof callback === "undefined") {
      callback = function() {};
    }
    if (typeof callback !== "function") {
      throw new Error("Second argument, when given, is expected to be a callback function");
    }

    var invocations = [];

    var check = function check(data) {
      if (invocations.length === targetCount) {
        throw new Error("Target count " + targetCount + " has already been reached");
      }

      if (typeof data === "undefined") {
        data = null;
      }
      invocations.push(data);

      if (invocations.length === targetCount) {
        callback();
      }
    };

    check.getCalls = function getCalls() {
      return invocations;
    };

    check.getCount = function getCount() {
      return invocations.length;
    };

    return check;
  };

}));
<commit_msg>Minor comments edit<commit_after>/*
 * checkmark
 *
 * Copyright (c) 2014 Radko Dinev <radko.dinev@gmail.com> (https://github.com/radkodinev)
 * Licensed under the MIT license
 */

(function(root, factory) {
  if (typeof define === 'function' && define.amd) {
    // AMD: register as an anonymous module
    define([], factory);
  } else if (typeof exports === 'object') {
    // CommonJS-like environments (that support module.exports, e.g. Node.js)
    module.exports = factory();
  } else {
    // Global/browser: export as a global, e.g. in browsers root is window
    root.Checkmark = factory();
  }
}(this, function() {

  return function ctr(targetCount, callback) {
    if (typeof targetCount !== "number") {
      throw new Error("First argument is expected to be a positive integer number");
    }
    if (typeof callback === "undefined") {
      callback = function() {};
    }
    if (typeof callback !== "function") {
      throw new Error("Second argument, when given, is expected to be a callback function");
    }

    var invocations = [];

    var check = function check(data) {
      if (invocations.length === targetCount) {
        throw new Error("Target count " + targetCount + " has already been reached");
      }

      if (typeof data === "undefined") {
        data = null;
      }
      invocations.push(data);

      if (invocations.length === targetCount) {
        callback();
      }
    };

    check.getCalls = function getCalls() {
      return invocations;
    };

    check.getCount = function getCount() {
      return invocations.length;
    };

    return check;
  };

}));
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import TinyDatePicker from 'tiny-date-picker';
import assign from 'lodash/assign';
import uniqueId from 'lodash/uniqueId';

class SprkDatePicker extends Component {
  constructor(props) {
    const { value } = props;
    super(props).datePickerInputRef = React.createRef();
    this.tdpConfig = {
      mode: 'dp-below',
      lang: {
        days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
      },
      min: '01/1/2008',
      max: '01/1/2068',
      format: (date) =>
        date
          .toLocaleDateString('en-US', {
            month: '2-digit',
            day: '2-digit',
            year: 'numeric',
          })
          .replace(/[^ -~]/g, ''),
    };

    if (value) {
      this.state = {
        hasValue: true,
      };
    } else {
      this.state = {
        hasValue: false,
      };
    }
  }

  componentDidMount() {
    const { datePickerConfig } = this.props;
    TinyDatePicker(
      this.datePickerInputRef.current,
      assign(this.tdpConfig, datePickerConfig),
    );
  }

  render() {
    const {
      datePickerConfig,
      variant,
      additionalClasses,
      analyticsString,
      formatter,
      idString,
      isDisabled,
      isValid,
      ariaDescribedBy,
      value,
      id,
      ...rest
    } = this.props;
    const { hasValue } = this.state;

    // Adds class for IE and Edge
    const handleOnBlur = (e) => {
      if (e.target.value.length > 0) {
        this.setState({ hasValue: true });
      } else {
        this.setState({ hasValue: false });
      }
    };

    return (
      <input
        className={classNames('sprk-b-TextInput', additionalClasses, {
          'sprk-b-TextInput--error': !isValid,
          'sprk-b-Input--has-floating-label': hasValue && variant === 'huge',
          'sprk-b-TextInput--has-svg-icon': variant !== 'huge',
        })}
        disabled={isDisabled}
        ref={this.datePickerInputRef}
        aria-describedby={ariaDescribedBy}
        data-id={idString}
        data-analytics={analyticsString}
        aria-invalid={!isValid}
        value={isValid && formatter ? formatter(value) : value}
        onBlur={(e) => handleOnBlur(e)}
        id={id}
        {...rest}
      />
    );
  }
}

SprkDatePicker.propTypes = {
  /**
   * Exposes configuration provided
   * by tiny-date-picker, see [github](https://github.com/chrisdavies/tiny-date-picker) for documentation.
   */
  datePickerConfig: PropTypes.shape({
    appendTo: PropTypes.node,
    lang: PropTypes.shape({
      days: PropTypes.arrayOf(PropTypes.string),
      months: PropTypes.arrayOf(PropTypes.string),
    }),
    today: PropTypes.string,
    clear: PropTypes.string,
    close: PropTypes.string,
    format: PropTypes.func,
    parse: PropTypes.func,
    mode: PropTypes.oneOf(['dp-modal', 'dp-below', 'dp-permanent']),
    highlightedDate: PropTypes.string,
    min: PropTypes.string,
    max: PropTypes.string,
    inRange: PropTypes.func,
    dateClass: PropTypes.func,
    dayOffset: PropTypes.number,
  }),
  /**
   * Determines the style of the input container.
   * Supplying no value will cause
   * the default styles to be used.
   */
  variant: PropTypes.oneOf(['huge']),
  /**
   * A space-separated string of classes
   * to add to the component.
   */
  additionalClasses: PropTypes.string,
  /**
   * Assigned to the `data-analytics` attribute serving as
   * a unique selector for outside libraries to capture data.
   */
  analyticsString: PropTypes.string,
  /**
   * A function supplied will be passed the value of the
   * input and then executed, if the valid prop is true. The value
   * returned will be assigned to the value of the input.
   */
  formatter: PropTypes.func,
  /**
   * Assigned to the `data-id` attribute serving as a
   * unique selector for automated tools.
   */
  idString: PropTypes.string,
  /**
   * Determines whether to render the
   * component in the valid or the error state.
   */
  isValid: PropTypes.bool,
  /**
   * Will render the component in it's disabled state.
   */
  isDisabled: PropTypes.bool,
  /**
   * 	Assigned to the `value` attribute
   *  of the rendered input element.
   */
  value: PropTypes.string,
  /**
   * Assigned to the `id` attribute
   * of the rendered input element.
   * A custom ID will
   * be added if this is not supplied.
   */
  id: PropTypes.string,
  /**
   * Assigned to the `aria-describedby`
   * attribute. Used to create
   * relationships between the
   * component and text that describes it,
   * such as helper text or an error field.
   */
  ariaDescribedBy: PropTypes.string,
};

SprkDatePicker.defaultProps = {
  datePickerConfig: {},
  formatter: (value) => value,
  isValid: true,
  id: uniqueId('sprk-datepicker-'),
  isDisabled: false,
};

export default SprkDatePicker;
<commit_msg>add comments to datepicker config<commit_after>import React, { Component } from 'react';
import classNames from 'classnames';
import PropTypes from 'prop-types';
import TinyDatePicker from 'tiny-date-picker';
import assign from 'lodash/assign';
import uniqueId from 'lodash/uniqueId';

class SprkDatePicker extends Component {
  constructor(props) {
    const { value } = props;
    super(props).datePickerInputRef = React.createRef();
    this.tdpConfig = {
      mode: 'dp-below',
      lang: {
        days: ['S', 'M', 'T', 'W', 'T', 'F', 'S'],
      },
      min: '01/1/2008',
      max: '01/1/2068',
      format: (date) =>
        date
          .toLocaleDateString('en-US', {
            month: '2-digit',
            day: '2-digit',
            year: 'numeric',
          })
          .replace(/[^ -~]/g, ''),
    };

    if (value) {
      this.state = {
        hasValue: true,
      };
    } else {
      this.state = {
        hasValue: false,
      };
    }
  }

  componentDidMount() {
    const { datePickerConfig } = this.props;
    TinyDatePicker(
      this.datePickerInputRef.current,
      assign(this.tdpConfig, datePickerConfig),
    );
  }

  render() {
    const {
      datePickerConfig,
      variant,
      additionalClasses,
      analyticsString,
      formatter,
      idString,
      isDisabled,
      isValid,
      ariaDescribedBy,
      value,
      id,
      ...rest
    } = this.props;
    const { hasValue } = this.state;

    // Adds class for IE and Edge
    const handleOnBlur = (e) => {
      if (e.target.value.length > 0) {
        this.setState({ hasValue: true });
      } else {
        this.setState({ hasValue: false });
      }
    };

    return (
      <input
        className={classNames('sprk-b-TextInput', additionalClasses, {
          'sprk-b-TextInput--error': !isValid,
          'sprk-b-Input--has-floating-label': hasValue && variant === 'huge',
          'sprk-b-TextInput--has-svg-icon': variant !== 'huge',
        })}
        disabled={isDisabled}
        ref={this.datePickerInputRef}
        aria-describedby={ariaDescribedBy}
        data-id={idString}
        data-analytics={analyticsString}
        aria-invalid={!isValid}
        value={isValid && formatter ? formatter(value) : value}
        onBlur={(e) => handleOnBlur(e)}
        id={id}
        {...rest}
      />
    );
  }
}

SprkDatePicker.propTypes = {
  /**
   * Exposes configuration provided
   * by tiny-date-picker, see [github](https://github.com/chrisdavies/tiny-date-picker) for documentation.
   */
  datePickerConfig: PropTypes.shape({
    /**
     * What DOM element the Date Picker will be added to. This defaults
     * to document.body
     */
    appendTo: PropTypes.node,
    /**
     * Lang can be used to customize the text that is displayed
     * in the calendar. You can use this to display a different language.
     */
    lang: PropTypes.shape({
      days: PropTypes.arrayOf(PropTypes.string),
      months: PropTypes.arrayOf(PropTypes.string),
    }),
    today: PropTypes.string,
    clear: PropTypes.string,
    close: PropTypes.string,
    /**
     * format {Date} -> string is a function which takes a
     * date and returns a string. It can be used to customize
     * the way a date will look in the input after the user has
     * selected it, and is particularly useful if you're targeting
     * a non-US customer.
     */
    format: PropTypes.func,
    /**
     * parse {string|Date} -> Date is the inverse of format.
     * If you specify one, you probably should specify the other
     * the default parse function handles whatever the new Date
     * constructor handles. Note that parse may be passed either a
     * string or a date.
     */
    parse: PropTypes.func,
    /**
     * mode {'dp-modal'|'dp-below'|'dp-permanent'} specifies the
     * way the date picker should display:
     * 'dp-modal' displays the picker as a modal
     * 'dp-below' displays the date picker as a dropdown
     * 'dp-permanent' displays the date picker as a permanent
     * (always showing) calendar.
     */
    mode: PropTypes.oneOf(['dp-modal', 'dp-below', 'dp-permanent']),
    /**
     * highlightedDate specifies what date to highlight when the
     * date picker is displayed and the associated input has no value.
     */
    highlightedDate: PropTypes.string,
    /**
     * min {string|Date} specifies the minimum date
     * that can be selected (inclusive).
     * All earlier dates will be disabled.
     */
    min: PropTypes.string,
    /**
     * max {string|Date} specifies the maximum date
     * that can be selected (inclusive).
     * All later dates will be disabled.
     */
    max: PropTypes.string,
    /**
     * inRange {Date} -> boolean takes a date and returns
     * true or false. If false, the date
     * will be disabled in the date picker.
     */
    inRange: PropTypes.func,
    /**
     * dateClass {Date} -> string takes a date and returns
     * a CSS class name to be associated
     * with that date in the date picker.
     */
    dateClass: PropTypes.func,
    /**
     * dayOffset {number} specifies which day of the week is
     * considered the first. By default,
     * this is 0 (Sunday). Set it to 1 for Monday, 2 for Tuesday, etc.
     */
    dayOffset: PropTypes.number,
  }),
  /**
   * Determines the style of the input container.
   * Supplying no value will cause
   * the default styles to be used.
   */
  variant: PropTypes.oneOf(['huge']),
  /**
   * A space-separated string of classes
   * to add to the component.
   */
  additionalClasses: PropTypes.string,
  /**
   * Assigned to the `data-analytics` attribute serving as
   * a unique selector for outside libraries to capture data.
   */
  analyticsString: PropTypes.string,
  /**
   * A function supplied will be passed the value of the
   * input and then executed, if the valid prop is true. The value
   * returned will be assigned to the value of the input.
   */
  formatter: PropTypes.func,
  /**
   * Assigned to the `data-id` attribute serving as a
   * unique selector for automated tools.
   */
  idString: PropTypes.string,
  /**
   * Determines whether to render the
   * component in the valid or the error state.
   */
  isValid: PropTypes.bool,
  /**
   * Will render the component in it's disabled state.
   */
  isDisabled: PropTypes.bool,
  /**
   * 	Assigned to the `value` attribute
   *  of the rendered input element.
   */
  value: PropTypes.string,
  /**
   * Assigned to the `id` attribute
   * of the rendered input element.
   * A custom ID will
   * be added if this is not supplied.
   */
  id: PropTypes.string,
  /**
   * Assigned to the `aria-describedby`
   * attribute. Used to create
   * relationships between the
   * component and text that describes it,
   * such as helper text or an error field.
   */
  ariaDescribedBy: PropTypes.string,
};

SprkDatePicker.defaultProps = {
  datePickerConfig: {},
  formatter: (value) => value,
  isValid: true,
  id: uniqueId('sprk-datepicker-'),
  isDisabled: false,
};

export default SprkDatePicker;
<|endoftext|>


<commit_before>
import {handleActions} from 'redux-actions'
import {map, reject, omit, object, pick, indexBy} from 'underline'
import invariant from 'invariant'
import uuid from 'node-uuid'

import SearchExamples from '../../constants/search-examples'
import staticTabData from '../../constants/static-tab-data'

import {filter} from 'underline'

const perish = process.env.PERISH === '1' ? console.log.bind(console) : () => 0

const baseTabs = ['featured', 'library', 'collections']

const initialState = {
  page: 'gate',
  tabs: {
    constant: baseTabs,
    transient: []
  },
  tabData: staticTabData::pick(...baseTabs)::indexBy('id'),
  id: 'featured',
  shortcutsShown: false
}

export default handleActions({
  SHORTCUTS_VISIBILITY_CHANGED: (state, action) => {
    const {visible} = action.payload
    return {...state, shortcutsShown: visible}
  },

  SWITCH_PAGE: (state, action) => {
    const page = action.payload
    return {...state, page}
  },

  NAVIGATE: (state, action) => {
    const {id, data} = action.payload
    invariant(typeof id === 'string', 'id must be a string')
    invariant(typeof data === 'object', 'data must be an object')

    const {tabData} = state
    const {tabs} = state
    const {constant, transient} = tabs

    const tabsByPath = tabData::map((x, id) => [x.path, id])::object()

    if (tabData[id]) {
      // switching to an existing tab, by id
      return {...state, id}
    } else if (tabsByPath[id]) {
      // switching to an existing tab, by path (don't open same game twice, etc.)
      const idForPath = tabsByPath[id]
      return {...state, id: idForPath}
    } else {
      // open a new tab
      // static tabs don't get UUIDs
      const newTab = staticTabData[id] ? id : uuid.v4()

      const newTabs = {
        constant,
        transient: [
          ...transient,
          newTab
        ]
      }

      const newTabData = {
        ...tabData,
        [newTab]: {
          ...staticTabData[id],
          ...tabData[id],
          path: id,
          ...data
        }
      }

      return {...state, id: newTab, tabs: newTabs, tabData: newTabData}
    }
  },

  MOVE_TAB: (state, action) => {
    const {before, after} = action.payload
    invariant(typeof before === 'number', 'old tab index is a number')
    invariant(typeof after === 'number', 'new tab index is a number')

    const {tabs} = state
    const {transient} = tabs

    const newTransient = transient::map((t, i) => {
      switch (i) {
        case before:
          return transient[after]
        case after:
          return transient[before]
        default:
          return t
      }
    })

    return {
      ...state,
      tabs: {
        ...tabs,
        transient: newTransient
      }
    }
  },

  CLOSE_TAB: (state, action) => {
    const {id, tabs, tabData} = state
    const closeId = action.payload || id
    const {constant, transient} = tabs

    const ids = constant.concat(transient)
    const index = ids.indexOf(id)

    const newTransient = transient::reject((x) => x === closeId)
    const newTabData = tabData::omit(closeId)

    const newIds = constant.concat(newTransient)
    const numNewIds = newIds.length

    const nextIndex = Math.min(index, numNewIds - 1)
    const newId = newIds[nextIndex]

    return {
      ...state,
      id: newId,
      tabs: {
        constant,
        transient: newTransient
      },
      tabData: newTabData
    }
  },

  SEARCH_FETCHED: (state, action) => {
    const {results} = action.payload
    const searchExampleIndex = Math.floor(Math.random() * (SearchExamples.length - 1))
    return {...state, searchResults: results, searchOpen: true, searchExample: SearchExamples[searchExampleIndex]}
  },

  TAB_DATA_FETCHED: (state, action) => {
    const {id, timestamp, data} = action.payload
    if (!timestamp) {
      perish('Ignoring non-timestamped tabData: ', id, data)
      return state
    }

    const {tabData} = state
    const oldData = tabData[id]
    if (oldData && oldData.timestamp && oldData.timestamp > timestamp) {
      perish('Ignoring stale tabData: ', id, data)
      return state
    }

    const newTabData = {
      ...tabData,
      [id]: {
        ...tabData[id],
        ...data
      }
    }

    return {...state, tabData: newTabData}
  },

  TAB_EVOLVED: (state, action) => {
    const {id, data} = action.payload
    invariant(typeof id === 'string', 'id must be a string')

    const {tabData} = state
    const newTabData = {
      ...tabData,
      [id]: {
        ...tabData[id],
        ...data
      }
    }

    return {
      ...state,
      tabData: newTabData
    }
  },

  TABS_RESTORED: (state, action) => {
    const snapshot = action.payload
    invariant(typeof snapshot === 'object', 'tab snapshot must be an object')

    const id = snapshot.current || state.id
    const tabData = []
    const transient = snapshot.items::map((tab) => {
      if (typeof tab !== 'object' || !tab.id || !tab.path) {
        return
      }

      tabData[tab.id] = {
        path: tab.path
      }
      return tab.id
    })::filter((x) => !!x)

    return {
      ...state,
      id,
      tabs: {
        ...state.tabs,
        transient
      },
      tabData: {
        ...state.tabData,
        ...tabData
      }
    }
  },

  LOGOUT: (state, action) => {
    return initialState
  },

  // happens after SESSION_READY depending on the user's profile (press, developer)
  UNLOCK_TAB: (state, action) => {
    const {path} = action.payload
    invariant(typeof path === 'string', 'unlocked tab path must be a string')

    const {constant} = state.tabs

    return {
      ...state,
      tabs: {
        ...state.tabs,
        constant: [
          ...constant,
          path
        ]
      },
      tabData: {
        ...state.tabData,
        [path]: {
          ...state.tabData[path],
          ...staticTabData[path]
        }
      }
    }
  },

  CLOSE_SEARCH: (state, action) => {
    return {...state, searchResults: null, searchOpen: false}
  }
}, initialState)
<commit_msg>Fix selection change behavior when closing tabs. Closes #612<commit_after>
import {handleActions} from 'redux-actions'
import {map, reject, omit, object, pick, indexBy} from 'underline'
import invariant from 'invariant'
import uuid from 'node-uuid'

import SearchExamples from '../../constants/search-examples'
import staticTabData from '../../constants/static-tab-data'

import {filter} from 'underline'

const perish = process.env.PERISH === '1' ? console.log.bind(console) : () => 0

const baseTabs = ['featured', 'library', 'collections']

const initialState = {
  page: 'gate',
  tabs: {
    constant: baseTabs,
    transient: []
  },
  tabData: staticTabData::pick(...baseTabs)::indexBy('id'),
  id: 'featured',
  shortcutsShown: false
}

export default handleActions({
  SHORTCUTS_VISIBILITY_CHANGED: (state, action) => {
    const {visible} = action.payload
    return {...state, shortcutsShown: visible}
  },

  SWITCH_PAGE: (state, action) => {
    const page = action.payload
    return {...state, page}
  },

  NAVIGATE: (state, action) => {
    const {id, data} = action.payload
    invariant(typeof id === 'string', 'id must be a string')
    invariant(typeof data === 'object', 'data must be an object')

    const {tabData} = state
    const {tabs} = state
    const {constant, transient} = tabs

    const tabsByPath = tabData::map((x, id) => [x.path, id])::object()

    if (tabData[id]) {
      // switching to an existing tab, by id
      return {...state, id}
    } else if (tabsByPath[id]) {
      // switching to an existing tab, by path (don't open same game twice, etc.)
      const idForPath = tabsByPath[id]
      return {...state, id: idForPath}
    } else {
      // open a new tab
      // static tabs don't get UUIDs
      const newTab = staticTabData[id] ? id : uuid.v4()

      const newTabs = {
        constant,
        transient: [
          ...transient,
          newTab
        ]
      }

      const newTabData = {
        ...tabData,
        [newTab]: {
          ...staticTabData[id],
          ...tabData[id],
          path: id,
          ...data
        }
      }

      return {...state, id: newTab, tabs: newTabs, tabData: newTabData}
    }
  },

  MOVE_TAB: (state, action) => {
    const {before, after} = action.payload
    invariant(typeof before === 'number', 'old tab index is a number')
    invariant(typeof after === 'number', 'new tab index is a number')

    const {tabs} = state
    const {transient} = tabs

    const newTransient = transient::map((t, i) => {
      switch (i) {
        case before:
          return transient[after]
        case after:
          return transient[before]
        default:
          return t
      }
    })

    return {
      ...state,
      tabs: {
        ...tabs,
        transient: newTransient
      }
    }
  },

  CLOSE_TAB: (state, action) => {
    const {id, tabs, tabData} = state
    const closeId = action.payload || id
    const {constant, transient} = tabs

    const ids = constant.concat(transient)
    const index = ids.indexOf(id)

    const newTransient = transient::reject((x) => x === closeId)
    const newTabData = tabData::omit(closeId)

    let newId = id
    if (id === closeId) {
      const newIds = constant.concat(newTransient)
      const numNewIds = newIds.length

      const nextIndex = Math.min(index, numNewIds - 1)
      newId = newIds[nextIndex]
    }

    return {
      ...state,
      id: newId,
      tabs: {
        constant,
        transient: newTransient
      },
      tabData: newTabData
    }
  },

  SEARCH_FETCHED: (state, action) => {
    const {results} = action.payload
    const searchExampleIndex = Math.floor(Math.random() * (SearchExamples.length - 1))
    return {...state, searchResults: results, searchOpen: true, searchExample: SearchExamples[searchExampleIndex]}
  },

  TAB_DATA_FETCHED: (state, action) => {
    const {id, timestamp, data} = action.payload
    if (!timestamp) {
      perish('Ignoring non-timestamped tabData: ', id, data)
      return state
    }

    const {tabData} = state
    const oldData = tabData[id]
    if (oldData && oldData.timestamp && oldData.timestamp > timestamp) {
      perish('Ignoring stale tabData: ', id, data)
      return state
    }

    const newTabData = {
      ...tabData,
      [id]: {
        ...tabData[id],
        ...data
      }
    }

    return {...state, tabData: newTabData}
  },

  TAB_EVOLVED: (state, action) => {
    const {id, data} = action.payload
    invariant(typeof id === 'string', 'id must be a string')

    const {tabData} = state
    const newTabData = {
      ...tabData,
      [id]: {
        ...tabData[id],
        ...data
      }
    }

    return {
      ...state,
      tabData: newTabData
    }
  },

  TABS_RESTORED: (state, action) => {
    const snapshot = action.payload
    invariant(typeof snapshot === 'object', 'tab snapshot must be an object')

    const id = snapshot.current || state.id
    const tabData = []
    const transient = snapshot.items::map((tab) => {
      if (typeof tab !== 'object' || !tab.id || !tab.path) {
        return
      }

      tabData[tab.id] = {
        path: tab.path
      }
      return tab.id
    })::filter((x) => !!x)

    return {
      ...state,
      id,
      tabs: {
        ...state.tabs,
        transient
      },
      tabData: {
        ...state.tabData,
        ...tabData
      }
    }
  },

  LOGOUT: (state, action) => {
    return initialState
  },

  // happens after SESSION_READY depending on the user's profile (press, developer)
  UNLOCK_TAB: (state, action) => {
    const {path} = action.payload
    invariant(typeof path === 'string', 'unlocked tab path must be a string')

    const {constant} = state.tabs

    return {
      ...state,
      tabs: {
        ...state.tabs,
        constant: [
          ...constant,
          path
        ]
      },
      tabData: {
        ...state.tabData,
        [path]: {
          ...state.tabData[path],
          ...staticTabData[path]
        }
      }
    }
  },

  CLOSE_SEARCH: (state, action) => {
    return {...state, searchResults: null, searchOpen: false}
  }
}, initialState)
<|endoftext|>


<commit_before>describe("RoomController ", function() {
    var rootScope, scope, ctrl, $q, $timeout, routeParams;
    var userId = "@foo:bar";
    var displayName = "Foo";
    var avatarUrl = "avatar.url";
    var roomId = "!ygsffwe:matrix.org";

    var dialogService = {
        showError: function(err){}, // will be spyed
        showSuccess: function(a,b){} // will be spyed
    };

    // test vars
    var testRoom, testPaginationChunk;

    // mock services
    var matrixService = {
        config: function() {
            return {
                user_id: userId
            }
        },
        paginateBackMessages: function(roomId, token, num){
            return resolve(testPaginationChunk, true);
        },
        setName: function(rm,name){},
        setTopic: function(rm,topic){}
    };

    var eventHandlerService = {
        joinRoom: function(rm){},
        handleRoomMessages: function(room, data, live, dir){},
        sendMessage: function(rm,input){}
    };
    var mFileUpload = {};
    var mUserDisplayNameFilter = function(roomId){ return "";};
    var modelService = {
        getRoom: function(roomId) {
            return testRoom;
        }
    };
    var recentsService = {
        setSelectedRoomId: function(roomId){}
    };
    var commandsService = {
        processInput: function(roomId, input){}
    };
    var MatrixCall = {};

    beforeEach(function() {
        module('matrixWebClient');

        // reset test vars
        testRoom = {
            room_id: roomId,
            old_room_state: {},
            current_room_state: {
                state_events: {}
            },
            events: []
        };

        testPaginationChunk = {
            chunk: [],
            start: "s",
            end: "e"
        };
    });

    // helper methods
    var resolve = function(output, isHttp) {
        var d = $q.defer();
        if (isHttp) {
            d.resolve({ data: output });
        }
        else {
            d.resolve(output);
        }
        return d.promise;
    };

    var reject = function(output, isHttp) {
        var d = $q.defer();
        if (isHttp) {
            d.reject({ data: output });
        }
        else {
            d.reject(output);
        }
        return d.promise;
    };

    beforeEach(inject(function($rootScope, $injector, $controller, _$q_, _$timeout_) {
            $q = _$q_;
            $timeout = _$timeout_;
            scope = $rootScope.$new();
            rootScope = $rootScope;
            routeParams = {

            };
            ctrl = $controller('RoomController', {
                '$scope': scope,
                '$rootScope': $rootScope,
                'matrixService': matrixService,
                'mUserDisplayNameFilter': mUserDisplayNameFilter,
                'eventHandlerService': eventHandlerService,
                'modelService': modelService,
                'recentsService': recentsService,
                'commandsService': commandsService,
                'MatrixCall': MatrixCall,
                'mFileUpload': mFileUpload,
                'dialogService': dialogService,
                '$routeParams': routeParams
            });
        })
    );

    it('should load a room alias in the url when initialised.', function() {
        var roomAlias = "#roomalias:matrix.org";
        routeParams.room_id_or_alias = encodeURIComponent(roomAlias);

        spyOn(eventHandlerService, "joinRoom").and.callFake(function(room) {
            return resolve("!roomid:matrix.org");
        });

        scope.onInit();
        rootScope.$digest();
        expect(eventHandlerService.joinRoom).toHaveBeenCalledWith(roomAlias);

    });

    it('should load a room ID in the url when initialised.', function() {
        var id = "!sdofh:matrix.org";
        routeParams.room_id_or_alias = encodeURIComponent(id);

        spyOn(eventHandlerService, "joinRoom").and.callFake(function(room) {
            return resolve(id);
        });

        scope.onInit();
        rootScope.$digest();
        expect(eventHandlerService.joinRoom).toHaveBeenCalledWith(id);

    });

    it('should be able to send a message.', function() {
        // setup
        var id = "!sdofh:matrix.org";
        var input = "Hello world";
        routeParams.room_id_or_alias = encodeURIComponent(id);
        spyOn(eventHandlerService, "joinRoom").and.returnValue(resolve(id));
        scope.onInit();
        rootScope.$digest();

        spyOn($.fn, "val").and.returnValue(input);
        spyOn(eventHandlerService, "sendMessage");
        scope.send();
        expect(eventHandlerService.sendMessage).toHaveBeenCalledWith(id, input, jasmine.any(Object));
    });

    it('should show an error if it failed to send a message.', function() {
        // setup
        var id = "!sdofh:matrix.org";
        var input = "Hello world";
        routeParams.room_id_or_alias = encodeURIComponent(id);
        spyOn(eventHandlerService, "joinRoom").and.returnValue(resolve(id));
        scope.onInit();
        rootScope.$digest();

        spyOn($.fn, "val").and.returnValue(input);
        spyOn(eventHandlerService, "sendMessage");
        scope.send();

        var error = "Oh no";
        spyOn(dialogService, "showError");
        var callback = eventHandlerService.sendMessage.calls.argsFor(0)[2];
        callback.onError(error);
        expect(dialogService.showError).toHaveBeenCalledWith(error);
    });

    it('should be able to edit the room name.', function() {
        var roomId = "!wefweui:matrix.org";
        var roomName = "Room Name";
        var newRoomName = "New Room Name";
        scope.room_id = roomId;
        scope.room = testRoom;
        testRoom.current_room_state.state_events["m.room.name"] = {
            content: {
                name: roomName
            },
            user_id: "@a:b",
            room_id: roomId,
            type: "m.room.name",
            event_id: "a"
        };

        expect(scope.name.isEditing).toBe(false);
        scope.name.editName(); //e.g. double click
        expect(scope.name.isEditing).toBe(true);
        expect(scope.name.newNameText).toEqual(roomName); // pre-fill current name
        scope.name.newNameText = newRoomName; // simulate user input
        spyOn(matrixService, "setName").and.returnValue(resolve({}));
        scope.name.updateName();
        expect(matrixService.setName).toHaveBeenCalledWith(roomId, newRoomName);
    });
});
<commit_msg>More room controller tests.<commit_after>describe("RoomController ", function() {
    var rootScope, scope, ctrl, $q, $timeout, routeParams;
    var userId = "@foo:bar";
    var displayName = "Foo";
    var avatarUrl = "avatar.url";
    var roomId = "!ygsffwe:matrix.org";

    var dialogService = {
        showError: function(err){}, // will be spyed
        showSuccess: function(a,b){} // will be spyed
    };

    // test vars
    var testRoom, testPaginationChunk;

    // mock services
    var matrixService = {
        config: function() {
            return {
                user_id: userId
            }
        },
        paginateBackMessages: function(roomId, token, num){
            return resolve(testPaginationChunk, true);
        },
        setName: function(rm,name){},
        setTopic: function(rm,topic){},
        redactEvent: function(roomId, eventId){}
    };

    var eventHandlerService = {
        joinRoom: function(rm){},
        handleRoomMessages: function(room, data, live, dir){},
        sendMessage: function(rm,input){},
        resendMessage: function(event, cb){}
    };
    var mFileUpload = {};
    var mUserDisplayNameFilter = function(roomId){ return "";};
    var modelService = {
        getRoom: function(roomId) {
            return testRoom;
        }
    };
    var recentsService = {
        setSelectedRoomId: function(roomId){}
    };
    var commandsService = {
        processInput: function(roomId, input){}
    };
    var MatrixCall = {};
    var modal = {
        open: function(){}
    };

    beforeEach(function() {
        module('matrixWebClient');

        // reset test vars
        testRoom = {
            room_id: roomId,
            old_room_state: {},
            current_room_state: {
                state_events: {}
            },
            events: []
        };

        testPaginationChunk = {
            chunk: [],
            start: "s",
            end: "e"
        };
    });

    // helper methods
    var resolve = function(output, isHttp) {
        var d = $q.defer();
        if (isHttp) {
            d.resolve({ data: output });
        }
        else {
            d.resolve(output);
        }
        return d.promise;
    };

    var reject = function(output, isHttp) {
        var d = $q.defer();
        if (isHttp) {
            d.reject({ data: output });
        }
        else {
            d.reject(output);
        }
        return d.promise;
    };

    beforeEach(inject(function($rootScope, $injector, $controller, _$q_, _$timeout_) {
            $q = _$q_;
            $timeout = _$timeout_;
            scope = $rootScope.$new();
            rootScope = $rootScope;
            routeParams = {

            };
            ctrl = $controller('RoomController', {
                '$scope': scope,
                '$rootScope': $rootScope,
                'matrixService': matrixService,
                'mUserDisplayNameFilter': mUserDisplayNameFilter,
                'eventHandlerService': eventHandlerService,
                'modelService': modelService,
                'recentsService': recentsService,
                'commandsService': commandsService,
                'MatrixCall': MatrixCall,
                'mFileUpload': mFileUpload,
                'dialogService': dialogService,
                '$routeParams': routeParams,
                '$modal': modal
            });
        })
    );

    it('should load a room alias in the url when initialised.', function() {
        var roomAlias = "#roomalias:matrix.org";
        routeParams.room_id_or_alias = encodeURIComponent(roomAlias);

        spyOn(eventHandlerService, "joinRoom").and.callFake(function(room) {
            return resolve("!roomid:matrix.org");
        });

        scope.onInit();
        rootScope.$digest();
        expect(eventHandlerService.joinRoom).toHaveBeenCalledWith(roomAlias);

    });

    it('should load a room ID in the url when initialised.', function() {
        var id = "!sdofh:matrix.org";
        routeParams.room_id_or_alias = encodeURIComponent(id);

        spyOn(eventHandlerService, "joinRoom").and.callFake(function(room) {
            return resolve(id);
        });

        scope.onInit();
        rootScope.$digest();
        expect(eventHandlerService.joinRoom).toHaveBeenCalledWith(id);

    });

    it('should be able to send a message.', function() {
        // setup
        var id = "!sdofh:matrix.org";
        var input = "Hello world";
        routeParams.room_id_or_alias = encodeURIComponent(id);
        spyOn(eventHandlerService, "joinRoom").and.returnValue(resolve(id));
        scope.onInit();
        rootScope.$digest();

        spyOn($.fn, "val").and.returnValue(input);
        spyOn(eventHandlerService, "sendMessage");
        scope.send();
        expect(eventHandlerService.sendMessage).toHaveBeenCalledWith(id, input, jasmine.any(Object));
    });

    it('should show an error if it failed to send a message.', function() {
        // setup
        var id = "!sdofh:matrix.org";
        var input = "Hello world";
        routeParams.room_id_or_alias = encodeURIComponent(id);
        spyOn(eventHandlerService, "joinRoom").and.returnValue(resolve(id));
        scope.onInit();
        rootScope.$digest();

        spyOn($.fn, "val").and.returnValue(input);
        spyOn(eventHandlerService, "sendMessage");
        scope.send();

        var error = "Oh no";
        spyOn(dialogService, "showError");
        var callback = eventHandlerService.sendMessage.calls.argsFor(0)[2];
        callback.onError(error);
        expect(dialogService.showError).toHaveBeenCalledWith(error);
    });

    it('should be able to edit the room name.', function() {
        var roomId = "!wefweui:matrix.org";
        var roomName = "Room Name";
        var newRoomName = "New Room Name";
        scope.room_id = roomId;
        scope.room = testRoom;
        testRoom.current_room_state.state_events["m.room.name"] = {
            content: {
                name: roomName
            },
            user_id: "@a:b",
            room_id: roomId,
            type: "m.room.name",
            event_id: "a"
        };

        expect(scope.name.isEditing).toBe(false);
        scope.name.editName(); //e.g. double click
        expect(scope.name.isEditing).toBe(true);
        expect(scope.name.newNameText).toEqual(roomName); // pre-fill current name
        scope.name.newNameText = newRoomName; // simulate user input
        spyOn(matrixService, "setName").and.returnValue(resolve({}));
        scope.name.updateName();
        expect(matrixService.setName).toHaveBeenCalledWith(roomId, newRoomName);
    });

    it('should be able to edit the room topic.', function() {
        var roomId = "!wefweui:matrix.org";
        var roomTopic = "Room Topic";
        var newRoomTopic = "New Room Topic";
        scope.room_id = roomId;
        scope.room = testRoom;
        testRoom.current_room_state.state_events["m.room.topic"] = {
            content: {
                topic: roomTopic
            },
            user_id: "@a:b",
            room_id: roomId,
            type: "m.room.topic",
            event_id: "a"
        };

        expect(scope.topic.isEditing).toBe(false);
        scope.topic.editTopic(); //e.g. double click
        expect(scope.topic.isEditing).toBe(true);
        expect(scope.topic.newTopicText).toEqual(roomTopic); // pre-fill current topic
        scope.topic.newTopicText = newRoomTopic; // simulate user input
        spyOn(matrixService, "setTopic").and.returnValue(resolve({}));
        scope.topic.updateTopic();
        expect(matrixService.setTopic).toHaveBeenCalledWith(roomId, newRoomTopic);
    });

    it('should lock the room when banned.', function() {
        var roomId = "!wefweui:matrix.org";
        scope.room_id = roomId;
        scope.room = testRoom;

        expect(scope.state.permission_denied).toBeUndefined();

        scope.$broadcast(eventHandlerService.MEMBER_EVENT, {
            content: {
                membership: "ban"
            },
            state_key: userId,
            user_id: "@a:b",
            room_id: roomId,
            event_id: "a",
            type: "m.room.member"
        }, true);

        expect(scope.state.permission_denied).toBeDefined();
    });

    it('should lock the room when they leave.', function() {
        var roomId = "!wefweui:matrix.org";
        scope.room_id = roomId;
        scope.room = testRoom;

        expect(scope.state.permission_denied).toBeUndefined();

        scope.$broadcast(eventHandlerService.MEMBER_EVENT, {
            content: {
                membership: "leave"
            },
            state_key: userId,
            user_id: userId,
            room_id: roomId,
            event_id: "a",
            type: "m.room.member"
        }, true);

        expect(scope.state.permission_denied).toBeDefined();
    });

    it('should lock the room when they are kicked.', function() {
        var roomId = "!wefweui:matrix.org";
        scope.room_id = roomId;
        scope.room = testRoom;

        expect(scope.state.permission_denied).toBeUndefined();

        scope.$broadcast(eventHandlerService.MEMBER_EVENT, {
            content: {
                membership: "leave"
            },
            state_key: userId,
            user_id: "@a:b",
            room_id: roomId,
            event_id: "a",
            type: "m.room.member"
        }, true);

        expect(scope.state.permission_denied).toBeDefined();
    });

    it('should be able to open the event info dialog.', function() {
        var roomId = "!wefweui:matrix.org";
        scope.room_id = roomId;
        scope.room = testRoom;

        var event = {
            content: {
                body: "something naughty",
                msgtype: "m.text"
            },
            user_id: userId,
            type: "m.room.message",
            event_id: "aa"
        };

        var defer = $q.defer();
        spyOn(modal, "open").and.callFake(function() {
            return {
                result: defer.promise
            };
        });
        expect(scope.event_selected).toBeUndefined();
        scope.openJson(event);
        expect(modal.open).toHaveBeenCalled();
        expect(scope.event_selected).toEqual(jasmine.objectContaining(event));
    });

    it('should be able to redact an event on the event info dialog.', function() {
        var roomId = "!wefweui:matrix.org";
        var eventId = "aaa";
        scope.room_id = roomId;
        scope.room = testRoom;

        var event = {
            content: {
                body: "something naughty",
                msgtype: "m.text"
            },
            user_id: userId,
            type: "m.room.message",
            room_id: roomId,
            event_id: eventId
        };

        // open the dialog
        var defer = $q.defer();
        spyOn(modal, "open").and.callFake(function() {
            return {
                result: defer.promise
            };
        });
        scope.openJson(event);

        // hit the redact button
        var redactDefer = $q.defer();
        spyOn(matrixService, "redactEvent").and.callFake(function() {
            return redactDefer.promise;
        });
        defer.resolve("redact");
        scope.$digest();
        expect(matrixService.redactEvent).toHaveBeenCalledWith(roomId, eventId);
    });

    it('should be able to resend an event on the event info dialog.', function() {
        var roomId = "!wefweui:matrix.org";
        var eventId = "aaa";
        scope.room_id = roomId;
        scope.room = testRoom;

        var event = {
            content: {
                body: "something naughty",
                msgtype: "m.text"
            },
            user_id: userId,
            type: "m.room.message",
            room_id: roomId,
            event_id: eventId,
            __echo_msg_state: "messageUnSent"
        };

        // open the dialog
        var defer = $q.defer();
        spyOn(modal, "open").and.callFake(function() {
            return {
                result: defer.promise
            };
        });
        scope.openJson(event);

        // hit the resend button
        var resendDefer = $q.defer();
        spyOn(eventHandlerService, "resendMessage").and.callFake(function() {
            return resendDefer.promise;
        });
        defer.resolve("resend");
        scope.$digest();
        expect(eventHandlerService.resendMessage).toHaveBeenCalledWith(
            event,
            jasmine.any(Object)
        );
    });

    it('should be able to open the room info dialog.', function() {
        var roomId = "!wefweui:matrix.org";
        var eventId = "aaa";
        scope.room_id = roomId;
        scope.room = testRoom;

        // open the dialog
        var defer = $q.defer();
        spyOn(modal, "open").and.callFake(function() {
            return {
                result: defer.promise
            };
        });
        scope.openRoomInfo();
        expect(modal.open).toHaveBeenCalled();
    });
});
<|endoftext|>