<commit_before>/*
 * Copyright (C) 2014-2014 52°North Initiative for Geospatial Open Source
 * Software GmbH
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 *
 * If the program is linked with libraries which are licensed under one of
 * the following licenses, the combination of the program with the linked
 * library is not considered a "derivative work" of the program:
 *
 *     - Apache License, version 2.0
 *     - Apache Software License, version 1.0
 *     - GNU Lesser General Public License, version 3
 *     - Mozilla Public License, versions 1.0, 1.1 and 2.0
 *     - Common Development and Distribution License (CDDL), version 1.0
 *
 * Therefore the distribution of the program linked with libraries licensed
 * under the aforementioned licenses, is permitted by the copyright holders
 * if the distribution is compliant with both the GNU General Public
 * License version 2 and the aforementioned licenses.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 */
var Map = {

	timeseriesCol : [],

	init : function() {
		$(document).ready(function() {
			$('[data-action="provider"]').click(function() {
				Map.openProviderList();
			});
			$('[data-action="locate"]').click(function() {
				Map.locateUser();
			});
		});
		if ($("#map").length > 0) {
			var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png', cloudmadeAttribution = '© OpenStreetMap & Contributors', cloudmade = L
					.tileLayer(cloudmadeUrl, {
						maxZoom : 17,
						attribution : false
					}), latlng = L.latLng(50, 10);
			L.Icon.Default.imagePath = 'images';

			this.map = L.map('map', {
				center : latlng,
				zoom : 5,
				layers : [ cloudmade ]
			});
		}

		// load stations for default provider
		this.loadStations();

		// locate user methods
		this.map.on('locationfound', this.onLocationFound);
		this.map.on('locationerror', this.onLocationError);

		EventManager.subscribe("resetStatus", $.proxy(this.loadStations, this));
		EventManager.subscribe("timeseries:showInMap", $.proxy(this.showTsInMap, this));
	},

	/*----- stations -----*/
	loadStations : function() {
		Rest.stations(null, {
			service : Status.get('provider')
		}).done($.proxy(this.createStationMarker, this));
		// load phenomena list
		Rest.phenomena(null, {
			service : Status.get('provider')
		}).done($.proxy(this.fillPhenomenaList, this));
	},

	createStationMarker : function(results) {
		if (this.stationMarkers != null) {
			this.map.removeLayer(this.stationMarkers);
		}
		if (results.length > 0) {
			var firstElemCoord = results[0].geometry.coordinates;
			var topmost = firstElemCoord[1];
			var bottommost = firstElemCoord[1];
			var leftmost = firstElemCoord[0];
			var rightmost = firstElemCoord[0];
			var markers = this.stationMarkers = new L.MarkerClusterGroup();
			that = this;
			$.each(results, function(n, elem) {
				var geom = elem.geometry.coordinates;
				if (!isNaN(geom[0]) || !isNaN(geom[1])) {
					if (geom[0] > rightmost) {
						rightmost = geom[0];
					}
					if (geom[0] < leftmost) {
						leftmost = geom[0];
					}
					if (geom[1] > topmost) {
						topmost = geom[1];
					}
					if (geom[1] < bottommost) {
						bottommost = geom[1];
					}
//					var marker = new L.circleMarker([ geom[1], geom[0] ], {
//						id : elem.properties.id,
//						fillColor: "#000",
//					    color: "#000",
//					    opacity: 1,
//					    weight: 1,
//					    fillOpacity: 0.2
//					});
					var marker = new L.marker([ geom[1], geom[0] ], {
						id : elem.properties.id,
					});
					marker.on('click', that.markerClicked);
					markers.addLayer(marker);
				}
			});
			this.map.addLayer(markers);
			this.map.fitBounds([
					[ parseFloat(bottommost), parseFloat(leftmost) ],
					[ parseFloat(topmost), parseFloat(rightmost) ] ]);
		}
	},

	markerClicked : function(marker) {
		Rest.stations(marker.target.options.id).done(function(results) {
			var tsList = $.map(results.properties.timeseries, function (elem, tsId) {
				if (Map.selectedPhenomenon == null || Map.selectedPhenomenon == elem.phenomenon.id) {
					return tsId;
				}
			});
			if (tsList.length == 1) {
				if (Map.timeseriesCol[tsList[0]] == null) {
					Rest.timeseriesById(tsList[0]).done(function(timeseries) {
						Map.addTimeseries(timeseries);
					});
				} else {
					Map.addTimeseries(Map.timeseriesCol[tsList[0]]);
				}
			} else {
				var phenomena = {};
				$.each(results.properties.timeseries, function(id, elem) {
					if(!phenomena.hasOwnProperty(elem.phenomenon.id)) {
						phenomena[elem.phenomenon.id] = {};
						phenomena[elem.phenomenon.id].timeseries = [];
						phenomena[elem.phenomenon.id].label = elem.phenomenon.label;
					}
					phenomena[elem.phenomenon.id].timeseries.push({
						id : id,
						selected : Status.hasTimeseriesWithId(id),
						procedure : elem.procedure.label
					});
				});
				Modal.show("station", {
					"name" : results.properties.label,
					"phenomena" : $.map(phenomena, function(id, elem) {
						return id;
					})
				});
				$('#confirmTimeseriesSelection').on('click', function(){
					$.each($('.tsItem').has(':checked'), function(id, elem) {
						Map.addTimeseries(Map.timeseriesCol[$(this).data('id')]);
					});
				});
				$.each(results.properties.timeseries, function(id) {
					if (Map.timeseriesCol[id] == null) {
						Rest.timeseriesById(id).done(function(timeseries) {
							Map.addTimeseriesToList(timeseries);
						});
					} else {
						Map.addTimeseriesToList(Map.timeseriesCol[id]);
					}
				});
			}
		});
	},

	addTimeseriesToList : function(timeseries) {
		$('[data-id=' + timeseries.getId() + ']').addClass('loaded').find(':input').prop('disabled', false);
		Map.timeseriesCol[timeseries.getId()] = timeseries;
	},

	addTimeseries : function(timeseries) {
		Pages.navigateToChart();
		TimeSeriesController.addTS(timeseries);
	},

	/*----- stations -----*/
	fillPhenomenaList : function(results) {
		$('.phenomena-entry').empty();
		this.createDefaultPhenomenaEntry();
		$.each(results, $.proxy(function(index, elem) {
			var html = this.createPhenomenaEntry(elem);
			$('.phenomena-entry').append(html);
			$('[data-id=' + elem.id + ']').click($.proxy(function(event){
				$('.phenomena-entry').find('.selected').removeClass('selected');
				$('[data-id=' + elem.id + ']').find('.item').addClass('selected');
				this.selectedPhenomenon = elem.id;
				Rest.stations(null, {
					service : Status.get('provider'),
					phenomenon : elem.id
				}).done($.proxy(function(result){
					$('.phenomena').toggleClass('active');
					this.createStationMarker(result);
				}, this));
			}, this));
		}, this));
	},

	createPhenomenaEntry : function(phenomenon) {
		this.selectedPhenomenon = null;
		var html = Template.createHtml("phenomenon-entry", {
			id : phenomenon.id,
			label : phenomenon.label
		});
		return html;
	},

	createDefaultPhenomenaEntry : function() {
		$('.phenomena-entry').append(this.createPhenomenaEntry({
			id : "all",
			label : "All phenomenons"
		}));
		$('[data-id=all]').click($.proxy(function(event, bla){
			$('.phenomena-entry').find('.selected').removeClass('selected');
			$('[data-id=all]').find('.item').addClass('selected');
			Map.loadStations();
		}));
		$('[data-id=all]').find('.item').addClass('selected');
	},

	/*----- provider list -----*/
	openProviderList : function() {
		Rest.services().done(this.createProviderList);
	},

	createProviderList : function(results) {
		var data = {
			"providers" : $.map(results, function(elem) {
				var provider = Settings.providerBlackList[elem.id];
				if (provider == null || !provider) {
					return {
						"name" : elem.label,
						"version" : elem.version,
						"stations" : elem.quantities.stations,
						"timeseries" : elem.quantities.timeseries,
						"url" : elem.serviceUrl,
						"id" : elem.id,
						"selected" : Status.get('provider') == elem.id,
						"type" : elem.type
					};
				}
			})
		};
		Modal.show('providers', data);
		$('.providerItem').on('click', function() {
			var id = $(this).data('id');
			Status.set('provider', id);
			Map.loadStations();
			Modal.hide();
		});
	},

	/*----- locate user -----*/
	locateUser : function() {
		this.map.locate({
			setView : true,
			maxZoom : Settings.zoom
		});
	},

	onLocationFound : function(e) {
//		if (Map.location != null) {
//			this.removeLayer(Map.location);
//		}
//		Map.location = new L.marker(e.latlng, {
//			draggable : false
//		});
//
//		this.addLayer(Map.location);
		var popup = L.popup().setLatLng(e.latlng).setContent('
Here is your current location
');
		Map.map.openPopup(popup);
	},

	onLocationError : function(e) {
		alert(e.message);
	},

	showTsInMap : function(event, ts) {
		Pages.navigateToMap();
		var coords = ts.getMetadata().station.geometry.coordinates,
		pos = L.latLng(coords[1], coords[0]),
		popup = L.popup().setLatLng(pos);
		var content = Template.createHtml("station-popup", {
			station : ts.getMetadata().station.properties.label,
			timeseries : ts.getMetadata().label,
			service : ts.getMetadata().parameters.service.label
		});
		popup.setContent(content);
		popup.openOn(Map.map);
		Map.map.setZoom(Settings.zoom);
		Map.map.panTo(pos);
	}
};<commit_msg>small css class fix<commit_after>/*
 * Copyright (C) 2014-2014 52°North Initiative for Geospatial Open Source
 * Software GmbH
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * by the Free Software Foundation.
 *
 * If the program is linked with libraries which are licensed under one of
 * the following licenses, the combination of the program with the linked
 * library is not considered a "derivative work" of the program:
 *
 *     - Apache License, version 2.0
 *     - Apache Software License, version 1.0
 *     - GNU Lesser General Public License, version 3
 *     - Mozilla Public License, versions 1.0, 1.1 and 2.0
 *     - Common Development and Distribution License (CDDL), version 1.0
 *
 * Therefore the distribution of the program linked with libraries licensed
 * under the aforementioned licenses, is permitted by the copyright holders
 * if the distribution is compliant with both the GNU General Public
 * License version 2 and the aforementioned licenses.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
 * Public License for more details.
 */
var Map = {

	timeseriesCol : [],

	init : function() {
		$(document).ready(function() {
			$('[data-action="provider"]').click(function() {
				Map.openProviderList();
			});
			$('[data-action="locate"]').click(function() {
				Map.locateUser();
			});
		});
		if ($("#map").length > 0) {
			var cloudmadeUrl = 'http://{s}.tile.cloudmade.com/BC9A493B41014CAABB98F0471D759707/997/256/{z}/{x}/{y}.png', cloudmadeAttribution = '© OpenStreetMap & Contributors', cloudmade = L
					.tileLayer(cloudmadeUrl, {
						maxZoom : 17,
						attribution : false
					}), latlng = L.latLng(50, 10);
			L.Icon.Default.imagePath = 'images';

			this.map = L.map('map', {
				center : latlng,
				zoom : 5,
				layers : [ cloudmade ]
			});
		}

		// load stations for default provider
		this.loadStations();

		// locate user methods
		this.map.on('locationfound', this.onLocationFound);
		this.map.on('locationerror', this.onLocationError);

		EventManager.subscribe("resetStatus", $.proxy(this.loadStations, this));
		EventManager.subscribe("timeseries:showInMap", $.proxy(this.showTsInMap, this));
	},

	/*----- stations -----*/
	loadStations : function() {
		Rest.stations(null, {
			service : Status.get('provider')
		}).done($.proxy(this.createStationMarker, this));
		// load phenomena list
		Rest.phenomena(null, {
			service : Status.get('provider')
		}).done($.proxy(this.fillPhenomenaList, this));
	},

	createStationMarker : function(results) {
		if (this.stationMarkers != null) {
			this.map.removeLayer(this.stationMarkers);
		}
		if (results.length > 0) {
			var firstElemCoord = results[0].geometry.coordinates;
			var topmost = firstElemCoord[1];
			var bottommost = firstElemCoord[1];
			var leftmost = firstElemCoord[0];
			var rightmost = firstElemCoord[0];
			var markers = this.stationMarkers = new L.MarkerClusterGroup();
			that = this;
			$.each(results, function(n, elem) {
				var geom = elem.geometry.coordinates;
				if (!isNaN(geom[0]) || !isNaN(geom[1])) {
					if (geom[0] > rightmost) {
						rightmost = geom[0];
					}
					if (geom[0] < leftmost) {
						leftmost = geom[0];
					}
					if (geom[1] > topmost) {
						topmost = geom[1];
					}
					if (geom[1] < bottommost) {
						bottommost = geom[1];
					}
//					var marker = new L.circleMarker([ geom[1], geom[0] ], {
//						id : elem.properties.id,
//						fillColor: "#000",
//					    color: "#000",
//					    opacity: 1,
//					    weight: 1,
//					    fillOpacity: 0.2
//					});
					var marker = new L.marker([ geom[1], geom[0] ], {
						id : elem.properties.id,
					});
					marker.on('click', that.markerClicked);
					markers.addLayer(marker);
				}
			});
			this.map.addLayer(markers);
			this.map.fitBounds([
					[ parseFloat(bottommost), parseFloat(leftmost) ],
					[ parseFloat(topmost), parseFloat(rightmost) ] ]);
		}
	},

	markerClicked : function(marker) {
		Rest.stations(marker.target.options.id).done(function(results) {
			var tsList = $.map(results.properties.timeseries, function (elem, tsId) {
				if (Map.selectedPhenomenon == null || Map.selectedPhenomenon == elem.phenomenon.id) {
					return tsId;
				}
			});
			if (tsList.length == 1) {
				if (Map.timeseriesCol[tsList[0]] == null) {
					Rest.timeseriesById(tsList[0]).done(function(timeseries) {
						Map.addTimeseries(timeseries);
					});
				} else {
					Map.addTimeseries(Map.timeseriesCol[tsList[0]]);
				}
			} else {
				var phenomena = {};
				$.each(results.properties.timeseries, function(id, elem) {
					if(!phenomena.hasOwnProperty(elem.phenomenon.id)) {
						phenomena[elem.phenomenon.id] = {};
						phenomena[elem.phenomenon.id].timeseries = [];
						phenomena[elem.phenomenon.id].label = elem.phenomenon.label;
					}
					phenomena[elem.phenomenon.id].timeseries.push({
						id : id,
						selected : Status.hasTimeseriesWithId(id),
						procedure : elem.procedure.label
					});
				});
				Modal.show("station", {
					"name" : results.properties.label,
					"phenomena" : $.map(phenomena, function(id, elem) {
						return id;
					})
				});
				$('#confirmTimeseriesSelection').on('click', function(){
					$.each($('.tsItem').has(':checked'), function(id, elem) {
						Map.addTimeseries(Map.timeseriesCol[$(this).data('id')]);
					});
				});
				$.each(results.properties.timeseries, function(id) {
					if (Map.timeseriesCol[id] == null) {
						Rest.timeseriesById(id).done(function(timeseries) {
							Map.addTimeseriesToList(timeseries);
						});
					} else {
						Map.addTimeseriesToList(Map.timeseriesCol[id]);
					}
				});
			}
		});
	},

	addTimeseriesToList : function(timeseries) {
		$('[data-id=' + timeseries.getId() + ']').addClass('loaded').find(':input').prop('disabled', false);
		Map.timeseriesCol[timeseries.getId()] = timeseries;
	},

	addTimeseries : function(timeseries) {
		Pages.navigateToChart();
		TimeSeriesController.addTS(timeseries);
	},

	/*----- stations -----*/
	fillPhenomenaList : function(results) {
		$('.phenomena-entry').empty();
		this.createDefaultPhenomenaEntry();
		$.each(results, $.proxy(function(index, elem) {
			var html = this.createPhenomenaEntry(elem);
			$('.phenomena-entry').append(html);
			$('[data-id=' + elem.id + ']').click($.proxy(function(event){
				$('.phenomena-entry').find('.selected').removeClass('selected');
				$('[data-id=' + elem.id + ']').find('.item').addClass('selected');
				this.selectedPhenomenon = elem.id;
				Rest.stations(null, {
					service : Status.get('provider'),
					phenomenon : elem.id
				}).done($.proxy(function(result){
					$('.phenomena').removeClass('active');
					this.createStationMarker(result);
				}, this));
			}, this));
		}, this));
	},

	createPhenomenaEntry : function(phenomenon) {
		this.selectedPhenomenon = null;
		var html = Template.createHtml("phenomenon-entry", {
			id : phenomenon.id,
			label : phenomenon.label
		});
		return html;
	},

	createDefaultPhenomenaEntry : function() {
		$('.phenomena-entry').append(this.createPhenomenaEntry({
			id : "all",
			label : "All phenomenons"
		}));
		$('[data-id=all]').click($.proxy(function(event, bla){
			$('.phenomena-entry').find('.selected').removeClass('selected');
			$('[data-id=all]').find('.item').addClass('selected');
			Map.loadStations();
		}));
		$('[data-id=all]').find('.item').addClass('selected');
	},

	/*----- provider list -----*/
	openProviderList : function() {
		Rest.services().done(this.createProviderList);
	},

	createProviderList : function(results) {
		var data = {
			"providers" : $.map(results, function(elem) {
				var provider = Settings.providerBlackList[elem.id];
				if (provider == null || !provider) {
					return {
						"name" : elem.label,
						"version" : elem.version,
						"stations" : elem.quantities.stations,
						"timeseries" : elem.quantities.timeseries,
						"url" : elem.serviceUrl,
						"id" : elem.id,
						"selected" : Status.get('provider') == elem.id,
						"type" : elem.type
					};
				}
			})
		};
		Modal.show('providers', data);
		$('.providerItem').on('click', function() {
			var id = $(this).data('id');
			Status.set('provider', id);
			Map.loadStations();
			Modal.hide();
		});
	},

	/*----- locate user -----*/
	locateUser : function() {
		this.map.locate({
			setView : true,
			maxZoom : Settings.zoom
		});
	},

	onLocationFound : function(e) {
//		if (Map.location != null) {
//			this.removeLayer(Map.location);
//		}
//		Map.location = new L.marker(e.latlng, {
//			draggable : false
//		});
//
//		this.addLayer(Map.location);
		var popup = L.popup().setLatLng(e.latlng).setContent('
Here is your current location
');
		Map.map.openPopup(popup);
	},

	onLocationError : function(e) {
		alert(e.message);
	},

	showTsInMap : function(event, ts) {
		Pages.navigateToMap();
		var coords = ts.getMetadata().station.geometry.coordinates,
		pos = L.latLng(coords[1], coords[0]),
		popup = L.popup().setLatLng(pos);
		var content = Template.createHtml("station-popup", {
			station : ts.getMetadata().station.properties.label,
			timeseries : ts.getMetadata().label,
			service : ts.getMetadata().parameters.service.label
		});
		popup.setContent(content);
		popup.openOn(Map.map);
		Map.map.setZoom(Settings.zoom);
		Map.map.panTo(pos);
	}
};<|endoftext|>


<commit_before><commit_msg>better event name<commit_after><|endoftext|>


<commit_before>kindling.module(function () {
	'use strict';

	var tabMap = {};

	function initSetting(setting, defaultValue) {
		localStorage[setting] = localStorage[setting] || defaultValue;
	}

	function getSettingsObject() {
		var i, settingsObject = {};
		var count = localStorage.length;
		for (i = 0; i < count; i += 1) {
			var key = localStorage.key(i);
			settingsObject[key] = localStorage.getItem(key);
		}
		return settingsObject;
	}

	function sendOptionsChangedNotification() {
		var settingsObject = getSettingsObject();
		var tab;
		for (tab in tabMap) {
			chrome.tabs.sendRequest(parseInt(tab, 10), { type: 'optionsChanged', value: settingsObject });
		}
	}

	function tryToCreateNotification(payload, sender, successCallback) {
		if (localStorage.disableNotificationsWhenInFocus === 'true') {
			chrome.windows.getLastFocused(function (wnd) {
				if (wnd.id === sender.tab.windowId) {
					chrome.tabs.getSelected(wnd.id, function (tab) {
						if (tab.id !== sender.tab.id) {
							successCallback(payload, sender);
						}
					});
				} else {
					successCallback(payload, sender);
				}
			});
		} else {
			successCallback(payload, sender);
		}
	}

	function showNotification(payload, sender) {
		var notification = webkitNotifications.createHTMLNotification('notification.html'
			+ '?room=' + encodeURIComponent(payload.room)
			+ '&author=' + encodeURIComponent(payload.author)
			+ '&avatar=' + encodeURIComponent(payload.avatar)
			+ '&user=' + encodeURIComponent(payload.username)
			+ '&baseUrl=' + encodeURIComponent(kindling.getDomain(sender.tab.url))
			+ '#' + payload.message);

		notification.onclick = function () {
			chrome.windows.update(tabMap[sender.tab.id], { focused: true });
			chrome.tabs.update(sender.tab.id, { selected: true });
		};

		notification.show();
	}

	return {
		init: function () {
			initSetting('enterRoom', 'false');
			initSetting('leaveRoom', 'false');
			initSetting('timeStamps', 'true');
			initSetting('filterNotifications', 'false');
			initSetting('autoDismiss', 'true');
			initSetting('notifications', 'true');
			initSetting('notificationTimeout', '5000');
			initSetting('highlightName', 'true');
			initSetting('useDifferentTheme', 'false');
			initSetting('soundAndEmojiMenus', 'true');
			initSetting('showAvatarsInChat', 'false');
			initSetting('useLargeAvatars', 'false');
			initSetting('showAvatarsInNotifications', localStorage.showAvatars === 'false' ? 'false' : 'true');
			initSetting('disableNotificationsWhenInFocus', localStorage.focusNotifications === 'false');
			localStorage.removeItem('focusNotifications'); //obsolete option

			chrome.tabs.onAttached.addListener(function (tabId, attachInfo) {
				if (tabMap.hasOwnProperty(tabId)) {
					tabMap[tabId] = attachInfo.newWindowId;
				}
			});

			chrome.extension.onRequest.addListener(function (request, sender, callback) {
				if (request.type === 'notification') {
					tryToCreateNotification(request.value, sender, showNotification);
				} else if (request.type === 'init') {
					chrome.pageAction.show(sender.tab.id);
					tabMap[sender.tab.id] = sender.tab.windowId;
					sendOptionsChangedNotification();
				} else if (request.type === 'unload') {
					delete tabMap[sender.tab.id];
				} else if (request.type === 'optionsChanged') {
					sendOptionsChangedNotification();
				}

				if (callback) {
					callback();
				}
			});
		}
	};
}());
<commit_msg>Avatars in the chat window is now on by default.<commit_after>kindling.module(function () {
	'use strict';

	var tabMap = {};

	function initSetting(setting, defaultValue) {
		localStorage[setting] = localStorage[setting] || defaultValue;
	}

	function getSettingsObject() {
		var i, settingsObject = {};
		var count = localStorage.length;
		for (i = 0; i < count; i += 1) {
			var key = localStorage.key(i);
			settingsObject[key] = localStorage.getItem(key);
		}
		return settingsObject;
	}

	function sendOptionsChangedNotification() {
		var settingsObject = getSettingsObject();
		var tab;
		for (tab in tabMap) {
			chrome.tabs.sendRequest(parseInt(tab, 10), { type: 'optionsChanged', value: settingsObject });
		}
	}

	function tryToCreateNotification(payload, sender, successCallback) {
		if (localStorage.disableNotificationsWhenInFocus === 'true') {
			chrome.windows.getLastFocused(function (wnd) {
				if (wnd.id === sender.tab.windowId) {
					chrome.tabs.getSelected(wnd.id, function (tab) {
						if (tab.id !== sender.tab.id) {
							successCallback(payload, sender);
						}
					});
				} else {
					successCallback(payload, sender);
				}
			});
		} else {
			successCallback(payload, sender);
		}
	}

	function showNotification(payload, sender) {
		var notification = webkitNotifications.createHTMLNotification('notification.html'
			+ '?room=' + encodeURIComponent(payload.room)
			+ '&author=' + encodeURIComponent(payload.author)
			+ '&avatar=' + encodeURIComponent(payload.avatar)
			+ '&user=' + encodeURIComponent(payload.username)
			+ '&baseUrl=' + encodeURIComponent(kindling.getDomain(sender.tab.url))
			+ '#' + payload.message);

		notification.onclick = function () {
			chrome.windows.update(tabMap[sender.tab.id], { focused: true });
			chrome.tabs.update(sender.tab.id, { selected: true });
		};

		notification.show();
	}

	return {
		init: function () {
			initSetting('enterRoom', 'false');
			initSetting('leaveRoom', 'false');
			initSetting('timeStamps', 'true');
			initSetting('filterNotifications', 'false');
			initSetting('autoDismiss', 'true');
			initSetting('notifications', 'true');
			initSetting('notificationTimeout', '5000');
			initSetting('highlightName', 'true');
			initSetting('useDifferentTheme', 'false');
			initSetting('soundAndEmojiMenus', 'true');
			initSetting('showAvatarsInChat', 'true');
			initSetting('useLargeAvatars', 'false');
			initSetting('showAvatarsInNotifications', localStorage.showAvatars === 'false' ? 'false' : 'true');
			initSetting('disableNotificationsWhenInFocus', localStorage.focusNotifications === 'false');
			localStorage.removeItem('focusNotifications'); //obsolete option

			chrome.tabs.onAttached.addListener(function (tabId, attachInfo) {
				if (tabMap.hasOwnProperty(tabId)) {
					tabMap[tabId] = attachInfo.newWindowId;
				}
			});

			chrome.extension.onRequest.addListener(function (request, sender, callback) {
				if (request.type === 'notification') {
					tryToCreateNotification(request.value, sender, showNotification);
				} else if (request.type === 'init') {
					chrome.pageAction.show(sender.tab.id);
					tabMap[sender.tab.id] = sender.tab.windowId;
					sendOptionsChangedNotification();
				} else if (request.type === 'unload') {
					delete tabMap[sender.tab.id];
				} else if (request.type === 'optionsChanged') {
					sendOptionsChangedNotification();
				}

				if (callback) {
					callback();
				}
			});
		}
	};
}());
<|endoftext|>


<commit_before>"use strict";

var passport = module.parent.require('passport'),
	passportTotp = require('passport-totp').Strategy,
	loggedIn = module.parent.require('connect-ensure-login'),

	db = module.parent.require('./database'),
	nconf = module.parent.require('nconf'),
	async = module.parent.require('async'),
	user = module.parent.require('./user'),
	notifications = module.parent.require('./notifications'),
	meta = module.parent.require('./meta'),
	utils = module.parent.require('../public/src/utils'),
	translator = module.parent.require('../public/src/modules/translator'),
	routeHelpers = module.parent.require('./controllers/helpers'),

	SocketPlugins = require.main.require('./src/socket.io/plugins'),
	plugin = {};

plugin.init = function(params, callback) {
	var router = params.router,
		hostMiddleware = params.middleware,
		hostControllers = params.controllers,
		hostHelpers = require.main.require('./src/routes/helpers'),
		controllers = require('./lib/controllers'),
		middlewares = require('./lib/middlewares');

	// ACP
	router.get('/admin/plugins/2factor', hostMiddleware.admin.buildHeader, controllers.renderAdminPage);
	router.get('/api/admin/plugins/2factor', controllers.renderAdminPage);

	// UCP
	hostHelpers.setupPageRoute(router, '/user/:userslug/2factor', hostMiddleware, [hostMiddleware.requireUser, hostMiddleware.exposeUid], controllers.renderSettings);

	// 2fa Login
	router.get('/login/2fa', hostMiddleware.buildHeader, loggedIn.ensureLoggedIn(), controllers.renderLogin);
	router.get('/api/login/2fa', loggedIn.ensureLoggedIn(), controllers.renderLogin);
	router.post('/login/2fa', loggedIn.ensureLoggedIn(), controllers.processLogin, function(req, res) {
		req.session.tfa = true;
		res.redirect(nconf.get('relative_path') + (req.query.next || '/'));
	});

	// 2fa backups codes
	router.get('/login/2fa/backup', hostMiddleware.buildHeader, loggedIn.ensureLoggedIn(), controllers.renderBackup);
	router.get('/api/login/2fa/backup', loggedIn.ensureLoggedIn(), controllers.renderBackup);
	router.post('/login/2fa/backup', loggedIn.ensureLoggedIn(), controllers.processBackup, function(req, res) {
		req.session.tfa = true;
		res.redirect(nconf.get('relative_path') + (req.query.next || '/'));
	});
	router.put('/login/2fa/backup', hostMiddleware.requireUser, middlewares.requireSecondFactor, hostMiddleware.applyCSRF, controllers.generateBackupCodes);

	// Websockets
	SocketPlugins['2factor'] = require('./websockets');

	// Login Strategy
	passport.use(new passportTotp(
		function(user, done) {
			plugin.get(user.uid, function(err, key) {
				if (err) { return done(err); }
				return done(null, key, 30);
			});
		}
	));

	callback();
};

plugin.addAdminNavigation = function(header, callback) {
	translator.translate('[[2factor:title]]', function(title) {
		header.plugins.push({
			route: '/plugins/2factor',
			icon: 'fa-lock',
			name: title
		});

		callback(null, header);
	});
};

plugin.addProfileItem = function(links, callback) {
	translator.translate('[[2factor:title]]', function(title) {
		links.push({
			id: '2factor',
			route: '2factor',
			icon: 'fa-lock',
			name: title,
			public: false
		});

		callback(null, links);
	});
};

plugin.get = function(uid, callback) {
	db.getObjectField('2factor:uid:key', uid, callback);
};

plugin.save = function(uid, key, callback) {
	db.setObjectField('2factor:uid:key', uid, key, callback);
};

plugin.hasKey = function(uid, callback) {
	db.isObjectField('2factor:uid:key', uid, callback);
};

plugin.generateBackupCodes = function(uid, callback) {
	var set = '2factor:uid:' + uid + ':backupCodes',
		codes = [],
		code;

	for(var x=0;x<5;x++) {
		code = utils.generateUUID().replace('-', '').slice(0, 10);
		codes.push(code);
	}

	async.series([
		async.apply(db.delete, set),		// Invalidate all old codes
		async.apply(db.setAdd, set, codes),	// Save new codes
		function(next) {
			notifications.create({
				bodyShort: '[[2factor:notification.backupCode.generated]]',
				bodyLong: '',
				nid: '2factor.backupCode.generated-' + uid + '-' + Date.now(),
				from: uid,
				path: '/'
			}, function(err, notification) {
				if (!err && notification) {
					notifications.push(notification, [uid], next);
				}
			});
		}
	], function(err) {
		callback(err, codes);
	});
};

plugin.useBackupCode = function(code, uid, callback) {
	var set = '2factor:uid:' + uid + ':backupCodes';

	async.waterfall([
		async.apply(db.isSetMember, set, code),
		function(valid, next) {
			if (valid) {
				// Invalidate this backup code
				db.setRemove(set, code, function(err) {
					next(err, valid);
				});

				notifications.create({
					bodyShort: '[[2factor:notification.backupCode.used]]',
					bodyLong: '',
					nid: '2factor.backupCode.used-' + uid + '-' + Date.now(),
					from: uid,
					path: '/'
				}, function(err, notification) {
					if (!err && notification) {
						notifications.push(notification, [uid]);
					}
				});
			} else {
				next(null, valid);
			}
		}
	], callback);
};

plugin.disassociate = function(uid, callback) {
	async.parallel([
		async.apply(db.deleteObjectField, '2factor:uid:key', uid),
		async.apply(db.delete, '2factor:uid:' + uid + ':backupCodes')
	], callback);
};

plugin.check = function(req, res, next) {
	if (!req.user || req.session.tfa === true) {
		return next();
	}

	plugin.hasKey(req.user.uid, function(err, hasKey) {
		if (hasKey) {
			// Account has TFA, redirect to login
			routeHelpers.redirect(res, '/login/2fa' + (res.locals.isAPI ? '?next=' + req.url.replace('/api', '') : ''));
		} else {
			// No TFA setup
			return next();
		}
	})
};

plugin.clearSession = function(data, callback) {
	delete data.req.session.tfa;
	setImmediate(callback);
};

plugin.getUsers = function(callback) {
	async.waterfall([
		async.apply(db.getObjectKeys, '2factor:uid:key'),
		function(uids, next) {
			user.getUsersFields(uids, ['username', 'userslug', 'picture'], next);
		}
	], callback);
};

plugin.updateTitle = function(data, callback) {
	translator.translate('[[2factor:title]]', function(title) {
		if (data.fragment.match(/^user\/.+\/2factor/)) {
			data.parsed = title;
		}

		callback(null, data);
	});
};

module.exports = plugin;<commit_msg>fixes #16<commit_after>"use strict";

var passport = module.parent.require('passport'),
	passportTotp = require('passport-totp').Strategy,
	loggedIn = module.parent.require('connect-ensure-login'),

	db = module.parent.require('./database'),
	nconf = module.parent.require('nconf'),
	async = module.parent.require('async'),
	user = module.parent.require('./user'),
	notifications = module.parent.require('./notifications'),
	meta = module.parent.require('./meta'),
	utils = module.parent.require('../public/src/utils'),
	translator = module.parent.require('../public/src/modules/translator'),
	routeHelpers = module.parent.require('./controllers/helpers'),

	SocketPlugins = require.main.require('./src/socket.io/plugins'),
	plugin = {};

plugin.init = function(params, callback) {
	var router = params.router,
		hostMiddleware = params.middleware,
		hostControllers = params.controllers,
		hostHelpers = require.main.require('./src/routes/helpers'),
		controllers = require('./lib/controllers'),
		middlewares = require('./lib/middlewares');

	// ACP
	router.get('/admin/plugins/2factor', hostMiddleware.admin.buildHeader, controllers.renderAdminPage);
	router.get('/api/admin/plugins/2factor', controllers.renderAdminPage);

	// UCP
	hostHelpers.setupPageRoute(router, '/user/:userslug/2factor', hostMiddleware, [hostMiddleware.requireUser, hostMiddleware.exposeUid], controllers.renderSettings);

	// 2fa Login
	router.get('/login/2fa', hostMiddleware.buildHeader, loggedIn.ensureLoggedIn(), controllers.renderLogin);
	router.get('/api/login/2fa', loggedIn.ensureLoggedIn(), controllers.renderLogin);
	router.post('/login/2fa', loggedIn.ensureLoggedIn(), controllers.processLogin, function(req, res) {
		req.session.tfa = true;
		res.redirect(nconf.get('relative_path') + (req.query.next || '/'));
	});

	// 2fa backups codes
	router.get('/login/2fa/backup', hostMiddleware.buildHeader, loggedIn.ensureLoggedIn(), controllers.renderBackup);
	router.get('/api/login/2fa/backup', loggedIn.ensureLoggedIn(), controllers.renderBackup);
	router.post('/login/2fa/backup', loggedIn.ensureLoggedIn(), controllers.processBackup, function(req, res) {
		req.session.tfa = true;
		res.redirect(nconf.get('relative_path') + (req.query.next || '/'));
	});
	router.put('/login/2fa/backup', hostMiddleware.requireUser, middlewares.requireSecondFactor, hostMiddleware.applyCSRF, controllers.generateBackupCodes);

	// Websockets
	SocketPlugins['2factor'] = require('./websockets');

	// Login Strategy
	passport.use(new passportTotp(
		function(user, done) {
			plugin.get(user.uid, function(err, key) {
				if (err) { return done(err); }
				return done(null, key, 30);
			});
		}
	));

	callback();
};

plugin.addAdminNavigation = function(header, callback) {
	translator.translate('[[2factor:title]]', function(title) {
		header.plugins.push({
			route: '/plugins/2factor',
			icon: 'fa-lock',
			name: title
		});

		callback(null, header);
	});
};

plugin.addProfileItem = function(links, callback) {
	translator.translate('[[2factor:title]]', function(title) {
		links.push({
			id: '2factor',
			route: '2factor',
			icon: 'fa-lock',
			name: title,
			public: false
		});

		callback(null, links);
	});
};

plugin.get = function(uid, callback) {
	db.getObjectField('2factor:uid:key', uid, callback);
};

plugin.save = function(uid, key, callback) {
	db.setObjectField('2factor:uid:key', uid, key, callback);
};

plugin.hasKey = function(uid, callback) {
	db.isObjectField('2factor:uid:key', uid, callback);
};

plugin.generateBackupCodes = function(uid, callback) {
	var set = '2factor:uid:' + uid + ':backupCodes',
		codes = [],
		code;

	for(var x=0;x<5;x++) {
		code = utils.generateUUID().replace('-', '').slice(0, 10);
		codes.push(code);
	}

	async.series([
		async.apply(db.delete, set),		// Invalidate all old codes
		async.apply(db.setAdd, set, codes),	// Save new codes
		function(next) {
			notifications.create({
				bodyShort: '[[2factor:notification.backupCode.generated]]',
				bodyLong: '',
				nid: '2factor.backupCode.generated-' + uid + '-' + Date.now(),
				from: uid,
				path: '/'
			}, function(err, notification) {
				if (!err && notification) {
					notifications.push(notification, [uid], next);
				}
			});
		}
	], function(err) {
		callback(err, codes);
	});
};

plugin.useBackupCode = function(code, uid, callback) {
	var set = '2factor:uid:' + uid + ':backupCodes';

	async.waterfall([
		async.apply(db.isSetMember, set, code),
		function(valid, next) {
			if (valid) {
				// Invalidate this backup code
				db.setRemove(set, code, function(err) {
					next(err, valid);
				});

				notifications.create({
					bodyShort: '[[2factor:notification.backupCode.used]]',
					bodyLong: '',
					nid: '2factor.backupCode.used-' + uid + '-' + Date.now(),
					from: uid,
					path: '/'
				}, function(err, notification) {
					if (!err && notification) {
						notifications.push(notification, [uid]);
					}
				});
			} else {
				next(null, valid);
			}
		}
	], callback);
};

plugin.disassociate = function(uid, callback) {
	async.parallel([
		async.apply(db.deleteObjectField, '2factor:uid:key', uid),
		async.apply(db.delete, '2factor:uid:' + uid + ':backupCodes')
	], callback);
};

plugin.check = function(req, res, next) {
	if (!req.user || req.session.tfa === true) {
		return next();
	}

	plugin.hasKey(req.user.uid, function(err, hasKey) {
		if (hasKey) {
			// Account has TFA, redirect to login
			routeHelpers.redirect(res, '/login/2fa' + (res.locals.isAPI ? '?next=' + req.url.replace('/api', '') : ''));
		} else {
			// No TFA setup
			return next();
		}
	})
};

plugin.clearSession = function(data, callback) {
	if (data.req.session) {
		delete data.req.session.tfa;
	}

	setImmediate(callback);
};

plugin.getUsers = function(callback) {
	async.waterfall([
		async.apply(db.getObjectKeys, '2factor:uid:key'),
		function(uids, next) {
			user.getUsersFields(uids, ['username', 'userslug', 'picture'], next);
		}
	], callback);
};

plugin.updateTitle = function(data, callback) {
	translator.translate('[[2factor:title]]', function(title) {
		if (data.fragment.match(/^user\/.+\/2factor/)) {
			data.parsed = title;
		}

		callback(null, data);
	});
};

module.exports = plugin;<|endoftext|>


<commit_before><commit_msg>[FANCOM-JS] - :punch: reading fancom.json config file<commit_after><|endoftext|>


<commit_before>class Transitions extends Phaser.Plugin {

  constructor (game, parent) {
    super(game, parent);

    this.transitionCompleted  = new Phaser.Signal();
    this.transitionRunning    = false;
    this.transitionRegistered = null;

    this._group    = this.game.stage.addChild(this.game.make.group());
    this._blackout = this._group.add(this._makeBlackout());

    this._iris       = this._group.add(new Iris(this.game, 240, 160));
    this._iris.alpha = 0;

    this.transitionCompleted.add(this._clearRegisteredTransition, this);
  }

  // --------------------------------------------------------------------------

  registerTransition (transitionName) {
    this.transitionRunning    = false;
    this.transitionRegistered = transitionName;
  }

  registerTransitionCallback (callback, context) {
    this.transitionCompleted.addOnce(callback, context);
  }

  doTransition () {
    if (this.transitionRunning) return;

    this.transitionRunning = true;

    switch (this.transitionRegistered) {
      case 'iris':
        this._openIris();
        break;
      case 'fade-from-black':
        this._fadeFromBlack();
        break;
      case 'fade-to-black':
        this._fadeToBlack();
        break;
      case 'blink-pink':
        this._blink(0xff7a7a);
        break;
      case 'blink-blue':
        this._blink(0x6baff5);
        break;
    }
  }

  // --------------------------------------------------------------------------

  _makeBitmap (width, height) {
    var bitmap = this.game.make.bitmapData(width, height);

    bitmap.fill(255, 255, 255);

    return bitmap;
  }

  _makeImage (x, y, width, height, alpha = 0, tint = 0x000000) {
    var image = this.game.make.image(x, y, this._makeBitmap(width, height));

    image.alpha = alpha;
    image.tint  = tint;

    return image;
  }

  _makeBlackout () {
    return this._makeImage(0, 0, 240, 160);
  }

  _makeTween (object) {
    return this.game.add.tween(object);
  }

  _fadeFromBlack () {
    this._fadeBlackout(1, 0);
  }

  _fadeToBlack () {
    this._fadeBlackout(0, 1);
  }

  _fadeBlackout (from, to) {
    var tween = this._makeTween(this._blackout);

    this._blackout.alpha = from;
    this._blackout.tint  = 0x000000;

    tween
      .to({ alpha: to }, 1000)
      .start();

    tween
      .onComplete.addOnce(this.transitionCompleted.dispatch, this);
  }

  _blink (color) {
    var tween = this._makeTween(this._blackout);

    this._blackout.alpha = 1;
    this._blackout.tint  = color;

    tween
      .to({ alpha: 0 }, 400)
      .start();
  }

  _openIris () {
    var tween = this._makeTween(this._iris);

    this._iris.alpha = 1;

    tween
      .to({ aperture: 1 }, 1000)
      .start();

    tween
      .onComplete.addOnce(this.transitionCompleted.dispatch, this);
  }

  _clearRegisteredTransition () {
    this.transitionRunning    = false;
    this.transitionRegistered = null;
  }

}

import Iris from 'objects/Iris';

export default Transitions;
<commit_msg>Guard already running transitions.<commit_after>class Transitions extends Phaser.Plugin {

  constructor (game, parent) {
    super(game, parent);

    this.transitionCompleted  = new Phaser.Signal();
    this.transitionRunning    = false;
    this.transitionRegistered = null;

    this._group    = this.game.stage.addChild(this.game.make.group());
    this._blackout = this._group.add(this._makeBlackout());

    this._iris       = this._group.add(new Iris(this.game, 240, 160));
    this._iris.alpha = 0;

    this.transitionCompleted.add(this._clearRegisteredTransition, this);
  }

  // --------------------------------------------------------------------------

  registerTransition (transitionName) {
    if (this.transitionRunning) return;

    this.transitionRunning    = false;
    this.transitionRegistered = transitionName;
  }

  registerTransitionCallback (callback, context) {
    if (this.transitionRunning) return;

    this.transitionCompleted.addOnce(callback, context);
  }

  doTransition () {
    if (this.transitionRunning) return;

    this.transitionRunning = true;

    switch (this.transitionRegistered) {
      case 'iris':
        this._openIris();
        break;
      case 'fade-from-black':
        this._fadeFromBlack();
        break;
      case 'fade-to-black':
        this._fadeToBlack();
        break;
      case 'blink-pink':
        this._blink(0xff7a7a);
        break;
      case 'blink-blue':
        this._blink(0x6baff5);
        break;
    }
  }

  // --------------------------------------------------------------------------

  _makeBitmap (width, height) {
    var bitmap = this.game.make.bitmapData(width, height);

    bitmap.fill(255, 255, 255);

    return bitmap;
  }

  _makeImage (x, y, width, height, alpha = 0, tint = 0x000000) {
    var image = this.game.make.image(x, y, this._makeBitmap(width, height));

    image.alpha = alpha;
    image.tint  = tint;

    return image;
  }

  _makeBlackout () {
    return this._makeImage(0, 0, 240, 160);
  }

  _makeTween (object) {
    return this.game.add.tween(object);
  }

  _fadeFromBlack () {
    this._fadeBlackout(1, 0);
  }

  _fadeToBlack () {
    this._fadeBlackout(0, 1);
  }

  _fadeBlackout (from, to) {
    var tween = this._makeTween(this._blackout);

    this._blackout.alpha = from;
    this._blackout.tint  = 0x000000;

    tween
      .to({ alpha: to }, 1000)
      .start();

    tween
      .onComplete.addOnce(this.transitionCompleted.dispatch, this);
  }

  _blink (color) {
    var tween = this._makeTween(this._blackout);

    this._blackout.alpha = 1;
    this._blackout.tint  = color;

    tween
      .to({ alpha: 0 }, 400)
      .start();
  }

  _openIris () {
    var tween = this._makeTween(this._iris);

    this._iris.alpha = 1;

    tween
      .to({ aperture: 1 }, 1000)
      .start();

    tween
      .onComplete.addOnce(this.transitionCompleted.dispatch, this);
  }

  _clearRegisteredTransition () {
    this.transitionRunning    = false;
    this.transitionRegistered = null;
  }

}

import Iris from 'objects/Iris';

export default Transitions;
<|endoftext|>


<commit_before>(function(module) {
	'use strict';
	/* globals module, require */

	var user = module.parent.require('./user'),
		meta = module.parent.require('./meta'),
		db = module.parent.require('../src/database'),
		passport = module.parent.require('passport'),
		passportFacebook = require('passport-facebook').Strategy,
		nconf = module.parent.require('nconf'),
		async = module.parent.require('async'),
		winston = module.parent.require('winston');

	var constants = Object.freeze({
		'name': 'Facebook',
		'admin': {
			'route': '/plugins/sso-facebook',
			'icon': 'fa-facebook-square'
		}
	});

	var Facebook = {};

	Facebook.init = function(params, callback) {
		function render(req, res) {
			res.render('admin/plugins/sso-facebook', {});
		}

		params.router.get('/admin/plugins/sso-facebook', params.middleware.admin.buildHeader, render);
		params.router.get('/api/admin/plugins/sso-facebook', render);

		callback();
	};

	Facebook.getStrategy = function(strategies, callback) {
		if (meta.config['social:facebook:app_id'] && meta.config['social:facebook:secret']) {
			passport.use(new passportFacebook({
				clientID: meta.config['social:facebook:app_id'],
				clientSecret: meta.config['social:facebook:secret'],
				callbackURL: nconf.get('url') + '/auth/facebook/callback'
			}, function(accessToken, refreshToken, profile, done) {
				var email;
				if (profile.emails.length) {
					email = profile.emails[0].value;
				} else {
					email = profile.username ? (profile.username + '@facebook.com') : (profile.id + '@facebook.com');
				}

				Facebook.login(profile.id, profile.displayName, email, 'https://graph.facebook.com/' + profile.id + '/picture?type=large', function(err, user) {
					if (err) {
						return done(err);
					}
					done(null, user);
				});
			}));

			strategies.push({
				name: 'facebook',
				url: '/auth/facebook',
				callbackURL: '/auth/facebook/callback',
				icon: 'fa-facebook-square',
				scope: 'email'
			});
		}

		callback(null, strategies);
	};

	Facebook.login = function(fbid, name, email, picture, callback) {
		Facebook.getUidByFbid(fbid, function(err, uid) {
			if(err) {
				return callback(err);
			}

			if (uid !== null) {
				// Existing User
				callback(null, {
					uid: uid
				});
			} else {
				// New User
				var success = function(uid) {
					// Save facebook-specific information to the user
					user.setUserField(uid, 'fbid', fbid);
					db.setObjectField('fbid:uid', fbid, uid);

					// Save their photo, if present
					if (picture) {
						user.setUserField(uid, 'uploadedpicture', picture);
						user.setUserField(uid, 'picture', picture);
					}

					callback(null, {
						uid: uid
					});
				};

				user.getUidByEmail(email, function(err, uid) {
					if(err) {
						return callback(err);
					}

					if (!uid) {
						user.create({username: name, email: email}, function(err, uid) {
							if(err) {
								return callback(err);
							}

							success(uid);
						});
					} else {
						success(uid); // Existing account -- merge
					}
				});
			}
		});
	};

	Facebook.getUidByFbid = function(fbid, callback) {
		db.getObjectField('fbid:uid', fbid, function(err, uid) {
			if (err) {
				return callback(err);
			}
			callback(null, uid);
		});
	};

	Facebook.addMenuItem = function(custom_header, callback) {
		custom_header.authentication.push({
			'route': constants.admin.route,
			'icon': constants.admin.icon,
			'name': constants.name
		});

		callback(null, custom_header);
	};

	Facebook.deleteUserData = function(uid, callback) {
		async.waterfall([
			async.apply(user.getUserField, uid, 'fbid'),
			function(oAuthIdToDelete, next) {
				db.deleteObjectField('fbid:uid', oAuthIdToDelete, next);
			}
		], function(err) {
			if (err) {
				winston.error('[sso-facebook] Could not remove OAuthId data for uid ' + uid + '. Error: ' + err);
				return callback(err);
			}
			callback(null, uid);
		});
	};

	module.exports = Facebook;
}(module));<commit_msg>prevent crash if profile emails is undefined or not array<commit_after>(function(module) {
	'use strict';
	/* globals module, require */

	var user = module.parent.require('./user'),
		meta = module.parent.require('./meta'),
		db = module.parent.require('../src/database'),
		passport = module.parent.require('passport'),
		passportFacebook = require('passport-facebook').Strategy,
		nconf = module.parent.require('nconf'),
		async = module.parent.require('async'),
		winston = module.parent.require('winston');

	var constants = Object.freeze({
		'name': 'Facebook',
		'admin': {
			'route': '/plugins/sso-facebook',
			'icon': 'fa-facebook-square'
		}
	});

	var Facebook = {};

	Facebook.init = function(params, callback) {
		function render(req, res) {
			res.render('admin/plugins/sso-facebook', {});
		}

		params.router.get('/admin/plugins/sso-facebook', params.middleware.admin.buildHeader, render);
		params.router.get('/api/admin/plugins/sso-facebook', render);

		callback();
	};

	Facebook.getStrategy = function(strategies, callback) {
		if (meta.config['social:facebook:app_id'] && meta.config['social:facebook:secret']) {
			passport.use(new passportFacebook({
				clientID: meta.config['social:facebook:app_id'],
				clientSecret: meta.config['social:facebook:secret'],
				callbackURL: nconf.get('url') + '/auth/facebook/callback'
			}, function(accessToken, refreshToken, profile, done) {
				var email;
				if (Array.isArray(profile.emails) && profile.emails.length) {
					email = profile.emails[0].value;
				} else {
					email = (profile.username ? profile.username : profile.id) + '@facebook.com';
				}

				Facebook.login(profile.id, profile.displayName, email, 'https://graph.facebook.com/' + profile.id + '/picture?type=large', function(err, user) {
					if (err) {
						return done(err);
					}
					done(null, user);
				});
			}));

			strategies.push({
				name: 'facebook',
				url: '/auth/facebook',
				callbackURL: '/auth/facebook/callback',
				icon: 'fa-facebook-square',
				scope: 'email'
			});
		}

		callback(null, strategies);
	};

	Facebook.login = function(fbid, name, email, picture, callback) {
		Facebook.getUidByFbid(fbid, function(err, uid) {
			if(err) {
				return callback(err);
			}

			if (uid !== null) {
				// Existing User
				callback(null, {
					uid: uid
				});
			} else {
				// New User
				var success = function(uid) {
					// Save facebook-specific information to the user
					user.setUserField(uid, 'fbid', fbid);
					db.setObjectField('fbid:uid', fbid, uid);

					// Save their photo, if present
					if (picture) {
						user.setUserField(uid, 'uploadedpicture', picture);
						user.setUserField(uid, 'picture', picture);
					}

					callback(null, {
						uid: uid
					});
				};

				user.getUidByEmail(email, function(err, uid) {
					if(err) {
						return callback(err);
					}

					if (!uid) {
						user.create({username: name, email: email}, function(err, uid) {
							if(err) {
								return callback(err);
							}

							success(uid);
						});
					} else {
						success(uid); // Existing account -- merge
					}
				});
			}
		});
	};

	Facebook.getUidByFbid = function(fbid, callback) {
		db.getObjectField('fbid:uid', fbid, function(err, uid) {
			if (err) {
				return callback(err);
			}
			callback(null, uid);
		});
	};

	Facebook.addMenuItem = function(custom_header, callback) {
		custom_header.authentication.push({
			'route': constants.admin.route,
			'icon': constants.admin.icon,
			'name': constants.name
		});

		callback(null, custom_header);
	};

	Facebook.deleteUserData = function(uid, callback) {
		async.waterfall([
			async.apply(user.getUserField, uid, 'fbid'),
			function(oAuthIdToDelete, next) {
				db.deleteObjectField('fbid:uid', oAuthIdToDelete, next);
			}
		], function(err) {
			if (err) {
				winston.error('[sso-facebook] Could not remove OAuthId data for uid ' + uid + '. Error: ' + err);
				return callback(err);
			}
			callback(null, uid);
		});
	};

	module.exports = Facebook;
}(module));
<|endoftext|>


<commit_before><commit_msg>disable object-curly-spacing<commit_after><|endoftext|>


<commit_before><commit_msg>modified<commit_after><|endoftext|>


<commit_before><commit_msg>optimized the way bytes were read from incoming stream<commit_after><|endoftext|>


<commit_before><commit_msg>removed unneeded console.log<commit_after><|endoftext|>


<commit_before><commit_msg>Added content<commit_after><|endoftext|>


<commit_before><commit_msg>add upload file handle<commit_after><|endoftext|>


<commit_before><commit_msg>separate directory-traversal from processing for clarity<commit_after><|endoftext|>


<commit_before><commit_msg>syntax fix<commit_after><|endoftext|>


<commit_before><commit_msg>adopt BEM classname convention<commit_after><|endoftext|>


<commit_before><commit_msg>[queue] [minor] Use explicit function instead of bind method<commit_after><|endoftext|>


<commit_before><commit_msg>feat: Better handling for detached HEAD<commit_after><|endoftext|>


<commit_before><commit_msg>fixed bug<commit_after><|endoftext|>


<commit_before><commit_msg>Add support for sending commands to Pianobar FIFO<commit_after><|endoftext|>


<commit_before><commit_msg>More refactorings, and ability to pass another port other than 9999 via env variable HTTP_PORT<commit_after><|endoftext|>


<commit_before><commit_msg>removing this.async<commit_after><|endoftext|>


<commit_before><commit_msg>commented out 2D draw calls<commit_after><|endoftext|>


<commit_before><commit_msg>Clean up the write() method.<commit_after><|endoftext|>


<commit_before><commit_msg>Unknown aliases with "<" and ">" no longer cause the program to halt execution.<commit_after><|endoftext|>


<commit_before><commit_msg>Regenerate<commit_after><|endoftext|>


<commit_before><commit_msg>Entry point place holder<commit_after><|endoftext|>


<commit_before><commit_msg>math in public folks... I'm such a freking idiot<commit_after><|endoftext|>


<commit_before><commit_msg>more fixes<commit_after><|endoftext|>


<commit_before><commit_msg>Avoid repeated array accesses (#24)<commit_after><|endoftext|>


<commit_before><commit_msg>pass string to `.is()`<commit_after><|endoftext|>


<commit_before><commit_msg>New version buffering requests<commit_after><|endoftext|>


<commit_before><commit_msg>feat(*): sub config<commit_after><|endoftext|>


<commit_before><commit_msg>combine ruleset<commit_after><|endoftext|>


<commit_before><commit_msg>add sta conf for heroku<commit_after><|endoftext|>


<commit_before><commit_msg>Acceptor message handling.<commit_after><|endoftext|>


<commit_before><commit_msg>Increase count value just before return<commit_after><|endoftext|>


<commit_before>/**
 * Copyright 2014, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
module.exports = require('./lib/Fluxible');
module.exports.FluxibleContext = require('./lib/FluxibleContext');
module.exports.Mixin = require('./mixins/FluxibleMixin');
<commit_msg>Remove FluxibleContext from exports since it is internal<commit_after>/**
 * Copyright 2014, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
module.exports = require('./lib/Fluxible');
module.exports.Mixin = require('./mixins/FluxibleMixin');
<|endoftext|>


<commit_before><commit_msg>Fix typo in index.js<commit_after><|endoftext|>


<commit_before><commit_msg> Fix issue when spec is undefined.<commit_after><|endoftext|>


<commit_before>const mongoose = require('mongoose')
const { composeWithMongoose } = require('graphql-compose-mongoose')

// - - - - - - Extra fields - - - - - -

let _extraInstallationSchema = {}
try {
  const { extraInstallationSchema } = require('./custom')
  _extraInstallationSchema = extraInstallationSchema
} catch (err) { err }

// - - - - - - Default fields - - - - - -

const InstallationSchemaObject = {
  // Devices
  deviceInfo: String,
  locale: String,
  country: String,
  timezone: String,
  deviceName: String,
  isEmulater: Boolean,
  isTablet: Boolean,

  // App
  bundleId: String,
  appVersion: String,

  // Notifications
  GCMSenderId: String,
  deviceToken: String,
  badge: String,
  channels: String,
}

const InstallationSchema = new mongoose.Schema(
  Object.assign(
    InstallationSchemaObject,
    _extraInstallationSchema
  ), {
    timestamps: true,
  }
)

// - - - - - - Plugins - - - - - -

const Installation = mongoose.model('Installation', InstallationSchema)
const InstallationTC = composeWithMongoose(Installation)

// - - - - - - Extras - - - - - -

const willInstall = (device) => new Promise((resolve, reject) => {
  Installation.create(device, (err, result) => {
    // Error?
    err && debug.error(err) && reject(err)
    // Succeed
    resolve(result)
  })
})

// - - - - - - Exports - - - - - -

module.exports = { Installation, InstallationTC, InstallationSchema, willInstall }<commit_msg>refactor(Installation): Deprecated isEmulater, isTablet<commit_after>const mongoose = require('mongoose')
const { composeWithMongoose } = require('graphql-compose-mongoose')

// - - - - - - Extra fields - - - - - -

let _extraInstallationSchema = {}
try {
  const { extraInstallationSchema } = require('./custom')
  _extraInstallationSchema = extraInstallationSchema
} catch (err) { err }

// - - - - - - Default fields - - - - - -

const InstallationSchemaObject = {
  // Devices
  deviceInfo: String,
  locale: String,
  country: String,
  timezone: String,
  deviceName: String,

  // App
  bundleId: String,
  appVersion: String,

  // Notifications
  GCMSenderId: String,
  deviceToken: String,
  badge: String,
  channels: String,
}

const InstallationSchema = new mongoose.Schema(
  Object.assign(
    InstallationSchemaObject,
    _extraInstallationSchema
  ), {
    timestamps: true,
  }
)

// - - - - - - Plugins - - - - - -

const Installation = mongoose.model('Installation', InstallationSchema)
const InstallationTC = composeWithMongoose(Installation)

// - - - - - - Extras - - - - - -

const willInstall = (device) => new Promise((resolve, reject) => {
  Installation.create(device, (err, result) => {
    // Error?
    err && debug.error(err) && reject(err)
    // Succeed
    resolve(result)
  })
})

// - - - - - - Exports - - - - - -

module.exports = { Installation, InstallationTC, InstallationSchema, willInstall }<|endoftext|>


<commit_before>
// POSIX IEEE P1003.1
// https://en.wikipedia.org/wiki/Tar_(computing)
const REGEXP = /^[^\s]+\d{6}\s(.{10})/;

module.exports.type = "tar";

module.exports.is = function isTar( sample ) {
    if ( !( sample instanceof Buffer ) ) {
        return false; // only buffers can represent tarballs
    }

    // var fname = sample.slice( 0, 100 );
    var mode = sample.slice( 100, 107 ).toString();
    var owner = sample.slice( 108, 115 ).toString();
    var group = sample.slice( 116, 123 ).toString();
    var size = sample.slice( 124, 135 ).toString();

    return mode && +mode > 111 && +mode < 777
        && owner && !isNaN( owner )
        && group && !isNaN( group )
        && size && !isNaN( size );
}

module.exports.parser = function () {
    return require( "tar" ).Parse();
}

module.exports.requires = [ "tar" ]
<commit_msg>Remove the obsolete tar regexp<commit_after>module.exports.type = "tar";

module.exports.is = function isTar( sample ) {
    if ( !( sample instanceof Buffer ) ) {
        return false; // only buffers can represent tarballs
    }

    // POSIX IEEE P1003.1
    // https://en.wikipedia.org/wiki/Tar_(computing)
    // var fname = sample.slice( 0, 100 );
    var mode = sample.slice( 100, 107 ).toString();
    var owner = sample.slice( 108, 115 ).toString();
    var group = sample.slice( 116, 123 ).toString();
    var size = sample.slice( 124, 135 ).toString();

    return mode && +mode > 111 && +mode < 777
        && owner && !isNaN( owner )
        && group && !isNaN( group )
        && size && !isNaN( size );
}

module.exports.parser = function () {
    return require( "tar" ).Parse();
}

module.exports.requires = [ "tar" ]
<|endoftext|>


<commit_before><commit_msg>fix angular can not add itself as a dependency<commit_after><|endoftext|>


<commit_before><commit_msg>refact, please ignore<commit_after><|endoftext|>


<commit_before>var _filters = [];

module.exports = function(originalObj, filters) {
  var flattenedObj = {};
  _filters = filters;

  // This takes advantage of JS's passing objects by reference
  iterate(originalObj, flattenedObj, '');

  return flattenedObj;
};

function iterate(obj, flat, path) {
  for( var key in obj ) {
    if (obj.hasOwnProperty(key)) {
      var val = obj[key],
          keyPath = path + key;

      checkType(key, val, flat, keyPath);
    }
  }
}

function arrIterate(arr, flat, path) {
  for (var idx = 0, len = arr.length; idx < len; ++idx) {
    var arPath = path + '[' + idx + ']';
    checkType( arr[idx], arr[idx], flat, arPath);
  }
}

function checkType(key, val, obj, path) {
  var type = typeof val,
      filter = _filters.indexOf(type) > -1;

  // Throw error if unsupported values are passed
  // Really, just throwing an error because idk how JS XML works.
  if (type === "xml") {
    throw new Error("Unsupported type passed!");
  }

  // If filtered type, don't add anything.
  if (filter) {
    return;
  }

  // If normal Key-Value, assign to flattened object
  if (type === "boolean" || type === "string" || type === "number" || type === "function") {
    var objKey = path || key;
    obj[objKey] = val;
    return;
  }

  // Otherwise if an object
  if (type === 'object') {

    // If value is an array, iterate again
    if (Array.isArray(val)) {
      arrIterate(val, obj, path);

    // Otherwise is an object, and iterates
    } else {
      var objPath = path + '.';
      return iterate(val, obj, objPath);
    }
  }

  // If value is an 'undefined' or otherwise falsy value,
  // don't add it to the flattened object
}<commit_msg>Fixed defaulting _filter.<commit_after>var _filters;

module.exports = function(originalObj, filters) {
  var flattenedObj = {};
  _filters = filters || [];

  // This takes advantage of JS's passing objects by reference
  iterate(originalObj, flattenedObj, '');

  return flattenedObj;
};

function iterate(obj, flat, path) {
  for( var key in obj ) {
    if (obj.hasOwnProperty(key)) {
      var val = obj[key],
          keyPath = path + key;

      checkType(key, val, flat, keyPath);
    }
  }
}

function arrIterate(arr, flat, path) {
  for (var idx = 0, len = arr.length; idx < len; ++idx) {
    var arPath = path + '[' + idx + ']';
    checkType( arr[idx], arr[idx], flat, arPath);
  }
}

function checkType(key, val, obj, path) {
  var type = typeof val,
      filter = _filters.indexOf(type) > -1;

  // Throw error if unsupported values are passed
  // Really, just throwing an error because idk how JS XML works.
  if (type === "xml") {
    throw new Error("Unsupported type passed!");
  }

  // If filtered type, don't add anything.
  if (filter) {
    return;
  }

  // If normal Key-Value, assign to flattened object
  if (type === "boolean" || type === "string" || type === "number" || type === "function") {
    var objKey = path || key;
    obj[objKey] = val;
    return;
  }

  // Otherwise if an object
  if (type === 'object') {

    // If value is an array, iterate again
    if (Array.isArray(val)) {
      arrIterate(val, obj, path);

    // Otherwise is an object, and iterates
    } else {
      var objPath = path + '.';
      return iterate(val, obj, objPath);
    }
  }

  // If value is an 'undefined' or otherwise falsy value,
  // don't add it to the flattened object
}<|endoftext|>


<commit_before>/*
The MIT License (MIT)

Copyright (c) 2015 Geoffrey Arnold

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

module.exports = function(RED) {
    'use strict';

    function LibratoConfigNode(n) {
        RED.nodes.createNode(this, n);
        this.email = n.email;
        this.token = n.token;

        this.client = require('librato-node');
        this.client.configure({
            email: this.email,
            token: this.token
        });

        this.log('Starting Librato client [' + this.email + ']');
        this.client.start();

        var node = this;

        this.on('close', function() {
            node.log('Stopping Librato client');
            node.client.stop();
        });
    }
    RED.nodes.registerType('librato-config', LibratoConfigNode);

    function LibratoNode(n) {
        RED.nodes.createNode(this, n);
        this.librato = RED.nodes.getNode(n.librato);
        this.metricName = n.metricName;
        this.metricType = n.metricType || 'gauge';

        var node = this;

        this.on('input', function(msg) {
            var value = msg.payload;

            if (node.librato) {
                if (node.metricType == 'gauge') {
                    node.librato.client.measure(node.metricName, value);
                } else {
                    node.librato.client.increment(node.metricName, value);
                }
            } else {
                node.error('Librato client is not configured');
            }
        });
    }
    RED.nodes.registerType('librato', LibratoNode);
}
<commit_msg>Ensuring `msg.payload` is a number.<commit_after>/*
The MIT License (MIT)

Copyright (c) 2015 Geoffrey Arnold

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/

module.exports = function(RED) {
    'use strict';

    function LibratoConfigNode(n) {
        RED.nodes.createNode(this, n);
        this.email = n.email;
        this.token = n.token;

        this.client = require('librato-node');
        this.client.configure({
            email: this.email,
            token: this.token
        });

        this.log('Starting Librato client [' + this.email + ']');
        this.client.start();

        var node = this;

        this.on('close', function() {
            node.log('Stopping Librato client');
            node.client.stop();
        });
    }
    RED.nodes.registerType('librato-config', LibratoConfigNode);

    function LibratoNode(n) {
        RED.nodes.createNode(this, n);
        this.librato = RED.nodes.getNode(n.librato);
        this.metricName = n.metricName;
        this.metricType = n.metricType || 'gauge';

        var node = this;

        this.on('input', function(msg) {
            var value = Number(msg.payload);

            if (isNaN(value)) {
                node.warn('Payload is NaN [' + msg.payload + ']');
            } else if (node.librato) {
                if (node.metricType == 'gauge') {
                    node.librato.client.measure(node.metricName, value);
                } else {
                    if (value) {
                        node.librato.client.increment(node.metricName, value);
                    } else {
                        node.librato.client.increment(node.metricName);
                    }
                }
            } else {
                node.error('Librato client is not configured');
            }
        });
    }
    RED.nodes.registerType('librato', LibratoNode);
}
<|endoftext|>


<commit_before><commit_msg>export default function<commit_after><|endoftext|>


<commit_before>#!/usr/bin/env node
'use strict'

const _ = require('lodash/fp')
const assert = require('assert')
const co = require('co')
const fs = require('mz/fs')
const path = require('path')
const requireDir = require('require-dir')
const winston = require('winston')

const librato = require('./index')

const logger = new winston.Logger({
  level: process.env.LIBRATO_LOG_LEVEL || process.env.LOG_LEVEL || 'info',
  transports: [
    new winston.transports.Console({
      stderrLevels: _.keys(winston.levels),
      prettyPrint: true,
      align: true,
      colorize: true
    })
  ]
})

const jsonStringify = json => JSON.stringify(json, undefined, 2) + '\n'

function writeFileOrFd (maybeSink) {
  const sink = maybeSink || process.stdout.fd
  const write = _.isString(sink) ? fs.writeFile : fs.write
  // return write(sink, ...arguments[1..])
  return write.apply(fs, _.chain(arguments).drop(1).unshift(sink).value())
}

// sync IO
function readConfigDir (path) {
  return requireDir(path, { recurse: true })
}

// Transforms config:
// 1. simplify structure read from dir (flattens subdirs and creates predictable arrays)
// 2. merge the __default__ metric with all other metrics and remove it
// 3. apply template_values to metric name/display_name/composite properties and
//    outdated metric names
function processRawConfig (config) {
  // support single objects or arrays in files in nested dirs, flatten to one level
  const allFlat = _.flow(_.defaultTo([]), _.toArray, _.flatten)

  // create all combinatorial permutations of values in config.template_values
  const allPermsRec = (acc, keys) =>
    _.isEmpty(keys)
      ? acc
      : _.flatMap(
        value => allPermsRec(_.merge(acc, { [keys[0]]: value }), _.drop(1, keys)),
        config.template_values[keys[0]]
      )
  const templateValuePermutations =
    _.isEmpty(config.template_values)
      ? [{}]
      : allPermsRec({}, _.keys(config.template_values))
  logger.debug({
    template_values: config.template_values,
    permutations: _.size(templateValuePermutations)
  })

  // template factories, simple and lifted to obj properties
  const createTemplate = source =>
    // lodash/fp is missing the arity-2 template function, so we need to un-fix it to pass options
    _.template.convert({fixed: false})(source, { interpolate: /{{([\s\S]+?)}}/g })
  const createPropsTemplate = obj => pathes => {
    const propValues = _.at(pathes, obj)
    const propTemplates = _.map(t => t ? createTemplate(t) : null, propValues)
    const evalPropTemplates = data => _.map(pt => pt ? pt(data) : null, propTemplates)
    const pathesZipEvaled =
      data => _.filter(x => x[1] !== null, _.zip(pathes, evalPropTemplates(data)))
    const setPathEvaled = (acc, pe) => _.set(pe[0], pe[1], acc)
    return data => _.reduce(setPathEvaled, obj, pathesZipEvaled(data))
  }

  // permutations in the sense of different template evaluations with templateValuePermutations
  const templatePermutations = template =>
    _.uniq(_.map(createTemplate(template), templateValuePermutations))
  const templatesPermutations = _.flatMap(templatePermutations)
  const permutationsOfObj = createObjTemplate => obj =>
    _.uniqWith(_.isEqual, _.map(createObjTemplate(obj), templateValuePermutations))
  const permutationsOfObjs = createObjTemplate => _.flatMap(permutationsOfObj(createObjTemplate))

  // custom metrics processing
  const applyDefaultMetric = metrics => {
    // want ES6: const [[defaultMetric={}], rest] = _.partition(...)
    const ps = _.partition(x => x.name === '__default__', metrics)
    assert(ps[0].length <= 1, 'more than 1 __default__ metric')
    const defaultMetric = ps[0][0] || {}
    const rest = ps[1]
    logger.debug({ defaultMetric })
    return _.map(m => _.merge(defaultMetric, m), rest)
  }
  const createMetricTemplate = metric =>
    createPropsTemplate(metric)(['name', 'display_name', 'composite'])
  const processRawMetrics =
    _.flow(allFlat, applyDefaultMetric, permutationsOfObjs(createMetricTemplate))

  return {
    metrics: processRawMetrics(config.metrics),
    spaces: allFlat(config.spaces),
    outdated: {
      metrics: templatesPermutations(config.outdated.metrics),
      spaces: config.outdated.spaces
    }
  }
}

// -- metric actions

function * listMetrics (maybeSink) {
  logger.verbose('listing metrics', { to: maybeSink })
  const metrics = yield librato.getAllPaginated(librato.getMetrics)
  const compact = _.map(_.get('name'), metrics)
  yield writeFileOrFd(maybeSink, jsonStringify(compact))
}

function * getMetrics (maybeSink) {
  logger.verbose('dumping metrics', { to: maybeSink })
  const metrics = yield librato.getAllPaginated(librato.getMetrics)
  yield writeFileOrFd(maybeSink, jsonStringify(metrics))
}

function * getMetric (name, maybeSink) {
  logger.verbose('retrieving metric %s', name, { name, to: maybeSink })
  const metric = yield librato.getMetric(name)
  yield writeFileOrFd(maybeSink, jsonStringify(metric))
}

// -- space actions

function * listSpaces (maybeSink) {
  logger.verbose('listing spaces', { to: maybeSink })
  const spaces = yield librato.getAllPaginated(librato.getSpaces)
  const compact = _.reduce((acc, s) => _.set(s.id, s.name, acc), {}, spaces)
  yield writeFileOrFd(maybeSink, jsonStringify(compact))
}

function * dumpSpace (name, maybeSink) {
  logger.verbose('dumping space', { space: name, to: maybeSink })
  const space = yield librato.dumpSpace(name)
  yield writeFileOrFd(maybeSink, jsonStringify(space))
}

function * createOrUpdateSpace (maybeSource) {
  const source = maybeSource || process.stdin.fd
  logger.verbose('updating space', { source })
  const buffer = yield fs.readFile(source)
  const space = JSON.parse(buffer.toString())
  logger.debug('space definition', { space })
  yield librato.createOrUpdateSpace(space)
}

function * deleteSpace (name) {
  logger.verbose('deleting space', { space: name })
  const space = yield librato.findSpaceByName(name)
  yield librato.deleteSpace(space.id)
}

// -- config dir actions

function * showConfigDir (configDir, maybeSink) {
  const absConfigDir = path.join(process.cwd(), configDir)
  logger.verbose('reading config dir %s', absConfigDir)
  const config = processRawConfig(readConfigDir(absConfigDir))
  yield writeFileOrFd(maybeSink, jsonStringify(config))
}

function * showRawConfigDir (configDir, maybeSink) {
  const absConfigDir = path.join(process.cwd(), configDir)
  logger.verbose('reading config dir %s', absConfigDir)
  const config = readConfigDir(absConfigDir)
  yield writeFileOrFd(maybeSink, jsonStringify(config))
}

/**
 * @TODO Some updates fail silently, e.g. trying to change a metric's l2met_type or created_by_ua.
 *  We could check this, alert, and provid an option to delete-and-recreate.
 *  But we don't know how the mentioned undocumented attributes are used, maybe they are
 *  informational only and we can ignore this.
 */
function * updateFromDir (configDir) {
  const absConfigDir = path.join(process.cwd(), configDir)
  logger.verbose('updating configuration from config dir %s', absConfigDir)
  const config = processRawConfig(readConfigDir(absConfigDir))

  var errorCount = 0
  const logOK = (what, id) => _result => {
    logger.verbose('%s %s', what, id)
  }
  const logAndCountError = (what, id) => err => {
    errorCount += 1
    logger.error('%s %s failed', what, id, {
      [what]: id,
      errors: err.error.errors
    })
  }
  const ignore404 = err => {
    if (err.statusCode !== 404) throw err
  }
  const withLogging = (what, id, action) =>
    action.then(logOK(what, id), logAndCountError(what, id))
  const withLoggingIgnore404 = (what, id, action) =>
    action.then(logOK(what, id)).catch(ignore404).catch(logAndCountError(what, id))

  const deleteMetric = name =>
    withLoggingIgnore404('delete metric', name, librato.deleteMetric(name))
  const updateMetric = metric =>
    withLogging('update metric', metric.name, librato.putMetric(metric.name, metric))
  const deleteSpace = name =>
    withLoggingIgnore404(
      'delete space', name,
      librato.findSpaceByName(name).then(_.get('id')).then(librato.deleteSpace)
    )
  const updateSpace = space =>
    withLogging('update space', space.name, librato.createOrUpdateSpace(space))

  yield {
    outdated: {
      metrics: _.map(deleteMetric, config.outdated.metrics),
      spaces: _.map(deleteSpace, config.outdated.spaces)
    },
    metrics: _.map(updateMetric, config.metrics),
    spaces: _.map(updateSpace, config.spaces)
  }

  if (errorCount > 0) { throw new Error(`${errorCount} errors occured`) }
}

// -- hidden dev actions

function * _adhoc () {
  logger.verbose('adhoc')
  // foo
}

// -- main

function * help () {
  const getCmdList = _.flow(_.keys, _.reject(_.startsWith('_')), _.join(', '))
  yield writeFileOrFd(null, `Commands: ${getCmdList(actions)}\n`)
}

const actions = {
  'list-metrics': listMetrics,
  'get-metrics': getMetrics,
  'get-metric': getMetric,
  'list-spaces': listSpaces,
  'dump-space': dumpSpace,
  'update-space': createOrUpdateSpace,
  'delete-space': deleteSpace,
  'show-config-dir': showConfigDir,
  'show-raw-config-dir': showRawConfigDir,
  'update-from-dir': updateFromDir,
  'help': help,
  '_adhoc': _adhoc
}

/**
 * CLI tool to manage Librato backend configuration.
 *
 * @author Jürgen Strobel <juergen.strobel@emarsys.com>
 */
function * main (argv) {
  const cmd = argv[2]
  const args = _.drop(3, argv)
  function * unknownCommand () { throw new Error(`unknown command ${cmd}, use "help"`) }
  try {
    if (process.env.LIBRATO_USER === undefined || process.env.LIBRATO_TOKEN === undefined) {
      throw new Error('LIBRATO_USER and LIBRATO_TOKEN must be set in the environment')
    }
    // let's look at proper argv parsing sometime
    // https://www.npmjs.com/package/command-line-args
    // or https://github.com/75lb/command-line-commands
    const action = _.getOr(unknownCommand, cmd, actions)
    logger.debug('dispatching', { cmd, action, args })
    yield action.apply(undefined, args)
    logger.debug('success')
  } catch (err) {
    process.exitCode = 1
    _.has('error', err)
      ? logger.error('%s: %s', err.name, err.message, err.error)
      : logger.error('%s: %s', err.name, err.message)
  }
}

module.exports = co.wrap(main)
module.exports.actions = actions

// execute main only if required at top level
if (require.main === module) { module.exports(process.argv) }
<commit_msg>EDREI-29826 - Removed _adhoc from cli tool.<commit_after>#!/usr/bin/env node
'use strict'

const _ = require('lodash/fp')
const assert = require('assert')
const co = require('co')
const fs = require('mz/fs')
const path = require('path')
const requireDir = require('require-dir')
const winston = require('winston')

const librato = require('./index')

const logger = new winston.Logger({
  level: process.env.LIBRATO_LOG_LEVEL || process.env.LOG_LEVEL || 'info',
  transports: [
    new winston.transports.Console({
      stderrLevels: _.keys(winston.levels),
      prettyPrint: true,
      align: true,
      colorize: true
    })
  ]
})

const jsonStringify = json => JSON.stringify(json, undefined, 2) + '\n'

function writeFileOrFd (maybeSink) {
  const sink = maybeSink || process.stdout.fd
  const write = _.isString(sink) ? fs.writeFile : fs.write
  // return write(sink, ...arguments[1..])
  return write.apply(fs, _.chain(arguments).drop(1).unshift(sink).value())
}

// sync IO
function readConfigDir (path) {
  return requireDir(path, { recurse: true })
}

// Transforms config:
// 1. simplify structure read from dir (flattens subdirs and creates predictable arrays)
// 2. merge the __default__ metric with all other metrics and remove it
// 3. apply template_values to metric name/display_name/composite properties and
//    outdated metric names
function processRawConfig (config) {
  // support single objects or arrays in files in nested dirs, flatten to one level
  const allFlat = _.flow(_.defaultTo([]), _.toArray, _.flatten)

  // create all combinatorial permutations of values in config.template_values
  const allPermsRec = (acc, keys) =>
    _.isEmpty(keys)
      ? acc
      : _.flatMap(
        value => allPermsRec(_.merge(acc, { [keys[0]]: value }), _.drop(1, keys)),
        config.template_values[keys[0]]
      )
  const templateValuePermutations =
    _.isEmpty(config.template_values)
      ? [{}]
      : allPermsRec({}, _.keys(config.template_values))
  logger.debug({
    template_values: config.template_values,
    permutations: _.size(templateValuePermutations)
  })

  // template factories, simple and lifted to obj properties
  const createTemplate = source =>
    // lodash/fp is missing the arity-2 template function, so we need to un-fix it to pass options
    _.template.convert({fixed: false})(source, { interpolate: /{{([\s\S]+?)}}/g })
  const createPropsTemplate = obj => pathes => {
    const propValues = _.at(pathes, obj)
    const propTemplates = _.map(t => t ? createTemplate(t) : null, propValues)
    const evalPropTemplates = data => _.map(pt => pt ? pt(data) : null, propTemplates)
    const pathesZipEvaled =
      data => _.filter(x => x[1] !== null, _.zip(pathes, evalPropTemplates(data)))
    const setPathEvaled = (acc, pe) => _.set(pe[0], pe[1], acc)
    return data => _.reduce(setPathEvaled, obj, pathesZipEvaled(data))
  }

  // permutations in the sense of different template evaluations with templateValuePermutations
  const templatePermutations = template =>
    _.uniq(_.map(createTemplate(template), templateValuePermutations))
  const templatesPermutations = _.flatMap(templatePermutations)
  const permutationsOfObj = createObjTemplate => obj =>
    _.uniqWith(_.isEqual, _.map(createObjTemplate(obj), templateValuePermutations))
  const permutationsOfObjs = createObjTemplate => _.flatMap(permutationsOfObj(createObjTemplate))

  // custom metrics processing
  const applyDefaultMetric = metrics => {
    // want ES6: const [[defaultMetric={}], rest] = _.partition(...)
    const ps = _.partition(x => x.name === '__default__', metrics)
    assert(ps[0].length <= 1, 'more than 1 __default__ metric')
    const defaultMetric = ps[0][0] || {}
    const rest = ps[1]
    logger.debug({ defaultMetric })
    return _.map(m => _.merge(defaultMetric, m), rest)
  }
  const createMetricTemplate = metric =>
    createPropsTemplate(metric)(['name', 'display_name', 'composite'])
  const processRawMetrics =
    _.flow(allFlat, applyDefaultMetric, permutationsOfObjs(createMetricTemplate))

  return {
    metrics: processRawMetrics(config.metrics),
    spaces: allFlat(config.spaces),
    outdated: {
      metrics: templatesPermutations(config.outdated.metrics),
      spaces: config.outdated.spaces
    }
  }
}

// -- metric actions

function * listMetrics (maybeSink) {
  logger.verbose('listing metrics', { to: maybeSink })
  const metrics = yield librato.getAllPaginated(librato.getMetrics)
  const compact = _.map(_.get('name'), metrics)
  yield writeFileOrFd(maybeSink, jsonStringify(compact))
}

function * getMetrics (maybeSink) {
  logger.verbose('dumping metrics', { to: maybeSink })
  const metrics = yield librato.getAllPaginated(librato.getMetrics)
  yield writeFileOrFd(maybeSink, jsonStringify(metrics))
}

function * getMetric (name, maybeSink) {
  logger.verbose('retrieving metric %s', name, { name, to: maybeSink })
  const metric = yield librato.getMetric(name)
  yield writeFileOrFd(maybeSink, jsonStringify(metric))
}

// -- space actions

function * listSpaces (maybeSink) {
  logger.verbose('listing spaces', { to: maybeSink })
  const spaces = yield librato.getAllPaginated(librato.getSpaces)
  const compact = _.reduce((acc, s) => _.set(s.id, s.name, acc), {}, spaces)
  yield writeFileOrFd(maybeSink, jsonStringify(compact))
}

function * dumpSpace (name, maybeSink) {
  logger.verbose('dumping space', { space: name, to: maybeSink })
  const space = yield librato.dumpSpace(name)
  yield writeFileOrFd(maybeSink, jsonStringify(space))
}

function * createOrUpdateSpace (maybeSource) {
  const source = maybeSource || process.stdin.fd
  logger.verbose('updating space', { source })
  const buffer = yield fs.readFile(source)
  const space = JSON.parse(buffer.toString())
  logger.debug('space definition', { space })
  yield librato.createOrUpdateSpace(space)
}

function * deleteSpace (name) {
  logger.verbose('deleting space', { space: name })
  const space = yield librato.findSpaceByName(name)
  yield librato.deleteSpace(space.id)
}

// -- config dir actions

function * showConfigDir (configDir, maybeSink) {
  const absConfigDir = path.join(process.cwd(), configDir)
  logger.verbose('reading config dir %s', absConfigDir)
  const config = processRawConfig(readConfigDir(absConfigDir))
  yield writeFileOrFd(maybeSink, jsonStringify(config))
}

function * showRawConfigDir (configDir, maybeSink) {
  const absConfigDir = path.join(process.cwd(), configDir)
  logger.verbose('reading config dir %s', absConfigDir)
  const config = readConfigDir(absConfigDir)
  yield writeFileOrFd(maybeSink, jsonStringify(config))
}

/**
 * @TODO Some updates fail silently, e.g. trying to change a metric's l2met_type or created_by_ua.
 *  We could check this, alert, and provid an option to delete-and-recreate.
 *  But we don't know how the mentioned undocumented attributes are used, maybe they are
 *  informational only and we can ignore this.
 */
function * updateFromDir (configDir) {
  const absConfigDir = path.join(process.cwd(), configDir)
  logger.verbose('updating configuration from config dir %s', absConfigDir)
  const config = processRawConfig(readConfigDir(absConfigDir))

  var errorCount = 0
  const logOK = (what, id) => _result => {
    logger.verbose('%s %s', what, id)
  }
  const logAndCountError = (what, id) => err => {
    errorCount += 1
    logger.error('%s %s failed', what, id, {
      [what]: id,
      errors: err.error.errors
    })
  }
  const ignore404 = err => {
    if (err.statusCode !== 404) throw err
  }
  const withLogging = (what, id, action) =>
    action.then(logOK(what, id), logAndCountError(what, id))
  const withLoggingIgnore404 = (what, id, action) =>
    action.then(logOK(what, id)).catch(ignore404).catch(logAndCountError(what, id))

  const deleteMetric = name =>
    withLoggingIgnore404('delete metric', name, librato.deleteMetric(name))
  const updateMetric = metric =>
    withLogging('update metric', metric.name, librato.putMetric(metric.name, metric))
  const deleteSpace = name =>
    withLoggingIgnore404(
      'delete space', name,
      librato.findSpaceByName(name).then(_.get('id')).then(librato.deleteSpace)
    )
  const updateSpace = space =>
    withLogging('update space', space.name, librato.createOrUpdateSpace(space))

  yield {
    outdated: {
      metrics: _.map(deleteMetric, config.outdated.metrics),
      spaces: _.map(deleteSpace, config.outdated.spaces)
    },
    metrics: _.map(updateMetric, config.metrics),
    spaces: _.map(updateSpace, config.spaces)
  }

  if (errorCount > 0) { throw new Error(`${errorCount} errors occured`) }
}

// -- main

function * help () {
  const getCmdList = _.flow(_.keys, _.reject(_.startsWith('_')), _.join(', '))
  yield writeFileOrFd(null, `Commands: ${getCmdList(actions)}\n`)
}

const actions = {
  'list-metrics': listMetrics,
  'get-metrics': getMetrics,
  'get-metric': getMetric,
  'list-spaces': listSpaces,
  'dump-space': dumpSpace,
  'update-space': createOrUpdateSpace,
  'delete-space': deleteSpace,
  'show-config-dir': showConfigDir,
  'show-raw-config-dir': showRawConfigDir,
  'update-from-dir': updateFromDir,
  'help': help
}

/**
 * CLI tool to manage Librato backend configuration.
 *
 * @author Jürgen Strobel <juergen.strobel@emarsys.com>
 */
function * main (argv) {
  const cmd = argv[2]
  const args = _.drop(3, argv)
  function * unknownCommand () { throw new Error(`unknown command ${cmd}, use "help"`) }
  try {
    if (process.env.LIBRATO_USER === undefined || process.env.LIBRATO_TOKEN === undefined) {
      throw new Error('LIBRATO_USER and LIBRATO_TOKEN must be set in the environment')
    }
    // let's look at proper argv parsing sometime
    // https://www.npmjs.com/package/command-line-args
    // or https://github.com/75lb/command-line-commands
    const action = _.getOr(unknownCommand, cmd, actions)
    logger.debug('dispatching', { cmd, action, args })
    yield action.apply(undefined, args)
    logger.debug('success')
  } catch (err) {
    process.exitCode = 1
    _.has('error', err)
      ? logger.error('%s: %s', err.name, err.message, err.error)
      : logger.error('%s: %s', err.name, err.message)
  }
}

module.exports = co.wrap(main)
module.exports.actions = actions

// execute main only if required at top level
if (require.main === module) { module.exports(process.argv) }
<|endoftext|>


<commit_before><commit_msg>Fix IE little bug<commit_after><|endoftext|>


<commit_before><commit_msg>maybe stringify AFTER you've composed your object<commit_after><|endoftext|>


<commit_before><commit_msg>Fixing seeding command issue without --seed params<commit_after><|endoftext|>


<commit_before><commit_msg>fix a bug<commit_after><|endoftext|>