<commit_before>import d3 from "d3"

var height=200,width=1200;

var viz=(stackdataArr,color2,bun,svg) => {
	console.log("func viz start");

	var stack = d3.layout.stack()
	.x(function(d){return 1;})
	.y(function(d){return d.y;})
	.values(function(d){return d;});
	var stackdata = stack(stackdataArr);
	var max = d3.max(stackdata[stackdata.length-1], function(d){return d.y + d.y0;});
	var scaleX = d3.scale.linear().domain([0,color2.length]).range([width/(color2.length),width]);
	var scaleY = d3.scale.linear().domain([0,max]).range([0,height]);
	var colors = ["#7777ff","#77ff77","#ff7777"];

	var area = d3.svg.area()
	.x(function(d,i){return (i+1) * width/color2.length})
	.y0(function(d){return height})
	.y1(function(d){return height - scaleY(d.y+d.y0)});
	svg.selectAll("path")
	.data(stackdata.reverse())
	.enter()
	.append("path")
	.attr("d", area)
	.attr("fill",function(d,i){return colors[i]});

	var range = d3.range((width)-(width/(color2.length*2)), color2.length-1, -width/(color2.length));
	svg.selectAll("line.v")
	.data(range).enter().append("line")
	.attr("x1", function(d,i){return d;}).attr("y1", 0)
	.attr("x2", function(d,i){return d;}).attr("y2", height);
	svg.selectAll("line")
	.attr("stroke", function(d,i){return color2[color2.length-1-i]})
	.attr("stroke-width", 3)
	.on('mouseover', function(d,i){
		console.log("%d,%s",2*(color2.length-i-1),bun[2*(color2.length-i-1)]);
		var e = document.getElementById('msg');
		e.innerHTML = bun[-3+2*(color2.length-i-1)]+"
"+bun[-2+2*(color2.length-i-1)]+"
"+bun[-1+2*(color2.length-i-1)]+"
"+bun[2*(color2.length-i-1)]+"
"+bun[1+2*(color2.length-i-1)]+"
"+bun[2+2*(color2.length-i-1)]+"
"+bun[3+2*(color2.length-i-1)];
		e.style.color = color2[color2.length-1-i];
	})
};

var funcChecked = (chboxlist,checked) => {
	console.log("funcChecked");
	var c;
	for(c=1;c<chboxlist.length;c++){
		const radio = document.getElementById(c).children;
		for(let i = 1, l = radio.length; i < l; i++){
			if(radio[i].control.checked==true){
				checked[c-1] = radio[i].control.value;
				if(radio[i].control.value=="1"){
					checked[c-1] =1;
				}else if(radio[i].control.value=="2"){
					checked[c-1] =2;
				}else if(radio[i].control.value=="3"){
					checked[c-1] =3;
				}else{
					checked[c-1] =0;
				}
			}
		}
	}
};

var setForViz = (keitaisokaiseki,checkboxlist,chboxlist,RGBlist,hatsugen,bun) => {

	d3.select("#svgdiv").select("svg").remove();

	var svg = d3.select("#svgdiv").append("svg")
	.attr("height",height)
	.attr("width",width);

	console.log("setForViz");
	var checked = [];
	var color2=[];
	var stackdataArr = [];
	funcChecked(chboxlist,checked);
	var h,i,j,c,m,n;

	for(n=0;n<RGBlist.length;n++){
		RGBlist[n][0]=0;
		RGBlist[n][1]=0;
		RGBlist[n][2]=0;
	}

	for(c=1;c<chboxlist.length;c++){
		if (checked[c]>=1) {
			console.log("checked[%d]=%d",c,checked[c]);
			n=0;
			for(m=1;m<keitaisokaiseki.length;m=m+2){
				for(i=0;i<keitaisokaiseki[m].length;i++){
					j=0;
					for(j=0;j<keitaisokaiseki[m][i].length;j++){
						if(keitaisokaiseki[m][i][j]==chboxlist[c][0]){
							console.log(chboxlist[c][0]);
							if(checked[c]==1){
								console.log("c=%d,m=%d,n=%d,%s",c,m,n,chboxlist[c][0]);
								RGBlist[n][0]=RGBlist[n][0]+1;
							}else if(checked[c]==2){
								console.log("c=%d,n=%d,%s",c,n,chboxlist[c][0]);
								RGBlist[n][1]=RGBlist[n][1]+1;
							}else if(checked[c]==3){
								console.log("c=%d,n=%d,%s",c,n,chboxlist[c][0]);
								RGBlist[n][2]=RGBlist[n][2]+1;
							}
						}
					}
				}
				n++
			}

		}
	}
	console.log(RGBlist);

	for(m=0;m<keitaisokaiseki.length/2;m++){
		if(RGBlist[m][3]>=1){
			color2[m]="#d4d";
		}else{
			color2[m]="gray";
		}
	}
	//console.log("color2.length"color2);

	for(h=0;h<3;h++){
		stackdataArr[h] = [];
		for(m=0;m<((keitaisokaiseki.length-1)/2);m++){//2個飛ばしにしたら後が面倒くさい。患者 1→0　3→1 長さ9なら番号は8まで
			stackdataArr[h][m]=new Object();
			stackdataArr[h][m]= {x:m+1,y:(28*(RGBlist[m][h])/(keitaisokaiseki[2*m+1].length))};
			console.log(stackdataArr[h][m]);
		}
	}

	viz(stackdataArr,color2,bun,svg);
}

//      radio[i].onchange = () => {};

export {setForViz};
<commit_msg>max deleted<commit_after>import d3 from "d3"

var height=200,width=1200;

var viz=(stackdataArr,color2,bun,svg) => {
	console.log("func viz start");

	var stack = d3.layout.stack()
	.x(function(d){return 1;})
	.y(function(d){return d.y;})
	.values(function(d){return d;});
	var stackdata = stack(stackdataArr);
	//var max = d3.max(stackdata[stackdata.length-1], function(d){return d.y + d.y0;});
	var scaleX = d3.scale.linear().domain([0,color2.length]).range([width/(color2.length),width]);
	var scaleY = d3.scale.linear().domain([0,6]).range([0,height]);
	var colors = ["#7777ff","#77ff77","#ff7777"];

	var area = d3.svg.area()
	.x(function(d,i){return (i+1) * width/color2.length})
	.y0(function(d){return height})
	.y1(function(d){return height - scaleY(d.y+d.y0)});
	svg.selectAll("path")
	.data(stackdata.reverse())
	.enter()
	.append("path")
	.attr("d", area)
	.attr("fill",function(d,i){return colors[i]});

	var range = d3.range((width)-(width/(color2.length*2)), color2.length-1, -width/(color2.length));
	svg.selectAll("line.v")
	.data(range).enter().append("line")
	.attr("x1", function(d,i){return d;}).attr("y1", 0)
	.attr("x2", function(d,i){return d;}).attr("y2", height);
	svg.selectAll("line")
	.attr("stroke", function(d,i){return color2[color2.length-1-i]})
	.attr("stroke-width", 3)
	.on('mouseover', function(d,i){
		console.log("%d,%s",2*(color2.length-i-1),bun[2*(color2.length-i-1)]);
		var e = document.getElementById('msg');
		e.innerHTML = bun[-3+2*(color2.length-i-1)]+"
"+bun[-2+2*(color2.length-i-1)]+"
"+bun[-1+2*(color2.length-i-1)]+"
"+bun[2*(color2.length-i-1)]+"
"+bun[1+2*(color2.length-i-1)]+"
"+bun[2+2*(color2.length-i-1)]+"
"+bun[3+2*(color2.length-i-1)];
		e.style.color = color2[color2.length-1-i];
	})
};

var funcChecked = (chboxlist,checked) => {
	console.log("funcChecked");
	var c;
	for(c=1;c<chboxlist.length;c++){
		const radio = document.getElementById(c).children;
		for(let i = 1, l = radio.length; i < l; i++){
			if(radio[i].control.checked==true){
				checked[c-1] = radio[i].control.value;
				if(radio[i].control.value=="1"){
					checked[c-1] =1;
				}else if(radio[i].control.value=="2"){
					checked[c-1] =2;
				}else if(radio[i].control.value=="3"){
					checked[c-1] =3;
				}else{
					checked[c-1] =0;
				}
			}
		}
	}
};

var setForViz = (keitaisokaiseki,checkboxlist,chboxlist,RGBlist,hatsugen,bun) => {

	d3.select("#svgdiv").select("svg").remove();

	var svg = d3.select("#svgdiv").append("svg")
	.attr("height",height)
	.attr("width",width);

	console.log("setForViz");
	var checked = [];
	var color2=[];
	var stackdataArr = [];
	funcChecked(chboxlist,checked);
	var h,i,j,c,m,n;

	for(n=0;n<RGBlist.length;n++){
		RGBlist[n][0]=0;
		RGBlist[n][1]=0;
		RGBlist[n][2]=0;
	}

	for(c=1;c<chboxlist.length;c++){
		if (checked[c]>=1) {
			console.log("checked[%d]=%d",c,checked[c]);
			n=0;
			for(m=1;m<keitaisokaiseki.length;m=m+2){
				for(i=0;i<keitaisokaiseki[m].length;i++){
					j=0;
					for(j=0;j<keitaisokaiseki[m][i].length;j++){
						if(keitaisokaiseki[m][i][j]==chboxlist[c][0]){
							console.log(chboxlist[c][0]);
							if(checked[c]==1){
								console.log("c=%d,m=%d,n=%d,%s",c,m,n,chboxlist[c][0]);
								RGBlist[n][0]=RGBlist[n][0]+1;
							}else if(checked[c]==2){
								console.log("c=%d,n=%d,%s",c,n,chboxlist[c][0]);
								RGBlist[n][1]=RGBlist[n][1]+1;
							}else if(checked[c]==3){
								console.log("c=%d,n=%d,%s",c,n,chboxlist[c][0]);
								RGBlist[n][2]=RGBlist[n][2]+1;
							}
						}
					}
				}
				n++
			}

		}
	}
	console.log(RGBlist);

	for(m=0;m<keitaisokaiseki.length/2;m++){
		if(RGBlist[m][3]>=1){
			color2[m]="#d4d";
		}else{
			color2[m]="gray";
		}
	}
	//console.log("color2.length"color2);

	for(h=0;h<3;h++){
		stackdataArr[h] = [];
		for(m=0;m<((keitaisokaiseki.length-1)/2);m++){//2個飛ばしにしたら後が面倒くさい。患者 1→0　3→1 長さ9なら番号は8まで
			stackdataArr[h][m]=new Object();
			stackdataArr[h][m]= {x:m+1,y:(1*(RGBlist[m][h])/(keitaisokaiseki[2*m+1].length))};
			console.log(stackdataArr[h][m]);
		}
	}

	viz(stackdataArr,color2,bun,svg);
}

//      radio[i].onchange = () => {};

export {setForViz};
<|endoftext|>


<commit_before>
var _      = require('underscore')
, Topogo   = require('../lib/Topogo').Topogo
, H        = require('./helpers/main')
, River    = require('da_river').River
, assert   = require('assert')
;

var table = Topogo.test_table_name.toUpperCase();
var T     = Topogo.new(table);
var Q     = T.pool();
var no_fin = function () {};

var R = function (done) {
  var r = River.new(null);
  return {
    job : function () {
      r.job.apply(r, arguments);
      return this;
    },
    run : function () {
      r.job(function () {
        done();
      });
      r.run.apply(r, arguments);
      return this;
    }
  };
};

