<commit_before>import { rgbToHex } from '../util.js';
import { map } from '../map.js';
import { controllers } from './Controller.js';

export class TimeSeriesMarker extends HTMLElement {
    constructor(latLon) {
        super();
        const roundLatLon = (num) => Math.round(num*100)/100;
        this.innerHTML = `

                hide

                    Add name:
                    <input id='timeseries-custom-name'></input>

                    lat: ${roundLatLon(latLon.lat)} lon: ${roundLatLon(latLon.lng)}
                    No layer with colorbar to show values

        `;
        this.chartColor = null;
        this.colorInputted = false;
        this.clrbarLocation = null;
        this.hideOnChart = false;
        this.infoOpen = false;
    }

    getChartColor() {
        return this.chartColor;
    }

    setChartColor(chartColor) {
        this.chartColor = chartColor;
        this.colorInputted = true;
    }

    setName(name) {
        this.querySelector('#timeseries-custom-name').value = name;
    }

    getName() {
        return this.querySelector('#timeseries-custom-name').value;
    }

    bindHide(fun) {
        const hideButton = this.querySelector('#hideMenu');
        hideButton.onclick = fun;
    }

    setRGBValues(rgb, clrbarLocation) {
        var [r, g, b] = rgb;
        if ((r + g + b) > 745) {
            [r, g, b] = [0, 0, 0];
        }
        if (!this.colorInputted) {
            var hexValue = rgbToHex(r, g, b);
            this.chartColor = hexValue;
        }
        this.clrbarLocation = clrbarLocation;
        const clrbarP = this.querySelector('#colorbar-location');
        const rgbP = this.querySelector('#rgb-value');
        clrbarP.style.display = 'none';
        rgbP.innerHTML = 'No layer with colorbar to show values of';
        rgbP.style.color = 'black';
        if (clrbarLocation != null) {
            clrbarP.style.display = 'block';
            clrbarP.innerHTML = 'colorbar location: ' + clrbarLocation;
            rgbP.style.color = `rgb(${r},${g},${b})`;
            rgbP.innerHTML = `pixel value: R${r} G${g} B${b}`;
        }
    }
}

export class Marker {
    constructor(latLon, coords) {
        this._latlng = latLon;
        this.imageCoords = coords;

        this.popup = L.popup({closeOnClick: false, autoClose: false, autoPan: false}).setLatLng(latLon).addTo(map);
        this.timeSeriesMarker = new TimeSeriesMarker(latLon, coords);
        this.timeSeriesMarker.bindHide(() => this.hideMarkerInfo());
        this.popup.setContent(this.timeSeriesMarker);
        this.popup.getElement().style.display = 'none';

        var markerIcon = L.icon({iconUrl: 'icons/arrow_drop_down_black_24dp.svg', iconAnchor: [13, 16]});
        this.marker = L.marker(latLon, {icon: markerIcon, autoPan: false}).addTo(map);
        this.popup.on('remove', () => {
            controllers.timeSeriesMarkers.remove(this);
            this.marker.removeFrom(map);
        });
        this.marker.on('mousedown', () => {
            if (this.timeSeriesMarker.infoOpen) {
                this.hideMarkerInfo();
            } else {
                this.showMarkerInfo();
            }
        });
    }

    hideMarkerInfo() {
        var popupElem = this.popup.getElement();
        popupElem.style.display = 'none';
        this.timeSeriesMarker.infoOpen = false;
    }

    showMarkerInfo() {
        var popupElem = this.popup.getElement();
        popupElem.style.display = 'block';
        this.timeSeriesMarker.infoOpen = true;
    }

    getContent() {
        return this.timeSeriesMarker;
    }
}

window.customElements.define('time-series-marker', TimeSeriesMarker);
<commit_msg>REFACTOR Uses an svg directly for the icon used as a timeSeries Marker instead of using an http request. This prevents placing markers from being blocked and also eliminates an http request.<commit_after>import { rgbToHex } from '../util.js';
import { map } from '../map.js';
import { controllers } from './Controller.js';

export class TimeSeriesMarker extends HTMLElement {
    constructor(latLon) {
        super();
        const roundLatLon = (num) => Math.round(num*100)/100;
        this.innerHTML = `

                hide

                    Add name:
                    <input id='timeseries-custom-name'></input>

                    lat: ${roundLatLon(latLon.lat)} lon: ${roundLatLon(latLon.lng)}
                    No layer with colorbar to show values

        `;
        this.chartColor = null;
        this.colorInputted = false;
        this.clrbarLocation = null;
        this.hideOnChart = false;
        this.infoOpen = false;
    }

    getChartColor() {
        return this.chartColor;
    }

    setChartColor(chartColor) {
        this.chartColor = chartColor;
        this.colorInputted = true;
    }

    setName(name) {
        this.querySelector('#timeseries-custom-name').value = name;
    }

    getName() {
        return this.querySelector('#timeseries-custom-name').value;
    }

    bindHide(fun) {
        const hideButton = this.querySelector('#hideMenu');
        hideButton.onclick = fun;
    }

    setRGBValues(rgb, clrbarLocation) {
        var [r, g, b] = rgb;
        if ((r + g + b) > 745) {
            [r, g, b] = [0, 0, 0];
        }
        if (!this.colorInputted) {
            var hexValue = rgbToHex(r, g, b);
            this.chartColor = hexValue;
        }
        this.clrbarLocation = clrbarLocation;
        const clrbarP = this.querySelector('#colorbar-location');
        const rgbP = this.querySelector('#rgb-value');
        clrbarP.style.display = 'none';
        rgbP.innerHTML = 'No layer with colorbar to show values of';
        rgbP.style.color = 'black';
        if (clrbarLocation != null) {
            clrbarP.style.display = 'block';
            clrbarP.innerHTML = 'colorbar location: ' + clrbarLocation;
            rgbP.style.color = `rgb(${r},${g},${b})`;
            rgbP.innerHTML = `pixel value: R${r} G${g} B${b}`;
        }
    }
}

export class Marker {
    constructor(latLon, coords) {
        this._latlng = latLon;
        this.imageCoords = coords;

        this.popup = L.popup({closeOnClick: false, autoClose: false, autoPan: false}).setLatLng(latLon).addTo(map);
        this.timeSeriesMarker = new TimeSeriesMarker(latLon, coords);
        this.timeSeriesMarker.bindHide(() => this.hideMarkerInfo());
        this.popup.setContent(this.timeSeriesMarker);
        this.popup.getElement().style.display = 'none';

        let svgString = `<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24'>
                                <path d="M0 0h24v24H0V0z" fill="none"></path>
                                <path d="M7 10l5 5 5-5H7z"></path>
                              </svg>`;
        let myIconUrl = encodeURI("data:image/svg+xml," + svgString).replace('#','%23');
        var markerIcon = L.icon({iconUrl: myIconUrl, iconAnchor: [13, 16]});

        this.marker = L.marker(latLon, {icon: markerIcon, autoPan: false}).addTo(map);
        this.popup.on('remove', () => {
            controllers.timeSeriesMarkers.remove(this);
            this.marker.removeFrom(map);
        });
        this.marker.on('mousedown', () => {
            if (this.timeSeriesMarker.infoOpen) {
                this.hideMarkerInfo();
            } else {
                this.showMarkerInfo();
            }
        });
    }

    hideMarkerInfo() {
        var popupElem = this.popup.getElement();
        popupElem.style.display = 'none';
        this.timeSeriesMarker.infoOpen = false;
    }

    showMarkerInfo() {
        var popupElem = this.popup.getElement();
        popupElem.style.display = 'block';
        this.timeSeriesMarker.infoOpen = true;
    }

    getContent() {
        return this.timeSeriesMarker;
    }
}

window.customElements.define('time-series-marker', TimeSeriesMarker);
<|endoftext|>


<commit_before>var request = require('request');
var q = require('queue-async');
var CacheOnDemand = require('cache-on-demand');

module.exports = RemoteProxy;
function RemoteProxy(raja, opts) {
	if (!(this instanceof RemoteProxy)) return new RemoteProxy(raja, opts);
	this.raja = raja;
	this.pollers = {};
	this.opts = opts || {};
	// default value
	if (this.opts.maxage == null) this.opts.maxage = 6000; // 100mn
	var self = this;
	raja.on('ready', function() {
		raja.store.lfu.on('eviction', function(url, resource) {
			var poller = self.pollers[url];
			if (!poller) return;
			delete self.pollers[url];
			// let it time out
		});
	});
}

RemoteProxy.prototype.get = function(url, opts, cb) {
	if (!cb && typeof opts == "function") {
		cb = opts;
		opts = null;
	}
	if (!opts) opts = {};
	var raja = this.raja;
	var poller = this.pollers[url] || {};
	poller.accept = opts.accept;
	if (poller.accept == "json") poller.accept = "application/json";

	raja.store.get(url, function(err, resource) {
		if (err) raja.error(err);
		if (!resource) resource = {url: url};
		if (!resource.maxage) resource.maxage = opts.maxage || this.opts.maxage;
		if (opts.preload) poller.preload = true;
		this.pollers[url] = poller;
		var delay = resource.mtime && (resource.maxage * 1000 - Date.now() + resource.mtime.getTime());
		if ((delay > 0 && resource.valid || poller.timeout || poller.preloading) && resource.data != null) {
			cb(null, resource);
			cb = null;
		}
		if (cb) {
			this.load(resource, poller, cb);
		} else if (!poller.timeout && !poller.preloading) {
			poller.timeout = setTimeout(this.load.bind(this, resource, poller), delay);
		}
	}.bind(this));
};

