<commit_before>$(document).ready(function() {
	// Update address bar when someone changes tabs
	$("a[data-toggle='tab']").on('shown.bs.tab', function(e) {
		// New target. Don't need jquery here...
		var newuri = updateQuery("tab", e.target.getAttribute('aria-controls'));
		window.history.replaceState(null, document.title, newuri);
	});

	// Grab del button clicks
	$("#attackersdiv").on("click", ".delbutton", function(e) {
		var t = $(e.target).data("ip");
		$.ajax({
			url: window.ajaxurl,
			data: { command: 'delattacker', module: 'firewall', target: t },
			success: function(data) {
				triggerPageUpdate();
			},
		});
	});
	triggerPageUpdate();
});

function triggerPageUpdate() {
	if (typeof window.updatetrigger !== "undefined") {
		window.clearTimeout(window.updatetrigger);
	}
	updateStatusPage();
	window.updatetrigger = window.setTimeout(function() { triggerPageUpdate(); }, 15000);
}

function updateQuery(key, value) {
	var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"), hash;
	var url = window.location.href;

	if (re.test(url)) {
		if (typeof value !== 'undefined' && value !== null) {
			return url.replace(re, '$1' + key + "=" + value + '$2$3');
		} else {
			hash = url.split('#');
			url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '');
			if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
				url += '#' + hash[1];
			}
			return url;
		}
	} else {
		if (typeof value !== 'undefined' && value !== null) {
			var separator = url.indexOf('?') !== -1 ? '&' : '?';
			hash = url.split('#');
			url = hash[0] + separator + key + '=' + value;
			if (typeof hash[1] !== 'undefined' && hash[1] !== null)
				url += '#' + hash[1];
			return url;
		} else {
			return url;
		}
	}
}

function updateStatusPage() {
	$(".notloading").hide();
	$(".loading").show();
	$.ajax({
		url: window.ajaxurl,
		data: { command: 'getattackers', module: 'firewall' },
		success: function(data) {
			$(".notloading").text("").show();
			$(".loading").hide();
			processStatusUpdate(data);
		},
	});
}

function processStatusUpdate(d) {
	// Summary page.
	$("#blocked").text(Object.keys(d.ATTACKER).length);
	$("#curblocked").text(d.summary.attackers.length);
	$("#rgd").text(d.summary.reged.length);
	$("#slowed").text(Object.keys(d.summary.clamped).length);
	$("#curslowed").text(d.summary.clamped.length);
	$("#totalremotes").text(d.summary.totalremotes);
	genRegHtml(d.summary.reged);
	genClampedHtml(d.summary.clamped);
	genBlockedHtml(d.summary.attackers, d);

	// Blocked only wants loading shown once.
	$(".onlyonce").removeClass("loading").removeClass("notloading");
}

function genRegHtml(registered) {
	if (registered.length == 0) {
		$("#noreged").show();
		return;
	}
	$("#noreged").hide();
	var h = "
";
	$.each(registered, function (i, v) {
		h += "
"+v+"
";
	});
	h += "
";
	$("#regul").html(h);
}

function genClampedHtml(clamped) {
	if (clamped.length == 0) {
		$("#noclamped").show();
		return;
	}
	$("#noclamped").hide();
	var h = "
";
	$.each(clamped, function (i, v) {
		h += "
"+v+"
";
	});
	h += "
";
	$("#clampeddiv").html(h);
}

function genBlockedHtml(attackers, d) {
	if (attackers.length == 0) {
		$("#noattackers").show();
		return;
	}
	$("#noattackers").hide();
	var h = "";
	$.each(attackers, function (i, v) {
		h += "

"+v+"

";
		h += "
Last 5 packets:
"+formatTimestamps(v, d)+"

";
		h += "
";
		h += "<button type='button' class='btn x-btn btn-danger delbutton' data-ip='"+v+"' title='Unblock'></button>"
		h += "

";
	});
	$("#attackersdiv").html(h);
}

function formatTimestamps(ip, data) {
	// data.summary.history.$ip contains a list of utimes.
	var resp = "";
	$.each(data.summary.history[ip], function(i, ut) {
		var d = new Date(ut.timestamp * 1000);
		resp += "
"+strDate(d)+" ("+ut.ago+"s ago)
\n";
	});
	return resp;
}

// This should probably override the Date object.. something like
// Date.prototype.getSaneDate = function () {
function strDate(d) {
	// Pad everything properly
	function pad(n){return n<10 ? '0'+n : n}
	var hh = pad(d.getHours());
	var mm = pad(d.getMinutes());
	var ss = pad(d.getSeconds());

	var dd = pad(d.getDate());
	var MM = pad(d.getMonth()+1); // Month is from 0-11, not 1-12.
	var yyyy = d.getFullYear();

	var ret = yyyy+"-"+MM+"-"+dd+" "+hh+":"+mm+":"+ss;
	return ret;
}
<commit_msg>FREEPBX-11310 - clear div when no limited hosts exist<commit_after>$(document).ready(function() {
	// Update address bar when someone changes tabs
	$("a[data-toggle='tab']").on('shown.bs.tab', function(e) {
		// New target. Don't need jquery here...
		var newuri = updateQuery("tab", e.target.getAttribute('aria-controls'));
		window.history.replaceState(null, document.title, newuri);
	});

	// Grab del button clicks
	$("#attackersdiv").on("click", ".delbutton", function(e) {
		var t = $(e.target).data("ip");
		$.ajax({
			url: window.ajaxurl,
			data: { command: 'delattacker', module: 'firewall', target: t },
			success: function(data) {
				triggerPageUpdate();
			},
		});
	});
	triggerPageUpdate();
});

function triggerPageUpdate() {
	if (typeof window.updatetrigger !== "undefined") {
		window.clearTimeout(window.updatetrigger);
	}
	updateStatusPage();
	window.updatetrigger = window.setTimeout(function() { triggerPageUpdate(); }, 15000);
}

function updateQuery(key, value) {
	var re = new RegExp("([?&])" + key + "=.*?(&|#|$)(.*)", "gi"), hash;
	var url = window.location.href;

	if (re.test(url)) {
		if (typeof value !== 'undefined' && value !== null) {
			return url.replace(re, '$1' + key + "=" + value + '$2$3');
		} else {
			hash = url.split('#');
			url = hash[0].replace(re, '$1$3').replace(/(&|\?)$/, '');
			if (typeof hash[1] !== 'undefined' && hash[1] !== null) {
				url += '#' + hash[1];
			}
			return url;
		}
	} else {
		if (typeof value !== 'undefined' && value !== null) {
			var separator = url.indexOf('?') !== -1 ? '&' : '?';
			hash = url.split('#');
			url = hash[0] + separator + key + '=' + value;
			if (typeof hash[1] !== 'undefined' && hash[1] !== null)
				url += '#' + hash[1];
			return url;
		} else {
			return url;
		}
	}
}

function updateStatusPage() {
	$(".notloading").hide();
	$(".loading").show();
	$.ajax({
		url: window.ajaxurl,
		data: { command: 'getattackers', module: 'firewall' },
		success: function(data) {
			$(".notloading").text("").show();
			$(".loading").hide();
			processStatusUpdate(data);
		},
	});
}

function processStatusUpdate(d) {
	// Summary page.
	$("#blocked").text(Object.keys(d.ATTACKER).length);
	$("#curblocked").text(d.summary.attackers.length);
	$("#rgd").text(d.summary.reged.length);
	$("#slowed").text(Object.keys(d.summary.clamped).length);
	$("#curslowed").text(d.summary.clamped.length);
	$("#totalremotes").text(d.summary.totalremotes);
	genRegHtml(d.summary.reged);
	genClampedHtml(d.summary.clamped);
	genBlockedHtml(d.summary.attackers, d);

	// Blocked only wants loading shown once.
	$(".onlyonce").removeClass("loading").removeClass("notloading");
}

function genRegHtml(registered) {
	if (registered.length == 0) {
		$("#noreged").show();
		return;
	}
	$("#noreged").hide();
	var h = "
";
	$.each(registered, function (i, v) {
		h += "
"+v+"
";
	});
	h += "
";
	$("#regul").html(h);
}

function genClampedHtml(clamped) {
	if (clamped.length == 0) {
		$("#noclamped").show();
		return;
	}
	$("#noclamped").hide();
	var h = "
";
	$.each(clamped, function (i, v) {
		h += "
"+v+"
";
	});
	h += "
";
	$("#clampeddiv").html(h);
}

function genBlockedHtml(attackers, d) {
	if (attackers.length == 0) {
		$("#attackersdiv").html('');
		$("#noattackers").show();
		return;
	}
	$("#noattackers").hide();
	var h = "";
	$.each(attackers, function (i, v) {
		h += "

"+v+"

";
		h += "
Last 5 packets:
"+formatTimestamps(v, d)+"

";
		h += "
";
		h += "<button type='button' class='btn x-btn btn-danger delbutton' data-ip='"+v+"' title='Unblock'></button>"
		h += "

";
	});
	$("#attackersdiv").html(h);
}

function formatTimestamps(ip, data) {
	// data.summary.history.$ip contains a list of utimes.
	var resp = "";
	$.each(data.summary.history[ip], function(i, ut) {
		var d = new Date(ut.timestamp * 1000);
		resp += "
"+strDate(d)+" ("+ut.ago+"s ago)
\n";
	});
	return resp;
}

// This should probably override the Date object.. something like
// Date.prototype.getSaneDate = function () {
function strDate(d) {
	// Pad everything properly
	function pad(n){return n<10 ? '0'+n : n}
	var hh = pad(d.getHours());
	var mm = pad(d.getMinutes());
	var ss = pad(d.getSeconds());

	var dd = pad(d.getDate());
	var MM = pad(d.getMonth()+1); // Month is from 0-11, not 1-12.
	var yyyy = d.getFullYear();

	var ret = yyyy+"-"+MM+"-"+dd+" "+hh+":"+mm+":"+ss;
	return ret;
}
<|endoftext|>


<commit_before>var $ = require('jquery');
var forOwn = require('lodash/object/forOwn');

window.Mojular = {
  Modules: {},
  Helpers: {},
  Events: $({}),

  init: function () {
    forOwn(this.Modules, function(module) {
      typeof module.init === 'function' && module.init()
    });

    // trigger initial render event
    this.Events.trigger('render');
  },

  // safe logging
  log: function (msg) {
    if (window && window.console) {
      window.console.log(msg);
    }
  },

  dir: function (obj) {
    if (window && window.console) {
      window.console.dir(obj);
    }
  }
};
<commit_msg>Avoid redefining global Mojular if it already exists<commit_after>var $ = require('jquery');
var forOwn = require('lodash/object/forOwn');

window.Mojular = window.Mojular || {
  Modules: {},
  Helpers: {},
  Events: $({}),

  init: function () {
    forOwn(this.Modules, function(module) {
      typeof module.init === 'function' && module.init()
    });

    // trigger initial render event
    this.Events.trigger('render');
  },

  // safe logging
  log: function (msg) {
    if (window && window.console) {
      window.console.log(msg);
    }
  },

  dir: function (obj) {
    if (window && window.console) {
      window.console.dir(obj);
    }
  }
};
<|endoftext|>


<commit_before>'use strict';