function is_recent(date) {
  return ((new Date).getTime() - date.getTime()) < 80;
}

function rand() { return parseInt(Math.random() * 1000); }

before(function (done) {
  R(done)
  .job(function (j) {
    Topogo.run("DROP TABLE IF EXISTS \"" + table + "\";", [], j);
  })
  .job(function (j) {
    Topogo.run("CREATE TABLE IF NOT EXISTS \"" + table +
               "\" (\n" +
               " id serial PRIMARY KEY, \n" +
               " name varchar(10), \n" +
               " body text ,   \n" +
               " $created_at , \n" +
               " $updated_at , \n" +
               " $trashed_at   \n);", [], j);
  })
  .run();
});

var name = "ro ro" + rand();
var body = "body: " + rand();
var id   = "wrong_id";

before(function (done) {
  R(done)
  .job(function (j) {
    var sql = 'INSERT INTO \"' + table +  '\" (name, body) VALUES ($1, $2) RETURNING * ;';
    Topogo.run(sql, [name, body], j);
  })
  .job(function (j, last) {
    id = last[0].id;
    j.finish();
  })
  .run();
});

after(function (done) {
  R(done)
  .job(function (j) {
    Topogo.run("DELETE FROM \"" + table + "\";", [], j);
  })
  .run();
});

describe( '.run', function () {
  it( 'uses process.DATABASE_URL by default', function (done) {
    River.new(null)
    .job(function (j) {
      Topogo.run("SELECT now()", {}, j);
    })
    .job(function (j, result) {
      assert.equal(H.is_date(result[0].now), true);
      done();
    })
    .run();
  });
}); // === end desc

// ================================================================
// ================== CREATE ======================================
// ================================================================

describe( '.create', function () {
  it( 'inserts object as row', function (done) {
    var body = Math.random(1000) + "";
    River.new(null)
    .job(function (j) {
      Topogo.new(table).create({name: "hi 1", body: body}, j);
    })
    .job(function (j, result) {
      assert.equal(result.id > 0, true);
      assert.equal(result.body, body);
      done();
    })
    .run();
  });

  it( 'runs .on_dup function if duplicate field name is created', function (done) {
    var body = Math.random(1000) + "";
    var t    = Topogo.new(table);
    t.on_dup('id', function (name) {
      assert.equal("id", name);
      done();
    });

    River.new(null)
    .job(function (j) {
      t.create({id: 1, name: "hi 1", body: body}, j);
    })
    .run();
  });
}); // === end desc

// ================================================================
// ================== READ ========================================
// ================================================================

describe( '.read', function () {

  describe( '.read_by_id', function () {

    it( 'returns a single result', function (done) {
      River.new(null)
      .job(function (j) {
        T.read_by_id(id, j);
      })
      .job(function (j, result) {
        assert.equal(result.id, id);
        assert.equal(result.body, body);
        done();
      })
      .run();
    });

  }); // === end desc

  describe( '.read_one', function () {

    it( 'returns a single result', function (done) {
      River.new(null)
      .job(function (j) {
        T.read_one({body: body}, j);
      })
      .job(function (j, last) {
        assert.equal(last.id, id);
        done();
      })
      .run();
    });
  }); // === end desc

  describe( '.read_list', function () {

    it( 'returns a list', function (done) {
      River.new(null)
      .job(function (j) {
        T.read_list({body: body}, j);
      })
      .job(function (j, last) {
        assert.equal(last.length, 1);
        done();
      })
      .run();
    });

  }); // === end desc

}); // === end desc

// ================================================================
// ================== UPDATE ======================================
// ================================================================

describe( '.update', function () {

  it( 'updates record with string id', function (done) {
    body = "new body " + rand();
    River.new(null)
    .job(function (j) {
      T.update(id.toString(), {body: body}, j);
    })
    .job(function (j, last) {
      assert.equal(last.id, id);
      Q.query('SELECT * from \"' + table + '\" WHERE body = $1 LIMIT 1;', [body], function (err, result) {
        if (err) throw err;
        var row = result.rows[0];
        assert.equal(row.body, body);
        assert.equal(row.id, id);
        done();
      });
    }).run();
  });

}); // === end desc

describe( '.update_and_stamp', function () {
  it( 'updates record with time stamp', function (done) {
    body = "new body " + rand();
    River.new(null)
    .job(function (j) {
      T.update_and_stamp(id.toString(), {body: body}, j);
    })
    .job(function (j, last) {
      assert.equal(last.id, id);
      Q.query('SELECT * from \"' + table + '\" WHERE body = $1 LIMIT 1;', [body], function (err, result) {
        if (err) throw err;
        var row = result.rows[0];
        assert.equal(row.body, body);
        assert.equal(row.id, id);
        assert.equal(is_recent(row.updated_at), true);
        done();
      });
    }).run();
  });
}); // === end desc

// ================================================================
// ================== Trash/Untrash ===============================
// ================================================================

describe( '.trash', function () {
  it( 'updates column trashed_at to: timestamp epoch', function (done) {

    var l = ((new Date).getTime() + '').length;

    River.new(null)
    .job(function (j) {
      T.trash(id, j);
    })
    .job(function (j, last) {
      assert.equal(is_recent(last.trashed_at), true);
      j.finish();
    })
    .job(function (j) {
      T.read_by_id(id, j);
    })
    .job(function (j, last) {
      assert.equal(is_recent(last.trashed_at), true);
      done();
    })
    .run();
  });

  it( 'passes first record to next job', function (done) {
    River.new(null)
    .job(function (j) {
      T.trash(id, j);
    })
    .job(function (j, last) {
      assert.equal(last.id, id);
      done();
    })
    .run();
  });
}); // === end desc

describe( '.untrash', function () {
  it( 'updates column trashed_at to: null', function (done) {
    River.new(null)
    .job(function (j) {
      T.trash(id, j);
    })
    .job(function (j) {
      T.untrash(id, j);
    })
    .job(function (j, last) {
      T.read_by_id(id, j);
    })
    .job(function (j, last) {
      assert.equal(last.trashed_at, null);
      assert.equal(last.id, id);
      done();
    })
    .run();
  });

  it( 'passes first record to next job', function (done) {
    River.new(null)
    .job(function (j) {
      T.untrash(id, j);
    })
    .job(function (j, last) {
      assert.equal(last.id, id);
      done();
    })
    .run();
  });
}); // === end desc

describe( '.delete_trashed', function () {

  it( 'does not delete records younger than days specified', function (done) {
    var day_4 = H.days_ago(4);
    var day_almost_4 = H.days_ago(4, 3000);

    River.new(null)
    .job(function (j) {
      T.update(id, {trashed_at: day_almost_4}, j);
    })
    .job(function (j, last) {
      T.delete_trashed(4, j);
    })
    .job(function (j, last) {
      assert.equal(last.length, 0);
      j.finish();
    })
    .job(function (j) {
      T.read_by_id(id, j);
    })
    .job(function (j, last) {
      assert.equal(last.id, id);
      done();
    })
    .run();
  });

  it( 'deletes records older than days specified', function (done) {
    var day_3 = H.days_ago(3);
    River.new(null)
    .job(function (j) {
      T.update(id, {trashed_at: day_3}, j);
    })
    .job(function (j, last) {
      T.delete_trashed(3, j);
    })
    .job(function (j, last) {
      assert.equal(last[0].id, id);
      done();
    })
    .run();
  });

}); // === end desc

<commit_msg>before/after should be closed off from other tests.<commit_after>
var _      = require('underscore')
, Topogo   = require('../lib/Topogo').Topogo
, H        = require('./helpers/main')
, River    = require('da_river').River
, assert   = require('assert')
;

var table = Topogo.test_table_name.toUpperCase();
var T     = Topogo.new(table);
var Q     = T.pool();
var no_fin = function () {};

var R = function (done) {
  var r = River.new(null);
  return {
    job : function () {
      r.job.apply(r, arguments);
      return this;
    },
    run : function () {
      r.job(function () {
        done();
      });
      r.run.apply(r, arguments);
      return this;
    }
  };
};

function is_recent(date) {
  return ((new Date).getTime() - date.getTime()) < 80;
}

function rand() { return parseInt(Math.random() * 1000); }

