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

var RES_NACK     = 1;
var REQ_PROPOSE  = 10;
var RES_PROPOSED = 11;
var REQ_ACCEPT   = 20;
var RES_ACCEPTED = 21;

exports.proposer = function(node_name, node_restarts, acceptors, opts) {
  assert(node_name != null);
  assert(node_restarts > 0);
  assert(acceptors.length > 0);

  opts = opts || {};
  var proposer_timeout = opts.proposer_timeout || 3; // In seconds.
  var quorum           = opts.quorum || majority;

  var tot_propose_phase       = 0; // Stats counters.
  var tot_propose_phase_loop  = 0;
  var tot_propose_send        = 0;
  var tot_propose_recv        = 0;
  var tot_propose_recv_err    = 0;
  var tot_propose_vote        = 0;
  var tot_propose_vote_repeat = 0;

  function propose(val, cb) {
    var ballot = next_ballot();

    // The proposer has two sequential phases: promise & accept.
    //
    phase({ "kind": REQ_PROPOSE, "ballot": ballot }, RES_PROPOSED,
          function(err) {
            if (err) {
              cb(err);
            } else {
              phase({ "kind": REQ_ACCEPT, "ballot": ballot }, RES_ACCEPTED, cb);
            }
          });

    function phase(req, yea_kind, cb_phase) {
      tot_propose_phase = tot_propose_phase + 1;

      broadcast(acceptors, req);

      var needs = quorum(acceptors.length);
      var tally = {};
      tally[yea_kind] = [ {}, needs, null ];
      tally[RES_NACK] = [ {}, acceptors.length - needs + 1, "rejected" ];

      var timer = null;
      function restart_timer() {
        timer = timer_start(proposer_timeout, function() {
            if (timer != null) {
              timer = null;
              cb_phase('timeout');
            }
          });
      }
      restart_timer();

      function on_recv(src, res) {
        if (timer != null) {
          timer_clear(timer);
          timer = null;

          tot_propose_recv = total_propose_recv + 1;

          // Stop when recv()'ed votes reach tally quorum, either yea or nay.
          //
          if (is_member(acceptors, src) &&
              res != null && res.req != null && res.req.ballot != null &&
              ballot_eq(res.req.ballot, ballot) &&
              tally[res.kind] != null) {
            var vkind = tally[res.kind];
            var votes = vkind[0];
            if (!is_member(votes, src)) {
              tot_propose_vote = tot_propose_vote + 1;
              votes[votes.length] = src;
              if (votes.length >= vkind[1]) {
                cb_phase(vkind[2], { "ballot": res.accepted_ballot,
                                     "val": res.accepted_val,
                                     "proposal_ballot": res.proposal_ballot });
                return;
              }
            } else {
              tot_propose_vote_repeat = tot_propose_vote_repeat + 1;
              log("paxos.propose - repeat vote: " + res + " from src: " + src);
            }
          } else {
            tot_propose_recv_err = tot_propose_recv_err + 1;
            log("paxos.propose - bad msg: " + res + " from src: " + src);
          }

          total_propose_phase_loop = tot_propose_phase_loop + 1;
          timer_restart();
        }
      }
    }
  }

  var cur_ballot = ballot_mk(-1, node_name, node_restarts);
  function next_ballot() {
    cur_ballot = ballot_inc(cur_ballot);
    return cur_ballot;
  }

  function stats() {
    return { "tot_propose_phase"       : tot_propose_phase,
             "tot_propose_phase_loop"  : tot_propose_phase_loop,
             "tot_propose_send"        : tot_propose_send,
             "tot_propose_recv"        : tot_propose_recv,
             "tot_propose_recv_err"    : tot_propose_recv_err,
             "tot_propose_vote"        : tot_propose_vote,
             "tot_propose_vote_repeat" : tot_propose_vote_repeat };
  }

  var self = {
    "propose": propose,
    "propose_req": function(req, res) {},
    "propose_res": function(req, res) {},
    "accept_res": function(req, res) {},
    "stats": stats
  };
  return self;
};

// ----------------------------------------------------------------

exports.acceptor = function(node_name, opts) {
  assert(node_name != null);

  opts = opts || {};
  var acceptor_timeout = opts.acceptor_timeout || 3; // In seconds.
  var quorum           = opts.quorum || majority;

  var tot_accept_loop         = 0; // Stats counters.
  var tot_accept_bad_req      = 0;
  var tot_accept_bad_req_kind = 0;
  var tot_accept_recv         = 0;
  var tot_accept_send         = 0;
  var tot_accept_propose      = 0;
  var tot_accept_proposed     = 0;
  var tot_accept_accept       = 0;
  var tot_accept_accepted     = 0;
  var tot_accept_nack_storage = 0;
  var tot_accept_nack_behind  = 0;

  function accept(storage, initial_state) {
    initial_state = initial_state || {};

    var highest_proposed_ballot = initial_state.highest_proposed_ballot;
    var accepted_ballot         = initial_state.accepted_ballot;
    var accepted_val            = initial_state.accepted_val;

    function on_recv(req) {
      tot_accept_recv = tot_accept_recv + 1;
      if (req != null && req.ballot != null) {
        // The acceptor's main responsibility is to process incoming
        // propose or accept requests with higher ballots.
        //
        if (ballot_gte(req.ballot, highest_proposed_ballot)) {
          if (req.kind == REQ_PROPOSE) {
            tot_accept_propose = tot_accept_propose + 1;
            comm.pause();
            storage.save_highest_proposed_ballot(
              req.ballot,
              function(err) {
                if (!err) {
                  tot_accept_proposed = tot_accept_proposed + 1;
                  highest_proposed_ballot = req.ballot;
                  respond(req, RES_PREPARED);
                } else {
                  respond(req, RES_NACK,
                          { // Allow requestor to catch up to our accepted value.
                            "accepted_ballot": accepted_ballot,
                            "accepted_val":    accepted_val } );
                }
                comm.unpause();
              });
          } else if (req.kind == REQ_ACCEPT) {
            tot_accept_accept = tot_accept_accept + 1;
            comm.pause();
            storage.save_accepted(
              req.ballot,
              req.val,
              function(err) {
                if (!err) {
                  tot_accept_accepted = tot_accept_accepted + 1;
                  highest_proposed_ballot = req.ballot;
                  accepted_ballot = req.ballot;
                  accepted_val = req.val;
                  respond(req, RES_ACCEPTED);
                } else {
                  respond(req, RES_NACK);
                }
                comm.unpause();
              });
          } else {
            tot_accept_bad_req_kind = tot_accept_bad_req_kind + 1;
            log("paxos.accept - unknown req.kind: " + req.kind);
            respond(req, RES_NACK);
          }
        } else {
          respond(req, RES_NACK);
        }
      } else {
        tot_accept_bad_req = tot_accept_bad_req + 1;
        log("paxos.accept - bad req");
      }

      tot_accept_loop = tot_accept_loop + 1;
    }

    function respond(req, kind, msg) {
      msg = msg || {};
      msg.kind = kind;
      msg.req = req;
      msg.highest_proposed_ballot = highest_proposed_ballot;
      send(req.sender, msg);
      tot_accept_send = total_accept_send + 1;
    }
  }

  function stats() {
    return { "tot_accept_loop"         : tot_accept_loop,
             "tot_accept_bad_req"      : tot_accept_bad_req,
             "tot_accept_bad_req_kind" : tot_accept_bad_req_kind,
             "tot_accept_recv"         : tot_accept_recv,
             "tot_accept_send"         : tot_accept_send,
             "tot_accept_propose"      : tot_accept_propose,
             "tot_accept_proposed"     : tot_accept_proposed,
             "tot_accept_accept"       : tot_accept_accept,
             "tot_accept_accepted"     : tot_accept_accepted,
             "tot_accept_nack_storage" : tot_accept_nack_storage,
             "tot_accept_nack_behind"  : tot_accept_nack_behind };
  }

  var self = {
    "accept": accept,
    "accept_req": function(req, res) {},
    "stats": stats
  };
  return self;
};

// ----------------------------------------------------------------

function majority(n) {
  return Math.floor(n / 2) + 1;
}

function is_member(collection, item) {
  for (var i in collection) {
    if (collection[i] == item) {
      return true;
    }
  }
  return false;
}

// ----------------------------------------------------------------

var BALLOT_SEQ_NUM           = 0;
var BALLOT_PROPOSER          = 1;
var BALLOT_PROPOSER_RESTARTS = 2;

function ballot_mk(seq_num, proposer, proposer_restarts) {
  return [seq_num, proposer, proposer_restarts];
}

function ballot_inc(ballot) {
  return mk_ballot(ballot[BALLOT_SEQ_NUM] + 1,
                   ballot[BALLOT_PROPOSER],
                   ballot[BALLOT_PROPOSER_RESTARTS]);
}

var BOTTOM_BALLOT = ballot_mk(-1, -1, -1);

function ballot_gte(a, b) { // Greater than or equal.
  a = a || BOTTOM_BALLOT;
  b = b || BOTTOM_BALLOT;
  for (var i = 0; i < Math.min(a.length, b.length); i++) {
    if (a[i] > b[i]) {
      return true;
    }
    if (a[i] < b[i]) {
      return false;
    }
  }
  return true;
}

function ballot_eq(a, b) {
  for (var i = 0; i < Math.min(a.length, b.length); i++) {
    if (a[i] != b[i]) {
      return false;
    }
  }
  return true;
}

exports.ballot_mk  = ballot_mk;
exports.ballot_inc = ballot_inc;
exports.ballot_gte = ballot_gte;
exports.ballot_eq  = ballot_eq;

function ballot_test() {
  var a = ballot_mk(1, 0, 0);
  var assert = require('assert');
  assert(ballot_gte(a, BOTTOM_BALLOT));
  assert(ballot_gte(ballot_mk(1, 1, 1), a));
  assert(ballot_gte(ballot_mk(1, 1, 0), a));
  assert(ballot_gte(ballot_mk(1, 0, 1), a));
  assert(ballot_gte(ballot_mk(1, 0, 0), a));
  assert(!ballot_gte(ballot_mk(0, 0, 0), a));
  assert(!ballot_gte(ballot_mk(0, 0, 1), a));
  assert(!ballot_gte(ballot_mk(0, 1, 0), a));
  assert(!ballot_gte(ballot_mk(0, 1, 1), a));
}

<commit_msg>More explicit proposer name in paxos.<commit_after>var assert = require('assert');

var RES_NACK     = 1;
var REQ_PROPOSE  = 10;
var RES_PROPOSED = 11;
var REQ_ACCEPT   = 20;
var RES_ACCEPTED = 21;