angular.module('flowsimUiApp')
  .factory('Profile', function(ETHERNET, fgConstraints) {

var TIPS = {};
var TESTS = {};

function Datapath(dp) {
  // Copy constructor
  if(dp && dp instanceof Datapath) {
    this.datapath_id   = dp.datapath_id;
    this.ip_reassembly = dp.ip_reassembly;
    this.n_buffers     = dp.n_buffers;

    this.mfc_desc   = dp.mfc_desc;
    this.hw_desc    = dp.hw_desc;
    this.sw_desc    = dp.sw_desc;
    this.serial_num = dp.serial_num;
    this.dp_desc    = dp.dp_desc;
  }
  // Default constructor
  else {
    this.datapath_id   = '01:23:45:67:89:ab'; // FIXME: bad default
    this.n_buffers     = 1024;
    this.ip_reassembly = true;

    // Descriptions
    this.mfr_description = '';
    this.hw_description  = '';
    this.sw_description  = '';
    this.serial_num      = '';
    this.dp_description  = '';
  }
}

Datapath.prototype.clone = function() {
  return new Datapath(this);
};

var DatapathUI = Datapath;
DatapathUI.prototype.toBase = Datapath.prototype.clone;

TIPS.datapath = {
  datapath_id: 'Unique id of the datapath',
  ip_reassembly: 'Datapath can reassemble IP fragments',
  n_buffers: 'Number of packets that can be buffered for controller',
  mfr_desc: '',
  hw_desc: '',
  serial_num: '',
  dp_desc: ''
};

TESTS.datapath = {
  datapath_id: function() { return true; },
  n_buffers:   fgConstraints.isUInt(0, 0xffff),
  mfr_desc:    function(v) { return !v || v.length <= 256 ; },
  hw_desc:     function(v) { return !v || v.length <= 256; },
  sw_desc:     function(v) { return !v || v.length <= 256; },
  serial_num:  function(v) { return !v || v.length <= 32; },
  dp_desc:     function(v) { return !v || v.length <= 256; }
};

function Port(p) {
  // Copy constructor
  if(p && p instanceof Port) {
    this.port_id = p.port_id;
    this.mac     = p.mac;
    this.name    = p.name;
    this.speed   = p.speed;
    this.mode    = p.mode;
    this.medium  = p.medium;
  } else {
    if(p && typeof p === 'number') {
      this.port_id = p;
    } else {
      this.port_id = 0
    }
    this.mac    = '00:00:00:00:00:00';
    this.name   = 'eth' + this.port_id;
    this.speed  = '1_gbps';
    this.mode   = 'full_duplex';
    this.medium = 'Copper';
  }
}

Port.prototype.clone = function() {
  return new Port(this);
};

var PortUI              = Port;
PortUI.prototype.toBase = Port.prototype.clone;

TIPS.port = {
  port_id: 'Ethernet port identifier',
  mac:     'MAC address used by port in spanning tree',
  name:    'display name of the port',
  speed:   'physical layer speed of port',
  mode:    'physical layer transmission mode',
  medium:  'physical layer medium of port'
};

TESTS.port = {
  mac: ETHERNET.isMac,
  name: function(v) { return /[a-zA-Z_][a-zA-Z_0-9]*/.test(v) }
};

var SPEEDS = [{
  label: '10 Mbps',
  value: '10_mbps'
}, {
  label: '100 Mbps',
  value: '100_mbps'
}, {
  label: '1 Gbps',
  value: '1_gbps'
}, {
  label: '10 Gbps',
  value: '10_gbps'
}, {
  label: '40 Gbps',
  value: '40_gbps'
}, {
  label: '100 Gbps',
  value: '100_gbps'
}, {
  label: '1 Tbps',
  value: '1_tbps'
}];

var MODES = [{
  label: 'Half Duplex',
  value: 'half_duplex'
}, {
  label: 'Full Duplex',
  value: 'full_duplex'
}];

var MEDIUMS = [
  'Copper',
  'Fiber'
];

function Ports(ports) {
  if(ports && ports instanceof Ports) {
    this.n_ports = ports.n_ports;
    this.ports = _.map(ports.ports, function(port) {
      return new Port(port);
    });
    this.vports = _.clone(ports.vports);
  } else {
    if(ports && typeof ports === 'number'){
      this.n_ports = ports;
    } else {
      this.n_ports = 24;
    }
    this.ports = _.map(_.range(this.n_ports), function(idx) {
      return new Port(idx);
    });
    this.vports = {
      port_stats: true,
      stp:        false,
      in_port:    true,
      table:      true,
      normal:     true,
      flood:      true,
      all:        true,
      controller: true,
      local:      true,
      any:        true,
      none:       true
    };
  }
}

Ports.prototype.clone = function() {
  return new Ports(this);
}

var PortsUI              = Ports;
PortsUI.prototype.toBase = Ports.prototype.clone;

PortsUI.prototype.rebuild = function() {
  var i;
  if(this.n_ports === this.ports.length) {
    return;
  } else if(this.n_ports < this.ports.length) {
    this.ports.splice(this.n_ports, this.ports.length-this.n_ports);
  } else {
    for(i=this.ports.length; i<this.n_ports; ++i) {
      this.ports.push(new Port(i));
    }
  }
};

function Meters(meters) {
  if(meters && meters instanceof Meters) {
  } else {
  }
}
Meters.prototype.clone = function() {
  return new Meters(this);
}

var MetersUI = Meters;
MetersUI.prototype.toBase = Meters.prototype.clone;

function Match(match) {
  if(match && match instanceof Match) {
  } else {
  }
}

TIPS.match = {
};
TESTS.match = {
};

function Instruction(ins) {
  if(ins && ins instanceof Instruction) {
  } else {
  }
}

TIPS.instruction = {
};
TESTS.instruction = {
};

function Miss(miss) {
  if(miss && miss instanceof Miss) {
  } else {
  }
}

TIPS.miss = {
};
TESTS.miss = {
};

function Table(table) {
  if(table && table instanceof Table) {
    this.table_id    = table.table_id;
    this.name        = table.name;
    this.max_entries = table.max_entries;
    this.table_stats = table.table_stats;
    this.flow_stats  = table.flow_stats;
    this.match       = new Match(table.match);
    this.instruction = new Insturction(table.insturction);
    this.miss        = new Miss(table.miss);
  } else {
    this.table_id    = table;
    this.name        = 'table' + this.table_id;
    this.max_entries = 256;
    this.table_stats = true;
    this.flow_stats  = true;
    this.match       = new Match();
    this.instruction = new Instruction();
    this.miss        = new Miss();
  }
}

TIPS.table = {
  table_id: 'Unique table identifier',
  name: 'Descriptive name for flow table type',
  max_entries: 'Maximum flows supported',
  table_stats: 'Ability of table to record lookup statistics',
  flow_stats: 'Ability of flow to record match statistics',
  flow_caps: 'Match, Instruction, and Actions to support'
};
TESTS.table = {
  name: function(n) { return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(n); },
  max_entries: fgConstraints.isUInt(0,0xffffffff)
};

function Tables(tables) {
  if(tables && tables instanceof Tables) {
    this.n_tables = tables.n_tables;
    this.tables = _.map(tables.tables, function(t) { return new Table(t); });
  } else {
    this.n_tables = 8;
    this.tables = _.map(_.range(this.n_tables), function(id) {
      return new Table(id);
    });
  }
}

Tables.prototype.rebuild = function() {
  var i;
  if(this.n_tables === this.tables.length) {
    return;
  } else if(this.n_tables < this.tables.length) {
    this.tables.splice(this.n_tables, this.tables.length-this.n_tables);
  } else {
    for(i=this.tables.length; i<this.n_tables; ++i) {
      this.tables.push(new Table(i));
    }
  }
};

TIPS.tables = {
  n_tables: 'Number of flow tables available'
};
TESTS.tables = {
  n_tables: fgConstraints.isUInt(0,0xff)
};

function Groups(groups) {
  if(groups && groups instanceof Groups) {
  } else {
  }
}

Groups.prototype.clone = function() {
  return new Groups(this);
}

var GroupsUI              = Groups;
GroupsUI.prototype.toBase = Groups.prototype.clone;

function Profile(p) {
  if(p && p instanceof Profile) {
    this.name     = p.name;
    this.datapath = new Datapath(p.datapath);
    this.ports    = new Ports(p.ports);
    this.meters   = new Meters(p.meters);
    this.tables   = new Tables(p.tables);
    this.groups   = new Groups(p.groups);
  } else if(p) {
    this.name = p;
    this.datapath = new Datapath();
    this.ports    = new Ports();
    this.meters   = new Meters();
    this.tables   = new Tables();
    this.groups   = new Groups();
  } else {
    throw 'Bad construction: Profile';
  }
}
Profile.prototype.clone = function() {
  return new Profile(this);
};

var ProfileUI = Profile;
ProfileUI.prototype.toBase = Profile.prototype.clone;

/**
 * @ngdoc service
 * @name flowsimUiApp.profile
 * @description
 * # profile
 * Service in the flowsimUiApp.
 */

    function create(name) {
      return new Profile(name);
    }

    function createUI(profile) {
      return new ProfileUI(profile);
    }

    function setVersion(profile, version) {
      console.log('version: '+version);
    }

    return {
      create: create,
      createUI: createUI,
      setVersion: setVersion,
      TIPS: TIPS,
      TESTS: TESTS,
      MEDIUMS: MEDIUMS,
      MODES: MODES,
      SPEEDS: SPEEDS
    };

});
<commit_msg>update<commit_after>'use strict';