RemoteProxy.prototype.load = CacheOnDemand(function(resource, poller, cb) {
	var raja = this.raja;
	if (!cb) cb = raja.error;
	var obj = { url: resource.url, headers: {} };
	if (resource.headers && resource.headers.ETag) {
		obj.headers["If-None-Match"] = resource.headers.ETag;
	}
	if (poller.accept) obj.headers["Accept"] = poller.accept;
	poller.preloading = true;
	request(obj, function(err, res, body) {
		var code = res && res.statusCode;
		var foreign, msg;
		if (err) {
			if (cb) cb(err);
			if (!poller.preload) return;
		} else {
			foreign = res.headers['x-raja'] !== raja.opts.namespace;
			msg = { url: resource.url, mtime: new Date() };
		}

		if (code >= 500 || !code) {
			cb(code);
		} else if (code == 404) {
			raja.store.del(resource.url, function(err) {
				if (err) return raja.error(err);
				msg.method = 'delete';
				raja.send(msg);
			});
			// do not track
			return cb(code);
		} else if (code >= 400) {
			// do not track
			return cb(code);
		} else if (code == 304) {
			cb(null, resource);
		}	else if (code >= 200 && code < 300) {
			var dataStr = resource.data;
			if (dataStr && Buffer.isBuffer(dataStr)) dataStr = dataStr.toString();
			var bodyStr = body;
			if (body && Buffer.isBuffer(body)) bodyStr = body.toString();
			if (dataStr != bodyStr) {
				var invalidate = resource.data !== undefined;
				resource.data = body;
				resource.headers = {
					'Content-Type': res.headers['content-type'],
					'Etag': res.headers['etag'],
					'Vary': 'Content-Type'
				};
				resource.valid = true; // valid now
				raja.store.set(resource.url, {
					data: body,
					headers: resource.headers,
					maxage: resource.maxage
				}, function(err) {
					if (err) return raja.error(err);
					if (!invalidate) return;
					msg.method = 'put';
					raja.send(msg);
				});
			}
			cb(null, resource);
		} else {
			console.error("Error while trying to fetch remote resource", code, resource.url);
		}
		poller.preloading = false;
		if (!poller.timeout) {
			poller.timeout = setTimeout(function(resource, poller) {
				delete poller.timeout;
				if (poller.preload) {
					this.load(resource, poller);
				}	else if (resource.valid && !foreign) {
					raja.store.invalidate(resource.url, function(err) {
						if (err) return raja.error(err);
						// force parents to update on demand
						raja.send({ url: resource.url, mtime: new Date(), method: 'put' });
					});
				}
			}.bind(this, resource, poller), resource.maxage * 1000);
		}
	}.bind(this));
}, function(resource) {
	return resource.url;
});

<commit_msg>Remote proxy: no max age by default<commit_after>var request = require('request');
var q = require('queue-async');
var CacheOnDemand = require('cache-on-demand');

module.exports = RemoteProxy;
function RemoteProxy(raja, opts) {
	if (!(this instanceof RemoteProxy)) return new RemoteProxy(raja, opts);
	this.raja = raja;
	this.pollers = {};
	this.opts = opts || {};
	// default value
	if (this.opts.maxage == null) this.opts.maxage = Infinity;
	var self = this;
	raja.on('ready', function() {
		raja.store.lfu.on('eviction', function(url, resource) {
			var poller = self.pollers[url];
			if (!poller) return;
			delete self.pollers[url];
			// let it time out
		});
	});
}

RemoteProxy.prototype.get = function(url, opts, cb) {
	if (!cb && typeof opts == "function") {
		cb = opts;
		opts = null;
	}
	if (!opts) opts = {};
	var raja = this.raja;
	var poller = this.pollers[url] || {};
	poller.accept = opts.accept;
	if (poller.accept == "json") poller.accept = "application/json";

	raja.store.get(url, function(err, resource) {
		if (err) raja.error(err);
		if (!resource) resource = {url: url};
		if (!resource.maxage) resource.maxage = opts.maxage || this.opts.maxage;
		if (opts.preload) poller.preload = true;
		this.pollers[url] = poller;
		var delay = resource.mtime && (resource.maxage * 1000 - Date.now() + resource.mtime.getTime());
		if ((delay > 0 && resource.valid || poller.timeout || poller.preloading) && resource.data != null) {
			cb(null, resource);
			cb = null;
		}
		if (cb) {
			this.load(resource, poller, cb);
		} else if (!poller.timeout && !poller.preloading && delay > 0 && delay < Infinity) {
			poller.timeout = setTimeout(this.load.bind(this, resource, poller, raja.error), delay);
		}
	}.bind(this));
};

RemoteProxy.prototype.load = CacheOnDemand(function(resource, poller, cb) {
	var raja = this.raja;
	if (!cb) cb = raja.error;
	var obj = { url: resource.url, headers: {} };
	if (resource.headers && resource.headers.ETag) {
		obj.headers["If-None-Match"] = resource.headers.ETag;
	}
	if (poller.accept) obj.headers["Accept"] = poller.accept;
	poller.preloading = true;
	request(obj, function(err, res, body) {
		var code = res && res.statusCode;
		var foreign, msg;
		if (err) {
			if (cb) cb(err);
			if (!poller.preload) return;
		} else {
			foreign = res.headers['x-raja'] !== raja.opts.namespace;
			msg = { url: resource.url, mtime: new Date() };
		}

		if (code >= 500 || !code) {
			cb(code);
		} else if (code == 404) {
			raja.store.del(resource.url, function(err) {
				if (err) return raja.error(err);
				msg.method = 'delete';
				raja.send(msg);
			});
			// do not track
			return cb(code);
		} else if (code >= 400) {
			// do not track
			return cb(code);
		} else if (code == 304) {
			cb(null, resource);
		}	else if (code >= 200 && code < 300) {
			var dataStr = resource.data;
			if (dataStr && Buffer.isBuffer(dataStr)) dataStr = dataStr.toString();
			var bodyStr = body;
			if (body && Buffer.isBuffer(body)) bodyStr = body.toString();
			if (dataStr != bodyStr) {
				var invalidate = resource.data !== undefined;
				resource.data = body;
				resource.headers = {
					'Content-Type': res.headers['content-type'],
					'Etag': res.headers['etag'],
					'Vary': 'Content-Type'
				};
				resource.valid = true; // valid now
				raja.store.set(resource.url, {
					data: body,
					headers: resource.headers,
					maxage: resource.maxage
				}, function(err) {
					if (err) return raja.error(err);
					if (!invalidate) return;
					msg.method = 'put';
					raja.send(msg);
				});
			}
			cb(null, resource);
		} else {
			console.error("Error while trying to fetch remote resource", code, resource.url);
		}
		poller.preloading = false;
		if (!poller.timeout && resource.maxage < Infinity) {
			poller.timeout = setTimeout(function(resource, poller) {
				delete poller.timeout;
				if (poller.preload) {
					this.load(resource, poller);
				}	else if (resource.valid && !foreign) {
					raja.store.invalidate(resource.url, function(err) {
						if (err) return raja.error(err);
						// force parents to update on demand
						raja.send({ url: resource.url, mtime: new Date(), method: 'put' });
					});
				}
			}.bind(this, resource, poller), resource.maxage * 1000);
		}
	}.bind(this));
}, function(resource) {
	return resource.url;
});

<|endoftext|>


<commit_before>'use strict';

const pokemonInfo = require('../../data/pokemon.json');
const CONSTANTS = require('./../constants');

const usage = 'Command usage: **!raid boss minutesRemaining [exgym] location details**';

//Format a date object as a string in 12 hour format
const format_time = (date_obj) => {
	// formats a javascript Date object into a 12h AM/PM time string
	var hour = date_obj.getHours();
	var minute = date_obj.getMinutes();
	const amPM = (hour > 11) ? 'pm' : 'am';
	if(hour > 12) {
		hour -= 12;
	} else if(hour === 0) {
		hour = '12';
	}
	if(minute < 10) {
		minute = '0' + minute;
	}
	return hour + ':' + minute + amPM;
};

const removeTags = (html) => {
	var oldHtml;
	do {
		oldHtml = html;
		html = html.replace(CONSTANTS.tagOrComment, '');
	} while (html !== oldHtml);
	return html.replace(/</g, '<');
};

