<commit_before>var weConfig = require('../config')
var OAuth = require('wechat-oauth')
var WechatAPI = require('wechat-api')
var request = require('request')

var fsm = require('./fsm')
var voiceReq = require('./voiceRequest')

var client = new OAuth(weConfig.appid, weConfig.secret)
var api = new WechatAPI(weConfig.appid, weConfig.secret)

module.exports = function(req, res, next) {
	var msg = req.weixin

	if (msg.MsgType === 'event' && msg.Event === 'subscribe') {
		var bindingUrl = client.getAuthorizeURL('http://roscoe.cn/info', 'binding', 'snsapi_userinfo')
		res.reply('等你好久了！点击这里以完成绑定(ง •_•)ง')
		next()
	}

	if (msg.MsgType === 'text') {
        getChatRes(msg.Content, function(resText){
            res.reply(resText)
            next()
        })
	}

	if (msg.MsgType === 'voice') {
		var recognition = msg.Recognition

		if (recognition && recognition !== "") {
            // 微信自带语义分析，查看是否是提醒
			api.semantic(msg.FromUserName, {
				query: recognition,
				category: 'remind',
				city: '上海'
			}, function(err, result) {
				if (err || result.errcode) {
                    // 自定义规则
                    fsm.start(recognition, function(fsmRes){
                        if(fsmRes && voiceReq[fsmRes.action]){
                            voiceReq[fsmRes.action](fsmRes, function(resText){
                                res.reply(resText)
                                next()
                            })
                        } else{
                            // 其它消息交给聊天机器人
                            getChatRes(recognition, function(resText){
                                res.reply(resText)
                                next()
                            })
                        }
                    })
				} else {
					var remindText = '已设置提醒：\n'
                        + semantic.datetime.date_ori
                        + semantic.datetime.time_ori + '：'
                        + semantic.event + '\n\n'
                        + '如需取消提醒请点击这里'

					res.reply(remindText)
                    next()
				}
			})
		} else {
			res.reply('不好意思没有听清(´_ゝ`)')
			next()
		}
	}
}

function getChatRes(msgText, callback){
    request.post({
        url: 'http://dev.hivoice.cn/exp_center/nlu/testService2Demo.action',
        form: {
            serviceId: 6,
            question: msgText
        }
    }, function(err, httpResponse, body) {
        if (err) {
            callback('服务器出了点小问题(´_ゝ`)')
        } else {
            var chatResMsg = body.match(/"text\\":\\".+?\\"/g)[1].slice(10).slice(0, -2)
            callback(chatResMsg)
        }
    })
}
<commit_msg>test semantic<commit_after>var weConfig = require('../config')
var OAuth = require('wechat-oauth')
var WechatAPI = require('wechat-api')
var request = require('request')

var fsm = require('./fsm')
var voiceReq = require('./voiceRequest')

var client = new OAuth(weConfig.appid, weConfig.secret)
var api = new WechatAPI(weConfig.appid, weConfig.secret)

module.exports = function(req, res, next) {
	var msg = req.weixin

	if (msg.MsgType === 'event' && msg.Event === 'subscribe') {
		var bindingUrl = client.getAuthorizeURL('http://roscoe.cn/info', 'binding', 'snsapi_userinfo')
		res.reply('等你好久了！点击这里以完成绑定(ง •_•)ง')
		next()
	}

	if (msg.MsgType === 'text') {
        getChatRes(msg.Content, function(resText){
            res.reply(resText)
            next()
        })
	}

	if (msg.MsgType === 'voice') {
		var recognition = msg.Recognition

		if (recognition && recognition !== "") {
            // 微信自带语义分析，查看是否是提醒
			api.semantic(msg.FromUserName, {
				query: recognition,
				category: 'remind',
				city: '上海'
			}, function(err, result) {
				if (err || result.errcode) {
                    // 自定义规则
                    fsm.start(recognition, function(fsmRes){
                        if(fsmRes && voiceReq[fsmRes.action]){
                            voiceReq[fsmRes.action](fsmRes, function(resText){
                                res.reply(resText)
                                next()
                            })
                        } else{
                            // 其它消息交给聊天机器人
                            getChatRes(recognition, function(resText){
                                res.reply(resText)
                                next()
                            })
                        }
                    })
				} else {
					var remindText = '已设置提醒：\n'
                        + result.semantic.datetime.date_ori
                        + result.semantic.datetime.time_ori + '：'
                        + result.semantic.event + '\n\n'
                        + '如需取消提醒请点击这里'

					res.reply(remindText)
                    next()
				}
			})
		} else {
			res.reply('不好意思没有听清(´_ゝ`)')
			next()
		}
	}
}

function getChatRes(msgText, callback){
    request.post({
        url: 'http://dev.hivoice.cn/exp_center/nlu/testService2Demo.action',
        form: {
            serviceId: 6,
            question: msgText
        }
    }, function(err, httpResponse, body) {
        if (err) {
            callback('服务器出了点小问题(´_ゝ`)')
        } else {
            var chatResMsg = body.match(/"text\\":\\".+?\\"/g)[1].slice(10).slice(0, -2)
            callback(chatResMsg)
        }
    })
}
<|endoftext|>


<commit_before>/* eslint-disable no-console */
const commando = require('discord.js-commando');
const oneLine = require('common-tags').oneLine;
const path = require('path');

const token = require('./auth.json').token;

const client = new commando.Client({
	owner: '81440962496172032',
	commandPrefix: 'c!',
	disableEveryone: true,
	messageCacheLifetime: 30,
	messageSweepInterval: 60,
	disabledEvents: [
		'GUILD_CREATE',
		'GUILD_DELETE',
		'GUILD_UPDATE',
		'GUILD_UNAVAILABLE',
		'GUILD_AVAILABLE',
		'GUILD_MEMBER_UPDATE',
		'GUILD_MEMBER_AVAILABLE',
		'GUILD_MEMBER_SPEAKING',
		'GUILD_ROLE_CREATE',
		'GUILD_ROLE_DELETE',
		'GUILD_ROLE_UPDATE',
		'CHANNEL_CREATE',
		'CHANNEL_DELETE',
		'CHANNEL_UPDATE',
		'CHANNEL_PINS_UPDATE',
		'MESSAGE_DELETE_BULK',
		'USER_UPDATE',
		'USER_NOTE_UPDATE',
		'PRESENCE_UPDATE',
		'TYPING_START',
		'TYPING_STOP',
		'VOICE_STATE_UPDATE',
		'FRIEND_ADD',
		'FRIEND_REMOVE',
		'RELATIONSHIP_ADD',
		'RELATIONSHIP_REMOVE'
	]
});

client.on('error', console.error)
	.on('warn', console.warn)
	.on('ready', () => {
		console.log(`Client ready; logged in as ${client.user.username}#${client.user.discriminator} (${client.user.id})`);
	})
	.on('disconnect', () => { console.warn('Disconnected!'); })
	.on('reconnect', () => { console.warn('Reconnecting...'); })
	.on('commandError', (cmd, err) => {
		if (err instanceof commando.FriendlyError) return;
		console.error(`Error in command ${cmd.groupID}:${cmd.memberName}`, err);
	})
	.on('commandBlocked', (msg, reason) => {
		console.log(oneLine`
			Command ${msg.command ? `${msg.command.groupID}:${msg.command.memberName}` : ''}
			blocked; ${reason}
		`);
	})
	.on('commandPrefixChange', (guild, prefix) => {
		console.log(oneLine`
			Prefix changed to ${prefix || 'the default'}
			${guild ? `in guild ${guild.name} (${guild.id})` : 'globally'}.
		`);
	})
	.on('commandStatusChange', (guild, command, enabled) => {
		console.log(oneLine`
			Command ${command.groupID}:${command.memberName}
			${enabled ? 'enabled' : 'disabled'}
			${guild ? `in guild ${guild.name} (${guild.id})` : 'globally'}.
		`);
	})
	.on('groupStatusChange', (guild, group, enabled) => {
		console.log(oneLine`
			Group ${group.id}
			${enabled ? 'enabled' : 'disabled'}
			${guild ? `in guild ${guild.name} (${guild.id})` : 'globally'}.
		`);
	})
	.on('guildMemberAdd', member => {
		member.guild.channels.get('232305140672102400').sendMessage(`**${member.user.username}#${member.user.discriminator}** (ID: ${member.user.id}) has joined us.`);
	})
	.on('guildMemberRemove', member => {
		member.guild.channels.get('232305140672102400').sendMessage(`**${member.user.username}#${member.user.discriminator}** (ID: ${member.user.id}) has left us.`);
	});

client.registry
	.registerGroups([
		['info', 'Info'],
		['math', 'Math'],
		['fun', 'Fun'],
		['music', 'Music'],
		['tags', 'Tags'],
		['rep', 'Reputation']
	])
	.registerDefaults()
	.registerCommandsIn(path.join(__dirname, 'commands'));

client.login(token);
<commit_msg>Change memberAdd & remove to mentions<commit_after>/* eslint-disable no-console */
const commando = require('discord.js-commando');
const oneLine = require('common-tags').oneLine;
const path = require('path');

const token = require('./auth.json').token;

const client = new commando.Client({
	owner: '81440962496172032',
	commandPrefix: 'c!',
	disableEveryone: true,
	messageCacheLifetime: 30,
	messageSweepInterval: 60,
	disabledEvents: [
		'GUILD_CREATE',
		'GUILD_DELETE',
		'GUILD_UPDATE',
		'GUILD_UNAVAILABLE',
		'GUILD_AVAILABLE',
		'GUILD_MEMBER_UPDATE',
		'GUILD_MEMBER_AVAILABLE',
		'GUILD_MEMBER_SPEAKING',
		'GUILD_ROLE_CREATE',
		'GUILD_ROLE_DELETE',
		'GUILD_ROLE_UPDATE',
		'CHANNEL_CREATE',
		'CHANNEL_DELETE',
		'CHANNEL_UPDATE',
		'CHANNEL_PINS_UPDATE',
		'MESSAGE_DELETE_BULK',
		'USER_UPDATE',
		'USER_NOTE_UPDATE',
		'PRESENCE_UPDATE',
		'TYPING_START',
		'TYPING_STOP',
		'VOICE_STATE_UPDATE',
		'FRIEND_ADD',
		'FRIEND_REMOVE',
		'RELATIONSHIP_ADD',
		'RELATIONSHIP_REMOVE'
	]
});

client.on('error', console.error)
	.on('warn', console.warn)
	.on('ready', () => {
		console.log(`Client ready; logged in as ${client.user.username}#${client.user.discriminator} (${client.user.id})`);
	})
	.on('disconnect', () => { console.warn('Disconnected!'); })
	.on('reconnect', () => { console.warn('Reconnecting...'); })
	.on('commandError', (cmd, err) => {
		if (err instanceof commando.FriendlyError) return;
		console.error(`Error in command ${cmd.groupID}:${cmd.memberName}`, err);
	})
	.on('commandBlocked', (msg, reason) => {
		console.log(oneLine`
			Command ${msg.command ? `${msg.command.groupID}:${msg.command.memberName}` : ''}
			blocked; ${reason}
		`);
	})
	.on('commandPrefixChange', (guild, prefix) => {
		console.log(oneLine`
			Prefix changed to ${prefix || 'the default'}
			${guild ? `in guild ${guild.name} (${guild.id})` : 'globally'}.
		`);
	})
	.on('commandStatusChange', (guild, command, enabled) => {
		console.log(oneLine`
			Command ${command.groupID}:${command.memberName}
			${enabled ? 'enabled' : 'disabled'}
			${guild ? `in guild ${guild.name} (${guild.id})` : 'globally'}.
		`);
	})
	.on('groupStatusChange', (guild, group, enabled) => {
		console.log(oneLine`
			Group ${group.id}
			${enabled ? 'enabled' : 'disabled'}
			${guild ? `in guild ${guild.name} (${guild.id})` : 'globally'}.
		`);
	})
	.on('guildMemberAdd', member => {
		member.guild.channels.get('232305140672102400').sendMessage(`**${member}** (ID: ${member.user.id}) has joined us.`);
	})
	.on('guildMemberRemove', member => {
		member.guild.channels.get('232305140672102400').sendMessage(`**${member}** (ID: ${member.user.id}) has left us.`);
	});