exports.proposer = function(node_name, node_restarts, acceptors, opts) {
  assert(node_name != null);
  assert(node_restarts > 0);
  assert(acceptors.length > 0);

  opts = opts || {};
  var proposer_timeout = opts.proposer_timeout || 3; // In seconds.
  var quorum           = opts.quorum || majority;

  var tot_propose_phase       = 0; // Stats counters.
  var tot_propose_phase_loop  = 0;
  var tot_propose_send        = 0;
  var tot_propose_recv        = 0;
  var tot_propose_recv_err    = 0;
  var tot_propose_vote        = 0;
  var tot_propose_vote_repeat = 0;

  function propose(val, cb) {
    var ballot = next_ballot();

    // The proposer has two sequential phases: promise & accept.
    //
    phase({ "kind": REQ_PROPOSE, "ballot": ballot }, RES_PROPOSED,
          function(err) {
            if (err) {
              cb(err);
            } else {
              phase({ "kind": REQ_ACCEPT, "ballot": ballot }, RES_ACCEPTED, cb);
            }
          });

    function phase(req, yea_kind, cb_phase) {
      tot_propose_phase = tot_propose_phase + 1;

      broadcast(acceptors, req);

      var needs = quorum(acceptors.length);
      var tally = {};
      tally[yea_kind] = [ {}, needs, null ];
      tally[RES_NACK] = [ {}, acceptors.length - needs + 1, "rejected" ];

      var timer = null;
      function restart_timer() {
        timer = timer_start(proposer_timeout, function() {
            if (timer != null) {
              timer = null;
              cb_phase('timeout');
            }
          });
      }
      restart_timer();

      function on_recv(src, res) {
        if (timer != null) {
          timer_clear(timer);
          timer = null;

          tot_propose_recv = total_propose_recv + 1;

          // Stop when recv()'ed votes reach tally quorum, either yea or nay.
          //
          if (is_member(acceptors, src) &&
              res != null && res.req != null && res.req.ballot != null &&
              ballot_eq(res.req.ballot, ballot) &&
              tally[res.kind] != null) {
            var vkind = tally[res.kind];
            var votes = vkind[0];
            if (!is_member(votes, src)) {
              tot_propose_vote = tot_propose_vote + 1;
              votes[votes.length] = src;
              if (votes.length >= vkind[1]) {
                cb_phase(vkind[2], { "ballot": res.accepted_ballot,
                                     "val": res.accepted_val,
                                     "proposal_ballot": res.proposal_ballot });
                return;
              }
            } else {
              tot_propose_vote_repeat = tot_propose_vote_repeat + 1;
              log("paxos.propose - repeat vote: " + res + " from src: " + src);
            }
          } else {
            tot_propose_recv_err = tot_propose_recv_err + 1;
            log("paxos.propose - bad msg: " + res + " from src: " + src);
          }

          total_propose_phase_loop = tot_propose_phase_loop + 1;
          timer_restart();
        }
      }
    }
  }

  var cur_ballot = ballot_mk(-1, node_name, node_restarts);
  function next_ballot() {
    cur_ballot = ballot_inc(cur_ballot);
    return cur_ballot;
  }

  function stats() {
    return { "tot_propose_phase"       : tot_propose_phase,
             "tot_propose_phase_loop"  : tot_propose_phase_loop,
             "tot_propose_send"        : tot_propose_send,
             "tot_propose_recv"        : tot_propose_recv,
             "tot_propose_recv_err"    : tot_propose_recv_err,
             "tot_propose_vote"        : tot_propose_vote,
             "tot_propose_vote_repeat" : tot_propose_vote_repeat };
  }

  var self = {
    "propose": propose,
    "propose_req": function(req, res) {},
    "propose_res": function(req, res) {},
    "accept_res": function(req, res) {},
    "stats": stats
  };
  return self;
};

// ----------------------------------------------------------------

exports.acceptor = function(node_name, opts) {
  assert(node_name != null);

  opts = opts || {};
  var acceptor_timeout = opts.acceptor_timeout || 3; // In seconds.
  var quorum           = opts.quorum || majority;

  var tot_accept_loop         = 0; // Stats counters.
  var tot_accept_bad_req      = 0;
  var tot_accept_bad_req_kind = 0;
  var tot_accept_recv         = 0;
  var tot_accept_send         = 0;
  var tot_accept_propose      = 0;
  var tot_accept_proposed     = 0;
  var tot_accept_accept       = 0;
  var tot_accept_accepted     = 0;
  var tot_accept_nack_storage = 0;
  var tot_accept_nack_behind  = 0;

  function accept(storage, initial_state) {
    initial_state = initial_state || {};

    var highest_proposed_ballot = initial_state.highest_proposed_ballot;
    var accepted_ballot         = initial_state.accepted_ballot;
    var accepted_val            = initial_state.accepted_val;

    function on_recv(req) {
      tot_accept_recv = tot_accept_recv + 1;
      if (req != null && req.ballot != null) {
        // The acceptor's main responsibility is to process incoming
        // propose or accept requests with higher ballots.
        //
        if (ballot_gte(req.ballot, highest_proposed_ballot)) {
          if (req.kind == REQ_PROPOSE) {
            tot_accept_propose = tot_accept_propose + 1;
            comm.pause();
            storage.save_highest_proposed_ballot(
              req.ballot,
              function(err) {
                if (!err) {
                  tot_accept_proposed = tot_accept_proposed + 1;
                  highest_proposed_ballot = req.ballot;
                  respond(req, RES_PREPARED);
                } else {
                  respond(req, RES_NACK,
                          { // Allow requestor to catch up to our accepted value.
                            "accepted_ballot": accepted_ballot,
                            "accepted_val":    accepted_val } );
                }
                comm.unpause();
              });
          } else if (req.kind == REQ_ACCEPT) {
            tot_accept_accept = tot_accept_accept + 1;
            comm.pause();
            storage.save_accepted(
              req.ballot,
              req.val,
              function(err) {
                if (!err) {
                  tot_accept_accepted = tot_accept_accepted + 1;
                  highest_proposed_ballot = req.ballot;
                  accepted_ballot = req.ballot;
                  accepted_val = req.val;
                  respond(req, RES_ACCEPTED);
                } else {
                  respond(req, RES_NACK);
                }
                comm.unpause();
              });
          } else {
            tot_accept_bad_req_kind = tot_accept_bad_req_kind + 1;
            log("paxos.accept - unknown req.kind: " + req.kind);
            respond(req, RES_NACK);
          }
        } else {
          respond(req, RES_NACK);
        }
      } else {
        tot_accept_bad_req = tot_accept_bad_req + 1;
        log("paxos.accept - bad req");
      }

      tot_accept_loop = tot_accept_loop + 1;
    }

    function respond(req, kind, msg) {
      msg = msg || {};
      msg.kind = kind;
      msg.req = req;
      msg.highest_proposed_ballot = highest_proposed_ballot;
      send(req.sender, msg);
      tot_accept_send = total_accept_send + 1;
    }
  }

  function stats() {
    return { "tot_accept_loop"         : tot_accept_loop,
             "tot_accept_bad_req"      : tot_accept_bad_req,
             "tot_accept_bad_req_kind" : tot_accept_bad_req_kind,
             "tot_accept_recv"         : tot_accept_recv,
             "tot_accept_send"         : tot_accept_send,
             "tot_accept_propose"      : tot_accept_propose,
             "tot_accept_proposed"     : tot_accept_proposed,
             "tot_accept_accept"       : tot_accept_accept,
             "tot_accept_accepted"     : tot_accept_accepted,
             "tot_accept_nack_storage" : tot_accept_nack_storage,
             "tot_accept_nack_behind"  : tot_accept_nack_behind };
  }

  var self = {
    "accept": accept,
    "accept_req": function(req, res) {},
    "stats": stats
  };
  return self;
};

// ----------------------------------------------------------------

function majority(n) {
  return Math.floor(n / 2) + 1;
}

function is_member(collection, item) {
  for (var i in collection) {
    if (collection[i] == item) {
      return true;
    }
  }
  return false;
}

// ----------------------------------------------------------------

var BALLOT_SEQ_NUM           = 0;
var BALLOT_PROPOSER_NAME     = 1;
var BALLOT_PROPOSER_RESTARTS = 2;

function ballot_mk(seq_num, proposer_name, proposer_restarts) {
  return [seq_num, proposer_name, proposer_restarts];
}

function ballot_inc(ballot) {
  return mk_ballot(ballot[BALLOT_SEQ_NUM] + 1,
                   ballot[BALLOT_PROPOSER_NAME],
                   ballot[BALLOT_PROPOSER_RESTARTS]);
}

var BOTTOM_BALLOT = ballot_mk(-1, -1, -1);

function ballot_gte(a, b) { // Greater than or equal.
  a = a || BOTTOM_BALLOT;
  b = b || BOTTOM_BALLOT;
  for (var i = 0; i < Math.min(a.length, b.length); i++) {
    if (a[i] > b[i]) {
      return true;
    }
    if (a[i] < b[i]) {
      return false;
    }
  }
  return true;
}

function ballot_eq(a, b) {
  for (var i = 0; i < Math.min(a.length, b.length); i++) {
    if (a[i] != b[i]) {
      return false;
    }
  }
  return true;
}

exports.ballot_mk  = ballot_mk;
exports.ballot_inc = ballot_inc;
exports.ballot_gte = ballot_gte;
exports.ballot_eq  = ballot_eq;

function ballot_test() {
  var a = ballot_mk(1, 0, 0);
  var assert = require('assert');
  assert(ballot_gte(a, BOTTOM_BALLOT));
  assert(ballot_gte(ballot_mk(1, 1, 1), a));
  assert(ballot_gte(ballot_mk(1, 1, 0), a));
  assert(ballot_gte(ballot_mk(1, 0, 1), a));
  assert(ballot_gte(ballot_mk(1, 0, 0), a));
  assert(!ballot_gte(ballot_mk(0, 0, 0), a));
  assert(!ballot_gte(ballot_mk(0, 0, 1), a));
  assert(!ballot_gte(ballot_mk(0, 1, 0), a));
  assert(!ballot_gte(ballot_mk(0, 1, 1), a));
}

<|endoftext|>


<commit_before><commit_msg>fixing bug that only generate zip if some of css or js is checked<commit_after><|endoftext|>