const raid = (data, message) => {
	let reply = '';

	const msgSplit = message.content.toLowerCase().split(' ');
	if (!msgSplit || msgSplit.length < 4) {
		reply = 'Sorry, incorrect format.\n'+usage;
		message.channel.send(reply);
		return reply;
	}
	let boss = CONSTANTS.standardizePokemonName(msgSplit[1].toLowerCase());

	if (!pokemonInfo[boss.toUpperCase()]) {
		reply = 'Sorry, boss not found. Please make sure to type the exact name of the raid boss and DO NOT USE THE @ tag.\n'+usage;
		message.channel.send(reply);
		return reply;
	}

	var bossTag = boss; //generate a tag for the boss to alert users

	data.GUILD.roles.forEach((role) => {
		if (role.name === boss){
			bossTag = '<@&' + role.id + '>'; //if the boss name is found as a role, put in mention format
		}
		else if (boss.substring(0,3) === '<@&') {
			if (role.id === boss.substring(3,boss.length-4)) { //if the user already mentioned the boss, strip the @ so as to not notify additionally
				bossTag = role.name;
				boss = role.name;
			}
		}
	});

	var legendaryTag = '';
	if (CONSTANTS.LEGENDARYMONS.indexOf(boss) > -1) {
		if (data.rolesByName['legendary']) {
			legendaryTag = ' <@&' + data.rolesByName['legendary'].id + '> ';
		} else {
			legendaryTag = '';
			console.warn('Please create a role called legendary.'); //eslint-disable-line
		}
	}

	const channelName = message.channel.name;
	const minutesLeft = parseInt(msgSplit[2]);
	if (isNaN(minutesLeft) || minutesLeft < 1 || minutesLeft > 120) {
		reply = 'Raid not processed, ensure minutes remaining is a integer between 1 and 120.\n'+usage;
		message.channel.send(reply);
		return reply;
	}
	var date = new Date(); //get today's date/time
	date.setMinutes(date.getMinutes() + minutesLeft); //add minutes remaining to get end time

	var twelveHrDate = format_time(date); //calc the friendly 12h date string for the UI

	//clean the date variable into a UTC object compatible with mysql and discord. this may no longer be required
	/*date = date.getUTCFullYear() + '-' +
			('00' + (date.getUTCMonth() + 1)).slice(-2) + '-' +
			('00' + date.getUTCDate()).slice(-2) + ' ' +
			('00' + date.getUTCHours()).slice(-2) + ':' +
			('00' + date.getUTCMinutes()).slice(-2) + ':' +
			('00' + date.getUTCSeconds()).slice(-2);
	*/

	//'exgym' parameter checks and tag assignment
	//  This will NOT detect @exgym in the parameter string. Must implement check/correct similar to boss, if desired.
	var specialRaidTag = '';
	const keyWord = msgSplit[3].toLowerCase(); //get the fourth parameter to check for matching keyword
	if (CONSTANTS.SPECIALRAIDS.indexOf(keyWord) > -1) {
		if (data.rolesByName[keyWord]) {
			specialRaidTag = ' <@&' + data.rolesByName[keyWord].id + '> ';
		} else {
			specialRaidTag = '';
			console.warn('Please create a role called ' + keyword + '.'); //eslint-disable-line
		}
	}

	//location information of raid
	var keyWordLength = 0;
	if (specialRaidTag !== '') {
		keyWordLength = keyWord.length + 1;
	}
	var detail = msgSplit.slice(3).join(' ');
	detail = removeTags(detail).replace('\'', '\'\''); //sanitize html and format for insertion into sql;
	if (!detail) {
		reply = 'Raid not processed, no location details. Use format: **!raid boss minutesRemaining [sponsored] [park] location details**';
		message.channel.send(reply);
		return reply;
	}
	if (detail.length > 255) {
		detail = detail.substring(0,255);
	}

	//var sql = 'INSERT INTO raids (boss, channel, endTime, detail) VALUES (\'' + boss + '\', \'' + channelId + '\', \'' + date.toString() + '\', \'' + detail + '\');';
	//console.log(sql); //currently logging all sql to the console for testing purposes
	/* not connecting to the database for now
	db.query(sql, function(err, result) {
		if (err) {
			console.log(err + '\n' + sql);
			} else {
			message.channel.send('Processed Raid #' + result.insertId + ' as ' + bossTag + ' (ending: ' + twelveHrDate + ') at ' + detail + ' added by ' + message.member.displayName);
		}
	});
	*/
	reply = reply = data.getEmoji(boss) + bossTag + legendaryTag + ' raid reported to ' + data.channelsByName['gymraids_alerts'] + ' (ending: ' + twelveHrDate + ') at ' + '**' + detail + '**' + specialRaidTag +' added by ' + message.member.displayName;
	message.channel.send(reply);
	let forwardReply = '- ' + data.getEmoji(boss) + '**' + boss.toUpperCase() + '**' + ' raid reported in ' + data.channelsByName[channelName] + ' ending at ' + twelveHrDate + ' at ' + detail;
	//send alert to #gymraids_alerts channel
	if (data.channelsByName['gymraids_alerts']) {
		data.channelsByName['gymraids_alerts'].send(forwardReply);
	} else {
		console.warn('Please add a channel called #gymraids_alerts'); // eslint-disable-line
	}

	//send alert to regional alert channel
	message.channel.permissionOverwrites.forEach((role) => {
		if (role.type !== 'role') return;

		var roleName = data.GUILD.roles.get(role.id).name;
		// todo : get rid of SF reference
		if (CONSTANTS.REGIONS.indexOf(roleName) > -1 && roleName !== 'sf' && roleName !== 'allregions') {
			if (data.channelsByName['gymraids_' + roleName]) {
				data.channelsByName['gymraids_' + roleName].send(forwardReply);
			} else {
				console.warn('Please add the channel gymraids_' + roleName); // eslint-disable-line
			}
		}
	});

	return reply;
};

/*	else if (message.content.substring(0,8) == '!raidegg') {
 if (message.channel.id == CHANNEL_IDS['#gymraids-alerts'] || message.channel.id == CHANNEL_IDS['#gymraids-meetups']) {
 message.channel.send(message.member.displayName + ', raid commands should only be run in the corresponding neighborhood channel');
 return;
 }
 const tier = message.content.split(' ')[1];
 var tierNum = parseInt(tier);
 if (isNaN(tierNum)) {
 message.channel.send('Raid not processed, use format: !raidegg [tierNumber] [minutesUntilHatch] [location details]');
 return;
 }

 const channelId = message.channel.id;
 const minutesToStart = parseInt(message.content.split(' ')[2]);
 if (isNaN(minutesToStart)) {
 message.channel.send('Raid not processed, use format: !raidegg [tierNumber] [minutesUntilHatch] [location details]');
 return;
 }
 var date = new Date(); //get today's date/time
 date.setMinutes(date.getMinutes() + minutesToStart); //add minutes until start of raid to get start time

 var twelveHrDate = format_time(date); //format into a friendly 12h date format for the UI

 //may not be required, format date for mysql/discord
 date = date.getUTCFullYear() + '-' +
 ('00' + (date.getUTCMonth() + 1)).slice(-2) + '-' +
 ('00' + date.getUTCDate()).slice(-2) + ' ' +
 ('00' + date.getUTCHours()).slice(-2) + ':' +
 ('00' + date.getUTCMinutes()).slice(-2) + ':' +
 ('00' + date.getUTCSeconds()).slice(-2);

 //location information of pokemon raid
 var detail = message.content.substring(message.content.indexOf(minutesToStart.toString()) + minutesToStart.toString().length + 1);
 detail = removeTags(detail).replace('\'', '\'\''); //sanitize html and format for insertion into sql
 if (detail == null || detail == '') {
 message.channel.send('Raid not processed: use format: !raidegg [tierNumber] [minutesUntilHatch] [location details]');
 return;
 }
 if (detail.length > 255) {
 detail = detail.substring(0,255);
 }
 var sql = 'INSERT INTO raids (tier, boss, channel, endTime, detail) VALUES (\'' + tier + '\', \'egg\', \'' + channelId + '\', \'' + date.toString() + '\', \'' + detail + '\');';
 //console.log(sql); //currently logging all sql to the console for testing purposes
 /* pausing database activity for now
 db.query(sql, function(err, result) {
 if (err) {
 console.log(err + '\n' + sql);

 } else {
 message.channel.send('Processed Unhatched Raid #' + result.insertId + ' as Tier ' + tier + ' (cracking: ' + twelveHrDate + ') at ' + detail + ' added by ' + message.member.displayName);
 }

 });

 message.channel.send('Unhatched Raid reported to ' + client.channels.get(CHANNEL_IDS['#gymraids-alerts']) + ' as Tier ' + tier + ' (cracking: ' + twelveHrDate + ') at ' + detail + ' added by ' + message.member.displayName);
 //send alert to #gymraids-alerts channel
 client.channels.get(CHANNEL_IDS['#gymraids-alerts']).send('- ***Tier ' + tier + ' egg*** reported in ' + client.channels.get(channelId) + ' cracking at ' + twelveHrDate + ' at ' + detail);
 return;
 }*/

module.exports = (data) => ( (message) => {
	return raid(data, message);
});
<commit_msg>Update raid.js<commit_after>'use strict';

const pokemonInfo = require('../../data/pokemon.json');
const CONSTANTS = require('./../constants');

const usage = 'Command usage: **!raid boss minutesRemaining [exgym] location details**';

//Format a date object as a string in 12 hour format
const format_time = (date_obj) => {
	// formats a javascript Date object into a 12h AM/PM time string
	var hour = date_obj.getHours();
	var minute = date_obj.getMinutes();
	const amPM = (hour > 11) ? 'pm' : 'am';
	if(hour > 12) {
		hour -= 12;
	} else if(hour === 0) {
		hour = '12';
	}
	if(minute < 10) {
		minute = '0' + minute;
	}
	return hour + ':' + minute + amPM;
};

const removeTags = (html) => {
	var oldHtml;
	do {
		oldHtml = html;
		html = html.replace(CONSTANTS.tagOrComment, '');
	} while (html !== oldHtml);
	return html.replace(/</g, '<');
};