angular.module('flowsimUiApp')
  .factory('Profile', function(ETHERNET, fgConstraints) {

var TIPS = {};
var TESTS = {};

function Datapath(dp) {
  // Copy constructor
  if(dp && dp instanceof Datapath) {
    this.datapath_id   = dp.datapath_id;
    this.ip_reassembly = dp.ip_reassembly;
    this.n_buffers     = dp.n_buffers;

    this.mfc_desc   = dp.mfc_desc;
    this.hw_desc    = dp.hw_desc;
    this.sw_desc    = dp.sw_desc;
    this.serial_num = dp.serial_num;
    this.dp_desc    = dp.dp_desc;
  }
  // Default constructor
  else {
    this.datapath_id   = '01:23:45:67:89:ab'; // FIXME: bad default
    this.n_buffers     = 1024;
    this.ip_reassembly = true;

    // Descriptions
    this.mfr_description = '';
    this.hw_description  = '';
    this.sw_description  = '';
    this.serial_num      = '';
    this.dp_description  = '';
  }
}

Datapath.prototype.clone = function() {
  return new Datapath(this);
};

var DatapathUI = Datapath;
DatapathUI.prototype.toBase = Datapath.prototype.clone;

TIPS.datapath = {
  datapath_id: 'Unique id of the datapath',
  ip_reassembly: 'Datapath can reassemble IP fragments',
  n_buffers: 'Number of packets that can be buffered for controller',
  mfr_desc: '',
  hw_desc: '',
  serial_num: '',
  dp_desc: ''
};

TESTS.datapath = {
  datapath_id: function() { return true; },
  n_buffers:   fgConstraints.isUInt(0, 0xffff),
  mfr_desc:    function(v) { return !v || v.length <= 256 ; },
  hw_desc:     function(v) { return !v || v.length <= 256; },
  sw_desc:     function(v) { return !v || v.length <= 256; },
  serial_num:  function(v) { return !v || v.length <= 32; },
  dp_desc:     function(v) { return !v || v.length <= 256; }
};

function Port(p) {
  // Copy constructor
  if(p && p instanceof Port) {
    this.port_id = p.port_id;
    this.mac     = p.mac;
    this.name    = p.name;
    this.speed   = p.speed;
    this.mode    = p.mode;
    this.medium  = p.medium;
  } else {
    if(p && typeof p === 'number') {
      this.port_id = p;
    } else {
      this.port_id = 0
    }
    this.mac    = '00:00:00:00:00:00';
    this.name   = 'eth' + this.port_id;
    this.speed  = '1_gbps';
    this.mode   = 'full_duplex';
    this.medium = 'Copper';
  }
}

Port.prototype.clone = function() {
  return new Port(this);
};

var PortUI              = Port;
PortUI.prototype.toBase = Port.prototype.clone;

TIPS.port = {
  port_id: 'Ethernet port identifier',
  mac:     'MAC address used by port in spanning tree',
  name:    'display name of the port',
  speed:   'physical layer speed of port',
  mode:    'physical layer transmission mode',
  medium:  'physical layer medium of port'
};

TESTS.port = {
  mac: ETHERNET.isMac,
  name: function(v) { return /[a-zA-Z_][a-zA-Z_0-9]*/.test(v) }
};

var SPEEDS = [{
  label: '10 Mbps',
  value: '10_mbps'
}, {
  label: '100 Mbps',
  value: '100_mbps'
}, {
  label: '1 Gbps',
  value: '1_gbps'
}, {
  label: '10 Gbps',
  value: '10_gbps'
}, {
  label: '40 Gbps',
  value: '40_gbps'
}, {
  label: '100 Gbps',
  value: '100_gbps'
}, {
  label: '1 Tbps',
  value: '1_tbps'
}];

var MODES = [{
  label: 'Half Duplex',
  value: 'half_duplex'
}, {
  label: 'Full Duplex',
  value: 'full_duplex'
}];

var MEDIUMS = [
  'Copper',
  'Fiber'
];

function Ports(ports) {
  if(ports && ports instanceof Ports) {
    this.n_ports = ports.n_ports;
    this.ports = _.map(ports.ports, function(port) {
      return new Port(port);
    });
    this.vports = _.clone(ports.vports);
  } else {
    if(ports && typeof ports === 'number'){
      this.n_ports = ports;
    } else {
      this.n_ports = 24;
    }
    this.ports = _.map(_.range(this.n_ports), function(idx) {
      return new Port(idx);
    });
    this.vports = {
      port_stats: true,
      stp:        false,
      in_port:    true,
      table:      true,
      normal:     true,
      flood:      true,
      all:        true,
      controller: true,
      local:      true,
      any:        true,
      none:       true
    };
  }
}

Ports.prototype.clone = function() {
  return new Ports(this);
}

var PortsUI              = Ports;
PortsUI.prototype.toBase = Ports.prototype.clone;

PortsUI.prototype.rebuild = function() {
  var i;
  if(this.n_ports === this.ports.length) {
    return;
  } else if(this.n_ports < this.ports.length) {
    this.ports.splice(this.n_ports, this.ports.length-this.n_ports);
  } else {
    for(i=this.ports.length; i<this.n_ports; ++i) {
      this.ports.push(new Port(i));
    }
  }
};

function Meters(meters) {
  if(meters && meters instanceof Meters) {
  } else {
  }
}
Meters.prototype.clone = function() {
  return new Meters(this);
}

var MetersUI = Meters;
MetersUI.prototype.toBase = Meters.prototype.clone;

function Match(match) {
  if(match && match instanceof Match) {
  } else {
  }
}

TIPS.match = {
};
TESTS.match = {
};

function Instruction(ins) {
  if(ins && ins instanceof Instruction) {
  } else {
  }
}

TIPS.instruction = {
};
TESTS.instruction = {
};

function Miss(miss) {
  if(miss && miss instanceof Miss) {
  } else {
  }
}

TIPS.miss = {
};
TESTS.miss = {
};

function Table(table) {
  if(table && table instanceof Table) {
    this.table_id    = table.table_id;
    this.name        = table.name;
    this.max_entries = table.max_entries;
    this.table_stats = table.table_stats;
    this.flow_stats  = table.flow_stats;
    this.match       = new Match(table.match);
    this.instruction = new Instruction(table.insturction);
    this.miss        = new Miss(table.miss);
  } else {
    this.table_id    = table;
    this.name        = 'table' + this.table_id;
    this.max_entries = 256;
    this.table_stats = true;
    this.flow_stats  = true;
    this.match       = new Match();
    this.instruction = new Instruction();
    this.miss        = new Miss();
  }
}

TIPS.table = {
  table_id: 'Unique table identifier',
  name: 'Descriptive name for flow table type',
  max_entries: 'Maximum flows supported',
  table_stats: 'Ability of table to record lookup statistics',
  flow_stats: 'Ability of flow to record match statistics',
  flow_caps: 'Match, Instruction, and Actions to support'
};
TESTS.table = {
  name: function(n) { return /^[a-zA-Z_][a-zA-Z0-9_]*$/.test(n); },
  max_entries: fgConstraints.isUInt(0,0xffffffff)
};

function Tables(tables) {
  if(tables && tables instanceof Tables) {
    this.n_tables = tables.n_tables;
    this.tables = _.map(tables.tables, function(t) { return new Table(t); });
  } else {
    this.n_tables = 8;
    this.tables = _.map(_.range(this.n_tables), function(id) {
      return new Table(id);
    });
  }
}

Tables.prototype.rebuild = function() {
  var i;
  if(this.n_tables === this.tables.length) {
    return;
  } else if(this.n_tables < this.tables.length) {
    this.tables.splice(this.n_tables, this.tables.length-this.n_tables);
  } else {
    for(i=this.tables.length; i<this.n_tables; ++i) {
      this.tables.push(new Table(i));
    }
  }
};

TIPS.tables = {
  n_tables: 'Number of flow tables available'
};
TESTS.tables = {
  n_tables: fgConstraints.isUInt(0,0xff)
};

function Groups(groups) {
  if(groups && groups instanceof Groups) {
  } else {
  }
}

Groups.prototype.clone = function() {
  return new Groups(this);
}

var GroupsUI              = Groups;
GroupsUI.prototype.toBase = Groups.prototype.clone;

function Profile(p) {
  if(p && p instanceof Profile) {
    this.name     = p.name;
    this.datapath = new Datapath(p.datapath);
    this.ports    = new Ports(p.ports);
    this.meters   = new Meters(p.meters);
    this.tables   = new Tables(p.tables);
    this.groups   = new Groups(p.groups);
  } else if(p) {
    this.name = p;
    this.datapath = new Datapath();
    this.ports    = new Ports();
    this.meters   = new Meters();
    this.tables   = new Tables();
    this.groups   = new Groups();
  } else {
    throw 'Bad construction: Profile';
  }
}
Profile.prototype.clone = function() {
  return new Profile(this);
};

var ProfileUI = Profile;
ProfileUI.prototype.toBase = Profile.prototype.clone;

/**
 * @ngdoc service
 * @name flowsimUiApp.profile
 * @description
 * # profile
 * Service in the flowsimUiApp.
 */

    function create(name) {
      return new Profile(name);
    }

    function createUI(profile) {
      return new ProfileUI(profile);
    }

    function setVersion(profile, version) {
      console.log('version: '+version);
    }

    return {
      create: create,
      createUI: createUI,
      setVersion: setVersion,
      TIPS: TIPS,
      TESTS: TESTS,
      MEDIUMS: MEDIUMS,
      MODES: MODES,
      SPEEDS: SPEEDS
    };

});
<|endoftext|>


<commit_before>/*
 * ************************************************************************
 * Copyright (c), 2013 Next Century Corporation. All Rights Reserved.
 *
 * This software code is the exclusive property of Next Century Corporation and is
 * protected by United States and International laws relating to the protection
 * of intellectual property.  Distribution of this software code by or to an
 * unauthorized party, or removal of any of these notices, is strictly
 * prohibited and punishable by law.
 *
 * UNLESS PROVIDED OTHERWISE IN A LICENSE AGREEMENT GOVERNING THE USE OF THIS
 * SOFTWARE, TO WHICH YOU ARE AN AUTHORIZED PARTY, THIS SOFTWARE CODE HAS BEEN
 * ACQUIRED BY YOU "AS IS" AND WITHOUT WARRANTY OF ANY KIND.  ANY USE BY YOU OF
 * THIS SOFTWARE CODE IS AT YOUR OWN RISK.  ALL WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE HEREBY EXPRESSLY
 * DISCLAIMED.
 *
 * PROPRIETARY AND CONFIDENTIAL TRADE SECRET MATERIAL NOT FOR DISCLOSURE OUTSIDE
 * OF NEXT CENTURY CORPORATION EXCEPT BY PRIOR WRITTEN PERMISSION AND WHEN
 * RECIPIENT IS UNDER OBLIGATION TO MAINTAIN SECRECY.
 */

$(function () {

    OWF.ready(function () {
        var timeline;
        OWF.relayFile = 'js/eventing/rpc_relay.uncompressed.html';
        neon.query.SERVER_URL = $("#neon-server").val();

        var COUNT_FIELD_NAME = 'Count';
        var clientId = OWF.getInstanceId();

        var messageHandler = new neon.eventing.MessageHandler({
            activeDatasetChanged: function (message) {
                neon.chartWidget.onActiveDatasetChanged(message, drawChart);
            },
            filtersChanged: onFiltersChanged

        });
        var eventPublisher = new neon.eventing.OWFEventPublisher(messageHandler);

        neon.toggle.createOptionsPanel("#options-panel");
        populateTimeGranularityDropdown();
        configureButtons();
        drawChart();
        restoreState();

        function configureButtons() {
            configureRedrawBoundsButton();
            configureResetFilterButton();
        }

        function getRedrawBoundsButton() {
            return $('#redraw-bounds');
        }

        function getResetFilterButton() {
            return $('#reset-filter');
        }

        function disableResetFilterButton() {
            getResetFilterButton().attr('disabled', 'disabled');
        }

        function configureRedrawBoundsButton() {
            getRedrawBoundsButton().click(function () {
                drawChart();
            });
        }

        function configureResetFilterButton() {
            // initially disabled until filter added
            disableResetFilterButton();
            getResetFilterButton().click(function () {
                //TODO: NEON-64 Once a callback is added, we can use the owfEventPublisher code.
                neon.query.removeFilter(neon.chartWidget.getFilterKey(), function(){
                    messageHandler.publishMessage(neon.eventing.Channels.FILTERS_CHANGED, {});
                    drawChart();
                });

            });
        }

        function onFiltersChanged(message) {
            if (message._source === messageHandler.id) {
                getResetFilterButton().removeAttr('disabled');
            }
            else{
                drawChart();
                disableResetFilterButton();
            }
        }

        /**
         * Redraws the chart based on the user selected attribtues
         * @method drawChart
         */
        function drawChart() {

            var xAttr = neon.chartWidget.getXAttribute();
            var yAttr = neon.chartWidget.getYAttribute();

            if (!xAttr) {
                doDrawChart({data: []});
                return;
            }

            var groupByHourClause = new neon.query.GroupByFunctionClause(neon.query.HOUR, xAttr, 'hour');
            var groupByDayClause = new neon.query.GroupByFunctionClause(neon.query.DAY, xAttr, 'day');
            var groupByMonthClause = new neon.query.GroupByFunctionClause(neon.query.MONTH, xAttr, 'month');
            var groupByYearClause = new neon.query.GroupByFunctionClause(neon.query.YEAR, xAttr, 'year');

            var query = new neon.query.Query()
                .selectFrom(neon.chartWidget.getDatabaseName(), neon.chartWidget.getTableName())
                .where(xAttr, '!=', null)
                .groupBy(groupByYearClause, groupByMonthClause, groupByDayClause, groupByHourClause);

            if (yAttr) {
                query.aggregate(neon.query.SUM, yAttr, yAttr);
            }
            else {
                query.aggregate(neon.query.COUNT, null, COUNT_FIELD_NAME);
            }
            var stateObject = buildStateObject(query);
            neon.query.executeQuery(query, doDrawChart);
            neon.query.saveState(clientId, stateObject);
        }

        function doDrawChart(data) {

            $('#chart').empty();

            var xAttr = neon.chartWidget.getXAttribute();
            var yAttr = neon.chartWidget.getYAttribute();

            if (!yAttr) {
                yAttr = COUNT_FIELD_NAME;
            }

            var dataByDate = data.data.map(function (el) {
                //month is 1-based
                var date = new Date(Date.UTC(el.year, el.month - 1, el.day, el.hour));
                var count = el[yAttr];
                var result = {};
                result[xAttr] = date;
                result[yAttr] = count;
                return result;
            });

            var granularity = $('#time-granularity option:selected').val();
            var opts = { "data": dataByDate, "x": xAttr, "y": yAttr,
                "interval": granularity, responsive: true};

            // TODO: We need this because we set a window listener which holds a reference to old timeline objects.
            // We should really only use one timeline object, but that will be fixed as part of NEON-294
            $(window).off("resize");
            timeline = new charts.Timeline('#chart', opts);
            configureFiltering(timeline, xAttr);
            timeline.draw();
        }

        function configureFiltering(timeline, xAttr) {
            timeline.onFilter(function (startDate, endDate) {
                var startFilterClause = neon.query.where(xAttr, '>=', startDate);
                var endFilterClause = neon.query.where(xAttr, '<', endDate);
                var filterClause = neon.query.and(startFilterClause, endFilterClause);
                var filter = new neon.query.Filter().selectFrom(neon.chartWidget.getDatabaseName(), neon.chartWidget.getTableName()).where(filterClause);

                eventPublisher.replaceFilter(neon.chartWidget.getFilterKey(), filter);
            });
        }

        function populateTimeGranularityDropdown() {

            neon.dropdown.populateAttributeDropdowns({fieldNames: charts.Timeline.GRANULARITIES_}, "time-granularity", drawChart);
        }

        function buildStateObject(query) {
            return {
                filterKey: neon.chartWidget.getFilterKey(),
                columns: neon.dropdown.getFieldNamesFromDropdown("x"),
                xValue: neon.chartWidget.getXAttribute(),
                yValue: neon.chartWidget.getYAttribute(),
                timeGranularity: $('#time-granularity').val(),
                query: query
            };
        }

        function restoreState() {
            neon.query.getSavedState(clientId, function (data) {
                neon.chartWidget.setFilterKey(data.filterKey);
                neon.chartWidget.setDatabaseName(data.filterKey.dataSet.databaseName);
                neon.chartWidget.setTableName(data.filterKey.dataSet.tableName);
                neon.dropdown.populateAttributeDropdowns(data.columns, ['x','y'], drawChart);
                $('#x option[value="' + data.xValue + '"]').prop('selected', true);
                $('#y option[value="' + data.yValue + '"]').prop('selected', true);
                $('#time-granularity option[value="' + data.timeGranularity + '"]').prop('selected', true);
                neon.query.executeQuery(data.query, doDrawChart);
            });
        }
    });

});<commit_msg>NEON-704, NEON-705 -- Make sure we can reset the time period.<commit_after>/*
 * ************************************************************************
 * Copyright (c), 2013 Next Century Corporation. All Rights Reserved.
 *
 * This software code is the exclusive property of Next Century Corporation and is
 * protected by United States and International laws relating to the protection
 * of intellectual property.  Distribution of this software code by or to an
 * unauthorized party, or removal of any of these notices, is strictly
 * prohibited and punishable by law.
 *
 * UNLESS PROVIDED OTHERWISE IN A LICENSE AGREEMENT GOVERNING THE USE OF THIS
 * SOFTWARE, TO WHICH YOU ARE AN AUTHORIZED PARTY, THIS SOFTWARE CODE HAS BEEN
 * ACQUIRED BY YOU "AS IS" AND WITHOUT WARRANTY OF ANY KIND.  ANY USE BY YOU OF
 * THIS SOFTWARE CODE IS AT YOUR OWN RISK.  ALL WARRANTIES OF ANY KIND, EITHER
 * EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE HEREBY EXPRESSLY
 * DISCLAIMED.
 *
 * PROPRIETARY AND CONFIDENTIAL TRADE SECRET MATERIAL NOT FOR DISCLOSURE OUTSIDE
 * OF NEXT CENTURY CORPORATION EXCEPT BY PRIOR WRITTEN PERMISSION AND WHEN
 * RECIPIENT IS UNDER OBLIGATION TO MAINTAIN SECRECY.
 */