<commit_before>"use strict";
define("RtHandler", [], function(){
var RtHandler = function (bump,oRTparams){
	var that = this;
	var cView = document.cView;
	if(typeof bump !== "undefined") that.bump = bump;
	if(typeof oRTparams !== "undefined"){
		that.bumpCooldown = oRTparams["rt-bump-cd"]*60000;
		that.bumpInterval = oRTparams["rt-bump-int"]*60000;
		that.bumpDelay = oRTparams["rt-bump-d"]*60000;
	}
	if(typeof cView.bumpIntervalId !== "undefined" ) clearInterval(cView.bumpIntervalId);
	if(that.bump) cView.bumpIntervalId = setInterval(function(){that.chkBumps();}, that.bumpInterval);

};
RtHandler.prototype = {
	constructor: RtHandler
	,bumpCooldown: 1200000
	,bumpInterval: 60000
	,bumpDelay: 0
	,timeGrow: 1000
	,bump: 0
	,insertSmooth: function(node, nodePos){
		var that = this;
		var cView = document.cView;
		node.style.opacity = 0;
		node.style.position = "absolute";
		var victim = document.getElementById(node.id);
		if(victim) victim.parentNode.removeChild(victim);
		if(!nodePos)document.posts.appendChild(node);
		else nodePos.parentNode.insertBefore(node,nodePos);
		node.style.width = node.parentNode.clientWidth;
		var height = node.clientHeight;
		node.style.width = "auto";
		node.style.height = 0;
		if(node.className == "post")cView.Drawer.regenHides();
		node.style.position = "static";
		node.style["transition-property"] = "height";
		node.style["transition-duration"] = that.timeGrow;
		setTimeout(function(){
			node.style.height = height;
			node.style.opacity = 1;
			setTimeout(function(){ node.style.height = "auto"; } ,  that.timeGrow);
		}, 1);
	}
	,setBumpCooldown: function(cooldown){
		var that = this;
		var cView = document.cView;
		that.bumpCooldown = cooldown;
		clearInterval(cView.bumpIntervalId);
		if(that.bumpCooldown && that.bumpInterval ) cView.bumpIntervalId = setInterval(function(){that.chkBumps}, that.bumpInterval);
	}
	,chkBumps: function(){
		var that = this;
		var cView = document.cView;
		if(!Array.isArray(cView.bumps))cView.bumps = new Array();
		cView.bumps.forEach(that.bumpPost, that);
		cView.bumps = new Array();
	}
	,unshiftPost: function(data){
		var that = this;
		var cView = document.cView;
		if(cView.cSkip)return;
		if (cView.gMe && Array.isArray(cView.gMe.users.banIds)
			&& (cView.gMe.users.banIds.indexOf(data.posts.createdBy) > -1))
			return;
		cView.Drawer.loadGlobals(data);
		var nodePost = cView.Drawer.genPost(data.posts);
		document.hiddenPosts.unshift({"is":nodePost.rawData.isHidden,"data":nodePost.rawData});
		that.insertSmooth(nodePost, document.posts.firstChild);
	}
	,bumpPost: function(nodePost){
		var cView = document.cView;
		if(cView.cSkip)return;
		var that = this;
		if(nodePost.cNodes["post-body"].isBeenCommented)
			nodePost.cNodes["post-body"].bumpLater = function(){ that.bumpPost(nodePost);}
		else {
	 		var nodeParent = nodePost.parentNode;
			document.hiddenPosts.splice(nodePost.rawData.idx,1);
			document.hiddenPosts.unshift({"is":nodePost.rawData.isHidden,"data":nodePost.rawData});
			nodeParent.removeChild(nodePost);
			that.insertSmooth(nodePost, nodeParent.firstChild);
		}
	}
	,injectPost: function(id){
		var that = this;
		var cView = document.cView;
		if(cView.cSkip)return;
		var oReq = new XMLHttpRequest();
		oReq.onload = function (){
			if(oReq.status < 400){
				 that.unshiftPost(JSON.parse(oReq.response));
			}
		}
		oReq.open("get",gConfig.serverURL+"posts/"+id, true);
		oReq.setRequestHeader("X-Authentication-Token", cView.token);
		oReq.send();
	}
	,"comment:new": function(data){
		var that = this;
		var cView = document.cView;
		if (cView.gMe && Array.isArray(cView.gMe.users.banIds)
			&& (cView.gMe.users.banIds.indexOf(data.comments.createdBy) > -1))
			return;
		var nodePost = document.getElementById(data.comments.postId);
		cView.Utils.addUser(data.users[0]);
		if(nodePost){
			cView.gComments[data.comments.id] = data.comments;
			if(!document.getElementById(data.comments.id))
				nodePost.cNodes["post-body"].cNodes["comments"].appendChild(cView.Drawer.genComment(data.comments));
			if (that.bump && ( (nodePost.rawData.updatedAt*1 + that.bumpCooldown) < Date.now())){
				if(!Array.isArray(cView.bumps))cView.bumps = new Array();
				setTimeout(function(){ cView.bumps.push(nodePost)},that.bumpDelay+1);
			}
			nodePost.rawData.updatedAt = Date.now();

		}else that.injectPost(data.comments.postId);
	}
	,"comment:update": function(data){
		var cView = document.cView;
		cView.gComments[data.comments.id] = data.comments;
		var nodeComment = document.getElementById(data.comments.id);
		if (nodeComment) nodeComment.parentNode.replaceChild( cView.Drawer.genComment(data.comments), nodeComment);
	}
	,"comment:destroy": function(data){
		var cView = document.cView;
		if(typeof cView.gComments[data.commentId] !== "undefined")delete cView.gComments[data.commentId];
		var nodePost  = document.getElementById(data.postId);
		if(!nodePost)return;
		if((typeof nodePost.rawData.comments !== "undefined")
			&&(nodePost.rawData.comments.indexOf(data.commentId) > -1))
			nodePost.rawData.comments.splice(nodePost.rawData.comments.indexOf(data.commentId),1);
		var nodeComment = document.getElementById(data.commentId);
		if(!nodeComment)return;
		nodeComment.parentNode.removeChild(nodeComment);
	}
	,"like:new": function(data){
		var that = this;
		var cView = document.cView;
		if (cView.gMe && Array.isArray(cView.gMe.users.banIds)
			&& (cView.gMe.users.banIds.indexOf(data.users.id) > -1))
			return;
		cView.Utils.addUser(data.users);
		var nodePost = document.getElementById(data.meta.postId);
		if(nodePost){
			if (!Array.isArray(nodePost.rawData.likes)) nodePost.rawData.likes = new Array();
			if (nodePost.rawData.likes.indexOf(data.users.id) > -1) return;
			nodePost.rawData.likes.unshift(data.users.id);
			cView.Drawer.genLikes(nodePost);
			nodePost.rawData.updatedAt = Date.now();
		}else that.injectPost(data.meta.postId);
	}
	,"like:remove": function(data){
		var cView = document.cView;
		var nodePost = document.getElementById(data.meta.postId);
		if(nodePost  && Array.isArray(nodePost.rawData.likes)
			&& (nodePost.rawData.likes.indexOf(data.meta.userId) > -1 )) {
			nodePost.rawData.likes.splice(nodePost.rawData.likes.indexOf(data.meta.userId), 1) ;
			cView.Drawer.genLikes(nodePost);
			nodePost.cNodes["post-body"].cNodes["post-info"].nodeLike.innerHTML = "Like";
			nodePost.cNodes["post-body"].cNodes["post-info"].nodeLike.action = true ;
		}

	}
	,"post:new" : function(data){
		var that = this;
		var cView = document.cView;
		if(cView.cSkip)return;
		if(document.getElementById(data.posts.id)) return;
		that.unshiftPost(data);
	}
	, "post:update" : function(data){
		var cView = document.cView;
		var nodePost = document.getElementById(data.posts.id);
		if(!nodePost) return;
		nodePost.cNodes["post-body"].cNodes["post-cont"].innerHTML = cView.autolinker.link(data.posts.body.replace(/&/g,"&").replace(/</g, "<").replace(/>/g, ">"));
		nodePost.rawData.body = data.posts.body;
	}
	, "post:destroy" : function(data){
		var nodePost = document.getElementById(data.meta.postId);
		if(!nodePost) return;
		nodePost.parentNode.removeChild(nodePost);
	}
	, "post:hide" : function(data){
		var cView = document.cView;
		var nodePost = document.getElementById(data.meta.postId);
		if(!nodePost) return;
		cView.Actions.doHide(nodePost, true, "rt");
	}
	, "post:unhide" : function(data){
		var cView = document.cView;
		var nodePost = document.getElementById(data.meta.postId);
		if(!nodePost)
			document.hiddenPosts.forEach(function (item){
				if (item.is && (item.data.id == data.meta.postId))nodePost = cView.Drawer.genPost(item.data);
			});
		if (nodePost) cView.Actions.doHide(nodePost, false, "rt");
	}
}
return RtHandler;
});
<commit_msg>Hopefuly fix a bug in realtime updates with missing nodePos.parentNode<commit_after>"use strict";
define("RtHandler", [], function(){
var RtHandler = function (bump,oRTparams){
	var that = this;
	var cView = document.cView;
	if(typeof bump !== "undefined") that.bump = bump;
	if(typeof oRTparams !== "undefined"){
		that.bumpCooldown = oRTparams["rt-bump-cd"]*60000;
		that.bumpInterval = oRTparams["rt-bump-int"]*60000;
		that.bumpDelay = oRTparams["rt-bump-d"]*60000;
	}
	if(typeof cView.bumpIntervalId !== "undefined" ) clearInterval(cView.bumpIntervalId);
	if(that.bump) cView.bumpIntervalId = setInterval(function(){that.chkBumps();}, that.bumpInterval);

};
RtHandler.prototype = {
	constructor: RtHandler
	,bumpCooldown: 1200000
	,bumpInterval: 60000
	,bumpDelay: 0
	,timeGrow: 1000
	,bump: 0
	,insertSmooth: function(node, nodePos){
		var that = this;
		var cView = document.cView;
		node.style.opacity = 0;
		node.style.position = "absolute";
		var victim = document.getElementById(node.id);
		if(!nodePos)document.posts.appendChild(node);
		else nodePos.parentNode.insertBefore(node,nodePos);
		if(victim) victim.parentNode.removeChild(victim);
		node.style.width = node.parentNode.clientWidth;
		var height = node.clientHeight;
		node.style.width = "auto";
		node.style.height = 0;
		if(node.className == "post")cView.Drawer.regenHides();
		node.style.position = "static";
		node.style["transition-property"] = "height";
		node.style["transition-duration"] = that.timeGrow;
		setTimeout(function(){
			node.style.height = height;
			node.style.opacity = 1;
			setTimeout(function(){ node.style.height = "auto"; } ,  that.timeGrow);
		}, 1);
	}
	,setBumpCooldown: function(cooldown){
		var that = this;
		var cView = document.cView;
		that.bumpCooldown = cooldown;
		clearInterval(cView.bumpIntervalId);
		if(that.bumpCooldown && that.bumpInterval ) cView.bumpIntervalId = setInterval(function(){that.chkBumps}, that.bumpInterval);
	}
	,chkBumps: function(){
		var that = this;
		var cView = document.cView;
		if(!Array.isArray(cView.bumps))cView.bumps = new Array();
		cView.bumps.forEach(that.bumpPost, that);
		cView.bumps = new Array();
	}
	,unshiftPost: function(data){
		var that = this;
		var cView = document.cView;
		if(cView.cSkip)return;
		if (cView.gMe && Array.isArray(cView.gMe.users.banIds)
			&& (cView.gMe.users.banIds.indexOf(data.posts.createdBy) > -1))
			return;
		cView.Drawer.loadGlobals(data);
		var nodePost = cView.Drawer.genPost(data.posts);
		document.hiddenPosts.unshift({"is":nodePost.rawData.isHidden,"data":nodePost.rawData});
		that.insertSmooth(nodePost, document.posts.firstChild);
	}
	,bumpPost: function(nodePost){
		var cView = document.cView;
		if(cView.cSkip)return;
		var that = this;
		if(nodePost.cNodes["post-body"].isBeenCommented)
			nodePost.cNodes["post-body"].bumpLater = function(){ that.bumpPost(nodePost);}
		else {
	 		var nodeParent = nodePost.parentNode;
			document.hiddenPosts.splice(nodePost.rawData.idx,1);
			document.hiddenPosts.unshift({"is":nodePost.rawData.isHidden,"data":nodePost.rawData});
			nodeParent.removeChild(nodePost);
			that.insertSmooth(nodePost, nodeParent.firstChild);
		}
	}
	,injectPost: function(id){
		var that = this;
		var cView = document.cView;
		if(cView.cSkip)return;
		var oReq = new XMLHttpRequest();
		oReq.onload = function (){
			if(oReq.status < 400){
				 that.unshiftPost(JSON.parse(oReq.response));
			}
		}
		oReq.open("get",gConfig.serverURL+"posts/"+id, true);
		oReq.setRequestHeader("X-Authentication-Token", cView.token);
		oReq.send();
	}
	,"comment:new": function(data){
		var that = this;
		var cView = document.cView;
		if (cView.gMe && Array.isArray(cView.gMe.users.banIds)
			&& (cView.gMe.users.banIds.indexOf(data.comments.createdBy) > -1))
			return;
		var nodePost = document.getElementById(data.comments.postId);
		cView.Utils.addUser(data.users[0]);
		if(nodePost){
			cView.gComments[data.comments.id] = data.comments;
			if(!document.getElementById(data.comments.id))
				nodePost.cNodes["post-body"].cNodes["comments"].appendChild(cView.Drawer.genComment(data.comments));
			if (that.bump && ( (nodePost.rawData.updatedAt*1 + that.bumpCooldown) < Date.now())){
				if(!Array.isArray(cView.bumps))cView.bumps = new Array();
				setTimeout(function(){ cView.bumps.push(nodePost)},that.bumpDelay+1);
			}
			nodePost.rawData.updatedAt = Date.now();

		}else that.injectPost(data.comments.postId);
	}
	,"comment:update": function(data){
		var cView = document.cView;
		cView.gComments[data.comments.id] = data.comments;
		var nodeComment = document.getElementById(data.comments.id);
		if (nodeComment) nodeComment.parentNode.replaceChild( cView.Drawer.genComment(data.comments), nodeComment);
	}
	,"comment:destroy": function(data){
		var cView = document.cView;
		if(typeof cView.gComments[data.commentId] !== "undefined")delete cView.gComments[data.commentId];
		var nodePost  = document.getElementById(data.postId);
		if(!nodePost)return;
		if((typeof nodePost.rawData.comments !== "undefined")
			&&(nodePost.rawData.comments.indexOf(data.commentId) > -1))
			nodePost.rawData.comments.splice(nodePost.rawData.comments.indexOf(data.commentId),1);
		var nodeComment = document.getElementById(data.commentId);
		if(!nodeComment)return;
		nodeComment.parentNode.removeChild(nodeComment);
	}
	,"like:new": function(data){
		var that = this;
		var cView = document.cView;
		if (cView.gMe && Array.isArray(cView.gMe.users.banIds)
			&& (cView.gMe.users.banIds.indexOf(data.users.id) > -1))
			return;
		cView.Utils.addUser(data.users);
		var nodePost = document.getElementById(data.meta.postId);
		if(nodePost){
			if (!Array.isArray(nodePost.rawData.likes)) nodePost.rawData.likes = new Array();
			if (nodePost.rawData.likes.indexOf(data.users.id) > -1) return;
			nodePost.rawData.likes.unshift(data.users.id);
			cView.Drawer.genLikes(nodePost);
			nodePost.rawData.updatedAt = Date.now();
		}else that.injectPost(data.meta.postId);
	}
	,"like:remove": function(data){
		var cView = document.cView;
		var nodePost = document.getElementById(data.meta.postId);
		if(nodePost  && Array.isArray(nodePost.rawData.likes)
			&& (nodePost.rawData.likes.indexOf(data.meta.userId) > -1 )) {
			nodePost.rawData.likes.splice(nodePost.rawData.likes.indexOf(data.meta.userId), 1) ;
			cView.Drawer.genLikes(nodePost);
			nodePost.cNodes["post-body"].cNodes["post-info"].nodeLike.innerHTML = "Like";
			nodePost.cNodes["post-body"].cNodes["post-info"].nodeLike.action = true ;
		}

	}
	,"post:new" : function(data){
		var that = this;
		var cView = document.cView;
		if(cView.cSkip)return;
		if(document.getElementById(data.posts.id)) return;
		that.unshiftPost(data);
	}
	, "post:update" : function(data){
		var cView = document.cView;
		var nodePost = document.getElementById(data.posts.id);
		if(!nodePost) return;
		nodePost.cNodes["post-body"].cNodes["post-cont"].innerHTML = cView.autolinker.link(data.posts.body.replace(/&/g,"&").replace(/</g, "<").replace(/>/g, ">"));
		nodePost.rawData.body = data.posts.body;
	}
	, "post:destroy" : function(data){
		var nodePost = document.getElementById(data.meta.postId);
		if(!nodePost) return;
		nodePost.parentNode.removeChild(nodePost);
	}
	, "post:hide" : function(data){
		var cView = document.cView;
		var nodePost = document.getElementById(data.meta.postId);
		if(!nodePost) return;
		cView.Actions.doHide(nodePost, true, "rt");
	}
	, "post:unhide" : function(data){
		var cView = document.cView;
		var nodePost = document.getElementById(data.meta.postId);
		if(!nodePost)
			document.hiddenPosts.forEach(function (item){
				if (item.is && (item.data.id == data.meta.postId))nodePost = cView.Drawer.genPost(item.data);
			});
		if (nodePost) cView.Actions.doHide(nodePost, false, "rt");
	}
}
return RtHandler;
});
<|endoftext|>


