<commit_before>(function(jQuery) {
"use strict";

var $ = jQuery;

var plugin = Echo.Plugin.manifest("ReplyCardUI", "Echo.StreamServer.Controls.Stream.Item");

if (Echo.Plugin.isDefined(plugin)) return;

plugin.init = function() {
	var self = this, item = this.component;
	this.extendTemplate("insertAsLastChild", "content", plugin.templates.form);
	this.extendTemplate("insertAsFirstChild", "avatar", plugin.templates.avatar);
	// insert element to add addditional spacing above the children container
	this.extendTemplate("insertBefore", "expandChildren", plugin.templates.childrenSpacing);
	var form = Echo.Utils.get(Echo.Variables, this._getSubmitKey());
	$.each(form || {}, function(key, value) {
		self.set(key, value);
	});
	item.addButtonSpec("ReplyCardUI", this._assembleButton());
	this.set("documentClickHandler", this._getClickHandler());
	$(document).on('click', this.get("documentClickHandler"));
};

plugin.config = {
	"actionString": "Add a comment...",
	"pauseTimeout": 0,
	"submitFormTimeout": 300,
	"compactFormTimeout": 200,
	"displayCompactForm": false
};

plugin.labels = {
	"replyControl": "Reply"
};

plugin.dependencies = [{
	"control": "Echo.StreamServer.Controls.Submit",
	"url": "{config:cdnBaseURL.sdk}/streamserver.pack.js"
}];

plugin.events = {
	"Echo.StreamServer.Controls.Stream.Plugins.ReplyCardUI.onFormExpand": function(topic, args) {
		var item = this.component;
		var context = item.config.get("context");
		if (this.get("expanded") && context && context !== args.context) {
			this._hideSubmit();
		}
	},
	"Echo.StreamServer.Controls.Submit.onPostComplete": function() {
		var self = this;
		setTimeout(function() {
			self._hideSubmit(true);
		}, this.config.get("pauseTimeout"));
	},
	"Echo.StreamServer.Controls.Stream.Item.onRender": function() {
		if (this.get("expanded")) {
			this._showSubmit();
		}
	}
};

plugin.templates.form =
	'
' +
		'

' +
		'
' +
			'

' +
			'
' +
				'<input type="text" class="{plugin.class:compactField} echo-primaryFont echo-secondaryColor">' +
			'
' +
		'
' +
	'
';

plugin.templates.childrenSpacing =
	'

';

plugin.component.renderers.container = function(element) {
	var item = this.component;
	var threading = item.threading;
	if (this.get("expanded")) {
		item.threading = true;
	}
	item.parentRenderer("container", arguments);
	item.threading = threading;
	return element;
};

plugin.component.renderers.children = function() {
	var item = this.component;
	// perform reply form rerendering *only* when we have exactly 1 item
	// (the first item is being added or the last one is being deleted)
	if (item.get("children").length === 1) {
		var child = item.get("children")[0];
		if (child.get("added") || child.get("deleted")) {
			this.view.render({"name": "compactForm"});
		}
	}
	return item.parentRenderer("children", arguments);
};

plugin.component.renderers.expandChildren = function() {
	var item = this.component;
	var element = item.parentRenderer("expandChildren", arguments);

	return !this.config.get("displayCompactForm")
		? element.addClass(this.cssPrefix + "expandChildren")
		: element;
};

plugin.renderers.replyForm = function(element) {
	var item = this.component;
	return element
		.addClass(item.get("cssPrefix") + "depth-" + (item.get("depth") + 1));
};

plugin.renderers.submitForm = function(element) {
	if (!this.config.get("displayCompactForm")) {
		element.addClass(this.cssPrefix + "additionalSpacing");
	}
	return this.get("expanded")
		? element.show() : element.empty().hide();
};

plugin.renderers.avatar = function(element) {
	var item = this.component;
	return item.get("depth") && !this.get("expanded")
		? element.hide() : element.show();
};

plugin.renderers.pluginAvatar = function(element) {
	var item = this.component;
	var avatarURL = item.user.get("avatar");
	if (!avatarURL) {
		avatarURL = item.config.get("defaultAvatar");
	}
	element.css("background-image", 'url("' + avatarURL + '")');
	// we have to do it because filter must work in IE8 only
	// in other cases we will have square avatar in IE 9
	var isIE8 = document.all && document.querySelector && !document.addEventListener;
	if (isIE8) {
		element.css({"filter": "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + avatarURL + "', sizingMethod='scale')"});
	}
	return element;
};

plugin.renderers.childrenSpacing = function(element) {
	return this._isCompactFormVisible()
		? element.show()
		: element.hide();
};

plugin.renderers.compactForm = function(element, extra) {
	extra = extra || {};
	return this._isCompactFormVisible()
		? element.slideDown(+extra.animate && this.config.get("compactFormTimeout"))
		: element.hide();
};

plugin.renderers.compactField = function(element) {
	var plugin = this;
	return element.focus(function() {
		plugin._showSubmit();
	}).val(this.config.get("actionString"));
};

plugin.methods.destroy = function() {
	if (this.get("submit")) {
		Echo.Utils.set(Echo.Variables, this._getSubmitKey(), {
			"expanded": this.get("expanded"),
			"data": {
				"object": this._getSubmitData()
			}
		});
	}
	$(document).off('click', this.get("documentClickHandler"));
};

plugin.methods._submitConfig = function(target) {
	var plugin = this, item = this.component;
	return plugin.config.assemble({
		"target": target,
		"parent": item.config.getAsHash(),
		"data": plugin.get("data") || {},
		"markers": this.config.get("extraMarkers"),
		"targetURL": item.get("data.object.id"),
		"targetQuery": item.config.get("query", ""),
		"ready": function() {
			plugin.set("submit", this);
			plugin._expand();
		}
	});
};

plugin.methods._showSubmit = function() {
	var item = this.component;
	var target = this.view.get("submitForm");
	var submit = this.get("submit");
	if (submit) {
		submit.config.set("target", target);
		submit.render();
		this._expand();
		return target;
	}
	var config = this._submitConfig(target);
	// add plugin for submit
	config.plugins.splice(0, 0, {
		"name": "ReplyCardUI",
		"inReplyTo": item.get("data")
	});
	// add plugin for auth
	$.map(config.plugins, function(plugin) {
		if (plugin.name === "JanrainAuth") {
			plugin.nestedPlugins = plugin.nestedPlugins || [];
			plugin.nestedPlugins.push({
				"name": "ReplyCardUI"
			});
		}
	});
	new Echo.StreamServer.Controls.Submit(config);
	return target;
};

plugin.methods._hideSubmit = function(animate) {
	var self = this, item = this.component;

	var submit = this.get("submit");
	if (submit) {
		submit.set("data", undefined);
	}
	this.set("expanded", false);

	var timeout = +animate && this.config.get("submitFormTimeout");
	this.view.get("submitForm")
		.slideUp(timeout, function() {
			self.view.render({"name": "avatar"});
			self.view.render({
				"name": "compactForm",
				"extra": {"animate": animate}
			});
			item.view.render({"name": "container"});
			self.events.publish({
				"topic": "onCollapse"
			});
		});
};

plugin.methods._isCompactFormVisible = function() {
	var item = this.component;
	return !item.get("depth") && !this.get("expanded") && this.config.get("displayCompactForm");
};

plugin.methods._expand = function() {
	var item = this.component;
	this.set("expanded", true);

	this.view.render({"name": "submitForm"});
	this.view.render({"name": "compactForm"});
	this.view.render({"name": "avatar"});

	this.events.publish({
		"topic": "onExpand",
		"data": {
			"context": item.config.get("context")
		}
	});
	item.view.render({"name": "container"});
};

plugin.methods._getClickHandler = function() {
	var plugin = this;
	return function(event) {
		var submit = plugin.get("submit");
		var submitForm = plugin.view.get("submitForm");
		var isClickedInSubmitForm = submitForm && submitForm.find(event.target).length;
		if (plugin.get("expanded") && submit && !submit.view.get("text").val() && !isClickedInSubmitForm) {
			plugin._hideSubmit();
		}
	};
};

plugin.methods._assembleButton = function() {
	var plugin = this;
	var callback = function() {
		plugin._showSubmit();
	};
	return function() {
		var item = this;
		return {
			"name": "ReplyCardUI",
			"icon": "icon-comment",
			"label": plugin.labels.get("replyControl"),
			"visible": item.get("depth") < item.config.get("parent.children.maxDepth"),
			"callback": callback
		};
	};
};

plugin.methods._getSubmitKey = function() {
	var item = this.component;
	var applicationContext = item.config.get("context").split("/")[0];
	return "forms." + item.data.unique + "-" + applicationContext;
};

plugin.methods._getSubmitData = function() {
	var data = {};
	var submit = this.get("submit");

	data["content"] = submit.view.get("text").val();
	$.map(["tags", "markers"], function(field) {
		var elements = submit.view.get(field).val().split(", ");
		data[field] = elements || [];
	});
	return data;
};

plugin.css =
	'.{plugin.class} .{plugin.class:childrenSpacing} { margin-top: 8px; }' +
	'.{plugin.class} .{class:children} .{plugin.class:childrenSpacing} { margin-top: 0px; }' +
	'.{plugin.class} .{plugin.class:replyForm} { margin-right: 15px; border-left: 4px solid transparent; }' +
	'.{plugin.class} .{plugin.class:submitForm} { padding: 8px 0px 15px 0px; }' +
	'.{plugin.class} .{plugin.class:compactForm} { padding: 8px 0px 15px 0px; }' +
	'.{plugin.class} .{class:content} .{class:expandChildren} { padding: 8px 0px; }' +
	'.{plugin.class} .{class:content} .{plugin.class:expandChildren} { padding: 15px 0px 8px 0px; }' +
	'.{plugin.class} .{plugin.class:additionalSpacing} { padding-top: 15px; }' +
	'.{plugin.class:compactContent} { padding: 0px 5px 0px 6px; background-color: #fff; height: 28px; line-height: 28px; }' +
	'.{plugin.class:avatar} { width: 28px; height: 28px; border-radius: 50%; margin: 1px 0px 0px 3px; }' +
	'.{plugin.class} .{plugin.class:avatar} > div { width: 28px; height: 28px; background-size:cover; display:inline-block; background-position:center; border-radius: 50%; }' +
	'.{plugin.class:compactBorder} { margin-left: 39px; border: 1px solid #d8d8d8; }' +
	'.{plugin.class:compactContent} input.{plugin.class:compactField}[type="text"].echo-secondaryColor { color: #C6C6C6 }' +
	'.{plugin.class:compactContent} input.{plugin.class:compactField}[type="text"].echo-primaryFont { font-size: 12px; line-height: 24px; }' +
	'.{plugin.class:compactContent} input.{plugin.class:compactField}[type="text"] { width: 100%; height: 24px; border: none; margin: 0px; padding: 0px; box-shadow: none; vertical-align: middle; }' +
	'.{plugin.class:compactContent} input.{plugin.class:compactField}[type="text"]:focus { outline: 0; box-shadow: none; }';

Echo.Plugin.create(plugin);

})(Echo.jQuery);

(function() {
"use strict";

var plugin = Echo.Plugin.manifest("ReplyCardUI", "Echo.StreamServer.Controls.Stream");

if (Echo.Plugin.isDefined(plugin)) return;

plugin.events = {
	"Echo.StreamServer.Controls.Stream.Item.Plugins.ReplyCardUI.onExpand": function(topic, args) {
		this.events.publish({
			"topic": "onFormExpand",
			"data": {
				"context": args.context
			}
		});
	}
};

Echo.Plugin.create(plugin);

})(Echo.jQuery);

(function(jQuery) {
"use strict";

var $ = jQuery;

var plugin = Echo.Plugin.manifest("ReplyCardUI", "Echo.StreamServer.Controls.Submit");

if (Echo.Plugin.isDefined(plugin)) return;

plugin.init = function() {
	var plugin = this, submit = plugin.component;
	var _prepareEventParams = submit._prepareEventParams;

	submit._prepareEventParams = function(params) {
		var _params = _prepareEventParams.call(submit, params);
		_params.inReplyTo = plugin.config.get("inReplyTo");
		return _params;
	};
};

$.map(["onRender", "onRerender"], function(topic) {
	plugin.events["Echo.StreamServer.Controls.Submit." + topic] = function() {
		var submit = this.component;
		submit.config.get("target").show();
		submit.view.get("text").focus();
	};
});

plugin.css =
	'.{plugin.class} div.{class:container} { padding: 0px; border: 0px; box-shadow: none; }';

Echo.Plugin.create(plugin);

})(Echo.jQuery);
<commit_msg>reply avatar renderer changed<commit_after>(function(jQuery) {
"use strict";

var $ = jQuery;

var plugin = Echo.Plugin.manifest("ReplyCardUI", "Echo.StreamServer.Controls.Stream.Item");

if (Echo.Plugin.isDefined(plugin)) return;

plugin.init = function() {
	var self = this, item = this.component;
	this.extendTemplate("insertAsLastChild", "content", plugin.templates.form);
	// insert element to add addditional spacing above the children container
	this.extendTemplate("insertBefore", "expandChildren", plugin.templates.childrenSpacing);
	var form = Echo.Utils.get(Echo.Variables, this._getSubmitKey());
	$.each(form || {}, function(key, value) {
		self.set(key, value);
	});
	item.addButtonSpec("ReplyCardUI", this._assembleButton());
	this.set("documentClickHandler", this._getClickHandler());
	$(document).on('click', this.get("documentClickHandler"));
};

plugin.config = {
	"actionString": "Add a comment...",
	"pauseTimeout": 0,
	"submitFormTimeout": 300,
	"compactFormTimeout": 200,
	"displayCompactForm": false
};

plugin.labels = {
	"replyControl": "Reply"
};

plugin.dependencies = [{
	"control": "Echo.StreamServer.Controls.Submit",
	"url": "{config:cdnBaseURL.sdk}/streamserver.pack.js"
}];

plugin.events = {
	"Echo.StreamServer.Controls.Stream.Plugins.ReplyCardUI.onFormExpand": function(topic, args) {
		var item = this.component;
		var context = item.config.get("context");
		if (this.get("expanded") && context && context !== args.context) {
			this._hideSubmit();
		}
	},
	"Echo.StreamServer.Controls.Submit.onPostComplete": function() {
		var self = this;
		setTimeout(function() {
			self._hideSubmit(true);
		}, this.config.get("pauseTimeout"));
	},
	"Echo.StreamServer.Controls.Stream.Item.onRender": function() {
		if (this.get("expanded")) {
			this._showSubmit();
		}
	}
};

plugin.templates.form =
	'
' +
		'

' +
		'
' +
			'

' +
			'
' +
				'<input type="text" class="{plugin.class:compactField} echo-primaryFont echo-secondaryColor">' +
			'
' +
		'
' +
	'
';

plugin.templates.childrenSpacing =
	'

';

plugin.component.renderers.container = function(element) {
	var item = this.component;
	var threading = item.threading;
	if (this.get("expanded")) {
		item.threading = true;
	}
	item.parentRenderer("container", arguments);
	item.threading = threading;
	return element;
};

plugin.component.renderers.children = function() {
	var item = this.component;
	// perform reply form rerendering *only* when we have exactly 1 item
	// (the first item is being added or the last one is being deleted)
	if (item.get("children").length === 1) {
		var child = item.get("children")[0];
		if (child.get("added") || child.get("deleted")) {
			this.view.render({"name": "compactForm"});
		}
	}
	return item.parentRenderer("children", arguments);
};

plugin.component.renderers.expandChildren = function() {
	var item = this.component;
	var element = item.parentRenderer("expandChildren", arguments);

	return !this.config.get("displayCompactForm")
		? element.addClass(this.cssPrefix + "expandChildren")
		: element;
};

plugin.renderers.replyForm = function(element) {
	var item = this.component;
	return element
		.addClass(item.get("cssPrefix") + "depth-" + (item.get("depth") + 1));
};

plugin.renderers.submitForm = function(element) {
	if (!this.config.get("displayCompactForm")) {
		element.addClass(this.cssPrefix + "additionalSpacing");
	}
	return this.get("expanded")
		? element.show() : element.empty().hide();
};

plugin.renderers.avatar = function(element) {
	var item = this.component;
	var avatarURL = item.user.get("avatar");
	if (!avatarURL) {
		avatarURL = item.config.get("defaultAvatar");
	}
	var avatarElem = element.children()[0];
	$(avatarElem).css("background-image", 'url("' + avatarURL + '")');
	// we have to do it because filter must work in IE8 only
	// in other cases we will have square avatar in IE 9
	var isIE8 = document.all && document.querySelector && !document.addEventListener;
	if (isIE8) {
		$(avatarElem).css({"filter": "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='" + avatarURL + "', sizingMethod='scale')"});
	}
	return item.get("depth") && !this.get("expanded")
		? element.hide() : element.show();
};

plugin.renderers.childrenSpacing = function(element) {
	return this._isCompactFormVisible()
		? element.show()
		: element.hide();
};

plugin.renderers.compactForm = function(element, extra) {
	extra = extra || {};
	return this._isCompactFormVisible()
		? element.slideDown(+extra.animate && this.config.get("compactFormTimeout"))
		: element.hide();
};

plugin.renderers.compactField = function(element) {
	var plugin = this;
	return element.focus(function() {
		plugin._showSubmit();
	}).val(this.config.get("actionString"));
};

plugin.methods.destroy = function() {
	if (this.get("submit")) {
		Echo.Utils.set(Echo.Variables, this._getSubmitKey(), {
			"expanded": this.get("expanded"),
			"data": {
				"object": this._getSubmitData()
			}
		});
	}
	$(document).off('click', this.get("documentClickHandler"));
};

plugin.methods._submitConfig = function(target) {
	var plugin = this, item = this.component;
	return plugin.config.assemble({
		"target": target,
		"parent": item.config.getAsHash(),
		"data": plugin.get("data") || {},
		"markers": this.config.get("extraMarkers"),
		"targetURL": item.get("data.object.id"),
		"targetQuery": item.config.get("query", ""),
		"ready": function() {
			plugin.set("submit", this);
			plugin._expand();
		}
	});
};

plugin.methods._showSubmit = function() {
	var item = this.component;
	var target = this.view.get("submitForm");
	var submit = this.get("submit");
	if (submit) {
		submit.config.set("target", target);
		submit.render();
		this._expand();
		return target;
	}
	var config = this._submitConfig(target);
	// add plugin for submit
	config.plugins.splice(0, 0, {
		"name": "ReplyCardUI",
		"inReplyTo": item.get("data")
	});
	// add plugin for auth
	$.map(config.plugins, function(plugin) {
		if (plugin.name === "JanrainAuth") {
			plugin.nestedPlugins = plugin.nestedPlugins || [];
			plugin.nestedPlugins.push({
				"name": "ReplyCardUI"
			});
		}
	});
	new Echo.StreamServer.Controls.Submit(config);
	return target;
};

plugin.methods._hideSubmit = function(animate) {
	var self = this, item = this.component;

	var submit = this.get("submit");
	if (submit) {
		submit.set("data", undefined);
	}
	this.set("expanded", false);

	var timeout = +animate && this.config.get("submitFormTimeout");
	this.view.get("submitForm")
		.slideUp(timeout, function() {
			self.view.render({"name": "avatar"});
			self.view.render({
				"name": "compactForm",
				"extra": {"animate": animate}
			});
			item.view.render({"name": "container"});
			self.events.publish({
				"topic": "onCollapse"
			});
		});
};

plugin.methods._isCompactFormVisible = function() {
	var item = this.component;
	return !item.get("depth") && !this.get("expanded") && this.config.get("displayCompactForm");
};

plugin.methods._expand = function() {
	var item = this.component;
	this.set("expanded", true);

	this.view.render({"name": "submitForm"});
	this.view.render({"name": "compactForm"});
	this.view.render({"name": "avatar"});

	this.events.publish({
		"topic": "onExpand",
		"data": {
			"context": item.config.get("context")
		}
	});
	item.view.render({"name": "container"});
};

plugin.methods._getClickHandler = function() {
	var plugin = this;
	return function(event) {
		var submit = plugin.get("submit");
		var submitForm = plugin.view.get("submitForm");
		var isClickedInSubmitForm = submitForm && submitForm.find(event.target).length;
		if (plugin.get("expanded") && submit && !submit.view.get("text").val() && !isClickedInSubmitForm) {
			plugin._hideSubmit();
		}
	};
};

plugin.methods._assembleButton = function() {
	var plugin = this;
	var callback = function() {
		plugin._showSubmit();
	};
	return function() {
		var item = this;
		return {
			"name": "ReplyCardUI",
			"icon": "icon-comment",
			"label": plugin.labels.get("replyControl"),
			"visible": item.get("depth") < item.config.get("parent.children.maxDepth"),
			"callback": callback
		};
	};
};

plugin.methods._getSubmitKey = function() {
	var item = this.component;
	var applicationContext = item.config.get("context").split("/")[0];
	return "forms." + item.data.unique + "-" + applicationContext;
};

plugin.methods._getSubmitData = function() {
	var data = {};
	var submit = this.get("submit");

	data["content"] = submit.view.get("text").val();
	$.map(["tags", "markers"], function(field) {
		var elements = submit.view.get(field).val().split(", ");
		data[field] = elements || [];
	});
	return data;
};

plugin.css =
	'.{plugin.class} .{plugin.class:childrenSpacing} { margin-top: 8px; }' +
	'.{plugin.class} .{class:children} .{plugin.class:childrenSpacing} { margin-top: 0px; }' +
	'.{plugin.class} .{plugin.class:replyForm} { margin-right: 15px; border-left: 4px solid transparent; }' +
	'.{plugin.class} .{plugin.class:submitForm} { padding: 8px 0px 15px 0px; }' +
	'.{plugin.class} .{plugin.class:compactForm} { padding: 8px 0px 15px 0px; }' +
	'.{plugin.class} .{class:content} .{class:expandChildren} { padding: 8px 0px; }' +
	'.{plugin.class} .{class:content} .{plugin.class:expandChildren} { padding: 15px 0px 8px 0px; }' +
	'.{plugin.class} .{plugin.class:additionalSpacing} { padding-top: 15px; }' +
	'.{plugin.class:compactContent} { padding: 0px 5px 0px 6px; background-color: #fff; height: 28px; line-height: 28px; }' +
	'.{plugin.class:avatar} { width: 28px; height: 28px; border-radius: 50%; margin: 1px 0px 0px 3px; }' +
	'.{plugin.class} .{plugin.class:avatar} > div { width: 28px; height: 28px; background-size:cover; display:inline-block; background-position:center; border-radius: 50%; }' +
	'.{plugin.class:compactBorder} { margin-left: 39px; border: 1px solid #d8d8d8; }' +
	'.{plugin.class:compactContent} input.{plugin.class:compactField}[type="text"].echo-secondaryColor { color: #C6C6C6 }' +
	'.{plugin.class:compactContent} input.{plugin.class:compactField}[type="text"].echo-primaryFont { font-size: 12px; line-height: 24px; }' +
	'.{plugin.class:compactContent} input.{plugin.class:compactField}[type="text"] { width: 100%; height: 24px; border: none; margin: 0px; padding: 0px; box-shadow: none; vertical-align: middle; }' +
	'.{plugin.class:compactContent} input.{plugin.class:compactField}[type="text"]:focus { outline: 0; box-shadow: none; }';

Echo.Plugin.create(plugin);

})(Echo.jQuery);

(function() {
"use strict";

var plugin = Echo.Plugin.manifest("ReplyCardUI", "Echo.StreamServer.Controls.Stream");

if (Echo.Plugin.isDefined(plugin)) return;

plugin.events = {
	"Echo.StreamServer.Controls.Stream.Item.Plugins.ReplyCardUI.onExpand": function(topic, args) {
		this.events.publish({
			"topic": "onFormExpand",
			"data": {
				"context": args.context
			}
		});
	}
};

Echo.Plugin.create(plugin);

})(Echo.jQuery);

(function(jQuery) {
"use strict";

var $ = jQuery;

var plugin = Echo.Plugin.manifest("ReplyCardUI", "Echo.StreamServer.Controls.Submit");

if (Echo.Plugin.isDefined(plugin)) return;

plugin.init = function() {
	var plugin = this, submit = plugin.component;
	var _prepareEventParams = submit._prepareEventParams;

	submit._prepareEventParams = function(params) {
		var _params = _prepareEventParams.call(submit, params);
		_params.inReplyTo = plugin.config.get("inReplyTo");
		return _params;
	};
};

$.map(["onRender", "onRerender"], function(topic) {
	plugin.events["Echo.StreamServer.Controls.Submit." + topic] = function() {
		var submit = this.component;
		submit.config.get("target").show();
		submit.view.get("text").focus();
	};
});

plugin.css =
	'.{plugin.class} div.{class:container} { padding: 0px; border: 0px; box-shadow: none; }';

Echo.Plugin.create(plugin);

})(Echo.jQuery);
<|endoftext|>


<commit_before>import {d, multihash, run} from 'lightsaber'
import fs from 'fs'
const jsonldSignatures = require('jsonld-signatures')
import bitcore from 'bitcore-lib'
import canonicalJson from 'json-stable-stringify'
import moment from 'moment'

export default class Trust {
  claim = (opts) => {
    const claim = {
      '@context': 'https://schema.trust.exchange/TrustClaim.jsonld',
      // id: multihash of json of final signed claim??? add at end.
      type: 'TrustClaim',
      issuer: opts.creator,
      issued: moment().format(),
      claim: {
        '@context': 'https://schema.org/',
        type: 'Review',
        itemReviewed: opts.target,
        author: opts.creator,
        keywords: opts.tags.split(/\s*,\s*/).join(', ').trim(),
        reviewRating: {
          '@context': 'https://schema.org/',
          type: 'Rating',
          bestRating: 1,
          worstRating: 0,
          ratingValue: opts.value,
          description: opts.description
        }
      }
    }

    d('\ninput:')
    d(JSON.stringify(claim, null, 4))

    let result
    jsonldSignatures.promises.sign(claim, {
      privateKeyWif: opts.privateKey,
      algorithm: 'EcdsaKoblitzSignature2016',
      domain: 'example.com',
      creator: 'EcdsaKoblitz-public-key:' + new bitcore.PrivateKey(opts.privateKey).toPublicKey()
    }).then((_result) => {
      result = _result
      d('\n\nsigned json:')
      d(result)
      const json = canonicalJson(result)
      d('\n\ncanonical json to timestamp:')
      d(json)
      d('\n\nmultihash:')
      d(multihash(json))
      run('mkdir -p claims')
      fs.writeFileSync('claims/xyz', json)
      const id = run('ipfs add -q claims/xyz').toString().trim()
      d('open https://ipfs.io/ipfs/' + id)

      return
    }).catch((error) => {
      console.error(error.stack)
      process.exit(1)
    })
  }

  get = () => d('TODO: implement this')

}
<commit_msg>add todo<commit_after>import {d, multihash, run} from 'lightsaber'
import fs from 'fs'
const jsonldSignatures = require('jsonld-signatures')
import bitcore from 'bitcore-lib'
import canonicalJson from 'json-stable-stringify'
import moment from 'moment'

export default class Trust {
  claim = (opts) => {
    const claim = {
      '@context': 'https://schema.trust.exchange/TrustClaim.jsonld',
      // id: multihash of json of final signed claim??? add at end.
      type: 'TrustClaim',
      issuer: opts.creator,
      issued: moment().format(),
      claim: {
        '@context': 'https://schema.org/',
        type: 'Review',
        itemReviewed: opts.target,
        author: opts.creator,
        keywords: opts.tags.split(/\s*,\s*/).join(', ').trim(),
        reviewRating: {
          '@context': 'https://schema.org/',
          type: 'Rating',
          bestRating: 1,
          worstRating: 0,
          ratingValue: opts.value,
          description: opts.description
        }
      }
    }

    d('\ninput:')
    d(JSON.stringify(claim, null, 4))

    let result
    jsonldSignatures.promises.sign(claim, {
      privateKeyWif: opts.privateKey,
      algorithm: 'EcdsaKoblitzSignature2016',
      domain: 'example.com',
      creator: 'EcdsaKoblitz-public-key:' + new bitcore.PrivateKey(opts.privateKey).toPublicKey()
    }).then((_result) => {
      result = _result
      d('\n\nsigned json:')
      d(result)
      const json = canonicalJson(result)
      d('\n\ncanonical json to timestamp:')
      d(json)
      d('\n\nmultihash:')
      d(multihash(json))
      run('mkdir -p claims')
      fs.writeFileSync('claims/xyz', json)
      const id = run('ipfs add -q claims/xyz').toString().trim()
      d('open https://ipfs.io/ipfs/' + id)

      return
    }).catch((error) => {
      console.error(error.stack)
      process.exit(1)
    })
  }

  get = () => d('TODO: implement this')
  map = () => d('TODO: implement this')

}
<|endoftext|>


<commit_before>socket.on('connected', function(connected) {
      /*
       * NULL: not connected to the node server
       * 1: connected
       */
      console.log(connected);
      var connected = connected;
      if(connected == 1){
       $('#login').html("
<button class='small button' onclick='return false;''>Login</button>      Hi ! Welcome to nodeChat, please login to post a message.
");

      }else{}
  });

  socket.on('disconnect', function () {
    document.getElementById('tchat').innerHTML += '
bot : You have been disconnected, possibly because this server was restarted.
';
    $('#user-form').remove();
    $('#user-name').remove();
    $('#login').remove();
    $('#disconnected').html('You have been disconnected, possibly because this server was restarted.');
  });
<commit_msg>Update checkConnection.js<commit_after>socket.on('connected', function(connected) {
      /*
       * NULL: not connected to the node server
       * 1: connected
       */
      console.log(connected);
      var connected = connected;
      if(connected == 1){
       $('#login').html("
<button class='small button' onclick='return false;''>Login</button>      Hi ! Welcome to nodeChat, please login to post a message.
");
      }else{}
  });

socket.on('BadName', function(c){
  /*
   * If this socket returns 1, it's because the name is too long
   */
   if(c == 1){
   console.log('The value of c is 1, the name is too long.')
   $('#login').html("
<button class='small button' onclick='return false;''>Login</button>      Hi ! Welcome to nodeChat, please login to post a message.
");
   //Clearing user form
   $('#user-name').html('');
   $('#user-form').html('');
   $('#user').html('Guest')
   }
})
  socket.on('disconnect', function () {
    document.getElementById('tchat').innerHTML += '
bot : You have been disconnected, possibly because this server was restarted.
';
    $('#user-form').remove();
    $('#user-name').remove();
    $('#login').remove();
    $('#disconnected').html('You have been disconnected, possibly because this server was restarted.');
  });
<|endoftext|>


<commit_before>angular.module('ot.service.event', [

])
    .service('otEventService', function ($interpolate) {

        var variableRegex = /\$\{([:a-zA-Z_]+)\}/g;
        var self = {};

        self.renderEvent = function (event) {

            return event.template.replace(
                variableRegex,
                replacementFunction(event)
            );
        };

        function replacementFunction(event) {
            return function (match, expression) {
                if (expression.charAt(0) == ':') {
                    // We want a value
                    var valueKey = expression.substring(1);
                    var value = event.values[valueKey];
                    if (!value) {
                        return replacementValueError(event, valueKey);
                    }
                    // Rendering
                    return $interpolate('{{value.value}}')({
                        valueKey: valueKey,
                        value: value
                    });
                } else {
                    // We want an entity reference
                    var entity = event.entities[expression];
                    if (!entity) {
                        return replacementEntityError(event, expression);
                    }
                    // Link definition
                    var link = {
                        cls: ''
                    };
                    if (expression == 'PROJECT') {
                        link.uri = "#/project/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'BRANCH') {
                        link.uri = "#/branch/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'BUILD') {
                        link.uri = "#/build/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'PROMOTION_LEVEL') {
                        link.uri = "#/promotionLevel/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'VALIDATION_STAMP') {
                        link.uri = "#/validationStamp/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'VALIDATION_RUN') {
                        link.uri = "#/validationRun/" + entity.id;
                        link.name = '#' + entity.runOrder;
                    }
                    // Link rendering
                    return $interpolate('{{name}}')(link);
                }
            };
        }

        return self;

    })
;<commit_msg>#33 Error handling at client side<commit_after>angular.module('ot.service.event', [

])
    .service('otEventService', function ($interpolate) {

        var variableRegex = /\$\{([:a-zA-Z_]+)\}/g;
        var self = {};

        self.renderEvent = function (event) {

            return event.template.replace(
                variableRegex,
                replacementFunction(event)
            );
        };

        function replacementFunction(event) {
            return function (match, expression) {
                if (expression.charAt(0) == ':') {
                    // We want a value
                    var valueKey = expression.substring(1);
                    var value = event.values[valueKey];
                    if (!value) {
                        return replacementValueError(event, valueKey);
                    }
                    // Rendering
                    return $interpolate('{{value.value}}')({
                        valueKey: valueKey,
                        value: value
                    });
                } else {
                    // We want an entity reference
                    var entity = event.entities[expression];
                    if (!entity) {
                        return replacementEntityError(event, expression);
                    }
                    // Link definition
                    var link = {
                        cls: ''
                    };
                    if (expression == 'PROJECT') {
                        link.uri = "#/project/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'BRANCH') {
                        link.uri = "#/branch/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'BUILD') {
                        link.uri = "#/build/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'PROMOTION_LEVEL') {
                        link.uri = "#/promotionLevel/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'VALIDATION_STAMP') {
                        link.uri = "#/validationStamp/" + entity.id;
                        link.name = entity.name;
                    }
                    else if (expression == 'VALIDATION_RUN') {
                        link.uri = "#/validationRun/" + entity.id;
                        link.name = '#' + entity.runOrder;
                    }
                    // Link rendering
                    return $interpolate('{{name}}')(link);
                }
            };
        }

        function replacementEntityError (event, expression) {
            return "#ERROR";
        }

        function replacementValueError (event, key) {
            return "#ERROR";
        }

        return self;

    })
;<|endoftext|>


<commit_before>/*
 * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
 *
 * @author Michael Weimann <mail@michael-weimann.eu>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */

// eslint

import { translate as t } from 'nextcloud-server/dist/l10n'
import axios from 'nextcloud-axios'

/**
 * Maps an API board to a menu item.
 * @param board
 * @returns {{id: *, classes: Array, bullet: string, text: *, router: {name: string, params: {id: *}}, utils: {actions: *[]}}}
 */
const mapBoardToItem = board => {
	return {
		id: board.id,
		classes: [],
		bullet: `#${board.color}`,
		text: board.title,
		owner: board.owner,
		router: {
			name: 'board',
			params: { id: board.id }
		},
		utils: {
			actions: boardActions
		}
	}
}

let defaultCategories = [
	{
		id: 'deck-boards',
		classes: [],
		icon: 'icon-deck',
		text: t('deck', 'All boards'),
		router: {
			name: 'boards'
		}
	},
	{
		id: 'deck-boards-archived',
		classes: [],
		icon: 'icon-archive',
		text: t('deck', 'Archived boards'),
		router: {
			name: 'boards.archived'
		}
	},
	{
		id: 'deck-boards-shared',
		classes: [],
		icon: 'icon-shared',
		text: t('deck', 'Shared boards'),
		router: {
			name: 'boards.shared'
		}
	}
]

const boardActions = [
	{
		action: () => {
		},
		icon: 'icon-edit',
		text: t('deck', 'Edit board')
	},
	{
		action: () => {
		},
		icon: 'icon-archive',
		text: t('deck', 'Archive board')
	},
	{
		action: () => {
		},
		icon: 'icon-delete',
		text: t('deck', 'Delete board')
	},
	{
		action: () => {
		},
		icon: 'icon-settings',
		text: t('deck', 'Board details')
	}
]

const addButton = {
	icon: 'icon-add',
	text: t('deck', 'Create new board'),
	action: () => {
	}
}

// initial state
const state = {
	hidden: false,
	boards: [],
	loading: false,
	filter: ''
}

export const BOARD_FILTERS = {
	ALL: '',
	ARCHIVED: 'archived',
	SHARED: 'shared'
}

// getters
const getters = {
	menu: state => {

		// filters the boards depending on the active filter
		const boards = state.boards.filter(board => {
			return state.filter === BOARD_FILTERS.ALL
				|| (state.filter === BOARD_FILTERS.ARCHIVED && board.archived === true)
				|| (state.filter === BOARD_FILTERS.SHARED && board.shared === 1)
		})

		return {
			loading: state.loading,
			items: defaultCategories
				.concat(boards.map(mapBoardToItem))
				.concat([addButton])
		}
	},
	boards: state => {
		// filters the boards depending on the active filter
		const boards = state.boards.filter(board => {
			return state.filter === BOARD_FILTERS.ALL
				|| (state.filter === BOARD_FILTERS.ARCHIVED && board.archived === true)
				|| (state.filter === BOARD_FILTERS.SHARED && board.shared === 1)
		})

		return boards.map(mapBoardToItem)
	}
}

// actions
const actions = {
	toggle({ commit }) {
		commit('toggle')
	},
	loadBoards({ commit }) {
		axios.get('/apps/deck/boards')
			.then((response) => {
				commit('setBoards', response.data)
			})
	}
}

// mutations
const mutations = {
	toggle(state) {
		state.hidden = !state.hidden
	},
	setBoards(state, boards) {
		state.boards = boards
	},
	setFilter(state, filter) {
		state.filter = filter
	}
}

export default {
	namespaced: true,
	state,
	getters,
	actions,
	mutations
}
<commit_msg>Removes filtering of the left side bar boards<commit_after>/*
 * @copyright Copyright (c) 2018 Julius Härtl <jus@bitgrid.net>
 *
 * @author Michael Weimann <mail@michael-weimann.eu>
 *
 * @license GNU AGPL version 3 or any later version
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of 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.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 *
 */

// eslint

import { translate as t } from 'nextcloud-server/dist/l10n'
import axios from 'nextcloud-axios'

/**
 * Maps an API board to a menu item.
 * @param board
 * @returns {{id: *, classes: Array, bullet: string, text: *, router: {name: string, params: {id: *}}, utils: {actions: *[]}}}
 */
const mapBoardToItem = board => {
	return {
		id: board.id,
		classes: [],
		bullet: `#${board.color}`,
		text: board.title,
		owner: board.owner,
		router: {
			name: 'board',
			params: { id: board.id }
		},
		utils: {
			actions: boardActions
		}
	}
}

let defaultCategories = [
	{
		id: 'deck-boards',
		classes: [],
		icon: 'icon-deck',
		text: t('deck', 'All boards'),
		router: {
			name: 'boards'
		}
	},
	{
		id: 'deck-boards-archived',
		classes: [],
		icon: 'icon-archive',
		text: t('deck', 'Archived boards'),
		router: {
			name: 'boards.archived'
		}
	},
	{
		id: 'deck-boards-shared',
		classes: [],
		icon: 'icon-shared',
		text: t('deck', 'Shared boards'),
		router: {
			name: 'boards.shared'
		}
	}
]

const boardActions = [
	{
		action: () => {
		},
		icon: 'icon-edit',
		text: t('deck', 'Edit board')
	},
	{
		action: () => {
		},
		icon: 'icon-archive',
		text: t('deck', 'Archive board')
	},
	{
		action: () => {
		},
		icon: 'icon-delete',
		text: t('deck', 'Delete board')
	},
	{
		action: () => {
		},
		icon: 'icon-settings',
		text: t('deck', 'Board details')
	}
]

const addButton = {
	icon: 'icon-add',
	text: t('deck', 'Create new board'),
	action: () => {
	}
}

// initial state
const state = {
	hidden: false,
	boards: [],
	loading: false,
	filter: ''
}

export const BOARD_FILTERS = {
	ALL: '',
	ARCHIVED: 'archived',
	SHARED: 'shared'
}

// getters
const getters = {
	menu: state => {

		return {
			loading: state.loading,
			items: defaultCategories
				.concat(state.boards.map(mapBoardToItem))
				.concat([addButton])
		}
	},
	boards: state => {
		// filters the boards depending on the active filter
		const boards = state.boards.filter(board => {
			return state.filter === BOARD_FILTERS.ALL
				|| (state.filter === BOARD_FILTERS.ARCHIVED && board.archived === true)
				|| (state.filter === BOARD_FILTERS.SHARED && board.shared === 1)
		})

		return boards.map(mapBoardToItem)
	}
}

// actions
const actions = {
	toggle({ commit }) {
		commit('toggle')
	},
	loadBoards({ commit }) {
		axios.get('/apps/deck/boards')
			.then((response) => {
				commit('setBoards', response.data)
			})
	}
}

// mutations
const mutations = {
	toggle(state) {
		state.hidden = !state.hidden
	},
	setBoards(state, boards) {
		state.boards = boards
	},
	setFilter(state, filter) {
		state.filter = filter
	}
}

export default {
	namespaced: true,
	state,
	getters,
	actions,
	mutations
}
<|endoftext|>


<commit_before>var redis = require('redis');
var appManager = require('./appManager.js');
var logger = require('../common/logger.js');
var serverOperations = require('../../common/serverOperations.js');

var channelName = 'server';
var subscriber = null;

function initialise() {
    logger.info('redisManager: initialise');
    subscriber = redis.createClient();
    logger.info('redisManager: created subscriber client');
    subscriber.on('message', function (channel, message) {
        logger.info('redisManager: message received: ' + message);
        var header = null;
        var body = null;
        if (message) {
            header = message.split(/ (.+)/)[0];
            body = message.split(/ (.+)/)[1];
        }
        if (channel === channelName) {
            switch (header) {
                case serverOperations.startScraper:
                    appManager.startScraping();
                    break;
                case serverOperations.stopScraper:
                    appManager.stopScraping();
                    break;
                case serverOperations.resumeScraper:
                    appManager.resumeScraping();
                    break;
                case serverOperations.quitScraper:
                    appManager.quitApp();
                    break;
                case serverOperations.setScraperQuery:
                    if (body) {
                        appManager.setScraperQuery(body);
                    }

                    break;
            }
        }
    });
    subscriber.subscribe(channelName);
    logger.info('redisManager: subscribed to ' + channelName);
}

module.exports = {
    initialise: initialise,
};<commit_msg>Fixed server operations require path<commit_after>var redis = require('redis');
var appManager = require('./appManager.js');
var logger = require('../common/logger.js');
var serverOperations = require('../common/serverOperations.js');

var channelName = 'server';
var subscriber = null;

function initialise() {
    logger.info('redisManager: initialise');
    subscriber = redis.createClient();
    logger.info('redisManager: created subscriber client');
    subscriber.on('message', function (channel, message) {
        logger.info('redisManager: message received: ' + message);
        var header = null;
        var body = null;
        if (message) {
            header = message.split(/ (.+)/)[0];
            body = message.split(/ (.+)/)[1];
        }
        if (channel === channelName) {
            switch (header) {
                case serverOperations.startScraper:
                    appManager.startScraping();
                    break;
                case serverOperations.stopScraper:
                    appManager.stopScraping();
                    break;
                case serverOperations.resumeScraper:
                    appManager.resumeScraping();
                    break;
                case serverOperations.quitScraper:
                    appManager.quitApp();
                    break;
                case serverOperations.setScraperQuery:
                    if (body) {
                        appManager.setScraperQuery(body);
                    }

                    break;
            }
        }
    });
    subscriber.subscribe(channelName);
    logger.info('redisManager: subscribed to ' + channelName);
}

module.exports = {
    initialise: initialise,
};<|endoftext|>


<commit_before>var rewire = require('rewire');
var nock = require('nock');

var gt = rewire('../index.js');

describe("The getRequestForPage function", function () {
  it("should return a request bound to the input url", function () {
    var testUrl = "https://www.google.com/";

    var testFunction = gt.__get__("getRequestForPage");
    var boundFunction = testFunction(testUrl);
    var result = boundFunction();

    expect({url: result.uri.href}).toEqual({url: jasmine.stringMatching(
      testUrl.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + "\/?"
    )});
  });
});

describe("The requestWithBodyTextAndUrlCallback function", function () {
  var testFunction = gt.__get__("requestWithBodyTextAndUrlCallback");
  var testUrl = "http://csb.stanford.edu/class/public/pages/sykes_webdesign/05_simple.html";
  var libs = {};
  var cb = null;
  var originalUnfluff = null;

  beforeAll(function (done) {
    libs['request'] = gt.__get__("request");

    spyOn(libs.request, 'get').and.callThrough();
    originalUnfluff = gt.__get__("unfluff");
    gt.__set__("unfluff", jasmine.createSpy().and.callFake(function (page) {
      return {
        text: "unfluff stand-in text"
      };
    }));

    cb = jasmine.createSpy('callback');
    testFunction(testUrl, cb);

    setTimeout(function() {
      done();
    }, 1000);
  });

  afterAll(function () {
    gt.__set__("unfluff", originalUnfluff);
  });

  it("should have called request with the right parameters", function (){
    expect(libs.request.get).toHaveBeenCalledWith({
      uri: testUrl,
      maxRedirects: 3,
      jar: true,
      headers: {"User-Agent": "Chrome/26.0.1410."}
    }, jasmine.any(Function));
  });

  it("should have called unfluff", function () {
    expect(gt.__get__("unfluff")).toHaveBeenCalled();
  });

  it("should have called the callback correctly", function () {
    expect(cb).toHaveBeenCalledWith(null, jasmine.objectContaining({
      pageHtml: "unfluff stand-in text",
      url: testUrl
    }));
  });
});

describe("The cossim function", function() {
  var testFunction = gt.__get__("cossim");

  it("should return a similarity of 1 for vectors that are the same", function () {
    var vec1 = [1, 1, 1];
    var vec2 = [1, 1, 1];
    var result1 = testFunction(vec1, vec2);

    expect(result1).toBeCloseTo(1.00, 2);

    var vec3 = [1, 5, 6, 7, 9];
    var vec4 = [1, 5, 6, 7, 9];
    var result2 = testFunction(vec3, vec4);

    expect(result2).toBeCloseTo(1.00, 2);
  });

  it("should return a similarity of 0 for orthogonal vectors", function () {
    var vec1 = [0, 0, 1];
    var vec2 = [1, 0, 0];
    var result1 = testFunction(vec1, vec2);

    expect(result1).toBeCloseTo(0.00, 2);

    var vec3 = [1, 0 ,0, 1];
    var vec4 = [0, 1, 0, 0];
    var result2 = testFunction(vec3, vec4);

    expect(result2).toBeCloseTo(0.00, 2);
  });

  it("should return a similarity of -1 for opposite vectors", function () {
    var vec1 = [-1, -3, -1, -5, -2, -9];
    var vec2 = [1, 3, 1, 5, 2, 9];
    var result1 = testFunction(vec1, vec2);

    expect(result1).toBeCloseTo(-1.00, 2);
  });

  it("should return correct similarities for test vectors", function () {
    var vec1 = [9, 4, 2, 49, 19, 1, 4, 12];
    var vec2 = [4, 3, 40, 10, 4, 1, 4, 2];
    var result1 = testFunction(vec1, vec2);

    expect(result1).toBeCloseTo(0.3184, 3);

    var vec3 = [2, -1, 4, -10, 5];
    var vec4 = [-1, 3, 2, -3, 4];
    var result2 = testFunction(vec3, vec4);

    expect(result2).toBeCloseTo(0.7024, 3);
  });
});

describe("The filterDomain function", function () {
  it("should filter links from the specified domain", function () {
      var testFunction = gt.__get__("filterDomain");
      var testUrl = "http://www.google.com";
      var filterUrls = [
        {href: "http://www.google.com/search"},
        {href: "http://www.bing.com/search"},
        {href: "https://www.google.com"},
      ];

      var cb = jasmine.createSpy("callback");

      testFunction(filterUrls, testUrl, cb);
      expect(cb).toHaveBeenCalledWith(null, [{href: "http://www.bing.com/search"}], testUrl);
  });
});

describe("The getPageBodies function", function () {
  var cb = null;
  var testLinkObjs = [];
  var testOriginalUrl = "";
  var originalUnfluff = null;

  beforeEach(function (done) {
    originalUnfluff = gt.__get__("unfluff");
    gt.__set__("unfluff", jasmine.createSpy().and.callFake(function (page) {
      return {
        text: page
      };
    }));

    var testServer = nock("http://www.test.com")
      .get("/test1.html")
      .reply(200, "first test page")
      .get("/test2.html")
      .reply(200, "second test page");

    var exampleServer = nock("http://www.example.com")
      .get("/")
      .reply(200, "example page");

    var testFunction = gt.__get__("getPageBodies");
    testOriginalUrl = "http://www.example.com/";
    testLinkObjs = [
      {href: "http://www.test.com/test1.html"},
      {href: "http://www.test.com/test2.html"}
    ];

    cb = jasmine.createSpy('callback');

    testFunction(testLinkObjs, testOriginalUrl, cb);

    setTimeout(() => {done();}, 1000);
  });

  afterEach(function () {
    nock.restore();
    gt.__set__("unfluff", originalUnfluff);
  });

  it("should get pages from input urls", function () {
    expect(cb).toHaveBeenCalledWith(null, [
      {pageHtml: "first test page", url: testLinkObjs[0].href},
      {pageHtml: "second test page", url: testLinkObjs[1].href},
      {pageHtml: "example page", url: testOriginalUrl}
      ]
    );
  });
});
<commit_msg>adding test for getMostSimilarLink<commit_after>var rewire = require('rewire');
var nock = require('nock');

var gt = rewire('../index.js');

describe("The getRequestForPage function", function () {
  it("should return a request bound to the input url", function () {
    var testUrl = "https://www.google.com/";

    var testFunction = gt.__get__("getRequestForPage");
    var boundFunction = testFunction(testUrl);
    var result = boundFunction();

    expect({url: result.uri.href}).toEqual({url: jasmine.stringMatching(
      testUrl.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") + "\/?"
    )});
  });
});

describe("The requestWithBodyTextAndUrlCallback function", function () {
  var testFunction = gt.__get__("requestWithBodyTextAndUrlCallback");
  var testUrl = "http://csb.stanford.edu/class/public/pages/sykes_webdesign/05_simple.html";
  var libs = {};
  var cb = null;
  var originalUnfluff = null;

  beforeAll(function (done) {
    libs['request'] = gt.__get__("request");

    spyOn(libs.request, 'get').and.callThrough();
    originalUnfluff = gt.__get__("unfluff");
    gt.__set__("unfluff", jasmine.createSpy().and.callFake(function (page) {
      return {
        text: "unfluff stand-in text"
      };
    }));

    cb = jasmine.createSpy('callback');
    testFunction(testUrl, cb);

    setTimeout(function() {
      done();
    }, 1000);
  });

  afterAll(function () {
    gt.__set__("unfluff", originalUnfluff);
  });

  it("should have called request with the right parameters", function (){
    expect(libs.request.get).toHaveBeenCalledWith({
      uri: testUrl,
      maxRedirects: 3,
      jar: true,
      headers: {"User-Agent": "Chrome/26.0.1410."}
    }, jasmine.any(Function));
  });

  it("should have called unfluff", function () {
    expect(gt.__get__("unfluff")).toHaveBeenCalled();
  });

  it("should have called the callback correctly", function () {
    expect(cb).toHaveBeenCalledWith(null, jasmine.objectContaining({
      pageHtml: "unfluff stand-in text",
      url: testUrl
    }));
  });
});

describe("The cossim function", function() {
  var testFunction = gt.__get__("cossim");

  it("should return a similarity of 1 for vectors that are the same", function () {
    var vec1 = [1, 1, 1];
    var vec2 = [1, 1, 1];
    var result1 = testFunction(vec1, vec2);

    expect(result1).toBeCloseTo(1.00, 2);

    var vec3 = [1, 5, 6, 7, 9];
    var vec4 = [1, 5, 6, 7, 9];
    var result2 = testFunction(vec3, vec4);

    expect(result2).toBeCloseTo(1.00, 2);
  });

  it("should return a similarity of 0 for orthogonal vectors", function () {
    var vec1 = [0, 0, 1];
    var vec2 = [1, 0, 0];
    var result1 = testFunction(vec1, vec2);

    expect(result1).toBeCloseTo(0.00, 2);

    var vec3 = [1, 0 ,0, 1];
    var vec4 = [0, 1, 0, 0];
    var result2 = testFunction(vec3, vec4);

    expect(result2).toBeCloseTo(0.00, 2);
  });

  it("should return a similarity of -1 for opposite vectors", function () {
    var vec1 = [-1, -3, -1, -5, -2, -9];
    var vec2 = [1, 3, 1, 5, 2, 9];
    var result1 = testFunction(vec1, vec2);

    expect(result1).toBeCloseTo(-1.00, 2);
  });

  it("should return correct similarities for test vectors", function () {
    var vec1 = [9, 4, 2, 49, 19, 1, 4, 12];
    var vec2 = [4, 3, 40, 10, 4, 1, 4, 2];
    var result1 = testFunction(vec1, vec2);

    expect(result1).toBeCloseTo(0.3184, 3);

    var vec3 = [2, -1, 4, -10, 5];
    var vec4 = [-1, 3, 2, -3, 4];
    var result2 = testFunction(vec3, vec4);

    expect(result2).toBeCloseTo(0.7024, 3);
  });
});

describe("The filterDomain function", function () {
  it("should filter links from the specified domain", function () {
      var testFunction = gt.__get__("filterDomain");
      var testUrl = "http://www.google.com";
      var filterUrls = [
        {href: "http://www.google.com/search"},
        {href: "http://www.bing.com/search"},
        {href: "https://www.google.com"},
      ];

      var cb = jasmine.createSpy("callback");

      testFunction(filterUrls, testUrl, cb);
      expect(cb).toHaveBeenCalledWith(null, [{href: "http://www.bing.com/search"}], testUrl);
  });
});

describe("The getPageBodies function", function () {
  var cb = null;
  var testLinkObjs = [];
  var testOriginalUrl = "";
  var originalUnfluff = null;

  beforeEach(function (done) {
    originalUnfluff = gt.__get__("unfluff");
    gt.__set__("unfluff", jasmine.createSpy().and.callFake(function (page) {
      return {
        text: page
      };
    }));

    var testServer = nock("http://www.test.com")
      .get("/test1.html")
      .reply(200, "first test page")
      .get("/test2.html")
      .reply(200, "second test page");

    var exampleServer = nock("http://www.example.com")
      .get("/")
      .reply(200, "example page");

    var testFunction = gt.__get__("getPageBodies");
    testOriginalUrl = "http://www.example.com/";
    testLinkObjs = [
      {href: "http://www.test.com/test1.html"},
      {href: "http://www.test.com/test2.html"}
    ];

    cb = jasmine.createSpy('callback');

    testFunction(testLinkObjs, testOriginalUrl, cb);

    setTimeout(() => {done();}, 1000);
  });

  afterEach(function () {
    nock.restore();
    gt.__set__("unfluff", originalUnfluff);
  });

  it("should get pages from input urls", function () {
    expect(cb).toHaveBeenCalledWith(null, [
      {pageHtml: "first test page", url: testLinkObjs[0].href},
      {pageHtml: "second test page", url: testLinkObjs[1].href},
      {pageHtml: "example page", url: testOriginalUrl}
      ]
    );
  });
});

describe("The getMostSimilarLink function", function () {
  var testFunction = gt.__get__("getMostSimilarLink");
  var testPageObjects = [];

  beforeEach(function () {
    testPageObjects = [
      {url: "http://www.test.com/test1.html", pageHtml: "first test example"},
      {url: "http://www.test.com/test2.html", pageHtml: "second test page"},
      {url: "http://www.example.com/example1.html", pageHtml: "first example page"},
      {url: "http://www.example.com/example2.html", pageHtml: "first test example"}
    ];

    cb = jasmine.createSpy('callback');

    testFunction(testPageObjects, cb);
  });

  it("should call the callback with the correct result", function() {
    expect(cb).toHaveBeenCalledWith(null, "http://www.test.com/test1.html", jasmine.any(Number));
  });
});
<|endoftext|>


<commit_before>//This file includes the functions that use the variables declared in the start file, as well as controlling scene changing

// Shows / hides scene specific information, when clicking trees
function showTextForest1() {
  if(document.getElementById("treeText1").getAttribute("visible") === false) {
    document.getElementById("treeText1").setAttribute("visible", "true");
  } else if(document.getElementById("treeText1").getAttribute("visible") === true) {
    document.getElementById("treeText1").setAttribute("visible", "false");
  }
}
function showTextForest2() {
  if(document.getElementById("treeText2").getAttribute("visible") === false) {
    document.getElementById("treeText2").setAttribute("visible", "true");
  } else if(document.getElementById("treeText2").getAttribute("visible") === true) {
    document.getElementById("treeText2").setAttribute("visible", "false");
  }
}
function showTextForest3() {
  if(document.getElementById("treeText3").getAttribute("visible") === false) {
    document.getElementById("treeText3").setAttribute("visible", "true");
  } else if(document.getElementById("treeText3").getAttribute("visible") === true) {
    document.getElementById("treeText3").setAttribute("visible", "false");
  }
}
function showTextForest4() {
  if(document.getElementById("treeText4").getAttribute("visible") === false) {
    document.getElementById("treeText4").setAttribute("visible", "true");
  } else if(document.getElementById("treeText4").getAttribute("visible") === true) {
    document.getElementById("treeText4").setAttribute("visible", "false");
  }
}

// Shows / hides scene specific information, when clicking trees
function showTextCreek1() {
  if(document.getElementById("creekText1").getAttribute("visible") === false) {
    document.getElementById("creekText1").setAttribute("visible", "true");
  } else if(document.getElementById("creekText1").getAttribute("visible") === true) {
    document.getElementById("creekText1").setAttribute("visible", "false");
  }
}
function showTextCreek2() {
  if(document.getElementById("creekText2").getAttribute("visible") === false) {
    document.getElementById("creekText2").setAttribute("visible", "true");
  } else if(document.getElementById("creekText2").getAttribute("visible") === true) {
    document.getElementById("creekText2").setAttribute("visible", "false");
  }
}
function showTextCreek3() {
  if(document.getElementById("creekText3").getAttribute("visible") === false) {
    document.getElementById("creekText3").setAttribute("visible", "true");
  } else if(document.getElementById("creekText3").getAttribute("visible") === true) {
    document.getElementById("creekText3").setAttribute("visible", "false");
  }
}
function showTextCreek4() {
  if(document.getElementById("creekText4").getAttribute("visible") === false) {
    document.getElementById("creekText4").setAttribute("visible", "true");
  } else if(document.getElementById("creekText4").getAttribute("visible") === true) {
    document.getElementById("creekText4").setAttribute("visible", "false");
  }
}

// Loads Forest Scene
function forestScene() {
    console.log("This is forestScene()");

    //turn off default scene info
    document.getElementById("defText1").setAttribute("visible", "false");
    document.getElementById("defText2").setAttribute("visible", "false");
    document.getElementById("defText3").setAttribute("visible", "false");
    document.getElementById("defText4").setAttribute("visible", "false");

    document.getElementById("debugText").setAttribute("visible", "false");
    document.getElementById("debugText2").setAttribute("visible", "false");
    document.getElementById("instrText").setAttribute("visible", "false");
    document.getElementById("instrText2").setAttribute("visible", "false");

    //make forestStuff entity visible
    panoElement.setAttribute("src", "#forestPano");
    document.getElementById("forestStuff").setAttribute("visible", "true");
    document.getElementById("creekStuff").setAttribute("visible", "false");
    document.getElementById("primitiveStuff").setAttribute("visible", "false");

    // audio = new Audio('https://sdykes3.github.io/forestVR/my-img/forestBest.wav');
    audioForest.play();
    audioCreek.pause();

}

// Loads Creek Scene
function creekScene() {
    console.log("This is creekScene()");

    //turn off default scene info
    document.getElementById("defText1").setAttribute("visible", "false");
    document.getElementById("defText2").setAttribute("visible", "false");
    document.getElementById("defText3").setAttribute("visible", "false");
    document.getElementById("defText4").setAttribute("visible", "false");

    document.getElementById("debugText").setAttribute("visible", "false");
    document.getElementById("debugText2").setAttribute("visible", "false");
    document.getElementById("instrText").setAttribute("visible", "false");
    document.getElementById("instrText2").setAttribute("visible", "false");

    //make creekStuff entity visible
    panoElement.setAttribute("src", "#creekPano");
    document.getElementById("creekStuff").setAttribute("visible", "true");
    document.getElementById("forestStuff").setAttribute("visible", "false");
    document.getElementById("primitiveStuff").setAttribute("visible", "false");

    // audio = new Audio('https://sdykes3.github.io/forestVR/my-img/streamBest.wav');
    audioForest.pause();
    audioCreek.play();

}

// Loads Default Scene
function defaultScene() {
    //turn on default scene info
    document.getElementById("defText1").setAttribute("visible", "true");
    document.getElementById("defText2").setAttribute("visible", "true");
    document.getElementById("defText3").setAttribute("visible", "true");
    document.getElementById("defText4").setAttribute("visible", "true");

    document.getElementById("debugText").setAttribute("visible", "true");
    document.getElementById("debugText2").setAttribute("visible", "true");
    document.getElementById("instrText").setAttribute("visible", "true");
    document.getElementById("instrText2").setAttribute("visible", "true");

    panoElement.setAttribute("src", "#woc");
    document.getElementById("primitiveStuff").setAttribute("visible", "true");
    document.getElementById("forestStuff").setAttribute("visible", "false");
    document.getElementById("creekStuff").setAttribute("visible", "false");

    audioForest.pause();
    audioCreek.pause();

}

//These are geolocation related functions.
function error(err) {
    //Send error details to the console.
    console.warn('ERROR(' + err.code + '): ' + err.message);
   //Displaying an error message.
    var messageElement= document.getElementById("choiceMsg");
    messageElement.innerHTML = "
You weren't able to get the geolocation.
 Check the console for more detail.
";
}

//This function is the one that determines whether to change the scenery or not
//It gets the distance between our current location and our chosen location
function checkReceivedLocation(positionData) {

    console.log("Checking location...");

    currentLocation = positionData.coords;

    //calculating distance with the circleDistance script, for each scene
    var newDistance0=circleDistance(currentLocation.longitude,
                                   currentLocation.latitude,
                                   locations[0].longitude,
                                   locations[0].latitude);

    var newDistance1=circleDistance(currentLocation.longitude,
                                   currentLocation.latitude,
                                   locations[1].longitude,
                                   locations[1].latitude);

    var resultText0="Distance to Forest scene is "+ (newDistance0*1000).toFixed(4) +"m.";

    var resultText1="Distance to Creek scene is "+ (newDistance1*1000).toFixed(4) +"m.";

    console.log(resultText0);
    console.log(resultText1);

    if (newDistance0 <= maxDistance ) {
        //You have reached the location.
        resultText0+="\nForest location was reached! Updating scene now.";
        console.log("Forest location was reached. Updating scene now.");

        inDefault = false;
        inForest = true;
        inCreek = false;
        console.log("Calling forestScene() now.");
        forestScene();

    } else {
        console.log("Forest location hasn't been reached yet.");
        resultText0+=" Location hasn't been reached yet.";

        //If not already displaying default scene, load it - in the event of walking out of range of other scenes
        if(!inDefault && !inCreek) {
          inDefault = true;
          inForest = false;
          inCreek = false;
          defaultScene();
        }
    }

    if (newDistance1 <= maxDistance ) {
        //You have reached the location.
        resultText1+="\nCreek location was reached! Updating scene now.";
        console.log("Creek location  was reached. Updating scene now.");

        inDefault = false;
        inForest = false;
        inCreek = true;
        console.log("Calling creekScene() now.");
        creekScene();

    } else {
        console.log("Creek location hasn't been reached yet.");
        resultText1+=" Location hasn't been reached yet.";

        //If not already displaying default scene, load it - in the event of walking out of range of other scenes
        if(!inDefault && !inForest) {
          inDefault = true;
          inForest = false;
          inCreek = false;
          defaultScene();
        }
    }

    debugText.setAttribute('text', resultText0);
    debugText2.setAttribute('text', resultText1);

}
<commit_msg>Update instruction text<commit_after>//This file includes the functions that use the variables declared in the start file, as well as controlling scene changing

// Shows / hides scene specific information, when clicking trees
function showTextForest1() {
  if(document.getElementById("treeText1").getAttribute("visible") === false) {
    document.getElementById("treeText1").setAttribute("visible", "true");
  } else if(document.getElementById("treeText1").getAttribute("visible") === true) {
    document.getElementById("treeText1").setAttribute("visible", "false");
  }
}
function showTextForest2() {
  if(document.getElementById("treeText2").getAttribute("visible") === false) {
    document.getElementById("treeText2").setAttribute("visible", "true");
  } else if(document.getElementById("treeText2").getAttribute("visible") === true) {
    document.getElementById("treeText2").setAttribute("visible", "false");
  }
}
function showTextForest3() {
  if(document.getElementById("treeText3").getAttribute("visible") === false) {
    document.getElementById("treeText3").setAttribute("visible", "true");
  } else if(document.getElementById("treeText3").getAttribute("visible") === true) {
    document.getElementById("treeText3").setAttribute("visible", "false");
  }
}
function showTextForest4() {
  if(document.getElementById("treeText4").getAttribute("visible") === false) {
    document.getElementById("treeText4").setAttribute("visible", "true");
  } else if(document.getElementById("treeText4").getAttribute("visible") === true) {
    document.getElementById("treeText4").setAttribute("visible", "false");
  }
}

// Shows / hides scene specific information, when clicking trees
function showTextCreek1() {
  if(document.getElementById("creekText1").getAttribute("visible") === false) {
    document.getElementById("creekText1").setAttribute("visible", "true");
  } else if(document.getElementById("creekText1").getAttribute("visible") === true) {
    document.getElementById("creekText1").setAttribute("visible", "false");
  }
}
function showTextCreek2() {
  if(document.getElementById("creekText2").getAttribute("visible") === false) {
    document.getElementById("creekText2").setAttribute("visible", "true");
  } else if(document.getElementById("creekText2").getAttribute("visible") === true) {
    document.getElementById("creekText2").setAttribute("visible", "false");
  }
}
function showTextCreek3() {
  if(document.getElementById("creekText3").getAttribute("visible") === false) {
    document.getElementById("creekText3").setAttribute("visible", "true");
  } else if(document.getElementById("creekText3").getAttribute("visible") === true) {
    document.getElementById("creekText3").setAttribute("visible", "false");
  }
}
function showTextCreek4() {
  if(document.getElementById("creekText4").getAttribute("visible") === false) {
    document.getElementById("creekText4").setAttribute("visible", "true");
  } else if(document.getElementById("creekText4").getAttribute("visible") === true) {
    document.getElementById("creekText4").setAttribute("visible", "false");
  }
}

// Loads Forest Scene
function forestScene() {
    console.log("This is forestScene()");

    //turn off default scene info
    document.getElementById("defText1").setAttribute("visible", "false");
    document.getElementById("defText2").setAttribute("visible", "false");
    document.getElementById("defText3").setAttribute("visible", "false");
    document.getElementById("defText4").setAttribute("visible", "false");

    document.getElementById("debugText").setAttribute("visible", "false");
    document.getElementById("debugText2").setAttribute("visible", "false");
    document.getElementById("instrText").setAttribute("visible", "false");
    document.getElementById("instrText2").setAttribute("visible", "false");

    //make forestStuff entity visible
    panoElement.setAttribute("src", "#forestPano");
    document.getElementById("forestStuff").setAttribute("visible", "true");
    document.getElementById("creekStuff").setAttribute("visible", "false");
    document.getElementById("primitiveStuff").setAttribute("visible", "false");

    // audio = new Audio('https://sdykes3.github.io/forestVR/my-img/forestBest.wav');
    audioForest.play();
    audioCreek.pause();

}

// Loads Creek Scene
function creekScene() {
    console.log("This is creekScene()");

    //turn off default scene info
    document.getElementById("defText1").setAttribute("visible", "false");
    document.getElementById("defText2").setAttribute("visible", "false");
    document.getElementById("defText3").setAttribute("visible", "false");
    document.getElementById("defText4").setAttribute("visible", "false");

    document.getElementById("debugText").setAttribute("visible", "false");
    document.getElementById("debugText2").setAttribute("visible", "false");
    document.getElementById("instrText").setAttribute("visible", "false");
    document.getElementById("instrText2").setAttribute("visible", "false");

    //make creekStuff entity visible
    panoElement.setAttribute("src", "#creekPano");
    document.getElementById("creekStuff").setAttribute("visible", "true");
    document.getElementById("forestStuff").setAttribute("visible", "false");
    document.getElementById("primitiveStuff").setAttribute("visible", "false");

    // audio = new Audio('https://sdykes3.github.io/forestVR/my-img/streamBest.wav');
    audioForest.pause();
    audioCreek.play();

}

// Loads Default Scene
function defaultScene() {
    //turn on default scene info
    document.getElementById("defText1").setAttribute("visible", "true");
    document.getElementById("defText2").setAttribute("visible", "true");
    document.getElementById("defText3").setAttribute("visible", "true");
    document.getElementById("defText4").setAttribute("visible", "true");

    document.getElementById("debugText").setAttribute("visible", "true");
    document.getElementById("debugText2").setAttribute("visible", "true");
    document.getElementById("instrText").setAttribute("visible", "true");
    document.getElementById("instrText2").setAttribute("visible", "true");

    panoElement.setAttribute("src", "#woc");
    document.getElementById("primitiveStuff").setAttribute("visible", "true");
    document.getElementById("forestStuff").setAttribute("visible", "false");
    document.getElementById("creekStuff").setAttribute("visible", "false");

    audioForest.pause();
    audioCreek.pause();

}

//These are geolocation related functions.
function error(err) {
    //Send error details to the console.
    console.warn('ERROR(' + err.code + '): ' + err.message);
   //Displaying an error message.
    var messageElement= document.getElementById("choiceMsg");
    messageElement.innerHTML = "
You weren't able to get the geolocation.
 Check the console for more detail.
";
}

//This function is the one that determines whether to change the scenery or not
//It gets the distance between our current location and our chosen location
function checkReceivedLocation(positionData) {

    console.log("Checking location...");

    currentLocation = positionData.coords;

    //calculating distance with the circleDistance script, for each scene
    var newDistance0=circleDistance(currentLocation.longitude,
                                   currentLocation.latitude,
                                   locations[0].longitude,
                                   locations[0].latitude);

    var newDistance1=circleDistance(currentLocation.longitude,
                                   currentLocation.latitude,
                                   locations[1].longitude,
                                   locations[1].latitude);

    var resultText0="Distance to Forest scene is "+ (newDistance0*1000).toFixed(2) +"m.";

    var resultText1="Distance to Creek scene is "+ (newDistance1*1000).toFixed(2) +"m.";

    console.log(resultText0);
    console.log(resultText1);

    if (newDistance0 <= maxDistance ) {
        //You have reached the location.
        resultText0+="\nForest location was reached! Updating scene now.";
        console.log("Forest location was reached. Updating scene now.");

        inDefault = false;
        inForest = true;
        inCreek = false;
        console.log("Calling forestScene() now.");
        forestScene();

    } else {
        console.log("Forest location hasn't been reached yet.");
        resultText0+=" Location hasn't been reached yet.";

        //If not already displaying default scene, load it - in the event of walking out of range of other scenes
        if(!inDefault && !inCreek) {
          inDefault = true;
          inForest = false;
          inCreek = false;
          defaultScene();
        }
    }

    if (newDistance1 <= maxDistance ) {
        //You have reached the location.
        resultText1+="\nCreek location was reached! Updating scene now.";
        console.log("Creek location  was reached. Updating scene now.");

        inDefault = false;
        inForest = false;
        inCreek = true;
        console.log("Calling creekScene() now.");
        creekScene();

    } else {
        console.log("Creek location hasn't been reached yet.");
        resultText1+=" Location hasn't been reached yet.";

        //If not already displaying default scene, load it - in the event of walking out of range of other scenes
        if(!inDefault && !inForest) {
          inDefault = true;
          inForest = false;
          inCreek = false;
          defaultScene();
        }
    }

    debugText.setAttribute('text', resultText0);
    debugText2.setAttribute('text', resultText1);

}
<|endoftext|>


<commit_before>const colors = {
  turquoise: 0x47debd,
  darkPurple: 0x2e044e,
  purple: 0x7821ec,
  yellow: 0xfff95d,
  white: 0xffffff,
  black: 0x000000
};

const root = new THREERoot({
  createCameraControls: true,
  zNear: 0.01,
  zFar: 1000,
  antialias: true
});

root.renderer.shadowMap.enabled = true;
root.renderer.setClearColor(0xf1f1f1);
root.camera.position.set(20, 10, 40);

const light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.set(0, 1, 0);
root.add(light);

const light2 = new THREE.DirectionalLight(0xffffff, 0.5);
light2.position.set(0, -1, 0);
root.add(light2);

// root.add(new THREE.AmbientLight(colors.purple));

root.add(new THREE.AxisHelper(40));

var brownMat = new THREE.MeshStandardMaterial({
  color: 0xffffff,
  flatShading: true,
  roughness: 1.0
});

Hero = function() {
  this.runningCycle = 0;
  this.mesh = new THREE.Group();
  this.body = new THREE.Group();
  this.mesh.add(this.body);

  var torsoGeom = new THREE.CubeGeometry(8,8,8, 1);//
  this.torso = new THREE.Mesh(torsoGeom, brownMat);
  this.torso.position.y = 8;
  this.torso.castShadow = true;
  this.body.add(this.torso);

  var handGeom = new THREE.CubeGeometry(3,3,3, 1);
  this.handR = new THREE.Mesh(handGeom, brownMat);
  this.handR.position.z=7;
  this.handR.position.y=8;
  this.body.add(this.handR);

  this.handL = this.handR.clone();
  this.handL.position.z = - this.handR.position.z;
  this.body.add(this.handL);

  var headGeom = new THREE.SphereGeometry(4, 48, 32);

  this.head = new FuzzyMesh({
    geometry: headGeom,
    materialUniformValues: {
      roughness: 1.0
    },
    config: {
      hairLength: 4,
      hairRadiusBase: 0.25,
      gravity: 2,
      fuzz: 0.25,
      minForceFactor: 0.5,
      maxForceFactor: 2.0
    }
  });

  this.head.position.y = 21;
  this.head.castShadow = true;
  this.body.add(this.head);

  var legGeom = new THREE.CubeGeometry(8,3,5, 1);

  this.legR = new THREE.Mesh(legGeom, brownMat);
  this.legR.position.x = 0;
  this.legR.position.z = 7;
  this.legR.position.y = 0;
  this.legR.castShadow = true;
  this.body.add(this.legR);

  this.legL = this.legR.clone();
  this.legL.position.z = - this.legR.position.z;
  this.legL.castShadow = true;
  this.body.add(this.legL);

  this.body.traverse(function(object) {
    if (object instanceof THREE.Mesh) {
      object.castShadow = true;
      object.receiveShadow = true;
    }
  });
};

Hero.prototype.run = function(){
  var s = 0.1;
  var t = this.runningCycle;

  t = t % (2*Math.PI);

  var amp = 4;
  var disp = .2;

  this.legR.rotation.z = 0;
  this.legR.position.y = 0;
  this.legR.position.x = 0;
  this.legL.rotation.z = 0;
  this.legL.position.y = 0;
  this.legL.position.x = 0;

  this.runningCycle += s;
  this.legR.position.x =  Math.cos(t) * amp;
  this.legR.position.y = - Math.sin(t) * amp;

  this.legL.position.x =  Math.cos(t + Math.PI) * amp;
  this.legL.position.y = - Math.sin(t + Math.PI) * amp;

  this.legL.position.y = Math.max (0, this.legL.position.y);
  this.legR.position.y = Math.max (0, this.legR.position.y);

  this.torso.position.y = 8 - Math.cos(  t * 2 ) * amp * .2;
  // this.head.position.y = 21 - Math.cos(  t * 2 ) * amp * .3;
  this.head.setPosition(new THREE.Vector3(
    this.head.position.x,
    21 - Math.cos(  t * 2 ) * amp * .3,
    this.head.position.z
  ));

  this.torso.rotation.y = -Math.cos( t + Math.PI ) * amp * .05;

  this.handR.position.x = -Math.cos( t ) * amp;
  this.handR.rotation.z = -Math.cos( t ) * Math.PI/8;
  this.handL.position.x = -Math.cos( t + Math.PI) * amp;
  this.handL.rotation.z = -Math.cos( t + Math.PI) * Math.PI/8;

  this.head.rotation.x = Math.cos( t ) * amp * .02;
  this.head.rotation.y =  Math.cos( t ) * amp * .01;

  if (t>Math.PI){
    this.legR.rotation.z = Math.cos(t * 2 + Math.PI/2) * Math.PI/4;
    this.legL.rotation.z = 0;
  } else{
    this.legR.rotation.z = 0;
    this.legL.rotation.z = Math.cos(t * 2 + Math.PI/2) *  Math.PI/4;
  }

  this.head.update();
};

const hero = new Hero();

hero.mesh.position.y = -15;
root.add(hero.mesh);

root.addUpdateCallback(() => {
  hero.run();
});

// new THREE.JSONLoader().load('https://s3-us-west-2.amazonaws.com/s.cdpn.io/304639/plus.json', (geometry) => {
//   // test shapes, try different ones :D
//   // model = new THREE.SphereGeometry(1, 16, 16);
//   // model = new THREE.PlaneGeometry(40, 10, 200, 40);
//   // model = new THREE.CylinderGeometry(2, 2, 8, 128, 64, true);
//   // model = new THREE.TorusGeometry(8, 1, 128, 256);
//   // model = new THREE.TorusKnotGeometry(2, 0.1, 64, 64, 3, 5);
//
//   const fuzzy = new FuzzyMesh({
//     geometry: geometry,
//     // directions: model.vertices,
//     config: {
//       hairLength: 2,
//       hairRadialSegments: 4,
//       hairRadiusTop: 0.0,
//       hairRadiusBase: 0.1,
//     },
//     materialUniformValues: {
//       roughness: 1.0
//     }
//   });
//   root.add(fuzzy);
//   root.addUpdateCallback(() => {
//     fuzzy.update();
//   });
//
//   const axes = [
//     new THREE.Vector3(1, 0, 0),
//     new THREE.Vector3(0, 1, 0),
//     new THREE.Vector3(0, 0, 1),
//   ];
//
//   const proxy = {
//     position: new THREE.Vector3(),
//     angle: 0,
//   };
//
//   const tl = new TimelineMax({
//     repeat: -1,
//     delay: 1,
//     repeatDelay: 1,
//     onRepeat: () => {
//       fuzzy.setRotationAxis(BAS.Utils.randomAxis());
//       // fuzzy.setRotationAxis(axes[Math.random() * 3 | 0]);
//     },
//     onUpdate: () => {
//       fuzzy.setPosition(proxy.position);
//       fuzzy.setRotationAngle(proxy.angle);
//     }
//   });
//
//   tl.to(proxy.position, 0.5, {y: 8, ease: Power2.easeOut});
//   tl.to(proxy.position, 0.5, {y: 0, ease: Power2.easeIn});
//   tl.to(proxy.position, 0.1, {y: -2, ease: Power2.easeOut});
//   tl.to(proxy.position, 0.5, {y: 0, ease: Power2.easeOut});
//   tl.fromTo(proxy, 1.0, {angle: 0}, {angle: Math.Math.PI * 2 * (Math.random() > 0.5 ? 1 : -1), ease: Power1.easeInOut}, 0);
// });
<commit_msg>character animation setup, needs configs and optims<commit_after>const colors = {
  turquoise: 0x47debd,
  darkPurple: 0x2e044e,
  purple: 0x7821ec,
  yellow: 0xfff95d,
  white: 0xffffff,
  black: 0x000000
};

// hero class

function Hero() {
  this.runningCycle = 0;
  this.mesh = new THREE.Group();
  this.body = new THREE.Group();
  this.mesh.add(this.body);

  this.torso = new FuzzyMesh({
    geometry: new THREE.SphereGeometry(4, 48, 32),
    materialUniformValues: {
      roughness: 1.0
    },
    config: {
      hairLength: 4,
      hairRadiusBase: 0.25,
      gravity: 2,
      fuzz: 0.25,
      minForceFactor: 0.5,
      maxForceFactor: 2.0,
      centrifugalForceFactor: 4,
    }
  });
  this.torso.position.y = 8;
  this.body.add(this.torso);

  this.handR = new FuzzyMesh({
    geometry: new THREE.SphereGeometry(1, 32, 32),
    materialUniformValues: {
      roughness: 1.0
    },
    config: {
      hairLength: 2,
      hairRadiusBase: 0.25,
      gravity: 2,
      fuzz: 0.25,
      minForceFactor: 0.5,
      maxForceFactor: 2.0
    }
  });
  this.handR.position.z = 7;
  this.handR.position.y = 8;
  this.handR.setRotationAxis(new THREE.Vector3(0, 0, 1));
  this.body.add(this.handR);

  this.handL = new FuzzyMesh({
    geometry: new THREE.SphereGeometry(1, 32, 32),
    materialUniformValues: {
      roughness: 1.0
    },
    config: {
      hairLength: 2,
      hairRadiusBase: 0.25,
      gravity: 2,
      fuzz: 0.25,
      minForceFactor: 0.5,
      maxForceFactor: 2.0
    }
  });
  this.handL.position.y = 8;
  this.handL.position.z = - this.handR.position.z;
  this.handL.setRotationAxis(new THREE.Vector3(0, 0, 1));
  this.body.add(this.handL);

  this.head = new FuzzyMesh({
    geometry: new THREE.SphereGeometry(4, 48, 32),
    materialUniformValues: {
      roughness: 1.0
    },
    config: {
      hairLength: 4,
      hairRadiusBase: 0.25,
      gravity: 2,
      fuzz: 0.25,
      minForceFactor: 0.5,
      maxForceFactor: 2.0
    }
  });

  this.head.position.y = 21;
  this.head.castShadow = true;
  this.head.setRotationAxis(new THREE.Vector3(1, 0, 0));
  this.body.add(this.head);

  this.legR = new FuzzyMesh({
    geometry: new THREE.SphereGeometry(3, 48, 16, 0, Math.PI * 2, 0, Math.PI * 0.5),
    materialUniformValues: {
      roughness: 1.0,
      side: THREE.DoubleSide
    },
    config: {
      hairLength: 2,
      hairRadiusBase: 0.25,
      gravity: 2,
      fuzz: 0.25,
      minForceFactor: 0.5,
      maxForceFactor: 2.0
    }
  });
  this.legR.position.z = 6;
  this.legR.setRotationAxis(new THREE.Vector3(0, 0, 1));
  this.body.add(this.legR);

  this.legL = new FuzzyMesh({
    geometry: new THREE.SphereGeometry(3, 48, 16, 0, Math.PI * 2, 0, Math.PI * 0.5),
    materialUniformValues: {
      roughness: 1.0,
      side: THREE.DoubleSide
    },
    config: {
      hairLength: 2,
      hairRadiusBase: 0.25,
      gravity: 2,
      fuzz: 0.25,
      minForceFactor: 0.5,
      maxForceFactor: 2.0
    }
  });
  this.legL.position.z = -6;
  this.legL.setRotationAxis(new THREE.Vector3(0, 0, 1));
  this.body.add(this.legL);
};

Hero.prototype.run = function(){
  var s = 0.1;
  var t = this.runningCycle;
  var amp = 4;

  t = t % (2*Math.PI);

  this.runningCycle += s;

  this.torso.setPosition(new THREE.Vector3(
    this.torso.position.x,
    8 - Math.cos(  t * 2 ) * amp * .2,
    this.torso.position.z
  ));

  this.head.setPosition(new THREE.Vector3(
    this.head.position.x,
    16 - Math.cos(  t * 2 ) * amp * .3,
    this.head.position.z
  ));

  this.torso.setRotationAngle(-Math.cos( t + Math.PI ) * amp * .05);

  this.handR.setPosition(new THREE.Vector3(
    -Math.cos( t ) * amp,
    this.handR.position.y,
    this.handR.position.z
  ));
  this.handR.setRotationAngle(-Math.cos(t) * Math.PI / 8);

  this.handL.setPosition(new THREE.Vector3(
    -Math.cos( t + Math.PI) * amp,
    this.handL.position.y,
    this.handL.position.z
  ));
  this.handL.setRotationAngle(-Math.cos(t + Math.PI) * Math.PI / 8);

  this.head.setRotationAngle(Math.cos(t) * amp * .02);
  // this.head.rotation.y =  Math.cos( t ) * amp * .01;

  this.legR.setPosition(new THREE.Vector3(
    Math.cos(t) * amp,
    Math.max(0, -Math.sin(t) * amp),
    6
  ));

  this.legL.setPosition(new THREE.Vector3(
    Math.cos(t + Math.PI) * amp,
    Math.max(0, -Math.sin(t + Math.PI) * amp),
    -6
  ));

  if (t > Math.PI){
    this.legR.setRotationAngle(Math.cos(t * 2 + Math.PI / 2) *  Math.PI / 4);
    this.legL.setRotationAngle(0);
  }
  else {
    this.legR.setRotationAngle(0);
    this.legL.setRotationAngle(Math.cos(t * 2 + Math.PI / 2) *  Math.PI / 4);
  }

  this.torso.update();
  this.head.update();
  this.handL.update();
  this.handR.update();
  this.legL.update();
  this.legR.update();
};

// scene stuff

const root = new THREERoot({
  createCameraControls: true,
  zNear: 0.01,
  zFar: 1000,
  antialias: true
});

root.renderer.shadowMap.enabled = true;
root.renderer.setClearColor(0xf1f1f1);
root.camera.position.set(30, 10, 30);

const light = new THREE.DirectionalLight(0xffffff, 0.5);
light.position.set(0, 1, 0);
root.add(light);

const light2 = new THREE.DirectionalLight(0xffffff, 0.5);
light2.position.set(0, -1, 0);
root.add(light2);

// root.add(new THREE.AmbientLight(colors.purple));
// root.add(new THREE.AxisHelper(40));

const hero = new Hero();
hero.mesh.position.y = -8;
root.add(hero.mesh);

root.addUpdateCallback(() => {
  hero.run();
});
<|endoftext|>