$(function () {

    OWF.ready(function () {
        var timeline;
        OWF.relayFile = 'js/eventing/rpc_relay.uncompressed.html';
        neon.query.SERVER_URL = $("#neon-server").val();

        var COUNT_FIELD_NAME = 'Count';
        var clientId = OWF.getInstanceId();

        var messageHandler = new neon.eventing.MessageHandler({
            activeDatasetChanged: function (message) {
                neon.chartWidget.onActiveDatasetChanged(message, drawChart);
            },
            filtersChanged: onFiltersChanged

        });
        var eventPublisher = new neon.eventing.OWFEventPublisher(messageHandler);

        neon.toggle.createOptionsPanel("#options-panel");
        populateTimeGranularityDropdown();
        configureButtons();
        drawChart();
        restoreState();

        function configureButtons() {
            configureRedrawBoundsButton();
            configureResetFilterButton();
        }

        function getRedrawBoundsButton() {
            return $('#redraw-bounds');
        }

        function getResetFilterButton() {
            return $('#reset-filter');
        }

        function disableResetFilterButton() {
            getResetFilterButton().attr('disabled', 'disabled');
        }

        function configureRedrawBoundsButton() {
            getRedrawBoundsButton().click(function () {
                drawChart();
            });
        }

        function configureResetFilterButton() {
            // initially disabled until filter added
            disableResetFilterButton();
            getResetFilterButton().click(function () {
                //TODO: NEON-64 Once a callback is added, we can use the owfEventPublisher code.
                neon.query.removeFilter(neon.chartWidget.getFilterKey(), function(){
                    messageHandler.publishMessage(neon.eventing.Channels.FILTERS_CHANGED, {});
                    drawChart();
                });

            });
        }

        function onFiltersChanged(message) {
            if (message._source === messageHandler.id) {
                getResetFilterButton().removeAttr('disabled');
            }
            else{
                drawChart();
                disableResetFilterButton();
            }
        }

        /**
         * Redraws the chart based on the user selected attribtues
         * @method drawChart
         */
        function drawChart() {

            var xAttr = neon.chartWidget.getXAttribute();
            var yAttr = neon.chartWidget.getYAttribute();

            if (!xAttr) {
                doDrawChart({data: []});
                return;
            }

            var groupByHourClause = new neon.query.GroupByFunctionClause(neon.query.HOUR, xAttr, 'hour');
            var groupByDayClause = new neon.query.GroupByFunctionClause(neon.query.DAY, xAttr, 'day');
            var groupByMonthClause = new neon.query.GroupByFunctionClause(neon.query.MONTH, xAttr, 'month');
            var groupByYearClause = new neon.query.GroupByFunctionClause(neon.query.YEAR, xAttr, 'year');

            var query = new neon.query.Query()
                .selectFrom(neon.chartWidget.getDatabaseName(), neon.chartWidget.getTableName())
                .where(xAttr, '!=', null)
                .groupBy(groupByYearClause, groupByMonthClause, groupByDayClause, groupByHourClause);

            if (yAttr) {
                query.aggregate(neon.query.SUM, yAttr, yAttr);
            }
            else {
                query.aggregate(neon.query.COUNT, null, COUNT_FIELD_NAME);
            }
            var stateObject = buildStateObject(query);
            neon.query.executeQuery(query, doDrawChart);
            neon.query.saveState(clientId, stateObject);
        }

        function doDrawChart(data) {

            $('#chart').empty();

            var xAttr = neon.chartWidget.getXAttribute();
            var yAttr = neon.chartWidget.getYAttribute();

            if (!yAttr) {
                yAttr = COUNT_FIELD_NAME;
            }

            var dataByDate = data.data.map(function (el) {
                //month is 1-based
                var date = new Date(Date.UTC(el.year, el.month - 1, el.day, el.hour));
                var count = el[yAttr];
                var result = {};
                result[xAttr] = date;
                result[yAttr] = count;
                return result;
            });

            var granularity = $('#time-granularity option:selected').val();
            var opts = { "data": dataByDate, "x": xAttr, "y": yAttr,
                "interval": granularity, responsive: true};

            // TODO: We need this because we set a window listener which holds a reference to old timeline objects.
            // We should really only use one timeline object, but that will be fixed as part of NEON-294
            $(window).off("resize");
            timeline = new charts.Timeline('#chart', opts);
            configureFiltering(timeline, xAttr);
            timeline.draw();
        }

        function configureFiltering(timeline, xAttr) {
            timeline.onFilter(function (startDate, endDate) {
                var startFilterClause = neon.query.where(xAttr, '>=', startDate);
                var endFilterClause = neon.query.where(xAttr, '<', endDate);
                var filterClause = neon.query.and(startFilterClause, endFilterClause);
                var filter = new neon.query.Filter().selectFrom(neon.chartWidget.getDatabaseName(), neon.chartWidget.getTableName()).where(filterClause);

                eventPublisher.replaceFilter(neon.chartWidget.getFilterKey(), filter);
            });
        }

        function populateTimeGranularityDropdown() {

            neon.dropdown.populateAttributeDropdowns({fieldNames: charts.Timeline.GRANULARITIES_}, "time-granularity", drawChart);
        }

        function buildStateObject(query) {
            return {
                filterKey: neon.chartWidget.getFilterKey(),
                columns: neon.dropdown.getFieldNamesFromDropdown("x"),
                xValue: neon.chartWidget.getXAttribute(),
                yValue: neon.chartWidget.getYAttribute(),
                timeGranularity: $('#time-granularity').val(),
                query: query
            };
        }

        function restoreState() {
            neon.query.getSavedState(clientId, function (data) {
                neon.chartWidget.setFilterKey(data.filterKey);
                neon.chartWidget.setDatabaseName(data.filterKey.dataSet.databaseName);
                neon.chartWidget.setTableName(data.filterKey.dataSet.tableName);
                neon.dropdown.populateAttributeDropdowns(data.columns, ['x','y'], drawChart);
                $('#x option[value="' + data.xValue + '"]').prop('selected', true);
                $('#y option[value="' + data.yValue + '"]').prop('selected', true);
                $('#time-granularity option[value="' + data.timeGranularity + '"]').prop('selected', true);
                neon.query.executeQuery(data.query, doDrawChart);
                getResetFilterButton().removeAttr('disabled');
            });
        }
    });

});<|endoftext|>


<commit_before>/*
 * This file is part of the Spludo Framework.
 * Copyright (c) 2009-2010 DracoBlue, http://dracoblue.net/
 *
 * Licensed under the terms of MIT License. For the full copyright and license
 * information, please see the LICENSE file in the root folder.
 */

/**
 * @class The manager for all registered sessions.
 *
 * @extends Logging
 *
 * @since 0.1
 * @author DracoBlue
 */
SessionManager = function(options) {
    options = options || {};

    if (typeof options.cookie_path !== "undefined") {
        this.cookie_path = options.cookie_path;
    } else {
        this.cookie_path = '/';
    }

    if (typeof options.cookie_key !== "undefined") {
        this.cookie_key = options.cookie_key;
    } else {
        this.cookie_key = "s";
    }

    var engine = GLOBAL[options.engine || "MemoryStorage"];

    this.storage = new engine("session_manager", options.engine_options || {});
};

extend(true, SessionManager.prototype, Logging.prototype);

SessionManager.prototype.logging_prefix = 'SessionManager';

SessionManager.prototype.removeSession = function(session_id) {
    var self = this;
    return function(cb) {
        self.info("removeSession: " + session_id);
        self.storage.remove(session_id);
        cb();
    };
};

SessionManager.prototype.getSession = function(session_id) {
    var self = this;
    return function(cb) {
        var session = self.storage.get(session_id) || null;

        if (session === null) {
            cb(null);
        } else {
            cb(JSON.parse(session));
        }
    };
};

SessionManager.prototype.setSession = function(session_id, session) {
    var self = this;
    return function(cb) {
        self.storage.set(session_id, JSON.stringify(session));
        cb();
    };
};

SessionManager.prototype.createSession = function(session) {
    var self = this;
    return function(cb) {
        var session_id = null;

        /*
         * FIXME: This is an ugly solution. Guess what happens if we have lots
         * of session. We need some way better function here.
         */
        while (session_id === null) {
            session_id = new String(Math.floor(Math.random()*999999999));
            if (self.storage.has(session_id)) {
                session_id = null;
            }
        }

        self.storage.set(session_id, JSON.stringify(session));

        self.info("createSession: " + session_id);

        cb(session_id);
    };
};

