<commit_before>(function($) {

	function Plot(elem, data, config, callback){

		var self = this,
			defaults = {
				width: 540, // width of canvas
				height: 300, // height of canvas
				style: "bar",
				barStyle: {
					hPadding: 2, // padding around
					barColor: "#FF9900"
				},
				lineStyle: {
					lineColor: "#FF9900"
				},
				grid: {
					draw: true
				}
			};

		self.config = $.extend({}, defaults, config);
		self.data = data;
		self.$el = $(elem);
		self.$canvas = self.$el.find("canvas.myPlot");
		self.$selectContainer = self.$el.find("div.mySelectContainer");
		self.$select = self.$el.find("div.mySelect");

		if(self.$canvas.length){
			self.clearCanvas();
		}else{
			self.createCanvas();
		}

		self.events();

		if(self.config.style === "bar"){
			self.drawBarGraph();
		}else if(self.config.style === "line"){
			self.drawLineGraph();
		}

		return this;

	}

	Plot.prototype.createCanvas = function(){
		var self = this;

		// create canvas element and range selector divs
		var canvas = $("<canvas>").addClass("myPlot"),
			selectContainer = $("<div>").addClass("mySelectContainer"),
			css = {
				position: "absolute",
				top: 0,
				left: 0,
				height: self.config.height,
				width: self.config.width
			}

		// create canvas and set dimensions
		canvas.attr({
			height: self.config.height,
			width: self.config.width
		}).css(css).appendTo(self.$el);
		self.$canvas = $("canvas.myPlot");

		selectContainer.attr({
			height: self.config.height,
			width: self.config.width,
			class: self.config.selectClass
		}).css(css).appendTo(self.$el);
		self.$selectContainer = $("div.mySelectContainer");

		self.$el.css({
			width: self.config.width,
			height: self.config.height,
			position: "relative"
		});

		self.context = self.$canvas[0].getContext("2d");
	}

	Plot.prototype.clearCanvas = function(){
		var self = this;

		self.context = self.$canvas[0].getContext("2d");
		self.context.clearRect(0,0,self.config.width,self.config.height);
	}

	Plot.prototype.drawBarGraph = function(){
		var self = this,
			heightUnits = 0,
			unitWidth, unitHeight;

		// get data max
		for(var i = 0; i < self.data.length; i++){
			if(self.data[i][1] > heightUnits){
				heightUnits = self.data[i][1];
			}
		}

		// set chart measurement units
		unitWidth = self.config.width / self.data.length;
		unitHeight = (self.config.height / (heightUnits + 1));

		for(var i = 0; i < self.data.length; i++){
			var dataPoint = self.data[i][1],
				nextPoint;

			if(typeof self.data[i+1] !== "undefined"){
				nextPoint = self.data[i+1][1];
			}

			var position = {
					height: dataPoint * unitHeight,
					width: Math.round(unitWidth - self.config.barStyle.hPadding),
					left: Math.round(unitWidth * i)
				}

			self.context.fillStyle = self.config.barStyle.barColor;

			if(dataPoint > 0){
				self.context.fillRect(
					position.left,
					self.config.height - position.height,
					position.width,
					position.height
				);
			}
		}

	}

	Plot.prototype.drawLineGraph = function(){
		var self = this,
			heightUnits = 0,
			unitWidth, unitHeight;

		// get data max
		for(var i = 0; i < self.data.length; i++){
			if(self.data[i][1] > heightUnits){
				heightUnits = self.data[i][1];
			}
		}

		// set chart measurement units
		unitWidth = self.config.width / self.data.length;
		unitHeight = (self.config.height / (heightUnits + 1));

		self.context.beginPath();

		for(var i = 0; i < self.data.length; i++){
			var dataPoint = self.data[i][1],
				nextPoint;

			if(typeof self.data[i+1] !== "undefined"){
				nextPoint = self.data[i+1][1];
			}

			var position = {
					top: self.config.height - (dataPoint * unitHeight),
					left: Math.round(unitWidth * i)
				},
				nextPosition = {
					top: self.config.height - (nextPoint * unitHeight),
					left: Math.round(unitWidth * (i + 1))
				}
			self.context.strokeStyle = self.config.lineStyle.lineColor;

			if(i == 0){
				self.context.moveTo(position.left, position.top);
			}

			//console.log(i,"drawing line from " + position.left + "," + position.top + " to " + nextPosition.left + "," + nextPosition.top);

			if(dataPoint > 0){
				self.context.lineTo(nextPosition.left, nextPosition.top);
			}
		}

		self.context.stroke();
	}

	Plot.prototype.events = function(){
		var self = this;

		// when selecting the range container, draw a box and send the range to the callback
		self.$selectContainer.mousedown(function(e){
			var css = {
					position: "absolute",
					top: 0,
					left: e.offsetX,
					height: $(this).height()
				};

			if(!self.$select){
				$("<div>").css(css).appendTo($(this));
				self.$select = $("div.mySelect");
			}else{
				$(this).find("div").css(css);
			}

			$(this).mousemove(function(e){
				console.log(e.offsetX, e.offsetY);

				var $el = $(this).find("div"),
					parentOffset = $(this).offset()	,
					offset = $el.offset();

				$el.css({
					width: e.offsetX-offset.left+parentOffset.left,
					background: "green",
					opacity: 0.2,
					border: "1px solid red"
				})
			})
		}).mouseup(function(e){
			console.log(e.offsetX, e.offsetY);
			$(this).unbind("mousemove");
		});

	}

	$.fn.myPlot = function(data, config, callback){
		new Plot(this, data, config, callback);
		return this;
	}

})(jQuery);<commit_msg>remove console.logs. oops.<commit_after>(function($) {

	function Plot(elem, data, config, callback){

		var self = this,
			defaults = {
				width: 540, // width of canvas
				height: 300, // height of canvas
				style: "bar",
				barStyle: {
					hPadding: 2, // padding around
					barColor: "#FF9900"
				},
				lineStyle: {
					lineColor: "#FF9900"
				},
				grid: {
					draw: true
				}
			};

		self.config = $.extend({}, defaults, config);
		self.data = data;
		self.$el = $(elem);
		self.$canvas = self.$el.find("canvas.myPlot");
		self.$selectContainer = self.$el.find("div.mySelectContainer");
		self.$select = self.$el.find("div.mySelect");

		if(self.$canvas.length){
			self.clearCanvas();
		}else{
			self.createCanvas();
		}

		self.events();

		if(self.config.style === "bar"){
			self.drawBarGraph();
		}else if(self.config.style === "line"){
			self.drawLineGraph();
		}

		return this;

	}

	Plot.prototype.createCanvas = function(){
		var self = this;

		// create canvas element and range selector divs
		var canvas = $("<canvas>").addClass("myPlot"),
			selectContainer = $("<div>").addClass("mySelectContainer"),
			css = {
				position: "absolute",
				top: 0,
				left: 0,
				height: self.config.height,
				width: self.config.width
			}

		// create canvas and set dimensions
		canvas.attr({
			height: self.config.height,
			width: self.config.width
		}).css(css).appendTo(self.$el);
		self.$canvas = $("canvas.myPlot");

		selectContainer.attr({
			height: self.config.height,
			width: self.config.width,
			class: self.config.selectClass
		}).css(css).appendTo(self.$el);
		self.$selectContainer = $("div.mySelectContainer");

		self.$el.css({
			width: self.config.width,
			height: self.config.height,
			position: "relative"
		});

		self.context = self.$canvas[0].getContext("2d");
	}

	Plot.prototype.clearCanvas = function(){
		var self = this;

		self.context = self.$canvas[0].getContext("2d");
		self.context.clearRect(0,0,self.config.width,self.config.height);
	}

	Plot.prototype.drawBarGraph = function(){
		var self = this,
			heightUnits = 0,
			unitWidth, unitHeight;

		// get data max
		for(var i = 0; i < self.data.length; i++){
			if(self.data[i][1] > heightUnits){
				heightUnits = self.data[i][1];
			}
		}

		// set chart measurement units
		unitWidth = self.config.width / self.data.length;
		unitHeight = (self.config.height / (heightUnits + 1));

		for(var i = 0; i < self.data.length; i++){
			var dataPoint = self.data[i][1],
				nextPoint;

			if(typeof self.data[i+1] !== "undefined"){
				nextPoint = self.data[i+1][1];
			}

			var position = {
					height: dataPoint * unitHeight,
					width: Math.round(unitWidth - self.config.barStyle.hPadding),
					left: Math.round(unitWidth * i)
				}

			self.context.fillStyle = self.config.barStyle.barColor;

			if(dataPoint > 0){
				self.context.fillRect(
					position.left,
					self.config.height - position.height,
					position.width,
					position.height
				);
			}
		}

	}

	Plot.prototype.drawLineGraph = function(){
		var self = this,
			heightUnits = 0,
			unitWidth, unitHeight;

		// get data max
		for(var i = 0; i < self.data.length; i++){
			if(self.data[i][1] > heightUnits){
				heightUnits = self.data[i][1];
			}
		}

		// set chart measurement units
		unitWidth = self.config.width / self.data.length;
		unitHeight = (self.config.height / (heightUnits + 1));

		self.context.beginPath();

		for(var i = 0; i < self.data.length; i++){
			var dataPoint = self.data[i][1],
				nextPoint;

			if(typeof self.data[i+1] !== "undefined"){
				nextPoint = self.data[i+1][1];
			}

			var position = {
					top: self.config.height - (dataPoint * unitHeight),
					left: Math.round(unitWidth * i)
				},
				nextPosition = {
					top: self.config.height - (nextPoint * unitHeight),
					left: Math.round(unitWidth * (i + 1))
				}
			self.context.strokeStyle = self.config.lineStyle.lineColor;

			if(i == 0){
				self.context.moveTo(position.left, position.top);
			}

			if(dataPoint > 0){
				self.context.lineTo(nextPosition.left, nextPosition.top);
			}
		}

		self.context.stroke();
	}

	Plot.prototype.events = function(){
		var self = this;

		// when selecting the range container, draw a box and send the range to the callback
		self.$selectContainer.mousedown(function(e){
			var css = {
					position: "absolute",
					top: 0,
					left: e.offsetX,
					height: $(this).height()
				};

			if(!self.$select){
				$("<div>").css(css).appendTo($(this));
				self.$select = $("div.mySelect");
			}else{
				$(this).find("div").css(css);
			}

			$(this).mousemove(function(e){

				var $el = $(this).find("div"),
					parentOffset = $(this).offset()	,
					offset = $el.offset();

				$el.css({
					width: e.offsetX-offset.left+parentOffset.left,
					background: "green",
					opacity: 0.2,
					border: "1px solid red"
				})
			})
		}).mouseup(function(e){
			$(this).unbind("mousemove");
		});

	}

	$.fn.myPlot = function(data, config, callback){
		new Plot(this, data, config, callback);
		return this;
	}

})(jQuery);<|endoftext|>