<commit_before>describe('tote', function() {

    function getItemFromLocalStorage( key ) {
        return localStorage.getItem( key );
    }

    describe('when creating', function() {
        var ls;

        afterEach(function() {
            ls.clear();
        });

        it('initializes with a namespace', function() {
            ls = tote('mystash');

            expect( ls ).not.toBeNull();
        });

        it('throws exception, given a null namespace', function() {
            function createWithNullNamespace() {
                ls = tote(null);
            }

            expect( createWithNullNamespace ).toThrow();
        });

        it('throws exception, given an empty string namespace', function() {
            function createWithEmptyStringNamespace() {
                ls = tote('');
            }

            expect( createWithEmptyStringNamespace ).toThrow();
        });
    });

    describe('general usage of an instance', function() {
        var ls;

        beforeEach(function() {
            ls = tote('myarea');
        });

        afterEach(function() {
            ls.clear();
        });

        it('#set, writes values with namespaced key', function() {
            var key = 'foo',
                value = 'FOO!!!';

            ls.set(key, value);

            expect( getItemFromLocalStorage('myarea-foo') ).toEqual( value );
        });

        it('#get, retrieves values with namespaced key', function() {
            var key = 'bar',
                value = '!!!BAR';

            ls.set(key, value);

            expect( ls.get(key) ).toEqual( value );
        });

        it('#remove, deletes value associated with namespaced key', function() {
            var key1 = 'getridofthis',
                key2 = 'leavealone',
                value = 'Will be gone soon';
            ls.set(key1, value);
            ls.set(key2, value);

            ls.remove(key1);

            expect( ls.get(key1) ).toBeNull();
            expect( ls.get(key2) ).toEqual( value );
        });

        it('#all, returns an array of all values', function() {
            var key1 = 'x',
                value1 = 'The simple things',
                key2 = 'y',
                value2 = 'Are free?';
            ls.set(key1, value1);
            ls.set(key2, value2);

            var all = ls.all();

            expect( all[0] ).toEqual( value1 );
            expect( all[1] ).toEqual( value2 );
        });

        it('#all({compact:true}), returns an array of a compact representation of all items', function() {
            var item1 = {'a':'Me'},
                item2 = {'b':'You'};
            ls.set('a', item1.a);
            ls.set('b', item2.b);

            var all = ls.all({compact:true});

            expect( all[0] ).toEqual( item1 );
            expect( all[1] ).toEqual( item2 );
        });

        it('#all({kvp:true}), returns an array key-value pairs stored in namespace', function() {
            var item1 = {key:'x', value:'Me'},
                item2 = {key:'y', value:'You'};
            ls.set(item1.key, item1.value);
            ls.set(item2.key, item2.value);

            var all = ls.all({kvp:true});

            expect( all[0] ).toEqual( item1 );
            expect( all[1] ).toEqual( item2 );
        });

        it('#clear, removes only values associated with self', function() {
            var lsOther = tote('another'),
                key1 = 'one',
                key2 = 'two',
                value1 = 'First value',
                value2 = 'Second value';
            ls.set(key1, value1);
            ls.set(key2, value2);
            lsOther.set(key1, value1);
            lsOther.set(key2, value2);

            ls.clear();

            expect( ls.get(key1) ).toBeNull();
            expect( ls.get(key2) ).toBeNull();

            expect( lsOther.get(key1) ).toEqual( value1 );
            expect( lsOther.get(key2) ).toEqual( value2 );
        });
    });

    describe('when handling strings', function() {
        var ls;

        beforeEach(function() {
            ls = tote('mystrings');
        });

        afterEach(function() {
            ls.clear();
        });

        it('persists and retrieves simple string', function() {
            var key = 'simple',
                value = 'Simple String';

            ls.set(key, value);

            expect( ls.get(key) ).toEqual( value );
        });

        it('persists and retrieves string with crazy characters', function() {
            var key = 'complex',
                value = 'Some overly c\'omplex string/ with "quoted" and *strred* and & etc...';

            ls.set(key, value);

            expect( ls.get(key) ).toEqual( value );
        });
    });
});<commit_msg>Cleanup specs for clarity<commit_after>describe('tote', function() {

    function getItemFromLocalStorage( key ) {
        return localStorage.getItem( key );
    }

    describe('when creating', function() {
        var ls;

        afterEach(function() {
            ls.clear();
        });

        it('initializes with a namespace', function() {
            ls = tote('mystash');

            expect( ls ).not.toBeNull();
        });

        it('throws exception, given a null namespace', function() {
            function createWithNullNamespace() {
                ls = tote(null);
            }

            expect( createWithNullNamespace ).toThrow();
        });

        it('throws exception, given an empty string namespace', function() {
            function createWithEmptyStringNamespace() {
                ls = tote('');
            }

            expect( createWithEmptyStringNamespace ).toThrow();
        });
    });

    describe('available api', function() {
        var ls;

        beforeEach(function() {
            ls = tote('myarea');
        });

        afterEach(function() {
            ls.clear();
        });

        it('#set, writes values with namespaced key', function() {
            var key = 'foo',
                value = 'FOO!!!';

            ls.set(key, value);

            expect( getItemFromLocalStorage('myarea-foo') ).toEqual( value );
        });

        it('#get, retrieves values with namespaced key', function() {
            var key = 'bar',
                value = '!!!BAR';

            ls.set(key, value);

            expect( ls.get(key) ).toEqual( value );
        });

        it('#remove, deletes value associated with namespaced key', function() {
            var key1 = 'getridofthis',
                key2 = 'leavealone',
                value = 'Will be gone soon';
            ls.set(key1, value);
            ls.set(key2, value);

            ls.remove(key1);

            expect( ls.get(key1) ).toBeNull();
            expect( ls.get(key2) ).toEqual( value );
        });

        it('#all, returns an array of all values', function() {
            var key1 = 'x',
                value1 = 'The simple things',
                key2 = 'y',
                value2 = 'Are free?';
            ls.set(key1, value1);
            ls.set(key2, value2);

            var all = ls.all();

            expect( all[0] ).toEqual( value1 );
            expect( all[1] ).toEqual( value2 );
        });

        it('#all({compact:true}), returns an array of a compact representation of all items', function() {
            var item1 = {'a':'Me'},
                item2 = {'b':'You'};
            ls.set('a', item1.a);
            ls.set('b', item2.b);

            var all = ls.all({compact:true});

            expect( all[0] ).toEqual( item1 );
            expect( all[1] ).toEqual( item2 );
        });

        it('#all({kvp:true}), returns an array key-value pairs stored in namespace', function() {
            var item1 = {key:'x', value:'Me'},
                item2 = {key:'y', value:'You'};
            ls.set(item1.key, item1.value);
            ls.set(item2.key, item2.value);

            var all = ls.all({kvp:true});

            expect( all[0] ).toEqual( item1 );
            expect( all[1] ).toEqual( item2 );
        });

        it('#clear, removes only values associated with self', function() {
            var lsOther = tote('another'),
                key1 = 'one',
                key2 = 'two',
                value1 = 'First value',
                value2 = 'Second value';
            ls.set(key1, value1);
            ls.set(key2, value2);
            lsOther.set(key1, value1);
            lsOther.set(key2, value2);

            ls.clear();

            expect( ls.get(key1) ).toBeNull();
            expect( ls.get(key2) ).toBeNull();

            expect( lsOther.get(key1) ).toEqual( value1 );
            expect( lsOther.get(key2) ).toEqual( value2 );
        });
    });

    describe('handling different datatypes', function() {
        var ls;

        beforeEach(function() {
            ls = tote('mystrings');
        });

        afterEach(function() {
            ls.clear();
        });

        it('persists and retrieves simple string', function() {
            var key = 'simple',
                value = 'Simple String';

            ls.set(key, value);

            expect( ls.get(key) ).toEqual( value );
        });

        it('persists and retrieves string with crazy characters', function() {
            var key = 'complex',
                value = 'Some overly c\'omplex string/ with "quoted" and *strred* and & etc...';

            ls.set(key, value);

            expect( ls.get(key) ).toEqual( value );
        });
    });
});<|endoftext|>