const raid = (data, message) => {
	let reply = '';

	const msgSplit = message.content.toLowerCase().split(' ');
	if (!msgSplit || msgSplit.length < 4) {
		reply = 'Sorry, incorrect format.\n'+usage;
		message.channel.send(reply);
		return reply;
	}
	let boss = CONSTANTS.standardizePokemonName(msgSplit[1].toLowerCase());

	if (!pokemonInfo[boss.toUpperCase()]) {
		reply = 'Sorry, boss not found. Please make sure to type the exact name of the raid boss and DO NOT USE THE @ tag.\n'+usage;
		message.channel.send(reply);
		return reply;
	}

	var bossTag = boss; //generate a tag for the boss to alert users

	data.GUILD.roles.forEach((role) => {
		if (role.name === boss){
			bossTag = '<@&' + role.id + '>'; //if the boss name is found as a role, put in mention format
		}
		else if (boss.substring(0,3) === '<@&') {
			if (role.id === boss.substring(3,boss.length-4)) { //if the user already mentioned the boss, strip the @ so as to not notify additionally
				bossTag = role.name;
				boss = role.name;
			}
		}
	});

	var legendaryTag = '';
	if (CONSTANTS.LEGENDARYMONS.indexOf(boss) > -1) {
		if (data.rolesByName['legendary']) {
			legendaryTag = ' <@&' + data.rolesByName['legendary'].id + '> ';
		} else {
			legendaryTag = '';
			console.warn('Please create a role called legendary.'); //eslint-disable-line
		}
	}

	const channelName = message.channel.name;
	const minutesLeft = parseInt(msgSplit[2]);
	if (isNaN(minutesLeft) || minutesLeft < 1 || minutesLeft > 120) {
		reply = 'Raid not processed, ensure minutes remaining is a integer between 1 and 120.\n'+usage;
		message.channel.send(reply);
		return reply;
	}
	var date = new Date(); //get today's date/time
	date.setMinutes(date.getMinutes() + minutesLeft); //add minutes remaining to get end time

	var twelveHrDate = format_time(date); //calc the friendly 12h date string for the UI

	//clean the date variable into a UTC object compatible with mysql and discord. this may no longer be required
	/*date = date.getUTCFullYear() + '-' +
			('00' + (date.getUTCMonth() + 1)).slice(-2) + '-' +
			('00' + date.getUTCDate()).slice(-2) + ' ' +
			('00' + date.getUTCHours()).slice(-2) + ':' +
			('00' + date.getUTCMinutes()).slice(-2) + ':' +
			('00' + date.getUTCSeconds()).slice(-2);
	*/

	//'exgym' parameter checks and tag assignment
	//  This will NOT detect @exgym in the parameter string. Must implement check/correct similar to boss, if desired.
	var specialRaidTag = '';
	const keyWord = msgSplit[3].toLowerCase(); //get the fourth parameter to check for matching keyword
	if (CONSTANTS.SPECIALRAIDS.indexOf(keyWord) > -1) {
		if (data.rolesByName[keyWord]) {
			specialRaidTag = ' <@&' + data.rolesByName[keyWord].id + '> ';
		} else {
			specialRaidTag = '';
			console.warn('Please create a role called ' + keyword + '.'); //eslint-disable-line
		}
	}

	//location information of raid
	var keyWordLength = 0;
	if (specialRaidTag !== '') {
		keyWordLength = keyWord.length + 1;
	}
	var detail = msgSplit.slice(3).join(' ');
	detail = removeTags(detail).replace('\'', '\'\''); //sanitize html and format for insertion into sql;
	if (!detail) {
		reply = 'Raid not processed, no location details. Use format: **!raid boss minutesRemaining [sponsored] [park] location details**';
		message.channel.send(reply);
		return reply;
	}
	if (detail.length > 255) {
		detail = detail.substring(0,255);
	}

	//var sql = 'INSERT INTO raids (boss, channel, endTime, detail) VALUES (\'' + boss + '\', \'' + channelId + '\', \'' + date.toString() + '\', \'' + detail + '\');';
	//console.log(sql); //currently logging all sql to the console for testing purposes
	/* not connecting to the database for now
	db.query(sql, function(err, result) {
		if (err) {
			console.log(err + '\n' + sql);
			} else {
			message.channel.send('Processed Raid #' + result.insertId + ' as ' + bossTag + ' (ending: ' + twelveHrDate + ') at ' + detail + ' added by ' + message.member.displayName);
		}
	});
	*/
	reply = reply = data.getEmoji(boss) + bossTag + legendaryTag + ' raid reported to ' + data.channelsByName['gymraids_alerts'] + ' (ending: ' + twelveHrDate + ') at ' + '**' + detail + '**' + specialRaidTag + ' added by ' + message.member.displayName;
	message.channel.send(reply);
	let forwardReply = '- ' + data.getEmoji(boss) + '**' + boss.toUpperCase() + '**' + ' raid reported in ' + data.channelsByName[channelName] + ' ending at ' + twelveHrDate + ' at ' + detail;
	//send alert to #gymraids_alerts channel
	if (data.channelsByName['gymraids_alerts']) {
		data.channelsByName['gymraids_alerts'].send(forwardReply);
	} else {
		console.warn('Please add a channel called #gymraids_alerts'); // eslint-disable-line
	}

	//send alert to regional alert channel
	message.channel.permissionOverwrites.forEach((role) => {
		if (role.type !== 'role') return;

		var roleName = data.GUILD.roles.get(role.id).name;
		// todo : get rid of SF reference
		if (CONSTANTS.REGIONS.indexOf(roleName) > -1 && roleName !== 'sf' && roleName !== 'allregions') {
			if (data.channelsByName['gymraids_' + roleName]) {
				data.channelsByName['gymraids_' + roleName].send(forwardReply);
			} else {
				console.warn('Please add the channel gymraids_' + roleName); // eslint-disable-line
			}
		}
	});

	return reply;
};

/*	else if (message.content.substring(0,8) == '!raidegg') {
 if (message.channel.id == CHANNEL_IDS['#gymraids-alerts'] || message.channel.id == CHANNEL_IDS['#gymraids-meetups']) {
 message.channel.send(message.member.displayName + ', raid commands should only be run in the corresponding neighborhood channel');
 return;
 }
 const tier = message.content.split(' ')[1];
 var tierNum = parseInt(tier);
 if (isNaN(tierNum)) {
 message.channel.send('Raid not processed, use format: !raidegg [tierNumber] [minutesUntilHatch] [location details]');
 return;
 }

 const channelId = message.channel.id;
 const minutesToStart = parseInt(message.content.split(' ')[2]);
 if (isNaN(minutesToStart)) {
 message.channel.send('Raid not processed, use format: !raidegg [tierNumber] [minutesUntilHatch] [location details]');
 return;
 }
 var date = new Date(); //get today's date/time
 date.setMinutes(date.getMinutes() + minutesToStart); //add minutes until start of raid to get start time

 var twelveHrDate = format_time(date); //format into a friendly 12h date format for the UI

 //may not be required, format date for mysql/discord
 date = date.getUTCFullYear() + '-' +
 ('00' + (date.getUTCMonth() + 1)).slice(-2) + '-' +
 ('00' + date.getUTCDate()).slice(-2) + ' ' +
 ('00' + date.getUTCHours()).slice(-2) + ':' +
 ('00' + date.getUTCMinutes()).slice(-2) + ':' +
 ('00' + date.getUTCSeconds()).slice(-2);

 //location information of pokemon raid
 var detail = message.content.substring(message.content.indexOf(minutesToStart.toString()) + minutesToStart.toString().length + 1);
 detail = removeTags(detail).replace('\'', '\'\''); //sanitize html and format for insertion into sql
 if (detail == null || detail == '') {
 message.channel.send('Raid not processed: use format: !raidegg [tierNumber] [minutesUntilHatch] [location details]');
 return;
 }
 if (detail.length > 255) {
 detail = detail.substring(0,255);
 }
 var sql = 'INSERT INTO raids (tier, boss, channel, endTime, detail) VALUES (\'' + tier + '\', \'egg\', \'' + channelId + '\', \'' + date.toString() + '\', \'' + detail + '\');';
 //console.log(sql); //currently logging all sql to the console for testing purposes
 /* pausing database activity for now
 db.query(sql, function(err, result) {
 if (err) {
 console.log(err + '\n' + sql);

 } else {
 message.channel.send('Processed Unhatched Raid #' + result.insertId + ' as Tier ' + tier + ' (cracking: ' + twelveHrDate + ') at ' + detail + ' added by ' + message.member.displayName);
 }

 });

 message.channel.send('Unhatched Raid reported to ' + client.channels.get(CHANNEL_IDS['#gymraids-alerts']) + ' as Tier ' + tier + ' (cracking: ' + twelveHrDate + ') at ' + detail + ' added by ' + message.member.displayName);
 //send alert to #gymraids-alerts channel
 client.channels.get(CHANNEL_IDS['#gymraids-alerts']).send('- ***Tier ' + tier + ' egg*** reported in ' + client.channels.get(channelId) + ' cracking at ' + twelveHrDate + ' at ' + detail);
 return;
 }*/

module.exports = (data) => ( (message) => {
	return raid(data, message);
});
<|endoftext|>