<commit_before>define(["./employees.js"], function (employees) {

    function OnStartup (bezl) {
        // Call setConfig which defines the handful of settings that you may wish to tweak
        bezl.functions['setConfig']();

        // Default the number of selected employees on the team grid to 0
        bezl.vars.employeesSelected = 0;

        // Initiate the queries to run up front
        employees.runQuery(bezl, 'Team');
        employees.runQuery(bezl, 'AllEmployees');
        employees.runQuery(bezl, 'OpenJobs');

        // Configure the team members jsGrid
        $("#jsGridTeam").jsGrid({
        width: "100%",
        height: "100%",
        heading: true,
        sorting: true,
        autoload: true,
        inserting: false,
        controller: {
            loadData: function() {
            return bezl.vars.team;
            }
        },
        fields: [
            { name: "display", title: "Name", type: "text", visible: true, width: 50, editing: false },
            { name: "clockedIn", title: "Clocked In", align: "center", width: 25,
            	itemTemplate: function(value, item) {
              	return $("<input>").attr("type", "checkbox")
                		.attr("checked", value || item.Checked)
                    .on("change", function() {
                    	item.Checked = $(this).is(":checked");
                    });
              }
            },
            { name: "currentActivity", title: "Current Activity", type: "text", visible: true, width: 50, editing: false }
        ],
        rowClick: function(args) {
            employees.select(bezl, args.item);
        }
        });

        // Configure the team members jsGrid
        $("#jsGridJobs").jsGrid({
        width: "600",
        height: "400",
        heading: true,
        filtering: true,
        sorting: true,
        autoload: true,
        inserting: false,
        controller: {
            loadData: function() {
            return bezl.vars.openJobs;
            }
        },
        fields: [
            { name: "jobId", title: "Job", type: "text", visible: true, width: 25, editing: false },
            { name: "jobDesc", title: "Description", type: "text", visible: true, width: 50, editing: false }
        ],
        rowClick: function(args) {
            bezl.vars.selectedJob = args.item;

            // Highlight the selected row in jsGrid
            if ( bezl.vars.selectedRow ) { bezl.vars.selectedRow.children('.jsgrid-cell').css('background-color', ''); }
            var $row = this.rowByItem(args.item);
            $row.children('.jsgrid-cell').css('background-color','#F7B64B');
            bezl.vars.selectedRow = $row;
        }
        });

    }

  return {
    onStartup: OnStartup
  }
});<commit_msg>Added filter link to Jobs Grid.<commit_after>define(["./employees.js"], function (employees) {

    function OnStartup (bezl) {
        // Call setConfig which defines the handful of settings that you may wish to tweak
        bezl.functions['setConfig']();

        // Default the number of selected employees on the team grid to 0
        bezl.vars.employeesSelected = 0;

        // Initiate the queries to run up front
        employees.runQuery(bezl, 'Team');
        employees.runQuery(bezl, 'AllEmployees');
        employees.runQuery(bezl, 'OpenJobs');

        // Configure the team members jsGrid
        $("#jsGridTeam").jsGrid({
        width: "100%",
        height: "100%",
        heading: true,
        sorting: true,
        autoload: true,
        inserting: false,
        controller: {
            loadData: function() {
            return bezl.vars.team;
            }
        },
        fields: [
            { name: "display", title: "Name", type: "text", visible: true, width: 50, editing: false },
            { name: "clockedIn", title: "Clocked In", align: "center", width: 25,
            	itemTemplate: function(value, item) {
              	return $("<input>").attr("type", "checkbox")
                		.attr("checked", value || item.Checked)
                    .on("change", function() {
                    	item.Checked = $(this).is(":checked");
                    });
              }
            },
            { name: "currentActivity", title: "Current Activity", type: "text", visible: true, width: 50, editing: false }
        ],
        rowClick: function(args) {
            employees.select(bezl, args.item);
        }
        });

        // Configure the team members jsGrid
        $("#jsGridJobs").jsGrid({
        width: "600",
        height: "400",
        heading: true,
        filtering: true,
        sorting: true,
        autoload: true,
        inserting: false,
        controller: {
            loadData: function(filter) {
                return $.grep(bezl.vars.openJobs, function (item) {
                    return (!filter.JobID || item.JobID.indexOf(filter.JobID) >= 0);
                }
            }
        },
        fields: [
            { name: "jobId", title: "Job", type: "text", visible: true, width: 25, editing: false },
            { name: "jobDesc", title: "Description", type: "text", visible: true, width: 50, editing: false }
        ],
        rowClick: function(args) {
            bezl.vars.selectedJob = args.item;

            // Highlight the selected row in jsGrid
            if ( bezl.vars.selectedRow ) { bezl.vars.selectedRow.children('.jsgrid-cell').css('background-color', ''); }
            var $row = this.rowByItem(args.item);
            $row.children('.jsgrid-cell').css('background-color','#F7B64B');
            bezl.vars.selectedRow = $row;
        }
        });

    }

  return {
    onStartup: OnStartup
  }
});<|endoftext|>


<commit_before>/*eslint-env node, mocha*/
const Bluebird   = require('bluebird');
const { expect } = require('chai');
const sinon      = require('sinon');
const MW         = require('../../lib/express');

const testDriver = {
  createPool: sinon.stub().returns(42)
}

const testConfig = {
  driver: testDriver
};

let conn       = null;
let pool       = null;
let driver     = null;

describe('expressjs Middleware', function() {

  beforeEach(() => {

    conn = {
      release: sinon.stub()
    };
    pool = {
      getConnection : sinon.stub().yields(null, conn)
    };

    driver = {
      createPool: sinon.stub().returns(pool)
    };

  });

  it('should be a function that returns a middleware function', () => {

    const mw = MW(testConfig);

    expect(mw).to.be.a('function');
    expect(mw.length).to.eql(3);

  });

  it('should throw a TypeError if a driver is not provided', () => {

    const test = () => MW(testDriver);

    expect(test).to.throw(TypeError, /You must provide a driver/);

  });

  it('should throw a TypeError if the driver does not have a ' +
  'createPool method', () => {

    const test = () => MW({ driver: {} });

    expect(test).to.throw(
      TypeError
    , /Your driver must support connection pooling/
    )

  });

  it('should create a connection pool and attach it to the ' +
  ' request object', () => {

    const mw = MW({ driver });

    const req = {};
    const res = {};

    mw(req, res, () => {

      expect(req.mysql).to.eql(conn);
      expect(pool.getConnection.calledOnce).to.be.true;
      expect(driver.createPool.calledOnce).to.be.true;

    });

  });

  it('should pass any connection error to the `next` function', (done) => {

    pool.getConnection = sinon.stub().yields(new Error('boom!'));

    const mw = MW({ driver });

    mw({}, {}, (err) => {

      expect(err.message).to.eql('boom!');
      done();

    });

  });

  it('should throw an error if you attempt to attach to an already ' +
  'attached namespace',(done) => {

    const mw = MW({ driver });
    const mw2 = MW({ driver });

    const req = {};
    const res = {};

    mw(req, res, () => {

      const test = () => mw2(req, res, done);

      expect(test).to.throw(
        Error,
        /Namespace Collision: mysql/
      );

      done();

    });

  });

  it('should cache multiple calls to the query method', (done) => {

    const mw = MW({ driver });

    const req = {};
    const res = {};

    const test_query  = 'foo, bar';
    const test_params = [ 'foo', 'bar' ]

    let calls = 0;
    const queryStub   = (sql, params, cb) => {
      expect(sql).to.eql(test_query);
      expect(params).to.eql(test_params);
      calls++;

      setTimeout(cb, 10, null, 'foo');

    };
    conn.query        = queryStub;

    const run = (req) => new Bluebird((resolve, reject) =>
      req.mysql.query(test_query, test_params, (err, result) =>
        err ? reject(err) : resolve(result)
      )
    );

    mw(req, res, () => {

      const x = run(req);
      const y = run(req);

      return Bluebird.all([ x, y ])

      .then((results) => {

        expect(results).to.deep.eql([ 'foo', 'foo' ]);
        expect(calls).to.eql(1);

        done();

      })

      .catch(done);

    });

  });

});
<commit_msg>finishes out all the tests.<commit_after>/*eslint-env node, mocha*/
const Bluebird   = require('bluebird');
const { expect } = require('chai');
const sinon      = require('sinon');
const MW         = require('../../lib/express');

const testDriver = {
  createPool: sinon.stub().returns(42)
}

const testConfig = {
  driver: testDriver
};

let conn       = null;
let pool       = null;
let driver     = null;

describe('expressjs Middleware', function() {

  beforeEach(() => {

    conn = {
      release: sinon.stub()
    };
    pool = {
      getConnection : sinon.stub().yields(null, conn)
    };

    driver = {
      createPool: sinon.stub().returns(pool)
    };

  });

  it('should be a function that returns a middleware function', () => {

    const mw = MW(testConfig);

    expect(mw).to.be.a('function');
    expect(mw.length).to.eql(3);

  });

  it('should throw a TypeError if a driver is not provided', () => {

    const test = () => MW(testDriver);

    expect(test).to.throw(TypeError, /You must provide a driver/);

  });

  it('should throw a TypeError if the driver does not have a ' +
  'createPool method', () => {

    const test = () => MW({ driver: {} });

    expect(test).to.throw(
      TypeError
    , /Your driver must support connection pooling/
    )

  });

  it('should create a connection pool and attach it to the ' +
  ' request object', () => {

    const mw = MW({ driver });

    const req = {};
    const res = {};

    mw(req, res, () => {

      expect(req.mysql).to.eql(conn);
      expect(pool.getConnection.calledOnce).to.be.true;
      expect(driver.createPool.calledOnce).to.be.true;

    });

  });

  it('should not patch an already patched handler', (done) => {

    conn.query   = 'TEST';
    conn.patched = true;

    const mw     = MW({ driver });

    mw({}, {}, () => {

      expect(conn.query).to.eql('TEST');
      done();

    });

  });

  it('should pass any connection error to the `next` function', (done) => {

    pool.getConnection = sinon.stub().yields(new Error('boom!'));

    const mw = MW({ driver });

    mw({}, {}, (err) => {

      expect(err.message).to.eql('boom!');
      done();

    });

  });

  it('should throw an error if you attempt to attach to an already ' +
  'attached namespace',(done) => {

    const mw = MW({ driver });
    const mw2 = MW({ driver });

    const req = {};
    const res = {};

    mw(req, res, () => {

      const test = () => mw2(req, res, done);

      expect(test).to.throw(
        Error,
        /Namespace Collision: mysql/
      );

      done();

    });

  });

  it('should handle a buffer query', (done) => {

    const mw           = MW({ driver });
    const test_query   = 'בחר * ממבח';
    const buffer_query = Buffer.from(test_query);

    const queryStub = (sql, params, cb) => {
      expect(sql).to.eql(buffer_query);
      expect(params).to.deep.eql([]);

      setTimeout(cb, 10, null, 'blah');
    };

    conn.query = queryStub;

    const req = {};

    mw(req, {}, () => req.mysql.query(buffer_query, (err, result) => {
      expect(result).to.eql('blah');
      done();
    }));

  });

  it('should allow only the query to be passed.', (done) => {

    const mw = MW({ driver });

    const test_query = 'DESUMO * A PROBATIO';

    const queryStub = (sql, params, cb) => {
      expect(sql).to.eql(test_query);
      expect(params).to.deep.eql([]);
      expect(cb).to.be.a('function');

      // call for posterity's sake
      cb();

      done();
    };
    conn.query = queryStub;

    const req = {};

    mw(req, {}, () => req.mysql.query(test_query));

  });

  it('should set the params to an empty array when not provided', (done) => {

    const mw = MW({ driver });

    const test_query = 'SELECT * FROM `test`';

    const queryStub = (sql, params, cb) => {
      expect(sql).to.eql(test_query);
      expect(params).to.deep.eql([]);

      setTimeout(cb, 10, null, 'foo');
    };
    conn.query = queryStub;

    const req = {};

    mw(req, {}, () => {

      req.mysql.query(test_query, (err, result) => {

        expect(result).to.eql('foo');
        expect(err).to.be.null;
        done();

      });

    });

  });

  it('should cache multiple calls to the query method', (done) => {

    const mw = MW({ driver });

    const req = {};
    const res = {};

    const test_query  = 'foo, bar';
    const test_params = [ 'foo', 'bar' ]

    let calls = 0;
    const queryStub   = (sql, params, cb) => {
      expect(sql).to.eql(test_query);
      expect(params).to.eql(test_params);
      calls++;

      setTimeout(cb, 10, null, 'foo');

    };
    conn.query        = queryStub;

    const run = (req) => new Bluebird((resolve, reject) =>
      req.mysql.query(test_query, test_params, (err, result) =>
        err ? reject(err) : resolve(result)
      )
    );

    mw(req, res, () => {

      const x = run(req);
      const y = run(req);

      return Bluebird.all([ x, y ])

      .then((results) => {

        expect(results).to.deep.eql([ 'foo', 'foo' ]);
        expect(calls).to.eql(1);

        done();

      })

      .catch(done);

    });

  });

});
<|endoftext|>


<commit_before>var pulsar = require('../package.json');
var p5 = require('p5');

pulsar.config = pulsarInitConfig;
pulsarInitConfig = undefined;

// pulsar utils
p5.pulsar = {};
p5.pulsar.merge = function(defaults, pulse) {
  for (var attribute in pulse) {
    defaults[attribute] = pulse[attribute];
  }
}

pulsar.sketch = function (p) {

  var Receiver = require('./Receiver.js');
  var receiver = new Receiver();

  var Processor = require('./Processor.js');
  var processor = new Processor();

  var DrawingManager = require('./DrawingManager.js');
  var dM = new DrawingManager(p);

  var versionTag = pulsar.name.toUpperCase() + "(" + pulsar.config.col + ", " + pulsar.config.row + ") - v" + pulsar.version;

  p.setup = function() {
    p.frameRate(30);
    receiver.connect();

    receiver.on('pulse', function(data) {
      console.log("Pulsar: received: " + data);
      var drawing = processor.createDrawing(p5, data, pulsar.config);
      if (drawing) {
        dM.add(drawing);
      }
    });

    receiver.on('pulsar control', function(data) {
      console.log("Pulsar: received: " + data);
      processor.processControl(data, pulsar.config);
    });

    p.createCanvas(p.windowWidth, p.windowHeight);

    dM.add(processor.createDrawing(p5, {name: 'pulsar-splash', version: pulsar.version}));
  }

  p.draw = function() {
    p.noStroke();
    p.background(0);

    dM.drawAll();

    p.textSize(15);
    p.fill(175);
    p.textAlign(p.LEFT);
    var verWidth = p.textWidth(versionTag);
    p.text(versionTag, p.windowWidth - verWidth - 10, p.windowHeight - 10);
  }

  p.windowResized = function() {
    p.resizeCanvas(p.windowWidth, p.windowHeight);
  }
}

new p5(pulsar.sketch);<commit_msg>Move the pulsar utilities on to the p object instead of p5<commit_after>var pulsar = require('../package.json');
var p5 = require('p5');

pulsar.config = pulsarInitConfig;
pulsarInitConfig = undefined;

pulsar.sketch = function (p) {

  // pulsar utils
  p.pulsar = {};
  p.pulsar.merge = function(defaults, pulse) {
    for (var attribute in pulse) {
      defaults[attribute] = pulse[attribute];
    }
  }

  var Receiver = require('./Receiver.js');
  var receiver = new Receiver();

  var Processor = require('./Processor.js');
  var processor = new Processor();

  var DrawingManager = require('./DrawingManager.js');
  var dM = new DrawingManager(p);

  var versionTag = pulsar.name.toUpperCase() + "(" + pulsar.config.col + ", " + pulsar.config.row + ") - v" + pulsar.version;

  p.setup = function() {
    p.frameRate(30);
    receiver.connect();

    receiver.on('pulse', function(data) {
      console.log("Pulsar: received: " + data);
      var drawing = processor.createDrawing(p, data, pulsar.config);
      if (drawing) {
        dM.add(drawing);
      }
    });

    receiver.on('pulsar control', function(data) {
      console.log("Pulsar: received: " + data);
      processor.processControl(data, pulsar.config);
    });

    p.createCanvas(p.windowWidth, p.windowHeight);

    dM.add(processor.createDrawing(p, {name: 'pulsar-splash', version: pulsar.version}));
  }

  p.draw = function() {
    p.noStroke();
    p.background(0);

    dM.drawAll();

    p.textSize(15);
    p.fill(175);
    p.textAlign(p.LEFT);
    var verWidth = p.textWidth(versionTag);
    p.text(versionTag, p.windowWidth - verWidth - 10, p.windowHeight - 10);
  }

  p.windowResized = function() {
    p.resizeCanvas(p.windowWidth, p.windowHeight);
  }
}

new p5(pulsar.sketch);<|endoftext|>


<commit_before>'use strict';

require('should');
const KEY_MAP = require('webdriver-keycode');

var platform = process.env.platform || 'iOS';
platform = platform.toLowerCase();

const pkg = require('../package');

/**
 * download app form npm
 *
 * or use online resource: https://npmcdn.com/ios-app-bootstrap@latest/build/ios-app-bootstrap.zip
 *
 * npm i ios-app-bootstrap --save-dev
 *
 * var opts = {
 *   app: path.join(__dirname, '..', 'node_modules', 'ios-app-bootstrap', 'build', 'ios-app-bootstrap.zip');
 * };
 */

// see: https://macacajs.github.io/desired-caps

var iOSOpts = {
  deviceName: 'iPhone 6s',
  platformName: 'iOS',
  autoAcceptAlerts: false,
  //reuse: 3,
  //udid: '',
  //bundleId: 'xudafeng.ios-app-bootstrap',
  app: 'https://npmcdn.com/ios-app-bootstrap@latest/build/ios-app-bootstrap.zip'
};

var androidOpts = {
  platformName: 'Android',
  autoAcceptAlerts: false,
  isWaitActivity: true,
  //reuse: 3,
  //udid: '',
  //package: 'com.github.android_app_bootstrap',
  //activity: 'com.github.android_app_bootstrap.activity.WelcomeActivity',
  app: 'https://npmcdn.com/android-app-bootstrap@latest/android_app_bootstrap/build/outputs/apk/android_app_bootstrap-debug.apk'
};

const isIOS = platform === 'ios';
const infoBoardXPath = isIOS ? '//*[@name="info"]' : '//*[@resource-id="com.github.android_app_bootstrap:id/info"]';
const webviewButtonXPath = isIOS ? '//*[@name="Webview"]' : '//*[@resource-id="android:id/tabs"]/android.widget.LinearLayout[2]';

const wd = require('macaca-wd');

// override custom wd
require('./wd-extend')(wd, isIOS);

describe('macaca mobile sample', function() {
  this.timeout(10 * 60 * 1000);

  const driver = wd.promiseChainRemote({
    host: 'localhost',
    port: 3456
  });

  driver.configureHttp({
    timeout: 600 * 1000
  });

  before(function() {
    return driver
      .init(isIOS ? iOSOpts : androidOpts);
  });

  after(function() {
    return driver
      .sleep(1000)
      .quit();
  });

  it('#1 should login success', function() {
    return driver
      .title()
      .then(data => {
        console.log(`current focus ${isIOS ? 'viewController' : 'activity'}: ${data}`);
      })
      .getWindowSize()
      .then(size => {
        console.log(`current window size ${JSON.stringify(size)}`);
      })
      .appLogin('中文+Test+12345678', '111111');
  });

  it('#2 should display home', function() {
    return driver
      .source()
      .then(res => {
        console.log(res);
      })
      .takeScreenshot();
  });

  it('#3 should scroll tableview', function() {
    return driver
      .testGetProperty()
      .waitForElementByName('HOME')
      .click()
      .waitForElementByName('list')
      .click()
      .sleep(2000);
  });

  it('#4 should cover gestrure', function() {
    return driver
      .waitForElementByName('Alert')
      .click()
      .sleep(5000)
      .acceptAlert()
      .sleep(1000)
      .customback()
      .waitForElementByName('Gesture')
      .click()
      .sleep(5000)
      .then(() => {
        return driver
          .touch('tap', {
            x: 100,
            y: 100
          })
          .sleep(1000)
          .elementByXPath(infoBoardXPath)
          .text()
          .then(text => {
            JSON.stringify(text).should.containEql('singleTap');
          });
      })
      .then(() => {
        return driver
          .touch('press', {
            x: 100,
            y: 100,
            duration: 2
          })
          .sleep(1000);
      })
      .then(() => {
        return driver
          .waitForElementByXPath(infoBoardXPath)
          .touch('pinch', {
            scale: 2,      // only for iOS
            velocity: 1,   // only for iOS
            direction: 'in',// only for Android
            percent: 0.2,  // only for Android
            steps: 200     // only for Android
          })
          .sleep(1000);
      })
      /*
      // TODO Android rotate
      .then(() => {
        return driver
          .touch('rotate', {
          })
          .sleep(1000);
      })*/
      .customback()
      .then(() => {
        return driver
          .touch('drag', {
            fromX: 100,
            fromY: 600,
            toX: 100,
            toY: 100,
            duration: 3
          })
          .sleep(1000);
      })
      .sleep(1000);
  });

  it('#5 should go into webview', function() {
    return driver
      .customback()
      .sleep(3000)
      .elementByXPath(webviewButtonXPath)
      .click()
      .sleep(3000)
      .takeScreenshot()
      .changeToWebviewContext()
      .elementById('pushView')
      .click()
      .changeToWebviewContext()
      .waitForElementById('popView')
      .click()
      .sleep(5000)
      .takeScreenshot();
  });

  it('#6 should go into test', function() {
    return driver
      .changeToNativeContext()
      .waitForElementByName('Baidu')
      .click()
      .sleep(5000)
      .takeScreenshot();
  });

  it('#7 should works with web', function() {
    return driver
      .changeToWebviewContext()
      .title()
      .then(title => {
        console.log(`title: ${title}`);
      })
      .url()
      .then(url => {
        console.log(`url: ${url}`);
      })
      .refresh()
      .sleep(2000)
      .elementById('index-kw')
      .getProperty('name')
      .then(info => {
        console.log(`get web attribute name: ${JSON.stringify(info)}`);
      })
      .waitForElementById('index-kw')
      .sendKeys('中文+Macaca')
      .elementById('index-bn')
      .click()
      .sleep(5000)
      .source()
      .then(html => {
        html.should.containEql('Macaca');
      })
      .execute(`document.body.innerHTML = "<h1>${pkg.name}</h1>"`)
      .sleep(3000)
      .takeScreenshot();
  });

  it('#8 should logout success', function() {
    return driver
      .changeToNativeContext()
      .waitForElementByName('PERSONAL')
      .click()
      .sleep(1000)
      .takeScreenshot()
      .waitForElementByName('Logout')
      .click()
      .sleep(1000)
      .takeScreenshot();
  });
});
<commit_msg>fix title<commit_after>'use strict';

require('should');
const KEY_MAP = require('webdriver-keycode');

var platform = process.env.platform || 'iOS';
platform = platform.toLowerCase();

const pkg = require('../package');

/**
 * download app form npm
 *
 * or use online resource: https://npmcdn.com/ios-app-bootstrap@latest/build/ios-app-bootstrap.zip
 *
 * npm i ios-app-bootstrap --save-dev
 *
 * var opts = {
 *   app: path.join(__dirname, '..', 'node_modules', 'ios-app-bootstrap', 'build', 'ios-app-bootstrap.zip');
 * };
 */

// see: https://macacajs.github.io/desired-caps

var iOSOpts = {
  deviceName: 'iPhone 6s',
  platformName: 'iOS',
  autoAcceptAlerts: false,
  //reuse: 3,
  //udid: '',
  //bundleId: 'xudafeng.ios-app-bootstrap',
  app: 'https://npmcdn.com/ios-app-bootstrap@latest/build/ios-app-bootstrap.zip'
};

var androidOpts = {
  platformName: 'Android',
  autoAcceptAlerts: false,
  isWaitActivity: true,
  //reuse: 3,
  //udid: '',
  //package: 'com.github.android_app_bootstrap',
  //activity: 'com.github.android_app_bootstrap.activity.WelcomeActivity',
  app: 'https://npmcdn.com/android-app-bootstrap@latest/android_app_bootstrap/build/outputs/apk/android_app_bootstrap-debug.apk'
};

const isIOS = platform === 'ios';
const infoBoardXPath = isIOS ? '//*[@name="info"]' : '//*[@resource-id="com.github.android_app_bootstrap:id/info"]';
const webviewButtonXPath = isIOS ? '//*[@name="Webview"]' : '//*[@resource-id="android:id/tabs"]/android.widget.LinearLayout[2]';

const wd = require('macaca-wd');

// override custom wd
require('./wd-extend')(wd, isIOS);

describe('macaca mobile sample', function() {
  this.timeout(10 * 60 * 1000);

  const driver = wd.promiseChainRemote({
    host: 'localhost',
    port: 3456
  });

  driver.configureHttp({
    timeout: 600 * 1000
  });

  before(function() {
    return driver
      .init(isIOS ? iOSOpts : androidOpts);
  });

  after(function() {
    return driver
      .sleep(1000)
      .quit();
  });

  it('#1 should login success', function() {
    return driver
      /*
      .title()
      .then(data => {
        console.log(`current focus ${isIOS ? 'viewController' : 'activity'}: ${data}`);
      })
      */
      .getWindowSize()
      .then(size => {
        console.log(`current window size ${JSON.stringify(size)}`);
      })
      .appLogin('中文+Test+12345678', '111111');
  });

  it('#2 should display home', function() {
    return driver
      .source()
      .then(res => {
        console.log(res);
      })
      .takeScreenshot();
  });

  it('#3 should scroll tableview', function() {
    return driver
      .testGetProperty()
      .waitForElementByName('HOME')
      .click()
      .waitForElementByName('list')
      .click()
      .sleep(2000);
  });

  it('#4 should cover gestrure', function() {
    return driver
      .waitForElementByName('Alert')
      .click()
      .sleep(5000)
      .acceptAlert()
      .sleep(1000)
      .customback()
      .waitForElementByName('Gesture')
      .click()
      .sleep(5000)
      .then(() => {
        return driver
          .touch('tap', {
            x: 100,
            y: 100
          })
          .sleep(1000)
          .elementByXPath(infoBoardXPath)
          .text()
          .then(text => {
            JSON.stringify(text).should.containEql('singleTap');
          });
      })
      .then(() => {
        return driver
          .touch('press', {
            x: 100,
            y: 100,
            duration: 2
          })
          .sleep(1000);
      })
      .then(() => {
        return driver
          .waitForElementByXPath(infoBoardXPath)
          .touch('pinch', {
            scale: 2,      // only for iOS
            velocity: 1,   // only for iOS
            direction: 'in',// only for Android
            percent: 0.2,  // only for Android
            steps: 200     // only for Android
          })
          .sleep(1000);
      })
      /*
      // TODO Android rotate
      .then(() => {
        return driver
          .touch('rotate', {
          })
          .sleep(1000);
      })*/
      .customback()
      .then(() => {
        return driver
          .touch('drag', {
            fromX: 100,
            fromY: 600,
            toX: 100,
            toY: 100,
            duration: 3
          })
          .sleep(1000);
      })
      .sleep(1000);
  });

  it('#5 should go into webview', function() {
    return driver
      .customback()
      .sleep(3000)
      .elementByXPath(webviewButtonXPath)
      .click()
      .sleep(3000)
      .takeScreenshot()
      .changeToWebviewContext()
      .elementById('pushView')
      .click()
      .changeToWebviewContext()
      .waitForElementById('popView')
      .click()
      .sleep(5000)
      .takeScreenshot();
  });

  it('#6 should go into test', function() {
    return driver
      .changeToNativeContext()
      .waitForElementByName('Baidu')
      .click()
      .sleep(5000)
      .takeScreenshot();
  });

  it('#7 should works with web', function() {
    return driver
      .changeToWebviewContext()
      .title()
      .then(title => {
        console.log(`title: ${title}`);
      })
      .url()
      .then(url => {
        console.log(`url: ${url}`);
      })
      .refresh()
      .sleep(2000)
      .elementById('index-kw')
      .getProperty('name')
      .then(info => {
        console.log(`get web attribute name: ${JSON.stringify(info)}`);
      })
      .waitForElementById('index-kw')
      .sendKeys('中文+Macaca')
      .elementById('index-bn')
      .click()
      .sleep(5000)
      .source()
      .then(html => {
        html.should.containEql('Macaca');
      })
      .execute(`document.body.innerHTML = "<h1>${pkg.name}</h1>"`)
      .sleep(3000)
      .takeScreenshot();
  });

  it('#8 should logout success', function() {
    return driver
      .changeToNativeContext()
      .waitForElementByName('PERSONAL')
      .click()
      .sleep(1000)
      .takeScreenshot()
      .waitForElementByName('Logout')
      .click()
      .sleep(1000)
      .takeScreenshot();
  });
});
<|endoftext|>


<commit_before>var system = require('system'),
    fs = require('fs');

// check for required arguments
if (system.args.length < 2) {
    console.log('Usage: casperjs opencms-casper.js <casperPath> --url=<base-url> --file=<file> --user=<user> --pass=<pass> --module=<module-name> --log=<log-dir>');
    phantom.exit(64);
}

// set casperjs path
phantom.casperPath = 'vendor/casperjs';

// if deployment is started by deploy script the 6th argument is the absolute path to casper js
// hopefully this will work on windows too
if (system.args[1]) {
    phantom.casperPath = system.args[1];
}

// inject casperjs
phantom.injectJs(phantom.casperPath + '/bin/bootstrap.js');

if (!phantom.casperLoaded) {
    console.log('This script must be invoked using the casperjs executable');
    phantom.exit(1);
}

// initialize casperjs and casperjs's utils
var utils = require('utils'),
    casper = require('casper').create();

// get some mor command line arguments
var loginUrl = casper.cli.get('url') + 'cms/system/login/index.html';
var topUrl = casper.cli.get('url') + 'cms/system/workplace/views/top_head.jsp';
var uploadUrl = casper.cli.get('url') + 'cms/system/workplace/views/admin/admin-main.jsp?path=%2Fmodules%2Fmodules_import';
var file = casper.cli.get('file');
var user = casper.cli.get('user');
var pass = casper.cli.get('pass');

// parse some options from cli
casper.options.verbose = casper.cli.get('direct') || false;
casper.options.logLevel = casper.cli.get('log-level') || "error";

if (casper.cli.has('module')) {
    var module = casper.cli.get('module');
}

if (casper.cli.has('log')) {
    var logDir = casper.cli.get('log');
}

var dateToYMD = function (date) {
    var d = date.getDate();
    var m = date.getMonth()+1;
    var y = date.getFullYear();
    var hh = date.getHours();
    var mm = date.getMinutes();
    var ss = date.getSeconds();
    return '' + y + '' + (m<=9?'0'+m:m) +''+ (d<=9?'0'+d:d) + '_' + (hh<=9?'0'+hh:hh) + '' + (mm<=9?'0'+mm:mm) + '' + (ss<=9?'0'+ss:ss);
};

// prints opencms reports in iframe to stdout
var updateReport = function () {
    var openCmsLog = casper.evaluate(function() {
        return document.querySelector('#report').contentDocument.querySelector('.main').innerText;
    });
    console.log(openCmsLog);
    if (logDir) {
        fs.write(logDir + '/' + dateToYMD(new Date()) + '_' + module + '.log', openCmsLog);
    }
};

// when the report iframe is requested, we tell the user
casper.on('navigation.requested', function(url, navigationType, navigationLocked, isMainFrame) {
    if (url.indexOf('reportupdate') > -1) casper.log('still working ...', 'info');
});

// on error print out message and exit
casper.on('error', function (msg, trace) {
    console.log(msg + '\n');
    trace.forEach(function(item) {
        console.log('  ', item.file, ':', item.line);
    });
    casper.exit(75);
});

casper.on('load.failed', function (obj) {
    casper.log('error loading ' + obj.url, 'error');
    casper.exit(69);
});

// open login form and submit
casper.start(loginUrl, function() {
    casper.fill('form[name="ocLoginForm"]', {
        ocUname: user,
        ocPword: pass
    }, true);
});

// open opencms header frame and change site to /
casper.thenOpen(topUrl, function() {
    casper.fill('form[name="wpSiteSelect"]', {
        wpSite: ''
    });
});

// open import form and submit the module zip file
casper.thenOpen(uploadUrl, function() {
    casper.fill('form[name="main"]', {
        importfile: file
    }, true);
});

// wait until the ok button isn't diabled anymore
casper.waitWhileSelector('form[name="main"] input[name="ok"]:disabled',
    function then() {},
    function timeout() {},
    60000*20);

// run all steps defined before
casper.run(function() {
    // after running all steps we get the opencms log and write to stdout
    updateReport();
    // we are done
    casper.echo('module deployed', 'GREEN_BAR');
    // exit with successful exit code
    casper.exit(0);
});
<commit_msg>Removed old deploy script<commit_after><|endoftext|>


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

/* eslint-env mocha */

const validate = require('../../lib/validate')
const x = require('cartesian')

const domain = 'dns-sd-lookup.toryt.org'
const protocols = ['tcp', 'udp']
// noinspection SpellCheckingInspection
const serviceType = 'a-Serv1ce-type'
const serviceSubTypes = [
  '',
  '_a-sub-service',
  '_a.complex.sub.service',
  'sub service type without an underscore' // this is allowed under RFC 6763
]
// noinspection SpellCheckingInspection
const instances = [
  'a-service-instance',
  'A Human Readable Sérvice Instance',
  'instance.withPartThatIsNotLongerThanIsAcceptableWhichIs63CharactersLabel.lastLabel'
  'instances\\.with\\.escaped\\\\dots\\\\and\\.slashes',
]

function createService (prefix) {
  return prefix ? `${prefix}._${serviceType}` : `_${serviceType}`
}

function createSubPrefix (subtype) {
  return subtype ? `${subtype}._sub` : ''
}

const services = serviceSubTypes.map(createSubPrefix).concat(instances).map(createService)

function createFqdn (c) {
  return `${c.service}._${c.protocol}.${domain}`
}

const protocol = '_tcp.'
let almostTooLong = domain
const placesLeft = validate.maxLength - almostTooLong.length - protocol.length - serviceType.length - 2
const times = placesLeft / (validate.maxLabelLength + 1)
// noinspection SpellCheckingInspection
const maxLabel = 'abcdefghijklmnopqrstuvwxyz'.repeat(2) + 'abcdefghijk.'
console.assert(maxLabel.length === validate.maxLabelLength + 1)
almostTooLong = maxLabel.repeat(times) + almostTooLong
const rest = (placesLeft % (validate.maxLabelLength + 1)) - 1
almostTooLong = maxLabel.substring(0, rest) + '.' + almostTooLong
const notTooLong = `_${serviceType}.${protocol}${almostTooLong}`
console.assert(notTooLong.length === validate.maxLength)
const tooLong = `_${serviceType}.${protocol}z${almostTooLong}`
console.assert(tooLong.length === validate.maxLength + 1)

describe('validate', function () {
  describe('#isBaseServiceType', function () {
    describe('true', function () {
      protocols.forEach(protocol => {
        const candidate = `_${serviceType}._${protocol}.${domain}`
        it(`returns true for ${candidate}`, function () {
          const result = validate.isBaseServiceType(candidate)
          console.log('%s --> %s', candidate, result)
          result.must.be.true()
        })
      })
      it(`returns true for the max length`, function () {
        const result = validate.isBaseServiceType(notTooLong)
        console.log('%s --> %s', notTooLong, result)
        result.must.be.true()
      })
      const lookupCase = '_t1i-no-sub._tcp.dns-sd-lookup.toryt.org'
      it(`returns true for the lookup case`, function () {
        const result = validate.isBaseServiceType(lookupCase)
        console.log('%s --> %s', lookupCase, result)
        result.must.be.true()
      })
    })
    describe('false', function () {
      // noinspection SpellCheckingInspection
      const fqdns = [
        null,
        undefined,
        '',
        '# not _ a domain',
        'notcporupd.' + domain,
        serviceType + '.notcporupd.' + domain,
        '_udp.' + domain,
        '_tcp.' + domain,
        '_thisIsSxteenLong._udp.' + domain,
        '_thisIsSxteenLong._tcp.' + domain,
        '_service spaces._udp.' + domain,
        '_service spaces._tcp.' + domain,
        '_service_undersc._udp.' + domain,
        '_service_undersc._tcp.' + domain,
        '_service,comma._udp.' + domain,
        '_double--dash._tcp.' + domain,
        'notStartWith_._udp.' + domain,
        'notStartWith_._tcp.' + domain,
        '_-dash._tcp.' + domain,
        '_dash-._tcp.' + domain,
        '_9number._tcp.' + domain,
        '_number9._tcp.' + domain,
        `_${serviceType}._udp.a.thisIs999NotATld`,
        `_${serviceType}._udp.a.domain_with.an.underscore.com`,
        tooLong
      ]
      fqdns.forEach(fqdn => {
        it(`returns false for ${fqdn}`, function () {
          const result = validate.isBaseServiceType(fqdn)
          console.log('%s --> %s', fqdn, result)
          result.must.be.false()
        })
      })
    })
  })

  describe('#isServiceInstance', function () {
    describe('true', function () {
      // noinspection JSUnresolvedFunction
      const fqdns = x({
        instance: instances,
        protocol: protocols
      }).map(c => `${c.instance}._${serviceType}._${c.protocol}.${domain}`)
      fqdns.forEach(candidate => {
        it(`returns true for ${candidate}`, function () {
          const result = validate.isServiceInstance(candidate)
          console.log('%s --> %s', candidate, result)
          result.must.be.true()
        })
      })
      it(`returns true for the max length`, function () { // MUDO
        const result = validate.isServiceInstance(notTooLong)
        console.log('%s --> %s', notTooLong, result)
        result.must.be.true()
      })
      const lookupCase = 'instance 1._t1i-no-sub._tcp.dns-sd-lookup.toryt.org'
      it(`returns true for the lookup case`, function () {
        const result = validate.isServiceInstance(lookupCase)
        console.log('%s --> %s', lookupCase, result)
        result.must.be.true()
      })
    })
    describe('false', function () {
      // noinspection SpellCheckingInspection
      const fqdns = [
        null,
        undefined,
        '',
        'instance.not.a.service',
        // since we know that we delegate here to isBaseServiceType, we do not need to test the variants (white box)
        'instance.withAPartThatIsLonger-ThanIsAcceptableWhichIs63ACharactersLabels.lastLabel._service._tcp.' + domain,
        tooLong // MUDO
      ]
      fqdns.forEach(fqdn => {
        it(`returns false for ${fqdn}`, function () {
          const result = validate.isServiceInstance(fqdn)
          console.log('%s --> %s', fqdn, result)
          result.must.be.false()
        })
      })
    })
  })

  describe('#isServiceTypeOrInstanceFqdn', function () {
    describe('true', function () {
      // noinspection JSUnresolvedFunction
      const fqdns = x({
        service: services,
        protocol: protocols
      }).map(createFqdn)
      fqdns.forEach(fqdn => {
        it(`returns true for ${fqdn}`, function () {
          const result = validate.isServiceTypeOrInstanceFqdn(fqdn)
          console.log('%s --> %s', fqdn, result)
          result.must.be.true()
        })
      })
    })
    describe('false', function () {
      // noinspection SpellCheckingInspection
      const fqdns = [
        null,
        undefined,
        '',
        '# not _ a domain',
        'notcporupd.' + domain,
        serviceType + '.notcporupd.' + domain,
        '_udp.' + domain,
        '_tcp.' + domain,
        '_service contains spaces._udp.' + domain,
        '_service contains spaces._tcp.' + domain,
        'serviceDoesNotStartWith_._udp.' + domain,
        'serviceDoesNotStartWith_._tcp.' + domain,
        tooLong
      ]
      fqdns.forEach(fqdn => {
        it(`returns false for ${fqdn}`, function () {
          const result = validate.isServiceTypeOrInstanceFqdn(fqdn)
          console.log('%s --> %s', fqdn, result)
          result.must.be.false()
        })
      })
    })
  })

  describe('#isValidDomainNamePart', function () {
    it('true on a good part', function () {
      const result = validate.isValidDomainNamePart('a-valid09-€₰૱εέ𒀪©∭∏∇𐡀☯°廓DOMAIN-é--name-part')
      result.must.be.true()
    })
    const wrongParts = [
      '-starts-with-a-dash',
      'ends-with-a-dash-',
      'has-a-(-character',
      'has-a-}-character',
      'has-a-.-character',
      'has-a-]-character',
      'has-a-_-character',
      'has-a-+-character',
      'has-a-%20-character',
      'has-a-%-character',
      'has-a- -space',
      'theLengthOfAPartIsLimitedTo63CharactersThisIsTooLongBy1Character'
    ]
    wrongParts.forEach(part => {
      it('false on wrong part ' + part, function () {
        const result = validate.isValidDomainNamePart(part)
        result.must.be.false()
      })
    })
  })

  describe('#isNatural', function () {
    const rights = [
      0,
      1,
      34e34,
      Number.MAX_SAFE_INTEGER,
      Number.MAX_VALUE
    ]
    rights.forEach(nr => {
      it('true on ' + nr, function () {
        const result = validate.isNatural(nr)
        result.must.be.true()
      })
    })
    const rights2 = [
      0,
      1,
      4
    ]
    rights2.forEach(nr => {
      it('true on ' + nr + ' with a maximum', function () {
        const result = validate.isNatural(nr, 4)
        result.must.be.true()
      })
    })
    const wrongs = [
      undefined,
      null,
      {},
      '',
      'string',
      new Date(),
      true,
      false,
      /abc/,
      Math.PI,
      3 / 5,
      Number.POSITIVE_INFINITY,
      -1,
      -Math.PI,
      Number.MIN_VALUE,
      Number.MIN_SAFE_INTEGER,
      Number.NEGATIVE_INFINITY,
      Number.NaN
    ]
    wrongs.forEach(w => {
      it('false on ' + w, function () {
        const result = validate.isNatural(w)
        result.must.be.false()
      })
    })
    const wrongs2 = [
      5,
      34e34,
      Number.MAX_SAFE_INTEGER,
      Number.MAX_VALUE
    ]
    wrongs2.forEach(w => {
      it('false on ' + w + ' with a maximum', function () {
        const result = validate.isNatural(w, 4)
        result.must.be.false()
      })
    })
  })
})
<commit_msg>fix not-too-long service name test<commit_after>/*
 * MIT License
 *
 * Copyright (c) 2017-2017 Jan Dockx
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/* eslint-env mocha */

const validate = require('../../lib/validate')
const x = require('cartesian')

const domain = 'dns-sd-lookup.toryt.org'
const protocols = ['tcp', 'udp']
// noinspection SpellCheckingInspection
const serviceType = 'a-Serv1ce-type'
const serviceSubTypes = [
  '',
  '_a-sub-service',
  '_a.complex.sub.service',
  'sub service type without an underscore' // this is allowed under RFC 6763
]
// noinspection SpellCheckingInspection
const instances = [
  'a-service-instance',
  'A Human Readable Sérvice Instance',
  'instances\\.with\\.escaped\\\\dots\\\\and\\.slashes',
  'instanceThatIsNotLongerThanIsAcceptableWhichIs63CharactersLabel'
]

function createService (prefix) {
  return prefix ? `${prefix}._${serviceType}` : `_${serviceType}`
}

function createSubPrefix (subtype) {
  return subtype ? `${subtype}._sub` : ''
}

const services = serviceSubTypes.map(createSubPrefix).concat(instances).map(createService)

function createFqdn (c) {
  return `${c.service}._${c.protocol}.${domain}`
}

const protocol = '_tcp.'
let almostTooLong = domain
const placesLeft = validate.maxLength - almostTooLong.length - protocol.length - serviceType.length - 2
const times = placesLeft / (validate.maxLabelLength + 1)
// noinspection SpellCheckingInspection
const maxLabel = 'abcdefghijklmnopqrstuvwxyz'.repeat(2) + 'abcdefghijk.'
console.assert(maxLabel.length === validate.maxLabelLength + 1)
almostTooLong = maxLabel.repeat(times) + almostTooLong
const rest = (placesLeft % (validate.maxLabelLength + 1)) - 1
almostTooLong = maxLabel.substring(0, rest) + '.' + almostTooLong
const notTooLong = `_${serviceType}.${protocol}${almostTooLong}`
console.assert(notTooLong.length === validate.maxLength)
const tooLong = `_${serviceType}.${protocol}z${almostTooLong}`
console.assert(tooLong.length === validate.maxLength + 1)

describe('validate', function () {
  describe('#isBaseServiceType', function () {
    describe('true', function () {
      protocols.forEach(protocol => {
        const candidate = `_${serviceType}._${protocol}.${domain}`
        it(`returns true for ${candidate}`, function () {
          const result = validate.isBaseServiceType(candidate)
          console.log('%s --> %s', candidate, result)
          result.must.be.true()
        })
      })
      it(`returns true for the max length`, function () {
        const result = validate.isBaseServiceType(notTooLong)
        console.log('%s --> %s', notTooLong, result)
        result.must.be.true()
      })
      const lookupCase = '_t1i-no-sub._tcp.dns-sd-lookup.toryt.org'
      it(`returns true for the lookup case`, function () {
        const result = validate.isBaseServiceType(lookupCase)
        console.log('%s --> %s', lookupCase, result)
        result.must.be.true()
      })
    })
    describe('false', function () {
      // noinspection SpellCheckingInspection
      const fqdns = [
        null,
        undefined,
        '',
        '# not _ a domain',
        'notcporupd.' + domain,
        serviceType + '.notcporupd.' + domain,
        '_udp.' + domain,
        '_tcp.' + domain,
        '_thisIsSxteenLong._udp.' + domain,
        '_thisIsSxteenLong._tcp.' + domain,
        '_service spaces._udp.' + domain,
        '_service spaces._tcp.' + domain,
        '_service_undersc._udp.' + domain,
        '_service_undersc._tcp.' + domain,
        '_service,comma._udp.' + domain,
        '_double--dash._tcp.' + domain,
        'notStartWith_._udp.' + domain,
        'notStartWith_._tcp.' + domain,
        '_-dash._tcp.' + domain,
        '_dash-._tcp.' + domain,
        '_9number._tcp.' + domain,
        '_number9._tcp.' + domain,
        `_${serviceType}._udp.a.thisIs999NotATld`,
        `_${serviceType}._udp.a.domain_with.an.underscore.com`,
        tooLong
      ]
      fqdns.forEach(fqdn => {
        it(`returns false for ${fqdn}`, function () {
          const result = validate.isBaseServiceType(fqdn)
          console.log('%s --> %s', fqdn, result)
          result.must.be.false()
        })
      })
    })
  })

  describe('#isServiceInstance', function () {
    describe('true', function () {
      // noinspection JSUnresolvedFunction
      const fqdns = x({
        instance: instances,
        protocol: protocols
      }).map(c => `${c.instance}._${serviceType}._${c.protocol}.${domain}`)
      fqdns.forEach(candidate => {
        it(`returns true for ${candidate}`, function () {
          const result = validate.isServiceInstance(candidate)
          console.log('%s --> %s', candidate, result)
          result.must.be.true()
        })
      })
      it(`returns true for the max length`, function () { // MUDO
        const result = validate.isServiceInstance(notTooLong)
        console.log('%s --> %s', notTooLong, result)
        result.must.be.true()
      })
      const lookupCase = 'instance 1._t1i-no-sub._tcp.dns-sd-lookup.toryt.org'
      it(`returns true for the lookup case`, function () {
        const result = validate.isServiceInstance(lookupCase)
        console.log('%s --> %s', lookupCase, result)
        result.must.be.true()
      })
    })
    describe('false', function () {
      // noinspection SpellCheckingInspection
      const fqdns = [
        null,
        undefined,
        '',
        'instance.not.a.service',
        // since we know that we delegate here to isBaseServiceType, we do not need to test the variants (white box)
        'instance.withAPartThatIsLonger-ThanIsAcceptableWhichIs63ACharactersLabels.lastLabel._service._tcp.' + domain,
        tooLong // MUDO
      ]
      fqdns.forEach(fqdn => {
        it(`returns false for ${fqdn}`, function () {
          const result = validate.isServiceInstance(fqdn)
          console.log('%s --> %s', fqdn, result)
          result.must.be.false()
        })
      })
    })
  })

  describe('#isServiceTypeOrInstanceFqdn', function () {
    describe('true', function () {
      // noinspection JSUnresolvedFunction
      const fqdns = x({
        service: services,
        protocol: protocols
      }).map(createFqdn)
      fqdns.forEach(fqdn => {
        it(`returns true for ${fqdn}`, function () {
          const result = validate.isServiceTypeOrInstanceFqdn(fqdn)
          console.log('%s --> %s', fqdn, result)
          result.must.be.true()
        })
      })
    })
    describe('false', function () {
      // noinspection SpellCheckingInspection
      const fqdns = [
        null,
        undefined,
        '',
        '# not _ a domain',
        'notcporupd.' + domain,
        serviceType + '.notcporupd.' + domain,
        '_udp.' + domain,
        '_tcp.' + domain,
        '_service contains spaces._udp.' + domain,
        '_service contains spaces._tcp.' + domain,
        'serviceDoesNotStartWith_._udp.' + domain,
        'serviceDoesNotStartWith_._tcp.' + domain,
        tooLong
      ]
      fqdns.forEach(fqdn => {
        it(`returns false for ${fqdn}`, function () {
          const result = validate.isServiceTypeOrInstanceFqdn(fqdn)
          console.log('%s --> %s', fqdn, result)
          result.must.be.false()
        })
      })
    })
  })

  describe('#isValidDomainNamePart', function () {
    it('true on a good part', function () {
      const result = validate.isValidDomainNamePart('a-valid09-€₰૱εέ𒀪©∭∏∇𐡀☯°廓DOMAIN-é--name-part')
      result.must.be.true()
    })
    const wrongParts = [
      '-starts-with-a-dash',
      'ends-with-a-dash-',
      'has-a-(-character',
      'has-a-}-character',
      'has-a-.-character',
      'has-a-]-character',
      'has-a-_-character',
      'has-a-+-character',
      'has-a-%20-character',
      'has-a-%-character',
      'has-a- -space',
      'theLengthOfAPartIsLimitedTo63CharactersThisIsTooLongBy1Character'
    ]
    wrongParts.forEach(part => {
      it('false on wrong part ' + part, function () {
        const result = validate.isValidDomainNamePart(part)
        result.must.be.false()
      })
    })
  })

  describe('#isNatural', function () {
    const rights = [
      0,
      1,
      34e34,
      Number.MAX_SAFE_INTEGER,
      Number.MAX_VALUE
    ]
    rights.forEach(nr => {
      it('true on ' + nr, function () {
        const result = validate.isNatural(nr)
        result.must.be.true()
      })
    })
    const rights2 = [
      0,
      1,
      4
    ]
    rights2.forEach(nr => {
      it('true on ' + nr + ' with a maximum', function () {
        const result = validate.isNatural(nr, 4)
        result.must.be.true()
      })
    })
    const wrongs = [
      undefined,
      null,
      {},
      '',
      'string',
      new Date(),
      true,
      false,
      /abc/,
      Math.PI,
      3 / 5,
      Number.POSITIVE_INFINITY,
      -1,
      -Math.PI,
      Number.MIN_VALUE,
      Number.MIN_SAFE_INTEGER,
      Number.NEGATIVE_INFINITY,
      Number.NaN
    ]
    wrongs.forEach(w => {
      it('false on ' + w, function () {
        const result = validate.isNatural(w)
        result.must.be.false()
      })
    })
    const wrongs2 = [
      5,
      34e34,
      Number.MAX_SAFE_INTEGER,
      Number.MAX_VALUE
    ]
    wrongs2.forEach(w => {
      it('false on ' + w + ' with a maximum', function () {
        const result = validate.isNatural(w, 4)
        result.must.be.false()
      })
    })
  })
})
<|endoftext|>


<commit_before>// Copyright 2002-2015, University of Colorado

/**
 * SO3 Molecule
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var AtomNode = require( 'NITROGLYCERIN/nodes/AtomNode' );
  var Element = require( 'NITROGLYCERIN/Element' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Vector2 = require( 'DOT/Vector2' );

  /**
   * @param {Object} [options]
   * @constructor
   */
  function SO3Node( options ) {

    options = _.extend( { atomOptions: {} }, options );

    // atoms
    var centerNode = new AtomNode( Element.S, options.atomOptions );
    var leftNode = new AtomNode( Element.O, options.atomOptions );
    var rightNode = new AtomNode( Element.O, options.atomOptions );
    var topNode = new AtomNode( Element.O, options.atomOptions );

    // layout
    topNode.x = centerNode.x + ( 0.1 * topNode.width );
    topNode.y = centerNode.left + ( 0.1 * topNode.height );
    leftNode.x = centerNode.left;
    leftNode.y = centerNode.y + ( 0.25 * leftNode.height );
    rightNode.x = centerNode.right;
    rightNode.y = centerNode.y + ( 0.25 * rightNode.height );

    options.children = [ new Node( {
      children: [ topNode, leftNode, centerNode, rightNode ],
      center: Vector2.ZERO // origin at geometric center
    } ) ];
    Node.call( this, options );
  }

  return inherit( Node, SO3Node );
} );
<commit_msg>#4 handle layout in options for SO3<commit_after>// Copyright 2002-2015, University of Colorado