describe('Topogo', function () {

  before(function (done) {
    R(done)
    .job(function (j) {
      Topogo.run("DROP TABLE IF EXISTS \"" + table + "\";", [], j);
    })
    .job(function (j) {
      Topogo.run("CREATE TABLE IF NOT EXISTS \"" + table +
                 "\" (\n" +
                 " id serial PRIMARY KEY, \n" +
                 " name varchar(10), \n" +
                 " body text ,   \n" +
                 " $created_at , \n" +
                 " $updated_at , \n" +
                 " $trashed_at   \n);", [], j);
    })
    .run();
  });

  var name = "ro ro" + rand();
  var body = "body: " + rand();
  var id   = "wrong_id";

  before(function (done) {
    R(done)
    .job(function (j) {
      var sql = 'INSERT INTO \"' + table +  '\" (name, body) VALUES ($1, $2) RETURNING * ;';
      Topogo.run(sql, [name, body], j);
    })
    .job(function (j, last) {
      id = last[0].id;
      j.finish();
    })
    .run();
  });

  after(function (done) {
    R(done)
    .job(function (j) {
      Topogo.run("DELETE FROM \"" + table + "\";", [], j);
    })
    .run();
  });

  describe( '.run', function () {
    it( 'uses process.DATABASE_URL by default', function (done) {
      River.new(null)
      .job(function (j) {
        Topogo.run("SELECT now()", {}, j);
      })
      .job(function (j, result) {
        assert.equal(H.is_date(result[0].now), true);
        done();
      })
      .run();
    });
  }); // === end desc

  // ================================================================
  // ================== CREATE ======================================
  // ================================================================

  describe( '.create', function () {
    it( 'inserts object as row', function (done) {
      var body = Math.random(1000) + "";
      River.new(null)
      .job(function (j) {
        Topogo.new(table).create({name: "hi 1", body: body}, j);
      })
      .job(function (j, result) {
        assert.equal(result.id > 0, true);
        assert.equal(result.body, body);
        done();
      })
      .run();
    });

    it( 'runs .on_dup function if duplicate field name is created', function (done) {
      var body = Math.random(1000) + "";
      var t    = Topogo.new(table);
      t.on_dup('id', function (name) {
        assert.equal("id", name);
        done();
      });

      River.new(null)
      .job(function (j) {
        t.create({id: 1, name: "hi 1", body: body}, j);
      })
      .run();
    });
  }); // === end desc

  // ================================================================
  // ================== READ ========================================
  // ================================================================

  describe( '.read', function () {

    describe( '.read_by_id', function () {

      it( 'returns a single result', function (done) {
        River.new(null)
        .job(function (j) {
          T.read_by_id(id, j);
        })
        .job(function (j, result) {
          assert.equal(result.id, id);
          assert.equal(result.body, body);
          done();
        })
        .run();
      });

    }); // === end desc

    describe( '.read_one', function () {

      it( 'returns a single result', function (done) {
        River.new(null)
        .job(function (j) {
          T.read_one({body: body}, j);
        })
        .job(function (j, last) {
          assert.equal(last.id, id);
          done();
        })
        .run();
      });
    }); // === end desc

    describe( '.read_list', function () {

      it( 'returns a list', function (done) {
        River.new(null)
        .job(function (j) {
          T.read_list({body: body}, j);
        })
        .job(function (j, last) {
          assert.equal(last.length, 1);
          done();
        })
        .run();
      });

    }); // === end desc

  }); // === end desc

  // ================================================================
  // ================== UPDATE ======================================
  // ================================================================

  describe( '.update', function () {

    it( 'updates record with string id', function (done) {
      body = "new body " + rand();
      River.new(null)
      .job(function (j) {
        T.update(id.toString(), {body: body}, j);
      })
      .job(function (j, last) {
        assert.equal(last.id, id);
        Q.query('SELECT * from \"' + table + '\" WHERE body = $1 LIMIT 1;', [body], function (err, result) {
          if (err) throw err;
          var row = result.rows[0];
          assert.equal(row.body, body);
          assert.equal(row.id, id);
          done();
        });
      }).run();
    });

  }); // === end desc

  describe( '.update_and_stamp', function () {
    it( 'updates record with time stamp', function (done) {
      body = "new body " + rand();
      River.new(null)
      .job(function (j) {
        T.update_and_stamp(id.toString(), {body: body}, j);
      })
      .job(function (j, last) {
        assert.equal(last.id, id);
        Q.query('SELECT * from \"' + table + '\" WHERE body = $1 LIMIT 1;', [body], function (err, result) {
          if (err) throw err;
          var row = result.rows[0];
          assert.equal(row.body, body);
          assert.equal(row.id, id);
          assert.equal(is_recent(row.updated_at), true);
          done();
        });
      }).run();
    });
  }); // === end desc

  // ================================================================
  // ================== Trash/Untrash ===============================
  // ================================================================

  describe( '.trash', function () {
    it( 'updates column trashed_at to: timestamp epoch', function (done) {

      var l = ((new Date).getTime() + '').length;

      River.new(null)
      .job(function (j) {
        T.trash(id, j);
      })
      .job(function (j, last) {
        assert.equal(is_recent(last.trashed_at), true);
        j.finish();
      })
      .job(function (j) {
        T.read_by_id(id, j);
      })
      .job(function (j, last) {
        assert.equal(is_recent(last.trashed_at), true);
        done();
      })
      .run();
    });

    it( 'passes first record to next job', function (done) {
      River.new(null)
      .job(function (j) {
        T.trash(id, j);
      })
      .job(function (j, last) {
        assert.equal(last.id, id);
        done();
      })
      .run();
    });
  }); // === end desc

  describe( '.untrash', function () {
    it( 'updates column trashed_at to: null', function (done) {
      River.new(null)
      .job(function (j) {
        T.trash(id, j);
      })
      .job(function (j) {
        T.untrash(id, j);
      })
      .job(function (j, last) {
        T.read_by_id(id, j);
      })
      .job(function (j, last) {
        assert.equal(last.trashed_at, null);
        assert.equal(last.id, id);
        done();
      })
      .run();
    });

    it( 'passes first record to next job', function (done) {
      River.new(null)
      .job(function (j) {
        T.untrash(id, j);
      })
      .job(function (j, last) {
        assert.equal(last.id, id);
        done();
      })
      .run();
    });
  }); // === end desc

  describe( '.delete_trashed', function () {

    it( 'does not delete records younger than days specified', function (done) {
      var day_4 = H.days_ago(4);
      var day_almost_4 = H.days_ago(4, 3000);

      River.new(null)
      .job(function (j) {
        T.update(id, {trashed_at: day_almost_4}, j);
      })
      .job(function (j, last) {
        T.delete_trashed(4, j);
      })
      .job(function (j, last) {
        assert.equal(last.length, 0);
        j.finish();
      })
      .job(function (j) {
        T.read_by_id(id, j);
      })
      .job(function (j, last) {
        assert.equal(last.id, id);
        done();
      })
      .run();
    });

    it( 'deletes records older than days specified', function (done) {
      var day_3 = H.days_ago(3);
      River.new(null)
      .job(function (j) {
        T.update(id, {trashed_at: day_3}, j);
      })
      .job(function (j, last) {
        T.delete_trashed(3, j);
      })
      .job(function (j, last) {
        assert.equal(last[0].id, id);
        done();
      })
      .run();
    });

  }); // === end desc

}); // describe Topogo

<|endoftext|>


<commit_before>MathJax.Hub.Register.StartupHook('Arabic TeX Startup', function () {
  MathJax.Hub.Register.StartupHook('TeX Jax Ready', function () {
    var TEX = MathJax.InputJax.TeX;
    var texParseMMLToken = TEX.Parse.prototype.mmlToken;
    var texParseAlignedArray = TEX.Parse.prototype.AlignedArray;
    var dict = MathJax.Hub.config.Arabic.dict;

    TEX.Definitions.Add({
      macros: {
        'ar': 'HandleArabic',
        'alwaysar': 'MarkAsArabic',
        'fliph': 'HandleFlipHorizontal'
      }
    });

    TEX.Definitions.Add({
      macros: function () {
        var definitions = {};

        Object.keys(dict).forEach(function (key) {
          var texCommand = dict[key][0];
          definitions[texCommand] = key;
        });

        return definitions;
      }()
    });

    TEX.Parse.Augment(function () {
      var parsers = {};

      Object.keys(dict).forEach(function (key) {
        parsers[key] = dict[key][1]; // Parser function
      });

      return parsers;
    }());

    TEX.Parse.Augment({
      flipHorizontal: function (token) {
        token.arabicFlipH = !token.arabicFlipH;
          // Invert the value, because flipping twice means, it is not flipped
        return token;
      },
      arabicNumber: function (token) {
        var numbersMap = MathJax.Hub.config.Arabic.numbersMap;
        var text = token.data[0].data[0];
        var mapped = text;

        Object.keys(numbersMap).forEach(function (arabicNumber) {
          var hindiNumber = numbersMap[arabicNumber];
          var regex = new RegExp('' + arabicNumber, 'g');
          mapped = mapped.replace(regex, hindiNumber);
        });

        if (mapped !== text) {
          token.data[0].data[0] = mapped;
          token.arabicFontLang = 'ar';
        }

        return this.flipHorizontal(token);
      },
      arabicIdentifier: function (token) {
        var identifiersMap = MathJax.Hub.config.Arabic.identifiersMap;
        var identifiersKeys = Object.keys(identifiersMap).sort(function (a, b) {
          return b.length - a.length;
        });

        var text = token.data[0].data[0];
        var mapped = text;

        if ('chars' === token.data[0].type) {
          // English Symbols like X and Y
          identifiersKeys.forEach(function (enChar) {
            var arChar = identifiersMap[enChar];
            var regex = new RegExp(enChar, 'g');
            mapped = mapped.replace(regex, arChar);
          });
        }

        if (mapped !== text) {
          token.data[0].data[0] = mapped;
          token.arabicFontLang = 'ar';
        }

        return this.flipHorizontal(token);
      },
      arabicOperator: function (token) {
        var operatorsMap = MathJax.Hub.config.Arabic.operatorsMap;
        var text = token.data[0].data[0];
        var mapped = text;

        Object.keys(operatorsMap).forEach(function (enOperator) {
          var regex = new RegExp('' + enOperator, 'g');
          var arOperator = operatorsMap[enOperator];
          mapped = mapped.replace(regex, arOperator);
        });

        if (mapped !== text) {
          token = this.flipHorizontal(token);
          token.arabicFontLang = 'ar';
          token.data[0].data[0] = mapped;
        }

        return token;
      },
      _getArgumentMML: function (name) {
        //  returns an argument that is a single MathML element
        //  (in an mrow if necessary)
        //
        //  This functions has been copied here from extensions/TeX/HTML.js, to avoid
        //  adding a dependency.
        //
        //  TODO: Consider importing (as a dependency) this from HTML.js instead!
        var arg = this.ParseArg(name);
        if (arg.inferred && arg.data.length == 1)
          {arg = arg.data[0]} else {delete arg.inferred}
        return arg;
      },
      mmlToken: function (token) {
        // TODO: Check for possible incompatibility with boldsymbol extension
        var parsedToken = texParseMMLToken.apply(this, [token]);

        if ('ar' === this.stack.env.lang) {
          this.markArabicToken(parsedToken);
        }

        return parsedToken;
      },
      markArabicToken: function (token) {
        if ('mn' === token.type) {
          return this.arabicNumber(token);
        } else if ('mi' === token.type) {
          return this.arabicIdentifier(token);
        } else if ('mo' === token.type) {
          return this.arabicOperator(token);
        }

        return token;
      },
      AlignedArray: function () {
        // Helper to Arabize the matrices, arrays and piecewise functions.
        var array = texParseAlignedArray.apply(this, arguments);
        var _this = this;

        if ('ar' === this.stack.env.lang) {
          var arrayEndTable = array.EndTable;
          array.EndTable = function () {
            var retVal = arrayEndTable.apply(this, arguments);

            // First level, iterate over the rows
            array.table.forEach(function (row, rowIndex) {
              // Second level, iterate over the columns
              row.data.forEach(function (cell, colIndex) {
                // Third level, iterate over the cell content
                cell.data[0].data.forEach(function (token) {
                  // Skip the first element of the matrix to solve a bug,
                  // not sure why it is there.
                  if (rowIndex || colIndex) {
                    _this.markArabicToken(token);
                  }
                });
              });
            });

            return retVal;
          };
        }

        return array;
      },
      HandleArabic: function (name) {
        if (MathJax.Hub.config.Arabic.isArabicPage) {
          this.MarkAsArabic(name);
        }
      },
      MarkAsArabic: function (name) {
        this.stack.env.lang = 'ar';
        var arg = this._getArgumentMML(name);
        this.Push(this.flipHorizontal(arg));
      },
      HandleFlipHorizontal: function (name) {
        var arg = this._getArgumentMML(name);
        this.Push(this.flipHorizontal(arg));
      }
    });

    MathJax.Hub.Startup.signal.Post('Arabic TeX Ready');
  });
});
<commit_msg>Refactor the signals a bit<commit_after>MathJax.Hub.Register.StartupHook('TeX Jax Ready', function () {
  MathJax.Hub.Register.StartupHook('Arabic TeX Startup', function () {
    var TEX = MathJax.InputJax.TeX;
    var texParseMMLToken = TEX.Parse.prototype.mmlToken;
    var texParseAlignedArray = TEX.Parse.prototype.AlignedArray;
    var dict = MathJax.Hub.config.Arabic.dict;

    TEX.Definitions.Add({
      macros: {
        'ar': 'HandleArabic',
        'alwaysar': 'MarkAsArabic',
        'fliph': 'HandleFlipHorizontal'
      }
    });

    TEX.Definitions.Add({
      macros: function () {
        var definitions = {};

        Object.keys(dict).forEach(function (key) {
          var texCommand = dict[key][0];
          definitions[texCommand] = key;
        });

        return definitions;
      }()
    });

    TEX.Parse.Augment(function () {
      var parsers = {};

      Object.keys(dict).forEach(function (key) {
        parsers[key] = dict[key][1]; // Parser function
      });

      return parsers;
    }());

    TEX.Parse.Augment({
      flipHorizontal: function (token) {
        token.arabicFlipH = !token.arabicFlipH;
          // Invert the value, because flipping twice means, it is not flipped
        return token;
      },
      arabicNumber: function (token) {
        var numbersMap = MathJax.Hub.config.Arabic.numbersMap;
        var text = token.data[0].data[0];
        var mapped = text;

        Object.keys(numbersMap).forEach(function (arabicNumber) {
          var hindiNumber = numbersMap[arabicNumber];
          var regex = new RegExp('' + arabicNumber, 'g');
          mapped = mapped.replace(regex, hindiNumber);
        });

        if (mapped !== text) {
          token.data[0].data[0] = mapped;
          token.arabicFontLang = 'ar';
        }

        return this.flipHorizontal(token);
      },
      arabicIdentifier: function (token) {
        var identifiersMap = MathJax.Hub.config.Arabic.identifiersMap;
        var identifiersKeys = Object.keys(identifiersMap).sort(function (a, b) {
          return b.length - a.length;
        });

        var text = token.data[0].data[0];
        var mapped = text;

        if ('chars' === token.data[0].type) {
          // English Symbols like X and Y
          identifiersKeys.forEach(function (enChar) {
            var arChar = identifiersMap[enChar];
            var regex = new RegExp(enChar, 'g');
            mapped = mapped.replace(regex, arChar);
          });
        }

        if (mapped !== text) {
          token.data[0].data[0] = mapped;
          token.arabicFontLang = 'ar';
        }

        return this.flipHorizontal(token);
      },
      arabicOperator: function (token) {
        var operatorsMap = MathJax.Hub.config.Arabic.operatorsMap;
        var text = token.data[0].data[0];
        var mapped = text;

        Object.keys(operatorsMap).forEach(function (enOperator) {
          var regex = new RegExp('' + enOperator, 'g');
          var arOperator = operatorsMap[enOperator];
          mapped = mapped.replace(regex, arOperator);
        });

        if (mapped !== text) {
          token = this.flipHorizontal(token);
          token.arabicFontLang = 'ar';
          token.data[0].data[0] = mapped;
        }

        return token;
      },
      _getArgumentMML: function (name) {
        //  returns an argument that is a single MathML element
        //  (in an mrow if necessary)
        //
        //  This functions has been copied here from extensions/TeX/HTML.js, to avoid
        //  adding a dependency.
        //
        //  TODO: Consider importing (as a dependency) this from HTML.js instead!
        var arg = this.ParseArg(name);
        if (arg.inferred && arg.data.length == 1)
          {arg = arg.data[0]} else {delete arg.inferred}
        return arg;
      },
      mmlToken: function (token) {
        // TODO: Check for possible incompatibility with boldsymbol extension
        var parsedToken = texParseMMLToken.apply(this, [token]);

        if ('ar' === this.stack.env.lang) {
          this.markArabicToken(parsedToken);
        }

        return parsedToken;
      },
      markArabicToken: function (token) {
        if ('mn' === token.type) {
          return this.arabicNumber(token);
        } else if ('mi' === token.type) {
          return this.arabicIdentifier(token);
        } else if ('mo' === token.type) {
          return this.arabicOperator(token);
        }

        return token;
      },
      AlignedArray: function () {
        // Helper to Arabize the matrices, arrays and piecewise functions.
        var array = texParseAlignedArray.apply(this, arguments);
        var _this = this;

        if ('ar' === this.stack.env.lang) {
          var arrayEndTable = array.EndTable;
          array.EndTable = function () {
            var retVal = arrayEndTable.apply(this, arguments);

            // First level, iterate over the rows
            array.table.forEach(function (row, rowIndex) {
              // Second level, iterate over the columns
              row.data.forEach(function (cell, colIndex) {
                // Third level, iterate over the cell content
                cell.data[0].data.forEach(function (token) {
                  // Skip the first element of the matrix to solve a bug,
                  // not sure why it is there.
                  if (rowIndex || colIndex) {
                    _this.markArabicToken(token);
                  }
                });
              });
            });

            return retVal;
          };
        }

        return array;
      },
      HandleArabic: function (name) {
        if (MathJax.Hub.config.Arabic.isArabicPage) {
          this.MarkAsArabic(name);
        }
      },
      MarkAsArabic: function (name) {
        this.stack.env.lang = 'ar';
        var arg = this._getArgumentMML(name);
        this.Push(this.flipHorizontal(arg));
      },
      HandleFlipHorizontal: function (name) {
        var arg = this._getArgumentMML(name);
        this.Push(this.flipHorizontal(arg));
      }
    });

    MathJax.Hub.Startup.signal.Post('Arabic TeX Ready');
  });
});
<|endoftext|>