<commit_before>define(function (require) {
	var THREE = require("THREE");
	var PLAYER = require("player/playerSize");
	var EntityState = require("./entityState");

	return function PlayerEntity() {
		var self = this;

		self.pos = function () {
			return state.pos;
		};

		self.look = function () {
			return state.look;
		};

		self.health = function () {
			return state.health;
		};

		self.vy = function () {
			return state.vy;
		};

		self.contains = function (x, y, z) {
			var box = new Box(pos, PLAYER.HALF_EXTENTS, PLAYER.CENTER_OFFSET);
			return box.contains(x, y, z);
		};

		self.addTo = function (scene) {
			scene.add(entityMesh);
		};

		self.removeFrom = function (scene) {
			scene.remove(entityMesh);
		};

		var UIViews = [];
		self.add = function (view) {
			UIViews.push(view);
			view.meshes().forEach(entityMesh.add.bind(entityMesh));
		}

		var state = new EntityState();

		var entityMesh = new THREE.Object3D();

		self.update = function (newState, clock) {
			state = newState;

			var pos = self.pos();
			var look = self.look();

			var co = PLAYER.CENTER_OFFSET;
			var c = new THREE.Vector3(
				pos.x + co.x,
				pos.y + co.y,
				pos.z + co.z
			);
			entityMesh.position.set(c.x, c.y, c.z);

			function lookAt(obj, pos, x, y, z) {
				var target = new THREE.Vector3(
					pos.x + x,
					pos.y + y,
					pos.z + z
				);
				obj.lookAt(target);
			}
			lookAt(entityMesh, c, look.x, 0, look.z);

			for (var i = 0; i < UIViews.length; i++) {
				UIViews[i].update(self, clock);
			}
		}

		// Utils
		// Clamp n between [a, b]. Behaviour is
		// undefined if a > b.
		function clamp(n, a, b) {
			return n < a ? a : n > b ? b : n;
		}
		// Return the sign of n, -1, 1, or 0.
		function signum(n) {
			return n < 0 ? -1 : n > 0 ? 1 : 0;
		}
	}
});
<commit_msg>UIViews -> uIViews<commit_after>define(function (require) {
	var THREE = require("THREE");
	var PLAYER = require("player/playerSize");
	var EntityState = require("./entityState");

	return function PlayerEntity() {
		var self = this;

		self.pos = function () {
			return state.pos;
		};

		self.look = function () {
			return state.look;
		};

		self.health = function () {
			return state.health;
		};

		self.vy = function () {
			return state.vy;
		};

		self.contains = function (x, y, z) {
			var box = new Box(pos, PLAYER.HALF_EXTENTS, PLAYER.CENTER_OFFSET);
			return box.contains(x, y, z);
		};

		self.addTo = function (scene) {
			scene.add(entityMesh);
		};

		self.removeFrom = function (scene) {
			scene.remove(entityMesh);
		};

		var uIViews = [];
		self.add = function (view) {
			uIViews.push(view);
			view.meshes().forEach(entityMesh.add.bind(entityMesh));
		}

		var state = new EntityState();

		var entityMesh = new THREE.Object3D();

		self.update = function (newState, clock) {
			state = newState;

			var pos = self.pos();
			var look = self.look();

			var co = PLAYER.CENTER_OFFSET;
			var c = new THREE.Vector3(
				pos.x + co.x,
				pos.y + co.y,
				pos.z + co.z
			);
			entityMesh.position.set(c.x, c.y, c.z);

			function lookAt(obj, pos, x, y, z) {
				var target = new THREE.Vector3(
					pos.x + x,
					pos.y + y,
					pos.z + z
				);
				obj.lookAt(target);
			}
			lookAt(entityMesh, c, look.x, 0, look.z);

			for (var i = 0; i < UIViews.length; i++) {
				UIViews[i].update(self, clock);
			}
		}

		// Utils
		// Clamp n between [a, b]. Behaviour is
		// undefined if a > b.
		function clamp(n, a, b) {
			return n < a ? a : n > b ? b : n;
		}
		// Return the sign of n, -1, 1, or 0.
		function signum(n) {
			return n < 0 ? -1 : n > 0 ? 1 : 0;
		}
	}
});
<|endoftext|>


<commit_before>"use strict";

const parseStyle = require("./ircmessageparser/parseStyle");
const findChannels = require("./ircmessageparser/findChannels");
const findLinks = require("./ircmessageparser/findLinks");
const findEmoji = require("./ircmessageparser/findEmoji");
const findNames = require("./ircmessageparser/findNames");
const merge = require("./ircmessageparser/merge");
const colorClass = require("./colorClass");
const emojiMap = require("../fullnamemap.json");
const LinkPreviewToggle = require("../../../components/LinkPreviewToggle.vue").default;

// Create an HTML `span` with styling information for a given fragment
function createFragment(fragment, createElement) {
	const classes = [];

	if (fragment.bold) {
		classes.push("irc-bold");
	}

	if (fragment.textColor !== undefined) {
		classes.push("irc-fg" + fragment.textColor);
	}

	if (fragment.bgColor !== undefined) {
		classes.push("irc-bg" + fragment.bgColor);
	}

	if (fragment.italic) {
		classes.push("irc-italic");
	}

	if (fragment.underline) {
		classes.push("irc-underline");
	}

	if (fragment.strikethrough) {
		classes.push("irc-strikethrough");
	}

	if (fragment.monospace) {
		classes.push("irc-monospace");
	}

	if (classes.length === 0 && !fragment.hexColor) {
		return fragment.text;
	}

	return createElement("span", {
		class: classes,
		style: {
			"color": `#${fragment.hexColor}`,
			"background-color": fragment.hexBgColor ? `#${fragment.hexBgColor}` : null,
		},
	}, fragment.text);
}

// Transform an IRC message potentially filled with styling control codes, URLs,
// nicknames, and channels into a string of HTML elements to display on the client.
module.exports = function parse(createElement, text, message = undefined, network = undefined) {
	// Extract the styling information and get the plain text version from it
	const styleFragments = parseStyle(text);
	const cleanText = styleFragments.map((fragment) => fragment.text).join("");

	// On the plain text, find channels and URLs, returned as "parts". Parts are
	// arrays of objects containing start and end markers, as well as metadata
	// depending on what was found (channel or link).
	const channelPrefixes = network ? network.serverOptions.CHANTYPES : ["#", "&"];
	const userModes = network ? network.serverOptions.PREFIX : ["!", "@", "%", "+"];
	const channelParts = findChannels(cleanText, channelPrefixes, userModes);
	const linkParts = findLinks(cleanText);
	const emojiParts = findEmoji(cleanText);
	const nameParts = findNames(cleanText, message ? (message.users || []) : []);

	const parts = channelParts
		.concat(linkParts)
		.concat(emojiParts)
		.concat(nameParts);

	// Merge the styling information with the channels / URLs / nicks / text objects and
	// generate HTML strings with the resulting fragments
	return merge(parts, styleFragments, cleanText).map((textPart) => {
		const fragments = textPart.fragments.map((fragment) => createFragment(fragment, createElement));

		// Wrap these potentially styled fragments with links and channel buttons
		if (textPart.link) {
			const preview = message && message.previews.find((p) => p.link === textPart.link);
			const link = createElement("a", {
				attrs: {
					href: textPart.link,
					target: "_blank",
					rel: "noopener",
				},
			}, fragments);

			if (!preview) {
				return link;
			}

			return [link, createElement(LinkPreviewToggle, {
				class: ["toggle-button", "toggle-preview"],
				props: {
					link: preview,
				},
			}, fragments)];
		} else if (textPart.channel) {
			return createElement("span", {
				class: [
					"inline-channel",
				],
				attrs: {
					"role": "button",
					"tabindex": 0,
					"data-chan": textPart.channel,
				},
			}, fragments);
		} else if (textPart.emoji) {
			const title = emojiMap[textPart.emoji] ? `Emoji: ${emojiMap[textPart.emoji]}` : null;

			return createElement("span", {
				class: [
					"emoji",
				],
				attrs: {
					"role": "img",
					"aria-label": title,
					"title": title,
				},
			}, fragments);
		} else if (textPart.nick) {
			return createElement("span", {
				class: [
					"user",
					colorClass(textPart.nick),
				],
				attrs: {
					"role": "button",
					"data-name": textPart.nick,
				},
			}, fragments);
		}

		return fragments;
	});
};
<commit_msg>Fix up how span elements are generated in message parser<commit_after>"use strict";

const parseStyle = require("./ircmessageparser/parseStyle");
const findChannels = require("./ircmessageparser/findChannels");
const findLinks = require("./ircmessageparser/findLinks");
const findEmoji = require("./ircmessageparser/findEmoji");
const findNames = require("./ircmessageparser/findNames");
const merge = require("./ircmessageparser/merge");
const colorClass = require("./colorClass");
const emojiMap = require("../fullnamemap.json");
const LinkPreviewToggle = require("../../../components/LinkPreviewToggle.vue").default;

// Create an HTML `span` with styling information for a given fragment
function createFragment(fragment, createElement) {
	const classes = [];

	if (fragment.bold) {
		classes.push("irc-bold");
	}

	if (fragment.textColor !== undefined) {
		classes.push("irc-fg" + fragment.textColor);
	}

	if (fragment.bgColor !== undefined) {
		classes.push("irc-bg" + fragment.bgColor);
	}

	if (fragment.italic) {
		classes.push("irc-italic");
	}

	if (fragment.underline) {
		classes.push("irc-underline");
	}

	if (fragment.strikethrough) {
		classes.push("irc-strikethrough");
	}

	if (fragment.monospace) {
		classes.push("irc-monospace");
	}

	const data = {};
	let hasData = false;

	if (classes.length > 0) {
		hasData = true;
		data.class = classes;
	}

	if (fragment.hexColor) {
		hasData = true;
		data.style = {
			color: `#${fragment.hexColor}`,
		};

		if (fragment.hexBgColor) {
			data.style["background-color"] = `#${fragment.hexBgColor}`;
		}
	}

	return hasData ? createElement("span", data, fragment.text) : fragment.text;
}