SessionManager.prototype.initializeWebContextSession = function (context, request) {
    var self = this;
    var session_id = (context.cookies && context.cookies[this.cookie_key]) || null;

    return function(cb) {
        if (session_id) {
            self.getSession(session_id)(function(session) {
                if (session) {
                    context.session = session;
                    cb(session_id);
                } else {
                    /*
                     * Seems like that cookie is invalid by now. Let's remove the
                     * cookie.
                     */
                    ContextToolkit.removeCookie(context, self.cookie_key);
                    cb(null);
                }
            });
        } else {
            cb(null);
        }
    };
};

SessionManager.prototype.finishWebContextSession = function (session_id, context, request) {
    var self = this;
    return function(cb) {
        if (session_id !== context.session_id) {
            session_id = context.session_id;

            if (session_id === null) {
                ContextToolkit.removeCookie(context, self.cookie_key);
            } else {
                ContextToolkit.setCookie(context, self.cookie_key, session_id, 0, self.cookie_path);
            }
        }
        cb();
    };
};
<commit_msg>Using the async (memory) storage properly now.<commit_after>/*
 * This file is part of the Spludo Framework.
 * Copyright (c) 2009-2010 DracoBlue, http://dracoblue.net/
 *
 * Licensed under the terms of MIT License. For the full copyright and license
 * information, please see the LICENSE file in the root folder.
 */

/**
 * @class The manager for all registered sessions.
 *
 * @extends Logging
 *
 * @since 0.1
 * @author DracoBlue
 */
SessionManager = function(options) {
    options = options || {};

    if (typeof options.cookie_path !== "undefined") {
        this.cookie_path = options.cookie_path;
    } else {
        this.cookie_path = '/';
    }

    if (typeof options.cookie_key !== "undefined") {
        this.cookie_key = options.cookie_key;
    } else {
        this.cookie_key = "s";
    }

    var engine = GLOBAL[options.engine || "MemoryStorage"];

    this.storage = new engine("session_manager", options.engine_options || {});
};

extend(true, SessionManager.prototype, Logging.prototype);

SessionManager.prototype.logging_prefix = 'SessionManager';

SessionManager.prototype.removeSession = function(session_id) {
    var self = this;
    return function(cb) {
        self.info("removeSession: " + session_id);
        self.storage.remove(session_id)(function() {
            cb();
        });
    };
};

SessionManager.prototype.getSession = function(session_id) {
    var self = this;
    return function(cb) {
        self.storage.get(session_id)(function(session_data) {
            if (!session_data) {
                cb(null);
            } else {
                self.log('getSession found', session_data);
                cb(JSON.parse(session_data));
            }
        });
    };
};

SessionManager.prototype.setSession = function(session_id, session) {
    var self = this;
    return function(cb) {
        self.storage.set(session_id, JSON.stringify(session))(function() {
            cb();
        });
    };
};

SessionManager.prototype.createSession = function(session) {
    var self = this;
    return function(cb) {
        var withUniqueSessionHandler = function(session_id) {
            self.info("createSession: " + session_id);
            self.storage.set(session_id, JSON.stringify(session))(function() {
                cb(session_id);
            });
        };

        /*
         * FIXME: This is an ugly solution. Guess what happens if we have lots
         * of session. We need some way better function here.
         */
        var tryToFindAnUnusedSessionId = function() {
            var session_id = new String(Math.floor(Math.random()*999999999));
            self.storage.has(session_id)(function(is_in_use) {
                if (is_in_use) {
                    session_id = null;
                    tryToFindAnUnusedSessionId();
                } else {
                    withUniqueSessionHandler(session_id);
                }
            });

        };

        tryToFindAnUnusedSessionId();
    };
};

SessionManager.prototype.initializeWebContextSession = function (context, request) {
    var self = this;
    var session_id = (context.cookies && context.cookies[this.cookie_key]) || null;

    return function(cb) {
        if (session_id) {
            self.getSession(session_id)(function(session) {
                if (typeof session === 'undefined') {
                    /*
                     * Seems like that cookie is invalid by now. Let's remove the
                     * cookie.
                     */
                    ContextToolkit.removeCookie(context, self.cookie_key);
                    cb(null);
                } else {
                    context.session = session;
                    cb(session_id);
                }
            });
        } else {
            cb(null);
        }
    };
};

SessionManager.prototype.finishWebContextSession = function (session_id, context, request) {
    var self = this;
    return function(cb) {
        if (session_id !== context.session_id) {
            session_id = context.session_id;

            if (session_id === null) {
                ContextToolkit.removeCookie(context, self.cookie_key);
            } else {
                ContextToolkit.setCookie(context, self.cookie_key, session_id, 0, self.cookie_path);
            }
        }
        cb();
    };
};
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import { DropdownButton, Glyphicon } from 'react-bootstrap';
import { Link } from 'react-router';
import NomadLink from '../link';
import FormatTime from '../format/time';
import shortUUID from '../../helpers/uuid';
import { renderDesiredStatus, renderClientStatus } from '../../helpers/render/allocation';

const getAllocationNumberFromName = (allocationName) => {
    const match = /[\d+]/.exec(allocationName);
    return match[0];
};

const optionsGlyph = <Glyphicon glyph="option-vertical" />;

const jobHeaderColumn = display =>
    (display ? Job	 : null);

const jobColumn = (allocation, display) =>
    (display ? <NomadLink jobId={ allocation.JobID } short="true" />	 : null);

const clientHeaderColumn = display =>
    (display ? Client	 : null);

const clientColumn = (allocation, nodes, display) =>
    (display ? <NomadLink nodeId={ allocation.NodeID } nodeList={ nodes } short="true" />	 : null);

let nodeIdToNameCache = {};

class AllocationList extends Component {

    componentWillReceiveProps(nextProps) {
        if (nextProps.nodes !== this.props.nodes) {
            nodeIdToNameCache = {};
        }
    }

    findNodeNameById(nodeId) {
        if (nodeId in nodeIdToNameCache) {
            return nodeIdToNameCache[nodeId];
        }

        const r = Object.keys(this.props.nodes)
            .filter(node =>
                this.props.nodes[node].ID === nodeId
            );

        if (r.length !== 0) {
            nodeIdToNameCache[nodeId] = this.props.nodes[r].Name;
        } else {
            nodeIdToNameCache[nodeId] = nodeId;
        }

        return nodeIdToNameCache[nodeId];
    }

    filteredAllocations() {
        const query = this.props.location.query || {};
        let allocations = this.props.allocations;

        if ('status' in query) {
            allocations = allocations.filter(allocation => allocation.ClientStatus === query.status);
        }

        if ('client' in query) {
            allocations = allocations.filter(allocation => allocation.NodeID === query.client);
        }

        if ('job' in query) {
            allocations = allocations.filter(allocation => allocation.JobID === query.job);
        }

        return allocations;
    }

    clientStatusFilter() {
        const location = this.props.location;
        const query = this.props.location.query || {};

        let title = 'Client Status';
        if ('status' in query) {
            title = {title}: { query.status };
        }

        return (
          <DropdownButton title={ title } key="filter-client-status" id="filter-client-status">

<Link to={ location.pathname } query={{ ...query, status: undefined }}>- Any -</Link>

<Link to={ location.pathname } query={{ ...query, status: 'running' }}>Running</Link>

<Link to={ location.pathname } query={{ ...query, status: 'complete' }}>Complete</Link>

<Link to={ location.pathname } query={{ ...query, status: 'lost' }}>Lost</Link>

<Link to={ location.pathname } query={{ ...query, status: 'failed' }}>Failed</Link>

          </DropdownButton>
        );
    }

    jobIdFilter() {
        const location = this.props.location;
        const query = this.props.location.query || {};

        let title = 'Job';
        if ('job' in query) {
            title = {title}: { query.job };
        }

        const jobs = this.props.allocations
          .map((allocation) => {
              return allocation.JobID;
          })
          .filter((v, i, a) => {
              return a.indexOf(v) === i;
          })
          .map((job) => {
              return (

                  <Link to={ location.pathname } query={{ ...query, job }}>{ job }</Link>

              );
          });

        jobs.unshift(

<Link to={ location.pathname } query={{ ...query, job: undefined }}>- Any -</Link>

        );

        return (
          <DropdownButton title={ title } key="filter-job" id="filter-job">
            { jobs }
          </DropdownButton>
        );
    }

    clientFilter() {
        const location = this.props.location;
        const query = this.props.location.query || {};

        let title = 'Client';
        if ('client' in query) {
            title = {title}: { this.findNodeNameById(query.client) };
        }

        const clients = this.props.allocations
          .map((allocation) => {
              return allocation.NodeID;
          })
          .filter((v, i, a) => {
              return a.indexOf(v) === i;
          })
          .map((client) => {
              return (

                  <Link to={ location.pathname } query={{ ...query, client }}>{ this.findNodeNameById(client) }</Link>

              );
          });

        clients.unshift(

            <Link to={ location.pathname } query={{ ...query, client: undefined }}>- Any -</Link>

        );

        return (
          <DropdownButton title={ title } key="filter-client" id="filter-client">
            { clients }
          </DropdownButton>
        );
    }

    render() {
        const showJobColumn = this.props.showJobColumn;
        const showClientColumn = this.props.showClientColumn;
        const allocations = this.props.allocations;
        const nodes = this.props.nodes;
        const className = this.props.containerClassName;

        return (

              { this.clientFilter() }

              { this.clientStatusFilter() }

              { this.jobIdFilter() }

                    ID
                    { jobHeaderColumn(showJobColumn) }
                    Task Group
                    Status
                    { clientHeaderColumn(showClientColumn) }
                    Age

                  {this.filteredAllocations().map((allocation, index) => {
                      return (

                          { renderClientStatus(allocation) }
                          <NomadLink allocId={ allocation.ID } short="true" />
                          { jobColumn(allocation, showJobColumn, nodes) }

                            <NomadLink jobId={ allocation.JobID } taskGroupId={ allocation.TaskGroupId }>
                              { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) })
                            </NomadLink>

                          { renderDesiredStatus(allocation) }
                          { clientColumn(allocation, nodes, showClientColumn) }
                          <FormatTime time={ allocation.CreateTime } />

                            <NomadLink
                              className="btn btn-xs btn-info btn-simple"
                              allocId={ allocation.ID }
                              linkAppend="/files?path=/alloc/logs/"
                            >
                              <Glyphicon glyph="align-left" />
                            </NomadLink>

                            <DropdownButton
                              noCaret
                              pullRight
                              dropup={ index > allocations.length - 4 }
                              className="btn btn-xs btn-simple pull-right"
                              title={ optionsGlyph }
                              key={ allocation.Name }
                              id={ `actions-${allocation.Name}` }
                            >

                                <NomadLink role="menuitem" evalId={ allocation.EvalID }>
                                  Allocation { shortUUID(allocation.EvalID) }
                                </NomadLink>

                                <NomadLink role="menuitem" allocId={ allocation.ID } linkAppend="/files">
                                  Files
                                </NomadLink>

                                <NomadLink role="menuitem" allocId={ allocation.ID }>Task States</NomadLink>

                            </DropdownButton>

                      );
                  })}

);
    }
}

AllocationList.defaultProps = {
    allocations: [],
    nodes: [],
    location: {},

    showJobColumn: true,
    showClientColumn: true,

    containerClassName: '',
};

AllocationList.propTypes = {
    allocations: PropTypes.array.isRequired,
    nodes: PropTypes.array.isRequired,
    location: PropTypes.object.isRequired,

    showJobColumn: PropTypes.bool.isRequired,
    showClientColumn: PropTypes.bool.isRequired,

    containerClassName: PropTypes.string.isRequired,
};