<commit_before>/* global describe, it, beforeEach, afterEach */
'use strict';
const InstanceManager = require('../InstanceManager.js');
const endpointToUrl = require('../common.js').endpointToUrl;

const expect = require('chai').expect;
const rp = require('request-promise');

let agencyRequest = function (options) {
  options.followRedirects = options.followRedirects || false;
  return rp(options)
  .then(response => {
    return response;
  })
  .catch(err => {
    if (err.statusCode === 307) {
      options.url = err.response.headers['location'];
      return agencyRequest(options);
    }
    return Promise.reject(err);
  });
};

let writeData = function (leader, data) {
  return agencyRequest({
    method: 'POST',
    url: endpointToUrl(leader.endpoint) + '/_api/agency/write',
    json: true,
    body: [[data]],
    followRedirects: false
  });
};

describe('Agency', function () {
  let instanceManager = new InstanceManager('agency');
  let leader;
  let followers;

  beforeEach(function () {
    return instanceManager.startAgency({agencySize: 3})
    .then(agents => {
      let checkForLeader = function () {
        return rp({
          url: endpointToUrl(agents[0].endpoint) + '/_api/agency/config',
          json: true
        })
        .then(result => {
          if (result.leaderId === '') {
            return Promise.reject();
          }
          return result.leaderId;
        })
        .catch(() => {
          return new Promise((resolve, reject) => {
            setTimeout(resolve, 100);
          })
          .then(() => {
            return checkForLeader();
          });
        });
      };
      return checkForLeader()
      .then(leaderId => {
        return agents.reduce((leaderInstance, agent) => {
          if (leaderInstance) {
            return leaderInstance;
          }

          return agencyRequest({
            url: agent.endpoint + '/_api/agency/config',
            json: true
          })
          .then(result => {
            if (result.configuration.id === leaderId) {
              return agent;
            }
          });
        });
      })
      .then(leaderInstance => {
        leader = leaderInstance;
        followers = instanceManager.agents().filter(agent => agent !== leader);
      });
    });
  });

  afterEach(function () {
    return instanceManager.cleanup()
    .then(log => {
      if (this.currentTest.state === 'failed') {
        this.currentTest.err.message = log + '\n\n' + this.currentTest.err.message;
      }
    });
  });

  it('should failover when stopping the leader', function () {
    let data = {'hans': 'wurst'};
    return writeData(leader, data)
    .then(() => {
      return instanceManager.kill(leader);
    })
    .then(() => {
      // mop: well the failover is of course not fully immediately
      return new Promise((resolve, reject) => {
        setTimeout(resolve, 100);
      });
    })
    .then(() => {
      return agencyRequest({
        method: 'POST',
        url: endpointToUrl(followers[0].endpoint) + '/_api/agency/read',
        json: true,
        body: [['/']]
      });
    })
    .then(result => {
      expect(result).to.be.instanceof(Array);
      expect(result[0]).to.eql(data);
    });
  });

  it('should not think it is the leader after a restart', function () {
    let data = {'hans': 'wurst'};
    return writeData(leader, data)
    .then(() => {
      return instanceManager.kill(leader);
    })
    .then(() => {
      return instanceManager.restart(leader);
    })
    .then(() => {
      return rp({
        method: 'POST',
        url: endpointToUrl(leader.endpoint) + '/_api/agency/read',
        json: true,
        body: [['/']],
        followRedirects: false
      })
      .then(() => {
        return Promise.all([
          rp({
            url: endpointToUrl(leader.endpoint) + '/_api/agency/config'
          }),
          rp({
            url: endpointToUrl(followers[0].endpoint) + '/_api/agency/config'
          })
        ])
        .then(results => {
          throw new Error('It should not report success! It should block all incoming rest requests until it redetermined who the leader is. Configresults: ' + JSON.stringify({leader: results[0], follower: results[1]}));
        });
      }, err => {
        expect(err.statusCode).to.equal(307);
      });
    });
  });
  it('should reintegrate a crashed follower', function () {
    throw new Error('hasi');
    // let data = {'koeln': 'sued'};
    // return writeData(leader, data)
    // .then(() => {
    //   return instanceManager.kill(followers[0], 'SIGKILL');
    // })
    // .then(() => {
    //   return instanceManager.restart(followers[0]);
    // })
    // .then(() => {
    //   return agencyRequest({
    //     method: 'POST',
    //     url: endpointToUrl(followers[0].endpoint) + '/_api/agency/read',
    //     json: true,
    //     body: [['/']]
    //   });
    // })
    // .then(result => {
    //   expect(result).to.be.instanceof(Array);
    //   expect(result[0]).to.eql(data);
    // });
  });
  it('should have the correct results after a funny fail rotation', function () {
    let promise = Promise.resolve();
    for (let i = 0; i < instanceManager.instances.length * 2; i++) {
      promise = (function (promise, i) {
        return promise.then(() => {
          let data = {'subba': i};
          let instance = instanceManager.instances[i % instanceManager.instances.length];
          return writeData(instance, data)
          .then(() => {
            return instanceManager.kill(instance);
          })
          .then(() => {
            return instanceManager.restart(instance);
          });
        });
      })(promise, i);
    }

    return promise
    .then(() => {
      return agencyRequest({
        method: 'POST',
        url: endpointToUrl(leader.endpoint) + '/_api/agency/read',
        json: true,
        body: [['/']]
      });
    })
    .then(result => {
      expect(result).to.be.instanceof(Array);
      expect(result[0]).to.eql({'subba': instanceManager.instances.length * 2 - 1});
    });
  });
});
<commit_msg>Fix bogus error<commit_after>/* global describe, it, beforeEach, afterEach */
'use strict';
const InstanceManager = require('../InstanceManager.js');
const endpointToUrl = require('../common.js').endpointToUrl;

const expect = require('chai').expect;
const rp = require('request-promise');

let agencyRequest = function (options) {
  options.followRedirects = options.followRedirects || false;
  return rp(options)
  .then(response => {
    return response;
  })
  .catch(err => {
    if (err.statusCode === 307) {
      options.url = err.response.headers['location'];
      return agencyRequest(options);
    }
    return Promise.reject(err);
  });
};

let writeData = function (leader, data) {
  return agencyRequest({
    method: 'POST',
    url: endpointToUrl(leader.endpoint) + '/_api/agency/write',
    json: true,
    body: [[data]],
    followRedirects: false
  });
};