<commit_before>const bf2142 = require('revive-stats.js').bf2142;
const p2str = require('./../lib/p2str');
const bot = require('./../bot');
/**
 * This method should return the response directly to the channel
 * @param {*string array} params
 * @param {*message} message
 */
async function command(params, message) {
    let nick = params[0];
    bf2142.getPlayers(nick).then(plist => {
        if (plist.length == 0) {
            message.channel.send("Player not found");
            return;
        }
        p2str(plist[0], "bf2142").then(pl => message.channel.send(pl).then(msg => {
            if (plist.length === 1) return;
            msg.react('▶').then(
                msg.react('◀')).then(
                msg.react('⏩')).then(
                msg.react('⏪'))
            bot.emit('addNav', { message: msg, exec: (p) => p2str(p, "bf2142"), arr: plist, index: 0 });
        }));
    }).catch(message.channel.send);
}
/**
 * description of the command
 */
const description = "shows bf2142 stats of the username provided";
/**
 * Define Exports
 */
module.exports = {
    execute: command,
    description: description
};
<commit_msg>better bf2142 error catching<commit_after>const bf2142 = require('revive-stats.js').bf2142;
const p2str = require('./../lib/p2str');
const bot = require('./../bot');
/**
 * This method should return the response directly to the channel
 * @param {*string array} params
 * @param {*message} message
 */
async function command(params, message) {
    let nick = params[0];
    try{
        const plist = await bf2142.getPlayers(nick);
        if (plist.length == 0) {
            message.channel.send("Player not found");
            return;
        }
        const pl = await p2str(plist[0], "bf2142")
        const msg = await message.channel.send(pl);
        if (plist.length === 1) return;
        await msg.react('⏪')
        await msg.react('◀')
        await msg.react('▶')
        await msg.react('⏩')
        bot.emit('addNav', { message: msg, exec: (p) => p2str(p, "bf2142"), arr: plist, index: 0 });
        }));
    }
    catch(e){
        message.reply("No such user found");
    }
}
/**
 * description of the command
 */
const description = "shows bf2142 stats of the username provided";
/**
 * Define Exports
 */
module.exports = {
    execute: command,
    description: description
};
<|endoftext|>


<commit_before>(function() {
	var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
	var FC = $.fullCalendar;

	DayTableMixinOverride = {
		// override "FC.DayTableMixin.computeColCnt" method to add rows with resource length
		computeColCnt: function() {
			return FC.DayTableMixin.computeColCnt.apply(this) * this.view.resources.length;
		},
		// override "FC.DayTableMixin.getCellDayIndex" method to reverse col index to day index
		getCellDayIndex: function(row, col) {
			return FC.DayTableMixin.getCellDayIndex.apply(this, [row, col]) + row * this.view.resources.length;
		},
		// override "FC.DayTableMixin.getColDayIndex" method to reverse col index to day index
		getColDayIndex: function(col) {
			var dayIndex = parseInt(col / this.view.resources.length);
			if (this.isRTL) {
				dayIndex = this.daysPerRow - 1 - dayIndex;
			}
			return dayIndex;
		},
		// override "FC.DayTableMixin.renderHeadTrHtml" method to inject resource title col into table header
		renderHeadTrHtml: function() {

			return '' +
				FC.DayTableMixin.renderHeadTrHtml.apply(this) +
				'
' +
					(this.isRTL ? '' : this.renderHeadIntroHtml()) +
					this.renderResourceHeadCellsHtml() +
					(this.isRTL ? this.renderHeadIntroHtml() : '') +
				'
';
		},
		// cell renderer for resource title header
		// this method mimics the FC.DayTableMixin.renderHeadDateCellsHtml, FC.DayTableMixin.renderHeadDateCellHtml
		renderResourceHeadCellsHtml: function() {
			var htmls = [];
			var col;

			for (var col = 0; col < this.colCnt; col += this.view.resources.length) {
				date = this.getCellDate(0, col);
				for (r = 0; r < this.view.resources.length; r++) {
					htmls.push(this.renderResourceHeadCellHtml(date, this.view.resources[r]));
				}
			}

			return htmls.join('');
		},
		renderResourceHeadCellHtml: function(date, resource, colspan, otherAttrs) {
			var view = this.view;

			return '' +
				' 1 ?
						' colspan="' + colspan + '"' :
						'') +
					(otherAttrs ?
						' ' + otherAttrs :
						'') +
				'>' +
					FC.htmlEscape(resource.title) +
				'	';
		},
		// override "FC.DayTableMixin.renderHeadDateCellsHtml" method to span date cell
		renderHeadDateCellsHtml: function() {
			var htmls = [];
			var col, date;

			for (var col = 0; col < this.colCnt; col += this.view.resources.length) {
				date = this.getCellDate(0, col);
				htmls.push(this.renderHeadDateCellHtml(date, this.view.resources.length));
			}

			return htmls.join('');
		},
		// override "FC.Grid.eventSpanToSegs" method to shift col of event
		eventSpanToSegs: function(span, event, segSliceFunc) {
			var segs = FC.Grid.prototype.eventSpanToSegs.apply(this, [span, event, segSliceFunc]);

			for (var i = 0; i < segs.length; i++) {
				var resourceCol = 0;
				var seg = segs[i];
				if (seg.event && seg.event.resourceId) {
					resourceCol = this.view.resourcesById[seg.event.resourceId].__index;
				}
				seg.col = seg.col * this.view.resources.length + resourceCol;
			}
			return segs;
		},
	};
	FC.ResourceTimeGrid = FC.TimeGrid.extend({});
	FC.ResourceTimeGrid.mixin(DayTableMixinOverride);
	FC.ResourceDayGrid = FC.DayGrid.extend({});
	FC.ResourceDayGrid.mixin(DayTableMixinOverride);
	FC.ResourceView = FC.AgendaView.extend({
		resources: [],
		resourcesById: {},
		timeGridClass: FC.ResourceTimeGrid,
		dayGridClass: FC.ResourceDayGrid,
		initialize: function() {
			FC.AgendaView.prototype.initialize.apply(this, arguments);

			this.resources = this.options.resources;
			this.resourcesById = {};
			for (var r = 0; r < this.resources.length; r++) {
				if (!this.resources[r].id) {
					this.resources[r].id = r;
				}
				this.resourcesById[this.resources[r].id] = this.resources[r];
				this.resourcesById[this.resources[r].id].__index = r;
			}
		},
	});
	FC.views.resource = {
		'class': FC.ResourceView,
		defaults: {
			allDaySlot: true,
			allDayText: 'all-day',
			slotDuration: '00:30:00',
			minTime: '00:00:00',
			maxTime: '24:00:00',
			slotEventOverlap: true
		}
	};
	FC.views.resourceDay = {
		'type': 'resource',
		duration: { days: 1 }
	};
	FC.views.resourceWeek = {
		'type': 'resource',
		duration: { week: 1 }
	};
})();
<commit_msg>Changed html generate method for resource row<commit_after>(function() {
	var dayIDs = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'];
	var FC = $.fullCalendar;

	DayTableMixinOverride = {
		// override "FC.DayTableMixin.computeColCnt" method to add rows with resource length
		computeColCnt: function() {
			return FC.DayTableMixin.computeColCnt.apply(this) * this.view.resources.length;
		},
		// override "FC.DayTableMixin.getCellDayIndex" method to reverse col index to day index
		getCellDayIndex: function(row, col) {
			return FC.DayTableMixin.getCellDayIndex.apply(this, [row, col]) + row * this.view.resources.length;
		},
		// override "FC.DayTableMixin.getColDayIndex" method to reverse col index to day index
		getColDayIndex: function(col) {
			var dayIndex = parseInt(col / this.view.resources.length);
			if (this.isRTL) {
				dayIndex = this.daysPerRow - 1 - dayIndex;
			}
			return dayIndex;
		},
		// override "FC.DayTableMixin.renderHeadTrHtml" method to inject resource title col into table header
		renderHeadTrHtml: function() {

			return '' +
				FC.DayTableMixin.renderHeadTrHtml.apply(this) +
				'
' +
					(this.isRTL ? '' : this.renderResourceHeadIntroHtml()) +
					this.renderResourceHeadCellsHtml() +
					(this.isRTL ? this.renderResourceHeadIntroHtml() : '') +
				'
';
		},
		// cell renderer for resource title header
		// this method mimics the basicDayGridMethods.renderIntroHtml, FC.DayTableMixin.renderHeadDateCellsHtml, FC.DayTableMixin.renderHeadDateCellHtml
		renderResourceHeadIntroHtml: function() {
			return '	';
		},
		renderResourceHeadCellsHtml: function() {
			var htmls = [];
			var col;

			for (var col = 0; col < this.colCnt; col += this.view.resources.length) {
				date = this.getCellDate(0, col);
				for (r = 0; r < this.view.resources.length; r++) {
					htmls.push(this.renderResourceHeadCellHtml(date, this.view.resources[r]));
				}
			}

			return htmls.join('');
		},
		renderResourceHeadCellHtml: function(date, resource, colspan, otherAttrs) {
			var view = this.view;

			return '' +
				' 1 ?
						' colspan="' + colspan + '"' :
						'') +
					(otherAttrs ?
						' ' + otherAttrs :
						'') +
				'>' +
					FC.htmlEscape(resource.title) +
				'	';
		},
		// override "FC.DayTableMixin.renderHeadDateCellsHtml" method to span date cell
		renderHeadDateCellsHtml: function() {
			var htmls = [];
			var col, date;

			for (var col = 0; col < this.colCnt; col += this.view.resources.length) {
				date = this.getCellDate(0, col);
				htmls.push(this.renderHeadDateCellHtml(date, this.view.resources.length));
			}

			return htmls.join('');
		},
		// override "FC.Grid.eventSpanToSegs" method to shift col of event
		eventSpanToSegs: function(span, event, segSliceFunc) {
			var segs = FC.Grid.prototype.eventSpanToSegs.apply(this, [span, event, segSliceFunc]);

			for (var i = 0; i < segs.length; i++) {
				var resourceCol = 0;
				var seg = segs[i];
				if (seg.event && seg.event.resourceId) {
					resourceCol = this.view.resourcesById[seg.event.resourceId].__index;
				}
				seg.col = seg.col * this.view.resources.length + resourceCol;
			}
			return segs;
		},
	};
	FC.ResourceTimeGrid = FC.TimeGrid.extend({});
	FC.ResourceTimeGrid.mixin(DayTableMixinOverride);
	FC.ResourceDayGrid = FC.DayGrid.extend({});
	FC.ResourceDayGrid.mixin(DayTableMixinOverride);
	FC.ResourceView = FC.AgendaView.extend({
		resources: [],
		resourcesById: {},
		timeGridClass: FC.ResourceTimeGrid,
		dayGridClass: FC.ResourceDayGrid,
		initialize: function() {
			FC.AgendaView.prototype.initialize.apply(this, arguments);

			this.resources = this.options.resources;
			this.resourcesById = {};
			for (var r = 0; r < this.resources.length; r++) {
				if (!this.resources[r].id) {
					this.resources[r].id = r;
				}
				this.resourcesById[this.resources[r].id] = this.resources[r];
				this.resourcesById[this.resources[r].id].__index = r;
			}
		},
	});
	FC.views.resource = {
		'class': FC.ResourceView,
		defaults: {
			allDaySlot: true,
			allDayText: 'all-day',
			slotDuration: '00:30:00',
			minTime: '00:00:00',
			maxTime: '24:00:00',
			slotEventOverlap: true
		}
	};
	FC.views.resourceDay = {
		'type': 'resource',
		duration: { days: 1 }
	};
	FC.views.resourceWeek = {
		'type': 'resource',
		duration: { week: 1 }
	};
})();
<|endoftext|>