export default AllocationList;
<commit_msg>even wider task group column<commit_after>import React, { Component, PropTypes } from 'react';
import { DropdownButton, Glyphicon } from 'react-bootstrap';
import { Link } from 'react-router';
import NomadLink from '../link';
import FormatTime from '../format/time';
import shortUUID from '../../helpers/uuid';
import { renderDesiredStatus, renderClientStatus } from '../../helpers/render/allocation';

const getAllocationNumberFromName = (allocationName) => {
    const match = /[\d+]/.exec(allocationName);
    return match[0];
};

const optionsGlyph = <Glyphicon glyph="option-vertical" />;

const jobHeaderColumn = display =>
    (display ? Job	 : null);

const jobColumn = (allocation, display) =>
    (display ? <NomadLink jobId={ allocation.JobID } short="true" />	 : null);

const clientHeaderColumn = display =>
    (display ? Client	 : null);

const clientColumn = (allocation, nodes, display) =>
    (display ? <NomadLink nodeId={ allocation.NodeID } nodeList={ nodes } short="true" />	 : null);

let nodeIdToNameCache = {};

class AllocationList extends Component {

    componentWillReceiveProps(nextProps) {
        if (nextProps.nodes !== this.props.nodes) {
            nodeIdToNameCache = {};
        }
    }

    findNodeNameById(nodeId) {
        if (nodeId in nodeIdToNameCache) {
            return nodeIdToNameCache[nodeId];
        }

        const r = Object.keys(this.props.nodes)
            .filter(node =>
                this.props.nodes[node].ID === nodeId
            );

        if (r.length !== 0) {
            nodeIdToNameCache[nodeId] = this.props.nodes[r].Name;
        } else {
            nodeIdToNameCache[nodeId] = nodeId;
        }

        return nodeIdToNameCache[nodeId];
    }

    filteredAllocations() {
        const query = this.props.location.query || {};
        let allocations = this.props.allocations;

        if ('status' in query) {
            allocations = allocations.filter(allocation => allocation.ClientStatus === query.status);
        }

        if ('client' in query) {
            allocations = allocations.filter(allocation => allocation.NodeID === query.client);
        }

        if ('job' in query) {
            allocations = allocations.filter(allocation => allocation.JobID === query.job);
        }

        return allocations;
    }

    clientStatusFilter() {
        const location = this.props.location;
        const query = this.props.location.query || {};

        let title = 'Client Status';
        if ('status' in query) {
            title = {title}: { query.status };
        }

        return (
          <DropdownButton title={ title } key="filter-client-status" id="filter-client-status">

<Link to={ location.pathname } query={{ ...query, status: undefined }}>- Any -</Link>

<Link to={ location.pathname } query={{ ...query, status: 'running' }}>Running</Link>

<Link to={ location.pathname } query={{ ...query, status: 'complete' }}>Complete</Link>

<Link to={ location.pathname } query={{ ...query, status: 'lost' }}>Lost</Link>

<Link to={ location.pathname } query={{ ...query, status: 'failed' }}>Failed</Link>

          </DropdownButton>
        );
    }

    jobIdFilter() {
        const location = this.props.location;
        const query = this.props.location.query || {};

        let title = 'Job';
        if ('job' in query) {
            title = {title}: { query.job };
        }

        const jobs = this.props.allocations
          .map((allocation) => {
              return allocation.JobID;
          })
          .filter((v, i, a) => {
              return a.indexOf(v) === i;
          })
          .map((job) => {
              return (

                  <Link to={ location.pathname } query={{ ...query, job }}>{ job }</Link>

              );
          });

        jobs.unshift(

<Link to={ location.pathname } query={{ ...query, job: undefined }}>- Any -</Link>

        );

        return (
          <DropdownButton title={ title } key="filter-job" id="filter-job">
            { jobs }
          </DropdownButton>
        );
    }

    clientFilter() {
        const location = this.props.location;
        const query = this.props.location.query || {};

        let title = 'Client';
        if ('client' in query) {
            title = {title}: { this.findNodeNameById(query.client) };
        }

        const clients = this.props.allocations
          .map((allocation) => {
              return allocation.NodeID;
          })
          .filter((v, i, a) => {
              return a.indexOf(v) === i;
          })
          .map((client) => {
              return (

                  <Link to={ location.pathname } query={{ ...query, client }}>{ this.findNodeNameById(client) }</Link>

              );
          });

        clients.unshift(

            <Link to={ location.pathname } query={{ ...query, client: undefined }}>- Any -</Link>

        );

        return (
          <DropdownButton title={ title } key="filter-client" id="filter-client">
            { clients }
          </DropdownButton>
        );
    }

    render() {
        const showJobColumn = this.props.showJobColumn;
        const showClientColumn = this.props.showClientColumn;
        const allocations = this.props.allocations;
        const nodes = this.props.nodes;
        const className = this.props.containerClassName;

        return (

              { this.clientFilter() }

              { this.clientStatusFilter() }

              { this.jobIdFilter() }

                    ID
                    { jobHeaderColumn(showJobColumn) }
                    Task Group
                    Status
                    { clientHeaderColumn(showClientColumn) }
                    Age
                    Actions

                  {this.filteredAllocations().map((allocation, index) => {
                      return (

                          { renderClientStatus(allocation) }
                          <NomadLink allocId={ allocation.ID } short="true" />
                          { jobColumn(allocation, showJobColumn, nodes) }

                            <NomadLink jobId={ allocation.JobID } taskGroupId={ allocation.TaskGroupId }>
                              { allocation.TaskGroup } (#{ getAllocationNumberFromName(allocation.Name) })
                            </NomadLink>

                          { renderDesiredStatus(allocation) }
                          { clientColumn(allocation, nodes, showClientColumn) }
                          <FormatTime time={ allocation.CreateTime } />

                            <NomadLink
                              className="btn btn-xs btn-info btn-simple"
                              allocId={ allocation.ID }
                              linkAppend="/files?path=/alloc/logs/"
                            >
                              <Glyphicon glyph="align-left" />
                            </NomadLink>

                            <DropdownButton
                              noCaret
                              pullRight
                              dropup={ index > allocations.length - 4 }
                              className="btn btn-xs btn-simple pull-right"
                              title={ optionsGlyph }
                              key={ allocation.Name }
                              id={ `actions-${allocation.Name}` }
                            >

                                <NomadLink role="menuitem" evalId={ allocation.EvalID }>
                                  Allocation { shortUUID(allocation.EvalID) }
                                </NomadLink>

                                <NomadLink role="menuitem" allocId={ allocation.ID } linkAppend="/files">
                                  Files
                                </NomadLink>

                                <NomadLink role="menuitem" allocId={ allocation.ID }>Task States</NomadLink>

                            </DropdownButton>

                      );
                  })}

);
    }
}

AllocationList.defaultProps = {
    allocations: [],
    nodes: [],
    location: {},

    showJobColumn: true,
    showClientColumn: true,

    containerClassName: '',
};

AllocationList.propTypes = {
    allocations: PropTypes.array.isRequired,
    nodes: PropTypes.array.isRequired,
    location: PropTypes.object.isRequired,

    showJobColumn: PropTypes.bool.isRequired,
    showClientColumn: PropTypes.bool.isRequired,

    containerClassName: PropTypes.string.isRequired,
};

export default AllocationList;
<|endoftext|>


<commit_before>import { PathService } from '../path';
import { View } from '../view/view';
import { Fastdom } from '../services/fastdom';
import { CellEditor } from '../edit/edit.cell.editor';

const MOUSE_LEFT_BUTTON = 1;

export class BodyCtrl extends View {
	constructor(model, view, table, bag) {
		super(model);

		this.view = view;
		this.bag = bag;
		this.table = table;
		this.rangeStartCell = null;
		this.allowBatch = false;
	}

	onScroll(e) {
		const scroll = this.model.scroll;

		const oldValue = scroll();
		const newValue = {};
		let hasChanges = false;
		if (oldValue.top !== e.scrollTop) {
			newValue.top = e.scrollTop;
			hasChanges = true;
		}

		if (oldValue.left !== e.scrollLeft) {
			newValue.left = e.scrollLeft;
			hasChanges = true;
		}

		if (hasChanges) {
			scroll(newValue, {
				source: 'body.core',
				behavior: 'core'
			});
		}
	}

	onWheel(e) {
		const model = this.model;
		if (model.edit().state === 'view') {
			const scroll = model.scroll;
			const table = this.table;
			const upper = 0;

			Fastdom.measure(() => {
				const lower = table.view.scrollHeight() - table.view.height();
				const top = Math.min(lower, Math.max(upper, scroll().top + e.deltaY));

				scroll({ top }, { source: 'body.core' });
			});
		}
	}

	onMouseDown(e) {
		if (e.which === MOUSE_LEFT_BUTTON) {
			const selectionState = this.selection;
			if (selectionState.area !== 'body') {
				return;
			}

			const pathFinder = new PathService(this.bag.body);
			const cell = pathFinder.cell(e.path);

			const editMode = this.model.edit().mode;
			if (selectionState.mode === 'range' || selectionState.mode === 'batch') {

				if (selectionState.mode === 'batch') {
					this.allowBatch = this.isAllowBatch(e, cell);
				}

				if (!editMode) {
					this.rangeStartCell = cell;
					if (this.rangeStartCell) {
						this.view.selection.selectRange(this.rangeStartCell, null, 'body');
					}
				}
			}
		}
	}

	onMouseMove(e) {
		const pathFinder = new PathService(this.bag.body);
		const row = pathFinder.row(e.path);
		const mode = this.selection.mode;

		if (row) {
			const index = row.index;
			const highlightRow = this.view.highlight.row;
			if (highlightRow.canExecute(index)) {
				this.model
					.highlight()
					.rows
					.filter(i => i !== index)
					.forEach(i => highlightRow.execute(i, false));

				highlightRow.execute(index, true);
			}
		}

		if (mode === 'range' || mode === 'batch') {
			const startCell = this.rangeStartCell;
			const endCell = pathFinder.cell(e.path);

			if (startCell && endCell) {
				this.navigate(endCell);
				this.view.selection.selectRange(startCell, endCell, 'body');

				if (mode === 'batch' && this.allowBatch) {
					const label = startCell.label;
					const value = startCell.value;
					const initialType = startCell.column.type;
					const columnIndices = this.model.columnList().index;
					const cells = [];

					this.selection.items.forEach(item => {
						const {row, column} = item;
						const key = column.key;
						const columnIndex = columnIndices.indexOf(key);
						const rowIndex = row.id;
						const cellView = this.table.body.cell(rowIndex, columnIndex).model();

						cells.push(cellView.model);
					});

					cells.forEach(cell => {
						const type = cell.column.type;

						if (initialType === type) {
							const cellEditor = new CellEditor(cell);
							cellEditor.label = label;
							cellEditor.value = value;
							cellEditor.commit();
						}
					});
				}
			}
		}
	}

	onMouseLeave() {
		const highlightRow = this.view.highlight.row;
		this.model
			.highlight()
			.rows
			.forEach(i => highlightRow.execute(i, false));
	}

	onMouseUp(e) {
		const mode = this.selection.mode;

		if (e.which === MOUSE_LEFT_BUTTON) {
			if (mode === 'range' || mode === 'batch') {
				this.rangeStartCell = null;
			}

			const pathFinder = new PathService(this.bag.body);
			const cell = pathFinder.cell(e.path);
			if (cell) {
				this.select(cell);
				this.navigate(cell);
				if (cell.column.editorOptions.trigger === 'click' && this.view.edit.cell.enter.canExecute(cell)) {
					this.view.edit.cell.enter.execute(cell);
				}
			}
		}
	}