describe('Agency', function () {
  let instanceManager = new InstanceManager('agency');
  let leader;
  let followers;

  beforeEach(function () {
    return instanceManager.startAgency({agencySize: 3})
    .then(agents => {
      let checkForLeader = function () {
        return rp({
          url: endpointToUrl(agents[0].endpoint) + '/_api/agency/config',
          json: true
        })
        .then(result => {
          if (result.leaderId === '') {
            return Promise.reject();
          }
          return result.leaderId;
        })
        .catch(() => {
          return new Promise((resolve, reject) => {
            setTimeout(resolve, 100);
          })
          .then(() => {
            return checkForLeader();
          });
        });
      };
      return checkForLeader()
      .then(leaderId => {
        return agents.reduce((leaderInstance, agent) => {
          if (leaderInstance) {
            return leaderInstance;
          }

          return agencyRequest({
            url: agent.endpoint + '/_api/agency/config',
            json: true
          })
          .then(result => {
            if (result.configuration.id === leaderId) {
              return agent;
            }
          });
        });
      })
      .then(leaderInstance => {
        leader = leaderInstance;
        followers = instanceManager.agents().filter(agent => agent !== leader);
      });
    });
  });

  afterEach(function () {
    return instanceManager.cleanup()
    .then(log => {
      if (this.currentTest.state === 'failed') {
        this.currentTest.err.message = log + '\n\n' + this.currentTest.err.message;
      }
    });
  });

  it('should failover when stopping the leader', function () {
    let data = {'hans': 'wurst'};
    return writeData(leader, data)
    .then(() => {
      return instanceManager.kill(leader);
    })
    .then(() => {
      // mop: well the failover is of course not fully immediately
      return new Promise((resolve, reject) => {
        setTimeout(resolve, 100);
      });
    })
    .then(() => {
      return agencyRequest({
        method: 'POST',
        url: endpointToUrl(followers[0].endpoint) + '/_api/agency/read',
        json: true,
        body: [['/']]
      });
    })
    .then(result => {
      expect(result).to.be.instanceof(Array);
      expect(result[0]).to.eql(data);
    });
  });

  it('should not think it is the leader after a restart', function () {
    let data = {'hans': 'wurst'};
    return writeData(leader, data)
    .then(() => {
      return instanceManager.kill(leader);
    })
    .then(() => {
      return instanceManager.restart(leader);
    })
    .then(() => {
      return rp({
        method: 'POST',
        url: endpointToUrl(leader.endpoint) + '/_api/agency/read',
        json: true,
        body: [['/']],
        followRedirects: false
      })
      .then(() => {
        return Promise.all([
          rp({
            url: endpointToUrl(leader.endpoint) + '/_api/agency/config'
          }),
          rp({
            url: endpointToUrl(followers[0].endpoint) + '/_api/agency/config'
          })
        ])
        .then(results => {
          throw new Error('It should not report success! It should block all incoming rest requests until it redetermined who the leader is. Configresults: ' + JSON.stringify({leader: results[0], follower: results[1]}));
        });
      }, err => {
        expect(err.statusCode).to.equal(307);
      });
    });
  });
  it('should reintegrate a crashed follower', function() {
    let data = {'koeln': 'sued'};
    return writeData(leader, data)
    .then(() => {
      return instanceManager.kill(followers[0], 'SIGKILL');
    })
    .then(() => {
      return instanceManager.restart(followers[0]);
    })
    .then(() => {
      return agencyRequest({
        method: 'POST',
        url: endpointToUrl(followers[0].endpoint) + '/_api/agency/read',
        json: true,
        body: [['/']],
      });
    })
    .then(result => {
      expect(result).to.be.instanceof(Array);
      expect(result[0]).to.eql(data);
    })
  });
  it('should have the correct results after a funny fail rotation', function () {
    let promise = Promise.resolve();
    for (let i = 0; i < instanceManager.instances.length * 2; i++) {
      promise = (function (promise, i) {
        return promise.then(() => {
          let data = {'subba': i};
          let instance = instanceManager.instances[i % instanceManager.instances.length];
          return writeData(instance, data)
          .then(() => {
            return instanceManager.kill(instance);
          })
          .then(() => {
            return instanceManager.restart(instance);
          });
        });
      })(promise, i);
    }

    return promise
    .then(() => {
      return agencyRequest({
        method: 'POST',
        url: endpointToUrl(leader.endpoint) + '/_api/agency/read',
        json: true,
        body: [['/']]
      });
    })
    .then(result => {
      expect(result).to.be.instanceof(Array);
      expect(result[0]).to.eql({'subba': instanceManager.instances.length * 2 - 1});
    });
  });
});
<|endoftext|>


<commit_before>document.observe("dom:loaded", function() {
  if($('#asset-bucket').length > 0){
    new Draggable('asset-bucket', { starteffect: false, endeffect: false });
  }
});

var Asset = {};

Asset.Tabs = Behavior.create({
  onclick: function(e){
    e.stop();
    Asset.ChooseTab(this.element);
  }
});

// factored out so that it can be called in an ajax response

Asset.ChooseTab = function (element) {
  var pane = $(element.href.split('#')[1]);
  var panes = $('assets').select('.pane');

  var tabs = $('asset-tabs').select('.asset-tab');
  tabs.each(function(tab) {tab.removeClassName('here');});

  element.addClassName('here');;
  panes.each(function(pane) {Element.hide(pane);});
  Element.show($(pane));
}

Asset.ChooseTabByName = function (tabname) {
  var element = $('tab_' + tabname);
  Asset.ChooseTab(element);
}

// factored out so that it can be called after new page part creation

Asset.MakeDroppables = function () {
  $$('.textarea').each(function(box){
    if (!box.hasClassName('droppable')) {
      Droppables.add(box, {
        accept: 'asset',
        onDrop: function(element) {
          var link = element.select('a.bucket_link')[0];
          var asset_id = element.id.split('_').last();
          var classes = element.className.split(' ');
          var tag_type = classes[0];
          var tag = '<r:assets:' + tag_type + ' id="' + asset_id + '" size="original" />';
          //Form.Element.focus(box);
        	if(!!document.selection){
        		box.focus();
        		var range = (box.range) ? box.range : document.selection.createRange();
        		range.text = tag;
        		range.select();
        	}else if(!!box.setSelectionRange){
        		var selection_start = box.selectionStart;
        		box.value = box.value.substring(0,selection_start) + tag + box.value.substring(box.selectionEnd);
        		box.setSelectionRange(selection_start + tag.length,selection_start + tag.length);
        	}
        	box.focus();
        }
      });
    	box.addClassName('droppable');
    }
  });
}

Asset.ShowBucket = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = $('asset-bucket');
    center(element);
    element.show();
    Asset.MakeDroppables();
  }
});

Asset.HideBucket = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = $('asset-bucket');
    element.hide();
  }
});

Asset.FileTypes = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = this.element;
    var type_id = element.text.downcase();
    var type_check = $(type_id + '-check');
    var search_form = $('filesearchform');
    if(element.hasClassName('pressed')) {
      element.removeClassName('pressed');
      type_check.removeAttribute('checked');
    } else {
      element.addClassName('pressed');
      type_check.setAttribute('checked', 'checked');
    }
    new Ajax.Updater('assets_table', search_form.action, {
      asynchronous: true,
      evalScripts:  true,
      parameters:   Form.serialize(search_form),
      method: 'get',
      onComplete: 'assets_table'
    });
  }
});

Asset.WaitingForm = Behavior.create({
  onsubmit: function(e){
    this.element.addClassName('waiting');
    return true;
  }
});

Asset.ResetForm = function (name) {
  var element = $('asset-upload');
  element.removeClassName('waiting');
  element.reset();
}

Asset.AddAsset = function (name) {
  element = $(name);
  asset = element.select('.asset')[0];
  console.log('inserted element is ', element);
  console.log('contained asset is ', asset);
  if (asset) {
    new Draggable(asset, { revert: true });
  }
}

Event.addBehavior({
  '#asset-tabs a'     : Asset.Tabs,
  '#close-link a'     : Asset.HideBucket,
  '#show-bucket a'    : Asset.ShowBucket,
  '#filesearchform a' : Asset.FileTypes,
  '#asset-upload'     : Asset.WaitingForm
});
<commit_msg>fixed minor js bug in dragging the assets window. Made the link toggle the window<commit_after>document.observe("dom:loaded", function() {
  if($('asset-bucket')){
    new Draggable('asset-bucket', { starteffect: false, endeffect: false });
  }
});

var Asset = {};

Asset.Tabs = Behavior.create({
  onclick: function(e){
    e.stop();
    Asset.ChooseTab(this.element);
  }
});

// factored out so that it can be called in an ajax response

Asset.ChooseTab = function (element) {
  var pane = $(element.href.split('#')[1]);
  var panes = $('assets').select('.pane');

  var tabs = $('asset-tabs').select('.asset-tab');
  tabs.each(function(tab) {tab.removeClassName('here');});

  element.addClassName('here');;
  panes.each(function(pane) {Element.hide(pane);});
  Element.show($(pane));
}

Asset.ChooseTabByName = function (tabname) {
  var element = $('tab_' + tabname);
  Asset.ChooseTab(element);
}

// factored out so that it can be called after new page part creation

Asset.MakeDroppables = function () {
  $$('.textarea').each(function(box){
    if (!box.hasClassName('droppable')) {
      Droppables.add(box, {
        accept: 'asset',
        onDrop: function(element) {
          var link = element.select('a.bucket_link')[0];
          var asset_id = element.id.split('_').last();
          var classes = element.className.split(' ');
          var tag_type = classes[0];
          var tag = '<r:assets:' + tag_type + ' id="' + asset_id + '" size="original" />';
          //Form.Element.focus(box);
        	if(!!document.selection){
        		box.focus();
        		var range = (box.range) ? box.range : document.selection.createRange();
        		range.text = tag;
        		range.select();
        	}else if(!!box.setSelectionRange){
        		var selection_start = box.selectionStart;
        		box.value = box.value.substring(0,selection_start) + tag + box.value.substring(box.selectionEnd);
        		box.setSelectionRange(selection_start + tag.length,selection_start + tag.length);
        	}
        	box.focus();
        }
      });
    	box.addClassName('droppable');
    }
  });
}

Asset.ShowBucket = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = $('asset-bucket');
    center(element);
    element.toggle();
    Asset.MakeDroppables();
  }
});

Asset.HideBucket = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = $('asset-bucket');
    element.hide();
  }
});

Asset.FileTypes = Behavior.create({
  onclick: function(e){
    e.stop();
    var element = this.element;
    var type_id = element.text.downcase();
    var type_check = $(type_id + '-check');
    var search_form = $('filesearchform');
    if(element.hasClassName('pressed')) {
      element.removeClassName('pressed');
      type_check.removeAttribute('checked');
    } else {
      element.addClassName('pressed');
      type_check.setAttribute('checked', 'checked');
    }
    new Ajax.Updater('assets_table', search_form.action, {
      asynchronous: true,
      evalScripts:  true,
      parameters:   Form.serialize(search_form),
      method: 'get',
      onComplete: 'assets_table'
    });
  }
});

Asset.WaitingForm = Behavior.create({
  onsubmit: function(e){
    this.element.addClassName('waiting');
    return true;
  }
});

Asset.ResetForm = function (name) {
  var element = $('asset-upload');
  element.removeClassName('waiting');
  element.reset();
}

Asset.AddAsset = function (name) {
  element = $(name);
  asset = element.select('.asset')[0];
  console.log('inserted element is ', element);
  console.log('contained asset is ', asset);
  if (asset) {
    new Draggable(asset, { revert: true });
  }
}

Event.addBehavior({
  '#asset-tabs a'     : Asset.Tabs,
  '#close-link a'     : Asset.HideBucket,
  '#show-bucket a'    : Asset.ShowBucket,
  '#filesearchform a' : Asset.FileTypes,
  '#asset-upload'     : Asset.WaitingForm
});
<|endoftext|>