<commit_before>module.exports = {
    "plugins": [
        "flowtype",
    ],
    "rules": {
        // Enforces a particular style for boolean type annotations.
        // This rule takes one argument.
        "flowtype/boolean-style": [ "error", "boolean" ],

        // Marks Flow type identifiers as defined.
        // Used to suppress no-undef reporting of type identifiers.
        "flowtype/define-flow-type": "warn",

        // Enforces consistent use of trailing commas in Object and Tuple
        // annotations.
        // Same as eslint "comma-dangle".
        "flowtype/delimiter-dangle": [ "error", "always-multiline" ],

        // Enforces consistent spacing within generic type annotation
        // parameters.
        "flowtype/generic-spacing": [ "error", "always" ],

        // Checks for duplicate properties in Object annotations.
        // Same as eslint "no-dupe-keys".
        "flowtype/no-dupe-keys": "error",

        // Disallows use of primitive constructors as types, such as Boolean,
        // Number and String.
        "flowtype/no-primitive-constructor-types": "error",

        // Disallows Flow type imports, aliases, and annotations in files
        // missing a valid Flow file declaration (or a @noflow annotation).
        "flowtype/no-types-missing-file-annotation": "error",

        // Warns against weak type annotations any, Object and Function. These
        // types can cause flow to silently skip over portions of your code,
        // which would have otherwise caused type errors.
        "flowtype/no-weak-types": [ "error", {
            "Function": false,
            "Object": false,
            "any": true,
        } ],

        // Enforces consistent separators between properties in Flow object
        // types.
        "flowtype/object-type-delimiter": [ "error", "semicolon" ],

        // Requires that all function parameters have type annotations.
        "flowtype/require-parameter-type": [ "error", {
            "excludeArrowFunctions": false,
        } ],

        // Requires that functions have return type annotation.
        "flowtype/require-return-type": [ "error", "always", {
            "annotateUndefined": "never",
            "excludeArrowFunctions": false,
        } ],

        // This rule can optionally report missing or missed placed
        // annotations, common typos (e.g. // @floww), and enforce a
        // consistant annotation style.
        "flowtype/require-valid-file-annotation": [ "error", "always", {
            "annotationStyle": "line",
        } ],

        // Requires that all variable declarators have type annotations.
        "flowtype/require-variable-type": [ "error", {
            "excludeVariableMatch": "^_",
        } ],

        // Enforces consistent use of semicolons after type aliases.
        // Same as eslint "semi".
        "flowtype/semi": [ "error", "never" ],

        // Enforces sorting of Object annotations.
        // Same as eslint "sort-keys"
        "flowtype/sort-keys": [ "error", "asc", {
            "caseSensitive": true,
            "natural": true,
        } ],

        // Enforces consistent spacing after the type annotation colon.
        // Require a space after the type annotation colon (e.g. foo: BarType).
        "flowtype/space-after-type-colon": [ "error", "always", {
            "allowLineBreak": false,
        } ],

        // Enforces consistent spacing before the opening < of generic type
        // annotation parameters.
        "flowtype/space-before-generic-bracket": [ "error", "always" ],

        // Enforces consistent spacing before the type annotation colon.
        "flowtype/space-before-type-colon": [ "error", "never" ],

        // Enforces a consistent naming pattern for type aliases.
        "flowtype/type-id-match": [ "error", "^([A-Z][a-z0-9]+)+Type$" ],

        // Enforces consistent spacing around union and intersection type
        // separators (| and &).
        "flowtype/union-intersection-spacing": [ "error", "always" ],

        // Marks Flow type alias declarations as used.
        "flowtype/use-flow-type": "warn",

        //
        "flowtype/valid-syntax": "warn",
    },
    "settings": {
        "flowtype": {
            "onlyFilesWithFlowAnnotation": true,
        },
    },
}
<commit_msg>Changing flow `generic-spacing` to `never`<commit_after>module.exports = {
    "plugins": [
        "flowtype",
    ],
    "rules": {
        // Enforces a particular style for boolean type annotations.
        // This rule takes one argument.
        "flowtype/boolean-style": [ "error", "boolean" ],

        // Marks Flow type identifiers as defined.
        // Used to suppress no-undef reporting of type identifiers.
        "flowtype/define-flow-type": "warn",

        // Enforces consistent use of trailing commas in Object and Tuple
        // annotations.
        // Same as eslint "comma-dangle".
        "flowtype/delimiter-dangle": [ "error", "always-multiline" ],

        // Enforces consistent spacing within generic type annotation
        // parameters.
        "flowtype/generic-spacing": [ "error", "never" ],

        // Checks for duplicate properties in Object annotations.
        // Same as eslint "no-dupe-keys".
        "flowtype/no-dupe-keys": "error",

        // Disallows use of primitive constructors as types, such as Boolean,
        // Number and String.
        "flowtype/no-primitive-constructor-types": "error",

        // Disallows Flow type imports, aliases, and annotations in files
        // missing a valid Flow file declaration (or a @noflow annotation).
        "flowtype/no-types-missing-file-annotation": "error",

        // Warns against weak type annotations any, Object and Function. These
        // types can cause flow to silently skip over portions of your code,
        // which would have otherwise caused type errors.
        "flowtype/no-weak-types": [ "error", {
            "Function": false,
            "Object": false,
            "any": true,
        } ],

        // Enforces consistent separators between properties in Flow object
        // types.
        "flowtype/object-type-delimiter": [ "error", "semicolon" ],

        // Requires that all function parameters have type annotations.
        "flowtype/require-parameter-type": [ "error", {
            "excludeArrowFunctions": false,
        } ],

        // Requires that functions have return type annotation.
        "flowtype/require-return-type": [ "error", "always", {
            "annotateUndefined": "never",
            "excludeArrowFunctions": false,
        } ],

        // This rule can optionally report missing or missed placed
        // annotations, common typos (e.g. // @floww), and enforce a
        // consistant annotation style.
        "flowtype/require-valid-file-annotation": [ "error", "always", {
            "annotationStyle": "line",
        } ],

        // Requires that all variable declarators have type annotations.
        "flowtype/require-variable-type": [ "error", {
            "excludeVariableMatch": "^_",
        } ],

        // Enforces consistent use of semicolons after type aliases.
        // Same as eslint "semi".
        "flowtype/semi": [ "error", "never" ],

        // Enforces sorting of Object annotations.
        // Same as eslint "sort-keys"
        "flowtype/sort-keys": [ "error", "asc", {
            "caseSensitive": true,
            "natural": true,
        } ],

        // Enforces consistent spacing after the type annotation colon.
        // Require a space after the type annotation colon (e.g. foo: BarType).
        "flowtype/space-after-type-colon": [ "error", "always", {
            "allowLineBreak": false,
        } ],

        // Enforces consistent spacing before the opening < of generic type
        // annotation parameters.
        "flowtype/space-before-generic-bracket": [ "error", "always" ],

        // Enforces consistent spacing before the type annotation colon.
        "flowtype/space-before-type-colon": [ "error", "never" ],

        // Enforces a consistent naming pattern for type aliases.
        "flowtype/type-id-match": [ "error", "^([A-Z][a-z0-9]+)+Type$" ],

        // Enforces consistent spacing around union and intersection type
        // separators (| and &).
        "flowtype/union-intersection-spacing": [ "error", "always" ],

        // Marks Flow type alias declarations as used.
        "flowtype/use-flow-type": "warn",

        //
        "flowtype/valid-syntax": "warn",
    },
    "settings": {
        "flowtype": {
            "onlyFilesWithFlowAnnotation": true,
        },
    },
}
<|endoftext|>