	select(cell) {
		const selectionState = this.selection;
		const mode = selectionState.mode;
		const area = selectionState.area;

		if (cell.column.type !== 'select' &&
			(area !== 'body' || mode === 'range' || mode === 'batch')) {
			return;
		}

		const model = this.model;
		const editMode = model.edit().mode;
		switch (selectionState.unit) {
			case 'row': {
				if (cell.column.type === 'select' && cell.column.editorOptions.trigger === 'focus') {
					const focusState = model.focus();
					if (focusState.rowIndex !== cell.rowIndex || focusState.columnIndex !== cell.columnIndex) {
						this.view.selection.toggleRow.execute(cell.row, 'body');
					}
				} else if (!editMode && cell.column.class !== 'control') {
					this.view.selection.toggleRow.execute(cell.row, 'body');
				}
				break;
			}

			case 'column': {
				if (!editMode) {
					this.view.selection.toggleColumn.execute(cell.column, 'body');
				}
				break;
			}

			case 'mix': {
				if (cell.column.type === 'row-indicator') {
					this.view.selection.toggleCell.execute(cell, 'body');
				}
			}
		}
	}

	navigate(cell) {
		const focus = this.view.nav.focus;
		if (focus.canExecute(cell)) {
			focus.execute(cell);
		}
	}

	get selection() {
		return this.model.selection();
	}

	isAllowBatch(e, cell) {
		const tr = cell.element;
		const clientRect = tr.getBoundingClientRect();

		const rectX = clientRect.right;
		const rectY = clientRect.bottom;

		const clickX = e.clientX;
		const clickY = e.clientY;

		return (rectX - clickX < 15) && (rectY - clickY < 15);
	}
}
<commit_msg>moved code from mouseMove func to mouseUp<commit_after>import { PathService } from '../path';
import { View } from '../view/view';
import { Fastdom } from '../services/fastdom';
import { CellEditor } from '../edit/edit.cell.editor';

const MOUSE_LEFT_BUTTON = 1;

export class BodyCtrl extends View {
	constructor(model, view, table, bag) {
		super(model);

		this.view = view;
		this.bag = bag;
		this.table = table;
		this.rangeStartCell = null;
		this.allowBatch = false;
	}

	onScroll(e) {
		const scroll = this.model.scroll;

		const oldValue = scroll();
		const newValue = {};
		let hasChanges = false;
		if (oldValue.top !== e.scrollTop) {
			newValue.top = e.scrollTop;
			hasChanges = true;
		}

		if (oldValue.left !== e.scrollLeft) {
			newValue.left = e.scrollLeft;
			hasChanges = true;
		}

		if (hasChanges) {
			scroll(newValue, {
				source: 'body.core',
				behavior: 'core'
			});
		}
	}

	onWheel(e) {
		const model = this.model;
		if (model.edit().state === 'view') {
			const scroll = model.scroll;
			const table = this.table;
			const upper = 0;

			Fastdom.measure(() => {
				const lower = table.view.scrollHeight() - table.view.height();
				const top = Math.min(lower, Math.max(upper, scroll().top + e.deltaY));

				scroll({ top }, { source: 'body.core' });
			});
		}
	}

	onMouseDown(e) {
		if (e.which === MOUSE_LEFT_BUTTON) {
			const selectionState = this.selection;
			if (selectionState.area !== 'body') {
				return;
			}

			const pathFinder = new PathService(this.bag.body);
			const cell = pathFinder.cell(e.path);

			const editMode = this.model.edit().mode;
			if (selectionState.mode === 'range' || selectionState.mode === 'batch') {

				if (selectionState.mode === 'batch') {
					this.allowBatch = this.isAllowBatch(e, cell);
				}

				if (!editMode) {
					this.rangeStartCell = cell;
					if (this.rangeStartCell) {
						this.view.selection.selectRange(this.rangeStartCell, null, 'body');
					}
				}
			}
		}
	}

	onMouseMove(e) {
		const pathFinder = new PathService(this.bag.body);
		const row = pathFinder.row(e.path);
		const mode = this.selection.mode;

		if (row) {
			const index = row.index;
			const highlightRow = this.view.highlight.row;
			if (highlightRow.canExecute(index)) {
				this.model
					.highlight()
					.rows
					.filter(i => i !== index)
					.forEach(i => highlightRow.execute(i, false));

				highlightRow.execute(index, true);
			}
		}

		if (mode === 'range' || mode === 'batch') {
			const startCell = this.rangeStartCell;
			const endCell = pathFinder.cell(e.path);

			if (startCell && endCell) {
				this.navigate(endCell);
				this.view.selection.selectRange(startCell, endCell, 'body');
			}
		}
	}

	onMouseLeave() {
		const highlightRow = this.view.highlight.row;
		this.model
			.highlight()
			.rows
			.forEach(i => highlightRow.execute(i, false));
	}

	onMouseUp(e) {
		const mode = this.selection.mode;
		const startCell = this.rangeStartCell;

		if (mode === 'batch' && this.allowBatch) {
			const label = startCell.label;
			const value = startCell.value;
			const initialType = startCell.column.type;
			const columnIndices = this.model.columnList().index;
			const cells = [];

			this.selection.items.forEach(item => {
				const {row, column} = item;
				const key = column.key;
				const columnIndex = columnIndices.indexOf(key);
				const rowIndex = row.id;
				const cellView = this.table.body.cell(rowIndex, columnIndex).model();

				cells.push(cellView.model);
			});

			cells.forEach(cell => {
				const type = cell.column.type;

				if (initialType === type) {
					const cellEditor = new CellEditor(cell);
					cellEditor.label = label;
					cellEditor.value = value;
					cellEditor.commit();
				}
			});
		}

		if (e.which === MOUSE_LEFT_BUTTON) {
			if (mode === 'range' || mode === 'batch') {
				this.rangeStartCell = null;
			}

			const pathFinder = new PathService(this.bag.body);
			const cell = pathFinder.cell(e.path);
			if (cell) {
				this.select(cell);
				this.navigate(cell);
				if (cell.column.editorOptions.trigger === 'click' && this.view.edit.cell.enter.canExecute(cell)) {
					this.view.edit.cell.enter.execute(cell);
				}
			}
		}
	}

	select(cell) {
		const selectionState = this.selection;
		const mode = selectionState.mode;
		const area = selectionState.area;

		if (cell.column.type !== 'select' &&
			(area !== 'body' || mode === 'range' || mode === 'batch')) {
			return;
		}

		const model = this.model;
		const editMode = model.edit().mode;
		switch (selectionState.unit) {
			case 'row': {
				if (cell.column.type === 'select' && cell.column.editorOptions.trigger === 'focus') {
					const focusState = model.focus();
					if (focusState.rowIndex !== cell.rowIndex || focusState.columnIndex !== cell.columnIndex) {
						this.view.selection.toggleRow.execute(cell.row, 'body');
					}
				} else if (!editMode && cell.column.class !== 'control') {
					this.view.selection.toggleRow.execute(cell.row, 'body');
				}
				break;
			}

			case 'column': {
				if (!editMode) {
					this.view.selection.toggleColumn.execute(cell.column, 'body');
				}
				break;
			}

			case 'mix': {
				if (cell.column.type === 'row-indicator') {
					this.view.selection.toggleCell.execute(cell, 'body');
				}
			}
		}
	}

	navigate(cell) {
		const focus = this.view.nav.focus;
		if (focus.canExecute(cell)) {
			focus.execute(cell);
		}
	}

	get selection() {
		return this.model.selection();
	}

	isAllowBatch(e, cell) {
		const tr = cell.element;
		const clientRect = tr.getBoundingClientRect();

		const rectX = clientRect.right;
		const rectY = clientRect.bottom;

		const clickX = e.clientX;
		const clickY = e.clientY;

		return (rectX - clickX < 15) && (rectY - clickY < 15);
	}
}
<|endoftext|>


<commit_before>/**
 * Created by Umayr Shahid on 10/27/2015.
 */

'use strict';

var webpack = require('webpack');
var path = require('path');

var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  context: path.join(__dirname, '/app'),
  entry: {
    app: [
      'webpack/hot/dev-server',
      './src/app.module'
    ]
  },
  output: {
    path: path.join(__dirname, '/build'),
    filename: 'bundle.js',
    publicPath: '/'
  },
  module: {
    loaders: [
      {
        test: /\.scss$/,
        loader: 'style!css!sass?includePaths[]=' + path.resolve(__dirname, './node_modules')
      },
      {
        test: /\.js$/,
        loader: 'ng-annotate',
        exclude: /node_modules/
      },
      {
        test: /\.html$/,
        loader: 'html'
      },
      {
        test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'url?limit=10000&minetype=application/font-woff'
      },
      {
        test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'url?limit=10000&minetype=application/font-woff'
      },
      {
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'url?limit=10000&minetype=application/octet-stream'
      },
      {
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'file'
      },
      {
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'url?limit=10000&minetype=image/svg+xml'
      },
      {
        test: /\.(png|jpe?g|gif|woff)$/,
        loader: 'url-loader?limit=8192'
      }
    ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.ProvidePlugin({
      '_': 'lodash'
    }),
    // definePlugin takes raw strings and inserts them, so you can put strings of JS if you want.
    new webpack.DefinePlugin({
      __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true'))
    }),
    new HtmlWebpackPlugin({
      template: './index.html'
    })
  ]
};
<commit_msg>Remove author credits<commit_after>'use strict';

var webpack = require('webpack');
var path = require('path');

var HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  context: path.join(__dirname, '/app'),
  entry: {
    app: [
      'webpack/hot/dev-server',
      './src/app.module'
    ]
  },
  output: {
    path: path.join(__dirname, '/build'),
    filename: 'bundle.js',
    publicPath: '/'
  },
  module: {
    loaders: [
      {
        test: /\.scss$/,
        loader: 'style!css!sass?includePaths[]=' + path.resolve(__dirname, './node_modules')
      },
      {
        test: /\.js$/,
        loader: 'ng-annotate',
        exclude: /node_modules/
      },
      {
        test: /\.html$/,
        loader: 'html'
      },
      {
        test: /\.woff(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'url?limit=10000&minetype=application/font-woff'
      },
      {
        test: /\.woff2(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'url?limit=10000&minetype=application/font-woff'
      },
      {
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'url?limit=10000&minetype=application/octet-stream'
      },
      {
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'file'
      },
      {
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
        loader: 'url?limit=10000&minetype=image/svg+xml'
      },
      {
        test: /\.(png|jpe?g|gif|woff)$/,
        loader: 'url-loader?limit=8192'
      }
    ]
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.ProvidePlugin({
      '_': 'lodash'
    }),
    // definePlugin takes raw strings and inserts them, so you can put strings of JS if you want.
    new webpack.DefinePlugin({
      __DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'true'))
    }),
    new HtmlWebpackPlugin({
      template: './index.html'
    })
  ]
};
<|endoftext|>


<commit_before>'use strict';
const _ = require('lodash');
const path = require('path');
const process = require('process');
const logger = require('./log');

let copy = require('recursive-copy'); // eslint-disable-line prefer-const
let chokidar = require('chokidar'); // eslint-disable-line prefer-const