<commit_before>(function(window, undefined) {

    var URIParser = {

        /**
         * Parse URI query strings
         * @param  {string} query_string The query string to parse
         * @param  {bool}   decode       Should values be URI decoded?
         * @return {object}              The decoded query string
         */
        query: function(query_string, decode) {
            // Default decode to true
            if (typeof decode === 'undefined') decode = true;

            // Replace the starting ?, if it is there
            query_string = query_string.replace(/^\?/, '');

            // Split the query string into key value parts
            var parts = query_string.split('&');

            // Iniate the return value
            var query = {};

            // Loop through each other the parts, splitting it into keys and values
            for (var i = 0, l = parts.length; i < l; i++) {
                var part = parts[i];
                var key;
                var val = '';

                if (part.match('=')) {
                    // If it is in the format key=val

                    // Split into the key and value by the = symbol
                    var part_parts = part.split('=');

                    // Assign key and value
                    key = part_parts[0];
                    val = part_parts[1];
                } else {
                    // If there is no value, just set the key to the full part
                    key = part;
                }

                // If we actually have a value, URI decode it
                if (val !== '') {
                    val = decodeURIComponent(val);
                }

                // Assign to the return value
                query[key] = val;
            }

            return query;
        },

        _extend: function() {
            // If we have more than two objects to merge
            if (arguments.length > 2) {
                // Get the first object.
                // Everything will merge into this.
                var obj = Array.prototype.shift.call(arguments);

                // While we have any more arguments, call extend with the initial obj and the next argument
                while (arguments.length > 0) {
                    obj = arguments.callee(obj, Array.prototype.shift.call(arguments));
                }

                return obj;
            }

            // Pull our objects out of the arguments array.
            var one = arguments[0];
            var two = arguments[1];

            // Loop through the second object to merge it with the first
            for (var key in two) {
                // If this key actually belongs to the second argument
                if (typeof two.hasOwnProperty === 'undefined' || two.hasOwnProperty(key)) {
                    var current = two[key];

                    if (typeof current === 'object' && typeof one[key] === 'object') {
                        // Deep copy
                        one[key] = extend(one[key], current);
                    } else {
                        one[key] = current;
                    }
                }
            }

            return one;
        }
    }

    if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
        // CommonJS, Node, PhantomJS, etc modules
        module.exports = exports = URIParser;
    } else if (typeof define !== 'undefined') {
        // RequireJS Module
        define(function(require, exports, module) {
            module.exports = exports = URIParser;
        });
    } else {
        // Being included directly in the browser
        window.URIParser = URIParser;

        var location = window.location;
        var defaults = {
            auto: {
                query: false
            },

            keys: {
                query: 'query'
            }
        };

        if (!location.query_opts) {
            location.query_opts = {};
        };

        var opts = URIParser._extend({}, defaults, location.query_opts);
        delete location['query_opts'];

        if (opts.auto || (typeof opts.auto === 'object' && opts.auto.query)) {
            location[opts.keys.query] = URIParser.query(location.search);
        }
    }
})(window);<commit_msg>Make extend slightly nicer<commit_after>(function(window, undefined) {

    var URIParser = {

        /**
         * Parse URI query strings
         * @param  {string} query_string The query string to parse
         * @param  {bool}   decode       Should values be URI decoded?
         * @return {object}              The decoded query string
         */
        query: function(query_string, decode) {
            // Default decode to true
            if (typeof decode === 'undefined') decode = true;

            // Replace the starting ?, if it is there
            query_string = query_string.replace(/^\?/, '');

            // Split the query string into key value parts
            var parts = query_string.split('&');

            // Iniate the return value
            var query = {};

            // Loop through each other the parts, splitting it into keys and values
            for (var i = 0, l = parts.length; i < l; i++) {
                var part = parts[i];
                var key;
                var val = '';

                if (part.match('=')) {
                    // If it is in the format key=val

                    // Split into the key and value by the = symbol
                    var part_parts = part.split('=');

                    // Assign key and value
                    key = part_parts[0];
                    val = part_parts[1];
                } else {
                    // If there is no value, just set the key to the full part
                    key = part;
                }

                // If we actually have a value, URI decode it
                if (val !== '') {
                    val = decodeURIComponent(val);
                }

                // Assign to the return value
                query[key] = val;
            }

            return query;
        },

        /**
         * Deep merge two or more objects
         * @return {object} Merged version of the arguments
         */
        _extend: function(one, two) {
            // If we have more than two objects to merge
            if (arguments.length > 2) {
                // Get the first object.
                // Everything will merge into this.
                var obj = Array.prototype.shift.call(arguments);

                // While we have any more arguments, call extend with the initial obj and the next argument
                while (arguments.length > 0) {
                    obj = arguments.callee(obj, Array.prototype.shift.call(arguments));
                }

                return obj;
            }

            // Check our arguments for errors
            if (typeof one !== 'object' || typeof two !== 'object') {
                throw {
                    name: 'ArgumentsError',
                    message: 'One or more arguments are not objects'
                }
            }

            // Loop through the second object to merge it with the first
            for (var key in two) {
                // If this key actually belongs to the second argument
                if (typeof two.hasOwnProperty === 'undefined' || two.hasOwnProperty(key)) {
                    var current = two[key];

                    if (typeof current === 'object' && typeof one[key] === 'object') {
                        // Deep copy
                        one[key] = extend(one[key], current);
                    } else {
                        one[key] = current;
                    }
                }
            }

            return one;
        }
    }

    if (typeof exports !== 'undefined' && typeof module !== 'undefined') {
        // CommonJS, Node, PhantomJS, etc modules
        module.exports = exports = URIParser;
    } else if (typeof define !== 'undefined') {
        // RequireJS Module
        define(function(require, exports, module) {
            module.exports = exports = URIParser;
        });
    } else {
        // Being included directly in the browser
        window.URIParser = URIParser;

        var location = window.location;
        var defaults = {
            auto: {
                query: false
            },

            keys: {
                query: 'query'
            }
        };

        if (!location.query_opts) {
            location.query_opts = {};
        };

        var opts = URIParser._extend({}, defaults, location.query_opts);
        delete location['query_opts'];

        if (opts.auto || (typeof opts.auto === 'object' && opts.auto.query)) {
            location[opts.keys.query] = URIParser.query(location.search);
        }
    }
})(window);<|endoftext|>


<commit_before>var keyRegex = /^[a-h][1-8]$/;
var fileRegex = /^[a-h]$/;

lichess.keyboardMove = function(opts) {
  if (opts.input.classList.contains('ready')) return;
  opts.input.classList.add('ready');
  var writer = sanWriter();
  var sans = null;
  var submit = function(v, force) {
    var foundUci = v.length >= 2 && sans && sanToUci(v, sans);
    if (foundUci) {
      // ambiguous castle
      if (v.toLowerCase() === 'o-o' && sans['O-O-O'] && !force) return;
      // ambiguous UCI
      if (v.match(keyRegex) && opts.hasSelected()) opts.select(v);
      else opts.san(foundUci.slice(0, 2), foundUci.slice(2));
      clear();
    } else if (sans && v.match(keyRegex)) {
      opts.select(v);
      clear();
    } else if (sans && v.match(fileRegex)) {
      // do nothing
    } else
      opts.input.classList.toggle('wrong', v.length && sans && !sanCandidates(v, sans).length);
  };
  var clear = function() {
    opts.input.value = '';
    opts.input.classList.remove('wrong');
  };
  makeBindings(opts, submit, clear);
  return function(fen, dests) {
    sans = dests && Object.keys(dests).length ? writer(fen, destsToUcis(dests)) : null;
    submit(opts.input.value);
  };
}

function makeBindings(opts, submit, clear) {
  Mousetrap.bind('enter', function() {
    opts.input.focus();
  });
  opts.input.addEventListener('keyup', function(e) {
    var v = e.target.value;
    if (v.indexOf('/') > -1) {
      focusChat();
      clear();
    } else submit(v, e.keyCode === 13);
  });
  opts.input.addEventListener('focus', function() {
    opts.setFocus(true);
  });
  opts.input.addEventListener('blur', function() {
    opts.setFocus(false);
  });
  opts.input.focus();
}

function sanToUci(san, sans) {
  var lowered = san.toLowerCase();
  for (var i in sans)
    if (i.toLowerCase() === lowered) return sans[i];
}

function sanCandidates(san, sans) {
  var lowered = san.toLowerCase();
  return Object.keys(sans).filter(function(s) {
    return s.toLowerCase().indexOf(lowered) === 0;
  });
}

function destsToUcis(dests) {
  var ucis = [];
  Object.keys(dests).forEach(function(orig) {
    dests[orig].forEach(function(dest) {
      ucis.push(orig + dest);
    });
  });
  return ucis;
}

function sanWriter() {

  var fixCrazySan = function(san) {
    return san[0] === 'P' ? san.slice(1) : san;
  };
  var decomposeUci = function(uci) {
    return [uci.slice(0, 2), uci.slice(2, 4), uci.slice(4, 5)];
  };

  var square = function(name) {
    return name.charCodeAt(0) - 97 + (name.charCodeAt(1) - 49) * 8;
  }

  var squareDist = function(a, b) {
    var x1 = a & 7,
      x2 = b & 7;
    var y1 = a >> 3,
      y2 = b >> 3;
    return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2));
  }

  var isBlack = function(p) {
    return p === p.toLowerCase();
  }

  var readFen = function(fen) {
    var parts = fen.split(' ');
    var board = {
      pieces: {},
      turn: parts[1] === 'w'
    };

    parts[0].split('/').slice(0, 8).forEach(function(row, y) {
      var x = 0;
      row.split('').forEach(function(v) {
        if (v == '~') return;
        var nb = parseInt(v, 10);
        if (nb) x += nb;
        else {
          var square = (7 - y) * 8 + x;
          board.pieces[square] = v;
          if (v === 'k' || v === 'K') board[v] = square;
          x++;
        }
      });
    });

    return board;
  }

  var kingMovesTo = function(s) {
    return [s - 1, s - 9, s - 8, s - 7, s + 1, s + 9, s + 8, s + 7].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) === 1;
    });
  }

  var knightMovesTo = function(s) {
    return [s + 17, s + 15, s + 10, s + 6, s - 6, s - 10, s - 15, s - 17].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) <= 2;
    });
  }

  var pawnAttacksTo = function(turn, s) {
    var left = turn ? 7 : -7;
    var right = turn ? 9 : -9;
    return [s + left, s + right].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) === 1;
    });
  }

  var ROOK_DELTAS = [8, 1, -8, -1];
  var BISHOP_DELTAS = [9, -9, 7, -7];
  var QUEEN_DELTAS = ROOK_DELTAS.concat(BISHOP_DELTAS);

  var slidingMovesTo = function(s, deltas, board) {
    var result = [];
    deltas.forEach(function(delta) {
      for (var square = s + delta; square >= 0 && square < 64 && squareDist(square, square - delta) === 1; square += delta) {
        result.push(square);
        if (board.pieces[square]) break;
      }
    });
    return result;
  }

  var sanOf = function(board, uci) {
    if (uci.indexOf('@') !== -1) return fixCrazySan(uci);

    var move = decomposeUci(uci);
    var from = square(move[0]);
    var to = square(move[1]);
    var p = board.pieces[from];
    var d = board.pieces[to];
    var pt = board.pieces[from].toLowerCase();

    // pawn moves
    if (pt === 'p') {
      var san;
      if (uci[0] === uci[2]) san = move[1];
      else san = uci[0] + 'x' + move[1];
      if (move[2]) san += '=' + move[2].toUpperCase();
      return san;
    }

    // castling
    if (pt == 'k' && ((d && isBlack(p) === isBlack(d)) || squareDist(from, to) > 1)) {
      if (to < from) return 'O-O-O';
      else return 'O-O';
    }

    var san = pt.toUpperCase();

    // disambiguate normal moves
    var candidates = [];
    if (pt == 'k') candidates = kingMovesTo(to);
    else if (pt == 'n') candidates = knightMovesTo(to);
    else if (pt == 'r') candidates = slidingMovesTo(to, ROOK_DELTAS, board);
    else if (pt == 'b') candidates = slidingMovesTo(to, BISHOP_DELTAS, board);
    else if (pt == 'q') candidates = slidingMovesTo(to, QUEEN_DELTAS, board);

    var rank = false,
      file = false;
    for (var i = 0; i < candidates.length; i++) {
      if (candidates[i] === from || board.pieces[candidates[i]] !== p) continue;
      if ((from >> 3) === (candidates[i] >> 3)) file = true;
      if ((from & 7) === (candidates[i] & 7)) rank = true;
      else file = true;
    }
    if (file) san += uci[0];
    if (rank) san += uci[1];

    // target
    if (d) san += 'x';
    san += move[1];
    return san;
  }

  return function(fen, ucis) {
    var board = readFen(fen);
    var sans = {}
    ucis.forEach(function(uci) {
      var san = sanOf(board, uci);
      sans[san] = uci;
      if (san.indexOf('x') !== -1)
        sans[san.replace('x', '')] = uci;
    });
    return sans;
  }
}