client.registry
	.registerGroups([
		['info', 'Info'],
		['math', 'Math'],
		['fun', 'Fun'],
		['music', 'Music'],
		['tags', 'Tags'],
		['rep', 'Reputation']
	])
	.registerDefaults()
	.registerCommandsIn(path.join(__dirname, 'commands'));

client.login(token);
<|endoftext|>


<commit_before><commit_msg>fixing Hot Swing<commit_after><|endoftext|>


<commit_before>
function guid() {
	function _p8(s) {
		var p = (Math.random().toString(16)+"000000000").substr(2,8);
		return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
	}
	return _p8() + _p8(true) + _p8(true) + _p8();
}

function CrocBase(root){

	if(root !== this) {
		if(typeof root !== 'object' || root.getRoot() !== root) {
			this.error('Was passed a root that may not in fact be a root!');
		}
	}

	this.uuid = guid();
	this.parent = null;
	this.children = [];
	this.lastTransform = [1, 0, 0, 1, 0, 0];
	this.width = 0;
	this.height = 0;
	this.visible = true;
	this.enabled = true;
	this.targetWidth = null;
	this.targetHeight = null;
	this.scaling = 'none';

	this.root = root;

	this.listeners = {};
}

CrocBase.prototype.event = function(eventType, eventData, cascadeEvent) {

	cascadeEvent = cascadeEvent || false;
	var retValue = true;

	if(eventType in this.listeners) {
		for(var i = 0; i < this.listeners[eventType].length; i++) {
			if(!this.listeners[eventType][i].call(this, eventData)) {
				retValue = false;
			}
		}
	}

	if(cascadeEvent && retValue) {
		for(var i = 0; i < this.children; i++) {
			if(!this.children[i].event(eventType, eventData, cascadeEvent)) {
				retValue = false;
			}
		}
	}

	return retValue;
};

CrocBase.prototype.error = function(type) {

	var sourceString = this.constructor.name;
	var currentCaller = arguments.callee.caller;
	var currentProto = this.constructor.prototype;

	while(true) {
		var currentProtoKeys = Object.keys(currentProto);

		for(var i = 0; i < currentProtoKeys.length; i++) {

			var currentKey = currentProtoKeys[i];
			var currentPrototypeProperty = this[currentKey];

			if(typeof currentPrototypeProperty === 'function') {
				if(currentPrototypeProperty === currentCaller) {
					sourceString = currentProto.constructor.name + ".prototype." + currentKey;
					break;
				}
			}

		}

		currentProto = currentProto.__proto__;

		if(currentProto === null || currentProto.length === 0) {
			break;
		}
	}

	var constructor = null;

	if(currentProto !== null) {
		constructor = currentProto.constructor;
	}

	var err = new Error();

	console.trace();
	console.log("Error: " + sourceString + " : " + type);

	this.event("error", {"type":type, "constructor":constructor, "attribute":currentProto, "source":sourceString, "stack":err.stack}, false);
};

CrocBase.prototype.addEventListener = function(event, callback) {
	if(!(event in this.listeners)) {
		this.listeners[event] = [];
	}

	if(callback in this.listeners[event]) {
		return;
	}

	this.listeners[event].push(callback);
};

CrocBase.prototype.removeEventListener = function(event, callback) {
	if(!(event in this.listeners)) {
		return false;
	}

	var index = this.listeners[event].indexOf(callback);

	if(index > -1) {
		this.listeners.splice(index, 1);
	}
};

CrocBase.prototype.removeAllEventListeners = function(event) {
	if(event === undefined) {
		this.listeners = {};
		return true;
	}

	if(!(event in this.listeners)) {
		return false;
	}

	this.listeners[event] = [];
	return true;
};

CrocBase.prototype.addChild = function(uiObject) {

	if(typeof uiObject !== "object") {
		this.error("Not a UIObject!");
		console.trace();
		return false;
	}

	if(uiObject.setParent(this) === false) {
		this.error("Unable to set UIObject's parent to this!");
		console.trace();
		return false;
	}

	this.children.push(uiObject);

	return true;
};

CrocBase.prototype.addChildren = function(uiObjectList) {
	for(var i = 0; i < uiObjectList.length; i++) {
		this.addChild(uiObjectList[i]);
	}

	this.getRoot().repaint();

	return;
};

CrocBase.prototype.removeChild = function(uiObject) {

	var childIndex = this.children.indexOf(uiObject);

	if(childIndex < 0) {
		this.error("Has no UIObject!");
		return false;
	}

	this.children.splice(childIndex, 1);

	this.getRoot().repaint();

	return true;
};

CrocBase.prototype.removeAllChildren = function() {
	this.children = [];
};

CrocBase.prototype.hasAncestor = function(uiObject) {

	if(this.parent === null) {
		return false;
	}

	else if(this.parent === uiObject) {
		return true;
	}

	else {
		return this.parent.hasAncestor(uiObject);
	}

};

CrocBase.prototype.getRoot = function() {
	return this.root;
};

CrocBase.prototype.setParent = function(parent) {

	if(parent.hasAncestor(this)) {
		this.error("Attempting to set parent would cause infinite child loop!");
		return false;
	}

	this.parent = parent;

	return true;
};

CrocBase.prototype.setChildren = function(uiObjectList) {
	this.removeAllChildren();
	this.addChildren(uiObjectList);
};

CrocBase.prototype.setVisible = function(visible) {
	if(this.visible !== visible) {
		this.visible = visible;
		this.getRoot().repaint();
	}
};

CrocBase.prototype.getVisible = function() {
	return this.visible;
};

CrocBase.prototype.setEnabled = function(enabled) {
	this.enabled = enabled;
};

CrocBase.prototype.getParent = function() {
	return this.parent;
};

CrocBase.prototype.getChildren = function() {
	return this.children;
};

CrocBase.prototype.childToFront = function(uiObject) {
	if(this.children.indexOf(uiObject) < 0) {
		return false;
	}

	this.children.splice(this.children.indexOf(uiObject), 1);
	this.children.unshift(uiObject);

	this.getRoot().repaint();

	return true;
};

CrocBase.prototype.childToBack = function(uiObject) {
	if(this.children.indexOf(uiObject) < 0) {
		return false;
	}

	this.children.splice(this.children.indexOf(uiObject), 1);
	this.children.push(uiObject);

	this.getRoot().repaint();

	return true;
};

CrocBase.prototype.getDescendants = function() {

	var retValue = [];

	retValue.push(this);
	retValue.push([]);

	for(var i = 0; i < this.children.length; i++) {
		retValue[1].push(this.children[i].getDescendants());
	}

	return retValue;
};

//Hit test is handled almost exactly like a paint except you use the context to create a bounding box test and then draw.
CrocBase.prototype.hitTest = function(context, x, y, width, height) {

	if(!this.visible) {
		return null;
	}

	var currentInvTransform = this.inverseTransform(context.getCurrentTransform());

	var p = this.transformPoint(currentInvTransform, x, y);
	var a = {x:0, y:0};
	var d = {x:this.getWidth(), y:this.getHeight()};

	if(p.x > a.x && p.x < d.x && p.y > a.y && p.y < d.y) {
		return this;
	}

	return null;
};

CrocBase.prototype.getWidth = function () {
	return this.width;
};

CrocBase.prototype.getHeight = function() {
	return this.height;
};

CrocBase.prototype.setTargetWidth = function(width) {

	if(this.targetWidth !== width) {
		this.targetWidth = width;
		this.getRoot().repaint();
	}
};

CrocBase.prototype.setTargetHeight = function(height) {

	if(this.targetHeight !== height) {
		this.targetHeight = height;
		this.getRoot().repaint();
	}
};

CrocBase.prototype.getTargetWidth = function() {
	return this.targetWidth;
};

CrocBase.prototype.getTargetHeight = function() {
	return this.targetHeight;
};

//This claims the focus from root
CrocBase.prototype.focus = function() {
	this.getRoot().setFocusedObject(this);
	this.event('focus');
	return;
};

CrocBase.prototype.blur = function() {
	if(this.hasFocus()) {
		this.getRoot().setFocusedObject(null);
		this.event('blur');
	};
};

CrocBase.prototype.hasFocus = function() {

	if(this.getRoot().focusedObject !== null) {
		return this.getRoot().focusedObject.uuid === this.uuid;
	}

	else {
		return false;
	}
};

//Without any sort of layout options or anything really the CrocBase does not paint it's children.
CrocBase.prototype.paint = function(context, width, height) {
	this.lastTransform = context.getCurrentTransform();

	this.width = this.convertToPixels(this.targetWidth, width);
	this.height = this.convertToPixels(this.targetHeight, height);

	if(this.getVisible()) {
		this.getRoot().testPaintWarnings(this, this.lastTransform);
	}

	return;
};

CrocBase.prototype.applyClip = function(context, width, height) {
	context.save();
	context.rect(0, 0, width, height);
	context.clip();
};

CrocBase.prototype.removeClip = function(context) {
	context.restore();
};

CrocBase.prototype.inverseTransform = function(t) {
	var a = t[0];
	var b = t[1];
	var c = 0;
	var d = t[2];
	var e = t[3];
	var f = 0;
	var g = t[4];
	var h = t[5];
	var i = 1;

	var A = e * i - f * h;
	var B = f * g - d * i;
	var C = d * h - e * g;
	var determinant = a * A + b * B + c * C;
	var oneOverDeterminant;

	if(determinant === 0) {
		return false; // singular; inverse does not exist
	}
	else {
		oneOverDeterminant = 1 / determinant;

		return [
			A * oneOverDeterminant,
			(c * h - b * i) * oneOverDeterminant,
			B * oneOverDeterminant,
			(a * i - c * g) * oneOverDeterminant,
			C * oneOverDeterminant,
			(b * g - a * h) * oneOverDeterminant,
		];
	}

};

CrocBase.prototype.transformClipSpace = function(transform, width, height) {
	var iMat = this.inverseTransform(transform);

	var vA = this.transformPoint(iMat, 0, 0);
	var vB = this.transformPoint(iMat, width, 0);
	var vC = this.transformPoint(iMat, width, height);
	var vD = this.transformPoint(iMat, 0, height);

	var width = Math.max(	((vA.x > 0 && vA.y > 0) ? vA.x : 0),
				((vB.x > 0 && vB.y > 0) ? vB.x : 0),
		       		((vC.x > 0 && vC.y > 0) ? vC.x : 0),
		       		((vD.x > 0 && vD.y > 0) ? vD.x : 0));

	var height = Math.max(	((vA.x > 0 && vA.y > 0) ? vA.y : 0),
				((vB.x > 0 && vB.y > 0) ? vB.y : 0),
		       		((vC.x > 0 && vC.y > 0) ? vC.y : 0),
		       		((vD.x > 0 && vD.y > 0) ? vD.y : 0));

	return {width:width, height:height};
};

CrocBase.prototype.transformPoint = function(t, x, y) {

	var xP = t[0] * x + t[2] * y + t[4];
	var yP = t[1] * x + t[3] * y + t[5];

	return {x:xP, y:yP};
};

CrocBase.prototype.convertToPixels = function(value, reference) {

	if(typeof value === 'string') {
		//It's a pixel
		if(value.indexOf('px', value.length - 2) !== -1) {
			return parseInt(value.substring(0, value.length - 2));

		}

		else if(value.indexOf('%', value.length - 1) !== -1) {
			var percent = parseFloat(value.substring(0, value.length - 1));
			return Math.round(reference * (percent/100.0));
		}
	}

	else if(typeof value === 'number') {
		return value;
	}

	else if(value === null || value === undefined) {
		return reference;
	}

	return reference;
};

