<commit_before>
ToolbarEvent = {};
ToolbarEvent.api = new StumbleUponApi(config);

ToolbarEvent.handleRequest = function(request, sender, sendResponse) {
	console.log("ToolbarEvent.handleRequest", request);
	var action = request.action && request.action.replace(/-[a-z]/, function(x){return x[1].toUpperCase();});
	if (!action || !ToolbarEvent[action])
		return false;
	ToolbarEvent[action](request, sender)
		.then(function(response) {
			console.log("ToolbarEvent.sendResponse", request, response);
			sendResponse(response);
		});
	return true;
}

ToolbarEvent._sanity = function() {
	return ToolbarEvent.api.cache.get('user')
		.then(function(user) {
			ToolbarEvent.api.cache.mset({ authed: config.authed = !!user.userid });
			if (!user.userid)
				return ToolbarEvent.ping();
			return user;
		})
}

ToolbarEvent.discover = function(request, sender) {
	return Page.getUrl(sender.tab.id)
	.then(function(url) {
		return ToolbarEvent.api.discover(url);
	})
	.then(function(url) {
		Page.note(sender.tab.id, url);
		return url;
	});
}

ToolbarEvent.mode = function(request, sender) {
	ToolbarEvent.api.cache.mset({ mode: config.mode = request.data.value || config.defaults.mode });
	ToolbarEvent.stumble(request, sender);
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.theme = function(request, sender) {
	ToolbarEvent.api.cache.mset({ theme: config.theme = request.data.value || config.defaults.theme });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.toggleHidden = function(request, sender) {
	ToolbarEvent.api.cache.mset({ hidden: config.hidden = !config.hidden });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.unhide = function(request, sender) {
	ToolbarEvent.api.cache.mset({ hidden: config.hidden = false });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.hide = function(request, sender) {
	ToolbarEvent.api.cache.mset({ hidden: config.hidden = true });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.repos = function(request, sender) {
	ToolbarEvent.api.cache.mset({ rpos: config.rpos = request.data.rpos });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent._buildResponse = function(change, all) {
	var response = Object.assign({all: all}, { config: config }, change);
	if (response.all) {
//				chrome.runtime.sendMessage(chrome.runtime.id, response);
		chrome.tabs.query({}, function(tabs) {
			tabs.forEach(function (tab) {
				chrome.tabs.sendMessage(tab.id, response);
			});
		});
	}
	return Promise.resolve(response);
}

ToolbarEvent.dislike = function(request, sender) {
	if ((request.url && request.url.userRating && request.url.userRating.type) == -1)
		return ToolbarEvent.unrate(request, sender);

	ToolbarEvent
		._sanity()
		.then(function() { return Page.getUrlId(sender.tab.id) })
		.then(function(urlid) {
			if (!urlid) {
				debug("Attempt to dislike url that doesn't exist", request);
				return Promise.resolve(request);
			}
			return ToolbarEvent.api.dislike(urlid)
				.then(function(response) {
					return Page.note(sender.tab.id, response.url);
				});
		})
		.catch(ToolbarEvent.error);

	request.url.userRating = { type: -1, subtype: 0 };
	return Promise.resolve(request);
}

ToolbarEvent.info = function(request, sender) {
	if (Page.getUrlId(sender.tab.id))
		chrome.tabs.create({ url: 'http://' + config.baseUrl + config.url.info.form({ urlid: Page.getUrlId(sender.tab.id) }) });
	Promise.resolve(request);
}

ToolbarEvent.updateConfig = function(request, sender) {
	Object.assign(config, request.data);
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.unrate = function(request, sender) {
	ToolbarEvent
		._sanity()
		.then(function() { return Page.getUrlId(sender.tab.id) })
		.then(function(urlid) {
			if (!urlid) {
				debug("Attempt to unrate url that doesn't exist", request);
				return Promise.resolve(request);
			}
			return ToolbarEvent.api.unrate(urlid)
				.then(function(response) {
					return Page.note(sender.tab.id, response.url);
				});
		})
		.catch(ToolbarEvent.error);

	request.url.userRating = { type: 0, subtype: 0 };
	return Promise.resolve(request);
}

ToolbarEvent.like = function(request, sender) {
	if ((request.url && request.url.userRating && request.url.userRating.type) == 1)
		return ToolbarEvent.unrate(request, sender);

	ToolbarEvent
		._sanity()
		.then(function() { return Page.getUrlId(sender.tab.id) })
		.then(function(urlid) {
			return urlid || ToolbarEvent.discover(request, sender)
				.then(function(url) { return url.urlid; });
		})
		.then(function(urlid) {
			return ToolbarEvent.api.like(urlid)
				.then(function(response) {
					return Page.note(sender.tab.id, response.url);
				});
		})
		.catch(ToolbarEvent.error);

	request.url.userRating = { type: 1, subtype: 0 };
	return Promise.resolve(request);
}

ToolbarEvent.inbox = function(request, sender) {
	return ToolbarEvent
		.api.getConversations()
		.then(function(inbox) {
			return ToolbarEvent._buildResponse({ inbox: inbox });
		})
		.catch(ToolbarEvent.error);
}

ToolbarEvent.stumble = function(request, sender) {
	return ToolbarEvent.api
		._mode(config.mode || config.defaults.mode)
		.nextUrl()
		.then(function(url) {
			ToolbarEvent.api
				.nextUrl(1)
				.then(ToolbarEvent.preload);
			Page.note(sender.tab.id, url);
			ToolbarEvent.api.reportStumble([url.urlid]);
			request.url = url;
			console.log(url);
			chrome.tabs.update(sender.tab.id, { url: url.url });
			// Don't send URL now, wait for init call
			return ToolbarEvent._buildResponse({});
		})
		.catch(ToolbarEvent.error);
}

ToolbarEvent.error = function(e) {
	console.log(e)
	//ToolbarEvent.loginPage();
}

ToolbarEvent.replyConvo = function(request, sender) {
	var convo = ToolbarEvent.api.getConversation(request.data.id);
	return Promise.resolve(convo.comment(request.data.comment))
		.then(function(comment) {
			return ToolbarEvent._buildResponse({ comment: comment });
		});
}

ToolbarEvent.loadConvo = function(request, sender) {
	console.log(request);
	var convo = ToolbarEvent.api.getConversation(request.data.value)
	return Promise.resolve(convo.messages())
		.then(function(convo) {
			return ToolbarEvent._buildResponse({ convo: convo });
		});
}

ToolbarEvent.openConvo = function(request, sender) {
	if (request.data.urlid && request.data.id) {
		return Promise.resolve(Page.getUrlByUrlid(request.data.urlid) || ToolbarEvent.api.getUrlByUrlid(request.data.urlid))
			.then(function(url) {
				Page.state[sender.tab.id] = { convo: request.data.id };
				chrome.tabs.update(sender.tab.id, {
					"url": url.url
				});
				return ToolbarEvent._buildResponse({ });
			}).catch(function() {
				request.data.urlid = null;
				return ToolbarEvent.openConvo(request, sender);
			});
	} else if (request.data.url) {
		chrome.tabs.update(sender.tab.id, {
			"url": request.data.url
		});
	}

	return ToolbarEvent._buildResponse({});
}

ToolbarEvent.signout = function() {
	ToolbarEvent.api._flush();

	chrome.tabs.create({
		"url": config.suPages.signout.form(config),
		active: false
	}, function(tab) {
		chrome.tabs.onUpdated.addListener(function(tabId , info) {
			if (info.status == "complete" && tabId == tab.id) {
				setTimeout(function() { chrome.tabs.remove(tabId); }, 2000);
			}
		});
	});

//	var signoutFrame = document.createElement('iframe');
//	signoutFrame.addEventListener("load", function() {
//		debug('Background logout');
//		//document.body.removeChild(signoutFrame);
//	});
//	signoutFrame.setAttribute('src', config.suPages.signout.form(config));
//	console.log(config.suPages.signout.form(config));
//	document.body.appendChild(signoutFrame);

	return ToolbarEvent.needsLogin();
}

ToolbarEvent.signin =
ToolbarEvent.loginPage = function(request, sender) {
	ToolbarEvent.api._flush();
	chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
		chrome.tabs.update((sender && sender.tab.id) || tabs[0].id, {
			"url": config.suPages.signin.form(config)
		});
	});
	return ToolbarEvent._buildResponse({});
}

ToolbarEvent.needsLogin = function() {
	debug('Needs login', arguments);
	ToolbarEvent.api.cache.mset({ authed: config.authed = false });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.ping = function() {
	return ToolbarEvent.api
		.ping()
		.then(ToolbarEvent.api.getUser.bind(ToolbarEvent.api))
		.then(function(user) {
			debug('Login success for user', user.username);
			ToolbarEvent.api.cache.mset({ authed: config.authed = true });
			ToolbarEvent.api.nextUrl(1)
				.then(ToolbarEvent.preload)
				.catch(function(e) {warning('Expected to preload next url', e);});
		})
		.catch(ToolbarEvent.needsLogin);
}

ToolbarEvent.preload = function(url) {
	ToolbarEvent._prerender.href  = url.url;
	ToolbarEvent._prefetch.href   = url.url;
	ToolbarEvent._preload.href    = url.url;
	debug("Preload", url.url);
}

ToolbarEvent.getUrlFromPageCache = function(url) {
	console.log('GUFPC', Page.urlCache[url]);
	return ToolbarEvent._buildResponse({url: Page.urlCache[url]});
}

ToolbarEvent.urlChange = function(request, sender) {
	return new Promise(function(resolve, reject) {
		chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
			var url = (request && request.url && request.url.url) || (tabs[0] && tabs[0].url);
			console.log(url);
			if (url) {
				Page.urlChange(url, tabs[0].id)
					.then(function(url) {
						resolve(ToolbarEvent._buildResponse({url: url}));
					});
			} else {
				reject();
			}
		});
	});
	return p;
	return ToolbarEvent._buildResponse({});
	//return ToolbarEvent._buildResponse({url: Page.urlCache[request && request.url && request.url.url]});
	return Promise.resolve(request);
}

ToolbarEvent.init = function(request, sender) {
	request.config = config;
	return ToolbarEvent._buildResponse({ url: Page.lastUrl(sender.tab.id), state: Page.lastState(sender.tab.id) });
}

ToolbarEvent._init = function() {
	ToolbarEvent.api.cache.mget(config.persist)
		 .then(function (map) {
			 Object.assign(config, map);
		 });

	ToolbarEvent.ping();

	ToolbarEvent._prerender  = document.createElement('link');
	ToolbarEvent._prefetch   = document.createElement('link');
	ToolbarEvent._preload    = document.createElement('link');

	ToolbarEvent._prerender.rel  = 'prerender';
	ToolbarEvent._prefetch.rel   = 'prefetch';
	ToolbarEvent._preload.rel    = 'preload';

	document.body.appendChild(ToolbarEvent._prerender);
	document.body.appendChild(ToolbarEvent._prefetch);
	document.body.appendChild(ToolbarEvent._preload);

	chrome.runtime.onMessage.addListener(ToolbarEvent.handleRequest);
}

ToolbarEvent._init();
ToolbarEvent.api._flush();

<commit_msg>State change for stumble<commit_after>
ToolbarEvent = {};
ToolbarEvent.api = new StumbleUponApi(config);

ToolbarEvent.handleRequest = function(request, sender, sendResponse) {
	console.log("ToolbarEvent.handleRequest", request);
	var action = request.action && request.action.replace(/-[a-z]/, function(x){return x[1].toUpperCase();});
	if (!action || !ToolbarEvent[action])
		return false;
	ToolbarEvent[action](request, sender)
		.then(function(response) {
			console.log("ToolbarEvent.sendResponse", request, response);
			sendResponse(response);
		});
	return true;
}

ToolbarEvent._sanity = function() {
	return ToolbarEvent.api.cache.get('user')
		.then(function(user) {
			ToolbarEvent.api.cache.mset({ authed: config.authed = !!user.userid });
			if (!user.userid)
				return ToolbarEvent.ping();
			return user;
		})
}

ToolbarEvent.discover = function(request, sender) {
	return Page.getUrl(sender.tab.id)
	.then(function(url) {
		return ToolbarEvent.api.discover(url);
	})
	.then(function(url) {
		Page.note(sender.tab.id, url);
		return url;
	});
}

ToolbarEvent.mode = function(request, sender) {
	ToolbarEvent.api.cache.mset({ mode: config.mode = request.data.value || config.defaults.mode });
	ToolbarEvent.stumble(request, sender);
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.theme = function(request, sender) {
	ToolbarEvent.api.cache.mset({ theme: config.theme = request.data.value || config.defaults.theme });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.toggleHidden = function(request, sender) {
	ToolbarEvent.api.cache.mset({ hidden: config.hidden = !config.hidden });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.unhide = function(request, sender) {
	ToolbarEvent.api.cache.mset({ hidden: config.hidden = false });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.hide = function(request, sender) {
	ToolbarEvent.api.cache.mset({ hidden: config.hidden = true });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.repos = function(request, sender) {
	ToolbarEvent.api.cache.mset({ rpos: config.rpos = request.data.rpos });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent._buildResponse = function(change, all) {
	var response = Object.assign({all: all}, { config: config }, change);
	if (response.all) {
//				chrome.runtime.sendMessage(chrome.runtime.id, response);
		chrome.tabs.query({}, function(tabs) {
			tabs.forEach(function (tab) {
				chrome.tabs.sendMessage(tab.id, response);
			});
		});
	}
	return Promise.resolve(response);
}

ToolbarEvent.dislike = function(request, sender) {
	if ((request.url && request.url.userRating && request.url.userRating.type) == -1)
		return ToolbarEvent.unrate(request, sender);

	ToolbarEvent
		._sanity()
		.then(function() { return Page.getUrlId(sender.tab.id) })
		.then(function(urlid) {
			if (!urlid) {
				debug("Attempt to dislike url that doesn't exist", request);
				return Promise.resolve(request);
			}
			return ToolbarEvent.api.dislike(urlid)
				.then(function(response) {
					return Page.note(sender.tab.id, response.url);
				});
		})
		.catch(ToolbarEvent.error);

	request.url.userRating = { type: -1, subtype: 0 };
	return Promise.resolve(request);
}

ToolbarEvent.info = function(request, sender) {
	if (Page.getUrlId(sender.tab.id))
		chrome.tabs.create({ url: 'http://' + config.baseUrl + config.url.info.form({ urlid: Page.getUrlId(sender.tab.id) }) });
	Promise.resolve(request);
}

ToolbarEvent.updateConfig = function(request, sender) {
	Object.assign(config, request.data);
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.unrate = function(request, sender) {
	ToolbarEvent
		._sanity()
		.then(function() { return Page.getUrlId(sender.tab.id) })
		.then(function(urlid) {
			if (!urlid) {
				debug("Attempt to unrate url that doesn't exist", request);
				return Promise.resolve(request);
			}
			return ToolbarEvent.api.unrate(urlid)
				.then(function(response) {
					return Page.note(sender.tab.id, response.url);
				});
		})
		.catch(ToolbarEvent.error);

	request.url.userRating = { type: 0, subtype: 0 };
	return Promise.resolve(request);
}

ToolbarEvent.like = function(request, sender) {
	if ((request.url && request.url.userRating && request.url.userRating.type) == 1)
		return ToolbarEvent.unrate(request, sender);

	ToolbarEvent
		._sanity()
		.then(function() { return Page.getUrlId(sender.tab.id) })
		.then(function(urlid) {
			return urlid || ToolbarEvent.discover(request, sender)
				.then(function(url) { return url.urlid; });
		})
		.then(function(urlid) {
			return ToolbarEvent.api.like(urlid)
				.then(function(response) {
					return Page.note(sender.tab.id, response.url);
				});
		})
		.catch(ToolbarEvent.error);

	request.url.userRating = { type: 1, subtype: 0 };
	return Promise.resolve(request);
}

ToolbarEvent.inbox = function(request, sender) {
	return ToolbarEvent
		.api.getConversations()
		.then(function(inbox) {
			return ToolbarEvent._buildResponse({ inbox: inbox });
		})
		.catch(ToolbarEvent.error);
}

ToolbarEvent.stumble = function(request, sender) {
	return ToolbarEvent.api
		._mode(config.mode || config.defaults.mode)
		.nextUrl()
		.then(function(url) {
			ToolbarEvent.api
				.nextUrl(1)
				.then(ToolbarEvent.preload);
			Page.note(sender.tab.id, url);
			Page.state[sender.tab.id] = { stumble: url }
			ToolbarEvent.api.reportStumble([url.urlid]);
			request.url = url;
			console.log(url);
			chrome.tabs.update(sender.tab.id, { url: url.url });
			// Don't send URL now, wait for init call
			return ToolbarEvent._buildResponse({});
		})
		.catch(ToolbarEvent.error);
}

ToolbarEvent.error = function(e) {
	console.log(e)
	//ToolbarEvent.loginPage();
}

ToolbarEvent.replyConvo = function(request, sender) {
	var convo = ToolbarEvent.api.getConversation(request.data.id);
	return Promise.resolve(convo.comment(request.data.comment))
		.then(function(comment) {
			return ToolbarEvent._buildResponse({ comment: comment });
		});
}

ToolbarEvent.stateChange = function(request, sender) {
	Page.state[sender.tab.id] = request.data;
}

ToolbarEvent.loadConvo = function(request, sender) {
	console.log(request);
	var convo = ToolbarEvent.api.getConversation(request.data.value)
	return Promise.resolve(convo.messages())
		.then(function(convo) {
			return ToolbarEvent._buildResponse({ convo: convo });
		});
}

ToolbarEvent.openConvo = function(request, sender) {
	if (request.data.urlid && request.data.id) {
		return Promise.resolve(Page.getUrlByUrlid(request.data.urlid) || ToolbarEvent.api.getUrlByUrlid(request.data.urlid))
			.then(function(url) {
				Page.state[sender.tab.id] = { convo: request.data.id };
				chrome.tabs.update(sender.tab.id, {
					"url": url.url
				});
				return ToolbarEvent._buildResponse({ });
			}).catch(function() {
				request.data.urlid = null;
				return ToolbarEvent.openConvo(request, sender);
			});
	} else if (request.data.url) {
		chrome.tabs.update(sender.tab.id, {
			"url": request.data.url
		});
	}

	return ToolbarEvent._buildResponse({});
}

ToolbarEvent.signout = function() {
	ToolbarEvent.api._flush();

	chrome.tabs.create({
		"url": config.suPages.signout.form(config),
		active: false
	}, function(tab) {
		chrome.tabs.onUpdated.addListener(function(tabId , info) {
			if (info.status == "complete" && tabId == tab.id) {
				setTimeout(function() { chrome.tabs.remove(tabId); }, 2000);
			}
		});
	});

//	var signoutFrame = document.createElement('iframe');
//	signoutFrame.addEventListener("load", function() {
//		debug('Background logout');
//		//document.body.removeChild(signoutFrame);
//	});
//	signoutFrame.setAttribute('src', config.suPages.signout.form(config));
//	console.log(config.suPages.signout.form(config));
//	document.body.appendChild(signoutFrame);

	return ToolbarEvent.needsLogin();
}

ToolbarEvent.signin =
ToolbarEvent.loginPage = function(request, sender) {
	ToolbarEvent.api._flush();
	chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
		chrome.tabs.update((sender && sender.tab.id) || tabs[0].id, {
			"url": config.suPages.signin.form(config)
		});
	});
	return ToolbarEvent._buildResponse({});
}

ToolbarEvent.needsLogin = function() {
	debug('Needs login', arguments);
	ToolbarEvent.api.cache.mset({ authed: config.authed = false });
	return ToolbarEvent._buildResponse({}, true);
}

ToolbarEvent.ping = function() {
	return ToolbarEvent.api
		.ping()
		.then(ToolbarEvent.api.getUser.bind(ToolbarEvent.api))
		.then(function(user) {
			debug('Login success for user', user.username);
			ToolbarEvent.api.cache.mset({ authed: config.authed = true });
			ToolbarEvent.api.nextUrl(1)
				.then(ToolbarEvent.preload)
				.catch(function(e) {warning('Expected to preload next url', e);});
		})
		.catch(ToolbarEvent.needsLogin);
}

ToolbarEvent.preload = function(url) {
	ToolbarEvent._prerender.href  = url.url;
	ToolbarEvent._prefetch.href   = url.url;
	ToolbarEvent._preload.href    = url.url;
	debug("Preload", url.url);
}

ToolbarEvent.getUrlFromPageCache = function(url) {
	console.log('GUFPC', Page.urlCache[url]);
	return ToolbarEvent._buildResponse({url: Page.urlCache[url]});
}

ToolbarEvent.urlChange = function(request, sender) {
	return new Promise(function(resolve, reject) {
		chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
			var url = (request && request.url && request.url.url) || (tabs[0] && tabs[0].url);
			console.log(url);
			if (url) {
				Page.urlChange(url, tabs[0].id)
					.then(function(url) {
						resolve(ToolbarEvent._buildResponse({url: url}));
					});
			} else {
				reject();
			}
		});
	});
	return p;
	return ToolbarEvent._buildResponse({});
	//return ToolbarEvent._buildResponse({url: Page.urlCache[request && request.url && request.url.url]});
	return Promise.resolve(request);
}

ToolbarEvent.init = function(request, sender) {
	request.config = config;
	return ToolbarEvent._buildResponse({ url: Page.lastUrl(sender.tab.id), state: Page.lastState(sender.tab.id) });
}

ToolbarEvent._init = function() {
	ToolbarEvent.api.cache.mget(config.persist)
		 .then(function (map) {
			 Object.assign(config, map);
		 });

	ToolbarEvent.ping();

	ToolbarEvent._prerender  = document.createElement('link');
	ToolbarEvent._prefetch   = document.createElement('link');
	ToolbarEvent._preload    = document.createElement('link');

	ToolbarEvent._prerender.rel  = 'prerender';
	ToolbarEvent._prefetch.rel   = 'prefetch';
	ToolbarEvent._preload.rel    = 'preload';

	document.body.appendChild(ToolbarEvent._prerender);
	document.body.appendChild(ToolbarEvent._prefetch);
	document.body.appendChild(ToolbarEvent._preload);

	chrome.runtime.onMessage.addListener(ToolbarEvent.handleRequest);
}

ToolbarEvent._init();
ToolbarEvent.api._flush();

<|endoftext|>


<commit_before>/*global $:false */

/**
 * Manages the background color and it's animations.
 */
var NowRadio = (function(nr) {
    'use strict';
    var isBright = true;
    function updateColors(color) {
        if (isBright) {
            nr.ColorManager.setElemBgToColor(nr.$elems.centerContainer, color);
            nr.ColorManager.setElemBgToColor(nr.$elems.newFaveBox, color);
            nr.$elems.metaThemeColor.attr('content', color);
        } else {
            nr.ColorManager.setElemBgToColor(nr.$elems.navBar, color);
            nr.ColorManager.setElemFgToColor(nr.$elems.stationInfo, color);
            nr.ColorManager.setElemBgToColor(nr.$elems.newFaveBox, color);
            nr.$elems.metaThemeColor.attr('content', "#000000");
        }
    }
    function switchBrightness() {
        if (isBright) {
            isBright = false;
            nr.$elems.centerContainer.velocity('stop', true);
            nr.$elems.centerContainer.css("background-color", "black");
            nr.$elems.navBar.css("color", "black");
            nr.ColorManager.updateToGenreColor();
            nr.$elems.metaThemeColor.attr('content', "#000000");
        } else {
            isBright = true;
            nr.$elems.navBar.velocity('stop', true);
            nr.$elems.navBar.css("backgroundColor", "black");
            nr.$elems.navBar.css("color", "white");
            nr.$elems.stationInfo.css("color", "black")
                .css("border-color", "black");
            nr.ColorManager.updateToGenreColor();
            nr.$elems.metaThemeColor.attr('content', nr.ColorManager.currentGenreColor());
        }
        window.localStorage.setItem("isBright", isBright);
    }

    nr.ColorManager = {};
    nr.ColorManager.updateToGenreColor = function() {
        updateColors(this.currentGenreColor());
    };
    nr.ColorManager.setToNeutral = function() {
        if (isBright) {
            nr.$elems.centerContainer.velocity('stop', true).velocity({
                backgroundColor: '#aaa'
            }, 50);
        } else {
            nr.$elems.navBar.velocity('stop', true).velocity({
                backgroundColor: '#aaa',
                text: '#aaa'
            }, 50);
        }
        nr.$elems.newFaveBox.css("background-color", "#aaa");
    };
    nr.ColorManager.setElemBgToColor = function(elem, color) {
        elem.velocity('stop', true).velocity({
            'backgroundColor': color
        }, 666);
    };
    nr.ColorManager.setElemFgToColor = function(elem, color) {
        elem.css({
            'color': color,
            'border-color': color
        });
    };
    nr.ColorManager.currentGenreColor = function() {
        return nr.Utils.genreNumToColor(nr.StationsManager.getActiveGenre());
    };
    nr.ColorManager.restoreColor = function() {
        var bright = window.localStorage.getItem("isBright");
        if (bright === "false") {
            switchBrightness();
        }
    };
    $(document).ready(function() {
        nr.$buttons.brightness.click(switchBrightness);
    });

    return nr;
}(NowRadio || {}));
<commit_msg>Change #aaa to #ddd in js files<commit_after>/*global $:false */

/**
 * Manages the background color and it's animations.
 */
var NowRadio = (function(nr) {
    'use strict';
    var isBright = true;
    function updateColors(color) {
        if (isBright) {
            nr.ColorManager.setElemBgToColor(nr.$elems.centerContainer, color);
            nr.ColorManager.setElemBgToColor(nr.$elems.newFaveBox, color);
            nr.$elems.metaThemeColor.attr('content', color);
        } else {
            nr.ColorManager.setElemBgToColor(nr.$elems.navBar, color);
            nr.ColorManager.setElemFgToColor(nr.$elems.stationInfo, color);
            nr.ColorManager.setElemBgToColor(nr.$elems.newFaveBox, color);
            nr.$elems.metaThemeColor.attr('content', "#000000");
        }
    }
    function switchBrightness() {
        if (isBright) {
            isBright = false;
            nr.$elems.centerContainer.velocity('stop', true);
            nr.$elems.centerContainer.css("background-color", "black");
            nr.$elems.navBar.css("color", "black");
            nr.ColorManager.updateToGenreColor();
            nr.$elems.metaThemeColor.attr('content', "#000000");
        } else {
            isBright = true;
            nr.$elems.navBar.velocity('stop', true);
            nr.$elems.navBar.css("backgroundColor", "black");
            nr.$elems.navBar.css("color", "white");
            nr.$elems.stationInfo.css("color", "black")
                .css("border-color", "black");
            nr.ColorManager.updateToGenreColor();
            nr.$elems.metaThemeColor.attr('content', nr.ColorManager.currentGenreColor());
        }
        window.localStorage.setItem("isBright", isBright);
    }

    nr.ColorManager = {};
    nr.ColorManager.updateToGenreColor = function() {
        updateColors(this.currentGenreColor());
    };
    nr.ColorManager.setToNeutral = function() {
        if (isBright) {
            nr.$elems.centerContainer.velocity('stop', true).velocity({
                backgroundColor: '#ddd'
            }, 50);
        } else {
            nr.$elems.navBar.velocity('stop', true).velocity({
                backgroundColor: '#ddd',
                text: '#ddd'
            }, 50);
        }
        nr.$elems.newFaveBox.css("background-color", "#ddd");
    };
    nr.ColorManager.setElemBgToColor = function(elem, color) {
        elem.velocity('stop', true).velocity({
            'backgroundColor': color
        }, 666);
    };
    nr.ColorManager.setElemFgToColor = function(elem, color) {
        elem.css({
            'color': color,
            'border-color': color
        });
    };
    nr.ColorManager.currentGenreColor = function() {
        return nr.Utils.genreNumToColor(nr.StationsManager.getActiveGenre());
    };
    nr.ColorManager.restoreColor = function() {
        var bright = window.localStorage.getItem("isBright");
        if (bright === "false") {
            switchBrightness();
        }
    };
    $(document).ready(function() {
        nr.$buttons.brightness.click(switchBrightness);
    });

    return nr;
}(NowRadio || {}));
<|endoftext|>


<commit_before>/**
 * Views for the story viewer Backbone application
 */
Namespace('storybase.viewer');

// Translations for interface text
Globalize.addCultureInfo('en', {
  messages: {
    "Topic Map": "Topic Map",
    "How Can You Help?": "How Can You Help?"
  }
});

Globalize.addCultureInfo('es', {
  messages: {
    "Topic Map": "Mapa Temático",
    "How Can You Help?": "How Can You Help?"
  }
});

// Container view for the viewer application.
// It delegates rendering and events for the entire app to views
// rendering more specific "widgets"
storybase.viewer.views.ViewerApp = Backbone.View.extend({
  // Initialize the view
  initialize: function() {
    this.sections = this.options.sections;
    this.story = this.options.story;
    this.navigationView = new storybase.viewer.views.StoryNavigation({
      sections: this.options.sections
    });
    this.headerView = new storybase.viewer.views.StoryHeader();
    this.setSection(this.sections.at(0), {showActiveSection: false});
    _.bindAll(this, 'handleScroll');
    $(window).scroll(this.handleScroll);
  },

  // Add the view's container element to the DOM and render the sub-views
  render: function() {
    this.$el.addClass(this.elClass);
    this.$('footer').append(this.navigationView.el);
    this.navigationView.render();
    this.$('.summary').show();
    this.$('.section').show();
    return this;
  },

  // Update the active story section in the sub-views
  updateSubviewSections: function() {
    this.navigationView.setSection(this.activeSection);
    this.headerView.setSection(this.activeSection);
  },

  // Show the active section
  showActiveSection: function() {
    throw "showActiveSection() is not implemented";
  },

  // Set the active story section
  setSection: function(section, options) {
    options = typeof options !== 'undefined' ? options : {};
    var showActiveSection = options.hasOwnProperty('showActiveSection') ? options.showActiveSection : true;
    this.activeSection = section;
    if (showActiveSection) {
      this.showActiveSection();
    }
    this.updateSubviewSections();
  },

  // Like setSection(), but takes a section ID as an argument instead of
  // a Section model instance object
  setSectionById: function(id) {
    this.setSection(this.sections.get(id));
  },

  // Convenience method to get the element for the active section
  activeSectionEl: function() {
      return this.$('#' + this.activeSection.id);
  },

  // Event handler for scroll event
  handleScroll: function(e) {
    // Do nothing. Subclasses might want to implement this to do some work
  }
});

// View for the story viewer header.
// Updates the section heading title when the active section changes
storybase.viewer.views.StoryHeader = Backbone.View.extend({
  el: 'header',

  render: function() {
    var $titleEl = this.$el.find('.section-title').first();
    if ($titleEl.length == 0) {
      $titleEl = $('
');
      this.$el.append($titleEl);
    }
    $titleEl.text(this.section.get('title'));
    return this;
  },

  setSection: function(section) {
    this.section = section;
    this.render();
  }
});

// View to provide previous/next buttons to navigate between sections
storybase.viewer.views.StoryNavigation = Backbone.View.extend({
  tagName: 'nav',

  className: 'story-nav',

  initialize: function() {
    this.section = null;
    this.sections = this.options.sections;
    if (this.options.hasOwnProperty('addlLinks')) {
      this.addlLinks = this.options.addlLinks.map(function(link) {
        return {
         text: link.text,
         id: link.id,
         href: link.hasOwnProperty('href') ? link.href: '#'
       }
      });
    }
    else {
      this.addlLinks = [];
    }
  },

  render: function() {
    var context = {};
    if (this.section) {
      context.next_section = this.sections.get(
	this.section.get('next_section_id'));
      context.previous_section = this.sections.get(
	this.section.get('previous_section_id'));
    }
    context.addl_links = this.addlLinks;

    this.$el.html(ich.navigationTemplate(context));
    return this;
  },

  setSection: function(section) {
    this.section = section;
    this.render();
  }
});

// Interative visualization of a spider story structure
storybase.viewer.views.Spider = Backbone.View.extend({
  events: {
    "hover g.node": "hoverSectionNode"
  },

  initialize: function() {
    this.sections = this.options.sections;
    this.insertBefore = this.options.insertBefore;
    this.subtractHeight = this.options.subtractHeight;
    this.subtractWidth = this.options.subtractWidth;
    this.activeSection = null;
    // The id for the visualization's wrapper element
    this.visId = 'spider-vis';
    this.maxDepth = null;
    this.sectionsAtDepth = [];
    this.maxSectionsAtDepth = 0;
    this.walkSectionHierarchy(0, this.sections.at(0));
  },

  // Walk the section hierarchy to build a sense of its "shape"
  walkSectionHierarchy: function(depth, section) {
    if (this.maxDepth == null ||
        depth > this.maxDepth) {
      this.maxDepth = depth;
    }

    if (this.sectionsAtDepth[depth] === undefined) {
      this.sectionsAtDepth[depth] = 1;
    }
    else {
      this.sectionsAtDepth[depth]++;
    }

    if (this.sectionsAtDepth[depth] > this.maxSectionsAtDepth) {
      this.maxSectionsAtDepth = this.sectionsAtDepth[depth];
    }

    var $this = this;
    _.each(section.get('children'), function(childId) {
      $this.walkSectionHierarchy(depth + 1, $this.sections.get(childId));
    });
  },

  // Return the visualization wrapper element
  visEl: function() {
    return this.$('#' + this.visId).first();
  },

  setSection: function(section) {
    this.activeSection = section;
    this.highlightSectionNode(this.activeSection.id);
  },

  highlightSectionNode: function(sectionId) {
    d3.selectAll('g.node').classed('active', false);
    d3.select('g.node.section-' + sectionId).classed('active', true);
  },

  // Get the dimensions of the visualization's wrapper element
  getVisDimensions: function() {
    // We have to calculate the dimensions relative to the window rather than
    // the parent element because the parent element is really tall as it
    // also contains the (hidden) section content.  It seems there should be
    // a better way to do this, but I don't know it.
    width = $(window).width();
    height = $(window).height();
    _.each(this.subtractWidth, function(selector) {
      width -= $(selector).outerWidth();
    });
    _.each(this.subtractHeight, function(selector) {
      height -= $(selector).outerHeight();
    });
    return {
      width: width,
      height: height
    };
  },

  // Get the radius of the tree
  getTreeRadius: function(width, height) {
    return (this.maxSectionsAtDepth == 1 ? _.max([width, height]) : _.min([width, height])) * .66;
  },

  render: function() {
    var $this = this;
    var elId = this.$el.attr('id');
    var dimensions = this.getVisDimensions();
    var treeRadius = this.getTreeRadius(dimensions.width, dimensions.height);
    var vis = d3.select("#" + elId).insert("svg", this.insertBefore)
        .attr("id", this.visId)
        .attr("width", dimensions.width)
        .attr("height", dimensions.height)
	.attr("style", "float:left")
      .append("g");
    var rootSection = this.sections.at(0).populateChildren();
    var tree = d3.layout.tree()
      .size([360, treeRadius - 120])
      .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
    var diagonal = d3.svg.diagonal.radial()
      .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
    var nodes = tree.nodes(rootSection);
    // Fix x coordinate (angle) when each level has only one child
    // In this case d.x = NaN which breakins things
    nodes = _.map(nodes, function(node) {
      node.x = $this.maxSectionsAtDepth == 1 ? 90 : node.x;
      return node;
    });
    var links = tree.links(nodes);

    var link = vis.selectAll("path.link")
        .data(links)
      .enter().append("path")
        .attr("class", "link")
        .attr("d", diagonal);

    var node = vis.selectAll("g.node")
      .data(nodes)
      .enter().append("g")
      .attr('class', function(d) {
        return "node section-" + d.id;
      })
      .attr("transform", function(d) {
	var transform = "";
	if (d.depth > 0) {
	  transform += "rotate(" + (d.x - 90) + ")";
	}
        transform += "translate(" + d.y + ")";
	return transform;
      });

    node.append("circle")
        .attr("r", 15);

    node.append("text")
      .attr("x", function(d) {
	if (d.depth == 0) { return 20; }
        return d.x < 180 ? 20 : -20;
      })
      .attr("y", ".31em")
      .attr("text-anchor", function(d) {
	if (d.depth == 0) { return "start"; }
        return d.x < 180 ? "start" : "end"; })
      .attr("transform", function(d) {
	var rotation = 0;
	if ($this.maxSectionsAtDepth == 1) {
	  rotation = 315;
	}
	else if (d.depth > 0) {
          rotation = 90 - d.x;
	}
	return "rotate(" + rotation + ")";
      })
      .text(function(d) { return d.get('title'); });

    // Center the tree within the viewport
    var treeBBox = vis[0][0].getBBox();
    var translateX = (0 - treeBBox.x) + ((dimensions.width - treeBBox.width) / 2);
    var translateY = (0 - treeBBox.y) + ((dimensions.height - treeBBox.height) / 2);
    vis.attr("transform", "translate(" + translateX + ", " + translateY + ")");
  },

  // Event handler for hovering over a section node
  // Changes the cursor to a "pointer" style icon to indicate that
  // the nodes are clickable.
  hoverSectionNode: function(e) {
    e.currentTarget.style.cursor = 'pointer';
  },
});

// Master view that shows a story in a linear fashion
storybase.viewer.views.LinearViewerApp = storybase.viewer.views.ViewerApp.extend({
  elClass: 'linear',

  // Get the position, from the top of the winder, of the lower edge of the
  // header
  headerBottom: function() {
    return this.$('header').offset().top + this.$('header').outerHeight();
  },

  footerTop: function() {
    return this.$('footer').offset().top;
  },

  // Show the active section
  showActiveSection: function() {
    var sectionTop = this.$('#' + this.activeSection.id).offset().top;
    this._preventScrollEvent = true;
    $(window).scrollTop(sectionTop - this.headerBottom());
  },

  // Return the element of the last visible story section
  getLastVisibleSectionEl: function() {
    var visibleSections = [];
    var numSections = this.$('section').length;
    for (var i = 0; i < numSections; i++) {
      var $section = this.$('section').eq(i);
      var sectionTop = $section.offset().top;
      var sectionBottom = sectionTop + $section.outerHeight();
      if (sectionTop >= this.headerBottom() &&
          sectionBottom <= this.footerTop()) {
        visibleSections.push($section);
      }
    }
    return _.last(visibleSections);
  },

  // Event handler for scroll event
  handleScroll: function(e) {
    var newSection = this.activeSection;
    if (this._preventScrollEvent !== true) {
      if ($(window).scrollTop() == 0) {
	// At the top of the window.  Set the active section to the
	// first section
	newSection = this.sections.first();
      }
      else {
	var $lastVisibleSectionEl = this.getLastVisibleSectionEl();
	if ($lastVisibleSectionEl) {
	  var lastVisibleSection = this.sections.get($lastVisibleSectionEl.attr('id'));
	  if (lastVisibleSection != this.activeSection) {
	    newSection = lastVisibleSection;
	  }
	}
      }
      this.setSection(newSection, {showActiveSection: false});
      storybase.viewer.router.navigate("sections/" + newSection.id,
                                     {trigger: false});
    }
    this._preventScrollEvent = false;
  }
});

// Master view that shows the story structure visualization initially
storybase.viewer.views.SpiderViewerApp = storybase.viewer.views.ViewerApp.extend({
  elClass: 'spider',

  events: {
    "click #topic-map": "clickTopicMapLink",
    "click g.node": "clickSectionNode"
  },

  initialize: function() {
    this.sections = this.options.sections;
    this.story = this.options.story;
    this.navigationView = new storybase.viewer.views.StoryNavigation({
      sections: this.options.sections,
      addlLinks: [{text: Globalize.localize("Topic Map"), id: 'topic-map'}]
    });
    this.headerView = new storybase.viewer.views.StoryHeader();
    this.initialView = new storybase.viewer.views.Spider({
      el: this.$('#body'),
      sections: this.options.sections,
      insertBefore: '.section',
      subtractWidth: ['.summary'],
      subtractHeight: ['header', 'footer']
    });
  },

  render: function() {
    this.$el.addClass(this.elClass);
    this.$('footer').append(this.navigationView.el);
    this.navigationView.render();
    this.initialView.render();
    this.$('.summary').show();
    // Hide all the section content initially
    this.$('.section').hide();
    return this;
  },

  // Show the active section
  showActiveSection: function() {
    // Hide the summary
    this.$('.summary').hide();
    // Hide all sections other than the active one
    this.$('.section').hide();
    this.$('#' + this.activeSection.id).show();
    // Hide the visualization
    this.initialView.$('svg').hide();
  },

  // Update the active story section in the sub-views
  updateSubviewSections: function() {
    this.navigationView.setSection(this.activeSection);
    this.headerView.setSection(this.activeSection);
    this.initialView.setSection(this.activeSection);
  },

  // Event handler for clicks on a section node
  clickSectionNode: function(e) {
    var node = d3.select(e.currentTarget);
    var sectionId = node.data()[0].id;
    this.initialView.visEl().hide();
    // TODO: I'm not sure if this is the best way to access the router
    // I don't like global variables, but passing it as an argument
    // makes for a weird circular dependency between the master view/
    // router.
    storybase.viewer.router.navigate("sections/" + sectionId,
                                     {trigger: true});
  },

  // Event handler for clicking the "Topic Map" link
  clickTopicMapLink: function(e) {
    var activeSectionEl = this.activeSectionEl();
    if (activeSectionEl !== null) {
      var visEl = this.initialView.visEl();
      if (visEl.css('display') == 'none') {
	this.initialView.visEl().show();
      }
      else {
	this.initialView.visEl().hide();
      }
      this.$('.summary').toggle();
    }
  }

});

// Get the appropriate master view based on the story structure type
storybase.viewer.views.getViewerApp = function(structureType, options) {
  if (structureType == 'linear') {
    return new storybase.viewer.views.LinearViewerApp(options);
  }
  else if (structureType == 'spider') {
    return new storybase.viewer.views.SpiderViewerApp(options);
  }
  else {
    throw "Unknown story structure type '" + structureType + "'";
  }
};
<commit_msg>Fixed scrolling by links in linear story viewer.<commit_after>/**
 * Views for the story viewer Backbone application
 */
Namespace('storybase.viewer');

// Translations for interface text
Globalize.addCultureInfo('en', {
  messages: {
    "Topic Map": "Topic Map",
    "How Can You Help?": "How Can You Help?"
  }
});

Globalize.addCultureInfo('es', {
  messages: {
    "Topic Map": "Mapa Temático",
    "How Can You Help?": "How Can You Help?"
  }
});

// Container view for the viewer application.
// It delegates rendering and events for the entire app to views
// rendering more specific "widgets"
storybase.viewer.views.ViewerApp = Backbone.View.extend({
  // Initialize the view
  initialize: function() {
    this.sections = this.options.sections;
    this.story = this.options.story;
    this.navigationView = new storybase.viewer.views.StoryNavigation({
      sections: this.options.sections
    });
    this.headerView = new storybase.viewer.views.StoryHeader();
    this.setSection(this.sections.at(0), {showActiveSection: false});
    _.bindAll(this, 'handleScroll');
    $(window).scroll(this.handleScroll);
  },

  // Add the view's container element to the DOM and render the sub-views
  render: function() {
    this.$el.addClass(this.elClass);
    this.$('footer').append(this.navigationView.el);
    this.navigationView.render();
    this.$('.summary').show();
    this.$('.section').show();
    return this;
  },

  // Update the active story section in the sub-views
  updateSubviewSections: function() {
    this.navigationView.setSection(this.activeSection);
    this.headerView.setSection(this.activeSection);
  },

  // Show the active section
  showActiveSection: function() {
    throw "showActiveSection() is not implemented";
  },

  // Set the active story section
  setSection: function(section, options) {
    options = typeof options !== 'undefined' ? options : {};
    var showActiveSection = options.hasOwnProperty('showActiveSection') ? options.showActiveSection : true;
    this.activeSection = section;
    if (showActiveSection) {
      this.showActiveSection();
    }
    this.updateSubviewSections();
  },

  // Like setSection(), but takes a section ID as an argument instead of
  // a Section model instance object
  setSectionById: function(id) {
    this.setSection(this.sections.get(id));
  },

  // Convenience method to get the element for the active section
  activeSectionEl: function() {
      return this.$('#' + this.activeSection.id);
  },

  // Event handler for scroll event
  handleScroll: function(e) {
    // Do nothing. Subclasses might want to implement this to do some work
  }
});

// View for the story viewer header.
// Updates the section heading title when the active section changes
storybase.viewer.views.StoryHeader = Backbone.View.extend({
  el: 'header',

  render: function() {
    var $titleEl = this.$el.find('.section-title').first();
    if ($titleEl.length == 0) {
      $titleEl = $('
');
      this.$el.append($titleEl);
    }
    $titleEl.text(this.section.get('title'));
    return this;
  },

  setSection: function(section) {
    this.section = section;
    this.render();
  }
});

// View to provide previous/next buttons to navigate between sections
storybase.viewer.views.StoryNavigation = Backbone.View.extend({
  tagName: 'nav',

  className: 'story-nav',

  initialize: function() {
    this.section = null;
    this.sections = this.options.sections;
    if (this.options.hasOwnProperty('addlLinks')) {
      this.addlLinks = this.options.addlLinks.map(function(link) {
        return {
         text: link.text,
         id: link.id,
         href: link.hasOwnProperty('href') ? link.href: '#'
       }
      });
    }
    else {
      this.addlLinks = [];
    }
  },

  render: function() {
    var context = {};
    if (this.section) {
      context.next_section = this.sections.get(
	this.section.get('next_section_id'));
      context.previous_section = this.sections.get(
	this.section.get('previous_section_id'));
    }
    context.addl_links = this.addlLinks;

    this.$el.html(ich.navigationTemplate(context));
    return this;
  },

  setSection: function(section) {
    this.section = section;
    this.render();
  }
});

// Interative visualization of a spider story structure
storybase.viewer.views.Spider = Backbone.View.extend({
  events: {
    "hover g.node": "hoverSectionNode"
  },

  initialize: function() {
    this.sections = this.options.sections;
    this.insertBefore = this.options.insertBefore;
    this.subtractHeight = this.options.subtractHeight;
    this.subtractWidth = this.options.subtractWidth;
    this.activeSection = null;
    // The id for the visualization's wrapper element
    this.visId = 'spider-vis';
    this.maxDepth = null;
    this.sectionsAtDepth = [];
    this.maxSectionsAtDepth = 0;
    this.walkSectionHierarchy(0, this.sections.at(0));
  },

  // Walk the section hierarchy to build a sense of its "shape"
  walkSectionHierarchy: function(depth, section) {
    if (this.maxDepth == null ||
        depth > this.maxDepth) {
      this.maxDepth = depth;
    }

    if (this.sectionsAtDepth[depth] === undefined) {
      this.sectionsAtDepth[depth] = 1;
    }
    else {
      this.sectionsAtDepth[depth]++;
    }

    if (this.sectionsAtDepth[depth] > this.maxSectionsAtDepth) {
      this.maxSectionsAtDepth = this.sectionsAtDepth[depth];
    }

    var $this = this;
    _.each(section.get('children'), function(childId) {
      $this.walkSectionHierarchy(depth + 1, $this.sections.get(childId));
    });
  },

  // Return the visualization wrapper element
  visEl: function() {
    return this.$('#' + this.visId).first();
  },

  setSection: function(section) {
    this.activeSection = section;
    this.highlightSectionNode(this.activeSection.id);
  },

  highlightSectionNode: function(sectionId) {
    d3.selectAll('g.node').classed('active', false);
    d3.select('g.node.section-' + sectionId).classed('active', true);
  },

  // Get the dimensions of the visualization's wrapper element
  getVisDimensions: function() {
    // We have to calculate the dimensions relative to the window rather than
    // the parent element because the parent element is really tall as it
    // also contains the (hidden) section content.  It seems there should be
    // a better way to do this, but I don't know it.
    width = $(window).width();
    height = $(window).height();
    _.each(this.subtractWidth, function(selector) {
      width -= $(selector).outerWidth();
    });
    _.each(this.subtractHeight, function(selector) {
      height -= $(selector).outerHeight();
    });
    return {
      width: width,
      height: height
    };
  },

  // Get the radius of the tree
  getTreeRadius: function(width, height) {
    return (this.maxSectionsAtDepth == 1 ? _.max([width, height]) : _.min([width, height])) * .66;
  },

  render: function() {
    var $this = this;
    var elId = this.$el.attr('id');
    var dimensions = this.getVisDimensions();
    var treeRadius = this.getTreeRadius(dimensions.width, dimensions.height);
    var vis = d3.select("#" + elId).insert("svg", this.insertBefore)
        .attr("id", this.visId)
        .attr("width", dimensions.width)
        .attr("height", dimensions.height)
	.attr("style", "float:left")
      .append("g");
    var rootSection = this.sections.at(0).populateChildren();
    var tree = d3.layout.tree()
      .size([360, treeRadius - 120])
      .separation(function(a, b) { return (a.parent == b.parent ? 1 : 2) / a.depth; });
    var diagonal = d3.svg.diagonal.radial()
      .projection(function(d) { return [d.y, d.x / 180 * Math.PI]; });
    var nodes = tree.nodes(rootSection);
    // Fix x coordinate (angle) when each level has only one child
    // In this case d.x = NaN which breakins things
    nodes = _.map(nodes, function(node) {
      node.x = $this.maxSectionsAtDepth == 1 ? 90 : node.x;
      return node;
    });
    var links = tree.links(nodes);

    var link = vis.selectAll("path.link")
        .data(links)
      .enter().append("path")
        .attr("class", "link")
        .attr("d", diagonal);

    var node = vis.selectAll("g.node")
      .data(nodes)
      .enter().append("g")
      .attr('class', function(d) {
        return "node section-" + d.id;
      })
      .attr("transform", function(d) {
	var transform = "";
	if (d.depth > 0) {
	  transform += "rotate(" + (d.x - 90) + ")";
	}
        transform += "translate(" + d.y + ")";
	return transform;
      });

    node.append("circle")
        .attr("r", 15);

    node.append("text")
      .attr("x", function(d) {
	if (d.depth == 0) { return 20; }
        return d.x < 180 ? 20 : -20;
      })
      .attr("y", ".31em")
      .attr("text-anchor", function(d) {
	if (d.depth == 0) { return "start"; }
        return d.x < 180 ? "start" : "end"; })
      .attr("transform", function(d) {
	var rotation = 0;
	if ($this.maxSectionsAtDepth == 1) {
	  rotation = 315;
	}
	else if (d.depth > 0) {
          rotation = 90 - d.x;
	}
	return "rotate(" + rotation + ")";
      })
      .text(function(d) { return d.get('title'); });

    // Center the tree within the viewport
    var treeBBox = vis[0][0].getBBox();
    var translateX = (0 - treeBBox.x) + ((dimensions.width - treeBBox.width) / 2);
    var translateY = (0 - treeBBox.y) + ((dimensions.height - treeBBox.height) / 2);
    vis.attr("transform", "translate(" + translateX + ", " + translateY + ")");
  },

  // Event handler for hovering over a section node
  // Changes the cursor to a "pointer" style icon to indicate that
  // the nodes are clickable.
  hoverSectionNode: function(e) {
    e.currentTarget.style.cursor = 'pointer';
  },
});

// Master view that shows a story in a linear fashion
storybase.viewer.views.LinearViewerApp = storybase.viewer.views.ViewerApp.extend({
  elClass: 'linear',

  // Get the position, from the top of the winder, of the lower edge of the
  // header
  headerBottom: function() {
    return headerHeight = this.$('header').outerHeight()
  },

  footerTop: function() {
    return this.$('footer').offset().top;
  },

  // Show the active section
  showActiveSection: function() {
    var sectionTop = this.$('#' + this.activeSection.id).offset().top;
    this._preventScrollEvent = true;
    var headerBottom = this.headerBottom();
    var scrollBy = Math.ceil(sectionTop - this.headerBottom());
    $(window).scrollTop(scrollBy);
  },

  // Return the element of the last visible story section
  getLastVisibleSectionEl: function() {
    var visibleSections = [];
    var numSections = this.$('section').length;
    for (var i = 0; i < numSections; i++) {
      var $section = this.$('section').eq(i);
      var sectionTop = $section.offset().top;
      var sectionBottom = sectionTop + $section.outerHeight();
      if (sectionTop >= this.headerBottom() &&
          sectionBottom <= this.footerTop()) {
        visibleSections.push($section);
      }
    }
    return _.last(visibleSections);
  },

  // Event handler for scroll event
  handleScroll: function(e) {
    var newSection = this.activeSection;
    if (this._preventScrollEvent !== true) {
      if ($(window).scrollTop() == 0) {
	// At the top of the window.  Set the active section to the
	// first section
	newSection = this.sections.first();
      }
      else {
	var $lastVisibleSectionEl = this.getLastVisibleSectionEl();
	if ($lastVisibleSectionEl) {
	  var lastVisibleSection = this.sections.get($lastVisibleSectionEl.attr('id'));
	  if (lastVisibleSection != this.activeSection) {
	    newSection = lastVisibleSection;
	  }
	}
      }
      this.setSection(newSection, {showActiveSection: false});
      storybase.viewer.router.navigate("sections/" + newSection.id,
                                     {trigger: false});
    }
    this._preventScrollEvent = false;
  }
});

// Master view that shows the story structure visualization initially
storybase.viewer.views.SpiderViewerApp = storybase.viewer.views.ViewerApp.extend({
  elClass: 'spider',

  events: {
    "click #topic-map": "clickTopicMapLink",
    "click g.node": "clickSectionNode"
  },

  initialize: function() {
    this.sections = this.options.sections;
    this.story = this.options.story;
    this.navigationView = new storybase.viewer.views.StoryNavigation({
      sections: this.options.sections,
      addlLinks: [{text: Globalize.localize("Topic Map"), id: 'topic-map'}]
    });
    this.headerView = new storybase.viewer.views.StoryHeader();
    this.initialView = new storybase.viewer.views.Spider({
      el: this.$('#body'),
      sections: this.options.sections,
      insertBefore: '.section',
      subtractWidth: ['.summary'],
      subtractHeight: ['header', 'footer']
    });
  },

  render: function() {
    this.$el.addClass(this.elClass);
    this.$('footer').append(this.navigationView.el);
    this.navigationView.render();
    this.initialView.render();
    this.$('.summary').show();
    // Hide all the section content initially
    this.$('.section').hide();
    return this;
  },

  // Show the active section
  showActiveSection: function() {
    // Hide the summary
    this.$('.summary').hide();
    // Hide all sections other than the active one
    this.$('.section').hide();
    this.$('#' + this.activeSection.id).show();
    // Hide the visualization
    this.initialView.$('svg').hide();
  },

  // Update the active story section in the sub-views
  updateSubviewSections: function() {
    this.navigationView.setSection(this.activeSection);
    this.headerView.setSection(this.activeSection);
    this.initialView.setSection(this.activeSection);
  },

  // Event handler for clicks on a section node
  clickSectionNode: function(e) {
    var node = d3.select(e.currentTarget);
    var sectionId = node.data()[0].id;
    this.initialView.visEl().hide();
    // TODO: I'm not sure if this is the best way to access the router
    // I don't like global variables, but passing it as an argument
    // makes for a weird circular dependency between the master view/
    // router.
    storybase.viewer.router.navigate("sections/" + sectionId,
                                     {trigger: true});
  },

  // Event handler for clicking the "Topic Map" link
  clickTopicMapLink: function(e) {
    var activeSectionEl = this.activeSectionEl();
    if (activeSectionEl !== null) {
      var visEl = this.initialView.visEl();
      if (visEl.css('display') == 'none') {
	this.initialView.visEl().show();
      }
      else {
	this.initialView.visEl().hide();
      }
      this.$('.summary').toggle();
    }
  }

});

// Get the appropriate master view based on the story structure type
storybase.viewer.views.getViewerApp = function(structureType, options) {
  if (structureType == 'linear') {
    return new storybase.viewer.views.LinearViewerApp(options);
  }
  else if (structureType == 'spider') {
    return new storybase.viewer.views.SpiderViewerApp(options);
  }
  else {
    throw "Unknown story structure type '" + structureType + "'";
  }
};
<|endoftext|>


<commit_before>/**
 * Created by truthlighting on 9/20/2016.
 */
/**
 * This guys does the other half of energy collection. The miner gets it from the source, and the helper does the
 * transportation. We don't want them just going for the nearest source, as that means that if we have more than one
 * miner, all the helpers will only go for the first miner. To counter this, we assign them to a miner the same way
 * we assign a miner to a source
 */

var helper = {
    parts: [
        [MOVE, CARRY],
        [MOVE, CARRY, MOVE, CARRY],
        [MOVE, CARRY, MOVE, CARRY, MOVE, CARRY]
    ],

    assignMiner: function () {
        var creep = this.creep;

        var miner = creep.pos.findClosestByPath(FIND_MY_CREEPS, {
            filter: function (miner) {
                if (miner.memory.role == 'miner' && miner.memory.helpers.length < miner.memory.helpersNeeded)
                    return true;

                return false;
            }
        });

        if (miner == undefined)
            return;

        creep.memory.miner = miner.id;
        miner.memory.helpers.push(creep.id);
    },

    /**
     * @TODO: Make helpers smarter about avoiding miners, instead of just waiting till they're 5 tiles away
     * @TODO: When spawns are at .25, and extensions have >= 200, help builders before filling shit up
     */
    action: function () {
        var creep = this.creep;

        if (creep.memory.courier !== undefined && creep.memory.courier == true) {
            creep.memory.courier = false;
            return;
        }

        //If this helper isn't assigned to a miner, find one and assign him to it. If it is assigned to a miner,
        //then find that miner by his id
        if (creep.memory.miner == undefined)
            this.assignMiner();

        var miner = Game.getObjectById(creep.memory.miner);

        if (miner == null) {
            creep.suicide();
            return;
        }
        //console.log("i'm here1");
        //If we can still pick up energy, let's do that
        //console.log("miner: " + miner);
        //console.log("creep:" + creep);
        //console.log("creep.carry: (" + _.sum(creep.carry) + ") < creep.carryCapacity (" + creep.carryCapacity + ")");
        //console.log(_.sum(creep.carry) < creep.carryCapacity);
        if (_.sum(creep.carry) < creep.carryCapacity) {
            //console.log("i'm here");
            if (creep.pos.isNearTo(miner)) {
                var energy = creep.pos.findInRange(FIND_DROPPED_ENERGY, 1)[0];
                //console.log("energy: " + energy);
                creep.pickup(energy);
            }
            else {
                if (miner.memory.isNearSource)
                    creep.moveTo(miner);
            }

            return;
        }

        var target = null;
        //console.log("I'm here");
        //Okay, everything below is for dropping energy off

        if (!target) {
            //var spawn = creep.pos.findClosestByPath(FIND_MY_SPAWNS);
            var spawn = creep.room.find(FIND_STRUCTURES, {
                            filter: (structure) => {
                                return (structure.structureType == STRUCTURE_EXTENSION ||
                                structure.structureType == STRUCTURE_SPAWN) &&
                //            structure.structureType == STRUCTURE_TOWER) &&
                                (structure.energy < structure.energyCapacity);
                            }
            })
            console.log("spawn: " + spawn);
            //If we found it, set it as our target
            if (spawn)
                target = spawn;
        }
        console.log("target: " + target + " creep.pos.findPathTo: " + creep.pos.findPathTo(target));
        //Let's get the direction we want to go in
        var targetDirection = creep.pos.findPathTo(target, { ignoreCreeps: true })[0].direction;
        console.log("I'm here 3");
        //Let's look for a courier in that direction. We'll check on making sure they're the right
        //role, if they can hold any energy, if they're in range and if they're in the same direction
        var leftDir = targetDirection - 1;
        var rightDir = targetDirection + 1;

        if (leftDir < 1)
            leftDir += 8;
        if (leftDir > 8)
            leftDir -= 8;

        if (rightDir < 1)
            rightDir += 8;
        if (rightDir > 8)
            rightDir -= 8;
        console.log("I'm here 2");
        var courier = creep.pos.findClosestByPath(FIND_MY_CREEPS, {
            filter: function (possibleTarget) {
                return (
                    possibleTarget.memory.role == creep.memory.role
//					&& possibleTarget.memory.miner == creep.memory.miner
                    && _.sum(possibleTarget.carry) < possibleTarget.carryCapacity
                    && creep.pos.inRangeTo(possibleTarget, 1)
                    && (
                        creep.pos.getDirectionTo(possibleTarget) == targetDirection
                        || creep.pos.getDirectionTo(possibleTarget) == leftDir
                        || creep.pos.getDirectionTo(possibleTarget) == rightDir
                    )
                );
            }
        });
        console.log("im here");
        //If we found a courier, make that courier our new target
        if (courier !== null && !creep.pos.isNearTo(target)) {
            target = courier;
            target.memory.courier = true;
        }
        console.log("target: " + target);
        //If we're near to the target, either give it our energy or drop it
        if (creep.pos.isNearTo(target)) {
            if (_.sum(target.carry) < target.carryCapacity) {
                creep.transfer(target, RESOURCE_ENERGY);
            }
            else
                creep.drop(RESOURCE_ENERGY);
        }
        //Let's do the moving
        else {
            creep.moveTo(target);
        }
    }
};

module.exports = helper;<commit_msg>fixing miner<commit_after>/**
 * Created by truthlighting on 9/20/2016.
 */
/**
 * This guys does the other half of energy collection. The miner gets it from the source, and the helper does the
 * transportation. We don't want them just going for the nearest source, as that means that if we have more than one
 * miner, all the helpers will only go for the first miner. To counter this, we assign them to a miner the same way
 * we assign a miner to a source
 */

var helper = {
    parts: [
        [MOVE, CARRY],
        [MOVE, CARRY, MOVE, CARRY],
        [MOVE, CARRY, MOVE, CARRY, MOVE, CARRY]
    ],

    assignMiner: function () {
        var creep = this.creep;

        var miner = creep.pos.findClosestByPath(FIND_MY_CREEPS, {
            filter: function (miner) {
                if (miner.memory.role == 'miner' && miner.memory.helpers.length < miner.memory.helpersNeeded)
                    return true;

                return false;
            }
        });

        if (miner == undefined)
            return;

        creep.memory.miner = miner.id;
        miner.memory.helpers.push(creep.id);
    },

    /**
     * @TODO: Make helpers smarter about avoiding miners, instead of just waiting till they're 5 tiles away
     * @TODO: When spawns are at .25, and extensions have >= 200, help builders before filling shit up
     */
    action: function () {
        var creep = this.creep;

        if (creep.memory.courier !== undefined && creep.memory.courier == true) {
            creep.memory.courier = false;
            return;
        }

        //If this helper isn't assigned to a miner, find one and assign him to it. If it is assigned to a miner,
        //then find that miner by his id
        if (creep.memory.miner == undefined)
            this.assignMiner();

        var miner = Game.getObjectById(creep.memory.miner);

        if (miner == null) {
            creep.suicide();
            return;
        }
        //console.log("i'm here1");
        //If we can still pick up energy, let's do that
        //console.log("miner: " + miner);
        //console.log("creep:" + creep);
        //console.log("creep.carry: (" + _.sum(creep.carry) + ") < creep.carryCapacity (" + creep.carryCapacity + ")");
        //console.log(_.sum(creep.carry) < creep.carryCapacity);
        if (_.sum(creep.carry) < creep.carryCapacity) {
            //console.log("i'm here");
            if (creep.pos.isNearTo(miner)) {
                var energy = creep.pos.findInRange(FIND_DROPPED_ENERGY, 1)[0];
                //console.log("energy: " + energy);
                creep.pickup(energy);
            }
            else {
                if (miner.memory.isNearSource)
                    creep.moveTo(miner);
            }

            return;
        }

        var target = null;
        //console.log("I'm here");
        //Okay, everything below is for dropping energy off

        if (!target) {
            //var spawn = creep.pos.findClosestByPath(FIND_MY_SPAWNS);
            var spawn = creep.room.find(FIND_STRUCTURES, {
                            filter: (structure) => {
                                return (structure.structureType == STRUCTURE_EXTENSION ||
                                structure.structureType == STRUCTURE_SPAWN) &&
                //            structure.structureType == STRUCTURE_TOWER) &&
                                (structure.energy < structure.energyCapacity);
                            }
            })
            //console.log("spawn: " + spawn);
            //If we found it, set it as our target
            if (spawn)
                target = spawn;
        }
        console.log("target: " + target + " creep.pos.findPathTo: " + creep.pos.findPathTo(target));
        //Let's get the direction we want to go in
        var targetDirection = creep.pos.findPathTo(target, { ignoreCreeps: true })[0].direction;
        console.log("I'm here 3");
        //Let's look for a courier in that direction. We'll check on making sure they're the right
        //role, if they can hold any energy, if they're in range and if they're in the same direction
        var leftDir = targetDirection - 1;
        var rightDir = targetDirection + 1;

        if (leftDir < 1)
            leftDir += 8;
        if (leftDir > 8)
            leftDir -= 8;

        if (rightDir < 1)
            rightDir += 8;
        if (rightDir > 8)
            rightDir -= 8;
        console.log("I'm here 2");
        var courier = creep.pos.findClosestByPath(FIND_MY_CREEPS, {
            filter: function (possibleTarget) {
                return (
                    possibleTarget.memory.role == creep.memory.role
//					&& possibleTarget.memory.miner == creep.memory.miner
                    && _.sum(possibleTarget.carry) < possibleTarget.carryCapacity
                    && creep.pos.inRangeTo(possibleTarget, 1)
                    && (
                        creep.pos.getDirectionTo(possibleTarget) == targetDirection
                        || creep.pos.getDirectionTo(possibleTarget) == leftDir
                        || creep.pos.getDirectionTo(possibleTarget) == rightDir
                    )
                );
            }
        });
        console.log("im here");
        //If we found a courier, make that courier our new target
        if (courier !== null && !creep.pos.isNearTo(target)) {
            target = courier;
            target.memory.courier = true;
        }
        console.log("target: " + target);
        //If we're near to the target, either give it our energy or drop it
        if (creep.pos.isNearTo(target)) {
            if (_.sum(target.carry) < target.carryCapacity) {
                creep.transfer(target, RESOURCE_ENERGY);
            }
            else
                creep.drop(RESOURCE_ENERGY);
        }
        //Let's do the moving
        else {
            creep.moveTo(target);
        }
    }
};

module.exports = helper;<|endoftext|>


<commit_before>/*
 *   Heuristic AI
 */
if(typeof(require) !== 'undefined'){
	var helpers = require("./../helpers").helpers;
	var engine = require("./../engine").engine;
}

engine.ai.ufo = function(){
	var previousPosition = this.position;
	var shoot = false;

	// AI
	// Priority 1: staying alive
	// Avoid collisions
	var nearestEntityDistance = Infinity;
	var nearestEntity = null;
	var nearestStarDistance = Infinity;
	var nearestStar = null;
	var evading = false;
	// Determine the nearest object
	for(var i = 0; i < this.engine.entities.length; i++){
		if(this.engine.entities[i] != this && this.engine.entities[i].owner != this && this.engine.entities[i].position){
			var d = helpers.distance(this.position, this.engine.entities[i].position);
			if(d < nearestEntityDistance){
				nearestEntityDistance = d;
				nearestEntity = this.engine.entities[i];
			}
			if(this.engine.entities[i].type == 'star' && this.engine.entities[i].colorIndex != this.colorIndex && d < nearestStarDistance){
				nearestStarDistance = d;
				nearestStar = this.engine.entities[i];
			}
		}
	}
	if(nearestEntity && nearestEntityDistance < 3){
		var deltax = nearestEntity.position.x - this.position.x;
		var deltay = nearestEntity.position.y - this.position.y;
		var targetVector = {
		y: (deltay) < 0 ? 1 : -1,
		x: (deltax) < 0 ? 1 : -1
		};
		this.position = {
		x: this.position.x + ( targetVector.x * this.speed ) ,
		y: this.position.y + ( targetVector.y * this.speed )
		};
		evading = true;
	}
	// Priority 2:
	// Select target
	var target = null;
	if(!target){
		target = nearestStar;
	}
	if(target){
		var deltax = target.position.x - this.position.x;
		var deltay = target.position.y - this.position.y;
		var targetVector = {
		y: (deltay) < 0 ? -1 : 1,
		x: (deltax) < 0 ? -1 : 1
		};
		if(!evading){
			var movey = !(deltay < 10 && deltay > -10);
			var movex = !(deltax < 80 && deltax > -80);
			var reversex = (deltax < 60 && deltax > -60);
			this.position = {
			x: this.position.x + ( targetVector.x * (movex ? this.speed : (reversex ? -this.speed : 0 ) ) ),
			y: this.position.y + ( targetVector.y * (movey ? this.speed : 0) )
			};
		}
		if(this.position.x == previousPosition.x && this.direction != targetVector.x){
			this.direction = targetVector.x;
		}
		// Only shoot when
		// - the target is near (y)
		// - the ship is pointed in the right direction
		shoot = ((deltay < 40 && deltay > -40) && (this.direction == targetVector.x));
	}

	return {
		mousePosition: this.mousePosition,
		shoot: this.shoot
	};
};<commit_msg>Removal of dead code<commit_after>/*
 *   Heuristic AI
 */
if(typeof(require) !== 'undefined'){
	var helpers = require("./../helpers").helpers;
	var engine = require("./../engine").engine;
}

engine.ai.ufo = function(){
	var previousPosition = this.position;
	// AI
	// Priority 1: staying alive
	// Avoid collisions
	var nearestEntityDistance = Infinity;
	var nearestEntity = null;
	var nearestStarDistance = Infinity;
	var nearestStar = null;
	var evading = false;
	// Determine the nearest object
	for(var i = 0; i < this.engine.entities.length; i++){
		if(this.engine.entities[i] != this && this.engine.entities[i].owner != this && this.engine.entities[i].position){
			var d = helpers.distance(this.position, this.engine.entities[i].position);
			if(d < nearestEntityDistance){
				nearestEntityDistance = d;
				nearestEntity = this.engine.entities[i];
			}
			if(this.engine.entities[i].type == 'star' && this.engine.entities[i].colorIndex != this.colorIndex && d < nearestStarDistance){
				nearestStarDistance = d;
				nearestStar = this.engine.entities[i];
			}
		}
	}
	if(nearestEntity && nearestEntityDistance < 3){
		var deltax = nearestEntity.position.x - this.position.x;
		var deltay = nearestEntity.position.y - this.position.y;
		var targetVector = {
		y: (deltay) < 0 ? 1 : -1,
		x: (deltax) < 0 ? 1 : -1
		};
		this.position = {
		x: this.position.x + ( targetVector.x * this.speed ) ,
		y: this.position.y + ( targetVector.y * this.speed )
		};
		evading = true;
	}
	// Priority 2:
	// Select target
	var target = null;
	if(!target){
		target = nearestStar;
	}
	if(target){
		var deltax = target.position.x - this.position.x;
		var deltay = target.position.y - this.position.y;
		var targetVector = {
		y: (deltay) < 0 ? -1 : 1,
		x: (deltax) < 0 ? -1 : 1
		};
		if(!evading){
			var movey = !(deltay < 10 && deltay > -10);
			var movex = !(deltax < 80 && deltax > -80);
			var reversex = (deltax < 60 && deltax > -60);
			this.position = {
			x: this.position.x + ( targetVector.x * (movex ? this.speed : (reversex ? -this.speed : 0 ) ) ),
			y: this.position.y + ( targetVector.y * (movey ? this.speed : 0) )
			};
		}
		if(this.position.x == previousPosition.x && this.direction != targetVector.x){
			this.direction = targetVector.x;
		}
		// Only shoot when
		// - the target is near (y)
		// - the ship is pointed in the right direction
		shoot = ((deltay < 40 && deltay > -40) && (this.direction == targetVector.x));
	}

	return {
		mousePosition: this.mousePosition,
		shoot: this.shoot
	};
};<|endoftext|>


<commit_before>BusyTime = new Meteor.Collection('busy_time');
/*
 * This collection represents the moments when the detector detected some
 * presence you know where
 * Following fields are present:
 *  - room_id: mongoid of the corresponding room object
 *  - opened_at: datetime indicating when it started
 *  - closed_at: end_time on when it ended
 *  - status: "free" or "busy"
 */

// Nothing is allowed

// Limiting publishing of last month data
if (Meteor.isServer) {
    Meteor.publish("busy_times", function () {
        return BusyTime.find({
            opened_at: {
                $gte: moment().subtract(1, 'month').toDate()
            }
        });
    });
}

if (Meteor.isClient) {
    Meteor.subscribe("busy_times");
}

BusyTime.getLast = function (room_id) {
    return BusyTime.find(
        {room_id: room_id},
        {
            sort: {opened_at: -1},
            limit: 1
        }
    ).fetch()[0];
}

Room = new Meteor.Collection('room');
// room_id
// name
// Nothing allowed
// publish all
if (Meteor.isServer) {
    Meteor.publish("rooms", function () {
        return Room.find();
    });
}

if (Meteor.isClient) {
    Meteor.subscribe("rooms");
}
<commit_msg>Adding stats collection<commit_after>BusyTime = new Meteor.Collection('busy_time');
/*
 * This collection represents the moments when the detector detected some
 * presence you know where
 * Following fields are present:
 *  - room_id: mongoid of the corresponding room object
 *  - opened_at: datetime indicating when it started
 *  - closed_at: end_time on when it ended
 *  - status: "free" or "busy"
 */

// Nothing is allowed

// Limiting publishing of last month data
if (Meteor.isServer) {
    Meteor.publish("busy_times", function () {
        return BusyTime.find({
            opened_at: {
                $gte: moment().subtract(1, 'month').toDate()
            }
        });
    });
}

if (Meteor.isClient) {
    Meteor.subscribe("busy_times");
}

BusyTime.getLast = function (room_id) {
    return BusyTime.find(
        {room_id: room_id},
        {
            sort: {opened_at: -1},
            limit: 1
        }
    ).fetch()[0];
}

Room = new Meteor.Collection('room');
// room_id
// name
// Nothing allowed
// publish all
if (Meteor.isServer) {
    Meteor.publish("rooms", function () {
        return Room.find();
    });
}

if (Meteor.isClient) {
    Meteor.subscribe("rooms");
}

Stats = new Meteor.Collection('stats');
// room_id
// name
// text
// value

// Nothing allowed
// publish all
if (Meteor.isServer) {
    Meteor.publish("stats", function () {
        return Stats.find();
    });
}

if (Meteor.isClient) {
    Meteor.subscribe("stats");
}
<|endoftext|>


<commit_before>import { Router } from 'express';
import parserBody from '../lib/parser-body.js';
import Meal from '../model/meal.js';
import { bearerAuth } from '../lib/parser-auth.js';

const mealRouter = module.exports = new Router();

mealRouter.post('/api/meals', bearerAuth, parserBody, (req, res, next) => {
  req.body.userId = req.user._id;
  new Meal(req.body)
    .save()
    .then(meal => res.status(201).json(meal))
    .catch(next);
});

mealRouter.put('/api/meals/:id', bearerAuth, parserBody, (req, res, next) => {
  let options = {
    new: true,
    runValidators: true,
  };
  req.body.userId = req.user._id;
  Meal.findOneAndUpdate(req.body.userId, req.body, options)
    .then(meal => res.status(202).json(meal))
    .catch(next);
});

mealRouter.get('/api/meals/:id', (req, res, next) => {
  Meal.findOne({ userId: req.params.id })
    .then(meal => {
      res.json(meal);
    })
    .catch(next);
});

mealRouter.delete('/api/meals:id', (req, res, next) => {
  Meal.findOneAndDelete({ userId: req. params.id })
    .then(() => {
      res.setStatus(204));
    })
    .catch(next);
})
<commit_msg>Removed extra paren<commit_after>import { Router } from 'express';
import parserBody from '../lib/parser-body.js';
import Meal from '../model/meal.js';
import { bearerAuth } from '../lib/parser-auth.js';

const mealRouter = module.exports = new Router();

mealRouter.post('/api/meals', bearerAuth, parserBody, (req, res, next) => {
  req.body.userId = req.user._id;
  new Meal(req.body)
    .save()
    .then(meal => res.status(201).json(meal))
    .catch(next);
});

mealRouter.put('/api/meals/:id', bearerAuth, parserBody, (req, res, next) => {
  let options = {
    new: true,
    runValidators: true,
  };
  req.body.userId = req.user._id;
  Meal.findOneAndUpdate(req.body.userId, req.body, options)
    .then(meal => res.status(202).json(meal))
    .catch(next);
});

mealRouter.get('/api/meals/:id', (req, res, next) => {
  Meal.findOne({ userId: req.params.id })
    .then(meal => {
      res.json(meal);
    })
    .catch(next);
});

mealRouter.delete('/api/meals:id', (req, res, next) => {
  Meal.findOneAndDelete({ userId: req. params.id })
    .then(() => {
      res.setStatus(204);
    })
    .catch(next);
})
<|endoftext|>


<commit_before>var _ = require('lodash');
var mongoose = require('mongoose');
var Comment = require('../../models/comment');
var Project = require('../../models/project');
var Task = require('../../models/task');

var notMember = new Error('Not member');
notMember.status = 400;
var forbidden = new Error('Forbidden');
forbidden.status = 403;
var notFound = new Error('Not Found');
notFound.status = 404;
var alreadyJoined = new Error('Already joined');
alreadyJoined.status = 409;

function deepPopulateComment(comment, next) {
  Comment
  .populate(comment, 'user task', function(err, _commentWithTask) {
    if (err) {
      return next(err);
    }
    Comment.populate(_commentWithTask, {
      path: 'task.project',
      model: 'Project'
    }, function(err, _commentWithProject) {
      if (err) {
        return next(err);
      }
      Comment.populate(_commentWithProject, {
        path: 'task.project.owner task.project.members',
        model: 'User'
      }, function(err, comment) {
        if (err) {
          return next(err);
        }
        return next(null, comment);
      });
    });
  });
}

function isTaskInProject(task, project_id) {
  if (!project_id) return true;
  return task.project._id == project_id;
}

function isProjectVisible(project, user) {
  return project.isPublic || project.owner.username === user.username ||
    _.some(project.members, 'username', user.username);
}

module.exports.addComment = function(req, res, task_id, project_id, next) {
  Task
    .findOne({ _id: task_id, project: project_id })
    .populate('owner assignedUsers project')
    .exec(function(err, _task) {
      if (err) {
        return next(err);
      }
      Task.populate(_task, {
        path: 'project.owner project.members',
        model: 'User',
      }, function(err, task) {
        if (err) {
          return next(err);
        }
        if (!isProjectVisible(task.project, req.user)) {
          return next(forbidden);
        }
        var comment = new Comment(req.body.comment);
        comment.task = task._id;
        comment.user = req.user._id;
        comment.save(function(err) {
          if (err) {
            return next(err);
          }
          Comment.populate(comment, 'user', function(err, comment) {
            comment.task = task;
            return res.status(201).json({ comment: comment });
          });
        });
      });
    });
};

module.exports.getComments = function(req, res, task_id, project_id, next) {
  var filter = {};
  if (task_id) filter.task = task_id;
  Comment
    .find(filter, function(err, comments) {
      deepPopulateComment(comments, function(err, comments) {
        comments = _.filter(comments, function(comment) {
          if (project_id && comment.task.project._id != project_id) {
            return false;
          }
          return isProjectVisible(comment.task.project, req.user);
        });
        return res.json({ comments: comments });
      });
    });
};

module.exports.getComment = function(req, res, comment_id, task_id, project_id, next) {
  var filter = { _id: comment_id };
  if (task_id) filter.task = task_id;
  Comment
    .findOne(filter, function(err, _comment) {
      if (err) {
        return next(err);
      }
      if (!_comment) {
        return next(notFound);
      }
      deepPopulateComment(_comment, function(err, comment) {
        if (!isTaskInProject(comment.task, project_id)) {
          return next(notFound);
        }
        if (!isProjectVisible(comment.task.project, req.user)) {
          return next(forbidden);
        }
        return res.json({ comment: comment });
      });
    });
};

module.exports.updateComment = function(req, res, comment_id, task_id, project_id, next) {
  var filter = { _id: comment_id };
  if (task_id) filter.task = task_id;
  Comment
    .findOne(filter, function(err, _comment) {
      if (err) {
        return next(err);
      }
      if (!_comment) {
        return next(notFound);
      }
      deepPopulateComment(_comment, function(err, comment) {
        if (!isTaskInProject(comment.task, project_id)) {
          return next(notFound);
        }
        if (!isProjectVisible(comment.task.project, req.user) ||
            (comment.task.project.owner.username !== req.user.username &&
             comment.user.username !== req.user.username)) {
          return next(forbidden);
        }
        comment = _.extend(comment, req.body.comment);
        comment.save(function(err) {
          if (err) {
            return next(err);
          }
          deepPopulateComment(comment, function(err, comment) {
            if (err) {
              return next(err);
            }
            return res.json({ comment: comment });
          });
        });
      });
    });
};

module.exports.deleteComment = function(req, res, comment_id, task_id, project_id, next) {
  var filter = { _id: comment_id };
  if (task_id) filter.task = task_id;
  Comment
    .findOne(filter, function(err, _comment) {
      if (err) {
        return next(err);
      }
      if (!_comment) {
        return next(notFound);
      }
      deepPopulateComment(_comment, function(err, comment) {
        if (!isTaskInProject(comment.task, project_id)) {
          return next(notFound);
        }
        if (!isProjectVisible(comment.task.project, req.user) ||
            (comment.task.project.owner.username !== req.user.username &&
             comment.user.username !== req.user.username)) {
          return next(forbidden);
        }
        comment.remove(function(err) {
          if (err) {
            return next(err);
          }
          return res.sendStatus(204);
        });
      });
    });
};

<commit_msg>populate users of tasks of comments<commit_after>var _ = require('lodash');
var mongoose = require('mongoose');
var Comment = require('../../models/comment');
var Project = require('../../models/project');
var Task = require('../../models/task');

var notMember = new Error('Not member');
notMember.status = 400;
var forbidden = new Error('Forbidden');
forbidden.status = 403;
var notFound = new Error('Not Found');
notFound.status = 404;
var alreadyJoined = new Error('Already joined');
alreadyJoined.status = 409;

function deepPopulateComment(comment, next) {
  Comment
    .populate(comment, 'user task', function(err, _commentWithTask) {
      if (err) {
        return next(err);
      }
      Comment.populate(_commentWithTask, {
        path: 'task.project',
        model: 'Project'
      }, function(err, _commentWithProject) {
        if (err) {
          return next(err);
        }
        Comment.populate(_commentWithProject, {
          path: 'task.project.owner task.project.members task.assignedUsers task.owner',
          model: 'User'
        }, function(err, comment) {
          if (err) {
            return next(err);
          }
          return next(null, comment);
        });
      });
    });
}

function isTaskInProject(task, project_id) {
  if (!project_id) return true;
  return task.project._id == project_id;
}

function isProjectVisible(project, user) {
  return project.isPublic || project.owner.username === user.username ||
    _.some(project.members, 'username', user.username);
}

module.exports.addComment = function(req, res, task_id, project_id, next) {
  Task
    .findOne({ _id: task_id, project: project_id })
    .populate('owner assignedUsers project')
    .exec(function(err, _task) {
      if (err) {
        return next(err);
      }
      Task.populate(_task, {
        path: 'project.owner project.members',
        model: 'User',
      }, function(err, task) {
        if (err) {
          return next(err);
        }
        if (!isProjectVisible(task.project, req.user)) {
          return next(forbidden);
        }
        var comment = new Comment(req.body.comment);
        comment.task = task._id;
        comment.user = req.user._id;
        comment.save(function(err) {
          if (err) {
            return next(err);
          }
          Comment.populate(comment, 'user', function(err, comment) {
            comment.task = task;
            return res.status(201).json({ comment: comment });
          });
        });
      });
    });
};

module.exports.getComments = function(req, res, task_id, project_id, next) {
  var filter = {};
  if (task_id) filter.task = task_id;
  Comment
    .find(filter, function(err, comments) {
      deepPopulateComment(comments, function(err, comments) {
        comments = _.filter(comments, function(comment) {
          if (project_id && comment.task.project._id != project_id) {
            return false;
          }
          return isProjectVisible(comment.task.project, req.user);
        });
        return res.json({ comments: comments });
      });
    });
};

module.exports.getComment = function(req, res, comment_id, task_id, project_id, next) {
  var filter = { _id: comment_id };
  if (task_id) filter.task = task_id;
  Comment
    .findOne(filter, function(err, _comment) {
      if (err) {
        return next(err);
      }
      if (!_comment) {
        return next(notFound);
      }
      deepPopulateComment(_comment, function(err, comment) {
        if (!isTaskInProject(comment.task, project_id)) {
          return next(notFound);
        }
        if (!isProjectVisible(comment.task.project, req.user)) {
          return next(forbidden);
        }
        return res.json({ comment: comment });
      });
    });
};

module.exports.updateComment = function(req, res, comment_id, task_id, project_id, next) {
  var filter = { _id: comment_id };
  if (task_id) filter.task = task_id;
  Comment
    .findOne(filter, function(err, _comment) {
      if (err) {
        return next(err);
      }
      if (!_comment) {
        return next(notFound);
      }
      deepPopulateComment(_comment, function(err, comment) {
        if (!isTaskInProject(comment.task, project_id)) {
          return next(notFound);
        }
        if (!isProjectVisible(comment.task.project, req.user) ||
            (comment.task.project.owner.username !== req.user.username &&
             comment.user.username !== req.user.username)) {
          return next(forbidden);
        }
        comment = _.extend(comment, req.body.comment);
        comment.save(function(err) {
          if (err) {
            return next(err);
          }
          deepPopulateComment(comment, function(err, comment) {
            if (err) {
              return next(err);
            }
            return res.json({ comment: comment });
          });
        });
      });
    });
};

module.exports.deleteComment = function(req, res, comment_id, task_id, project_id, next) {
  var filter = { _id: comment_id };
  if (task_id) filter.task = task_id;
  Comment
    .findOne(filter, function(err, _comment) {
      if (err) {
        return next(err);
      }
      if (!_comment) {
        return next(notFound);
      }
      deepPopulateComment(_comment, function(err, comment) {
        if (!isTaskInProject(comment.task, project_id)) {
          return next(notFound);
        }
        if (!isProjectVisible(comment.task.project, req.user) ||
            (comment.task.project.owner.username !== req.user.username &&
             comment.user.username !== req.user.username)) {
          return next(forbidden);
        }
        comment.remove(function(err) {
          if (err) {
            return next(err);
          }
          return res.sendStatus(204);
        });
      });
    });
};

<|endoftext|>


<commit_before>/**
 * React Starter Kit (https://www.reactstarterkit.com/)
 *
 * Copyright © 2014-present Kriasoft, LLC. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */

import path from 'path';
import fetch from 'node-fetch';
import { spawn } from './lib/cp';
import { makeDir } from './lib/fs';
import run from './run';

// GitHub Pages
const remote = {
  name: 'github',
  url: 'https://github.com/kevinchau321/TReactr.git',
  branch: 'gh-pages',
  website: 'https://kevinchau321.github.io/TReactr/',
  static: true,
};

// Azure Web Apps
// const remote = {
//   name: 'azure',
//   url: 'https://<user>@<app>.scm.azurewebsites.net:443/<app>.git',
//   branch: 'master',
//   website: `http://<app>.azurewebsites.net`,
// };

const options = {
  cwd: path.resolve(__dirname, '../build', remote.static ? 'public' : ''),
  stdio: ['ignore', 'inherit', 'inherit'],
};

/**
 * Deploy the contents of the `/build` folder to a remote server via Git.
 */
async function deploy() {
  // Initialize a new repository
  await makeDir('build/public');
  await spawn('git', ['init', '--quiet'], options);

  // Changing a remote's URL
  let isRemoteExists = false;
  try {
    await spawn('git', ['config', '--get', `remote.${remote.name}.url`], options);
    isRemoteExists = true;
  } catch (error) {
    /* skip */
  }
  await spawn('git', ['remote', isRemoteExists ? 'set-url' : 'add', remote.name, remote.url], options);

  // Fetch the remote repository if it exists
  let isRefExists = false;
  try {
    await spawn('git', ['ls-remote', '--exit-code', remote.url, remote.branch], options);
    isRefExists = true;
  } catch (error) {
    /* skip */
  }
  if (isRefExists) {
    await spawn('git', ['fetch', remote.name], options);
    await spawn('git', ['reset', `${remote.name}/${remote.branch}`, '--hard'], options);
    await spawn('git', ['clean', '--force'], options);
  }

  // Build the project in RELEASE mode which
  // generates optimized and minimized bundles
  process.argv.push('--release');
  if (remote.static) process.argv.push('--static');
  await run(require('./build').default);

  // Push the contents of the build folder to the remote server via Git
  await spawn('git', ['add', '.', '--all'], options);
  await spawn('git', ['commit', '--message', `Update ${new Date().toISOString()}`], options);
  await spawn('git', ['push', remote.name, `master:${remote.branch}`, '--force', '--set-upstream'], options);

  // Check if the site was successfully deployed
  const response = await fetch(remote.website);
  console.log(`${remote.website} => ${response.status} ${response.statusText}`);
}

export default deploy;
<commit_msg>added heroku deployment<commit_after>/**
 * React Starter Kit (https://www.reactstarterkit.com/)
 *
 * Copyright © 2014-present Kriasoft, LLC. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */

import path from 'path';
import fetch from 'node-fetch';
import { spawn } from './lib/cp';
import { makeDir } from './lib/fs';
import run from './run';

// GitHub Pages
const remote = {
  name: 'github',
  url: 'https://github.com/kevinchau321/TReactr.git',
  branch: 'heroku',
  website: 'https://treactr.herokuapp.com/',
  static: true,
};

// Azure Web Apps
// const remote = {
//   name: 'azure',
//   url: 'https://<user>@<app>.scm.azurewebsites.net:443/<app>.git',
//   branch: 'master',
//   website: `http://<app>.azurewebsites.net`,
// };

const options = {
  cwd: path.resolve(__dirname, '../build', remote.static ? 'public' : ''),
  stdio: ['ignore', 'inherit', 'inherit'],
};

/**
 * Deploy the contents of the `/build` folder to a remote server via Git.
 */
async function deploy() {
  // Initialize a new repository
  await makeDir('build/public');
  await spawn('git', ['init', '--quiet'], options);

  // Changing a remote's URL
  let isRemoteExists = false;
  try {
    await spawn('git', ['config', '--get', `remote.${remote.name}.url`], options);
    isRemoteExists = true;
  } catch (error) {
    /* skip */
  }
  await spawn('git', ['remote', isRemoteExists ? 'set-url' : 'add', remote.name, remote.url], options);

  // Fetch the remote repository if it exists
  let isRefExists = false;
  try {
    await spawn('git', ['ls-remote', '--exit-code', remote.url, remote.branch], options);
    isRefExists = true;
  } catch (error) {
    /* skip */
  }
  if (isRefExists) {
    await spawn('git', ['fetch', remote.name], options);
    await spawn('git', ['reset', `${remote.name}/${remote.branch}`, '--hard'], options);
    await spawn('git', ['clean', '--force'], options);
  }

  // Build the project in RELEASE mode which
  // generates optimized and minimized bundles
  process.argv.push('--release');
  if (remote.static) process.argv.push('--static');
  await run(require('./build').default);

  // Push the contents of the build folder to the remote server via Git
  await spawn('git', ['add', '.', '--all'], options);
  await spawn('git', ['commit', '--message', `Update ${new Date().toISOString()}`], options);
  await spawn('git', ['push', remote.name, `master:${remote.branch}`, '--force', '--set-upstream'], options);

  // Check if the site was successfully deployed
  const response = await fetch(remote.website);
  console.log(`${remote.website} => ${response.status} ${response.statusText}`);
}

export default deploy;
<|endoftext|>