function focusChat() {
  var chatInput = document.querySelector('.mchat input.lichess_say');
  if (chatInput) chatInput.focus();
}
<commit_msg>don't autofocus keyboard input on page load<commit_after>var keyRegex = /^[a-h][1-8]$/;
var fileRegex = /^[a-h]$/;

lichess.keyboardMove = function(opts) {
  if (opts.input.classList.contains('ready')) return;
  opts.input.classList.add('ready');
  var writer = sanWriter();
  var sans = null;
  var submit = function(v, force) {
    var foundUci = v.length >= 2 && sans && sanToUci(v, sans);
    if (foundUci) {
      // ambiguous castle
      if (v.toLowerCase() === 'o-o' && sans['O-O-O'] && !force) return;
      // ambiguous UCI
      if (v.match(keyRegex) && opts.hasSelected()) opts.select(v);
      else opts.san(foundUci.slice(0, 2), foundUci.slice(2));
      clear();
    } else if (sans && v.match(keyRegex)) {
      opts.select(v);
      clear();
    } else if (sans && v.match(fileRegex)) {
      // do nothing
    } else
      opts.input.classList.toggle('wrong', v.length && sans && !sanCandidates(v, sans).length);
  };
  var clear = function() {
    opts.input.value = '';
    opts.input.classList.remove('wrong');
  };
  makeBindings(opts, submit, clear);
  return function(fen, dests) {
    sans = dests && Object.keys(dests).length ? writer(fen, destsToUcis(dests)) : null;
    submit(opts.input.value);
  };
}

function makeBindings(opts, submit, clear) {
  Mousetrap.bind('enter', function() {
    opts.input.focus();
  });
  opts.input.addEventListener('keyup', function(e) {
    var v = e.target.value;
    if (v.indexOf('/') > -1) {
      focusChat();
      clear();
    } else submit(v, e.keyCode === 13);
  });
  opts.input.addEventListener('focus', function() {
    opts.setFocus(true);
  });
  opts.input.addEventListener('blur', function() {
    opts.setFocus(false);
  });
}

function sanToUci(san, sans) {
  var lowered = san.toLowerCase();
  for (var i in sans)
    if (i.toLowerCase() === lowered) return sans[i];
}

function sanCandidates(san, sans) {
  var lowered = san.toLowerCase();
  return Object.keys(sans).filter(function(s) {
    return s.toLowerCase().indexOf(lowered) === 0;
  });
}

function destsToUcis(dests) {
  var ucis = [];
  Object.keys(dests).forEach(function(orig) {
    dests[orig].forEach(function(dest) {
      ucis.push(orig + dest);
    });
  });
  return ucis;
}

function sanWriter() {

  var fixCrazySan = function(san) {
    return san[0] === 'P' ? san.slice(1) : san;
  };
  var decomposeUci = function(uci) {
    return [uci.slice(0, 2), uci.slice(2, 4), uci.slice(4, 5)];
  };

  var square = function(name) {
    return name.charCodeAt(0) - 97 + (name.charCodeAt(1) - 49) * 8;
  }

  var squareDist = function(a, b) {
    var x1 = a & 7,
      x2 = b & 7;
    var y1 = a >> 3,
      y2 = b >> 3;
    return Math.max(Math.abs(x1 - x2), Math.abs(y1 - y2));
  }

  var isBlack = function(p) {
    return p === p.toLowerCase();
  }

  var readFen = function(fen) {
    var parts = fen.split(' ');
    var board = {
      pieces: {},
      turn: parts[1] === 'w'
    };

    parts[0].split('/').slice(0, 8).forEach(function(row, y) {
      var x = 0;
      row.split('').forEach(function(v) {
        if (v == '~') return;
        var nb = parseInt(v, 10);
        if (nb) x += nb;
        else {
          var square = (7 - y) * 8 + x;
          board.pieces[square] = v;
          if (v === 'k' || v === 'K') board[v] = square;
          x++;
        }
      });
    });

    return board;
  }

  var kingMovesTo = function(s) {
    return [s - 1, s - 9, s - 8, s - 7, s + 1, s + 9, s + 8, s + 7].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) === 1;
    });
  }

  var knightMovesTo = function(s) {
    return [s + 17, s + 15, s + 10, s + 6, s - 6, s - 10, s - 15, s - 17].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) <= 2;
    });
  }

  var pawnAttacksTo = function(turn, s) {
    var left = turn ? 7 : -7;
    var right = turn ? 9 : -9;
    return [s + left, s + right].filter(function(o) {
      return o >= 0 && o < 64 && squareDist(s, o) === 1;
    });
  }

  var ROOK_DELTAS = [8, 1, -8, -1];
  var BISHOP_DELTAS = [9, -9, 7, -7];
  var QUEEN_DELTAS = ROOK_DELTAS.concat(BISHOP_DELTAS);

  var slidingMovesTo = function(s, deltas, board) {
    var result = [];
    deltas.forEach(function(delta) {
      for (var square = s + delta; square >= 0 && square < 64 && squareDist(square, square - delta) === 1; square += delta) {
        result.push(square);
        if (board.pieces[square]) break;
      }
    });
    return result;
  }

  var sanOf = function(board, uci) {
    if (uci.indexOf('@') !== -1) return fixCrazySan(uci);

    var move = decomposeUci(uci);
    var from = square(move[0]);
    var to = square(move[1]);
    var p = board.pieces[from];
    var d = board.pieces[to];
    var pt = board.pieces[from].toLowerCase();

    // pawn moves
    if (pt === 'p') {
      var san;
      if (uci[0] === uci[2]) san = move[1];
      else san = uci[0] + 'x' + move[1];
      if (move[2]) san += '=' + move[2].toUpperCase();
      return san;
    }

    // castling
    if (pt == 'k' && ((d && isBlack(p) === isBlack(d)) || squareDist(from, to) > 1)) {
      if (to < from) return 'O-O-O';
      else return 'O-O';
    }

    var san = pt.toUpperCase();

    // disambiguate normal moves
    var candidates = [];
    if (pt == 'k') candidates = kingMovesTo(to);
    else if (pt == 'n') candidates = knightMovesTo(to);
    else if (pt == 'r') candidates = slidingMovesTo(to, ROOK_DELTAS, board);
    else if (pt == 'b') candidates = slidingMovesTo(to, BISHOP_DELTAS, board);
    else if (pt == 'q') candidates = slidingMovesTo(to, QUEEN_DELTAS, board);

    var rank = false,
      file = false;
    for (var i = 0; i < candidates.length; i++) {
      if (candidates[i] === from || board.pieces[candidates[i]] !== p) continue;
      if ((from >> 3) === (candidates[i] >> 3)) file = true;
      if ((from & 7) === (candidates[i] & 7)) rank = true;
      else file = true;
    }
    if (file) san += uci[0];
    if (rank) san += uci[1];

    // target
    if (d) san += 'x';
    san += move[1];
    return san;
  }

  return function(fen, ucis) {
    var board = readFen(fen);
    var sans = {}
    ucis.forEach(function(uci) {
      var san = sanOf(board, uci);
      sans[san] = uci;
      if (san.indexOf('x') !== -1)
        sans[san.replace('x', '')] = uci;
    });
    return sans;
  }
}

function focusChat() {
  var chatInput = document.querySelector('.mchat input.lichess_say');
  if (chatInput) chatInput.focus();
}
<|endoftext|>


<commit_before>QUnit.module( "assert" );

QUnit.test( "propEqual", function( assert ) {
	assert.expect( 5 );
	var objectCreate = Object.create || function( origin ) {
		function O() {}
		O.prototype = origin;
		var r = new O();
		return r;
	};

	function Foo( x, y, z ) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
	Foo.prototype.doA = function() {};
	Foo.prototype.doB = function() {};
	Foo.prototype.bar = "prototype";

	function Bar() {
	}
	Bar.prototype = objectCreate( Foo.prototype );
	Bar.prototype.constructor = Bar;

	assert.propEqual(
		new Foo( 1, "2", [] ),
		{
			x: 1,
			y: "2",
			z: []
		}
	);

	assert.notPropEqual(
		new Foo( "1", 2, 3 ),
		{
			x: 1,
			y: "2",
			z: 3
		},
		"Primitive values are strictly compared"
	);

	assert.notPropEqual(
		new Foo( 1, "2", [] ),
		{
			x: 1,
			y: "2",
			z: {}
		},
		"Array type is preserved"
	);

	assert.notPropEqual(
		new Foo( 1, "2", {} ),
		{
			x: 1,
			y: "2",
			z: []
		},
		"Empty array is not the same as empty object"
	);

	assert.propEqual(
		new Foo( 1, "2", new Foo( [ 3 ], new Bar(), null ) ),
		{
			x: 1,
			y: "2",
			z: {
				x: [ 3 ],
				y: {},
				z: null
			}
		},
		"Complex nesting of different types, inheritance and constructors"
	);
});