// Transform an IRC message potentially filled with styling control codes, URLs,
// nicknames, and channels into a string of HTML elements to display on the client.
module.exports = function parse(createElement, text, message = undefined, network = undefined) {
	// Extract the styling information and get the plain text version from it
	const styleFragments = parseStyle(text);
	const cleanText = styleFragments.map((fragment) => fragment.text).join("");

	// On the plain text, find channels and URLs, returned as "parts". Parts are
	// arrays of objects containing start and end markers, as well as metadata
	// depending on what was found (channel or link).
	const channelPrefixes = network ? network.serverOptions.CHANTYPES : ["#", "&"];
	const userModes = network ? network.serverOptions.PREFIX : ["!", "@", "%", "+"];
	const channelParts = findChannels(cleanText, channelPrefixes, userModes);
	const linkParts = findLinks(cleanText);
	const emojiParts = findEmoji(cleanText);
	const nameParts = findNames(cleanText, message ? (message.users || []) : []);

	const parts = channelParts
		.concat(linkParts)
		.concat(emojiParts)
		.concat(nameParts);

	// Merge the styling information with the channels / URLs / nicks / text objects and
	// generate HTML strings with the resulting fragments
	return merge(parts, styleFragments, cleanText).map((textPart) => {
		const fragments = textPart.fragments.map((fragment) => createFragment(fragment, createElement));

		// Wrap these potentially styled fragments with links and channel buttons
		if (textPart.link) {
			const preview = message && message.previews.find((p) => p.link === textPart.link);
			const link = createElement("a", {
				attrs: {
					href: textPart.link,
					target: "_blank",
					rel: "noopener",
				},
			}, fragments);

			if (!preview) {
				return link;
			}

			return [link, createElement(LinkPreviewToggle, {
				class: ["toggle-button", "toggle-preview"],
				props: {
					link: preview,
				},
			}, fragments)];
		} else if (textPart.channel) {
			return createElement("span", {
				class: [
					"inline-channel",
				],
				attrs: {
					"role": "button",
					"tabindex": 0,
					"data-chan": textPart.channel,
				},
			}, fragments);
		} else if (textPart.emoji) {
			const title = emojiMap[textPart.emoji] ? `Emoji: ${emojiMap[textPart.emoji]}` : null;

			return createElement("span", {
				class: [
					"emoji",
				],
				attrs: {
					"role": "img",
					"aria-label": title,
					"title": title,
				},
			}, fragments);
		} else if (textPart.nick) {
			return createElement("span", {
				class: [
					"user",
					colorClass(textPart.nick),
				],
				attrs: {
					"role": "button",
					"data-name": textPart.nick,
				},
			}, fragments);
		}

		return fragments;
	});
};
<|endoftext|>


<commit_before>
"use strict";

import {ListController} from '../controllers/ListController';
import {CrudController} from '../controllers/CrudController';
import {Navigation} from '../services/Navigation';

let nav = new Navigation();
let defaults = {
    list: {
        options: {
            controller: ListController,
            controllerAs: 'list',
            templateUrl: '../monad/templates/list.html'
        }
    },
    crud: {
        options: {
            controller: CrudController,
            controllerAs: 'crud'
        }
    }
};
let interfacer = angular.module('monad.interface', []);

class Component {

    constructor(name, dependencies = [], configFn = undefined) {
        this.paths = {};
        this.name = name;
        this.$manager = undefined;
        this.dependencies = dependencies;
        this.configFn = configFn;
        this.queued = [];
        this.$bootstrapped = false;
        this.defaults = angular.extend({}, defaults);
        this.settings = {};

        for (let prop in interfacer) {
            if (typeof interfacer[prop] == 'function') {
                this[prop] = (...args) => {
                    this.queued.push([prop].concat(args));
                    return this;
                };
            }
        }
    }

    bootstrap() {
        if (this.$bootstrapped) {
            return;
        }
        this.$bootstrapped = true;
        let deps = [];
        this.dependencies.map(dep => {
            if (typeof dep == 'string' && monad.exists(dep)) {
                dep = monad.component(dep);
            }
            if (typeof dep == 'object' && dep instanceof Component) {
                dep.bootstrap();
                deps.push(dep.name);
            } else {
                deps.push(dep);
            }
        });
        this.ngmod = angular.module(this.name, deps, this.configFn);
        this.queued.map(proxy => {
            let fn = proxy.shift();
            if (typeof fn == 'string') {
                this.ngmod[fn](...proxy);
            } else {
                fn.apply(this, proxy);
            }
        });
    }

    extend(component) {
        if (typeof component == 'string') {
            if (monad.exists(component)) {
                component = monad.component(component);
            } else {
                throw `Component ${component} is undefined and cannot be extended upon.`;
            }
        }
        this.defaults = angular.extend({}, defaults, component.defaults, this.defaults)
    }

    list(url, options = {}, resolve = {}) {
        // Defaults for options:
        delete options.template; // Don't do this.

        // Defaults for resolve:
        resolve.Manager = resolve.Manager || [normalize(this.name) + 'Manager', Manager => Manager];

        // It's easier if we can specify 'columns' on the options:
        if ('columns' in options) {
            let columns = options.columns;
            resolve.columns = () => columns;
            delete options.columns;
        }

        if (!('menu' in options) || options.menu) {
            nav.register(options.menu || 'main', '/:language' + url, 'monad.navigation.' + normalize(this.name, '.$1'));
        }
        delete(options.menu);

        this.settings.list = {url, options, resolve};
        this.queued.push([addTarget, 'list']);
        return this;
    }

    update(url, options = {}, resolve = {}) {
        // Defaults for options:
        options.templateUrl = options.templateUrl || this.name + '/schema.html';
        delete options.template; // Don't do this.

        // Defaults for resolve:
        resolve.Manager = resolve.Manager || [normalize(this.name) + 'Manager', Manager => Manager];

        this.settings.update = {url, options, resolve};
        this.queued.push([addTarget, 'update']);
        return this;
    }

    manager(Manager) {
        this.$manager = normalize(this.name) + 'Manager';
        this.service(this.$manager, Manager);
        return this;
    }

};

/**
 * Private helper-functions:
 * {{{
 */
function addTarget(type) {
    let settings = angular.extend({}, this.defaults[type], this.settings[type]);
    settings.resolve = settings.resolve || {};
    settings.resolve.module = () => this.name;
    settings.options.resolve = settings.resolve;
    this.ngmod.config(['$routeProvider', '$translatePartialLoaderProvider', ($routeProvider, $translatePartialLoaderProvider) => {
        $routeProvider.when('/:language' + settings.url, settings.options);
        $translatePartialLoaderProvider.addPart(this.name);
    }]);
};

function normalize(name, replace = undefined) {
    if (replace == undefined) {
        replace = match => match.substring(1).toUpperCase();
    }
    return name.replace(/\/(\w)/g, replace);
};
/** }}} */

export {Component};

<commit_msg>add a custom merge function, angular 1.3 does not support it yet<commit_after>
"use strict";

import {ListController} from '../controllers/ListController';
import {CrudController} from '../controllers/CrudController';
import {Navigation} from '../services/Navigation';

let nav = new Navigation();
let defaults = {
    list: {
        options: {
            controller: ListController,
            controllerAs: 'list',
            templateUrl: '../monad/templates/list.html'
        }
    },
    crud: {
        options: {
            controller: CrudController,
            controllerAs: 'crud'
        }
    }
};
let interfacer = angular.module('monad.interface', []);

class Component {

    constructor(name, dependencies = [], configFn = undefined) {
        this.paths = {};
        this.name = name;
        this.$manager = undefined;
        this.dependencies = dependencies;
        this.configFn = configFn;
        this.queued = [];
        this.$bootstrapped = false;
        this.defaults = angular.extend({}, defaults);
        this.settings = {};

        for (let prop in interfacer) {
            if (typeof interfacer[prop] == 'function') {
                this[prop] = (...args) => {
                    this.queued.push([prop].concat(args));
                    return this;
                };
            }
        }
    }

    bootstrap() {
        if (this.$bootstrapped) {
            return;
        }
        this.$bootstrapped = true;
        let deps = [];
        this.dependencies.map(dep => {
            if (typeof dep == 'string' && monad.exists(dep)) {
                dep = monad.component(dep);
            }
            if (typeof dep == 'object' && dep instanceof Component) {
                dep.bootstrap();
                deps.push(dep.name);
            } else {
                deps.push(dep);
            }
        });
        this.ngmod = angular.module(this.name, deps, this.configFn);
        this.queued.map(proxy => {
            let fn = proxy.shift();
            if (typeof fn == 'string') {
                this.ngmod[fn](...proxy);
            } else {
                fn.apply(this, proxy);
            }
        });
    }

    extend(component) {
        if (typeof component == 'string') {
            if (monad.exists(component)) {
                component = monad.component(component);
            } else {
                throw `Component ${component} is undefined and cannot be extended upon.`;
            }
        }
        this.defaults = angular.extend({}, defaults, component.defaults, this.defaults)
    }