/**
 * SO3 Molecule
 *
 * @author Chris Malley (PixelZoom, Inc.)
 */
define( function( require ) {
  'use strict';

  // modules
  var AtomNode = require( 'NITROGLYCERIN/nodes/AtomNode' );
  var Element = require( 'NITROGLYCERIN/Element' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Vector2 = require( 'DOT/Vector2' );

  /**
   * @param {Object} [options]
   * @constructor
   */
  function SO3Node( options ) {

    options = _.extend( { atomOptions: {} }, options );

    // atoms
    var centerNode = new AtomNode( Element.S, options.atomOptions );
    var leftNode = new AtomNode( Element.O, _.extend( {
      x: centerNode.left,
      y: centerNode.y + ( 0.2 * centerNode.height )
    }, options.atomOptions ) );
    var rightNode = new AtomNode( Element.O, _.extend( {
      x: centerNode.right,
      y: centerNode.y + ( 0.2 * centerNode.height )
    }, options.atomOptions ) );
    var topNode = new AtomNode( Element.O, _.extend( {
      x: centerNode.x + ( 0.08 * centerNode.width ),
      y: centerNode.left + ( 0.08 * centerNode.height )
    }, options.atomOptions ) );

    options.children = [ new Node( {
      children: [ topNode, leftNode, centerNode, rightNode ],
      center: Vector2.ZERO // origin at geometric center
    } ) ];
    Node.call( this, options );
  }

  return inherit( Node, SO3Node );
} );
<|endoftext|>


<commit_before>/*jshint white: false, strict: false, */
/*global define: false */

define( function ( require ) {

  /***
   * Component (prototype interface)
   *
   * A component is a basic unit of game functionality. Components are narrow in scope and are composed
   * together by entities to form game objects.
   */
  function Component( options ) {
      this.type = options.type || undefined;
      this.subtype = options.subtype || [];
      this.requires = options.requires || [];
      this.parent = null;
  }
  Component.prototype.getType = function() {
      return this.type;
  };
  Component.prototype.getSubtype = function() {
      return this.subtype;
  };

  return Component;
});<commit_msg>Simplify Component ctor, undefined is redundant.<commit_after>/*jshint white: false, strict: false, */
/*global define: false */

define( function ( require ) {

  /***
   * Component (prototype interface)
   *
   * A component is a basic unit of game functionality. Components are narrow in scope and are composed
   * together by entities to form game objects.
   */
  function Component( options ) {
      this.type = options.type;
      this.subtype = options.subtype || [];
      this.requires = options.requires || [];
      this.parent = null;
  }
  Component.prototype.getType = function() {
      return this.type;
  };
  Component.prototype.getSubtype = function() {
      return this.subtype;
  };

  return Component;
});
<|endoftext|>


<commit_before>var fs = require('fs')
  , test = require('tape')
  , path = require('path')
  , logRotate = require('../');

function fileName() { return __dirname +"/test.log_"+ Date.now(); }
function writes(s, ct) {
  var done = ct || 100
    , inv;

  inv = setInterval(function() {
    var chunk = Date.now() + "\n"; // 14 bytes
    s.write(chunk);
    if (! --done) {
      clearInterval(inv);
      s.end();
    }
  }, 1);
}

test('rotates based on file size option', function(t) {
  var files = []
    , file = fileName();

  var s = logRotate({ file: file, size: 600 });

  s.on('finish', function() {
    t.equals(files.length, 2, 'should have 2 files');
    // TODO clean up files
    t.end();
  })

  s.on('rotated', function(file) {
    files.push(file);
  });

  // start writing
  writes(s, 100);
});

test('keeps the appropriate number of rotated logs', function(t) {
  var file = fileName()
    , s = logRotate({ file: file, size: 600, keep: 5 });

  s.on('finish', function() {
    console.log('finished');
    fs.readdir(__dirname, function(err, files) {
      var kept = 0;
      for (var i = 0, l = files.length; i < l; i++) {
        if (files[i].indexOf(path.basename(file)) !== -1) kept++;
      }

      t.equals(kept, 5, 'should keep 5 files');
      // TODO clean up files
      t.end();
    });
  })

  // start writing
  writes(s, 200);
});
<commit_msg>add bytes test, create convenience funcs<commit_after>var fs = require('fs')
  , test = require('tape')
  , path = require('path')
  , logRotate = require('../');

function fileName() { return __dirname +"/test.log_"+ Date.now(); }
function getFiles(name, cb) {
  fs.readdir(__dirname,  function(err, files) {
    if (err) return cb(err);
    cb(null, files.filter(function(file) {
      return file.indexOf(path.basename(name)) !== -1;
    }));
  });
}
function cleanup(name) {
  getFiles(name, function(err, files) {
    while (files.length) fs.unlinkSync(__dirname +"/"+ files.shift());
  });
}

function getSizes(name, cb) {
  var sizes = []
    , ct = 0;
  function done(err) { if (! --ct) cb(err, sizes); }

  getFiles(name, function(err, files) {
    ct = files.length;
    files.forEach(function(file) {
      fs.stat(__dirname +'/'+ file, function(err, st) {
        sizes.push(st.size);
        done(err);
      });
    });
  });
}

function writes(s, ct, cb) {
  var done = ct || 100
    , inv;

  if (cb) { s.on('finish', cb); }

  inv = setInterval(function() {
    var chunk = Date.now() + "\n"; // 14 bytes
    s.write(chunk);
    if (! --done) {
      clearInterval(inv);
      s.end();
    }
  }, 1);
}

test('rotates based on file size option', function(t) {
  var files = []
    , file = fileName();

  var s = logRotate({ file: file, size: 600 });

  s.on('rotated', function(file) {
    files.push(file);
  });

  // start writing
  writes(s, 100, function() {
    t.equals(files.length, 2, 'should have 2 files');
    cleanup(file);
    t.end();
  });
});

test('writes the correct number of bytes', function(t) {
  var bytes = 0
    , file = fileName();

  var s = logRotate({ file: file, size: 600 });

  // start writing
  writes(s, 100, function() {
    getSizes(file, function(err, sizes) {
      var bytes = 0;
      while (sizes.length) bytes += sizes.shift();
      t.equals(bytes, 100*14, 'should have 2 files');
      cleanup(file);
      t.end();
    });
  });
});

test('keeps the appropriate number of rotated logs', function(t) {
  var file = fileName()
    , s = logRotate({ file: file, size: 600, keep: 5 });

  // start writing
  writes(s, 200, function() {
    getFiles(file, function(err, files) {
      t.equals(files.length, 5, 'should keep 5 files');
      cleanup(file);
      t.end();
    });
  });
});
<|endoftext|>


<commit_before>/*global jQuery:true*/
(function($, window){
	"use strict";

	function NumericInput( el ){
		this.el = el;
		this.$el = $( el );

		// prevent double init
		if( this.$el.data( "NumericInput" ) ){
			return;
		}

		this.$el.data( "NumericInput", this);

		this.allowFloat =
			this.$el.is( '[data-float]' ) || this.$el.is( '[data-numeric-input-float]' );
		this.allowNegative = this.$el.is( '[data-numeric-input-negative]' );

		var ua, isFirefoxDesktop, isSafari6, self = this;
		ua = navigator.userAgent.toLowerCase();

		// Issue #267 and #521
		// https://github.com/filamentgroup/lm-esales/issues/267
		// https://github.com/filamentgroup/lm-esales/issues/521
		// The goal is to target Firefox on Mac OS, Windows, and Linux (desktop)
		// UA ref from MDN for Firefox:
		// https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference
		// NOTE if they make one for windows mobile it may match "Windonws"
		isFirefoxDesktop = /windows|macintosh|linux/.test(ua) && /firefox/.test(ua);

		// Safari 6 removes leading zeros with type="number"
		// This is a bad user agent sniff but is limited to an outdated version
		// of Safari (this bug is fixed in 7+). This behavior cannot be feature
		// tested due to the bug not exhibiting when setting the .value property.
		isSafari6 = !!ua.match( /safari/i ) && !!ua.match( /version\/6\./i ) && !window.chrome;

		if( isFirefoxDesktop || isSafari6 ){
			if( this.$el.attr( "type" ) === "number" ) {
				this.$el.attr( "type", "text" );
			}
		}

		this.isNavDisabled =
			(this.$el.attr("data-numeric-input-nav-disabled") !== null &&
			 this.$el.attr("data-numeric-input-nav-disabled") !== undefined) ||
			(this.$el.attr("class") || "").indexOf("formcore-disable-spinner") >= 0;

		this.$el.on( "focus", function( e ) {
			self.initMaxlength();
		}).on( "keydown", function( e ) {
			self.onKeydown( e );
		}).on( "keypress", function( e ) {
			self.onKeypress( e );
		}).on( "paste", function( e ){
			self.onPaste( e );
		});
	};

	NumericInput.allowedKeys = [
		8, // Backspace
		9, // Tab
		13, // Enter
		27, // Escape
		33, // Pgup
		34, // Pgdown
		35, // End
		36, // Home
		37, // ArrowLeft
		38, // ArrowUp
		39, // ArrowRight
		40, // ArrowDown
		46 // Delete
	];

	NumericInput.prototype.initMaxlength = function(){
		// if maxLength isn't defined on `$el` then `parseInt` will return
		// `NaN` which is falsey meaning there is no max length. The max length
		// is then `Infinity`.

		// Will also accept the number of digits in max
		this.maxLength = parseInt( this.$el.attr( "maxlength" ), 10 ) ||
			( "" + ( Math.abs( parseInt( this.$el.attr( "max" ), 10 ) ) || "" ) ).length ||
			Infinity;
	};

	// Reference: https://github.com/wesbos/keycodes/blob/gh-pages/scripts.js
	NumericInput.prototype.isNumeric = function( code ){
		return code >= 48 && code <= 57 ||
			code >= 96 && code <= 105;
	};

	NumericInput.prototype.isCodeDecimalPoint = function( code ){
		return code === 110 || code === 190;
	};

	NumericInput.prototype.isCodeNegativeSign = function( code ){
		return code === 109 || code === 173 || code === 189;
	};

	NumericInput.prototype.onKeydown = function( event ){
		var allowed = false;
		var code = event.keyCode;

		// modifier keys and keys listed in allowedKeys property
		if( !code || this.isMetaKeyAllowed( event ) ){
			allowed = true;
		// numeric codes are always allowed without a shift modifier and below the maxlength
		} else if( this.isNumeric( code ) && !event.shiftKey && !this.isMaxLengthExceeded() ) {
			allowed = true;
		// typing when maxlength exceeded only if text selected
		} else if( this.isMaxLengthExceeded() && this.isInputTextSelected() ) {
			allowed = true;
		// allow negative signs
		} else if( this.allowNegative && this.isCodeNegativeSign( code ) && ( !this.el.value.length || this.el.value.indexOf( '-' ) === -1 ) ) {
			allowed = true;
		// allow decimal points
		} else if( this.allowFloat && this.isCodeDecimalPoint( code ) && ( !this.el.value.length || this.el.value.indexOf( '.' ) === -1 ) ) {
			allowed = true;
		}

		// Suppress "double action" if event prevented
		//
		// Kill keypress if the max length has been exceeded and the text
		// in the field isn't selected.
		//
		// Note that numeric inputs are not included in the types that
		// support the `maxlength` attribute. `max` support is failing in
		// our testing
		// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
		// (see `maxlength`)
		if( !allowed ) {
			event.preventDefault();
		}

		// record the keydown code for subsequent keypress checks/hairsplitting
		this.keydownCode = code;
	};

	// used to prevent mobile safari from allowing shifted numeric keycodes
	// because it doesn't set the `shiftKey` properly
	// Credit to: http://notes.ericjiang.com/posts/333
	NumericInput.keypressBlacklist = [
		33, // `!` aka Shift + 1
		64, // `@` aka Shift + 2
		35, // `#` aka Shift + 3
		36, // `$` aka Shift + 4
		94, // `^` aka Shift + 6
		38, // `&` aka Shift + 7
		42, // `*` aka Shift + 8
		40, // `(` aka Shift + 9
		41, // `)` aka Shift + 0
	];

	NumericInput.prototype.onKeypress = function( event ){
		var allowed = true;
		var code = event.keyCode;

		// indexOf not supported everywhere for arrays
		$.each(NumericInput.keypressBlacklist, function(i, e){
			if( e === code ) {
				allowed = false;
			}
		});

		// mobile safari registers % as 37 but firefox also does for the arrow
		// key, thankfully firefox registers the keydown event code as 37 also
		if(this.keydownCode == 53 && code == 37){
			allowed = false;
		}

		if( allowed ){
			return;
		}

		event.preventDefault();
	};

	NumericInput.prototype.onPaste = function( e ){
		var event = e.originalEvent || e;

		// http://stackoverflow.com/questions/6035071/intercept-paste-event-in-javascript
		var pastedText;

		if (window.clipboardData && window.clipboardData.getData) { // IE
			pastedText = window.clipboardData.getData('Text');
		} else if (event.clipboardData && event.clipboardData.getData) {
			pastedText = event.clipboardData.getData('text/plain');
		}

		// if we were unable to get the pasted text avoid doing anything
		if( !pastedText ){
			return;
		}

		// otherwise force the text to look right
		this.el.value = pastedText
			// remove signs that appear inside the string
			.replace(/(.+)\-(.+)/g, "$1$2")

			// remove all decimals beside the first
			.replace(/(.+[\.,].+)\.(.+)/g, "$1$2")

			// remove any non float/integer characters left
			.replace(/[^0-9\.\-,]*/g, "")

			// truncate the value to the maxlength
			.slice(0, this.maxLength);

		// prevent the original paste behavior
		event.preventDefault();
	};

	NumericInput.prototype.isMetaKeyAllowed = function( event ) {
		var isAllowed = false, key = event.keyCode;

		// indexOf not supported everywhere for arrays
		$.each(NumericInput.allowedKeys, function(i, e){
			if( e === key ) {
				isAllowed = true;
			}
		});

		// the up/down arrow key numeric navigation of values may be disabled
		if( this.isNavDisabled && ( key == 38 || key == 40 ) ){
			isAllowed = false;
		}

		return event.altKey || event.ctrlKey || event.metaKey || isAllowed;
	};

	NumericInput.prototype.isMaxLengthExceeded = function() {
		return this.maxLength !== undefined && this.$el.val().length >= this.maxLength;
	};

	NumericInput.prototype.isInputTextSelected = function() {
		var selectionText;

		// if firefox
		// use try-catch otherwise we get InvalidStateError when using selectionStart on type="number" in Chrome
		try {
			if( !isNaN( this.el.selectionStart ) || !isNaN( this.el.selectionEnd ) ) {
				return Math.abs( this.el.selectionStart - this.el.selectionEnd ) > 0;
			}
		} catch(e) {}

		// else if most browsers
		// else if ie8 or lower
		if( window.getSelection ) {
			selectionText = window.getSelection().toString();
		} else if( document.selection && document.selection.type != "Control" ) {
			selectionText = document.selection.createRange().text;
		}

		return selectionText ? this.$el.val().indexOf(selectionText) > -1 : false;
	};

	window.NumericInput = NumericInput;
}(jQuery, this));
<commit_msg>prevent unknown codes from going through on keydown<commit_after>/*global jQuery:true*/
(function($, window){
	"use strict";

	function NumericInput( el ){
		this.el = el;
		this.$el = $( el );

		// prevent double init
		if( this.$el.data( "NumericInput" ) ){
			return;
		}

		this.$el.data( "NumericInput", this);

		this.allowFloat =
			this.$el.is( '[data-float]' ) || this.$el.is( '[data-numeric-input-float]' );
		this.allowNegative = this.$el.is( '[data-numeric-input-negative]' );

		var ua, isFirefoxDesktop, isSafari6, self = this;
		ua = navigator.userAgent.toLowerCase();

		// Issue #267 and #521
		// https://github.com/filamentgroup/lm-esales/issues/267
		// https://github.com/filamentgroup/lm-esales/issues/521
		// The goal is to target Firefox on Mac OS, Windows, and Linux (desktop)
		// UA ref from MDN for Firefox:
		// https://developer.mozilla.org/en-US/docs/Web/HTTP/Gecko_user_agent_string_reference
		// NOTE if they make one for windows mobile it may match "Windonws"
		isFirefoxDesktop = /windows|macintosh|linux/.test(ua) && /firefox/.test(ua);

		// Safari 6 removes leading zeros with type="number"
		// This is a bad user agent sniff but is limited to an outdated version
		// of Safari (this bug is fixed in 7+). This behavior cannot be feature
		// tested due to the bug not exhibiting when setting the .value property.
		isSafari6 = !!ua.match( /safari/i ) && !!ua.match( /version\/6\./i ) && !window.chrome;

		if( isFirefoxDesktop || isSafari6 ){
			if( this.$el.attr( "type" ) === "number" ) {
				this.$el.attr( "type", "text" );
			}
		}

		this.isNavDisabled =
			(this.$el.attr("data-numeric-input-nav-disabled") !== null &&
			 this.$el.attr("data-numeric-input-nav-disabled") !== undefined) ||
			(this.$el.attr("class") || "").indexOf("formcore-disable-spinner") >= 0;

		this.$el.on( "focus", function( e ) {
			self.initMaxlength();
		}).on( "keydown", function( e ) {
			self.onKeydown( e );
		}).on( "keypress", function( e ) {
			self.onKeypress( e );
		}).on( "paste", function( e ){
			self.onPaste( e );
		});
	};

	NumericInput.allowedKeys = [
		8, // Backspace
		9, // Tab
		13, // Enter
		27, // Escape
		33, // Pgup
		34, // Pgdown
		35, // End
		36, // Home
		37, // ArrowLeft
		38, // ArrowUp
		39, // ArrowRight
		40, // ArrowDown
		46 // Delete
	];

	NumericInput.prototype.initMaxlength = function(){
		// if maxLength isn't defined on `$el` then `parseInt` will return
		// `NaN` which is falsey meaning there is no max length. The max length
		// is then `Infinity`.

		// Will also accept the number of digits in max
		this.maxLength = parseInt( this.$el.attr( "maxlength" ), 10 ) ||
			( "" + ( Math.abs( parseInt( this.$el.attr( "max" ), 10 ) ) || "" ) ).length ||
			Infinity;
	};

	// Reference: https://github.com/wesbos/keycodes/blob/gh-pages/scripts.js
	NumericInput.prototype.isNumeric = function( code ){
		return code >= 48 && code <= 57 ||
			code >= 96 && code <= 105;
	};

	NumericInput.prototype.isCodeDecimalPoint = function( code ){
		return code === 110 || code === 190;
	};

	NumericInput.prototype.isCodeNegativeSign = function( code ){
		return code === 109 || code === 173 || code === 189;
	};

	NumericInput.prototype.onKeydown = function( event ){
		var allowed = false;
		var code = event.keyCode;

		// modifier keys and keys listed in allowedKeys property
		if( code === undefined || this.isMetaKeyAllowed( event ) ){
			allowed = true;
		// numeric codes are always allowed without a shift modifier and below the maxlength
		} else if( this.isNumeric( code ) && !event.shiftKey && !this.isMaxLengthExceeded() ) {
			allowed = true;
		// typing when maxlength exceeded only if text selected
		} else if( this.isMaxLengthExceeded() && this.isInputTextSelected() ) {
			allowed = true;
		// allow negative signs
		} else if( this.allowNegative && this.isCodeNegativeSign( code ) && ( !this.el.value.length || this.el.value.indexOf( '-' ) === -1 ) ) {
			allowed = true;
		// allow decimal points
		} else if( this.allowFloat && this.isCodeDecimalPoint( code ) && ( !this.el.value.length || this.el.value.indexOf( '.' ) === -1 ) ) {
			allowed = true;
		}

		// Suppress "double action" if event prevented
		//
		// Kill keypress if the max length has been exceeded and the text
		// in the field isn't selected.
		//
		// Note that numeric inputs are not included in the types that
		// support the `maxlength` attribute. `max` support is failing in
		// our testing
		// https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input
		// (see `maxlength`)
		if( !allowed ) {
			event.preventDefault();
		}

		// record the keydown code for subsequent keypress checks/hairsplitting
		this.keydownCode = code;
	};

	// used to prevent mobile safari from allowing shifted numeric keycodes
	// because it doesn't set the `shiftKey` properly
	// Credit to: http://notes.ericjiang.com/posts/333
	NumericInput.keypressBlacklist = [
		33, // `!` aka Shift + 1
		64, // `@` aka Shift + 2
		35, // `#` aka Shift + 3
		36, // `$` aka Shift + 4
		// NOTE `%` aka Shift + 5 is handled in the body of `onKeypress`
		94, // `^` aka Shift + 6
		38, // `&` aka Shift + 7
		42, // `*` aka Shift + 8
		40, // `(` aka Shift + 9
		41  // `)` aka Shift + 0
	];

	NumericInput.prototype.onKeypress = function( event ){
		var allowed = true;
		var code = event.keyCode;

		// indexOf not supported everywhere for arrays
		$.each(NumericInput.keypressBlacklist, function(i, e){
			if( e === code ) {
				allowed = false;
			}
		});

		// mobile safari registers % as 37 but firefox also does for the arrow
		// key, thankfully firefox registers the keydown event code as 37 also
		if(this.keydownCode == 53 && code == 37){
			allowed = false;
		}

		if( allowed ){
			return;
		}

		event.preventDefault();
	};

	NumericInput.prototype.onPaste = function( e ){
		var event = e.originalEvent || e;

		// http://stackoverflow.com/questions/6035071/intercept-paste-event-in-javascript
		var pastedText;

		if (window.clipboardData && window.clipboardData.getData) { // IE
			pastedText = window.clipboardData.getData('Text');
		} else if (event.clipboardData && event.clipboardData.getData) {
			pastedText = event.clipboardData.getData('text/plain');
		}

		// if we were unable to get the pasted text avoid doing anything
		if( !pastedText ){
			return;
		}

		// otherwise force the text to look right
		this.el.value = pastedText
			// remove signs that appear inside the string
			.replace(/(.+)\-(.+)/g, "$1$2")

			// remove all decimals beside the first
			.replace(/(.+[\.,].+)\.(.+)/g, "$1$2")

			// remove any non float/integer characters left
			.replace(/[^0-9\.\-,]*/g, "")

			// truncate the value to the maxlength
			.slice(0, this.maxLength);

		// prevent the original paste behavior
		event.preventDefault();
	};

	NumericInput.prototype.isMetaKeyAllowed = function( event ) {
		var isAllowed = false, key = event.keyCode;

		// indexOf not supported everywhere for arrays
		$.each(NumericInput.allowedKeys, function(i, e){
			if( e === key ) {
				isAllowed = true;
			}
		});

		// the up/down arrow key numeric navigation of values may be disabled
		if( this.isNavDisabled && ( key == 38 || key == 40 ) ){
			isAllowed = false;
		}

		return event.altKey || event.ctrlKey || event.metaKey || isAllowed;
	};

	NumericInput.prototype.isMaxLengthExceeded = function() {
		return this.maxLength !== undefined && this.$el.val().length >= this.maxLength;
	};

	NumericInput.prototype.isInputTextSelected = function() {
		var selectionText;

		// if firefox
		// use try-catch otherwise we get InvalidStateError when using selectionStart on type="number" in Chrome
		try {
			if( !isNaN( this.el.selectionStart ) || !isNaN( this.el.selectionEnd ) ) {
				return Math.abs( this.el.selectionStart - this.el.selectionEnd ) > 0;
			}
		} catch(e) {}

		// else if most browsers
		// else if ie8 or lower
		if( window.getSelection ) {
			selectionText = window.getSelection().toString();
		} else if( document.selection && document.selection.type != "Control" ) {
			selectionText = document.selection.createRange().text;
		}

		return selectionText ? this.$el.val().indexOf(selectionText) > -1 : false;
	};

	window.NumericInput = NumericInput;
}(jQuery, this));
<|endoftext|>