QUnit.test( "throws", function( assert ) {
	assert.expect( 16 );
	function CustomError( message ) {
		this.message = message;
	}

	CustomError.prototype.toString = function() {
		return this.message;
	};

	assert.throws(
		function() {
			throw "my error";
		}
	);

	assert.throws(
		function() {
			throw "my error";
		},
		"simple string throw, no 'expected' value given"
	);

	// This test is for IE 7 and prior which does not properly
	// implement Error.prototype.toString
	assert.throws(
		function() {
			throw new Error( "error message" );
		},
		/error message/,
		"use regexp against instance of Error"
	);

	assert.throws(
		function() {
			throw new TypeError();
		},
		Error,
		"thrown TypeError without a message is an instance of Error"
	);

	assert.throws(
		function() {
			throw new TypeError();
		},
		TypeError,
		"thrown TypeError without a message is an instance of TypeError"
	);

	assert.throws(
		function() {
			throw new TypeError( "error message" );
		},
		Error,
		"thrown TypeError with a message is an instance of Error"
	);

	// This test is for IE 8 and prior which goes against the standards
	// by considering that the native Error constructors, such TypeError,
	// are also instances of the Error constructor. As such, the assertion
	// sometimes went down the wrong path.
	assert.throws(
		function() {
			throw new TypeError( "error message" );
		},
		TypeError,
		"thrown TypeError with a message is an instance of TypeError"
	);

	assert.throws(
		function() {
			throw new CustomError( "some error description" );
		},
		CustomError,
		"thrown error is an instance of CustomError"
	);

	assert.throws(
		function() {
			throw new Error( "some error description" );
		},
		/description/,
		"use a regex to match against the stringified error"
	);

	assert.throws(
		function() {
			throw new Error( "foo" );
		},
		new Error( "foo" ),
		"thrown error object is similar to the expected Error object"
	);

	assert.throws(
		function() {
			throw new CustomError( "some error description" );
		},
		new CustomError( "some error description" ),
		"thrown error object is similar to the expected CustomError object"
	);

	assert.throws(
		function() {
			throw {
				name: "SomeName",
				message: "some message"
			};
		},
		{ name: "SomeName", message: "some message" },
		"thrown error object is similar to the expected plain object"
	);

	assert.throws(
		function() {
			throw new CustomError( "some error description" );
		},
		function( err ) {
			return err instanceof CustomError && /description/.test( err );
		},
		"custom validation function"
	);

	assert.throws(
		function() {

			/*jshint ignore:start */
			( window.execScript || function( data ) {
				window.eval.call( window, data );
			})( "throw 'error';" );

			/*jshint ignore:end */
		},
		"globally-executed errors caught"
	);

	this.CustomError = CustomError;

	assert.throws(
		function() {
			throw new this.CustomError( "some error description" );
		},
		/description/,
		"throw error from property of 'this' context"
	);

	assert.throws(
		function() {
			throw "some error description";
		},
		"some error description",
		"handle string typed thrown errors"
	);
});

QUnit.test( "raises, alias for throws", function( assert ) {
	assert.expect( 1 );
	assert.raises(function() {
		throw "my error";
	});
});
<commit_msg>Tests: Add missing tests for assertions<commit_after>QUnit.module( "assert" );

QUnit.test( "ok", function( assert ) {
	assert.ok( true );
	assert.ok( 1 );
	assert.ok( "1" );
	assert.ok( Infinity );
	assert.ok( {} );
	assert.ok( [] );
});

QUnit.test( "notOk", function( assert ) {
	assert.notOk( false );
	assert.notOk( 0 );
	assert.notOk( "" );
	assert.notOk( null );
	assert.notOk( undefined );
	assert.notOk( NaN );
});

QUnit.test( "equal", function( assert ) {
	assert.equal( 1, 1 );
	assert.equal( "foo", "foo" );
	assert.equal( "foo", [ "foo" ] );
	assert.equal( "foo", { toString: function() { return "foo"; } } );
	assert.equal( 0, [ 0 ] );
});

QUnit.test( "notEqual", function( assert ) {
	assert.notEqual( 1, 2 );
	assert.notEqual( "foo", "bar" );
	assert.notEqual( {}, {} );
	assert.notEqual( [], [] );
});

QUnit.test( "strictEqual", function( assert ) {
	assert.strictEqual( 1, 1 );
	assert.strictEqual( "foo", "foo" );
});

QUnit.test( "notStrictEqual", function( assert ) {
	assert.notStrictEqual( 1, 2 );
	assert.notStrictEqual( "foo", "bar" );
	assert.notStrictEqual( "foo", [ "foo" ] );
	assert.notStrictEqual( "1", 1 );
	assert.notStrictEqual( "foo", { toString: function() { return "foo"; } } );
});

QUnit.test( "propEqual", function( assert ) {
	assert.expect( 5 );
	var objectCreate = Object.create || function( origin ) {
		function O() {}
		O.prototype = origin;
		var r = new O();
		return r;
	};

	function Foo( x, y, z ) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
	Foo.prototype.doA = function() {};
	Foo.prototype.doB = function() {};
	Foo.prototype.bar = "prototype";

	function Bar() {
	}
	Bar.prototype = objectCreate( Foo.prototype );
	Bar.prototype.constructor = Bar;

	assert.propEqual(
		new Foo( 1, "2", [] ),
		{
			x: 1,
			y: "2",
			z: []
		}
	);

	assert.notPropEqual(
		new Foo( "1", 2, 3 ),
		{
			x: 1,
			y: "2",
			z: 3
		},
		"Primitive values are strictly compared"
	);

	assert.notPropEqual(
		new Foo( 1, "2", [] ),
		{
			x: 1,
			y: "2",
			z: {}
		},
		"Array type is preserved"
	);

	assert.notPropEqual(
		new Foo( 1, "2", {} ),
		{
			x: 1,
			y: "2",
			z: []
		},
		"Empty array is not the same as empty object"
	);

	assert.propEqual(
		new Foo( 1, "2", new Foo( [ 3 ], new Bar(), null ) ),
		{
			x: 1,
			y: "2",
			z: {
				x: [ 3 ],
				y: {},
				z: null
			}
		},
		"Complex nesting of different types, inheritance and constructors"
	);
});

QUnit.test( "throws", function( assert ) {
	assert.expect( 16 );
	function CustomError( message ) {
		this.message = message;
	}

	CustomError.prototype.toString = function() {
		return this.message;
	};

	assert.throws(
		function() {
			throw "my error";
		}
	);

	assert.throws(
		function() {
			throw "my error";
		},
		"simple string throw, no 'expected' value given"
	);

	// This test is for IE 7 and prior which does not properly
	// implement Error.prototype.toString
	assert.throws(
		function() {
			throw new Error( "error message" );
		},
		/error message/,
		"use regexp against instance of Error"
	);

	assert.throws(
		function() {
			throw new TypeError();
		},
		Error,
		"thrown TypeError without a message is an instance of Error"
	);

	assert.throws(
		function() {
			throw new TypeError();
		},
		TypeError,
		"thrown TypeError without a message is an instance of TypeError"
	);

	assert.throws(
		function() {
			throw new TypeError( "error message" );
		},
		Error,
		"thrown TypeError with a message is an instance of Error"
	);

	// This test is for IE 8 and prior which goes against the standards
	// by considering that the native Error constructors, such TypeError,
	// are also instances of the Error constructor. As such, the assertion
	// sometimes went down the wrong path.
	assert.throws(
		function() {
			throw new TypeError( "error message" );
		},
		TypeError,
		"thrown TypeError with a message is an instance of TypeError"
	);

	assert.throws(
		function() {
			throw new CustomError( "some error description" );
		},
		CustomError,
		"thrown error is an instance of CustomError"
	);

	assert.throws(
		function() {
			throw new Error( "some error description" );
		},
		/description/,
		"use a regex to match against the stringified error"
	);

	assert.throws(
		function() {
			throw new Error( "foo" );
		},
		new Error( "foo" ),
		"thrown error object is similar to the expected Error object"
	);

	assert.throws(
		function() {
			throw new CustomError( "some error description" );
		},
		new CustomError( "some error description" ),
		"thrown error object is similar to the expected CustomError object"
	);

	assert.throws(
		function() {
			throw {
				name: "SomeName",
				message: "some message"
			};
		},
		{ name: "SomeName", message: "some message" },
		"thrown error object is similar to the expected plain object"
	);

	assert.throws(
		function() {
			throw new CustomError( "some error description" );
		},
		function( err ) {
			return err instanceof CustomError && /description/.test( err );
		},
		"custom validation function"
	);

	assert.throws(
		function() {

			/*jshint ignore:start */
			( window.execScript || function( data ) {
				window.eval.call( window, data );
			})( "throw 'error';" );

			/*jshint ignore:end */
		},
		"globally-executed errors caught"
	);

	this.CustomError = CustomError;

	assert.throws(
		function() {
			throw new this.CustomError( "some error description" );
		},
		/description/,
		"throw error from property of 'this' context"
	);

	assert.throws(
		function() {
			throw "some error description";
		},
		"some error description",
		"handle string typed thrown errors"
	);
});

QUnit.test( "raises, alias for throws", function( assert ) {
	assert.expect( 1 );
	assert.raises(function() {
		throw "my error";
	});
});

QUnit.module( "failing assertions", {
	beforeEach: function( assert ) {
		var originalPush = assert.push;

		assert.push = function( result, actual, expected, message ) {

			// inverts the result so we can test failing assertions
			originalPush( !result, actual, expected, message );
		};
	}
});

QUnit.test( "ok", function( assert ) {
	assert.ok( false );
	assert.ok( 0 );
	assert.ok( "" );
	assert.ok( null );
	assert.ok( undefined );
	assert.ok( NaN );
});

QUnit.test( "notOk", function( assert ) {
	assert.notOk( true );
	assert.notOk( 1 );
	assert.notOk( "1" );
	assert.notOk( Infinity );
	assert.notOk( {} );
	assert.notOk( [] );
});

QUnit.test( "equal", function( assert ) {
	assert.equal( 1, 2 );
	assert.equal( "foo", "bar" );
	assert.equal( {}, {} );
	assert.equal( [], [] );
});

QUnit.test( "notEqual", function( assert ) {
	assert.notEqual( 1, 1 );
	assert.notEqual( "foo", "foo" );
	assert.notEqual( "foo", [ "foo" ] );
	assert.notEqual( "foo", { toString: function() { return "foo"; } } );
	assert.notEqual( 0, [ 0 ] );
});

QUnit.test( "strictEqual", function( assert ) {
	assert.strictEqual( 1, 2 );
	assert.strictEqual( "foo", "bar" );
	assert.strictEqual( "foo", [ "foo" ] );
	assert.strictEqual( "1", 1 );
	assert.strictEqual( "foo", { toString: function() { return "foo"; } } );
});

QUnit.test( "notStrictEqual", function( assert ) {
	assert.notStrictEqual( 1, 1 );
	assert.notStrictEqual( "foo", "foo" );
});

QUnit.test( "deepEqual", function( assert ) {
	assert.deepEqual( [ "foo", "bar" ], [ "foo" ] );
});

QUnit.test( "notDeepEqual", function( assert ) {
	assert.notDeepEqual( [ "foo", "bar" ], [ "foo", "bar" ] );
});

QUnit.test( "propEqual", function( assert ) {
	function Foo( x, y, z ) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
	Foo.prototype.baz = function() {};
	Foo.prototype.bar = "prototype";

	assert.propEqual(
		new Foo( "1", 2, 3 ),
		{
			x: 1,
			y: "2",
			z: 3
		}
	);
});

QUnit.test( "notPropEqual", function( assert ) {
	function Foo( x, y, z ) {
		this.x = x;
		this.y = y;
		this.z = z;
	}
	Foo.prototype.baz = function() {};
	Foo.prototype.bar = "prototype";

	assert.notPropEqual(
		new Foo( 1, "2", [] ),
		{
			x: 1,
			y: "2",
			z: []
		}
	);
});

QUnit.test( "throws", function( assert ) {
	assert.throws(
		function() {
			return;
		},
		"throws fails without a thrown error"
	);

	assert.throws(
		function() {
			throw "foo";
		},
		/bar/,
		"throws fail when regexp doens't match the error message"
	);
});
<|endoftext|>