<commit_before>(function() {

// TODO
// set/show username
// show user list

var userInfo = {};
var userList = []; // users on the chat
var logger;
var failMessagePosted = false;

// set up a logger
if (typeof console == "undefined" || typeof console.log == "undefined") {
	logger = function() { };
} else {
	logger = function(m) { console.log(m); }
}

/**
 * Fix &<>" in HTML string
 */
function escapeHTML(s) {
	return s.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
}

/**
 * Do something later
 */
function defer(f)
{
	setTimeout(f, 5);
}

/**
 * make random ID (UUID-ish), stolen from stackoverflow
 */
function randomID()
{
	var S4 = function() {
		return Math.floor(Math.random() * 0x10000).toString(16);
	};

	return (
			S4() + S4() + "-" +
			S4() + "-" +
			S4() + "-" +
			S4() + "-" +
			S4() + S4() + S4()
		);
}

/**
 * Add a message to the chat window
 */
function addChatMessage(username, msg) {
	var html = "
";
	var msgclass;

	if (username) {
		html += '' + username + ' ';
		html += ': ';
		msgclass = 'chat-message';
	} else {
		msgclass = 'system-message';
	}

	html += '' + msg + '
';

	// append HTML and scroll down
	$('#output-div').append(html);

	/*
	defer(function() {
		$('#output-div').animate({'scrollTop': $("#output-div").get(0).scrollHeight}, 500);
	});
	*/
	$('#output-div').get(0).scrollTop = $("#output-div").get(0).scrollHeight;
}

/**
 * Handle a long poll message
 */
function handleMessage(m) {

	switch(m.type) {
		case "message":
			addChatMessage(m.username, escapeHTML(m.message));
			break;

		case "newuser":
			userList.push({
				"publicid": m.publicid,
				"username": m.username
			});
			addChatMessage(null, m.username + " joined the chat");
			break;

		default:
			logger("unknown message type: " + m.type);
	}
}

/**
 * Run a long poll
 */
function longPoll() {
	logger("longpoll: start");

	function longPollSuccess(data, textStatus, jqXHR) {
		failMessagePosted = false

		logger("longpoll: got result");

		if (data.type == "status" && data.status == "error") {
			logger("longpoll error: " + data.message)
			addChatMessage(null, "Long poll error: " + data.message);
			setTimeout(function() { longPoll(); }, 5000);
			return
		}

		// process
		for (var i = 0, l = data.length; i < l; i++) {
			handleMessage(data[i])
		}

		// again!
		longPoll();
	}

	function longPollError(jqXHR, textStatus, errorThrown) {
		if (textStatus == "error") {
			logger("longpoll error: " + textStatus + " " + errorThrown)

			if (!failMessagePosted) {
				addChatMessage(null, "Error polling server");
				failMessagePosted = true
			}

			// again, after a delay
			setTimeout(function() { longPoll(); }, 5000);
		} else {
			logger("longpoll complete");

			// error is timeout or abort
			longPoll();
		}
	}

	$.ajax({
		"cache": false,
		"data": { "id": userInfo.id },
		"timeout": 120*1000,
		"url": "poll",
		"type": "POST",
		"success": longPollSuccess,
		"error": longPollError
	});
}

/**
 * Send generic command to server
 *
 * @param data object with data to send
 * @param success callback for success
 * @param error callback for error
 */
function sendCommand(data, success, error) {
	$.ajax({
		"cache": false,
		"data": data,
		"url": "cmd",
		"type": "POST",
		"success": success,
		"error": error
	});
}

/**
 * Send text to the server
 */
function sendText() {
	function success(data, textStatus, jqXHR) {
		if (data.type == "status" && data.status == "error") {
			addChatMessage(null, "Error sending data to server: " + data.message);
		}
		$('#input-field').val('');
	}

	function error(jqXHR, textStatus, errorThrown) {
		addChatMessage(null, "Error sending data to server");
	}

	var text = $('#input-field').val();
	text = $.trim(text);

	if (text == '') { return; }

	sendCommand({
			"command": "broadcast",
			"id": userInfo.id,
			"message": text
		}, success, error);
}

/**
 * Look for returns on the input form
 */
function inputKeyPressed(ev) {
	if (ev.which == 13) {
		sendText();
		return false;
	}
}

/**
 * Do a login
 */
function login(completeCallback) {
	function success(data, textStatus, jqXHR) {
		if (data.type == "status" && data.status == "error") {
			addChatMessage(null, "Error logging in: " + data.message);
			return
		}

		// get response
		userInfo.pubId = data.publicid;
		userInfo.username = data.username;

		// TODO: get user list in separate request
		//userList = data.userlist;

		if (completeCallback) {
			addChatMessage(null, "Welcome to the chat, " + userInfo.username);

			completeCallback();
		}
	}

	function error(jqXHR, textStatus, errorThrown) {
		logger("login error: " + textStatus);
	}

	userInfo.id = randomID();

	// TODO: set up with a username ahead of time
	sendCommand({
			"command": "login",
			"id": userInfo.id
		}, success, error);
}

/**
 * Stuff to do once login is complete
 */
function onLoginComplete() {
	longPoll();
	$('#send-button').on('click', sendText);
	$('#input-field').on('keypress', inputKeyPressed);
}

/**
 * On ready
 */
$(function() {
	login(onLoginComplete)
});

})();
<commit_msg>remove extra space<commit_after>(function() {

// TODO
// set/show username
// show user list

var userInfo = {};
var userList = []; // users on the chat
var logger;
var failMessagePosted = false;

// set up a logger
if (typeof console == "undefined" || typeof console.log == "undefined") {
	logger = function() { };
} else {
	logger = function(m) { console.log(m); }
}

/**
 * Fix &<>" in HTML string
 */
function escapeHTML(s) {
	return s.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """);
}

/**
 * Do something later
 */
function defer(f)
{
	setTimeout(f, 5);
}

/**
 * make random ID (UUID-ish), stolen from stackoverflow
 */
function randomID()
{
	var S4 = function() {
		return Math.floor(Math.random() * 0x10000).toString(16);
	};

	return (
			S4() + S4() + "-" +
			S4() + "-" +
			S4() + "-" +
			S4() + "-" +
			S4() + S4() + S4()
		);
}

/**
 * Add a message to the chat window
 */
function addChatMessage(username, msg) {
	var html = "
";
	var msgclass;

	if (username) {
		html += '' + username + '';
		html += ': ';
		msgclass = 'chat-message';
	} else {
		msgclass = 'system-message';
	}

	html += '' + msg + '
';

	// append HTML and scroll down
	$('#output-div').append(html);

	/*
	defer(function() {
		$('#output-div').animate({'scrollTop': $("#output-div").get(0).scrollHeight}, 500);
	});
	*/
	$('#output-div').get(0).scrollTop = $("#output-div").get(0).scrollHeight;
}

/**
 * Handle a long poll message
 */
function handleMessage(m) {

	switch(m.type) {
		case "message":
			addChatMessage(m.username, escapeHTML(m.message));
			break;

		case "newuser":
			userList.push({
				"publicid": m.publicid,
				"username": m.username
			});
			addChatMessage(null, m.username + " joined the chat");
			break;

		default:
			logger("unknown message type: " + m.type);
	}
}

/**
 * Run a long poll
 */
function longPoll() {
	logger("longpoll: start");

	function longPollSuccess(data, textStatus, jqXHR) {
		failMessagePosted = false

		logger("longpoll: got result");

		if (data.type == "status" && data.status == "error") {
			logger("longpoll error: " + data.message)
			addChatMessage(null, "Long poll error: " + data.message);
			setTimeout(function() { longPoll(); }, 5000);
			return
		}

		// process
		for (var i = 0, l = data.length; i < l; i++) {
			handleMessage(data[i])
		}

		// again!
		longPoll();
	}

	function longPollError(jqXHR, textStatus, errorThrown) {
		if (textStatus == "error") {
			logger("longpoll error: " + textStatus + " " + errorThrown)

			if (!failMessagePosted) {
				addChatMessage(null, "Error polling server");
				failMessagePosted = true
			}

			// again, after a delay
			setTimeout(function() { longPoll(); }, 5000);
		} else {
			logger("longpoll complete");

			// error is timeout or abort
			longPoll();
		}
	}

	$.ajax({
		"cache": false,
		"data": { "id": userInfo.id },
		"timeout": 120*1000,
		"url": "poll",
		"type": "POST",
		"success": longPollSuccess,
		"error": longPollError
	});
}

/**
 * Send generic command to server
 *
 * @param data object with data to send
 * @param success callback for success
 * @param error callback for error
 */
function sendCommand(data, success, error) {
	$.ajax({
		"cache": false,
		"data": data,
		"url": "cmd",
		"type": "POST",
		"success": success,
		"error": error
	});
}

/**
 * Send text to the server
 */
function sendText() {
	function success(data, textStatus, jqXHR) {
		if (data.type == "status" && data.status == "error") {
			addChatMessage(null, "Error sending data to server: " + data.message);
		}
		$('#input-field').val('');
	}

	function error(jqXHR, textStatus, errorThrown) {
		addChatMessage(null, "Error sending data to server");
	}

	var text = $('#input-field').val();
	text = $.trim(text);

	if (text == '') { return; }

	sendCommand({
			"command": "broadcast",
			"id": userInfo.id,
			"message": text
		}, success, error);
}

/**
 * Look for returns on the input form
 */
function inputKeyPressed(ev) {
	if (ev.which == 13) {
		sendText();
		return false;
	}
}

/**
 * Do a login
 */
function login(completeCallback) {
	function success(data, textStatus, jqXHR) {
		if (data.type == "status" && data.status == "error") {
			addChatMessage(null, "Error logging in: " + data.message);
			return
		}

		// get response
		userInfo.pubId = data.publicid;
		userInfo.username = data.username;

		// TODO: get user list in separate request
		//userList = data.userlist;

		if (completeCallback) {
			addChatMessage(null, "Welcome to the chat, " + userInfo.username);

			completeCallback();
		}
	}

	function error(jqXHR, textStatus, errorThrown) {
		logger("login error: " + textStatus);
	}

	userInfo.id = randomID();

	// TODO: set up with a username ahead of time
	sendCommand({
			"command": "login",
			"id": userInfo.id
		}, success, error);
}

/**
 * Stuff to do once login is complete
 */
function onLoginComplete() {
	longPoll();
	$('#send-button').on('click', sendText);
	$('#input-field').on('keypress', inputKeyPressed);
}

/**
 * On ready
 */
$(function() {
	login(onLoginComplete)
});

})();
<|endoftext|>


<commit_before>const models = require('./models')
const stripe = require('stripe')(process.env.STRIPE_KEY)

const scripts = {
  accountInfo: () => {
    models.User
      .findAll(
        {}
      )
      .then(users => {
        if (!users) return false

        if (users.length <= 0) return false

        const accountInfo = users.map(u => {
          if (!u.account_id) {
            return {
              user: u.email,
              active_account: false
            }
          }
          const accountDetails = stripe.accounts.retrieve(u.account_id).then(account => {
            return {
              user: u.email,
              active_account: true,
              account: account
            }
          })
          return accountDetails
        })
        // eslint-disable-next-line no-console
        console.log('users', accountInfo)
        return accountInfo
      }).catch(error => {
        // eslint-disable-next-line no-console
        console.log('error when search user: ', error)
        return false
      })
  }
}

if (process.argv[2]) scripts[process.argv[2]]()
<commit_msg>getting tasks with wrong issue urls<commit_after>const models = require('./models')
const Promise = require('bluebird')
const url = require('url')
const requestPromise = require('request-promise')
const stripe = require('stripe')(process.env.STRIPE_KEY)

const scripts = {
  accountInfo: () => {
    return models.User
      .findAll(
        {}
      )
      .then(users => {
        if (!users) return false

        if (users.length <= 0) return false

        const accountInfo = users.map(u => {
          if (!u.account_id) {
            return {
              user: u.email,
              active_account: false
            }
          }
          const accountDetails = stripe.accounts.retrieve(u.account_id).then(account => {
            return {
              user: u.email,
              active_account: true,
              account: account
            }
          })
          return accountDetails
        })
        // eslint-disable-next-line no-console
        console.log('users', accountInfo)
        return accountInfo
      }).catch(error => {
        // eslint-disable-next-line no-console
        console.log('error when search user: ', error)
        return false
      })
  },
  deleteInvalidTasks: () => {
    return models.Task
      .findAll(
        {
          where: {
            provider: 'github'
          }
        }
      )
      .then(tasks => {
        const tasksPromises = tasks.map(t => {
          const uri = t.url
          const splitIssueUrl = url.parse(uri).path.split('/')
          const userOrCompany = splitIssueUrl[1]
          const projectName = splitIssueUrl[2]
          const issueId = splitIssueUrl[4]
          if (!userOrCompany || !projectName || !issueId || isNaN(issueId)) return t
          return requestPromise({
            uri,
            resolveWithFullResponse: true
          }).then(response => {
            // eslint-disable-next-line no-console
            console.log('response status code for issue', response.statusCode, t.url)
            // eslint-disable-next-line no-console
            console.log('task successfull from Github', t.url)
            return false
          }).catch(e => {
            // eslint-disable-next-line no-console
            console.log('task with error from Github', t.url)
            return t
          })
        })
        return Promise.all(tasksPromises).then(results => {
          // eslint-disable-next-line no-console
          console.log('results from tasksPromises', results)
          return results.filter(t => t.id)
        })
      }).catch(error => {
        // eslint-disable-next-line no-console
        console.log('error when search task: ', error)
        return false
      })
  }
}

// if (process.argv[2]) scripts[process.argv[2]]()

module.exports = { scripts }
<|endoftext|>


<commit_before>(function(){
	var B={};

	var setAttribute='setAttribute';
	var getAttribute='getAttribute';

	var ex=function(v){return v!=null && v!=undefined;};
	B.exists=ex;

	var $id=function(id){
		if(typeof id=="string" && id!='')
			return document.getElementById(id);
		else if(id==='' || !ex(id))
			return null;
		else
			return id;
	};
	B.$id=$id;

	var cattr=document.all?'className':'class';
	function classRegex(c){return new RegExp('(?:\\s|^)'+c+'(?:\\s|$)');}

	B.hasClass=function(i,c){
		i=$id(i);
		if(!ex(i) || !i[getAttribute](cattr))
			return false;
		return i[getAttribute](cattr).match(classRegex(c));
	};
	B.addClass=function(i,c){
		i=$id(i);
		if(!B.hasClass(i,c)){
			var cn=i[getAttribute](cattr)||'';
			i[setAttribute](cattr,cn+' '+c);
		}
	};
	B.removeClass=function(i,c){
		i=$id(i);
		if(ex(i) && B.hasClass(i,c)){
			var cn=i[getAttribute](cattr).replace(classRegex(c),' ');
			i[setAttribute](cattr,cn);
		}
	};
	B.replaceClass=function(i,cO,cN,app){
		i=$id(i);
		if(ex(i)){
			var cn=i[getAttribute](cattr);
			if(B.hasClass(i,cO)) {
				cn=cn.replace(classRegex(cO),' '+cN+' ');
				i[setAttribute](cattr,cn);
			}else if(app)
				B.addClass(i, cN);
		}
	};
	B.setClass = function(i,c){
		i=$id(i);
		ex(i) && i[setAttribute](cattr,c);
	};

	B.create=function(n,att,p){
		var e;
		var appendChild = 'appendChild';
		if(n=='text')
			e=document.createTextNode(att['value']);
		else{
			e=document.createElement(n);
			for(var k in att){
				switch(k){
				default:
					e[setAttribute](k, att[k]);
					break;
				case 'id':
					if($id(att[k])==null || $id(att[k])==undefined)
						e[setAttribute]('id',att[k]);
					break;
				case 'style':
				case 'cssText':
					// doesn't seem to work with IE
					e[setAttribute]('cssText',att[k]);
					e[setAttribute]('style',att[k]);
					break;
				case 'class':
				case 'className':
					B.setClass(e,att[k]);
					break;
				case 'text':
					e[appendChild](document.createTextNode(att[k]));
					break;
				}
			}
		}
		//if the parent is given, the created node will be put in it
		if(ex($id(p)) || p && ex($id(p.element))){
			if(!ex(p.element)) $id(p)[appendChild](e);
			else{
				//if the elem has to be inserted before an element
				if(ex($id(p.before))) $id(p.element).insertBefore(e, $id(p.before));
				//else if it has to be inserted after an element
				else if(ex($id(p.after)) && ex($id(p.after).nextSibling)) $id(p.element).insertBefore($id(p.after).nextSibling);
				//else append
				else $id(p.element)[appendChild](e);
			}
		}
		return e;
	};

	B.addEvent=function(item,event,action,opt,args){
		opt=opt||{};
		args=args||new Array();
		item=$id(item);
		item[event+action]=function(evt){
			var scope=$id('scope' in opt?opt['scope']:window);
			if(!opt['skipEvent']) action.apply(scope,args.concat([evt]));
			else action.apply(scope,args);
		};

		if(item.attachEvent) item.attachEvent('on'+event,item[event+action]);
		else if(item.addEventListener) item.addEventListener(event,item[event+action],opt['propagate'] == true);
	};

	B.removeEvent=function(item,event,action,opt,args){
		opt=opt||{};
		args=args||new Array();
		item=$id(item);
		if(item.detachEvent) item.detachEvent('on'+event,item[event+action]);
		else if(item.removeEventListener) item.removeEventListener(event,item[event+action],opt['propagate'] == true);
		delete item[event+action];
	};

	B.appendChildren=function(i,c){
		var lC=c.length;
		i=$id(i);
		for(var k=0;k<lC;k++)
			i[appendChild](c[i]);
	};

	B.getStyle=function(i,s){
		if(i.currentStyle){
			s=s.replace(/\-(\w)/g,function(m,p1){return p1.toUpperCase();});
			var y=i.currentStyle[s];
		}else if(window.getComputedStyle){
			s=s.replace(/([A-Z])/g,function(p1){return "-"+p1.toLowerCase();});
			var y=document.defaultView.getComputedStyle(i,null).getPropertyValue(s);
		}
		return y;
	};

	B.getStyleValue=function(i,s){
		var v=B.getStyle(i, s);
		return isNaN(parseFloat(v))?0:v;
	};

	// Finally, set B visible to everybody
	window['B']=B;

	/******** MISC NON-BUTTERFLY FEATURES **********/

	function indexOf(v){
		for(var k in this)
			if(this[k]==v) return k;
		return -1;
	}

	Object.prototype.indexOf = Object.prototype.indexOf || indexOf;
	Array.prototype.indexOf = Array.prototype.indexOf || indexOf;

	function bind(obj){
		var s=Array.prototype.slice;
		args=s.call(arguments, 1);
		var self=this;
		var n=function(){};
		bound=function(){
			return self.apply(
				this instanceof n ? this : ( obj || {} ),
				args.concat(s.call(arguments))
			);
		};
		n.prototype=self.prototype;
		bound.prototype=new n();
		return bound;
	}
	Function.prototype.bind = Function.prototype.bind || bind;

})();
<commit_msg>vital tests added<commit_after>(function(){
	var B={};

	var setAttribute='setAttribute';
	var getAttribute='getAttribute';

	var ex=function(v){return v!=null && v!=undefined;};
	B.exists=ex;

	var $id=function(id){
		if(typeof id=="string" && id!='')
			return document.getElementById(id);
		else if(id==='' || !ex(id))
			return null;
		else
			return id;
	};
	B.$id=$id;

	var cattr=document.all?'className':'class';
	function classRegex(c){return new RegExp('(?:\\s|^)'+c+'(?:\\s|$)');}

	B.hasClass=function(i,c){
		i=$id(i);
		if(!ex(i) || !i[getAttribute](cattr))
			return false;
		return i[getAttribute](cattr).match(classRegex(c));
	};
	B.addClass=function(i,c){
		i=$id(i);
		if(!B.hasClass(i,c)){
			var cn=i[getAttribute](cattr)||'';
			i[setAttribute](cattr,cn+' '+c);
		}
	};
	B.removeClass=function(i,c){
		i=$id(i);
		if(ex(i) && B.hasClass(i,c)){
			var cn=i[getAttribute](cattr).replace(classRegex(c),' ');
			i[setAttribute](cattr,cn);
		}
	};
	B.replaceClass=function(i,cO,cN,app){
		i=$id(i);
		if(ex(i)){
			var cn=i[getAttribute](cattr);
			if(B.hasClass(i,cO)) {
				cn=cn.replace(classRegex(cO),' '+cN+' ');
				i[setAttribute](cattr,cn);
			}else if(app)
				B.addClass(i, cN);
		}
	};
	B.setClass = function(i,c){
		i=$id(i);
		ex(i) && i[setAttribute](cattr,c);
	};

	B.create=function(n,att,p){
		var e;
		var appendChild = 'appendChild';
		if(n=='text')
			e=document.createTextNode(att['value']);
		else{
			e=document.createElement(n);
			for(var k in att){
				switch(k){
				default:
					e[setAttribute](k, att[k]);
					break;
				case 'id':
					if($id(att[k])==null || $id(att[k])==undefined)
						e[setAttribute]('id',att[k]);
					break;
				case 'style':
				case 'cssText':
					// doesn't seem to work with IE
					e[setAttribute]('cssText',att[k]);
					e[setAttribute]('style',att[k]);
					break;
				case 'class':
				case 'className':
					B.setClass(e,att[k]);
					break;
				case 'text':
					e[appendChild](document.createTextNode(att[k]));
					break;
				}
			}
		}
		//if the parent is given, the created node will be put in it
		if(ex($id(p)) || p && ex($id(p.element))){
			if(!ex(p.element)) $id(p)[appendChild](e);
			else{
				//if the elem has to be inserted before an element
				if(ex($id(p.before))) $id(p.element).insertBefore(e, $id(p.before));
				//else if it has to be inserted after an element
				else if(ex($id(p.after)) && ex($id(p.after).nextSibling)) $id(p.element).insertBefore($id(p.after).nextSibling);
				//else append
				else $id(p.element)[appendChild](e);
			}
		}
		return e;
	};

	B.addEvent=function(item,event,action,opt,args){
		opt=opt||{};
		args=args||new Array();
		item=$id(item);
		item[event+action]=function(evt){
			var scope=$id('scope' in opt?opt['scope']:window);
			if(!opt['skipEvent']) action.apply(scope,args.concat([evt]));
			else action.apply(scope,args);
		};

		if(item.attachEvent) item.attachEvent('on'+event,item[event+action]);
		else if(item.addEventListener) item.addEventListener(event,item[event+action],opt['propagate'] == true);
	};

	B.removeEvent=function(item,event,action,opt,args){
		opt=opt||{};
		args=args||new Array();
		item=$id(item);
		if(item.detachEvent) item.detachEvent('on'+event,item[event+action]);
		else if(item.removeEventListener) item.removeEventListener(event,item[event+action],opt['propagate'] == true);
		delete item[event+action];
	};

	B.appendChildren=function(i,c){
		var lC=c.length;
		i=$id(i);
		for(var k=0;k<lC;k++)
			i[appendChild](c[i]);
	};

	B.getStyle=function(i,s){
		i=$id(i);
		if (!ex(i)) return;
		if(i.currentStyle){
			s=s.replace(/\-(\w)/g,function(m,p1){return p1.toUpperCase();});
			var y=i.currentStyle[s];
		}else if(window.getComputedStyle){
			s=s.replace(/([A-Z])/g,function(p1){return "-"+p1.toLowerCase();});
			var y=document.defaultView.getComputedStyle(i,null).getPropertyValue(s);
		}
		return y;
	};

	B.getStyleValue=function(i,s){
		var v=B.getStyle(i, s);
		return isNaN(parseFloat(v))?0:v;
	};

	// Finally, set B visible to everybody
	window['B']=B;

	/******** MISC NON-BUTTERFLY FEATURES **********/

	function indexOf(v){
		for(var k in this)
			if(this[k]==v) return k;
		return -1;
	}

	Object.prototype.indexOf = Object.prototype.indexOf || indexOf;
	Array.prototype.indexOf = Array.prototype.indexOf || indexOf;

	function bind(obj){
		var s=Array.prototype.slice;
		args=s.call(arguments, 1);
		var self=this;
		var n=function(){};
		bound=function(){
			return self.apply(
				this instanceof n ? this : ( obj || {} ),
				args.concat(s.call(arguments))
			);
		};
		n.prototype=self.prototype;
		bound.prototype=new n();
		return bound;
	}
	Function.prototype.bind = Function.prototype.bind || bind;

})();
<|endoftext|>


<commit_before>"use strict";

var FileInput = (function () {
    function FileInputException(message) {
        this.message = message;
        this.name = "FileInputException";
    }

    function FileInput() {
        var _data;
        Object.defineProperty(this, 'data', {
            get: function () {
                return _data;
            }
            ,
            set: function (v) {
                _data = v;
                this.onload(_data);
            }
        }
        );
        var options;
        if ((options=arguments[0]) instanceof Object) {
            var value, key;
            for (key in options) {
                switch ((value=options[key],key)) {
                    case "accept": this.accept = value;
                    break;
                    case "fileupload": this.createFileUpload(value);
                    break;
                    case "dragndrop": this.createDragDrop(value);
                    break;
                    case "onload": this.onload = value;
                    break;
                    case "onerror": this.onerror = value;
                    break;
                    case "dragndrop_hoverclass": this.dragndrop_hoverclass = value;
                    break;
                    case "type": this.type = value;
                    break;
                }
            }
        }
    }
    FileInput.TYPE = {
        ARRAYBUFFER: 0, DATAURL: 1, TEXT: 2, FILE:3
    }
    ;

    FileInput.prototype.accept = "";
    FileInput.prototype.dragndrop_hoverclass = "";
    FileInput.prototype.type=FileInput.TYPE.ARRAYBUFFER;

    function accepted(accept,file) {
        if (accept.trim()!="") {
            var accept_mime = accept.split(",").filter(function (a) {
                var acc = a.trim();
                return !(acc[0]==".")
            }).map(function (a) {
                var acc = a.trim();
                return new RegExp(a.trim().replace('*',"\\S*"));
            });
            var accept_ext = accept.split(",").filter(function (a) {
                var acc = a.trim();
                return (acc[0]==".")
            }).map(function (a) {
                var acc = a.trim();
                return new RegExp(a.trim().replace('*',"\\S*"));
            });
            var i,len;
            for (i=0,len=accept_mime.length;i<len;i++) {
                if (accept_mime[i].test(file.type)) {
                    return true;
                }
            }
            for (i=0,len=accept_ext.length;i<len;i++) {
                if (accept_ext[i].test(file.name)) {
                    return true;
                }
            }
        }else{
            return true;
        }
    }

    function readFile(file) {
        var fileInputObj  = this;
        if (file != undefined) {
            var reader = new FileReader();
            reader.onload = function (event) {
                fileInputObj.data = event.target.result;
            }
            ;
            if (accepted(this.accept,file)) {
                switch (this.type) {
                    case FileInput.TYPE.ARRAYBUFFER: reader.readAsArrayBuffer(file);
                    break;
                    case FileInput.TYPE.DATAURL: reader.readAsDataURL(file);
                    break;
                    case FileInput.TYPE.TEXT: reader.readAsText(file);
                    break;
                    case FileInput.TYPE.FILE: fileInputObj.data = file;
                    break;
                    default: throw new FileInputException("Unknown type: "+this.type);
                }
            }else{
                throw new FileInputException("Loaded file is not acceptable");
            }
        }
    }
    FileInput.prototype.createFileUpload = function (element) {
        var fileInputObj = this;
        element.type = "file";
        element.onchange = function (e) {
            try {
                e.stopPropagation();
                e.preventDefault();
                var file = e.target.files[0];
                readFile.call(fileInputObj, file);
                return false;
            }
            catch (e) {
                fileInputObj.onerror.call(fileInputObj,e);
            }
        }
        ;
    }
    ;
    FileInput.prototype.createDragDrop = function (element,hoverclass) {
        if (hoverclass == undefined) {
            hoverclass = "";
        }
        var fileInputObj = this;
        element.draggable = false;
        element.ondragover = function (e) {
            this.classList.add(hoverclass);
            e.preventDefault();
            return false;
        }
        ;
        element.ondragleave = element.ondragend = function (e) {
            this.classList.remove(hoverclass);
		    return false;
        }
        ;
        element.ondrop = function (e) {
            try {
                this.classList.remove(hoverclass);
                e.preventDefault();
                var file = e.dataTransfer.files[0];
                readFile.call(fileInputObj, file);
                return false;
            }
            catch (e) {
                fileInputObj.onerror.call(fileInputObj,e);
            }
        }
        ;
    }
    ;
    /*
    FileInput.prototype.createPaste = function (element) {
        var fileinput = this;
        element.onpaste = function(event){
          var clipboardData = (event.clipboardData || event.originalEvent.clipboardData);

          var data = null;

          if (clipboardData.files.length>0) {
              data = clipboardData.files;
          }else if (clipboardData.items.length>0) {
              data = clipboardData.items;
          }else{
              console.log("bail paste");
              return false;
          }
          console.log(data[0].getAsFile());
          //console.log(clipboardData.files);
          //console.log(clipboardData.items);

          console.log(data);

          return;
          readFile.call(fileInputObj,file);

          //var blob = items[0].getAsFile();
          //var reader = new FileReader();
          //reader.onload = function (event) {
    	  //	fileinput.data = event.target.result;
    	  //	fileinput.onload();
    	  //}
          //reader.readAsArrayBuffer(blob);
        }
    }*/

    FileInput.prototype.onload = function () {};
    FileInput.prototype.onerror = function () {};
    FileInput.prototype.data = null;
    return FileInput;
}
)();
<commit_msg>Remove comments<commit_after>"use strict";

var FileInput = (function () {
    function FileInputException(message) {
        this.message = message;
        this.name = "FileInputException";
    }

    function FileInput() {
        var _data;
        Object.defineProperty(this, 'data', {
            get: function () {
                return _data;
            }
            ,
            set: function (v) {
                _data = v;
                this.onload(_data);
            }
        }
        );
        var options;
        if ((options=arguments[0]) instanceof Object) {
            var value, key;
            for (key in options) {
                switch ((value=options[key],key)) {
                    case "accept": this.accept = value;
                    break;
                    case "fileupload": this.createFileUpload(value);
                    break;
                    case "dragndrop": this.createDragDrop(value);
                    break;
                    case "onload": this.onload = value;
                    break;
                    case "onerror": this.onerror = value;
                    break;
                    case "dragndrop_hoverclass": this.dragndrop_hoverclass = value;
                    break;
                    case "type": this.type = value;
                    break;
                }
            }
        }
    }
    FileInput.TYPE = {
        ARRAYBUFFER: 0, DATAURL: 1, TEXT: 2, FILE:3
    }
    ;

    FileInput.prototype.accept = "";
    FileInput.prototype.dragndrop_hoverclass = "";
    FileInput.prototype.type=FileInput.TYPE.ARRAYBUFFER;

    function accepted(accept,file) {
        if (accept.trim()!="") {
            var accept_mime = accept.split(",").filter(function (a) {
                var acc = a.trim();
                return !(acc[0]==".")
            }).map(function (a) {
                var acc = a.trim();
                return new RegExp(a.trim().replace('*',"\\S*"));
            });
            var accept_ext = accept.split(",").filter(function (a) {
                var acc = a.trim();
                return (acc[0]==".")
            }).map(function (a) {
                var acc = a.trim();
                return new RegExp(a.trim().replace('*',"\\S*"));
            });
            var i,len;
            for (i=0,len=accept_mime.length;i<len;i++) {
                if (accept_mime[i].test(file.type)) {
                    return true;
                }
            }
            for (i=0,len=accept_ext.length;i<len;i++) {
                if (accept_ext[i].test(file.name)) {
                    return true;
                }
            }
        }else{
            return true;
        }
    }

    function readFile(file) {
        var fileInputObj  = this;
        if (file != undefined) {
            var reader = new FileReader();
            reader.onload = function (event) {
                fileInputObj.data = event.target.result;
            }
            ;
            if (accepted(this.accept,file)) {
                switch (this.type) {
                    case FileInput.TYPE.ARRAYBUFFER: reader.readAsArrayBuffer(file);
                    break;
                    case FileInput.TYPE.DATAURL: reader.readAsDataURL(file);
                    break;
                    case FileInput.TYPE.TEXT: reader.readAsText(file);
                    break;
                    case FileInput.TYPE.FILE: fileInputObj.data = file;
                    break;
                    default: throw new FileInputException("Unknown type: "+this.type);
                }
            }else{
                throw new FileInputException("Loaded file is not acceptable");
            }
        }
    }
    FileInput.prototype.createFileUpload = function (element) {
        var fileInputObj = this;
        element.type = "file";
        element.onchange = function (e) {
            try {
                e.stopPropagation();
                e.preventDefault();
                var file = e.target.files[0];
                readFile.call(fileInputObj, file);
                return false;
            }
            catch (e) {
                fileInputObj.onerror.call(fileInputObj,e);
            }
        }
        ;
    }
    ;
    FileInput.prototype.createDragDrop = function (element,hoverclass) {
        if (hoverclass == undefined) {
            hoverclass = "";
        }
        var fileInputObj = this;
        element.draggable = false;
        element.ondragover = function (e) {
            this.classList.add(hoverclass);
            e.preventDefault();
            return false;
        }
        ;
        element.ondragleave = element.ondragend = function (e) {
            this.classList.remove(hoverclass);
		    return false;
        }
        ;
        element.ondrop = function (e) {
            try {
                this.classList.remove(hoverclass);
                e.preventDefault();
                var file = e.dataTransfer.files[0];
                readFile.call(fileInputObj, file);
                return false;
            }
            catch (e) {
                fileInputObj.onerror.call(fileInputObj,e);
            }
        }
        ;
    }
    ;

    FileInput.prototype.onload = function () {};
    FileInput.prototype.onerror = function () {};

    FileInput.prototype.data = null;
    return FileInput;
}
)();
<|endoftext|>


<commit_before>$(function() {
    $(window).scroll(function() {
        var scroll = $(window).scrollTop();
        if (scroll >= 500) {
            $(".header").addClass('smaller');
        } else {
            $(".header").removeClass("smaller");
        }
    });
});
<commit_msg>unsafe script issue<commit_after><script>
$(function() {
    $(window).scroll(function() {
        var scroll = $(window).scrollTop();
        if (scroll >= 500) {
            $(".header").addClass('smaller');
        } else {
            $(".header").removeClass("smaller");
        }
    });
});
</script>
<|endoftext|>


<commit_before>// Copyright 2013-2019, University of Colorado Boulder

/**
 * GaugeNode is a circular gauge that depicts some dynamic value.
 * This was originally ported from the speedometer node in forces-and-motion-basics.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author John Blanco (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var Circle = require( 'SCENERY/nodes/Circle' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Matrix3 = require( 'DOT/Matrix3' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Property = require( 'AXON/Property' );
  var Range = require( 'DOT/Range' );
  var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );
  var Shape = require( 'KITE/Shape' );
  var Tandem = require( 'TANDEM/Tandem' );
  var Text = require( 'SCENERY/nodes/Text' );
  var Util = require( 'DOT/Util' );

  /**
   * @param {Property.<number>} valueProperty - the portrayed value
   * @param {string} label - label to display (scaled to fit if necessary)
   * @param {Range} range - range of portrayable values. valueProperty is clamped to be within this range
   * @param {Object} [options]
   * @constructor
   */
  function GaugeNode( valueProperty, label, range, options ) {
    options = _.extend( {
      // Defaults
      radius: 100,
      backgroundFill: 'white',
      backgroundStroke: 'rgb( 85, 85, 85 )',
      backgroundLineWidth: 2,
      maxLabelWidthScale: 1.3, // {number} defines max width of the label, relative to the radius

      // 10 ticks each on the right side and left side, plus one in the center
      numberOfTicks: 21,

      // the top half of the gauge, plus PI/8 extended below the top half on each side
      span: Math.PI + Math.PI / 4, // {number} the visible span of the gauge value range, in radians
      majorTickLength: 10,
      minorTickLength: 5,
      majorTickLineWidth: 2,
      minorTickLineWidth: 1,

      // Determines whether the gauge will be updated when the value changes.
      // Use this to (for example) disable updates while a gauge is not visible.
      updateEnabledProperty: new Property( true ),
      tandem: Tandem.required
    }, options );

    assert && assert( range instanceof Range, 'range must be of type Range: ' + range );
    assert && assert( options.span <= 2 * Math.PI, 'options.span must be <= 2 * Math.PI: ' + options.span );

    Node.call( this );

    // @public (read-only) {number}
    this.radius = options.radius;

    var anglePerTick = options.span / options.numberOfTicks;
    var tandem = options.tandem;

    this.addChild( new Circle( this.radius, {
      fill: options.backgroundFill,
      stroke: options.backgroundStroke,
      lineWidth: options.backgroundLineWidth
    } ) );

    var foregroundNode = new Node( { pickable: false, tandem: tandem.createTandem( 'foregroundNode' ) } );
    this.addChild( foregroundNode );

    var needle = new Path( Shape.lineSegment( 0, 0, this.radius, 0 ), {
      stroke: 'red',
      lineWidth: 3
    } );
    foregroundNode.addChild( needle );

    var labelNode = new Text( label, {
      font: new PhetFont( 20 ),
      maxWidth: this.radius * options.maxLabelWidthScale,
      tandem: tandem.createTandem( 'labelNode' )
    } ).mutate( {
      centerX: 0,
      centerY: -this.radius / 3
    } );
    foregroundNode.addChild( labelNode );

    var pin = new Circle( 2, { fill: 'black' } );
    foregroundNode.addChild( pin );

    var totalAngle = ( options.numberOfTicks - 1 ) * anglePerTick;
    var startAngle = -1 / 2 * Math.PI - totalAngle / 2;
    var endAngle = startAngle + totalAngle;

    var scratchMatrix = new Matrix3();

    var updateNeedle = function() {
      if ( options.updateEnabledProperty.get() ) {
        if ( typeof( valueProperty.get() ) === 'number' ) {
          assert && assert( valueProperty.get() >= 0, 'GaugeNode representing negative values indicates a logic error' );

          // clamp value to valid range and map it to an angle
          valueProperty.value = Util.clamp( valueProperty.get(), range.min, range.max );
          var needleAngle = Util.linear( range.min, range.max, startAngle, endAngle, valueProperty.get() );

          // 2d rotation, but reusing our matrix above
          needle.setMatrix( scratchMatrix.setToRotationZ( needleAngle ) );
          needle.visible = true;
        }
        else {

          // Hide the needle if there is no value number value to portray.
          needle.visible = false;
        }
      }
    };

    valueProperty.link( updateNeedle );
    options.updateEnabledProperty.link( updateNeedle );

    // Render all of the ticks into two layers (since they have different strokes)
    // see https://github.com/phetsims/energy-skate-park-basics/issues/208
    var bigTicksShape = new Shape();
    var smallTicksShape = new Shape();

    // Add the tick marks
    for ( var i = 0; i < options.numberOfTicks; i++ ) {
      var tickAngle = i * anglePerTick + startAngle;

      var tickLength = i % 2 === 0 ? options.majorTickLength : options.minorTickLength;
      var x1 = ( this.radius - tickLength ) * Math.cos( tickAngle );
      var y1 = ( this.radius - tickLength ) * Math.sin( tickAngle );
      var x2 = this.radius * Math.cos( tickAngle );
      var y2 = this.radius * Math.sin( tickAngle );
      if ( i % 2 === 0 ) {
        bigTicksShape.moveTo( x1, y1 );
        bigTicksShape.lineTo( x2, y2 );
      }
      else {
        smallTicksShape.moveTo( x1, y1 );
        smallTicksShape.lineTo( x2, y2 );
      }
    }

    foregroundNode.addChild( new Path( bigTicksShape, { stroke: 'gray', lineWidth: options.majorTickLineWidth } ) );
    foregroundNode.addChild( new Path( smallTicksShape, { stroke: 'gray', lineWidth: options.minorTickLineWidth } ) );
    this.mutate( options );

    // @private
    this.disposeGaugeNode = function() {
      if ( valueProperty.hasListener( updateNeedle ) ) {
        valueProperty.unlink( updateNeedle );
      }

      if ( options.updateEnabledProperty.hasListener( updateNeedle ) ) {
        options.updateEnabledProperty.unlink( updateNeedle );
      }
    };
  }

  sceneryPhet.register( 'GaugeNode', GaugeNode );

  return inherit( Node, GaugeNode, {

    // @public
    dispose: function() {
      this.disposeGaugeNode();
      Node.prototype.dispose.call( this );
    }
  } );
} );<commit_msg>Dispose updateEnabledProperty if not provided in options, see https://github.com/phetsims/scenery-phet/issues/432<commit_after>// Copyright 2013-2019, University of Colorado Boulder

/**
 * GaugeNode is a circular gauge that depicts some dynamic value.
 * This was originally ported from the speedometer node in forces-and-motion-basics.
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author John Blanco (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var Circle = require( 'SCENERY/nodes/Circle' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Matrix3 = require( 'DOT/Matrix3' );
  var Node = require( 'SCENERY/nodes/Node' );
  var Path = require( 'SCENERY/nodes/Path' );
  var PhetFont = require( 'SCENERY_PHET/PhetFont' );
  var Property = require( 'AXON/Property' );
  var Range = require( 'DOT/Range' );
  var sceneryPhet = require( 'SCENERY_PHET/sceneryPhet' );
  var Shape = require( 'KITE/Shape' );
  var Tandem = require( 'TANDEM/Tandem' );
  var Text = require( 'SCENERY/nodes/Text' );
  var Util = require( 'DOT/Util' );

  /**
   * @param {Property.<number>} valueProperty - the portrayed value
   * @param {string} label - label to display (scaled to fit if necessary)
   * @param {Range} range - range of portrayable values. valueProperty is clamped to be within this range
   * @param {Object} [options]
   * @constructor
   */
  function GaugeNode( valueProperty, label, range, options ) {

    // flag if options.updateEnabledProperty is provided so we know how to correctly dispose it
    var updateEnabledPropertySupplied = options && options.hasOwnProperty( 'updateEnabledProperty' );

    options = _.extend( {
      // Defaults
      radius: 100,
      backgroundFill: 'white',
      backgroundStroke: 'rgb( 85, 85, 85 )',
      backgroundLineWidth: 2,
      maxLabelWidthScale: 1.3, // {number} defines max width of the label, relative to the radius

      // 10 ticks each on the right side and left side, plus one in the center
      numberOfTicks: 21,

      // the top half of the gauge, plus PI/8 extended below the top half on each side
      span: Math.PI + Math.PI / 4, // {number} the visible span of the gauge value range, in radians
      majorTickLength: 10,
      minorTickLength: 5,
      majorTickLineWidth: 2,
      minorTickLineWidth: 1,

      // Determines whether the gauge will be updated when the value changes.
      // Use this to (for example) disable updates while a gauge is not visible.
      updateEnabledProperty: new Property( true ),
      tandem: Tandem.required
    }, options );

    assert && assert( range instanceof Range, 'range must be of type Range: ' + range );
    assert && assert( options.span <= 2 * Math.PI, 'options.span must be <= 2 * Math.PI: ' + options.span );

    Node.call( this );

    // @public (read-only) {number}
    this.radius = options.radius;

    var anglePerTick = options.span / options.numberOfTicks;
    var tandem = options.tandem;

    this.addChild( new Circle( this.radius, {
      fill: options.backgroundFill,
      stroke: options.backgroundStroke,
      lineWidth: options.backgroundLineWidth
    } ) );

    var foregroundNode = new Node( { pickable: false, tandem: tandem.createTandem( 'foregroundNode' ) } );
    this.addChild( foregroundNode );

    var needle = new Path( Shape.lineSegment( 0, 0, this.radius, 0 ), {
      stroke: 'red',
      lineWidth: 3
    } );
    foregroundNode.addChild( needle );

    var labelNode = new Text( label, {
      font: new PhetFont( 20 ),
      maxWidth: this.radius * options.maxLabelWidthScale,
      tandem: tandem.createTandem( 'labelNode' )
    } ).mutate( {
      centerX: 0,
      centerY: -this.radius / 3
    } );
    foregroundNode.addChild( labelNode );

    var pin = new Circle( 2, { fill: 'black' } );
    foregroundNode.addChild( pin );

    var totalAngle = ( options.numberOfTicks - 1 ) * anglePerTick;
    var startAngle = -1 / 2 * Math.PI - totalAngle / 2;
    var endAngle = startAngle + totalAngle;

    var scratchMatrix = new Matrix3();

    var updateNeedle = function() {
      if ( options.updateEnabledProperty.get() ) {
        if ( typeof( valueProperty.get() ) === 'number' ) {
          assert && assert( valueProperty.get() >= 0, 'GaugeNode representing negative values indicates a logic error' );

          // clamp value to valid range and map it to an angle
          valueProperty.value = Util.clamp( valueProperty.get(), range.min, range.max );
          var needleAngle = Util.linear( range.min, range.max, startAngle, endAngle, valueProperty.get() );

          // 2d rotation, but reusing our matrix above
          needle.setMatrix( scratchMatrix.setToRotationZ( needleAngle ) );
          needle.visible = true;
        }
        else {

          // Hide the needle if there is no value number value to portray.
          needle.visible = false;
        }
      }
    };

    valueProperty.link( updateNeedle );
    options.updateEnabledProperty.link( updateNeedle );

    // Render all of the ticks into two layers (since they have different strokes)
    // see https://github.com/phetsims/energy-skate-park-basics/issues/208
    var bigTicksShape = new Shape();
    var smallTicksShape = new Shape();

    // Add the tick marks
    for ( var i = 0; i < options.numberOfTicks; i++ ) {
      var tickAngle = i * anglePerTick + startAngle;

      var tickLength = i % 2 === 0 ? options.majorTickLength : options.minorTickLength;
      var x1 = ( this.radius - tickLength ) * Math.cos( tickAngle );
      var y1 = ( this.radius - tickLength ) * Math.sin( tickAngle );
      var x2 = this.radius * Math.cos( tickAngle );
      var y2 = this.radius * Math.sin( tickAngle );
      if ( i % 2 === 0 ) {
        bigTicksShape.moveTo( x1, y1 );
        bigTicksShape.lineTo( x2, y2 );
      }
      else {
        smallTicksShape.moveTo( x1, y1 );
        smallTicksShape.lineTo( x2, y2 );
      }
    }

    foregroundNode.addChild( new Path( bigTicksShape, { stroke: 'gray', lineWidth: options.majorTickLineWidth } ) );
    foregroundNode.addChild( new Path( smallTicksShape, { stroke: 'gray', lineWidth: options.minorTickLineWidth } ) );
    this.mutate( options );

    // @private
    this.disposeGaugeNode = function() {
      if ( valueProperty.hasListener( updateNeedle ) ) {
        valueProperty.unlink( updateNeedle );
      }

      if ( updateEnabledPropertySupplied && options.updateEnabledProperty.hasListener( updateNeedle ) ) {
        options.updateEnabledProperty.unlink( updateNeedle );
      }
      else {
        options.updateEnabledProperty.dispose();
      }
    };
  }

  sceneryPhet.register( 'GaugeNode', GaugeNode );

  return inherit( Node, GaugeNode, {

    // @public
    dispose: function() {
      this.disposeGaugeNode();
      Node.prototype.dispose.call( this );
    }
  } );
} );<|endoftext|>


<commit_before>(function() {
  // optical computation
  function hyperfocal(focal, aperture, coc) {
    return focal + Math.pow(focal, 2) / (aperture * coc);
  }

  function limits(focal, subject, hyperfocal) {
    let hs = hyperfocal * subject;
    let sf = subject - focal;
    let inf = hyperfocal < (subject - focal);
    return [
      hs / (hyperfocal + sf),
      inf ? Infinity : hs / (hyperfocal - sf)
    ];
  }

  function circleOfConfusion(diagonal) {
    const divisor = 1500;
    return diagonal / divisor;
  }

  // utilities
  function cm(x) {
    return x / 100;
  }

  function mm(x) {
    return x / 1000;
  }

  function Multivariable(focal, aperture, subject, coc) {
    this.focal = focal;
    this.aperture = aperture;
    this.subject = subject;
    this.coc = coc;

    this.hyperfocal = function() {
      return hyperfocal(mm(this.focal), this.aperture, mm(this.coc));
    };

    this.limits = function() {
      return limits(mm(this.focal), this.subject, this.hyperfocal());
    };

    this.total = function() {
      let lims = this.limits();
      if (lims[0] > lims[1]) {
        return undefined;
      }
      return lims[1] - lims[0];
    }

    this.setAndGet = function(input, output) {
      let that = this;
      return function(val) {
        let copy = Object.create(that);
        copy[input] = val;
        return copy[output]();
      }
    };
  }

  function range(low, high, step = 1) {
    return Array.from(Array((high - low) / step).keys())
      .map(x => x * step + low);
  }

  function rangeIncl(low, high, step = 1) {
    return range(low, high, step).concat(high);
  }

  function roundSignificant(number, digits = 3) {
    let allDigits = Math.floor(Math.log10(number)) + 1;
    let factor = Math.pow(10, digits - allDigits);
    return Math.round(factor * number) / factor;
  }

  function formatLength(meters) {
    let rounded, unit = 'm';
    if (meters >= 1000) {
      rounded = Math.round(meters);
      unit = 'km';
    } else if (meters >= 1) {
      rounded = roundSignificant(meters);
    } else {
      unit = 'cm';
      rounded = Math.round(meters * 100);
    }

    return [rounded.toString().substr(0, 4), unit].join(' ');
  }

  function plot(x, y, params) {
    const xAxes = {
      aperture: {
        type: 'log',
        title: 'aperture',
        tickvals: fStops.filter((val, i) => i % 3 == 0),
        fixedrange: true
      },
      focal: {
        title: 'focal length [mm]',
        fixedrange: true
      },
      subject: {
        title: 'subject distance [m]',
        fixedrange: true
      },
    };

    const yAxes = {
      limits: {
        title: 'distance [m]',
        range: [0, 300],
        fixedrange: true
      },
      hyperfocal: {
        title: 'hyperfocal distance [m]',
        fixedrange: true
      },
      total: {
        title: 'total depth of field [m]',
        range: [0, 100],
        fixedrange: true
      }
    };

    let func = new Multivariable(
      params.focal, params.aperture, params.subject, params.coc
    ).setAndGet(x, y);

    let xSeries;
    switch (x) {
      case 'aperture':
        xSeries = fStops;
        break;
      case 'focal':
        switch (params.focalRange) {
          case 'wide':
            xSeries = rangeIncl(10, 28);
            break;
          case 'normal':
            xSeries = rangeIncl(24, 100);
            break;
          case 'tele':
            xSeries = rangeIncl(80, 300);
            break;
        }
        break;
      case 'subject':
        switch (params.subjectRange) {
          case 'near':
            xSeries = rangeIncl(0.1, 1, 0.1);
            break;
          case 'normal':
            xSeries = rangeIncl(1, 5, 0.05);
            break;
          case 'far':
            xSeries = rangeIncl(5, 10, 0.1);
            break;
          case 'super-far':
            xSeries = rangeIncl(10, 100);
            break;
        }
        break;
    }

    let ySeries = xSeries.map(func);
    let xAxis = xAxes[x];
    let yAxis = yAxes[y];

    let traces = [
      {
        x: xSeries,
        y: ySeries,
        line: {shape: 'spline'},
        hoverinfo: 'x+text',
        mode: 'lines'
      }
    ];

    if (y == 'limits') {
      let near = traces[0].y.map(x => x[0]);
      let far = traces[0].y.map(x => x[1]);
      traces[0].y = near;
      traces[0].fill = 'none';
      traces.push(Object.create(traces[0]))
      traces[1].y = far;
      traces[1].fill = 'tonexty';
    }

    if ('range' in yAxis) {
      yAxis.range[1] = Math.min(
        Math.max.apply(null, traces[traces.length - 1].y.filter(x => isFinite(x))),
        yAxis.range[1]
      );
    }

    traces.forEach(trace => trace.text = trace.y.map(formatLength));

    return {
      traces: traces,
      options: {
        margin: { t: 20, b: 35, l: 45, r: 20 },
        xaxis: xAxis,
        yaxis: yAxis,
        font: { family: 'Lato' },
        showlegend: false
      }
    };
  }

  // data
  const sensorSizes = [
    {symbol: 'full frame', crop: 1, diagonal: 43.2},
    {symbol: 'APS-C', crop: 1.53, diagonal: 28.3},
    {symbol: 'Canon APS-C', crop: 1.61, diagonal: 26.82},
    {symbol: 'Four Thirds', crop: 2, diagonal: 22.5},
    {symbol: '1 inch', crop: 2.72, diagonal: 15.86},
    {symbol: '1/2.3 inch', crop: 5.64, diagonal: 7.66},
    {symbol: '1/3 inch', crop: 7.21, diagonal: 6},
  ];

  const fStops = [
    1, 1.1, 1.2, 1.4, 1.6, 1.8, 2, 2.2, 2.5, 2.8, 3.2, 3.5, 4, 4.5,
    5, 5.6, 6.3, 7.1, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 29, 32
  ];

  // vue
  const app = new Vue({
    el: '#app',
    data: {
      sensorSizes: sensorSizes,
      fStops: fStops,
      // defaults
      sensorIndex: 0,
      yPlot: 'total',
      xPlot: 'aperture',
      xFocalRange: 'normal',
      xSubjectRange: 'normal',
      fStop: 6,
      logFocalEquiv: 1.7,
      logSubject: 0.3,
    },
    computed: {
      sensor: function() {
        return sensorSizes[this.sensorIndex];
      },
      focalEquiv: function() {
        return Math.min(Math.round(Math.pow(10, this.logFocalEquiv)), 300);
      },
      focal: function() {
        return Math.round(this.focalEquiv / this.sensor.crop);
      },
      aperture: function() {
        return fStops[this.fStop];
      },
      subject: function() {
        return Math.round(100 * Math.pow(10, this.logSubject)) / 100;
      }
    },
    watch: {
      sensorIndex: function() {
        this.plot();
      },
      yPlot: function(value) {
        if (value == 'hyperfocal' && this.xPlot == 'subject') {
          this.xPlot = 'aperture';
        }
        this.plot();
      },
      xPlot: function() {
        this.plot();
      },
      xFocalRange: function() {
        this.plot();
      },
      xSubjectRange: function() {
        this.plot();
      },
      fStop: function() {
        this.plot();
      },
      focalEquiv: function() {
        this.plot();
      },
      subject: function() {
        this.plot();
      }
    },
    methods: {
      formatLength: formatLength,
      plot: function() {
        const plotDiv = document.getElementById('plot')

        let plotConfig = plot(this.xPlot, this.yPlot, {
          crop: this.sensor.crop,
          focal: this.focal,
          aperture: this.aperture,
          subject: this.subject,
          coc: circleOfConfusion(this.sensor.diagonal),
          focalRange: this.xFocalRange,
          subjectRange: this.xSubjectRange,
        });

        Plotly.purge(plotDiv);
        Plotly.plot(plotDiv, plotConfig.traces, plotConfig.options,
          {
            displayModeBar: false,
            scrollZoom: false
          }
        );
      },
      keep: function() {
        //
      }
    }
  });

  // on ready
  app.plot();

  // auto resize
  window.addEventListener('resize', function() {
    Plotly.Plots.resize(
      Plotly.d3
        .select('#plot')
        .style({ width: '100%', height: '100%' })
        .node()
    );
  });
})();
<commit_msg>JS cleanup<commit_after>(function() {
  "use strict";
  // optical computation
  function hyperfocal(focal, aperture, coc) {
    return focal + Math.pow(focal, 2) / (aperture * coc);
  }

  function limits(focal, subject, hyperfocal) {
    let hs = hyperfocal * subject;
    let sf = subject - focal;
    let inf = hyperfocal < (subject - focal);
    return [
      hs / (hyperfocal + sf),
      inf ? Infinity : hs / (hyperfocal - sf)
    ];
  }

  function circleOfConfusion(diagonal) {
    const divisor = 1500;
    return diagonal / divisor;
  }

  // utilities
  function mm(x) {
    return x / 1000;
  }

  function Multivariable(focal, aperture, subject, coc) {
    this.focal = focal;
    this.aperture = aperture;
    this.subject = subject;
    this.coc = coc;

    this.hyperfocal = function() {
      return hyperfocal(mm(this.focal), this.aperture, mm(this.coc));
    };

    this.limits = function() {
      return limits(mm(this.focal), this.subject, this.hyperfocal());
    };

    this.total = function() {
      let lims = this.limits();
      if (lims[0] > lims[1]) {
        return undefined;
      }
      return lims[1] - lims[0];
    };

    this.setAndGet = function(input, output) {
      let that = this;
      return function(val) {
        let copy = Object.create(that);
        copy[input] = val;
        return copy[output]();
      };
    };
  }

  function range(low, high, step = 1) {
    return Array.from(Array((high - low) / step).keys())
      .map(x => x * step + low);
  }

  function rangeIncl(low, high, step = 1) {
    return range(low, high, step).concat(high);
  }

  function roundSignificant(number, digits = 3) {
    let allDigits = Math.floor(Math.log10(number)) + 1;
    let factor = Math.pow(10, digits - allDigits);
    return Math.round(factor * number) / factor;
  }

  function formatLength(meters) {
    let rounded, unit = 'm';
    if (meters >= 1000) {
      rounded = Math.round(meters);
      unit = 'km';
    } else if (meters >= 1) {
      rounded = roundSignificant(meters);
    } else {
      unit = 'cm';
      rounded = Math.round(meters * 100);
    }

    return [rounded.toString().substr(0, 4), unit].join(' ');
  }

  function plot(x, y, params) {
    const xAxes = {
      aperture: {
        type: 'log',
        title: 'aperture',
        tickvals: fStops.filter((val, i) => i % 3 == 0),
        fixedrange: true
      },
      focal: {
        title: 'focal length [mm]',
        fixedrange: true
      },
      subject: {
        title: 'subject distance [m]',
        fixedrange: true
      },
    };

    const yAxes = {
      limits: {
        title: 'distance [m]',
        range: [0, 300],
        fixedrange: true
      },
      hyperfocal: {
        title: 'hyperfocal distance [m]',
        fixedrange: true
      },
      total: {
        title: 'total depth of field [m]',
        range: [0, 100],
        fixedrange: true
      }
    };

    let func = new Multivariable(
      params.focal, params.aperture, params.subject, params.coc
    ).setAndGet(x, y);

    let xSeries;
    switch (x) {
      case 'aperture':
        xSeries = fStops;
        break;
      case 'focal':
        switch (params.focalRange) {
          case 'wide':
            xSeries = rangeIncl(10, 28);
            break;
          case 'normal':
            xSeries = rangeIncl(24, 100);
            break;
          case 'tele':
            xSeries = rangeIncl(80, 300);
            break;
        }
        break;
      case 'subject':
        switch (params.subjectRange) {
          case 'near':
            xSeries = rangeIncl(0.1, 1, 0.1);
            break;
          case 'normal':
            xSeries = rangeIncl(1, 5, 0.05);
            break;
          case 'far':
            xSeries = rangeIncl(5, 10, 0.1);
            break;
          case 'super-far':
            xSeries = rangeIncl(10, 100);
            break;
        }
        break;
    }

    let ySeries = xSeries.map(func);
    let xAxis = xAxes[x];
    let yAxis = yAxes[y];

    let traces = [
      {
        x: xSeries,
        y: ySeries,
        line: {shape: 'spline'},
        hoverinfo: 'x+text',
        mode: 'lines'
      }
    ];

    if (y == 'limits') {
      let near = traces[0].y.map(x => x[0]);
      let far = traces[0].y.map(x => x[1]);
      traces[0].y = near;
      traces[0].fill = 'none';
      traces.push(Object.create(traces[0]));
      traces[1].y = far;
      traces[1].fill = 'tonexty';
    }

    if ('range' in yAxis) {
      yAxis.range[1] = Math.min(
        Math.max.apply(null, traces[traces.length - 1].y.filter(x => isFinite(x))),
        yAxis.range[1]
      );
    }

    traces.forEach(trace => trace.text = trace.y.map(formatLength));

    return {
      traces: traces,
      options: {
        margin: { t: 20, b: 35, l: 45, r: 20 },
        xaxis: xAxis,
        yaxis: yAxis,
        font: { family: 'Lato' },
        showlegend: false
      }
    };
  }

  // data
  const sensorSizes = [
    {symbol: 'full frame', crop: 1, diagonal: 43.2},
    {symbol: 'APS-C', crop: 1.53, diagonal: 28.3},
    {symbol: 'Canon APS-C', crop: 1.61, diagonal: 26.82},
    {symbol: 'Four Thirds', crop: 2, diagonal: 22.5},
    {symbol: '1 inch', crop: 2.72, diagonal: 15.86},
    {symbol: '1/2.3 inch', crop: 5.64, diagonal: 7.66},
    {symbol: '1/3 inch', crop: 7.21, diagonal: 6},
  ];

  const fStops = [
    1, 1.1, 1.2, 1.4, 1.6, 1.8, 2, 2.2, 2.5, 2.8, 3.2, 3.5, 4, 4.5,
    5, 5.6, 6.3, 7.1, 8, 9, 10, 11, 13, 14, 16, 18, 20, 22, 25, 29, 32
  ];

  // vue
  const app = new Vue({
    el: '#app',
    data: {
      sensorSizes: sensorSizes,
      fStops: fStops,
      // defaults
      sensorIndex: 0,
      yPlot: 'total',
      xPlot: 'aperture',
      xFocalRange: 'normal',
      xSubjectRange: 'normal',
      fStop: 6,
      logFocalEquiv: 1.7,
      logSubject: 0.3,
    },
    computed: {
      sensor: function() {
        return sensorSizes[this.sensorIndex];
      },
      focalEquiv: function() {
        return Math.min(Math.round(Math.pow(10, this.logFocalEquiv)), 300);
      },
      focal: function() {
        return Math.round(this.focalEquiv / this.sensor.crop);
      },
      aperture: function() {
        return fStops[this.fStop];
      },
      subject: function() {
        return Math.round(100 * Math.pow(10, this.logSubject)) / 100;
      }
    },
    watch: {
      sensorIndex: function() {
        this.plot();
      },
      yPlot: function(value) {
        if (value == 'hyperfocal' && this.xPlot == 'subject') {
          this.xPlot = 'aperture';
        }
        this.plot();
      },
      xPlot: function() {
        this.plot();
      },
      xFocalRange: function() {
        this.plot();
      },
      xSubjectRange: function() {
        this.plot();
      },
      fStop: function() {
        this.plot();
      },
      focalEquiv: function() {
        this.plot();
      },
      subject: function() {
        this.plot();
      }
    },
    methods: {
      formatLength: formatLength,
      plot: function() {
        const plotDiv = document.getElementById('plot');

        let plotConfig = plot(this.xPlot, this.yPlot, {
          crop: this.sensor.crop,
          focal: this.focal,
          aperture: this.aperture,
          subject: this.subject,
          coc: circleOfConfusion(this.sensor.diagonal),
          focalRange: this.xFocalRange,
          subjectRange: this.xSubjectRange,
        });

        Plotly.purge(plotDiv);
        Plotly.plot(plotDiv, plotConfig.traces, plotConfig.options,
          {
            displayModeBar: false,
            scrollZoom: false
          }
        );
      },
      keep: function() {
        //
      }
    }
  });

  // on ready
  app.plot();

  // auto resize
  window.addEventListener('resize', function() {
    Plotly.Plots.resize(
      Plotly.d3
        .select('#plot')
        .style({ width: '100%', height: '100%' })
        .node()
    );
  });
})();
<|endoftext|>


<commit_before>function ScoreText(score, color, x, y, charPool) {
    this.digits = [];
    this.value = score;
    this.color = color;
    this.x = x;
    this.y = y;
    this.charPool = charPool;
    this.lifetime = 100;
    this.setScore(score);
}

ScoreText.colorPalette = [
  0x000000, // black
  0xcc0000, // red triangle
  0xcccc00, // yellow square
  0x00dd00, // green circle
  0x2244cc, // blue hexagon
  0xdd00dd, // purple downTriangle
  0xff9400, // orange rhombus
  0x000000
];

ScoreText.charAspectRatio = 36.0 / 48.0; // width/height

ScoreText.prototype.setScore = function (newScore) {
    var dec = newScore.toString();
    for (var i = this.digits.length; i < dec.length; i++) {
        var d = this.charPool.getFirstDead(true, 0, 0, 'number', dec.charAt(i));
        d.anchor.x = 0.5;
        d.anchor.y = 0.5;
        d.tint = ScoreText.colorPalette[this.color];
        this.digits.push(d);
    }
    while (dec.length < this.digits.length) {
        this.digits.pop().kill();
    }
    this.value = newScore;
};

ScoreText.prototype.showAtPosition = function (x, y, charHeight) {
    var dec = this.value.toString();
    var charWidth = charHeight * ScoreText.charAspectRatio;
    for (var i = 0; i < this.digits.length; i++) {
        var d = this.digits[i];
        d.x = x + (i - (this.digits.length - 1) / 2) * charWidth;
        d.y = y;
        var digit = "9";
        if (dec.length <= this.digits.length) {
            if (i < this.digits.length - dec.length) {
                digit = "0";
            }
            else {
                digit = dec.charAt(dec.length - this.digits.length + i);
            }
        }
        if (d.frameName !== digit) {
            d.frameName = digit;
        }
        d.width = charWidth;
        d.height = charHeight;
        //d.tint = ScoreText.colorPalette[this.color];
        d.alpha = this.lifetime / 100;
    }
};

ScoreText.prototype.popup = function (boardx, boardy, boardsize) {
    this.lifetime--;
    if (this.lifetime >= 90) {
        this.showAtPosition(
          boardx + boardsize * (this.x + 0.5),
          boardy + boardsize * (this.y + 0.5),
          boardsize * (2/3) * (100 - this.lifetime) / 10);
    }
    else {
        this.showAtPosition(
          boardx + boardsize * (this.x + 0.5),
          boardy + boardsize * (this.y + 0.5 + (this.lifetime - 90) / 100 * 0.4),
          boardsize * (2/3));
    }
    return this.lifetime <= 0;
};

ScoreText.prototype.showWithBounds = function (x, y, width, height) {
    var w = height * ScoreText.charAspectRatio * this.value.toString().length;
    if (w > width) {
        this.showAtPosition(x, y, height * width / w);
    }
    else {
        this.showAtPosition(x, y, height);
    }
};

ScoreText.prototype.kill = function () {
    for (var i = 0; i < this.digits.length; i++) {
        this.digits[i].kill();
    }
};
<commit_msg>fix ScoreText popup layer<commit_after>function ScoreText(score, color, x, y, charPool) {
    this.digits = [];
    this.value = score;
    this.color = color;
    this.x = x;
    this.y = y;
    this.charPool = charPool;
    this.lifetime = 100;
    this.setScore(score);
}

ScoreText.colorPalette = [
  0x000000, // black
  0xcc0000, // red triangle
  0xcccc00, // yellow square
  0x00dd00, // green circle
  0x2244cc, // blue hexagon
  0xdd00dd, // purple downTriangle
  0xff9400, // orange rhombus
  0x000000
];

ScoreText.charAspectRatio = 36.0 / 48.0; // width/height

ScoreText.prototype.setScore = function (newScore) {
    var dec = newScore.toString();
    for (var i = this.digits.length; i < dec.length; i++) {
        var d = this.charPool.getFirstDead(true, 0, 0, 'number', dec.charAt(i));
        d.bringToTop();
        d.anchor.x = 0.5;
        d.anchor.y = 0.5;
        d.tint = ScoreText.colorPalette[this.color];
        this.digits.push(d);
    }
    while (dec.length < this.digits.length) {
        this.digits.pop().kill();
    }
    this.value = newScore;
};

ScoreText.prototype.showAtPosition = function (x, y, charHeight) {
    var dec = this.value.toString();
    var charWidth = charHeight * ScoreText.charAspectRatio;
    for (var i = 0; i < this.digits.length; i++) {
        var d = this.digits[i];
        d.x = x + (i - (this.digits.length - 1) / 2) * charWidth;
        d.y = y;
        var digit = "9";
        if (dec.length <= this.digits.length) {
            if (i < this.digits.length - dec.length) {
                digit = "0";
            }
            else {
                digit = dec.charAt(dec.length - this.digits.length + i);
            }
        }
        if (d.frameName !== digit) {
            d.frameName = digit;
        }
        d.width = charWidth;
        d.height = charHeight;
        //d.tint = ScoreText.colorPalette[this.color];
        d.alpha = this.lifetime / 100;
    }
};

ScoreText.prototype.popup = function (boardx, boardy, boardsize) {
    this.lifetime--;
    if (this.lifetime >= 90) {
        this.showAtPosition(
          boardx + boardsize * (this.x + 0.5),
          boardy + boardsize * (this.y + 0.5),
          boardsize * (2/3) * (100 - this.lifetime) / 10);
    }
    else {
        this.showAtPosition(
          boardx + boardsize * (this.x + 0.5),
          boardy + boardsize * (this.y + 0.5 + (this.lifetime - 90) / 100 * 0.4),
          boardsize * (2/3));
    }
    return this.lifetime <= 0;
};

ScoreText.prototype.showWithBounds = function (x, y, width, height) {
    var w = height * ScoreText.charAspectRatio * this.value.toString().length;
    if (w > width) {
        this.showAtPosition(x, y, height * width / w);
    }
    else {
        this.showAtPosition(x, y, height);
    }
};

ScoreText.prototype.kill = function () {
    for (var i = 0; i < this.digits.length; i++) {
        this.digits[i].kill();
    }
};
<|endoftext|>


<commit_before>exports.commands = {
	l: 'lick',
        lick: function (target, room, user) {
		if (!target) return;
		target = this.splitTarget(target);
		var targetUser = this.targetUser;
		if (!targetUser || !targetUser.connected) {
			return this.sendReply("User " + this.targetUsername + " not found.");
		}
		if (!this.can('lick', targetUser, room)) return false;
		this.addModCommand("" + targetUser.name + " was " + msg);
		targetUser.popup("You have been " + msg);
	}
};
<commit_msg>Delete lick.js<commit_after><|endoftext|>


<commit_before>// Copyright (c) 2015 Walter Bender
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

// Based on ta-stats.py by Walter Bender

// TODO: CLEAN UP THIS LIST

// Assign each block to a bin.
const TACAT = {
    'newnote': 'note',
    'rest2': 'note',
    'osctime': 'note',
    'turtlenote': 'notefactor',

    'rhythmicdot': 'rhythm',
    'tie': 'rhythm',
    'multiplybeatfactor': 'rhythm',
    'dividebeatfactor': 'rhythm',
    'skipnotes': 'rhythm',
    'duplicatenotes': 'rhythm',
    'backward': 'rhythm',
    'setbpm': 'rhythm',
    'setmasterbpm': 'rhythm',
    'newswing2': 'rhythm',
    'drift': 'rhythm',

    'matrix': 'ignore',
    'tuplet2': 'ignore',
    'rhythm': 'ignore',
    'rhythmruler': 'ignore',
    'pitchstaircase': 'ignore',
    'pitchslider': 'ignore',
    'status': 'ignore',
    'pitchdrummatrix': 'ignore',
    'tempo': 'ignore',
    'modewidget': 'ignore',

    'bpmfactor': 'rhythmfactor',
    'beatfactor': 'rhythmfactor',
    'skipfactor': 'rhythmfactor',
    'duplicationfactor': 'rhythmfactor',

    'notename': 'ignore',
    'solfege': 'ignore',
    'drumname': 'ignore',
    'voicename': 'ignore',
    'modename': 'ignore',

    'hertz': 'pitch',
    'pitch': 'pitch',
    'steppitch': 'pitch',
    'sharp': 'pitch',
    'flat': 'pitch',

    'transpositionfactor': 'transposefactor',
    'consonantstepsizedown': 'transposefactor',
    'consonantstepsizeup': 'transposefactor',
    'turtlepitch': 'transposefactor',
    'number2pitch': 'transposefactor',
    'number2octave': 'transposefactor',

    'settransposition': 'transpose',
    'invert': 'transpose',
    'invert2': 'transpose',

    'diminished': 'pitchchord',
    'augmented': 'pitchchord',
    'perfect': 'pitchchord',
    'minor': 'pitchchord',
    'major': 'pitchchord',
    'interval': 'pitchchord',

    'staccatofactor': 'tonefactor',
    'sluffactor': 'tonefactor',
    'notevolumefactor': 'tonefactor',
    'key': 'tonefactor',

    'setkey': 'tone',
    'setkey2': 'tone',
    'setvoice': 'tone',
    'setdrum': 'tone',
    'articulation': 'tone',
    'setnotevolume2': 'tone',
    'newstaccato': 'tone',
    'newslur': 'tone',
    'swing': 'tone',
    'crescendo': 'tone',

    'clear': 'forward',
    'forward': 'forward',
    'back': 'forward',
    'left': 'forward',
    'right': 'forward',

    'arc': 'arc',
    'bezier': 'arc',
    'controlpoint1': 'arc',
    'controlpoint2': 'arc',

    'x': 'coord',
    'y': 'coord',
    'heading': 'coord',

    'setxy': 'setxy',
    'seth': 'setxy',

    'settranslucency': 'pen',
    'sethue': 'pen',
    'penup': 'pen',
    'setpensize': 'pen',
    'setcolor': 'pen',
    'pensize': 'pen',
    'color': 'pen',
    'setshade': 'pen',
    'setgray': 'pen',
    'gray': 'pen',
    'fillscreen': 'pen',
    'pendown': 'pen',

    'beginfill': 'fill',
    'fill': 'fill',
    'setfont': 'fill',
    'hollowline': 'fill',
    'endfill': 'fill',

    'plus': 'number',
    'minus': 'number',
    'multiply': 'number',
    'divide': 'number',
    'oneOf': 'number',
    'shade': 'pen',
    'mod': 'number',
    'int': 'number',
    'sqrt': 'number',
    'identity': 'number',

    'and': 'boolean',
    'or': 'boolean',
    'not': 'boolean',
    'greater': 'boolean',
    'less': 'boolean',
    'equal': 'boolean',

    'random': 'random',

    'repeat': 'repeat',
    'forever': 'repeat',

    'if': 'ifthen',
    'ifthenelse': 'ifthen',
    'while': 'ifthen',
    'until': 'ifthen',

    'action': 'action',
    'do': 'action',
    'nameddo': 'action',
    'listen': 'action',
    'dispatch': 'action',
    'calc': 'action',
    'doArg': 'action',
    'calcArg': 'action',
    'dispatch': 'action',
    'namedcalc': 'action',
    'nameddoArg': 'action',
    'namedcalcArg': 'action',
    'arg': 'action',
    'namedarg': 'action',
    'return': 'action',

    'storein': 'box',
    'namedbox': 'box',
    'increment': 'box',
    'incrementOne': 'box',

    'luminance': 'sensor',
    'mousex': 'sensor',
    'mousey': 'sensor',

    'drum': 'action',
    'start': 'action',

    'mousebutton': 'sensor',
    'keyboard': 'sensor',
    'readpixel': 'sensor',
    'see': 'sensor',
    'time': 'sensor',
    'sound': 'sensor',
    'volume': 'sensor',
    'resistance': 'sensor',
    'voltage': 'sensor',
    'kbinput': 'sensor',

    'video': 'media',
    'wait': 'media',
    'camera': 'media',
    'journal': 'media',
    'audio': 'media',
    'show': 'media',
    'setscale': 'media',
    'savepix': 'media',
    'savesvg': 'media',
    'mediawait': 'media',
    'mediapause': 'media',
    'mediastop': 'media',
    'mediaplay': 'media',
    'speak': 'media',
    'sinewave': 'media',
    'description': 'media',

    'push': 'extras',
    'pop': 'extras',
    'printheap': 'extras',
    'clearheap': 'extras',
    'isheapempty': 'extras',
    'chr': 'extras',

    'int': 'number',

    'myfunction': 'python',
    'userdefined': 'python',
    'box': 'box',
    'showHeap': 'extras',
    'emptyHeap': 'extras',
    'loadblock': 'python',
    'loadpalette': 'python',

    'hidden': 'ignore',
    'hiddennoflow': 'ignore',
    'text': 'ignore',
    'number': 'ignore',
    'hspace': 'ignore',
    'vspace': 'ignore'
};

// Assign each bin to a palette.
const TAPAL = {
    'note': 'notesp',
    'rhythm': 'notesp',
    'rhythmfactor': 'notesp',
    'notefactor': 'notesp',
    'pitch': 'pitchp',
    'pitchchord': 'pitchp',
    'transpose': 'pitchp',
    'transposefactor': 'pitchp',
    'tone': 'tonep',
    'forward': 'turtlep',
    'arc': 'turtlep',
    'coord': 'turtlep',
    'setxy': 'turtlep',
    'pen': 'penp',
    'fill': 'penp',
    'random': 'numberp',
    'boolean': 'numberp',
    'repeat': 'flowp',
    'ifthen': 'flowp',
    'action': 'boxp',
    'box': 'boxp',
    'sensor': 'sensorp',
    'media': 'mediap',
    'extras': 'extrasp',
    'number': 'numberp',
    'python': 'extrasp',
    'ignore': 'numberp'
};

// Assign a score for each bin.
const TASCORE = {
    'note': 1,
    'notefactor': 1,
    'rhythm': 5,
    'rhythmfactor': 5,
    'pitchchord': 3,
    'pitch': 1,
    'transpose': 5,
    'transposefactor': 5,
    'tone': 5,
    'forward': 3,
    'arc': 3,
    'setxy': 2.5,
    'coord': 4,
    'turtlep': 5,
    'pen': 2.5,
    'fill': 2.5,
    'penp': 5,
    'number': .5,
    'boolean': 2.5,
    'random': 2.5,
    'repeat': 2.5,
    'ifthen': 7.5,
    'flowp': 10,
    'box': 7.5,
    'action': 7.5,
    'boxp': 0,
    'media': 5,
    'mediap': 0,
    'python': 5,
    'extras': 5,
    'extrasp': 0,
    'ignore': 0,
    'sensor': 5,
    'sensorp': 0
};

// The list of palettes.
const PALS = ['notesp', 'pitchp', 'tonep', 'turtlep', 'penp', 'numberp', 'flowp', 'boxp', 'sensorp', 'mediap', 'extrasp'];

const PALLABELS = [_('rhythm'), _('pitch'), _('tone'), _('turtle'), _('pen'), _('number'), _('flow'), _('action'), _('sensors'), _('media'), _('extras')];

function analyzeProject(blocks) {
    // Parse block data and generate score based on rubric

    var blockList = [];
    for (var blk = 0; blk < blocks.blockList.length; blk++) {
        if (blocks.blockList[blk].trash) {
            continue;
        }
        // Check to see if the block is solo or has no child flow..
        switch(blocks.blockList[blk].name) {
        case 'rhythmicdot':
        case 'tie':
        case 'drift':
        case 'osctime':
        case 'sharp':
        case 'flat':
        case 'fill':
        case 'hollowline':
	case 'start':
            if (blocks.blockList[blk].connections[1] == null) {
		continue;
	    }
            break;
        case 'note':
        case 'dividebeatfactor':
        case 'multiplybeatfactor':
        case 'duplicatenotes':
        case 'skipnotes':
        case 'setbpm':
        case 'settransposition':
        case 'staccato':
        case 'slur':
        case 'swing':
        case 'crescendo':
        case 'setnotevolume2':
        case 'action':
            if (blocks.blockList[blk].connections[2] == null) {
		continue;
	    }
	    break;
        case 'invert':
        case 'tuplet2':
            if (blocks.blockList[blk].connections[3] == null) {
		continue;
	    }
	    break;
	default:
            if (blocks.blockList[blk].connections[0] == null && last(blocks.blockList[blk].connections) == null) {
		continue;
	    }
	    break;
	}
        blockList.push(blocks.blockList[blk].name);
    }

    scores = [];
    for (var i = 0; i < PALS.length; i++) {
        scores.push(0);
    }

    cats = [];
    pals = [];

    for (var b = 0; b < blockList.length; b++) {
        if (blockList[b] in TACAT) {
            if (!(TACAT[blockList[b]] in cats)) {
                cats.push(TACAT[blockList[b]]);
            }
        } else {
           console.log(blockList[b] + ' not in catalog');
        }
    }
    for (var c = 0; c < cats.length; c++) {
        if (cats[c] in TAPAL) {
            if (!(TAPAL[cats[c]] in pals)) {
                pals.push(TAPAL[cats[c]]);
            }
        }
    }

    for (var c = 0; c < cats.length; c++) {
        if (cats[c] in TASCORE) {
            scores[PALS.indexOf(TAPAL[cats[c]])] += TASCORE[cats[c]];
        }
    }

    for (var p = 0; p < pals.length; p++) {
        if (pals[p] in TASCORE) {
            scores[PALS.indexOf(pals[p])] += TASCORE[pals[p]];
        }
    }

    return scores;
};

function scoreToChartData(scores) {
    var normalizedScores = [];
    var maxScore = 0;
    for (var i = 0; i < scores.length; i++) {
        if (scores[i] > maxScore) {
            maxScore = scores[i];
        }
    }

    if (maxScore > 0) {
        var scale = 100 / maxScore;
    } else {
        var scale = 1;
    }

    if (scale > 1) {
        scale = 1;
    }

    for (var i = 0; i < scores.length; i++) {
        normalizedScores.push(scores[i] * scale);
    }

    var data = {
        labels: PALLABELS,
        datasets: [
            {
                label: '',
                fillColor: 'rgba(220,220,220,0.4)',
                strokeColor: 'rgba(220,220,220,1)',
                pointColor: 'rgba(220,220,220,1)',
                pointStrokeColor: '#fff',
                pointHighlightFill: '#fff',
                pointHighlightStroke: 'rgba(220,220,220,1)',
                data: normalizedScores,
            },
        ]
    };

    return data;
};

function getChartOptions(callback) {
    return {
    // Callback for rendering chart into a bitmap
    onAnimationComplete: callback,

    //Boolean - Whether to show lines for each scale point
    scaleShowLine : true,

    //Boolean - Whether we show the angle lines out of the radar
    angleShowLineOut : true,

    //Boolean - Whether to show labels on the scale
    scaleShowLabels : false,

    // Boolean - Whether the scale should begin at zero
    scaleBeginAtZero : true,

    //String - Colour of the angle line
    angleLineColor : 'rgba(0,0,0,.2)',

    //Number - Pixel width of the angle line
    angleLineWidth : 10,

    //String - Point label font declaration
    pointLabelFontFamily : 'Arial',

    //String - Point label font weight
    pointLabelFontStyle : 'normal',

    //Number - Point label font size in pixels
    pointLabelFontSize : 30,

    //String - Point label font colour
    pointLabelFontColor : '#666',

    //Boolean - Whether to show a dot for each point
    pointDot : true,

    //Number - Radius of each point dot in pixels
    pointDotRadius : 18,

    //Number - Pixel width of point dot stroke
    pointDotStrokeWidth : 6,

    //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
    pointHitDetectionRadius : 20,

    //Boolean - Whether to show a stroke for datasets
    datasetStroke : true,

    //Number - Pixel width of dataset stroke
    datasetStrokeWidth : 12,

    //Boolean - Whether to fill the dataset with a colour
    datasetFill : true,

    //String - A legend template
    legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%>
<span style=\"background-color:<%=datasets[i].strokeColor%>\"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
<%}%>
"
    }
};
<commit_msg>add print to analytics<commit_after>// Copyright (c) 2015 Walter Bender
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the The GNU Affero General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// You should have received a copy of the GNU Affero General Public
// License along with this library; if not, write to the Free Software
// Foundation, 51 Franklin Street, Suite 500 Boston, MA 02110-1335 USA

// Based on ta-stats.py by Walter Bender

// TODO: CLEAN UP THIS LIST

// Assign each block to a bin.
const TACAT = {
    'newnote': 'note',
    'rest2': 'note',
    'osctime': 'note',
    'turtlenote': 'notefactor',

    'rhythmicdot': 'rhythm',
    'tie': 'rhythm',
    'multiplybeatfactor': 'rhythm',
    'dividebeatfactor': 'rhythm',
    'skipnotes': 'rhythm',
    'duplicatenotes': 'rhythm',
    'backward': 'rhythm',
    'setbpm': 'rhythm',
    'setmasterbpm': 'rhythm',
    'newswing2': 'rhythm',
    'drift': 'rhythm',

    'matrix': 'ignore',
    'tuplet2': 'ignore',
    'rhythm': 'ignore',
    'rhythmruler': 'ignore',
    'pitchstaircase': 'ignore',
    'pitchslider': 'ignore',
    'status': 'ignore',
    'pitchdrummatrix': 'ignore',
    'tempo': 'ignore',
    'modewidget': 'ignore',

    'bpmfactor': 'rhythmfactor',
    'beatfactor': 'rhythmfactor',
    'skipfactor': 'rhythmfactor',
    'duplicationfactor': 'rhythmfactor',

    'notename': 'ignore',
    'solfege': 'ignore',
    'drumname': 'ignore',
    'voicename': 'ignore',
    'modename': 'ignore',

    'hertz': 'pitch',
    'pitch': 'pitch',
    'steppitch': 'pitch',
    'sharp': 'pitch',
    'flat': 'pitch',

    'transpositionfactor': 'transposefactor',
    'consonantstepsizedown': 'transposefactor',
    'consonantstepsizeup': 'transposefactor',
    'turtlepitch': 'transposefactor',
    'number2pitch': 'transposefactor',
    'number2octave': 'transposefactor',

    'settransposition': 'transpose',
    'invert': 'transpose',
    'invert2': 'transpose',

    'diminished': 'pitchchord',
    'augmented': 'pitchchord',
    'perfect': 'pitchchord',
    'minor': 'pitchchord',
    'major': 'pitchchord',
    'interval': 'pitchchord',

    'staccatofactor': 'tonefactor',
    'sluffactor': 'tonefactor',
    'notevolumefactor': 'tonefactor',
    'key': 'tonefactor',

    'setkey': 'tone',
    'setkey2': 'tone',
    'setvoice': 'tone',
    'setdrum': 'tone',
    'articulation': 'tone',
    'setnotevolume2': 'tone',
    'newstaccato': 'tone',
    'newslur': 'tone',
    'swing': 'tone',
    'crescendo': 'tone',

    'clear': 'forward',
    'forward': 'forward',
    'back': 'forward',
    'left': 'forward',
    'right': 'forward',

    'arc': 'arc',
    'bezier': 'arc',
    'controlpoint1': 'arc',
    'controlpoint2': 'arc',

    'x': 'coord',
    'y': 'coord',
    'heading': 'coord',

    'setxy': 'setxy',
    'seth': 'setxy',

    'settranslucency': 'pen',
    'sethue': 'pen',
    'penup': 'pen',
    'setpensize': 'pen',
    'setcolor': 'pen',
    'pensize': 'pen',
    'color': 'pen',
    'setshade': 'pen',
    'setgray': 'pen',
    'gray': 'pen',
    'fillscreen': 'pen',
    'pendown': 'pen',

    'beginfill': 'fill',
    'fill': 'fill',
    'setfont': 'fill',
    'hollowline': 'fill',
    'endfill': 'fill',

    'plus': 'number',
    'minus': 'number',
    'multiply': 'number',
    'divide': 'number',
    'oneOf': 'number',
    'shade': 'pen',
    'mod': 'number',
    'int': 'number',
    'sqrt': 'number',
    'identity': 'number',

    'and': 'boolean',
    'or': 'boolean',
    'not': 'boolean',
    'greater': 'boolean',
    'less': 'boolean',
    'equal': 'boolean',

    'random': 'random',

    'repeat': 'repeat',
    'forever': 'repeat',

    'if': 'ifthen',
    'ifthenelse': 'ifthen',
    'while': 'ifthen',
    'until': 'ifthen',

    'action': 'action',
    'do': 'action',
    'nameddo': 'action',
    'listen': 'action',
    'dispatch': 'action',
    'calc': 'action',
    'doArg': 'action',
    'calcArg': 'action',
    'dispatch': 'action',
    'namedcalc': 'action',
    'nameddoArg': 'action',
    'namedcalcArg': 'action',
    'arg': 'action',
    'namedarg': 'action',
    'return': 'action',

    'storein': 'box',
    'namedbox': 'box',
    'increment': 'box',
    'incrementOne': 'box',

    'luminance': 'sensor',
    'mousex': 'sensor',
    'mousey': 'sensor',

    'drum': 'action',
    'start': 'action',

    'mousebutton': 'sensor',
    'keyboard': 'sensor',
    'readpixel': 'sensor',
    'see': 'sensor',
    'time': 'sensor',
    'sound': 'sensor',
    'volume': 'sensor',
    'resistance': 'sensor',
    'voltage': 'sensor',
    'kbinput': 'sensor',

    'video': 'media',
    'wait': 'media',
    'camera': 'media',
    'journal': 'media',
    'audio': 'media',
    'show': 'media',
    'setscale': 'media',
    'savepix': 'media',
    'savesvg': 'media',
    'mediawait': 'media',
    'mediapause': 'media',
    'mediastop': 'media',
    'mediaplay': 'media',
    'speak': 'media',
    'sinewave': 'media',
    'description': 'media',

    'push': 'extras',
    'pop': 'extras',
    'printheap': 'extras',
    'clearheap': 'extras',
    'isheapempty': 'extras',
    'chr': 'extras',
    'print': 'extras',

    'int': 'number',

    'myfunction': 'python',
    'userdefined': 'python',
    'box': 'box',
    'showHeap': 'extras',
    'emptyHeap': 'extras',
    'loadblock': 'python',
    'loadpalette': 'python',

    'hidden': 'ignore',
    'hiddennoflow': 'ignore',
    'text': 'ignore',
    'number': 'ignore',
    'hspace': 'ignore',
    'vspace': 'ignore'
};

// Assign each bin to a palette.
const TAPAL = {
    'note': 'notesp',
    'rhythm': 'notesp',
    'rhythmfactor': 'notesp',
    'notefactor': 'notesp',
    'pitch': 'pitchp',
    'pitchchord': 'pitchp',
    'transpose': 'pitchp',
    'transposefactor': 'pitchp',
    'tone': 'tonep',
    'forward': 'turtlep',
    'arc': 'turtlep',
    'coord': 'turtlep',
    'setxy': 'turtlep',
    'pen': 'penp',
    'fill': 'penp',
    'random': 'numberp',
    'boolean': 'numberp',
    'repeat': 'flowp',
    'ifthen': 'flowp',
    'action': 'boxp',
    'box': 'boxp',
    'sensor': 'sensorp',
    'media': 'mediap',
    'extras': 'extrasp',
    'number': 'numberp',
    'python': 'extrasp',
    'ignore': 'numberp'
};

// Assign a score for each bin.
const TASCORE = {
    'note': 1,
    'notefactor': 1,
    'rhythm': 5,
    'rhythmfactor': 5,
    'pitchchord': 3,
    'pitch': 1,
    'transpose': 5,
    'transposefactor': 5,
    'tone': 5,
    'forward': 3,
    'arc': 3,
    'setxy': 2.5,
    'coord': 4,
    'turtlep': 5,
    'pen': 2.5,
    'fill': 2.5,
    'penp': 5,
    'number': .5,
    'boolean': 2.5,
    'random': 2.5,
    'repeat': 2.5,
    'ifthen': 7.5,
    'flowp': 10,
    'box': 7.5,
    'action': 7.5,
    'boxp': 0,
    'media': 5,
    'mediap': 0,
    'python': 5,
    'extras': 5,
    'extrasp': 0,
    'ignore': 0,
    'sensor': 5,
    'sensorp': 0
};

// The list of palettes.
const PALS = ['notesp', 'pitchp', 'tonep', 'turtlep', 'penp', 'numberp', 'flowp', 'boxp', 'sensorp', 'mediap', 'extrasp'];

const PALLABELS = [_('rhythm'), _('pitch'), _('tone'), _('turtle'), _('pen'), _('number'), _('flow'), _('action'), _('sensors'), _('media'), _('extras')];

function analyzeProject(blocks) {
    // Parse block data and generate score based on rubric

    var blockList = [];
    for (var blk = 0; blk < blocks.blockList.length; blk++) {
        if (blocks.blockList[blk].trash) {
            continue;
        }
        // Check to see if the block is solo or has no child flow..
        switch(blocks.blockList[blk].name) {
        case 'rhythmicdot':
        case 'tie':
        case 'drift':
        case 'osctime':
        case 'sharp':
        case 'flat':
        case 'fill':
        case 'hollowline':
	case 'start':
            if (blocks.blockList[blk].connections[1] == null) {
		continue;
	    }
            break;
        case 'note':
        case 'dividebeatfactor':
        case 'multiplybeatfactor':
        case 'duplicatenotes':
        case 'skipnotes':
        case 'setbpm':
        case 'settransposition':
        case 'staccato':
        case 'slur':
        case 'swing':
        case 'crescendo':
        case 'setnotevolume2':
        case 'action':
            if (blocks.blockList[blk].connections[2] == null) {
		continue;
	    }
	    break;
        case 'invert':
        case 'tuplet2':
            if (blocks.blockList[blk].connections[3] == null) {
		continue;
	    }
	    break;
	default:
            if (blocks.blockList[blk].connections[0] == null && last(blocks.blockList[blk].connections) == null) {
		continue;
	    }
	    break;
	}
        blockList.push(blocks.blockList[blk].name);
    }

    scores = [];
    for (var i = 0; i < PALS.length; i++) {
        scores.push(0);
    }

    cats = [];
    pals = [];

    for (var b = 0; b < blockList.length; b++) {
        if (blockList[b] in TACAT) {
            if (!(TACAT[blockList[b]] in cats)) {
                cats.push(TACAT[blockList[b]]);
            }
        } else {
           console.log(blockList[b] + ' not in catalog');
        }
    }
    for (var c = 0; c < cats.length; c++) {
        if (cats[c] in TAPAL) {
            if (!(TAPAL[cats[c]] in pals)) {
                pals.push(TAPAL[cats[c]]);
            }
        }
    }

    for (var c = 0; c < cats.length; c++) {
        if (cats[c] in TASCORE) {
            scores[PALS.indexOf(TAPAL[cats[c]])] += TASCORE[cats[c]];
        }
    }

    for (var p = 0; p < pals.length; p++) {
        if (pals[p] in TASCORE) {
            scores[PALS.indexOf(pals[p])] += TASCORE[pals[p]];
        }
    }

    return scores;
};

function scoreToChartData(scores) {
    var normalizedScores = [];
    var maxScore = 0;
    for (var i = 0; i < scores.length; i++) {
        if (scores[i] > maxScore) {
            maxScore = scores[i];
        }
    }

    if (maxScore > 0) {
        var scale = 100 / maxScore;
    } else {
        var scale = 1;
    }

    if (scale > 1) {
        scale = 1;
    }

    for (var i = 0; i < scores.length; i++) {
        normalizedScores.push(scores[i] * scale);
    }

    var data = {
        labels: PALLABELS,
        datasets: [
            {
                label: '',
                fillColor: 'rgba(220,220,220,0.4)',
                strokeColor: 'rgba(220,220,220,1)',
                pointColor: 'rgba(220,220,220,1)',
                pointStrokeColor: '#fff',
                pointHighlightFill: '#fff',
                pointHighlightStroke: 'rgba(220,220,220,1)',
                data: normalizedScores,
            },
        ]
    };

    return data;
};

function getChartOptions(callback) {
    return {
    // Callback for rendering chart into a bitmap
    onAnimationComplete: callback,

    //Boolean - Whether to show lines for each scale point
    scaleShowLine : true,

    //Boolean - Whether we show the angle lines out of the radar
    angleShowLineOut : true,

    //Boolean - Whether to show labels on the scale
    scaleShowLabels : false,

    // Boolean - Whether the scale should begin at zero
    scaleBeginAtZero : true,

    //String - Colour of the angle line
    angleLineColor : 'rgba(0,0,0,.2)',

    //Number - Pixel width of the angle line
    angleLineWidth : 10,

    //String - Point label font declaration
    pointLabelFontFamily : 'Arial',

    //String - Point label font weight
    pointLabelFontStyle : 'normal',

    //Number - Point label font size in pixels
    pointLabelFontSize : 30,

    //String - Point label font colour
    pointLabelFontColor : '#666',

    //Boolean - Whether to show a dot for each point
    pointDot : true,

    //Number - Radius of each point dot in pixels
    pointDotRadius : 18,

    //Number - Pixel width of point dot stroke
    pointDotStrokeWidth : 6,

    //Number - amount extra to add to the radius to cater for hit detection outside the drawn point
    pointHitDetectionRadius : 20,

    //Boolean - Whether to show a stroke for datasets
    datasetStroke : true,

    //Number - Pixel width of dataset stroke
    datasetStrokeWidth : 12,

    //Boolean - Whether to fill the dataset with a colour
    datasetFill : true,

    //String - A legend template
    legendTemplate : "<ul class=\"<%=name.toLowerCase()%>-legend\"><% for (var i=0; i<datasets.length; i++){%>
<span style=\"background-color:<%=datasets[i].strokeColor%>\"><%if(datasets[i].label){%><%=datasets[i].label%><%}%>
<%}%>
"
    }
};
<|endoftext|>