CrocBase.prototype.convertToPercentile = function(value, reference) {

	if(typeof value === 'string') {
		//It's a pixel
		if(value.indexOf('px', value.length - 2) !== -1) {
			return ((parseInt(value.substring(0, value.length - 2))/reference) * 100).toFixed(2) + '%';

		}

		else if(value.indexOf('%', value.length - 1) !== -1) {
			return value;
		}
	}

	else if(typeof value === 'number') {
		return ((value/reference) * 100).toFixed(2) + '%';
	}

	else if(value === null || value === undefined) {
		return '0%';
	}

	return '0%';
};

<commit_msg>Adding a child should trigger a repaint.<commit_after>
function guid() {
	function _p8(s) {
		var p = (Math.random().toString(16)+"000000000").substr(2,8);
		return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
	}
	return _p8() + _p8(true) + _p8(true) + _p8();
}

function CrocBase(root){

	if(root !== this) {
		if(typeof root !== 'object' || root.getRoot() !== root) {
			this.error('Was passed a root that may not in fact be a root!');
		}
	}

	this.uuid = guid();
	this.parent = null;
	this.children = [];
	this.lastTransform = [1, 0, 0, 1, 0, 0];
	this.width = 0;
	this.height = 0;
	this.visible = true;
	this.enabled = true;
	this.targetWidth = null;
	this.targetHeight = null;
	this.scaling = 'none';

	this.root = root;

	this.listeners = {};
}

CrocBase.prototype.event = function(eventType, eventData, cascadeEvent) {

	cascadeEvent = cascadeEvent || false;
	var retValue = true;

	if(eventType in this.listeners) {
		for(var i = 0; i < this.listeners[eventType].length; i++) {
			if(!this.listeners[eventType][i].call(this, eventData)) {
				retValue = false;
			}
		}
	}

	if(cascadeEvent && retValue) {
		for(var i = 0; i < this.children; i++) {
			if(!this.children[i].event(eventType, eventData, cascadeEvent)) {
				retValue = false;
			}
		}
	}

	return retValue;
};

CrocBase.prototype.error = function(type) {

	var sourceString = this.constructor.name;
	var currentCaller = arguments.callee.caller;
	var currentProto = this.constructor.prototype;

	while(true) {
		var currentProtoKeys = Object.keys(currentProto);

		for(var i = 0; i < currentProtoKeys.length; i++) {

			var currentKey = currentProtoKeys[i];
			var currentPrototypeProperty = this[currentKey];

			if(typeof currentPrototypeProperty === 'function') {
				if(currentPrototypeProperty === currentCaller) {
					sourceString = currentProto.constructor.name + ".prototype." + currentKey;
					break;
				}
			}

		}

		currentProto = currentProto.__proto__;

		if(currentProto === null || currentProto.length === 0) {
			break;
		}
	}

	var constructor = null;

	if(currentProto !== null) {
		constructor = currentProto.constructor;
	}

	var err = new Error();

	console.trace();
	console.log("Error: " + sourceString + " : " + type);

	this.event("error", {"type":type, "constructor":constructor, "attribute":currentProto, "source":sourceString, "stack":err.stack}, false);
};

CrocBase.prototype.addEventListener = function(event, callback) {
	if(!(event in this.listeners)) {
		this.listeners[event] = [];
	}

	if(callback in this.listeners[event]) {
		return;
	}

	this.listeners[event].push(callback);
};

CrocBase.prototype.removeEventListener = function(event, callback) {
	if(!(event in this.listeners)) {
		return false;
	}

	var index = this.listeners[event].indexOf(callback);

	if(index > -1) {
		this.listeners.splice(index, 1);
	}
};

CrocBase.prototype.removeAllEventListeners = function(event) {
	if(event === undefined) {
		this.listeners = {};
		return true;
	}

	if(!(event in this.listeners)) {
		return false;
	}

	this.listeners[event] = [];
	return true;
};

CrocBase.prototype.addChild = function(uiObject) {

	if(typeof uiObject !== "object") {
		this.error("Not a UIObject!");
		console.trace();
		return false;
	}

	if(uiObject.setParent(this) === false) {
		this.error("Unable to set UIObject's parent to this!");
		console.trace();
		return false;
	}

	this.children.push(uiObject);

	this.getRoot().repaint();

	return true;
};

CrocBase.prototype.addChildren = function(uiObjectList) {
	for(var i = 0; i < uiObjectList.length; i++) {
		this.addChild(uiObjectList[i]);
	}

	return;
};

CrocBase.prototype.removeChild = function(uiObject) {

	var childIndex = this.children.indexOf(uiObject);

	if(childIndex < 0) {
		this.error("Has no UIObject!");
		return false;
	}

	this.children.splice(childIndex, 1);

	this.getRoot().repaint();

	return true;
};

CrocBase.prototype.removeAllChildren = function() {
	this.children = [];
};

CrocBase.prototype.hasAncestor = function(uiObject) {

	if(this.parent === null) {
		return false;
	}

	else if(this.parent === uiObject) {
		return true;
	}

	else {
		return this.parent.hasAncestor(uiObject);
	}

};

CrocBase.prototype.getRoot = function() {
	return this.root;
};

CrocBase.prototype.setParent = function(parent) {

	if(parent.hasAncestor(this)) {
		this.error("Attempting to set parent would cause infinite child loop!");
		return false;
	}

	this.parent = parent;

	return true;
};

CrocBase.prototype.setChildren = function(uiObjectList) {
	this.removeAllChildren();
	this.addChildren(uiObjectList);
};

CrocBase.prototype.setVisible = function(visible) {
	if(this.visible !== visible) {
		this.visible = visible;
		this.getRoot().repaint();
	}
};

CrocBase.prototype.getVisible = function() {
	return this.visible;
};

CrocBase.prototype.setEnabled = function(enabled) {
	this.enabled = enabled;
};

CrocBase.prototype.getParent = function() {
	return this.parent;
};

CrocBase.prototype.getChildren = function() {
	return this.children;
};

CrocBase.prototype.childToFront = function(uiObject) {
	if(this.children.indexOf(uiObject) < 0) {
		return false;
	}

	this.children.splice(this.children.indexOf(uiObject), 1);
	this.children.unshift(uiObject);

	this.getRoot().repaint();

	return true;
};

CrocBase.prototype.childToBack = function(uiObject) {
	if(this.children.indexOf(uiObject) < 0) {
		return false;
	}

	this.children.splice(this.children.indexOf(uiObject), 1);
	this.children.push(uiObject);

	this.getRoot().repaint();

	return true;
};

CrocBase.prototype.getDescendants = function() {

	var retValue = [];

	retValue.push(this);
	retValue.push([]);

	for(var i = 0; i < this.children.length; i++) {
		retValue[1].push(this.children[i].getDescendants());
	}

	return retValue;
};

//Hit test is handled almost exactly like a paint except you use the context to create a bounding box test and then draw.
CrocBase.prototype.hitTest = function(context, x, y, width, height) {

	if(!this.visible) {
		return null;
	}

	var currentInvTransform = this.inverseTransform(context.getCurrentTransform());

	var p = this.transformPoint(currentInvTransform, x, y);
	var a = {x:0, y:0};
	var d = {x:this.getWidth(), y:this.getHeight()};

	if(p.x > a.x && p.x < d.x && p.y > a.y && p.y < d.y) {
		return this;
	}

	return null;
};

CrocBase.prototype.getWidth = function () {
	return this.width;
};

CrocBase.prototype.getHeight = function() {
	return this.height;
};

CrocBase.prototype.setTargetWidth = function(width) {

	if(this.targetWidth !== width) {
		this.targetWidth = width;
		this.getRoot().repaint();
	}
};

CrocBase.prototype.setTargetHeight = function(height) {

	if(this.targetHeight !== height) {
		this.targetHeight = height;
		this.getRoot().repaint();
	}
};

CrocBase.prototype.getTargetWidth = function() {
	return this.targetWidth;
};

CrocBase.prototype.getTargetHeight = function() {
	return this.targetHeight;
};

//This claims the focus from root
CrocBase.prototype.focus = function() {
	this.getRoot().setFocusedObject(this);
	this.event('focus');
	return;
};

CrocBase.prototype.blur = function() {
	if(this.hasFocus()) {
		this.getRoot().setFocusedObject(null);
		this.event('blur');
	};
};

CrocBase.prototype.hasFocus = function() {

	if(this.getRoot().focusedObject !== null) {
		return this.getRoot().focusedObject.uuid === this.uuid;
	}

	else {
		return false;
	}
};

//Without any sort of layout options or anything really the CrocBase does not paint it's children.
CrocBase.prototype.paint = function(context, width, height) {
	this.lastTransform = context.getCurrentTransform();

	this.width = this.convertToPixels(this.targetWidth, width);
	this.height = this.convertToPixels(this.targetHeight, height);

	if(this.getVisible()) {
		this.getRoot().testPaintWarnings(this, this.lastTransform);
	}

	return;
};

CrocBase.prototype.applyClip = function(context, width, height) {
	context.save();
	context.rect(0, 0, width, height);
	context.clip();
};

CrocBase.prototype.removeClip = function(context) {
	context.restore();
};

CrocBase.prototype.inverseTransform = function(t) {
	var a = t[0];
	var b = t[1];
	var c = 0;
	var d = t[2];
	var e = t[3];
	var f = 0;
	var g = t[4];
	var h = t[5];
	var i = 1;

	var A = e * i - f * h;
	var B = f * g - d * i;
	var C = d * h - e * g;
	var determinant = a * A + b * B + c * C;
	var oneOverDeterminant;

	if(determinant === 0) {
		return false; // singular; inverse does not exist
	}
	else {
		oneOverDeterminant = 1 / determinant;

		return [
			A * oneOverDeterminant,
			(c * h - b * i) * oneOverDeterminant,
			B * oneOverDeterminant,
			(a * i - c * g) * oneOverDeterminant,
			C * oneOverDeterminant,
			(b * g - a * h) * oneOverDeterminant,
		];
	}

};

CrocBase.prototype.transformClipSpace = function(transform, width, height) {
	var iMat = this.inverseTransform(transform);

	var vA = this.transformPoint(iMat, 0, 0);
	var vB = this.transformPoint(iMat, width, 0);
	var vC = this.transformPoint(iMat, width, height);
	var vD = this.transformPoint(iMat, 0, height);

	var width = Math.max(	((vA.x > 0 && vA.y > 0) ? vA.x : 0),
				((vB.x > 0 && vB.y > 0) ? vB.x : 0),
		       		((vC.x > 0 && vC.y > 0) ? vC.x : 0),
		       		((vD.x > 0 && vD.y > 0) ? vD.x : 0));

	var height = Math.max(	((vA.x > 0 && vA.y > 0) ? vA.y : 0),
				((vB.x > 0 && vB.y > 0) ? vB.y : 0),
		       		((vC.x > 0 && vC.y > 0) ? vC.y : 0),
		       		((vD.x > 0 && vD.y > 0) ? vD.y : 0));

	return {width:width, height:height};
};

CrocBase.prototype.transformPoint = function(t, x, y) {

	var xP = t[0] * x + t[2] * y + t[4];
	var yP = t[1] * x + t[3] * y + t[5];

	return {x:xP, y:yP};
};

CrocBase.prototype.convertToPixels = function(value, reference) {

	if(typeof value === 'string') {
		//It's a pixel
		if(value.indexOf('px', value.length - 2) !== -1) {
			return parseInt(value.substring(0, value.length - 2));

		}

		else if(value.indexOf('%', value.length - 1) !== -1) {
			var percent = parseFloat(value.substring(0, value.length - 1));
			return Math.round(reference * (percent/100.0));
		}
	}

	else if(typeof value === 'number') {
		return value;
	}

	else if(value === null || value === undefined) {
		return reference;
	}

	return reference;
};

CrocBase.prototype.convertToPercentile = function(value, reference) {

	if(typeof value === 'string') {
		//It's a pixel
		if(value.indexOf('px', value.length - 2) !== -1) {
			return ((parseInt(value.substring(0, value.length - 2))/reference) * 100).toFixed(2) + '%';

		}

		else if(value.indexOf('%', value.length - 1) !== -1) {
			return value;
		}
	}

	else if(typeof value === 'number') {
		return ((value/reference) * 100).toFixed(2) + '%';
	}

	else if(value === null || value === undefined) {
		return '0%';
	}

	return '0%';
};