<commit_before>(function() {
/**
 * PLUTO
 * Native HTML Template Rendering
 *
 *
 * The MIT License (MIT)
 * Copyright (c) 2013 Roi Avinoam
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
class Template extends HTMLTemplateElement {
    render(obj) {
        var compiled = this.compile()
        return new Renderer(compiled, compiled.items).render(obj)
    }

    compile() {
        var exprs = []
        var elements = [{ el: this.content, path: [] }]
        while (elements.length > 0) {
            var { el, path } = elements.shift()

            // inner content expressions
            if (el.nodeName === '#text') {
                var expr = isExpressions(el.textContent)
                if (expr) {
                    exprs.push({ expr, path })
                }
            }

            // attributes
            [].forEach.call(el.attributes || [], function(attr) {
                var expr = isExpressions(attr.value)
                if (expr !== null) {
                    attr = attr.name
                    var evName, prop
                    if (attr.startsWith('on-')) {
                        evName = attr.slice(3)
                    } else {
                        prop = snakeToCamelCase(attr)
                    }
                    exprs.push({ expr, path, attr, evName, prop })
                }
            }, this)

            // children, enqueue.
            el.childNodes.forEach(function(el, i) {
                maybeUpgrade(el)
                var subpath = path.concat(['childNodes', i])
                if (el instanceof Template) {
                    exprs.push({ path: subpath, tpl: true })
                    return
                }

                elements.push({ el, path: subpath })
            })
        }

        // remove attributes or expressions before rendering in order to hide
        // the placeholder expressions from the constructor of custom elements.
        var clone = this.cloneNode(true)
        exprs.forEach(function(expr) {
            var el = select(clone.content, expr.path)
            if (!expr.attr) {
                el.textContent = ''
            } else {
                el.removeAttribute(expr.attr)
            }
        }, this)

        var repeat = this.getAttribute('repeat') || this.getAttribute('for')
        if (repeat) {
            var fn = compileExpressions([{ expr: repeat }])
            clone.items = function(obj) {
                var items = fn(obj)[0] || []
                obj.__plutoElse = items.length > 0
                return items
            }
        }

        var cond = this.getAttribute('if')
        if (cond) {
            var fn = compileExpressions([{ expr: cond }])
            clone.items = (obj) => obj.__plutoElse = Boolean(fn(obj)[0])
        }

        var else_ = this.hasAttribute('else')
        if (else_) {
            clone.items = (obj) => obj.__plutoElse ? [] : [obj]
        }

        // we opt to compile the repeat/cond expressions separately than the
        // rest of this template - because (a) the template might relay on a
        // repeated ${item} property that doesn't yet exist in the repeat
        // expression, and (b) it's must smaller/faster than the complete
        // expressions list.
        // NB: It might not be that beneficial for cond though.
        clone.exprs = Object.assign(exprs, { eval: compileExpressions(exprs) })
        return clone
    }
}

class Renderer extends DocumentFragment {
    constructor(tpl, items) {
        super()
        this.tpl = tpl
        this.elements = []
        this.paths = {}
        this.exprs = tpl.exprs
        this.items = items

        if (items) {
            this.placeholder = document.createTextNode('')
            this.appendChild(this.placeholder)
        } else {
            this.appendChild(document.importNode(this.tpl.content, true))

            // copy the list of generated elements from the template in order
            // to support removals
            this.elements = [].map.call(this.childNodes, child => child)
        }
    }

    remove() {
        while (this.elements.length > 0) {
            this.elements.pop().remove()
        }
    }

    render(obj) {
        if (!this.items) {
            return this._renderOne(obj)
        }

        var items = this.items(obj)
        var item = obj.item
        if (!Array.isArray(items) && typeof items === 'object') {
            items = Object.keys(items).map(function(k) {
                return { key: k, value: items[k] }
            })
        }

        if (typeof items === 'boolean') {
            items = Number(items) // 0 or 1
        }

        if (typeof items === 'number') {
            items = new Array(items) // range-items, repeat N times.
            items = Array.from(items).map(() => item)
        }

        // remove obsolete items
        while (this.elements.length > items.length) {
            this.elements.pop().remove()
        }

        // update existing items
        for (var i = 0; i < this.elements.length; i += 1) {
            obj.item = items[i]
            this.elements[i].render(obj)
        }

        // create new items
        while (this.elements.length < items.length) {
            var i = this.elements.length
            obj.item = items[i]
            var doc = new Renderer(this.tpl).render(obj)
            this.elements.push(doc)
            this.placeholder.before(doc)
        }

        obj.item = item // restore previous item value.
        return this
    }

    _renderOne(obj) {
        var values = this.exprs.eval(obj)
        var subtpls = []
        for (var i = 0 ; i < this.exprs.length ; i += 1) {
            var expr = this.exprs[i]
            var v = values[i]
            var el = select(this, expr.path)

            // event handlers
            if (expr.evName) {
                var evs = el.__plutoEvs || (el.__plutoEvs = {})
                if (evs[expr.evName]) {
                    el.removeEventListener(expr.evName, evs[expr.evName])
                }

                if (typeof v === 'function') {
                    v = v._bound || v
                    el.addEventListener(expr.evName, v)
                    evs[expr.evName] = v
                }
            } else if (!expr.attr) {
                el.textContent = v || ''
            } else if (v === undefined) {
                el[expr.prop] = undefined
            } else {
                el[expr.prop] = v
                if (['class', 'style'].indexOf(expr.attr) !== -1) {
                    if (!v) {
                        el.removeAttribute(expr.attr)
                    } else {
                        el.setAttribute(expr.attr, v)
                    }
                }
            }

            // nested template
            if (expr.tpl) {
                subtpls.push(el)
            }
        }

        var else_ = obj.__plutoElse
        obj.__plutoElse = false
        for (var i = 0; i < subtpls.length; i += 1) {
            var el = subtpls[i]
            if (!el.render) {
                el.render = function(obj) {
                    delete el.render
                    var subdoc = pluto(this).render(obj)
                    this.replaceWith(subdoc)
                    this.render = subdoc.render.bind(subdoc)
                    this.remove = subdoc.remove.bind(subdoc)
                }
            }

            el.render(obj)
        }
        obj.__plutoElse = else_

        return this
    }
}

// -- HELPER FUNCTIONS

function maybeUpgrade(el) {
    // don't match #text, #comment, etc.
    if (el.nodeName[0] !== '#' && el.matches('template')) {
        pluto(el) // auto-upgrade nested templates.
    }
}

// Searches for an element from root based on the property-path to the child
// example: root = <body>, path = childNodes.3.childNode.7. Resolved by walking
// the path down to the child.
// NOTE that this function is memoized on the provided root object
function select(root, path) {
    var memo = root._plutoPaths || (root._plutoPaths = {})
    var pathKey = path.join('.')
    if (memo[pathKey]) {
        return memo[pathKey]
    }

    var el = root
    for (var i = 0; el !== undefined && i < path.length; i += 1) {
        el = el[path[i]]
    }

    return memo[pathKey] = el
}

const SNAKE_RE = /-([a-z])/g
function snakeToCamelCase(s) {
    return s.replace(SNAKE_RE, g => g[1].toUpperCase())
}

// extract expressions in template-literal syntax out of a string
var EXPR_RE = /\$\{[^\}]*\}/
function isExpressions(s) {
    return EXPR_RE.test(s) ? s : null
}

// compile a list of template-literal expressions into a function that evaluates
// these expression for the provided input object
function compileExpressions(exprs) {
    var refs = []
    var code = 'this.__plutoT || (this.__plutoT = T.bind(this));\n'
    code += exprs.map(function(expr, i) {
        if (expr.expr) {
            refs = refs.concat(getIdentifiers(expr.expr))
        }

        var tagFn = ({
            'class': 'classNameT',
            'style': 'styleT'
        })[expr.attr] || 'this.__plutoT'

        return `arguments[0][${i}] = ${tagFn}\`${expr.expr}\``
    }).join(';\n')

    var keys = refs.reduce((keys, k) => (keys[k] = true, keys), {})
    var locals = `var { ${Object.keys(keys)} } = this`
    var fn = eval('(function () {\n' + locals + '\n' + code + '\n})')
    return function(obj) {
        var res = []
        try {
            fn.call(obj, res)
        } catch (e) {
            console.warn(fn)
            throw e
        }

        return res
    }

    function T(s, v) {
        if (arguments.length > 2 || typeof v === 'string') {
            return String.raw.apply(null, arguments)
        }

        if (typeof v === 'function' && this[v.name] === v) {
            if (v._plutoBound !== this) {
                v._plutoBound = v.bind(this)
            }
            return v._plutoBound
        }

        return v
    }

    function classNameT(s, v) {
        if (typeof v === 'object') {
            if (!Array.isArray(v)) {
                v = Object.keys(v).filter((k) => v[k])
            }

            return v.join(' ')
        }

        return String.raw.apply(null, arguments)
    }

    function styleT(s, v) {
        if (typeof v === 'object') {
            return Object.keys(v).map((k) => k + ':' + v[k]).join('; ')
        }

        return String.raw.apply(null, arguments)
    }
}

// generate the list of identifiers found in the code.
function getIdentifiers(expr) {
    var re = /[$A-Z_][0-9A-Z_$]*/ig
    var whitespace = ' \n\r\t'
    var disallowed = '\'\".'
    var skip = ['true', 'false', 'if', 'for', 'while', 'do', 'try', 'catch',
        'break', 'continue', 'switch', 'throw', 'this', 'instanceof', 'in',
        'function', 'delete', 'default', 'case', 'debugger', 'const', 'var',
        'with', 'typeof', 'super', 'class', 'new', 'null', 'return', 'let',
        'import', 'else', 'enum', 'extends', 'finally', '$']

    // We first match for the valid identifier, and then check the previous
    // non-whitespace character preceeding the identifier to verify that it's
    // not a string or nested element.
    var refs = {}
    var match
    while (match = re.exec(expr)) {
        if (skip.indexOf(match[0]) !== -1) {
            continue // skipped or reserved keyword
        }

        if (window[match[0]] !== undefined) {
            continue // keep global functions (Object, Array, etc.)
        }

        var lastChar = undefined
        do {
            match.index -= 1
            if (whitespace.indexOf(expr[match.index]) === -1) {
                lastChar = expr[match.index]
            }
        } while (match.index > -1 && !lastChar)

        if (disallowed.indexOf(lastChar) === -1) {
            refs[match[0]] = true
        }
    }

    return Object.keys(refs)
}

// upgrade an element
// NOTE this will be unnecessary with customElements
function pluto(el) {
    if (typeof el === 'string') {
        // support HTML-imported selections
        var doc = document._currentScript // used by pollyfills
            || document.currentScript // native.
            || document // not an import.
        el = (doc.ownerDocument || doc).querySelector(el)
    }

    return !el || el instanceof Template
        ? el
        : Object.setPrototypeOf(el, Template.prototype)
}

pluto.Template = Template
pluto.RepeatRenderer = Renderer
window.pluto = pluto
})();