    list(url, options = {}, resolve = {}) {
        // Defaults for options:
        delete options.template; // Don't do this.

        // Defaults for resolve:
        resolve.Manager = resolve.Manager || [normalize(this.name) + 'Manager', Manager => Manager];

        // It's easier if we can specify 'columns' on the options:
        if ('columns' in options) {
            let columns = options.columns;
            resolve.columns = () => columns;
            delete options.columns;
        }

        if (!('menu' in options) || options.menu) {
            nav.register(options.menu || 'main', '/:language' + url, 'monad.navigation.' + normalize(this.name, '.$1'));
        }
        delete(options.menu);

        this.settings.list = {url, options, resolve};
        this.queued.push([addTarget, 'list']);
        return this;
    }

    update(url, options = {}, resolve = {}) {
        // Defaults for options:
        options.templateUrl = options.templateUrl || this.name + '/schema.html';
        delete options.template; // Don't do this.

        // Defaults for resolve:
        resolve.Manager = resolve.Manager || [normalize(this.name) + 'Manager', Manager => Manager];

        this.settings.update = {url, options, resolve};
        this.queued.push([addTarget, 'update']);
        return this;
    }

    manager(Manager) {
        this.$manager = normalize(this.name) + 'Manager';
        this.service(this.$manager, Manager);
        return this;
    }

};

/**
 * Private helper-functions:
 * {{{
 */
function addTarget(type) {
    let settings = merge(this.defaults[type], this.settings[type]);
    settings.resolve = settings.resolve || {};
    settings.resolve.module = () => this.name;
    settings.options.resolve = settings.resolve;
    this.ngmod.config(['$routeProvider', '$translatePartialLoaderProvider', ($routeProvider, $translatePartialLoaderProvider) => {
        $routeProvider.when('/:language' + settings.url, settings.options);
        $translatePartialLoaderProvider.addPart(this.name);
    }]);
};

function normalize(name, replace = undefined) {
    if (replace == undefined) {
        replace = match => match.substring(1).toUpperCase();
    }
    return name.replace(/\/(\w)/g, replace);
};

function merge(...args) {
    let merged = {};
    args.map(arg => {
        for (let prop in arg) {
            if (!(prop in merged)) {
                merged[prop] = arg[prop];
                continue;
            }
            if (typeof merged[prop] != typeof arg[prop]) {
                merged[prop] = arg[prop];
                continue;
            }
            if (angular.isArray(merged[prop]) != angular.isArray(arg[prop])) {
                merged[prop] = arg[prop];
                continue;
            }
            if (angular.isArray(merged[prop]) && angular.isArray(arg[prop])) {
                arg[prop].map(elem => {
                    if (merged[prop].indexOf(elem) == -1) {
                        merged[prop].push(elem);
                    }
                });
                continue;
            }
            if (typeof arg[prop] != 'object') {
                merged[prop] = arg[prop];
                continue;
            }
            merged[prop] = merge(merged[prop], arg[prop]);
        }
    });
    return merged;
};

/** }}} */

export {Component};

<|endoftext|>


<commit_before><commit_msg>removed red arrows<commit_after><|endoftext|>


<commit_before>import layoutsIncluded from '../layouts-included';
import { LAYOUT_CHANGE, CMD_VIEW, SUB_LAYOUT, SUBLAYOUT_CHANGE } from 'constants';
import config from 'config/config';

const initialState = {
    current: config.backendLayouts ? null : "layout1",
    loaded: {
      ...layoutsIncluded,
    },
    sublayout: {},
    currentView: null,
    currentSublayout: null
};

export default function reducer( state = initialState, action ) {
  switch ( action.type ) {

    case LAYOUT_CHANGE:

      const loaded = state.loaded;

      if ( !config.backendLayouts ) {
        return {
         ...state,
         current: action.payload.code
        };
      }

      if (action.payload.data) {
        loaded[action.payload.code] = action.payload.data;
      }

      return {
        ...state,
        current: action.payload.code,
        loaded
      };

    case CMD_VIEW:

        const newLayoutCode = action.payload.code;
        if(newLayoutCode) {
            return {
                ...state,
                currentView: {
                    code: newLayoutCode,
                    dataCode: action.payload.root
                },
                currentSublayout: null
            };
        }

    case SUBLAYOUT_CHANGE:

        const newSublayoutCode = action.payload.code;
        const newSublayout = action.payload.layout;
        if(newSublayoutCode) {
            return {
                ...state,
                currentView: null,
                currentSublayout: {
                    code: newSublayoutCode,
                    layout: [newSublayout]
                }
            }
        }

    case SUB_LAYOUT:

        let sublayout_code = action.payload.code;
        let layout = action.payload.items;
        if(sublayout_code && layout) {
            return {
                ...state,
                sublayout: {
                    ...state.sublayout,
                    [sublayout_code]: {
                        layout: [layout]
                    }
                }
            };
        }

    default:
      return state;
  }
}
<commit_msg>update<commit_after>import layoutsIncluded from '../layouts-included';
import { LAYOUT_CHANGE, CMD_VIEW, SUB_LAYOUT, SUBLAYOUT_CHANGE } from 'constants';
import config from 'config/config';

const initialState = {
    current: config.backendLayouts ? null : "layout1",
    loaded: {
      ...layoutsIncluded,
    },
    sublayout: {},
    currentView: null,
    currentSublayout: null
};

export default function reducer( state = initialState, action ) {
  switch ( action.type ) {

    case LAYOUT_CHANGE:

      const loaded = state.loaded;

      if ( !config.backendLayouts ) {
        return {
         ...state,
         current: action.payload.code
        };
      }

      if (action.payload.data) {
        loaded[action.payload.code] = action.payload.data;
      }

      return {
        ...state,
        current: action.payload.code,
        loaded
      };

    case CMD_VIEW:

        const newLayoutCode = action.payload.code;
        if(newLayoutCode) {
            return {
                ...state,
                currentView: {
                    code: newLayoutCode,
                    dataCode: action.payload.root
                },
                currentSublayout: null
            };
        }

    case SUBLAYOUT_CHANGE:

        const newSublayoutCode = action.payload.code;
        const newSublayout = action.payload.items;
        if(newSublayoutCode) {
            return {
                ...state,
                currentView: null,
                currentSublayout: {
                    code: newSublayoutCode,
                    layout: [newSublayout]
                }
            }
        }

    case SUB_LAYOUT:

        let sublayout_code = action.payload.code;
        let layout = action.payload.items;
        if(sublayout_code && layout) {
            return {
                ...state,
                sublayout: {
                    ...state.sublayout,
                    [sublayout_code]: {
                        layout: [layout]
                    }
                }
            };
        }

    default:
      return state;
  }
}
<|endoftext|>


<commit_before><commit_msg>workaround for Chrome promise bug<commit_after><|endoftext|>


<commit_before>import Client from 'jsonrpc-websocket-client'
import eventHub from '../eventHub'

export default {
  install (Vue, options) {
    let url = options.url
    let client = new Client(url)

    Vue.prototype.$clientcall = function (path, args) {
      // console.log(path, args, client.status)
      if (client.status === 'closed') { // TODO handle 'connecting' status
        return client.open().then(() => {
          return client.call(path, args).catch((err) => {
            eventHub.$emit('clienterror', err)
          })
        })
      } else {
        return client.call(path, args).catch((err) => {
          eventHub.$emit('clienterror', err)
        })
      }
    }
  }

}
<commit_msg>Hack on client to retry on fail<commit_after>import Client from 'jsonrpc-websocket-client'
import eventHub from '../eventHub'

export default {
  install (Vue, options) {
    let url = options.url
    let client = new Client(url)

    Vue.prototype.$clientcall = function (path, args) {
      let prm = new Promise((resolve, reject) => {
        if (client.status === 'closed') { // TODO handle 'connecting' status
          client.open().then(() => {
            client.call(path, args).then((result) => {
              resolve(result)
            }, (err) => {
              console.log('Error while doing request but keep retrying', err)
              client.call(path, args).then((result) => {
                resolve(result)
              }, (err) => {
                eventHub.$emit('clienterror', err)
              })
            })
          })
        } else {
          client.call(path, args).then((result) => {
            resolve(result)
          }, (err) => {
            console.log('Error while doing request but keep retrying', err)
            client.open().then(() => {
              client.call(path, args).then((result) => {
                resolve(result)
              }, (err) => {
                eventHub.$emit('clienterror', err)
              })
            })
          })
        }
      })
      return prm
    }
  }

}
<|endoftext|>


<commit_before><commit_msg>Update horoscope.js<commit_after><|endoftext|>


<commit_before>var React = require('react'),
	Field = require('../Field');

// Scope jQuery and the bootstrap-markdown editor so it will mount
var $ = require('jquery');
require('./lib/bootstrap-markdown');