<|endoftext|>


<commit_before>/*
 * jQuery UI menubar
 *
 * backported from Michael Lang's fork: http://www.nexul.com/prototypes/toolbar/demo.html
 */
(function($) {

// TODO take non-menubar buttons into account
$.widget("ui.menubar", {
   options: {
      buttons: false,
      menuIcon: false
   },
	_create: function() {
		var self = this;
		var items = this.items = this.element.children("button, a");
		var o = this.options;

		this.element.addClass('ui-menubar ui-widget-header ui-helper-clearfix');
		this._focusable(items);
		items.next("ul").each(function(i, elm) {
			$(elm).menu({
				select: function(event, ui) {
					ui.item.parents("ul:last").hide()
					self.options.select.apply(this, arguments);
				}
			}).hide().keydown(function(event) {
				var menu = $(this);
				if (menu.is(":hidden"))
					return;
				event.stopPropagation();
				switch (event.keyCode) {
				case $.ui.keyCode.LEFT:
					self.left(event);
					event.preventDefault();
					break;
				case $.ui.keyCode.RIGHT:
					self.right(event);
					event.preventDefault();
					break;
				};
			}).blur(function() {
				$(this).hide().prev().removeClass("ui-state-active").removeAttr("tabIndex");
				self.timer = setTimeout(function() {
					self.open = false;
				}, 13);
			});
		});
		items.each(function() {
			var input = $(this),
				   menu = input.next("ul");

			input.bind("click focus mouseenter", function(event) {
   				event.preventDefault();
   				event.stopPropagation();
			   	if (menu.is(":visible") && self.active && self.active[0] == menu[0]) {
					self._close();
					return;
				}
   				if (menu.length && (self.open || event.type == "click")) {
   					self._open(event, menu);
   				}
   			})
			.addClass("ui-button ui-widget ui-button-text-only ui-menubar-link")
			.wrapInner("");
			self._hoverable(input)

			if (o.menuIcon) {
				input.addClass("ui-state-default").append("");
				input.removeClass("ui-button-text-only").addClass("ui-button-text-icon-secondary");
			}

			if (!o.buttons) {
				input.addClass('ui-menubar-link').removeClass('ui-state-default');
			};

		});
		$(document).click(function(event) {
			!$(event.target).closest(".ui-menubar").length && self._close();
		});
	},

	_close: function() {
		this.items.next("ul").hide();
		this.items.removeClass("ui-state-active").removeAttr("tabIndex");
		this.open = false;
	},

	_open: function(event, menu) {
		if (this.active) {
			this.active.menu("closeAll").hide();
			this.active.prev().removeClass("ui-state-active").removeAttr("tabIndex");
		}
		clearTimeout(this.timer);
		this.open = true;
		// set tabIndex -1 to have the button skipped on shift-tab when menu is open (it gets focus)
		var button = menu.prev().addClass("ui-state-active").attr("tabIndex", -1);
		this.active = menu.show().position({
			my: "left top",
			at: "left bottom",
			of: button
		}).focus();
	},

	left: function(event) {
		var prev = this.active.prevAll( ".ui-menu" ).eq( 0 );
		if (prev.length) {
			this._open(event, prev);
		} else {
			this._open(event, this.element.children(".ui-menu:last"));
		}
	},

	right: function(event) {
		var next =  this.active.nextAll( ".ui-menu" ).eq( 0 );
		if (next.length) {
			this._open(event, next);
		} else {
			this._open(event, this.element.children(".ui-menu:first"));
		}
	}
});

}(jQuery));
<commit_msg>Menu: menubar cleanup<commit_after>/*
 * jQuery UI menubar
 *
 * backported from Michael Lang's fork: http://www.nexul.com/prototypes/toolbar/demo.html
 */
(function($) {

// TODO take non-menubar buttons into account
$.widget("ui.menubar", {
   options: {
      buttons: false,
      menuIcon: false
   },
	_create: function() {
		var self = this;
		var items = this.items = this.element.children("button, a");
		var o = this.options;

		this.element.addClass('ui-menubar ui-widget-header ui-helper-clearfix');
		this._focusable(items);
		this._hoverable(items);
		items.next("ul").each(function(i, elm) {
			$(elm).menu({
				select: function(event, ui) {
					ui.item.parents("ul:last").hide()
					self.options.select.apply(this, arguments);
				}
			}).hide().keydown(function(event) {
				var menu = $(this);
				if (menu.is(":hidden"))
					return;
				event.stopPropagation();
				switch (event.keyCode) {
				case $.ui.keyCode.LEFT:
					self.left(event);
					event.preventDefault();
					break;
				case $.ui.keyCode.RIGHT:
					self.right(event);
					event.preventDefault();
					break;
				};
			}).blur(function() {
				$(this).hide().prev().removeClass("ui-state-active").removeAttr("tabIndex");
				self.timer = setTimeout(function() {
					self.open = false;
				}, 13);
			});
		});
		items.each(function() {
			var input = $(this),
				   menu = input.next("ul");

			input.bind("click focus mouseenter", function(event) {
   				event.preventDefault();
   				event.stopPropagation();
			   	if (menu.is(":visible") && self.active && self.active[0] == menu[0]) {
					self._close();
					return;
				}
   				if (menu.length && (self.open || event.type == "click")) {
   					self._open(event, menu);
   				}
   			})
			.addClass("ui-button ui-widget ui-button-text-only ui-menubar-link")
			.wrapInner("");

			if (o.menuIcon) {
				input.addClass("ui-state-default").append("");
				input.removeClass("ui-button-text-only").addClass("ui-button-text-icon-secondary");
			}

			if (!o.buttons) {
				input.addClass('ui-menubar-link').removeClass('ui-state-default');
			};

		});
		$(document).click(function(event) {
			!$(event.target).closest(".ui-menubar").length && self._close();
		});
	},

	_close: function() {
		this.items.next("ul").hide();
		this.items.removeClass("ui-state-active").removeAttr("tabIndex");
		this.open = false;
	},

	_open: function(event, menu) {
		if (this.active) {
			this.active.menu("closeAll").hide();
			this.active.prev().removeClass("ui-state-active").removeAttr("tabIndex");
		}
		clearTimeout(this.timer);
		this.open = true;
		// set tabIndex -1 to have the button skipped on shift-tab when menu is open (it gets focus)
		var button = menu.prev().addClass("ui-state-active").attr("tabIndex", -1);
		this.active = menu.show().position({
			my: "left top",
			at: "left bottom",
			of: button
		}).focus();
	},

	left: function(event) {
		var prev = this.active.prevAll( ".ui-menu" ).eq( 0 );
		if (prev.length) {
			this._open(event, prev);
		} else {
			this._open(event, this.element.children(".ui-menu:last"));
		}
	},

	right: function(event) {
		var next =  this.active.nextAll( ".ui-menu" ).eq( 0 );
		if (next.length) {
			this._open(event, next);
		} else {
			this._open(event, this.element.children(".ui-menu:first"));
		}
	}
});

}(jQuery));
<|endoftext|>


<commit_before>var wolfram = require('wolfram');
var wc = null;

module.exports.init = function(bot) {
  bot.getConfig("wolfram.json", function(err, conf) {
    if(err) console.log("Unable to load wolfram module: " + err);
    try {
      wc = new wolfram.createClient(conf.appid);
    } catch(ex) {
      bot.say("Error loading wolfram library: " + ex);
    }
  });
};

module.exports.commands = ['wolf', 'wolfram', 'wolframalpha', 'wa'];

module.exports.run = function(remainder, parts, reply, command, from, to, text, raw) {
  if(wc === null) {
    return reply("Unable to handle wolfram request; lib not loaded");
  }

  wc.query(remainder, function(err, res) {
    if(err) return reply("Wolfram error: " + err);

      if(res.length === 1) {
        return reply("No result for query: " + out[0].subpods[0].value);
      }

    var primary_pods = res.filter(function(x){return x.primary;});
    if(primary_pods.length === 0) {
      try {
        return reply(res[0].subpods[0].value + ': ' + res[1].subpods[0].value.split('\n').join(' ~ '));
      } catch(ex) {
        return reply("No primary pod, try http://www.wolframalpha.com/input/?i="+encodeURIComponent(remainder));
      }
    }

    var ppod = primary_pods[0];
    try {
      if(ppod.title && ppod.subpods[0].value) {
        reply(ppod.title + ": " + ppod.subpods[0].value);
      } else {
        throw("Can't handle this ppod");
      }
    } catch(ex) {
      console.log(ppod);
      reply("Not sure how to handle primary pod, someone should pull request this");
    }
  });
};
<commit_msg>More wolfram error handling<commit_after>var wolfram = require('wolfram');
var wc = null;

module.exports.init = function(bot) {
  bot.getConfig("wolfram.json", function(err, conf) {
    if(err) console.log("Unable to load wolfram module: " + err);
    try {
      wc = new wolfram.createClient(conf.appid);
    } catch(ex) {
      bot.say("Error loading wolfram library: " + ex);
    }
  });
};

module.exports.commands = ['wolf', 'wolfram', 'wolframalpha', 'wa'];

module.exports.run = function(remainder, parts, reply, command, from, to, text, raw) {
  if(wc === null) {
    return reply("Unable to handle wolfram request; lib not loaded");
  }

  wc.query(remainder, function(err, res) {
    if(err) return reply("Wolfram error: " + err);
    if(!(res && res.length)) return reply("Wolfram error, response is dicked");

    if(res.length === 1) {
      return reply("No result for query: " + out[0].subpods[0].value);
    }

    var primary_pods = res.filter(function(x){return x.primary;});
    if(primary_pods.length === 0) {
      try {
        return reply(res[0].subpods[0].value + ': ' + res[1].subpods[0].value.split('\n').join(' ~ '));
      } catch(ex) {
        return reply("No primary pod, try http://www.wolframalpha.com/input/?i="+encodeURIComponent(remainder));
      }
    }

    var ppod = primary_pods[0];
    try {
      if(ppod.title && ppod.subpods[0].value) {
        reply(ppod.title + ": " + ppod.subpods[0].value);
      } else {
        throw("Can't handle this ppod");
      }
    } catch(ex) {
      console.log(ppod);
      reply("Not sure how to handle primary pod, someone should pull request this");
    }
  });
};
<|endoftext|>


<commit_before>/* eslint-env node, browser */
import { expect } from 'chai';

fixture `Check if the button text changes`
    .page('http://localhost:9090/index.html');