(function() {

    // placed here in order to have its own scope clear of any of the pluto
    // local variables.
    pluto._eval = function(code) {
        return eval(code)
    }
})();
<commit_msg>Support else-if in a single attribute<commit_after>(function() {
/**
 * PLUTO
 * Native HTML Template Rendering
 *
 *
 * The MIT License (MIT)
 * Copyright (c) 2013 Roi Avinoam
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
class Template extends HTMLTemplateElement {
    render(obj) {
        var compiled = this.compile()
        return new Renderer(compiled, compiled.items).render(obj)
    }

    compile() {
        var exprs = []
        var elements = [{ el: this.content, path: [] }]
        while (elements.length > 0) {
            var { el, path } = elements.shift()

            // inner content expressions
            if (el.nodeName === '#text') {
                var expr = isExpressions(el.textContent)
                if (expr) {
                    exprs.push({ expr, path })
                }
            }

            // attributes
            [].forEach.call(el.attributes || [], function(attr) {
                var expr = isExpressions(attr.value)
                if (expr !== null) {
                    attr = attr.name
                    var evName, prop
                    if (attr.startsWith('on-')) {
                        evName = attr.slice(3)
                    } else {
                        prop = snakeToCamelCase(attr)
                    }
                    exprs.push({ expr, path, attr, evName, prop })
                }
            }, this)

            // children, enqueue.
            el.childNodes.forEach(function(el, i) {
                maybeUpgrade(el)
                var subpath = path.concat(['childNodes', i])
                if (el instanceof Template) {
                    exprs.push({ path: subpath, tpl: true })
                    return
                }

                elements.push({ el, path: subpath })
            })
        }

        // remove attributes or expressions before rendering in order to hide
        // the placeholder expressions from the constructor of custom elements.
        var clone = this.cloneNode(true)
        exprs.forEach(function(expr) {
            var el = select(clone.content, expr.path)
            if (!expr.attr) {
                el.textContent = ''
            } else {
                el.removeAttribute(expr.attr)
            }
        }, this)

        var repeat = this.getAttribute('repeat') || this.getAttribute('for')
        if (repeat) {
            clone.items = function(fn, obj) {
                var items = fn(obj)[0] || []
                obj.__plutoElse = items.length > 0
                return items
            }.bind(clone, compileExpressions([{ expr: repeat }]))
        }

        var elseIf = this.getAttribute('else-if')
        var cond = this.getAttribute('if') || elseIf
        if (cond) {
            clone.items = function(fn, obj) {
                return obj.__plutoElse = Boolean(fn(obj)[0])
            }.bind(clone, compileExpressions([{ expr: cond }]))
        }

        var else_ = this.hasAttribute('else') || elseIf
        if (else_) {
            clone.items = function(fn, obj) {
                return obj.__plutoElse ? [] : fn(obj)
            }.bind(clone, clone.items || Array)
        }

        // we opt to compile the repeat/cond expressions separately than the
        // rest of this template - because (a) the template might relay on a
        // repeated ${item} property that doesn't yet exist in the repeat
        // expression, and (b) it's must smaller/faster than the complete
        // expressions list.
        // NB: It might not be that beneficial for cond though.
        clone.exprs = Object.assign(exprs, { eval: compileExpressions(exprs) })
        return clone
    }
}

class Renderer extends DocumentFragment {
    constructor(tpl, items) {
        super()
        this.tpl = tpl
        this.elements = []
        this.paths = {}
        this.exprs = tpl.exprs
        this.items = items

        if (items) {
            this.placeholder = document.createTextNode('')
            this.appendChild(this.placeholder)
        } else {
            this.appendChild(document.importNode(this.tpl.content, true))

            // copy the list of generated elements from the template in order
            // to support removals
            this.elements = [].map.call(this.childNodes, child => child)
        }
    }

    remove() {
        while (this.elements.length > 0) {
            this.elements.pop().remove()
        }
    }

    render(obj) {
        if (!this.items) {
            return this._renderOne(obj)
        }

        var items = this.items(obj)
        var item = obj.item
        if (!Array.isArray(items) && typeof items === 'object') {
            items = Object.keys(items).map(function(k) {
                return { key: k, value: items[k] }
            })
        }

        if (typeof items === 'boolean') {
            items = Number(items) // 0 or 1
        }

        if (typeof items === 'number') {
            items = new Array(items) // range-items, repeat N times.
            items = Array.from(items).map(() => item)
        }

        // remove obsolete items
        while (this.elements.length > items.length) {
            this.elements.pop().remove()
        }

        // update existing items
        for (var i = 0; i < this.elements.length; i += 1) {
            obj.item = items[i]
            this.elements[i].render(obj)
        }

        // create new items
        while (this.elements.length < items.length) {
            var i = this.elements.length
            obj.item = items[i]
            var doc = new Renderer(this.tpl).render(obj)
            this.elements.push(doc)
            this.placeholder.before(doc)
        }

        obj.item = item // restore previous item value.
        return this
    }

    _renderOne(obj) {
        var values = this.exprs.eval(obj)
        var subtpls = []
        for (var i = 0 ; i < this.exprs.length ; i += 1) {
            var expr = this.exprs[i]
            var v = values[i]
            var el = select(this, expr.path)

            // event handlers
            if (expr.evName) {
                var evs = el.__plutoEvs || (el.__plutoEvs = {})
                if (evs[expr.evName]) {
                    el.removeEventListener(expr.evName, evs[expr.evName])
                }

                if (typeof v === 'function') {
                    v = v._bound || v
                    el.addEventListener(expr.evName, v)
                    evs[expr.evName] = v
                }
            } else if (!expr.attr) {
                el.textContent = v || ''
            } else if (v === undefined) {
                el[expr.prop] = undefined
            } else {
                el[expr.prop] = v
                if (['class', 'style'].indexOf(expr.attr) !== -1) {
                    if (!v) {
                        el.removeAttribute(expr.attr)
                    } else {
                        el.setAttribute(expr.attr, v)
                    }
                }
            }

            // nested template
            if (expr.tpl) {
                subtpls.push(el)
            }
        }

        var else_ = obj.__plutoElse
        obj.__plutoElse = false
        for (var i = 0; i < subtpls.length; i += 1) {
            var el = subtpls[i]
            if (!el.render) {
                el.render = function(obj) {
                    delete el.render
                    var subdoc = pluto(this).render(obj)
                    this.replaceWith(subdoc)
                    this.render = subdoc.render.bind(subdoc)
                    this.remove = subdoc.remove.bind(subdoc)
                }
            }

            el.render(obj)
        }
        obj.__plutoElse = else_

        return this
    }
}

// -- HELPER FUNCTIONS

function maybeUpgrade(el) {
    // don't match #text, #comment, etc.
    if (el.nodeName[0] !== '#' && el.matches('template')) {
        pluto(el) // auto-upgrade nested templates.
    }
}

// Searches for an element from root based on the property-path to the child
// example: root = <body>, path = childNodes.3.childNode.7. Resolved by walking
// the path down to the child.
// NOTE that this function is memoized on the provided root object
function select(root, path) {
    var memo = root._plutoPaths || (root._plutoPaths = {})
    var pathKey = path.join('.')
    if (memo[pathKey]) {
        return memo[pathKey]
    }

    var el = root
    for (var i = 0; el !== undefined && i < path.length; i += 1) {
        el = el[path[i]]
    }

    return memo[pathKey] = el
}

const SNAKE_RE = /-([a-z])/g
function snakeToCamelCase(s) {
    return s.replace(SNAKE_RE, g => g[1].toUpperCase())
}

// extract expressions in template-literal syntax out of a string
var EXPR_RE = /\$\{[^\}]*\}/
function isExpressions(s) {
    return EXPR_RE.test(s) ? s : null
}

// compile a list of template-literal expressions into a function that evaluates
// these expression for the provided input object
function compileExpressions(exprs) {
    var refs = []
    var code = 'this.__plutoT || (this.__plutoT = T.bind(this));\n'
    code += exprs.map(function(expr, i) {
        if (expr.expr) {
            refs = refs.concat(getIdentifiers(expr.expr))
        }

        var tagFn = ({
            'class': 'classNameT',
            'style': 'styleT'
        })[expr.attr] || 'this.__plutoT'

        return `arguments[0][${i}] = ${tagFn}\`${expr.expr}\``
    }).join(';\n')

    var keys = refs.reduce((keys, k) => (keys[k] = true, keys), {})
    var locals = `var { ${Object.keys(keys)} } = this`
    var fn = eval('(function () {\n' + locals + '\n' + code + '\n})')
    return function(obj) {
        var res = []
        try {
            fn.call(obj, res)
        } catch (e) {
            console.warn(fn)
            throw e
        }

        return res
    }

    function T(s, v) {
        if (arguments.length > 2 || typeof v === 'string') {
            return String.raw.apply(null, arguments)
        }

        if (typeof v === 'function' && this[v.name] === v) {
            if (v._plutoBound !== this) {
                v._plutoBound = v.bind(this)
            }
            return v._plutoBound
        }

        return v
    }

    function classNameT(s, v) {
        if (typeof v === 'object') {
            if (!Array.isArray(v)) {
                v = Object.keys(v).filter((k) => v[k])
            }

            return v.join(' ')
        }

        return String.raw.apply(null, arguments)
    }

    function styleT(s, v) {
        if (typeof v === 'object') {
            return Object.keys(v).map((k) => k + ':' + v[k]).join('; ')
        }

        return String.raw.apply(null, arguments)
    }
}

// generate the list of identifiers found in the code.
function getIdentifiers(expr) {
    var re = /[$A-Z_][0-9A-Z_$]*/ig
    var whitespace = ' \n\r\t'
    var disallowed = '\'\".'
    var skip = ['true', 'false', 'if', 'for', 'while', 'do', 'try', 'catch',
        'break', 'continue', 'switch', 'throw', 'this', 'instanceof', 'in',
        'function', 'delete', 'default', 'case', 'debugger', 'const', 'var',
        'with', 'typeof', 'super', 'class', 'new', 'null', 'return', 'let',
        'import', 'else', 'enum', 'extends', 'finally', '$']

    // We first match for the valid identifier, and then check the previous
    // non-whitespace character preceeding the identifier to verify that it's
    // not a string or nested element.
    var refs = {}
    var match
    while (match = re.exec(expr)) {
        if (skip.indexOf(match[0]) !== -1) {
            continue // skipped or reserved keyword
        }

        if (window[match[0]] !== undefined) {
            continue // keep global functions (Object, Array, etc.)
        }

        var lastChar = undefined
        do {
            match.index -= 1
            if (whitespace.indexOf(expr[match.index]) === -1) {
                lastChar = expr[match.index]
            }
        } while (match.index > -1 && !lastChar)

        if (disallowed.indexOf(lastChar) === -1) {
            refs[match[0]] = true
        }
    }

    return Object.keys(refs)
}

// upgrade an element
// NOTE this will be unnecessary with customElements
function pluto(el) {
    if (typeof el === 'string') {
        // support HTML-imported selections
        var doc = document._currentScript // used by pollyfills
            || document.currentScript // native.
            || document // not an import.
        el = (doc.ownerDocument || doc).querySelector(el)
    }

    return !el || el instanceof Template
        ? el
        : Object.setPrototypeOf(el, Template.prototype)
}

pluto.Template = Template
pluto.RepeatRenderer = Renderer
window.pluto = pluto
})();

(function() {

    // placed here in order to have its own scope clear of any of the pluto
    // local variables.
    pluto._eval = function(code) {
        return eval(code)
    }
})();
<|endoftext|>


<commit_before>import { ViewComponent } from './ViewComponent';
import { InvalidArgumentError } from '../errors/InvalidArgumentError';
import mustache from 'mustache';

export class TemplateViewComponent extends ViewComponent {
	// routeUrl: The route url to which the component is bound
	// domContainerElement: The element that will be rendered into
	// templates: An object whose properties are template names and whose values are the content of the templates
	// localCSS: An object whose properties are CSS class names and whose values are the localized CSS class names
	//		The component will change the matching CSS class names in the templates.
	constructor(routeUrl, domContainerElement, templates, localCSS) {
		super(routeUrl, domContainerElement);
		this.templates = templates || {};

		if (templates && localCSS) {
			// localize the CSS class names in the templates
			for (const name in this.templates) {
				let content = this.templates[name];
				for (const oCN in localCSS) {
					const nCN = localCSS[oCN];
					content = content
						.replace(new RegExp(`class="${oCN}"`, 'gi'), `class="${nCN}"`)
						.replace(new RegExp(`class='${oCN}'`, 'gi'), `class='${nCN}'`);
				}
				this.templates[name] = content;
			}
		}
	}

	addTemplate(name, content) {
		this.templates[name] = content;
	}

	removeTemplate(name) {
		delete this.templates[name];
	}

	// Renders a named template
	// A template is a string that will be replaced using mustache.
	// For controls within the template, you should use: {{ControlClassName.ControlId}},
	//	e.g. {{MyControl.123}} => where the class is MyControl and the id is 123.
	renderTemplate(name, data) {
		let templateStr = this.templates[name];
		if (!templateStr) {
			throw new InvalidArgumentError(`No template was found with the name: "${name}"`);
		}

		if (this.controls) {
			const controlData = {};
			for (let controlId in this.controls) {
				const control = this.controls[controlId];
				controlData[control.constructor.name] = {};
				controlData[control.constructor.name][control.id] = control.render(data, this.lastEvent);
			}

			for (let key in controlData) {
				data[key] = controlData[key];
			}
		}

		return mustache.render(templateStr, data);
	}
};<commit_msg>Added code to clone the data before templating in the renderTemplate method of TemplateViewComponent to prevent store item pollution<commit_after>import { ViewComponent } from './ViewComponent';
import { InvalidArgumentError } from '../errors/InvalidArgumentError';
import mustache from 'mustache';

export class TemplateViewComponent extends ViewComponent {
	// routeUrl: The route url to which the component is bound
	// domContainerElement: The element that will be rendered into
	// templates: An object whose properties are template names and whose values are the content of the templates
	// localCSS: An object whose properties are CSS class names and whose values are the localized CSS class names
	//		The component will change the matching CSS class names in the templates.
	constructor(routeUrl, domContainerElement, templates, localCSS) {
		super(routeUrl, domContainerElement);
		this.templates = templates || {};

		if (templates && localCSS) {
			// localize the CSS class names in the templates
			for (const name in this.templates) {
				let content = this.templates[name];
				for (const oCN in localCSS) {
					const nCN = localCSS[oCN];
					content = content
						.replace(new RegExp(`class="${oCN}"`, 'gi'), `class="${nCN}"`)
						.replace(new RegExp(`class='${oCN}'`, 'gi'), `class='${nCN}'`);
				}
				this.templates[name] = content;
			}
		}
	}

	addTemplate(name, content) {
		this.templates[name] = content;
	}

	removeTemplate(name) {
		delete this.templates[name];
	}

	// Renders a named template
	// A template is a string that will be replaced using mustache.
	// For controls within the template, you should use: {{ControlClassName.ControlId}},
	//	e.g. {{MyControl.123}} => where the class is MyControl and the id is 123.
	renderTemplate(name, data) {
		let templateStr = this.templates[name];
		if (!templateStr) {
			throw new InvalidArgumentError(`No template was found with the name: "${name}"`);
		}

		// we clone the data to prevent pollution of the store item!!!
		let clonedData = {};
		for (let key in data) {
			clonedData[key] = data[key];
		}

		if (this.controls) {
			const controlData = {};
			for (let controlId in this.controls) {
				const control = this.controls[controlId];
				controlData[control.constructor.name] = {};
				controlData[control.constructor.name][control.id] = control.render(clonedData, this.lastEvent);
			}

			for (let key in controlData) {
				clonedData[key] = controlData[key];
			}
		}

		return mustache.render(templateStr, clonedData);
	}
};<|endoftext|>