module.exports = Field.create({

	displayName: 'MarkdownField',

	componentDidMount: function() {
		var markdownOptions = {
			autofocus: false,
			savable: false,
			additionalButtons: this.buttonsToAdd(),
			resize: 'vertical',
			reorderButtonGroups: ['groupFont', 'groupHeaders', 'groupLink', 'groupMisc', 'groupUtil']
		};

		// only have access to `refs` during componentDidMount
		$(this.refs.markdownTextarea.getDOMNode()).markdown(markdownOptions);
	},

	// Add Heading buttons
	buttonsToAdd: function() {
		// Append/remove ### surround the selection
		// Source: https://github.com/toopay/bootstrap-markdown/blob/master/js/bootstrap-markdown.js#L909
		var headingCallback = function (e, hType) {
			var chunk, cursor, selected = e.getSelection(), content = e.getContent(), pointer, prevChar;

			if (selected.length == 0) {
				// Give extra word
				chunk = e.__localize('heading text');
			} else {
				chunk = selected.text + '\n';
			}

			// transform selection and set the cursor into chunked text
			if ((pointer = hType.length+1, content.substr(selected.start-pointer,pointer) == hType+' ')
				|| (pointer = hType.length, content.substr(selected.start-pointer,pointer) == hType)) {
				e.setSelection(selected.start-pointer,selected.end);
				e.replaceSelection(chunk);
				cursor = selected.start-pointer;
			} else if (selected.start > 0 && (prevChar = content.substr(selected.start-1,1), !!prevChar && prevChar != '\n')) {
				e.replaceSelection('\n\n'+hType+' '+chunk);
				cursor = selected.start+hType.length+3;
			} else {
				// Empty string before element
				e.replaceSelection(hType+' '+chunk);
				cursor = selected.start+hType.length+1;
			}

			// Set the cursor
			e.setSelection(cursor,cursor+chunk.length);
		};

		return [{
			name: 'groupHeaders',
			data: [{
				name: 'cmdH1',
				title: 'Heading 1',
				btnText: 'H1',
				callback: function(e){
					headingCallback(e, '#');
				}
			},{
				name: 'cmdH2',
				title: 'Heading 2',
				btnText: 'H2',
				callback: function(e){
					headingCallback(e, '##');
				}
			},{
				name: 'cmdH3',
				title: 'Heading 3',
				btnText: 'H3',
				callback: function(e){
					headingCallback(e, '###');
				}
			},{
				name: 'cmdH4',
				title: 'Heading 4',
				btnText: 'H4',
				callback: function(e){
					headingCallback(e, '####');
				}
			}]
		}];
	},

	renderField: function() {
		var styles = {
			padding: 8
		};
		return (

				<textarea name={this.props.paths.md} style={styles} defaultValue={this.props.value.md} ref="markdownTextarea" className="form-control markdown code"></textarea>

		);
	}

});
<commit_msg>Override shouldCollapse for Markdown fields<commit_after>var React = require('react'),
	Field = require('../Field');

// Scope jQuery and the bootstrap-markdown editor so it will mount
var $ = require('jquery');
require('./lib/bootstrap-markdown');

module.exports = Field.create({

	displayName: 'MarkdownField',

	shouldCollapse : function() {
		return this.props.collapse && !this.props.value.md;
	},

	componentDidMount: function() {
		var markdownOptions = {
			autofocus: false,
			savable: false,
			additionalButtons: this.buttonsToAdd(),
			resize: 'vertical',
			reorderButtonGroups: ['groupFont', 'groupHeaders', 'groupLink', 'groupMisc', 'groupUtil']
		};

		// only have access to `refs` during componentDidMount
		$(this.refs.markdownTextarea.getDOMNode()).markdown(markdownOptions);
	},

	// Add Heading buttons
	buttonsToAdd: function() {
		// Append/remove ### surround the selection
		// Source: https://github.com/toopay/bootstrap-markdown/blob/master/js/bootstrap-markdown.js#L909
		var headingCallback = function (e, hType) {
			var chunk, cursor, selected = e.getSelection(), content = e.getContent(), pointer, prevChar;

			if (selected.length == 0) {
				// Give extra word
				chunk = e.__localize('heading text');
			} else {
				chunk = selected.text + '\n';
			}

			// transform selection and set the cursor into chunked text
			if ((pointer = hType.length+1, content.substr(selected.start-pointer,pointer) == hType+' ')
				|| (pointer = hType.length, content.substr(selected.start-pointer,pointer) == hType)) {
				e.setSelection(selected.start-pointer,selected.end);
				e.replaceSelection(chunk);
				cursor = selected.start-pointer;
			} else if (selected.start > 0 && (prevChar = content.substr(selected.start-1,1), !!prevChar && prevChar != '\n')) {
				e.replaceSelection('\n\n'+hType+' '+chunk);
				cursor = selected.start+hType.length+3;
			} else {
				// Empty string before element
				e.replaceSelection(hType+' '+chunk);
				cursor = selected.start+hType.length+1;
			}

			// Set the cursor
			e.setSelection(cursor,cursor+chunk.length);
		};

		return [{
			name: 'groupHeaders',
			data: [{
				name: 'cmdH1',
				title: 'Heading 1',
				btnText: 'H1',
				callback: function(e){
					headingCallback(e, '#');
				}
			},{
				name: 'cmdH2',
				title: 'Heading 2',
				btnText: 'H2',
				callback: function(e){
					headingCallback(e, '##');
				}
			},{
				name: 'cmdH3',
				title: 'Heading 3',
				btnText: 'H3',
				callback: function(e){
					headingCallback(e, '###');
				}
			},{
				name: 'cmdH4',
				title: 'Heading 4',
				btnText: 'H4',
				callback: function(e){
					headingCallback(e, '####');
				}
			}]
		}];
	},

	renderField: function() {
		var styles = {
			padding: 8
		};
		return (

				<textarea name={this.props.paths.md} style={styles} defaultValue={this.props.value.md} ref="markdownTextarea" className="form-control markdown code"></textarea>

		);
	}

});
<|endoftext|>


<commit_before><commit_msg>removed error re: fips link<commit_after><|endoftext|>


<commit_before>'use strict';
var chalk = require('chalk');

var CHECK = chalk.green('\u2713'),
    XMARK = chalk.red('\u2718');

module.exports = function(runner) {
    var browserSuites, failed, passed, skipped;

    function reportSuccess(data) {
        report(CHECK, data.stateName, data.browserId);
    }

    function reportFail(data) {
        report(XMARK, data.stateName, data.browserId);
    }

    function report(mark, stateName, browserId) {
        var fullSuiteName = browserSuites[browserId].join(' ');
        console.log('%s %s ' + chalk.underline('%s') + ' ' + chalk.yellow('[%s]'),
            mark,
            fullSuiteName,
            stateName,
            browserId
        );
    }

    runner.on('begin', function(data) {
        failed = passed = skipped = 0;
        browserSuites = {};
        data.browserIds.forEach(function(browserId) {
            browserSuites[browserId] = [];
        });
    });

    runner.on('beginSuite', function(data) {
        browserSuites[data.browserId].push(data.suiteName);
    });

    runner.on('endSuite', function(data) {
        browserSuites[data.browserId].pop();
    });

     //for test command
    runner.on('endTest', function(result) {
        if (result.equal) {
            reportSuccess(result);
            passed++;
        } else {
            reportFail(result);
            failed++;
        }
    });

    //for gather command
    runner.on('capture', function(data) {
        reportSuccess(data);
        passed++;
    });

    runner.on('error', function(error) {
        reportFail(error);

        if (error.originalError) {
            error = error.originalError;
        }
        console.error(error.stack || error.message);

        failed++;
    });

    runner.on('end', function() {
        var total = failed + passed + skipped;
        console.log('Total: %s Passed: %s Failed: %s Skipped: %s',
                    chalk.underline(total),
                    chalk.green(passed),
                    chalk.red(failed),
                    chalk.cyan(skipped));
    });
};
<commit_msg>Fix codestyle in flat reporter<commit_after>'use strict';
var chalk = require('chalk');

var CHECK = chalk.green('\u2713'),
    XMARK = chalk.red('\u2718');

module.exports = function(runner) {
    var browserSuites, failed, passed, skipped;

    function reportSuccess(data) {
        report(CHECK, data.stateName, data.browserId);
    }

    function reportFail(data) {
        report(XMARK, data.stateName, data.browserId);
    }

    function report(mark, stateName, browserId) {
        var fullSuiteName = browserSuites[browserId].join(' ');
        console.log('%s %s ' + chalk.underline('%s') + ' ' + chalk.yellow('[%s]'),
            mark,
            fullSuiteName,
            stateName,
            browserId
        );
    }

    runner.on('begin', function(data) {
        failed = passed = skipped = 0;
        browserSuites = {};
        data.browserIds.forEach(function(browserId) {
            browserSuites[browserId] = [];
        });
    });

    runner.on('beginSuite', function(data) {
        browserSuites[data.browserId].push(data.suiteName);
    });

    runner.on('endSuite', function(data) {
        browserSuites[data.browserId].pop();
    });

    //for test command
    runner.on('endTest', function(result) {
        if (result.equal) {
            reportSuccess(result);
            passed++;
        } else {
            reportFail(result);
            failed++;
        }
    });

    //for gather command
    runner.on('capture', function(data) {
        reportSuccess(data);
        passed++;
    });

    runner.on('error', function(error) {
        reportFail(error);

        if (error.originalError) {
            error = error.originalError;
        }
        console.error(error.stack || error.message);

        failed++;
    });

    runner.on('end', function() {
        var total = failed + passed + skipped;
        console.log('Total: %s Passed: %s Failed: %s Skipped: %s',
                    chalk.underline(total),
                    chalk.green(passed),
                    chalk.red(failed),
                    chalk.cyan(skipped));
    });
};
<|endoftext|>