const asset_copier = () => {
  const transform_paths = directories => {
    //create array with all source keys minus our blacklist
    const dirs = {};
    const blackList = [
      'root',
      'patterns',
      'data',
      'meta',
      'annotations',
      'patternlabFiles',
    ];
    _.each(directories.source, (dir, key) => {
      if (blackList.includes(key)) {
        return;
      }

      if (!dirs.key) {
        dirs[key] = {};
      }
    });

    // loop through all source keys
    _.each(dirs, (dir, key) => {
      // add source key path
      dirs[key].source = directories.source[key];

      // add public key path
      dirs[key].public = directories.public[key];
    });
    return dirs;
  };

  const copyFile = (p, dest, options) => {
    copy(p, dest, options).on(copy.events.COPY_FILE_COMPLETE, () => {
      logger.debug(`Moved ${p} to ${dest}`);
      options.emitter.emit('patternlab-asset-change', {
        file: p,
        dest: dest,
      });
    });
  };

  const asset_copy = (assetDirectories, patternlab, options) => {
    //take our configured paths and sanitize best we can to only the assets
    const dirs = transform_paths(assetDirectories);

    //find out where we are
    const basePath = path.resolve(process.cwd());

    const copyOptions = {
      overwrite: true,
      emitter: patternlab.events,
      debug: patternlab.config.debug,
    };

    //loop through each directory asset object (source / public pairing)
    _.each(dirs, (dir, key) => {
      //if we want to watch files, do so, otherwise just copy each file
      if (options.watch) {
        logger.info(
          `Pattern Lab is watching ${path.resolve(
            basePath,
            dir.source
          )} for changes`
        );

        if (patternlab.watchers[key]) {
          patternlab.watchers[key].close();
        }

        const assetWatcher = chokidar.watch(
          path.resolve(basePath, dir.source),
          {
            ignored: /(^|[\/\\])\../,
            ignoreInitial: false,
            awaitWriteFinish: {
              stabilityThreshold: 200,
              pollInterval: 100,
            },
          }
        );

        //watch for changes and copy
        assetWatcher
          .on('addDir', p => {
            const destination = path.resolve(basePath, dir.public);
            copyFile(p, destination, copyOptions);
          })
          .on('add', p => {
            const destination = path.resolve(
              basePath,
              dir.public + '/' + path.basename(p)
            );
            copyFile(p, destination, copyOptions);
          })
          .on('change', p => {
            const destination = path.resolve(
              basePath,
              dir.public + '/' + path.basename(p)
            );
            copyFile(p, destination, copyOptions);
          });

        patternlab.watchers[key] = assetWatcher;
      } else {
        //just copy
        const destination = path.resolve(basePath, dir.public);
        copyFile(dir.source, destination, copyOptions);
      }
    });

    // copy the styleguide
    copyFile(
      assetDirectories.source.styleguide,
      assetDirectories.public.root,
      copyOptions
    );

    // copy the favicon
    copyFile(
      `${assetDirectories.source.root}/favicon.ico`,
      `${assetDirectories.public.root}/favicon.ico`,
      copyOptions
    );

    //we need to special case patterns/**/*.md|.json|.pattern-extensions as well as the global structures
    if (options.watch) {
      // watch global structures, such as _data/* and _meta/
      const globalSources = [
        assetDirectories.source.data,
        assetDirectories.source.meta,
      ];
      const globalPaths = globalSources.map(globalSource =>
        path.join(basePath, globalSource, '*')
      );

      _.each(globalPaths, globalPath => {
        logger.info(`Pattern Lab is watching ${globalPath} for changes`);

        if (patternlab.watchers[globalPath]) {
          patternlab.watchers[globalPath].close();
        }

        const globalWatcher = chokidar.watch(path.resolve(globalPath), {
          ignored: /(^|[\/\\])\../,
          ignoreInitial: true,
          awaitWriteFinish: {
            stabilityThreshold: 200,
            pollInterval: 100,
          },
        });

        //watch for changes and rebuild
        globalWatcher
          .on('addDir', p => {
            patternlab.events.emit('patternlab-global-change', {
              file: p,
            });
          })
          .on('add', p => {
            patternlab.events.emit('patternlab-global-change', {
              file: p,
            });
          })
          .on('change', p => {
            patternlab.events.emit('patternlab-global-change', {
              file: p,
            });
          });

        patternlab.watchers[globalPath] = globalWatcher;
      });

      // watch patterns
      const baseFileExtensions = ['.json', '.yml', '.yaml', '.md'];
      const patternWatches = baseFileExtensions
        .concat(patternlab.engines.getSupportedFileExtensions())
        .map(dotExtension =>
          path.join(
            basePath,
            assetDirectories.source.patterns,
            `/**/*${dotExtension}`
          )
        );
      _.each(patternWatches, patternWatchPath => {
        logger.info(`Pattern Lab is watching ${patternWatchPath} for changes`);

        const patternWatcher = chokidar.watch(path.resolve(patternWatchPath), {
          ignored: /(^|[\/\\])\../,
          ignoreInitial: true,
          awaitWriteFinish: {
            stabilityThreshold: 200,
            pollInterval: 100,
          },
        });

        //watch for changes and rebuild
        patternWatcher
          .on('addDir', p => {
            patternlab.events.emit('patternlab-pattern-change', {
              file: p,
            });
          })
          .on('add', p => {
            patternlab.events.emit('patternlab-pattern-change', {
              file: p,
            });
          })
          .on('change', p => {
            patternlab.events.emit('patternlab-pattern-change', {
              file: p,
            });
          });
      });
    }
  };

  return {
    copyAssets: (assetDirectories, patternlab, options) => {
      asset_copy(assetDirectories, patternlab, options);
    },
    transformConfigPaths: paths => {
      return transform_paths(paths);
    },
  };
};

module.exports = asset_copier;
<commit_msg>refactor(asset_copy): Be quieter about what files are watched<commit_after>'use strict';
const _ = require('lodash');
const path = require('path');
const process = require('process');
const logger = require('./log');

let copy = require('recursive-copy'); // eslint-disable-line prefer-const
let chokidar = require('chokidar'); // eslint-disable-line prefer-const

const asset_copier = () => {
  const transform_paths = directories => {
    //create array with all source keys minus our blacklist
    const dirs = {};
    const blackList = [
      'root',
      'patterns',
      'data',
      'meta',
      'annotations',
      'patternlabFiles',
    ];
    _.each(directories.source, (dir, key) => {
      if (blackList.includes(key)) {
        return;
      }

      if (!dirs.key) {
        dirs[key] = {};
      }
    });

    // loop through all source keys
    _.each(dirs, (dir, key) => {
      // add source key path
      dirs[key].source = directories.source[key];

      // add public key path
      dirs[key].public = directories.public[key];
    });
    return dirs;
  };

  const copyFile = (p, dest, options) => {
    copy(p, dest, options).on(copy.events.COPY_FILE_COMPLETE, () => {
      logger.debug(`Moved ${p} to ${dest}`);
      options.emitter.emit('patternlab-asset-change', {
        file: p,
        dest: dest,
      });
    });
  };

  const asset_copy = (assetDirectories, patternlab, options) => {
    //take our configured paths and sanitize best we can to only the assets
    const dirs = transform_paths(assetDirectories);

    //find out where we are
    const basePath = path.resolve(process.cwd());

    const copyOptions = {
      overwrite: true,
      emitter: patternlab.events,
      debug: patternlab.config.debug,
    };

    //loop through each directory asset object (source / public pairing)
    _.each(dirs, (dir, key) => {
      //if we want to watch files, do so, otherwise just copy each file
      if (options.watch) {
        logger.debug(
          `Pattern Lab is watching ${path.resolve(
            basePath,
            dir.source
          )} for changes`
        );

        if (patternlab.watchers[key]) {
          patternlab.watchers[key].close();
        }

        const assetWatcher = chokidar.watch(
          path.resolve(basePath, dir.source),
          {
            ignored: /(^|[\/\\])\../,
            ignoreInitial: false,
            awaitWriteFinish: {
              stabilityThreshold: 200,
              pollInterval: 100,
            },
          }
        );

        //watch for changes and copy
        assetWatcher
          .on('addDir', p => {
            const destination = path.resolve(basePath, dir.public);
            copyFile(p, destination, copyOptions);
          })
          .on('add', p => {
            const destination = path.resolve(
              basePath,
              dir.public + '/' + path.basename(p)
            );
            copyFile(p, destination, copyOptions);
          })
          .on('change', p => {
            const destination = path.resolve(
              basePath,
              dir.public + '/' + path.basename(p)
            );
            copyFile(p, destination, copyOptions);
          });

        patternlab.watchers[key] = assetWatcher;
      } else {
        //just copy
        const destination = path.resolve(basePath, dir.public);
        copyFile(dir.source, destination, copyOptions);
      }
    });

    // copy the styleguide
    copyFile(
      assetDirectories.source.styleguide,
      assetDirectories.public.root,
      copyOptions
    );

    // copy the favicon
    copyFile(
      `${assetDirectories.source.root}/favicon.ico`,
      `${assetDirectories.public.root}/favicon.ico`,
      copyOptions
    );

    //we need to special case patterns/**/*.md|.json|.pattern-extensions as well as the global structures
    if (options.watch) {
      // watch global structures, such as _data/* and _meta/
      const globalSources = [
        assetDirectories.source.data,
        assetDirectories.source.meta,
      ];
      const globalPaths = globalSources.map(globalSource =>
        path.join(basePath, globalSource, '*')
      );

      _.each(globalPaths, globalPath => {
        logger.debug(`Pattern Lab is watching ${globalPath} for changes`);

        if (patternlab.watchers[globalPath]) {
          patternlab.watchers[globalPath].close();
        }

        const globalWatcher = chokidar.watch(path.resolve(globalPath), {
          ignored: /(^|[\/\\])\../,
          ignoreInitial: true,
          awaitWriteFinish: {
            stabilityThreshold: 200,
            pollInterval: 100,
          },
        });

        //watch for changes and rebuild
        globalWatcher
          .on('addDir', p => {
            patternlab.events.emit('patternlab-global-change', {
              file: p,
            });
          })
          .on('add', p => {
            patternlab.events.emit('patternlab-global-change', {
              file: p,
            });
          })
          .on('change', p => {
            patternlab.events.emit('patternlab-global-change', {
              file: p,
            });
          });

        patternlab.watchers[globalPath] = globalWatcher;
      });

      // watch patterns
      const baseFileExtensions = ['.json', '.yml', '.yaml', '.md'];
      const patternWatches = baseFileExtensions
        .concat(patternlab.engines.getSupportedFileExtensions())
        .map(dotExtension =>
          path.join(
            basePath,
            assetDirectories.source.patterns,
            `/**/*${dotExtension}`
          )
        );
      _.each(patternWatches, patternWatchPath => {
        logger.debug(`Pattern Lab is watching ${patternWatchPath} for changes`);

        const patternWatcher = chokidar.watch(path.resolve(patternWatchPath), {
          ignored: /(^|[\/\\])\../,
          ignoreInitial: true,
          awaitWriteFinish: {
            stabilityThreshold: 200,
            pollInterval: 100,
          },
        });

        //watch for changes and rebuild
        patternWatcher
          .on('addDir', p => {
            patternlab.events.emit('patternlab-pattern-change', {
              file: p,
            });
          })
          .on('add', p => {
            patternlab.events.emit('patternlab-pattern-change', {
              file: p,
            });
          })
          .on('change', p => {
            patternlab.events.emit('patternlab-pattern-change', {
              file: p,
            });
          });
      });
    }
    logger.info(
      `Pattern Lab is watching for changes to files under ${
        assetDirectories.source.root
      }`
    );
  };

  return {
    copyAssets: (assetDirectories, patternlab, options) => {
      asset_copy(assetDirectories, patternlab, options);
    },
    transformConfigPaths: paths => {
      return transform_paths(paths);
    },
  };
};

module.exports = asset_copier;
<|endoftext|>


<commit_before>import websocket from '../../../../render/vue/modules/websocket/websocket';
describe('webSocket module', function() {
  afterEach(function(done) {
    // Cleanup
    websocket.close();
    done();
  });
  it('should have connection lifecycle constants defined on the instance', () => {
    expect(websocket.WebSocket('wss://echo.websocket.org').CONNECTING).to.be.equal(0);
  });
});
<commit_msg> * [html5] fix lint error in webSocket test code<commit_after>import websocket from '../../../../render/vue/modules/websocket/websocket'
describe('webSocket module', function () {
  afterEach(function (done) {
    // Cleanup
    websocket.close()
    done()
  })
  it('should have connection lifecycle constants defined on the instance', () => {
    expect(websocket.WebSocket('wss://echo.websocket.org').CONNECTING).to.be.equal(0)
  })
})
<|endoftext|>