test('My test', async t => {
    await t
		.click('#click-here');

    const button = await t.select('#click-here');

    expect(button.value).to.equal('Hello!');
});
<commit_msg>[docs] Update docs to use new snapshot property shorthand feature. Modify variable names and style to follow recommended code practices. (#910)<commit_after>import { expect } from 'chai';

fixture `Check if the button text changes`
    .page `http://localhost:9090/index.html`;

test('My test', async t => {
    await t
		.click('#click-here');

    const button = await t.select('#click-here');

    expect(button.value).to.equal('Hello!');
});
<|endoftext|>


<commit_before>import rest from 'feathers-rest/client'
const jQuery = require('jquery')
// Include and set up feathers client
const Feathers = require('feathers/client')
const hooks = require('feathers-hooks')
const authentication = require('feathers-authentication-client')
// const socketio = require('feathers-socketio/client')
// const io = require('socket.io-client')
// const socket = io(finalHost)
console.log('trying to connect')
const feathers = Feathers()
.configure(rest('localhost:3000').jquery(jQuery))
.configure(hooks())
.configure(authentication({storage: window.localStorage}))

// Add services
feathers.service('match')

export default feathers
<commit_msg>static<commit_after>import rest from 'feathers-rest/client'
const jQuery = require('jquery')
// Include and set up feathers client
const Feathers = require('feathers/client')
const hooks = require('feathers-hooks')
const authentication = require('feathers-authentication-client')
// const socketio = require('feathers-socketio/client')
// const io = require('socket.io-client')
// const socket = io(finalHost)
console.log('trying to connect')
const feathers = Feathers()
.configure(rest('http://localhost:3000').jquery(jQuery))
.configure(hooks())
.configure(authentication({storage: window.localStorage}))

// Add services
feathers.service('match')

export default feathers
<|endoftext|>


<commit_before>function setCustom(settingKey, newValue, scenario = 'primary') {
  // sets a value in the "Customize Profile Request" box
  let newConfig = {}
  cy.get(`@${scenario}`)
    .findByLabelText(/Customize Profile Request/i)
    .as('profile')
    .invoke('val')
    .then((currentConfig) => {
      newConfig = JSON.parse(currentConfig)
      newConfig[settingKey] = newValue
      cy.get('@profile')
        .invoke('val', JSON.stringify(newConfig, null, 2))
        .trigger('change') // TODO not updating map
    })
}

function setOrigin(latLonArray) {
  // TODO not yet updating map marker
  setCustom('fromLat', latLonArray[0])
  setCustom('fromLon', latLonArray[1])
}

function fetchResults() {
  cy.findByText(/Fetch Results/i).click()
  // wait for results
  cy.findByText(/Fetch Results/i).should('not.exist')
  cy.findByText(/Fetch Results/i).should('exist')
}

context('Analysis', () => {
  before(() => {
    cy.setup('project')
    cy.setup('opportunities')
  })

  beforeEach(() => {
    cy.navTo('edit modifications') // refresh analysis page by navigating away
    cy.navTo('Analyze')
    cy.fixture('regions/scratch.json').as('region')
    // alias lots of things
    cy.get('div.leaflet-container').as('map')
    cy.get('div#PrimaryAnalysisSettings').as('primary')
    cy.get('div#ComparisonAnalysisSettings').as('comparison')
    // set a standard project, scenario, and opportunity dataset
    // across all tests
    cy.get('@primary')
      .findByLabelText(/^Project$/)
      .click({force: true})
      .type('scratch{enter}')
    cy.get('@primary')
      .findByLabelText(/^Scenario$/)
      .click({force: true})
      .type('baseline{enter}')
    cy.findByLabelText(/^Opportunity Dataset$/)
      .click({force: true})
      .type('default{enter}')
      .should('be.disabled') // becomes disabled while loading
    // enabled again once loaded
    cy.findByLabelText(/^Opportunity Dataset$/).should('be.enabled')
  })

  context('of a point', () => {
    it('has all form elements', function () {
      // note that elements touched in beforeEach are neglected here
      cy.findByLabelText(/Time cutoff/i)
      cy.findByLabelText(/Travel time percentile/i)
      cy.get('@primary')
        .findByRole('button', {name: 'Multi-point'})
        .should('be.disabled')
      cy.get('@primary').contains('scratch project')
      cy.get('@primary').contains('Baseline')
      cy.get('@primary').findAllByLabelText(/Bookmark/)
      cy.get('@primary').findByLabelText(/Access mode/i)
      cy.get('@primary').findByLabelText(/Transit modes/i)
      cy.get('@primary').findByLabelText(/Egress mode/i)
      cy.findByLabelText(/Walk speed/i)
      cy.findByLabelText(/Max walk time/i)
      cy.get('@primary').findByLabelText(/Date/i)
      cy.findByLabelText(/From time/i)
      cy.findByLabelText(/To time/i)
      cy.get('@primary').findByLabelText(/Simulated Schedules/i)
      cy.get('@primary').findByLabelText(/Maximum transfers/i)
      cy.findByLabelText(/Routing engine/i)
      cy.get('@primary').findAllByLabelText(/Bounds of analysis/i)
      cy.get('@primary').findByLabelText(/Customize Profile Request/i)
      cy.findByText(/Fetch Results/i).should('be.enabled')
    })

    it('runs, giving <del>reasonable</del> results', function () {
      // tests basic single point analysis at specified locations
      // compares mapped results to snapshots
      fetchResults() // initialize request
      // set new parameters
      cy.findByLabelText(/Time cutoff/i)
        .invoke('val', 75) // TODO not working
        .trigger('change', {force: true})
      cy.findByLabelText(/Travel time percentile/i)
        .invoke('val', 75) // TODO not working yet
        .trigger('change', {force: true})
      // move marker and align map for snapshot
      for (let key in this.region.locations) {
        let location = this.region.locations[key]
        setOrigin(location)
        cy.centerMapOn(location)
        fetchResults()
        //cy.get('@map').matchImageSnapshot() // TODO
      }
    })

    it('gives different results at different times', function () {
      const location = this.region.locations.center
      setOrigin(location)
      cy.centerMapOn(location)
      // set time window in morning rush -- should have high access
      cy.findByLabelText(/From time/i)
        .as('from')
        .clear()
        .type('06:00')
      cy.findByLabelText(/To time/i)
        .as('to')
        .clear()
        .type('08:00')
      fetchResults()
      //cy.get('@map').matchImageSnapshot() // TODO
      // set time window in late evening - lower access
      cy.get('@from').clear().type('22:00')
      cy.get('@to').clear().type('23:59')
      fetchResults()
      //cy.get('@map').matchImageSnapshot() // TODO
      // narrow window to one minute - no variability
      cy.get('@from').clear().type('12:00')
      cy.get('@to').clear().type('12:01')
      // TODO snapshot chart too
    })

    it('charts accessibility', function () {
      // TODO move marker and verify other settings
      fetchResults()
      cy.get('svg#results-chart')
      // TODO take snapshot
    })

    it('sets custom analysis bounds')

    it('sets a bookmark')

    it('handles access by walk/bike only')
  })

  context('of a region', () => {
    it.skip('runs a regional analysis', function () {
      fetchResults()
      cy.get('@primary')
        .findByRole('button', {name: 'Multi-point'})
        .should('be.enabled')
    })

    it('compares two regional analyses')

    it('uploads an aggregation area')

    it('aggregates results to subregion')
  })
})
<commit_msg>flesh out tests<commit_after>function setCustom(settingKey, newValue, scenario = 'primary') {
  // sets a value in the "Customize Profile Request" box
  let newConfig = {}
  cy.get(`@${scenario}`)
    .findByLabelText(/Customize Profile Request/i)
    .as('profile')
    .invoke('val')
    .then((currentConfig) => {
      newConfig = JSON.parse(currentConfig)
      newConfig[settingKey] = newValue
      cy.get('@profile')
        .invoke('val', JSON.stringify(newConfig, null, 2))
        .trigger('change') // TODO not updating map
    })
}

function setOrigin(latLonArray) {
  // TODO not yet updating map marker
  setCustom('fromLat', latLonArray[0])
  setCustom('fromLon', latLonArray[1])
}

function fetchResults() {
  cy.findByText(/Fetch Results/i).click()
  // wait for results
  cy.findByText(/Fetch Results/i).should('not.exist')
  cy.findByText(/Fetch Results/i).should('exist')
}

context('Analysis', () => {
  before(() => {
    cy.setup('project')
    cy.setup('opportunities')
  })

  beforeEach(() => {
    cy.navTo('edit modifications') // refresh analysis page by navigating away
    cy.navTo('Analyze')
    cy.fixture('regions/scratch.json').as('region')
    // alias lots of things
    cy.get('div.leaflet-container').as('map')
    cy.get('div#PrimaryAnalysisSettings').as('primary')
    cy.get('div#ComparisonAnalysisSettings').as('comparison')
    // set a standard project, scenario, and opportunity dataset
    // across all tests
    cy.get('@primary')
      .findByLabelText(/^Project$/)
      .click({force: true})
      .type('scratch{enter}')
    cy.get('@primary')
      .findByLabelText(/^Scenario$/)
      .click({force: true})
      .type('baseline{enter}')
    cy.findByLabelText(/^Opportunity Dataset$/)
      .click({force: true})
      .type('default{enter}')
      .should('be.disabled') // becomes disabled while loading
    // enabled again once loaded
    cy.findByLabelText(/^Opportunity Dataset$/).should('be.enabled')
  })

  context('of a point', () => {
    it('has all form elements', function () {
      // note that elements touched in beforeEach are neglected here
      cy.findByLabelText(/Time cutoff/i)
      cy.findByLabelText(/Travel time percentile/i)
      cy.get('@primary')
        .findByRole('button', {name: 'Multi-point'})
        .should('be.disabled')
      cy.get('@primary').contains('scratch project')
      cy.get('@primary').contains('Baseline')
      cy.get('@primary').findAllByLabelText(/Bookmark/)
      cy.get('@primary').findByLabelText(/Access mode/i)
      cy.get('@primary').findByLabelText(/Transit modes/i)
      cy.get('@primary').findByLabelText(/Egress mode/i)
      cy.findByLabelText(/Walk speed/i)
      cy.findByLabelText(/Max walk time/i)
      cy.get('@primary').findByLabelText(/Date/i)
      cy.findByLabelText(/From time/i)
      cy.findByLabelText(/To time/i)
      cy.get('@primary').findByLabelText(/Simulated Schedules/i)
      cy.get('@primary').findByLabelText(/Maximum transfers/i)
      cy.findByLabelText(/Routing engine/i)
      cy.get('@primary').findAllByLabelText(/Bounds of analysis/i)
      cy.get('@primary').findByLabelText(/Customize Profile Request/i)
      cy.findByText(/Fetch Results/i).should('be.enabled')
    })

    it('runs, giving reasonable results', function () {
      // tests basic single point analysis at specified locations
      // compares mapped results to snapshots
      fetchResults() // initialize request
      // set new parameters
      cy.findByLabelText(/Time cutoff/i)
        .invoke('val', 75) // TODO not working
        .trigger('change', {force: true})
      cy.findByLabelText(/Travel time percentile/i)
        .invoke('val', 75) // TODO not working yet
        .trigger('change', {force: true})
      // move marker and align map for snapshot
      for (let key in this.region.locations) {
        let location = this.region.locations[key]
        setOrigin(location)
        cy.centerMapOn(location)
        fetchResults()
        //cy.get('@map').matchImageSnapshot() // TODO
      }
    })

    it('gives different results at different times', function () {
      const location = this.region.locations.center
      setOrigin(location)
      cy.centerMapOn(location)
      // set time window in morning rush -- should have high access
      cy.findByLabelText(/From time/i)
        .as('from')
        .clear()
        .type('06:00')
      cy.findByLabelText(/To time/i)
        .as('to')
        .clear()
        .type('08:00')
      fetchResults()
      //cy.get('@map').matchImageSnapshot() // TODO
      // set time window in late evening - lower access
      cy.get('@from').clear().type('22:00')
      cy.get('@to').clear().type('23:59')
      fetchResults()
      //cy.get('@map').matchImageSnapshot() // TODO
      // narrow window to one minute - no variability
      cy.get('@from').clear().type('12:00')
      cy.get('@to').clear().type('12:01')
      // TODO snapshot chart too
    })

    it('handles direct access by walk/bike only', function () {
      const location = this.region.locations.middle
      setOrigin(location)
      // turn off all transit
      cy.get('@primary')
        .findByLabelText(/Transit modes/i)
        .findByRole('button', {name: /All/i})
        .click()
      cy.get('@primary')
        .findByLabelText(/Access mode/i)
        .should('not.exist')
      // it has changed names, becoming:
      cy.get('@primary')
        .findByLabelText(/Direct mode/i)
        .findByTitle(/Bike/i)
        .click()
      fetchResults()
      // TODO take snapshot of map and chart
    })

    it('charts accessibility', function () {
      // TODO verify other settings
      const location = this.region.locations.center
      setOrigin(location)
      fetchResults()
      cy.get('svg#results-chart')
      //cy.get('@map').matchImageSnapshot() // TODO take a snapshot
      // add a comparison case to the chart
      cy.get('@comparison')
        .findByLabelText(/^Project$/)
        .click({force: true})
        .type('scratch{enter}')
      cy.get('@comparison')
        .findByLabelText(/^Scenario$/)
        .click({force: true})
        .type('baseline{enter}')
      // change the mode
      cy.get('@comparison')
        .findByLabelText(/Identical request settings/i)
        .uncheck({force: true})
      cy.get('@comparison')
        .findByLabelText(/Access mode/i)
        .findByTitle(/Bike/i)
        .click()
      fetchResults()
      //cy.get('@map').matchImageSnapshot() // TODO take a snapshot
    })

    it('uses custom analysis bounds')

    it('sets a bookmark')
  })

  context('of a region', () => {
    it.skip('runs a regional analysis', function () {
      fetchResults()
      cy.get('@primary')
        .findByRole('button', {name: 'Multi-point'})
        .should('be.enabled')
    })

    it('compares two regional analyses')

    it('uploads an aggregation area')

    it('aggregates results to subregion')
  })
})
<|endoftext|>


<commit_before>Milestones = new Mongo.Collection('milestones');

Milestones.validTypes = ['strategic', 'year', 'month', 'week'];

Milestones.attachSchema(new SimpleSchema({
  'period': { 'type': String, 'optional': true },
  'type': { 'type': String, 'allowedValues': Milestones.validTypes },
  'userId': { 'type': String },
  'parentId': { 'type': String, 'optional': true },
  'startsAt': { 'type': Date, 'optional': true, 'label': 'Start Period' },
  'endsAt': { 'type': Date, 'optional': true, 'label': 'End Period' }
}));

Milestones.boundsFor = (date, type) => {
  if (type === 'strategic') {
    return {
      'startsAt': moment(2000, 'YYYY').toDate(),
      'endsAt': moment().add(100, 'y').toDate()
    };
  }
  return {
    'startsAt': Milestones.bound(date.clone().startOf(type), 'start').toDate(),
    'endsAt': Milestones.bound(date.clone().endOf(type), 'end').toDate()
  };
};

// Returns nearest week bound for given date
Milestones.bound = (date, type = 'start') => {
  let _date = date;
  if (type === 'start' && date.day() > 4) {
    _date = date.add(1, 'w');
  }
  if (type === 'end' && date.day() <= 4) {
    _date = date.subtract(1, 'w');
  }
  return _date[`${type}Of`]('isoWeek');
};

Milestones.relativeType = (type, levelDiff) => {
  return Milestones.validTypes[Milestones.validTypes.indexOf(type) + levelDiff];
};

Milestones.periodFormats = extended => ({
  'year': { 'parse': 'YYYY', 'display': 'YYYY' },
  'month': { 'parse': 'YYYY-MM', 'display': extended ? 'MMMM YYYY' : 'MMMM' },
  'week': { 'parse': '', 'display': extended ? 'DD MMMM YYYY' : 'DD MMM' }
});

Milestones.helpers({
  'goals': function() {
    return Goals.find({'milestoneId': this._id}, {'sort': {'priority': 1}});
  },
  'parent': function() { return Milestones.findOne(this.parentId); },
  'children': function() {
    return Milestones.find({'parentId': this._id}, {'sort': {'startsAt': -1}});
  },
  'title': function(extended) {
    let format = Milestones.periodFormats(extended)[this.type];
    if (this.type === 'strategic') return 'Strategic';
    if (this.type === 'week') {
      let periods = [
        moment(this.period).startOf('week').format('DD'),
        moment(this.period).endOf('week').format(format.display)
      ];
      return periods.join('-');
    }

    return moment(this.period, format.parse).format(format.display);
  },
  'progress': function() {
    let sum = 0;
    let count = 0;
    let goals = Goals.find({
      'milestoneId': this._id
      }, {
        fields: {
          'completedPct': 1,
        }
      }).fetch();

    _.forEach(goals, function(goal) {
        sum += goal.completedPct;
        count ++;
    });

    return Math.round(sum/goals.length) || 0;
  }
});

if (Meteor.isServer) {
  Milestones.allow({
    'insert': function(userId, doc) { return userId === doc.userId; },
    'update': function(userId, doc) { return userId === doc.userId; },
    'remove': function() { return false; }
  });
}

<commit_msg>Fixed 'progress' Milestone helper<commit_after>Milestones = new Mongo.Collection('milestones');

Milestones.validTypes = ['strategic', 'year', 'month', 'week'];

Milestones.attachSchema(new SimpleSchema({
  'period': { 'type': String, 'optional': true },
  'type': { 'type': String, 'allowedValues': Milestones.validTypes },
  'userId': { 'type': String },
  'parentId': { 'type': String, 'optional': true },
  'startsAt': { 'type': Date, 'optional': true, 'label': 'Start Period' },
  'endsAt': { 'type': Date, 'optional': true, 'label': 'End Period' }
}));

Milestones.boundsFor = (date, type) => {
  if (type === 'strategic') {
    return {
      'startsAt': moment(2000, 'YYYY').toDate(),
      'endsAt': moment().add(100, 'y').toDate()
    };
  }
  return {
    'startsAt': Milestones.bound(date.clone().startOf(type), 'start').toDate(),
    'endsAt': Milestones.bound(date.clone().endOf(type), 'end').toDate()
  };
};

// Returns nearest week bound for given date
Milestones.bound = (date, type = 'start') => {
  let _date = date;
  if (type === 'start' && date.day() > 4) {
    _date = date.add(1, 'w');
  }
  if (type === 'end' && date.day() <= 4) {
    _date = date.subtract(1, 'w');
  }
  return _date[`${type}Of`]('isoWeek');
};

Milestones.relativeType = (type, levelDiff) => {
  return Milestones.validTypes[Milestones.validTypes.indexOf(type) + levelDiff];
};

Milestones.periodFormats = extended => ({
  'year': { 'parse': 'YYYY', 'display': 'YYYY' },
  'month': { 'parse': 'YYYY-MM', 'display': extended ? 'MMMM YYYY' : 'MMMM' },
  'week': { 'parse': '', 'display': extended ? 'DD MMMM YYYY' : 'DD MMM' }
});

Milestones.helpers({
  'goals': function() {
    return Goals.find({'milestoneId': this._id}, {'sort': {'priority': 1}});
  },
  'parent': function() { return Milestones.findOne(this.parentId); },
  'children': function() {
    return Milestones.find({'parentId': this._id}, {'sort': {'startsAt': -1}});
  },
  'title': function(extended) {
    let format = Milestones.periodFormats(extended)[this.type];
    if (this.type === 'strategic') return 'Strategic';
    if (this.type === 'week') {
      let periods = [
        moment(this.period).startOf('week').format('DD'),
        moment(this.period).endOf('week').format(format.display)
      ];
      return periods.join('-');
    }

    return moment(this.period, format.parse).format(format.display);
  },
  'progress': function() {
    let cursor = Goals.find(
      {
        'milestoneId': this._id
      }, {
        'fields': {
          'completedPct': 1
        }
      });
    let sum = _.reduce(cursor.map(function(goal) {
      return goal;
    }), function(memo, goal) {
      return memo + goal.completedPct;
    }, 0) || 0;

    return Math.round(sum / cursor.count()) || 0;
  }
});

if (Meteor.isServer) {
  Milestones.allow({
    'insert': function(userId, doc) { return userId === doc.userId; },
    'update': function(userId, doc) { return userId === doc.userId; },
    'remove': function() { return false; }
  });
}

<|endoftext|>


<commit_before>(function (undefined) {
  var jsdom = require('jsdom').jsdom,
      myWindow = jsdom().createWindow(),
      $ = require('../lib/jquery-1.5'),
      jq = require('../lib/jquery-1.5').create(),
      jQuery = require('../lib/jquery-1.5').create(myWindow);

    $("
test passes
").appendTo("body");
    console.log($("body").html());

    jq("
other test passes
").appendTo("body");
    console.log(jq("body").html());

    jQuery("
third test passes
").appendTo("body");
    console.log(jQuery("body").html());

}());
<commit_msg>make local tests work<commit_after>(function (undefined) {
  var jsdom = require('jsdom').jsdom,
      myWindow = jsdom().createWindow(),
      $ = require('../dist/node-jquery'),
      jq = require('../dist/node-jquery').create(),
      jQuery = require('../dist/node-jquery').create(myWindow);

    $("
test passes
").appendTo("body");
    console.log($("body").html());

    jq("
other test passes
").appendTo("body");
    console.log(jq("body").html());

    jQuery("
third test passes
").appendTo("body");
    console.log(jQuery("body").html());

}());
<|endoftext|>


<commit_before>context('Timeline Email', () => {
	before(() => {
		cy.visit('/login');
		cy.login();
		cy.visit('/app/todo');
	});

	it('Adding new ToDo', () => {
		cy.click_listview_primary_button('Add ToDo');
		cy.get('.custom-actions:visible > .btn').contains("Edit in full page").click({delay: 500});
		cy.fill_field("description", "Test ToDo",  "Text Editor");
		cy.wait(500);
		cy.get('.primary-action').contains('Save').click({force: true});
		cy.wait(700);
	});

	it('Adding email and verifying timeline content for email attachment, deleting attachment and ToDo', () => {
		cy.visit('/app/todo');
		cy.get('.list-row > .level-left > .list-subject').eq(0).click();

		//Creating a new email
		cy.get('.timeline-actions > .timeline-item > .action-buttons > .action-btn').click();
		cy.fill_field('recipients', 'test@example.com', 'MultiSelect');
		cy.get('.modal.show > .modal-dialog > .modal-content > .modal-body > :nth-child(1) > .form-layout > .form-page > :nth-child(3) > .section-body > .form-column > form > [data-fieldtype="Text Editor"] > .form-group > .control-input-wrapper > .control-input > .ql-container > .ql-editor').type('Test Mail');

		//Adding attachment to the email
		cy.get('.add-more-attachments > .btn').click();
		cy.get('.mt-2 > .btn > .mt-1').eq(2).click();
		cy.get('.input-group > .form-control').type('https://wallpaperplay.com/walls/full/8/2/b/72402.jpg');
		cy.get('.btn-primary').contains('Upload').click();

		//Sending the email
		cy.click_modal_primary_button('Send', {delay: 500});

		//To check if the sent mail content is shown in the timeline content
		cy.get('[data-doctype="Communication"] > .timeline-content').should('contain', 'Test Mail');

		//To check if the attachment of email is shown in the timeline content
		cy.get('.timeline-content').should('contain', 'Added 72402.jpg');

		//Deleting the sent email
		cy.get('[title="Open Communication"] > .icon').first().click({force: true});
		cy.get('#page-Communication > .page-head > .container > .row > .col > .standard-actions > .menu-btn-group > .btn').click();
		cy.get('#page-Communication > .page-head > .container > .row > .col > .standard-actions > .menu-btn-group > .dropdown-menu > li > .grey-link').eq(9).click();
		cy.get('.modal.show > .modal-dialog > .modal-content > .modal-footer > .standard-actions > .btn-primary').click();

		cy.visit('/app/todo');
		cy.get('.list-row > .level-left > .list-subject > .level-item.ellipsis > .ellipsis').eq(0).click();

		//Removing the added attachment
		cy.get('.attachment-row > .data-pill > .remove-btn > .icon').click();
		cy.wait(500);
		cy.get('.modal-footer:visible > .standard-actions > .btn-primary').contains('Yes').click();

		//To check if the removed attachment is shown in the timeline content
		cy.get('.timeline-content').should('contain', 'Removed 72402.jpg');
		cy.wait(500);

		//To check if the discard button functionality in email is working correctly
		cy.get('.timeline-actions > .timeline-item > .action-buttons > .action-btn').click();
		cy.fill_field('recipients', 'test@example.com', 'MultiSelect');
		cy.get('.modal-footer > .standard-actions > .btn-secondary').contains('Discard').click();
		cy.wait(500);
		cy.get('.timeline-actions > .timeline-item > .action-buttons > .action-btn').click();
		cy.wait(500);
		cy.get_field('recipients', 'MultiSelect').should('have.text', '');
		cy.get('.modal-header:visible > .modal-actions > .btn-modal-close > .icon').click();

		//Deleting the added ToDo
		cy.get('.menu-btn-group:visible > .btn').click();
		cy.get('.menu-btn-group:visible > .dropdown-menu > li > .dropdown-item').contains('Delete').click();
		cy.get('.modal-footer:visible > .standard-actions > .btn-primary').click();
	});
});
<commit_msg>test: flaky timeline_email fix<commit_after>context('Timeline Email', () => {
	before(() => {
		cy.visit('/login');
		cy.login();
		cy.visit('/app/todo');
	});

	it('Adding new ToDo', () => {
		cy.click_listview_primary_button('Add ToDo');
		cy.get('.custom-actions:visible > .btn').contains("Edit in full page").click({delay: 500});
		cy.fill_field("description", "Test ToDo",  "Text Editor");
		cy.wait(500);
		cy.get('.primary-action').contains('Save').click({force: true});
		cy.wait(700);
	});

	it('Adding email and verifying timeline content for email attachment', () => {
		cy.visit('/app/todo');
		cy.get('.list-row > .level-left > .list-subject').eq(0).click();

		//Creating a new email
		cy.get('.timeline-actions > .timeline-item > .action-buttons > .action-btn').click();
		cy.fill_field('recipients', 'test@example.com', 'MultiSelect');
		cy.get('.modal.show > .modal-dialog > .modal-content > .modal-body > :nth-child(1) > .form-layout > .form-page > :nth-child(3) > .section-body > .form-column > form > [data-fieldtype="Text Editor"] > .form-group > .control-input-wrapper > .control-input > .ql-container > .ql-editor').type('Test Mail');

		//Adding attachment to the email
		cy.get('.add-more-attachments > .btn').click();
		cy.get('.mt-2 > .btn > .mt-1').eq(2).click();
		cy.get('.input-group > .form-control').type('https://wallpaperplay.com/walls/full/8/2/b/72402.jpg');
		cy.get('.btn-primary').contains('Upload').click();

		//Sending the email
		cy.click_modal_primary_button('Send', {delay: 500});

		//To check if the sent mail content is shown in the timeline content
		cy.get('[data-doctype="Communication"] > .timeline-content').should('contain', 'Test Mail');

		//To check if the attachment of email is shown in the timeline content
		cy.get('.timeline-content').should('contain', 'Added 72402.jpg');

		//Deleting the sent email
		cy.get('[title="Open Communication"] > .icon').first().click({force: true});
		cy.get('#page-Communication > .page-head > .container > .row > .col > .standard-actions > .menu-btn-group > .btn').click();
		cy.get('#page-Communication > .page-head > .container > .row > .col > .standard-actions > .menu-btn-group > .dropdown-menu > li > .grey-link').eq(9).click();
		cy.get('.modal.show > .modal-dialog > .modal-content > .modal-footer > .standard-actions > .btn-primary').click();
	});

	it('Deleting attachment and ToDo', () => {
		cy.visit('/app/todo');
		cy.get('.list-row > .level-left > .list-subject > .level-item.ellipsis > .ellipsis').eq(0).click();

		//Removing the added attachment
		cy.get('.attachment-row > .data-pill > .remove-btn > .icon').click();
		cy.wait(500);
		cy.get('.modal-footer:visible > .standard-actions > .btn-primary').contains('Yes').click();

		//To check if the removed attachment is shown in the timeline content
		cy.get('.timeline-content').should('contain', 'Removed 72402.jpg');
		cy.wait(500);

		//To check if the discard button functionality in email is working correctly
		cy.get('.timeline-actions > .timeline-item > .action-buttons > .action-btn').click();
		cy.fill_field('recipients', 'test@example.com', 'MultiSelect');
		cy.get('.modal-footer > .standard-actions > .btn-secondary').contains('Discard').click();
		cy.wait(500);
		cy.get('.timeline-actions > .timeline-item > .action-buttons > .action-btn').click();
		cy.wait(500);
		cy.get_field('recipients', 'MultiSelect').should('have.text', '');
		cy.get('.modal-header:visible > .modal-actions > .btn-modal-close > .icon').click();

		//Deleting the added ToDo
		cy.get('.menu-btn-group:visible > .btn').click();
		cy.get('.menu-btn-group:visible > .dropdown-menu > li > .dropdown-item').contains('Delete').click();
		cy.get('.modal-footer:visible > .standard-actions > .btn-primary').click();
	});
});
<|endoftext|>


<commit_before>// Activities don't need a schema because they are always set from the a trusted
// environment - the server - and there is no risk that a user change the logic
// we use with this collection. Moreover using a schema for this collection
// would be difficult (different activities have different fields) and wouldn't
// bring any direct advantage.
//
// XXX The activities API is not so nice and need some functionalities. For
// instance if a user archive a card, and un-archive it a few seconds later we
// should remove both activities assuming it was an error the user decided to
// revert.
Activities = new Mongo.Collection('activities');

Activities.helpers({
  board() {
    return Boards.findOne(this.boardId);
  },
  oldBoard() {
    return Boards.findOne(this.oldBoardId);
  },
  user() {
    return Users.findOne(this.userId);
  },
  member() {
    return Users.findOne(this.memberId);
  },
  list() {
    return Lists.findOne(this.listId);
  },
  swimlane() {
    return Swimlanes.findOne(this.swimlaneId);
  },
  oldSwimlane() {
    return Swimlanes.findOne(this.oldSwimlaneId);
  },
  oldList() {
    return Lists.findOne(this.oldListId);
  },
  card() {
    return Cards.findOne(this.cardId);
  },
  comment() {
    return CardComments.findOne(this.commentId);
  },
  attachment() {
    return Attachments.findOne(this.attachmentId);
  },
  checklist() {
    return Checklists.findOne(this.checklistId);
  },
  checklistItem() {
    return ChecklistItems.findOne(this.checklistItemId);
  },
  subtasks() {
    return Cards.findOne(this.subtaskId);
  },
  customField() {
    return CustomFields.findOne(this.customFieldId);
  },
  // Label activity did not work yet, unable to edit labels when tried this.
  //label() {
  //  return Cards.findOne(this.labelId);
  //},
});

Activities.before.update((userId, doc, fieldNames, modifier) => {
  modifier.$set = modifier.$set || {};
  modifier.$set.modifiedAt = new Date();
});

Activities.before.insert((userId, doc) => {
  doc.createdAt = new Date();
  doc.modifiedAt = doc.createdAt;
});

Activities.after.insert((userId, doc) => {
  const activity = Activities._transform(doc);
  RulesHelper.executeRules(activity);
});

if (Meteor.isServer) {
  // For efficiency create indexes on the date of creation, and on the date of
  // creation in conjunction with the card or board id, as corresponding views
  // are largely used in the App. See #524.
  Meteor.startup(() => {
    Activities._collection._ensureIndex({ createdAt: -1 });
    Activities._collection._ensureIndex({ modifiedAt: -1 });
    Activities._collection._ensureIndex({ cardId: 1, createdAt: -1 });
    Activities._collection._ensureIndex({ boardId: 1, createdAt: -1 });
    Activities._collection._ensureIndex(
      { commentId: 1 },
      { partialFilterExpression: { commentId: { $exists: true } } },
    );
    Activities._collection._ensureIndex(
      { attachmentId: 1 },
      { partialFilterExpression: { attachmentId: { $exists: true } } },
    );
    Activities._collection._ensureIndex(
      { customFieldId: 1 },
      { partialFilterExpression: { customFieldId: { $exists: true } } },
    );
    // Label activity did not work yet, unable to edit labels when tried this.
    //Activities._collection._dropIndex({ labelId: 1 }, { "indexKey": -1 });
    //Activities._collection._dropIndex({ labelId: 1 }, { partialFilterExpression: { labelId: { $exists: true } } });
  });

  Activities.after.insert((userId, doc) => {
    const activity = Activities._transform(doc);
    let participants = [];
    let watchers = [];
    let title = 'act-activity-notify';
    const board = Boards.findOne(activity.boardId);
    const description = `act-${activity.activityType}`;
    const params = {
      activityId: activity._id,
    };
    if (activity.userId) {
      // No need send notification to user of activity
      // participants = _.union(participants, [activity.userId]);
      const user = activity.user();
      if (user) {
        if (user.getName()) {
          params.user = user.getName();
        }
        if (user.emails) {
          params.userEmails = user.emails;
        }
        if (activity.userId) {
          params.userId = activity.userId;
        }
      }
    }
    if (activity.boardId) {
      if (board.title.length > 0) {
        params.board = board.title;
      } else {
        params.board = '';
      }
      title = 'act-withBoardTitle';
      params.url = board.absoluteUrl();
      params.boardId = activity.boardId;
    }
    if (activity.oldBoardId) {
      const oldBoard = activity.oldBoard();
      if (oldBoard) {
        watchers = _.union(watchers, oldBoard.watchers || []);
        params.oldBoard = oldBoard.title;
        params.oldBoardId = activity.oldBoardId;
      }
    }
    if (activity.memberId) {
      participants = _.union(participants, [activity.memberId]);
      params.member = activity.member().getName();
    }
    if (activity.listId) {
      const list = activity.list();
      watchers = _.union(watchers, list.watchers || []);
      params.list = list.title;
      params.listId = activity.listId;
    }
    if (activity.oldListId) {
      const oldList = activity.oldList();
      if (oldList) {
        watchers = _.union(watchers, oldList.watchers || []);
        params.oldList = oldList.title;
        params.oldListId = activity.oldListId;
      }
    }
    if (activity.oldSwimlaneId) {
      const oldSwimlane = activity.oldSwimlane();
      if (oldSwimlane) {
        watchers = _.union(watchers, oldSwimlane.watchers || []);
        params.oldSwimlane = oldSwimlane.title;
        params.oldSwimlaneId = activity.oldSwimlaneId;
      }
    }
    if (activity.cardId) {
      const card = activity.card();
      participants = _.union(participants, [card.userId], card.members || []);
      watchers = _.union(watchers, card.watchers || []);
      params.card = card.title;
      title = 'act-withCardTitle';
      params.url = card.absoluteUrl();
      params.cardId = activity.cardId;
    }
    if (activity.swimlaneId) {
      const swimlane = activity.swimlane();
      params.swimlane = swimlane.title;
      params.swimlaneId = activity.swimlaneId;
    }
    if (activity.commentId) {
      const comment = activity.comment();
      params.comment = comment.text;
      if (board) {
        const comment = params.comment;
        const knownUsers = board.members.map(member => {
          const u = Users.findOne(member.userId);
          if (u) {
            member.username = u.username;
            member.emails = u.emails;
          }
          return member;
        });
        const mentionRegex = /\B@(?:(?:"([\w.\s]*)")|([\w.]+))/gi; // including space in username
        let currentMention;
        while ((currentMention = mentionRegex.exec(comment)) !== null) {
          /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "[iI]gnored" }]*/
          const [ignored, quoteduser, simple] = currentMention;
          const username = quoteduser || simple;
          if (username === params.user) {
            // ignore commenter mention himself?
            continue;
          }
          const atUser = _.findWhere(knownUsers, { username });
          if (!atUser) {
            continue;
          }
          const uid = atUser.userId;
          params.atUsername = username;
          params.atEmails = atUser.emails;
          title = 'act-atUserComment';
          watchers = _.union(watchers, [uid]);
        }
      }
      params.commentId = comment._id;
    }
    if (activity.attachmentId) {
      const attachment = activity.attachment();
      params.attachment = attachment.original.name;
      params.attachmentId = attachment._id;
    }
    if (activity.checklistId) {
      const checklist = activity.checklist();
      if (checklist) {
        if (checklist.title) {
          params.checklist = checklist.title;
        }
      }
    }
    if (activity.checklistItemId) {
      const checklistItem = activity.checklistItem();
      if (checklistItem) {
        if (checklistItem.title) {
          params.checklistItem = checklistItem.title;
        }
      }
    }
    if (activity.customFieldId) {
      const customField = activity.customField();
      if (customField) {
        if (customField.name) {
          params.customField = customField.name;
        }
        if (actitivy.value) {
          params.customFieldValue = activity.value;
        }
      }
    }
    // Label activity did not work yet, unable to edit labels when tried this.
    //if (activity.labelId) {
    //  const label = activity.label();
    //  params.label = label.name;
    //  params.labelId = activity.labelId;
    //}
    if (
      (!activity.timeKey || activity.timeKey === 'dueAt') &&
      activity.timeValue
    ) {
      // due time reminder, if it doesn't have old value, it's a brand new set, need some differentiation
      title = activity.timeOldValue ? 'act-withDue' : 'act-newDue';
    }
    ['timeValue', 'timeOldValue'].forEach(key => {
      // copy time related keys & values to params
      const value = activity[key];
      if (value) params[key] = value;
    });
    if (board) {
      const BIGEVENTS = process.env.BIGEVENTS_PATTERN; // if environment BIGEVENTS_PATTERN is set, any activityType matching it is important
      if (BIGEVENTS) {
        try {
          const atype = activity.activityType;
          if (new RegExp(BIGEVENTS).exec(atype)) {
            watchers = _.union(
              watchers,
              board.activeMembers().map(member => member.userId),
            ); // notify all active members for important events
          }
        } catch (e) {
          // passed env var BIGEVENTS_PATTERN is not a valid regex
        }
      }

      const watchingUsers = _.pluck(
        _.where(board.watchers, { level: 'watching' }),
        'userId',
      );
      const trackingUsers = _.pluck(
        _.where(board.watchers, { level: 'tracking' }),
        'userId',
      );
      watchers = _.union(
        watchers,
        watchingUsers,
        _.intersection(participants, trackingUsers),
      );
    }
    Notifications.getUsers(watchers).forEach(user => {
      // don't notify a user of their own behavior
      if (user._id !== userId) {
        Notifications.notify(user, title, description, params);
      }
    });

    const integrations = Integrations.find({
      boardId: { $in: [board._id, Integrations.Const.GLOBAL_WEBHOOK_ID] },
      // type: 'outgoing-webhooks', // all types
      enabled: true,
      activities: { $in: [description, 'all'] },
    }).fetch();
    if (integrations.length > 0) {
      params.watchers = watchers;
      integrations.forEach(integration => {
        Meteor.call(
          'outgoingWebhooks',
          integration,
          description,
          params,
          () => {
            return;
          },
        );
      });
    }
  });
}

export default Activities;
<commit_msg>Fix syntax typo<commit_after>// Activities don't need a schema because they are always set from the a trusted
// environment - the server - and there is no risk that a user change the logic
// we use with this collection. Moreover using a schema for this collection
// would be difficult (different activities have different fields) and wouldn't
// bring any direct advantage.
//
// XXX The activities API is not so nice and need some functionalities. For
// instance if a user archive a card, and un-archive it a few seconds later we
// should remove both activities assuming it was an error the user decided to
// revert.
Activities = new Mongo.Collection('activities');

Activities.helpers({
  board() {
    return Boards.findOne(this.boardId);
  },
  oldBoard() {
    return Boards.findOne(this.oldBoardId);
  },
  user() {
    return Users.findOne(this.userId);
  },
  member() {
    return Users.findOne(this.memberId);
  },
  list() {
    return Lists.findOne(this.listId);
  },
  swimlane() {
    return Swimlanes.findOne(this.swimlaneId);
  },
  oldSwimlane() {
    return Swimlanes.findOne(this.oldSwimlaneId);
  },
  oldList() {
    return Lists.findOne(this.oldListId);
  },
  card() {
    return Cards.findOne(this.cardId);
  },
  comment() {
    return CardComments.findOne(this.commentId);
  },
  attachment() {
    return Attachments.findOne(this.attachmentId);
  },
  checklist() {
    return Checklists.findOne(this.checklistId);
  },
  checklistItem() {
    return ChecklistItems.findOne(this.checklistItemId);
  },
  subtasks() {
    return Cards.findOne(this.subtaskId);
  },
  customField() {
    return CustomFields.findOne(this.customFieldId);
  },
  // Label activity did not work yet, unable to edit labels when tried this.
  //label() {
  //  return Cards.findOne(this.labelId);
  //},
});

Activities.before.update((userId, doc, fieldNames, modifier) => {
  modifier.$set = modifier.$set || {};
  modifier.$set.modifiedAt = new Date();
});

Activities.before.insert((userId, doc) => {
  doc.createdAt = new Date();
  doc.modifiedAt = doc.createdAt;
});

Activities.after.insert((userId, doc) => {
  const activity = Activities._transform(doc);
  RulesHelper.executeRules(activity);
});

if (Meteor.isServer) {
  // For efficiency create indexes on the date of creation, and on the date of
  // creation in conjunction with the card or board id, as corresponding views
  // are largely used in the App. See #524.
  Meteor.startup(() => {
    Activities._collection._ensureIndex({ createdAt: -1 });
    Activities._collection._ensureIndex({ modifiedAt: -1 });
    Activities._collection._ensureIndex({ cardId: 1, createdAt: -1 });
    Activities._collection._ensureIndex({ boardId: 1, createdAt: -1 });
    Activities._collection._ensureIndex(
      { commentId: 1 },
      { partialFilterExpression: { commentId: { $exists: true } } },
    );
    Activities._collection._ensureIndex(
      { attachmentId: 1 },
      { partialFilterExpression: { attachmentId: { $exists: true } } },
    );
    Activities._collection._ensureIndex(
      { customFieldId: 1 },
      { partialFilterExpression: { customFieldId: { $exists: true } } },
    );
    // Label activity did not work yet, unable to edit labels when tried this.
    //Activities._collection._dropIndex({ labelId: 1 }, { "indexKey": -1 });
    //Activities._collection._dropIndex({ labelId: 1 }, { partialFilterExpression: { labelId: { $exists: true } } });
  });

  Activities.after.insert((userId, doc) => {
    const activity = Activities._transform(doc);
    let participants = [];
    let watchers = [];
    let title = 'act-activity-notify';
    const board = Boards.findOne(activity.boardId);
    const description = `act-${activity.activityType}`;
    const params = {
      activityId: activity._id,
    };
    if (activity.userId) {
      // No need send notification to user of activity
      // participants = _.union(participants, [activity.userId]);
      const user = activity.user();
      if (user) {
        if (user.getName()) {
          params.user = user.getName();
        }
        if (user.emails) {
          params.userEmails = user.emails;
        }
        if (activity.userId) {
          params.userId = activity.userId;
        }
      }
    }
    if (activity.boardId) {
      if (board.title.length > 0) {
        params.board = board.title;
      } else {
        params.board = '';
      }
      title = 'act-withBoardTitle';
      params.url = board.absoluteUrl();
      params.boardId = activity.boardId;
    }
    if (activity.oldBoardId) {
      const oldBoard = activity.oldBoard();
      if (oldBoard) {
        watchers = _.union(watchers, oldBoard.watchers || []);
        params.oldBoard = oldBoard.title;
        params.oldBoardId = activity.oldBoardId;
      }
    }
    if (activity.memberId) {
      participants = _.union(participants, [activity.memberId]);
      params.member = activity.member().getName();
    }
    if (activity.listId) {
      const list = activity.list();
      watchers = _.union(watchers, list.watchers || []);
      params.list = list.title;
      params.listId = activity.listId;
    }
    if (activity.oldListId) {
      const oldList = activity.oldList();
      if (oldList) {
        watchers = _.union(watchers, oldList.watchers || []);
        params.oldList = oldList.title;
        params.oldListId = activity.oldListId;
      }
    }
    if (activity.oldSwimlaneId) {
      const oldSwimlane = activity.oldSwimlane();
      if (oldSwimlane) {
        watchers = _.union(watchers, oldSwimlane.watchers || []);
        params.oldSwimlane = oldSwimlane.title;
        params.oldSwimlaneId = activity.oldSwimlaneId;
      }
    }
    if (activity.cardId) {
      const card = activity.card();
      participants = _.union(participants, [card.userId], card.members || []);
      watchers = _.union(watchers, card.watchers || []);
      params.card = card.title;
      title = 'act-withCardTitle';
      params.url = card.absoluteUrl();
      params.cardId = activity.cardId;
    }
    if (activity.swimlaneId) {
      const swimlane = activity.swimlane();
      params.swimlane = swimlane.title;
      params.swimlaneId = activity.swimlaneId;
    }
    if (activity.commentId) {
      const comment = activity.comment();
      params.comment = comment.text;
      if (board) {
        const comment = params.comment;
        const knownUsers = board.members.map(member => {
          const u = Users.findOne(member.userId);
          if (u) {
            member.username = u.username;
            member.emails = u.emails;
          }
          return member;
        });
        const mentionRegex = /\B@(?:(?:"([\w.\s]*)")|([\w.]+))/gi; // including space in username
        let currentMention;
        while ((currentMention = mentionRegex.exec(comment)) !== null) {
          /*eslint no-unused-vars: ["error", { "varsIgnorePattern": "[iI]gnored" }]*/
          const [ignored, quoteduser, simple] = currentMention;
          const username = quoteduser || simple;
          if (username === params.user) {
            // ignore commenter mention himself?
            continue;
          }
          const atUser = _.findWhere(knownUsers, { username });
          if (!atUser) {
            continue;
          }
          const uid = atUser.userId;
          params.atUsername = username;
          params.atEmails = atUser.emails;
          title = 'act-atUserComment';
          watchers = _.union(watchers, [uid]);
        }
      }
      params.commentId = comment._id;
    }
    if (activity.attachmentId) {
      const attachment = activity.attachment();
      params.attachment = attachment.original.name;
      params.attachmentId = attachment._id;
    }
    if (activity.checklistId) {
      const checklist = activity.checklist();
      if (checklist) {
        if (checklist.title) {
          params.checklist = checklist.title;
        }
      }
    }
    if (activity.checklistItemId) {
      const checklistItem = activity.checklistItem();
      if (checklistItem) {
        if (checklistItem.title) {
          params.checklistItem = checklistItem.title;
        }
      }
    }
    if (activity.customFieldId) {
      const customField = activity.customField();
      if (customField) {
        if (customField.name) {
          params.customField = customField.name;
        }
        if (activity.value) {
          params.customFieldValue = activity.value;
        }
      }
    }
    // Label activity did not work yet, unable to edit labels when tried this.
    //if (activity.labelId) {
    //  const label = activity.label();
    //  params.label = label.name;
    //  params.labelId = activity.labelId;
    //}
    if (
      (!activity.timeKey || activity.timeKey === 'dueAt') &&
      activity.timeValue
    ) {
      // due time reminder, if it doesn't have old value, it's a brand new set, need some differentiation
      title = activity.timeOldValue ? 'act-withDue' : 'act-newDue';
    }
    ['timeValue', 'timeOldValue'].forEach(key => {
      // copy time related keys & values to params
      const value = activity[key];
      if (value) params[key] = value;
    });
    if (board) {
      const BIGEVENTS = process.env.BIGEVENTS_PATTERN; // if environment BIGEVENTS_PATTERN is set, any activityType matching it is important
      if (BIGEVENTS) {
        try {
          const atype = activity.activityType;
          if (new RegExp(BIGEVENTS).exec(atype)) {
            watchers = _.union(
              watchers,
              board.activeMembers().map(member => member.userId),
            ); // notify all active members for important events
          }
        } catch (e) {
          // passed env var BIGEVENTS_PATTERN is not a valid regex
        }
      }

      const watchingUsers = _.pluck(
        _.where(board.watchers, { level: 'watching' }),
        'userId',
      );
      const trackingUsers = _.pluck(
        _.where(board.watchers, { level: 'tracking' }),
        'userId',
      );
      watchers = _.union(
        watchers,
        watchingUsers,
        _.intersection(participants, trackingUsers),
      );
    }
    Notifications.getUsers(watchers).forEach(user => {
      // don't notify a user of their own behavior
      if (user._id !== userId) {
        Notifications.notify(user, title, description, params);
      }
    });

    const integrations = Integrations.find({
      boardId: { $in: [board._id, Integrations.Const.GLOBAL_WEBHOOK_ID] },
      // type: 'outgoing-webhooks', // all types
      enabled: true,
      activities: { $in: [description, 'all'] },
    }).fetch();
    if (integrations.length > 0) {
      params.watchers = watchers;
      integrations.forEach(integration => {
        Meteor.call(
          'outgoingWebhooks',
          integration,
          description,
          params,
          () => {
            return;
          },
        );
      });
    }
  });
}

export default Activities;
<|endoftext|>