<commit_before>define([
	'jquery',
	'underscore',
	'backbone',
	'config',
	'utils',
	'text!templates/map-layer.html',
	'views/panel-view-base',
	'views/histogram-view',
	'views/legend-view',
	'lib/color-gradient/color-gradient',
], function($, _, Backbone, config, utils, templateHtml, PanelViewBase, HistogramView, LegendView, ColorGradient) {

	var MapLayerView = Backbone.View.extend({

		className: 'map-layer',

	    events: {
			//'click .visibility' : 'visibilityChanged',
			'click .panel-controls .toggle-layer': 'toggleLayerClicked',
			'click .panel-controls .show-layer-editor': 'showLayerEditorClicked',
			'click .panel-controls .show-layer-details': 'showLayerDetailsClicked',
			'click .panel-controls .show-layer-extents': 'showLayerExtentsClicked',
			'click .panel-controls .move-layer ': function() { return false; }
	    },

	    initialize: function(options)
	    {
			this.vent = options.vent;
		    this.template = _.template(templateHtml);
		    this.listenTo(this.model, 'change', this.modelChanged);
		    this.listenTo(this.model, 'toggle:enabled', this.updateEnabled);
		    this.listenTo(this.model, 'destroy', this.remove);

			this.listenTo(this.model.featureCollection, 'request', this.layerFeaturesRequest);
			this.listenTo(this.model.featureCollection, 'error', this.layerFeaturesRequestError);
			this.listenTo(this.model.featureCollection, 'sync', this.layerFeaturesSynced);
	    },

	    showSpinner: function()
	    {
	    	if (!this.spinner.is(':visible')) {
	    		this.spinner.css({opacity: 0}).show();
	    	}
			this.spinner.stop().animate({opacity: 1}, 50);
	    },

	    hideSpinner: function()
	    {
	    	var self = this;
			this.spinner.stop().fadeOut(300, function() {
				//self.spinner.hide();
			});
	    },

	    layerFeaturesRequest: function(model, xhr, options)
	    {
	    	this.isLoading = true;
	    	this.updateStatus();
	    },

	    layerFeaturesRequestError: function(model, xhr, options)
	    {
	    	this.isLoading = false;
	    	this.updateStatus(__('failed'));
	    },

	    layerFeaturesSynced: function(model, resp, options)
	    {
	    	this.isLoading = false;
	    	this.updateStatus();
	    },

	    updateStatus: function(status)
	    {
	    	var countStatus = '',
				progress = this.model.getFeatureCollectionAttr('progress'),
				featureCollection = this.model.featureCollection;

			if (this.isLoading || this.model.getDataStatus() != DataStatus.COMPLETE) {
		    	this.showSpinner();
			} else {
		    	this.hideSpinner();
			}

			if (!status) {
		    	switch (this.model.getDataStatus()) {
		    		case DataStatus.COMPLETE:
		    			if (this.model.isEnabled()) {
		    				if (featureCollection.initiallyFetched) {
								status = __('%(number)i of %(total)i', {
									number: formatLargeNumber(featureCollection.counts.original),
									total: formatLargeNumber(featureCollection.counts.full)
								});
								var url = featureCollection.url();
								if (this.model.attributes.featureCollection) {
									status += ' ';
								}
							} else {
			    				status = 'loading…';
							}
		    			} else {
		    				status = '';
		    			}
						break;
		    		case DataStatus.IMPORTING:
		    		case DataStatus.IMPORTING_INC:
		    			status = __(progress ? 'importing… %(count)s' : 'importing…', {
		    				count: formatLargeNumber(this.model.attributes.featureCollection.progress)
		    			});
						break;
		    		case DataStatus.UNREDUCED:
		    		case DataStatus.UNREDUCED_INC:
		    			status = __('queued for crunching…');
						break;
		    		case DataStatus.REDUCING:
		    		case DataStatus.REDUCING_INC:
		    			if (this.model.attributes.featureCollection.numBusy) {
			    			var percent = Math.floor(progress / this.model.attributes.featureCollection.numBusy * 100);
			    			status = __(progress ? 'crunching… %(percent)s%' : 'crunching…', {
			    				percent: percent
			    			});
			    			this.$('.progress .bar').css('width', percent + '%');
			    			this.$('.progress').show();
		    			} else {
			    			status = __('crunching…', {
			    			});
		    			}
						break;
		    	}
			}

	    	var el = this.$(".status .text");
	    	el.html(status);
	    },

	    render: function()
	    {
	    	var self = this;
			this.$el.html(this.template());
			this.$el.attr('data-id', this.model.id);

			var stateIndicator = this.$('.state-indicator');
			if (stateIndicator.length) {
				this.spinner = stateIndicator.html(new Spinner({radius:4,length:0,width:4,color:'#eee',lines:7,speed:1.5}).spin().el).hide();
			}

			// set up accordion group
			this.toggleEl = this.$(".accordion-toggle");
			this.collapseEl = this.$(".collapse");
			this.toggleEl.attr("href", "#collapse-" + this.className + '-' + this.model.id);
			this.collapseEl.attr("id", "collapse-" + this.className + '-' + this.model.id);
			// toggle initial state of accordion group
			var enabled = this.model.isEnabled();
			if (enabled) {
				this.collapseEl.addClass('in');
			} else {
				this.toggleEl.addClass('collapsed');
			}
			this.collapseEl.on('show', function() {
				if (!self.model.isEnabled()) {
					self.model.toggleEnabled(true);
				}
			});

			this.$('.status').toggle(enabled);
			this.$('.admin-control').toggle(app.isMapAdmin());
			this.$('.details').hide();
			this.populateFromModel(true);

			return this;
	    },

	    expand: function()
	    {
	    	if (!this.collapseEl.is('.in')) {
		    	this.collapseEl.collapse('toggle');
		    	// class not set by Bootstrap if toggled like this
				this.toggleEl.removeClass('collapsed');
	    	}
	    	return this;
	    },

	    collapse: function()
	    {
	    	if (this.collapseEl.is('.in')) {
		    	this.collapseEl.collapse('toggle');
		    	// class not set by Bootstrap if toggled like this
				this.toggleEl.addClass('collapsed');
	    	}
	    	return this;
	    },

	    hide: function(duration)
	    {
	    	this.$el.hide(duration);
	    	return this;
	    },

	    show: function(duration)
	    {
	    	this.$el.show(duration);
	    	return this;
	    },

	    renderHistogram: function()
	    {
	    	if (this.histogramView) {
	    		this.histogramView.$el.remove();
	    	} else {
				this.histogramView = new HistogramView({model: this.model});
	    	}
			if (!this.model.canDisplayValues()
				|| !this.model.isNumeric()
				|| !this.model.getLayerOptions().histogram) return;

			this.$('.graphs').append(this.histogramView.el);
			this.histogramView.render().delegateEvents();
	    },

	    renderLegend: function()
	    {
	    	if (this.legendView) {
	    		this.legendView.$el.remove();
	    	} else {
				this.legendView = new LegendView({model: this.model});
	    	}
			if (!this.model.canDisplayValues()) return;
			this.$('.legend').append(this.legendView.el);
			this.legendView.render().delegateEvents();
	    },

	    setSuperView: function(superView) {
			this.listenTo(superView, 'panel:resize', this.panelViewResized);
	    },

		panelViewResized: function(panelView)
		{
			if (this.histogramView) {
				this.histogramView.render();
			}
	    	if (this.legendView) {
				this.legendView.removePopover();
			}
		},

		updateEnabled: function(animate)
		{
	    	if (this.legendView) {
				this.legendView.removePopover();
			}
			var enabled = this.model.isEnabled(),
				d = animate || animate == undefined ? 'fast' : 0;
			$(this.el).toggleClass('enabled', enabled);
			$(this.el).toggleClass('disabled', !enabled);
			if (enabled) {
				this.$('.status').slideDown(d);
			} else {
				this.$('.status').slideUp(d);
			}
			if (!enabled) {
				this.collapse();
			} else {
				this.expand();
			}

			this.$('.layer-extents').toggle(enabled
				&& this.model.getBbox().length > 0);
		},

		modelChanged: function(model)
		{
	    	if (this.legendView) {
				this.legendView.removePopover();
			}
			this.populateFromModel(
				this.model.hasChangedColors()
				|| this.model.hasChanged('featureCollection.status')
				|| this.model.hasChanged('layerOptions.histogram'));
		},

	    populateFromModel: function(renderSubViews)
	    {
	    	this.updateEnabled(false);
            if (renderSubViews) {
				this.renderHistogram();
				this.renderLegend();
			}
			this.updateStatus();
			this.$('.model-title').text(this.model.getDisplay('title'));

			this.$('.admin-control.layer-editor').toggle(app.isMapAdmin()
				&& this.model.getDataStatus() == DataStatus.COMPLETE);

			var collectionAttrs = this.model.attributes.featureCollection,
				description = this.model.getDisplay('description'),
				source = this.model.getDisplay('source'),
				sourceUrl = this.model.getDisplay('sourceUrl');

			if (description) {
				this.$('.description').html(description);
				this.$('.layer-details').show();
			} else {
				this.$('.description').hide();
				this.$('.panel-controls .layer-details').hide();
			}

			if (source || (collectionAttrs && collectionAttrs.sync)) {
				this.$('.source').show();
				var sourceLink = sourceUrl && sourceUrl.length ?
						'%(source)s'.format({sourceUrl: sourceUrl, source: source}) : source;
				if (source) {
					source = __('Source: %(source)s', {source: sourceLink});
				}
    			if (collectionAttrs.sync) {
					source += ' (' + __('updated %(date)s', {
						date: new Date(
							collectionAttrs.reduce ?
							(collectionAttrs.updatedAt < collectionAttrs.lastReducedAt || !collectionAttrs.lastReducedAt ?
								collectionAttrs.updatedAt : collectionAttrs.lastReducedAt)
							: collectionAttrs.updatedAt)
								.format(locale.formats.DATE_SHORT)
					}) + ')';
    			}
				this.$('.source').html(source);
			} else {
				this.$('.source').hide();
			}
	    },

		toggleLayerClicked: function(event)
		{
			this.model.toggleEnabled(!this.model.isEnabled());
			return false;
		},

		showLayerEditorClicked: function(event)
		{
			this.vent.trigger('showMapLayerEditor', this.model);
			return false;
		},

		showLayerExtentsClicked: function(event)
		{
			app.mapView.zoomToExtent(this.model.attributes.featureCollection.bbox);
			return false;
		},

		showLayerDetailsClicked: function(event)
		{
			var self = this;
			this.$('.details').uiToggle({
				activate: this.$('.show-layer-details'),
				show: function() {
					self.expand();
				}
			});
			return false;
		}

	});

	return MapLayerView;
});
<commit_msg>Improved enter key handling and fixed color scheme bugs<commit_after>define([
	'jquery',
	'underscore',
	'backbone',
	'config',
	'utils',
	'text!templates/map-layer.html',
	'views/panel-view-base',
	'views/histogram-view',
	'views/legend-view',
	'lib/color-gradient/color-gradient',
], function($, _, Backbone, config, utils, templateHtml, PanelViewBase, HistogramView, LegendView, ColorGradient) {

	var MapLayerView = Backbone.View.extend({

		className: 'map-layer',

	    events: {
			//'click .visibility' : 'visibilityChanged',
			'click .panel-controls .toggle-layer': 'toggleLayerClicked',
			'click .panel-controls .show-layer-editor': 'showLayerEditorClicked',
			'click .panel-controls .show-layer-details': 'showLayerDetailsClicked',
			'click .panel-controls .show-layer-extents': 'showLayerExtentsClicked',
			'click .panel-controls .move-layer ': function() { return false; }
	    },

	    initialize: function(options)
	    {
			this.vent = options.vent;
		    this.template = _.template(templateHtml);
		    this.listenTo(this.model, 'change', this.modelChanged);
		    this.listenTo(this.model, 'toggle:enabled', this.updateEnabled);
		    this.listenTo(this.model, 'destroy', this.remove);

			this.listenTo(this.model.featureCollection, 'request', this.layerFeaturesRequest);
			this.listenTo(this.model.featureCollection, 'error', this.layerFeaturesRequestError);
			this.listenTo(this.model.featureCollection, 'sync', this.layerFeaturesSynced);
	    },

	    showSpinner: function()
	    {
	    	if (!this.spinner.is(':visible')) {
	    		this.spinner.css({opacity: 0}).show();
	    	}
			this.spinner.stop().animate({opacity: 1}, 50);
	    },

	    hideSpinner: function()
	    {
	    	var self = this;
			this.spinner.stop().fadeOut(300, function() {
				//self.spinner.hide();
			});
	    },

	    layerFeaturesRequest: function(model, xhr, options)
	    {
	    	this.isLoading = true;
	    	this.updateStatus();
	    },

	    layerFeaturesRequestError: function(model, xhr, options)
	    {
	    	this.isLoading = false;
	    	this.updateStatus(__('failed'));
	    },

	    layerFeaturesSynced: function(model, resp, options)
	    {
	    	this.isLoading = false;
	    	this.updateStatus();
	    },

	    updateStatus: function(status)
	    {
	    	var countStatus = '',
				progress = this.model.getFeatureCollectionAttr('progress'),
				featureCollection = this.model.featureCollection;

			if (this.isLoading || this.model.getDataStatus() != DataStatus.COMPLETE) {
		    	this.showSpinner();
			} else {
		    	this.hideSpinner();
			}

			if (!status) {
		    	switch (this.model.getDataStatus()) {
		    		case DataStatus.COMPLETE:
		    			if (this.model.isEnabled()) {
		    				if (featureCollection.initiallyFetched) {
								status = __('%(number)i of %(total)i', {
									number: formatLargeNumber(featureCollection.counts.original),
									total: formatLargeNumber(featureCollection.counts.full)
								});
								var url = featureCollection.url();
								if (this.model.attributes.featureCollection) {
									status += ' ';
								}
							} else {
			    				status = 'loading…';
							}
		    			} else {
		    				status = '';
		    			}
						break;
		    		case DataStatus.IMPORTING:
		    		case DataStatus.IMPORTING_INC:
		    			status = __(progress ? 'importing… %(count)s' : 'importing…', {
		    				count: formatLargeNumber(this.model.attributes.featureCollection.progress)
		    			});
						break;
		    		case DataStatus.UNREDUCED:
		    		case DataStatus.UNREDUCED_INC:
		    			status = __('queued for crunching…');
						break;
		    		case DataStatus.REDUCING:
		    		case DataStatus.REDUCING_INC:
		    			if (this.model.attributes.featureCollection.numBusy) {
			    			var percent = Math.floor(progress / this.model.attributes.featureCollection.numBusy * 100);
			    			status = __(progress ? 'crunching… %(percent)s%' : 'crunching…', {
			    				percent: percent
			    			});
			    			this.$('.progress .bar').css('width', percent + '%');
			    			this.$('.progress').show();
		    			} else {
			    			status = __('crunching…', {
			    			});
		    			}
						break;
		    	}
			}

	    	var el = this.$(".status .text");
	    	el.html(status);
	    },

	    render: function()
	    {
	    	var self = this;
			this.$el.html(this.template());
			this.$el.attr('data-id', this.model.id);

			var stateIndicator = this.$('.state-indicator');
			if (stateIndicator.length) {
				this.spinner = stateIndicator.html(new Spinner({radius:4,length:0,width:4,color:'#eee',lines:7,speed:1.5}).spin().el).hide();
			}

			// set up accordion group
			this.toggleEl = this.$(".accordion-toggle");
			this.collapseEl = this.$(".collapse");
			this.toggleEl.attr("href", "#collapse-" + this.className + '-' + this.model.id);
			this.collapseEl.attr("id", "collapse-" + this.className + '-' + this.model.id);
			// toggle initial state of accordion group
			var enabled = this.model.isEnabled();
			if (enabled) {
				this.collapseEl.addClass('in');
			} else {
				this.toggleEl.addClass('collapsed');
			}
			this.collapseEl.on('show', function() {
				if (!self.model.isEnabled()) {
					self.model.toggleEnabled(true);
				}
			});

			this.$('.status').toggle(enabled);
			this.$('.admin-control').toggle(app.isMapAdmin());
			this.$('.details').hide();
			this.populateFromModel(true);

			return this;
	    },

	    expand: function()
	    {
	    	if (!this.collapseEl.is('.in')) {
		    	this.collapseEl.collapse('toggle');
		    	// class not set by Bootstrap if toggled like this
				this.toggleEl.removeClass('collapsed');
	    	}
	    	return this;
	    },

	    collapse: function()
	    {
	    	if (this.collapseEl.is('.in')) {
		    	this.collapseEl.collapse('toggle');
		    	// class not set by Bootstrap if toggled like this
				this.toggleEl.addClass('collapsed');
	    	}
	    	return this;
	    },

	    hide: function(duration)
	    {
	    	this.$el.hide(duration);
	    	return this;
	    },

	    show: function(duration)
	    {
	    	this.$el.show(duration);
	    	return this;
	    },

	    renderHistogram: function()
	    {
	    	if (this.histogramView) {
	    		this.histogramView.$el.remove();
	    	} else {
				this.histogramView = new HistogramView({model: this.model});
	    	}
			if (!this.model.canDisplayValues()
				|| !this.model.isNumeric()
				|| !this.model.getLayerOptions().histogram) return;

			this.$('.graphs').append(this.histogramView.el);
			this.histogramView.render().delegateEvents();
	    },

	    renderLegend: function()
	    {
	    	if (this.legendView) {
	    		this.legendView.$el.remove();
	    	} else {
				this.legendView = new LegendView({model: this.model});
	    	}
			if (!this.model.canDisplayValues()) return;
			this.$('.legend').append(this.legendView.el);
			this.legendView.render().delegateEvents();
	    },

	    setSuperView: function(superView) {
			this.listenTo(superView, 'panel:resize', this.panelViewResized);
	    },

		panelViewResized: function(panelView)
		{
			if (this.histogramView) {
				this.histogramView.render();
			}
	    	if (this.legendView) {
				this.legendView.removePopover();
			}
		},

		updateEnabled: function(animate)
		{
	    	if (this.legendView) {
				this.legendView.removePopover();
			}
			var enabled = this.model.isEnabled(),
				d = animate || animate == undefined ? 'fast' : 0;
			$(this.el).toggleClass('enabled', enabled);
			$(this.el).toggleClass('disabled', !enabled);
			if (enabled) {
				this.$('.status').slideDown(d);
			} else {
				this.$('.status').slideUp(d);
			}
			if (!enabled) {
				this.collapse();
			} else {
				this.expand();
			}

			this.$('.layer-extents').toggle(enabled
				&& this.model.getBbox().length > 0);
		},

		modelChanged: function(model)
		{
	    	if (this.legendView) {
				this.legendView.removePopover();
			}
			this.populateFromModel(
				this.model.hasChangedColors()
				|| this.model.hasChanged('featureCollection.status')
				|| this.model.hasChanged('layerOptions.unit')
				|| this.model.hasChanged('layerOptions.histogram'));
		},

	    populateFromModel: function(renderSubViews)
	    {
	    	this.updateEnabled(false);
            if (renderSubViews) {
				this.renderHistogram();
				this.renderLegend();
			}
			this.updateStatus();
			this.$('.model-title').text(this.model.getDisplay('title'));

			this.$('.admin-control.layer-editor').toggle(app.isMapAdmin()
				&& this.model.getDataStatus() == DataStatus.COMPLETE);

			var collectionAttrs = this.model.attributes.featureCollection,
				description = this.model.getDisplay('description'),
				source = this.model.getDisplay('source'),
				sourceUrl = this.model.getDisplay('sourceUrl');

			if (description) {
				this.$('.description').html(description);
				this.$('.layer-details').show();
			} else {
				this.$('.description').hide();
				this.$('.panel-controls .layer-details').hide();
			}

			if (source || (collectionAttrs && collectionAttrs.sync)) {
				this.$('.source').show();
				var sourceLink = sourceUrl && sourceUrl.length ?
						'%(source)s'.format({sourceUrl: sourceUrl, source: source}) : source;
				if (source) {
					source = __('Source: %(source)s', {source: sourceLink});
				}
    			if (collectionAttrs.sync) {
					source += ' (' + __('updated %(date)s', {
						date: new Date(
							collectionAttrs.reduce ?
							(collectionAttrs.updatedAt < collectionAttrs.lastReducedAt || !collectionAttrs.lastReducedAt ?
								collectionAttrs.updatedAt : collectionAttrs.lastReducedAt)
							: collectionAttrs.updatedAt)
								.format(locale.formats.DATE_SHORT)
					}) + ')';
    			}
				this.$('.source').html(source);
			} else {
				this.$('.source').hide();
			}
	    },

		toggleLayerClicked: function(event)
		{
			this.model.toggleEnabled(!this.model.isEnabled());
			return false;
		},

		showLayerEditorClicked: function(event)
		{
			this.vent.trigger('showMapLayerEditor', this.model);
			return false;
		},

		showLayerExtentsClicked: function(event)
		{
			app.mapView.zoomToExtent(this.model.attributes.featureCollection.bbox);
			return false;
		},

		showLayerDetailsClicked: function(event)
		{
			var self = this;
			this.$('.details').uiToggle({
				activate: this.$('.show-layer-details'),
				show: function() {
					self.expand();
				}
			});
			return false;
		}

	});

	return MapLayerView;
});
<|endoftext|>


<commit_before>document.addEventListener('DOMContentLoaded', function() {

    var themesTypesNames = [];
    themesTypesNames.push('ColorThemes');

    /*
     * By default 2 types of themes: application and RAE search (only background
     * color in this) with 4 themes for the first and 2 for the second.
     * First theme of each type is selected.
     */
    var themes = [];
    themes.push({name: 'ColorThemes', values: [
            {name: 'dark', shownName: 'dark',
                values: {'@background': '#151515', '@foreground': '#BBBBBB',
                        '@links': '#88AAFF', '@linksBackground': 'rgba(87, 187, 255, 0.2)',
                        '@listsHeader': '#FFAA15'}},
            {name: 'black', shownName: 'black',
                values: {'@background': '#000000', '@foreground': '#999999',
                        '@links': '#7799EE', '@linksBackground': 'rgba(65, 165, 235, 0.2)',
                        '@listsHeader': '#EE9900'}},
            {name: 'dawn', shownName: 'dawn',
                values: {'@background': '#DD8800', '@foreground': '#FFFFFF',
                        '@links': '#0044FF', '@linksBackground': 'rgba(0, 0, 87, 0.3)',
                        '@listsHeader': '#AA0000'}},
			{name: 'sunset', shownName: 'sunset',
                values: {'@background': '#880000', '@foreground': '#DDBB88',
                        '@links': '#0044FF', '@linksBackground': 'rgba(0, 0, 87, 0.3)',
                        '@listsHeader': '#DD8800'}},
			{name: 'nightly', shownName: 'nightly',
                values: {'@background': '#001144', '@foreground': '#AACCFF',
                        '@links': '#0044FF', '@linksBackground': 'rgba(0, 0, 87, 0.3)',
                        '@listsHeader': '#FFAA15'}},
            {name: 'sepia', shownName: 'sepia',
                values: {'@background': '#CCCCAA', '@foreground': '#000',
                        '@links': '#0000BB', '@linksBackground': 'rgba(0, 213, 255, 0.3)',
                        '@listsHeader': '#FF4E00'}},
            {name: 'light', shownName: 'light',
                values: {'@background': '#E8E8E8', '@foreground': '#000000',
                        '@links': '#0000BB', '@linksBackground': 'rgba(0, 213, 255, 0.3)',
                        '@listsHeader': '#FF4E00'}}],
		preview: {'this': 'background: @background; color: @foreground !important;', 'label': 'color: @foreground !important;', 'a': 'color: @links;',
			'section header': 'color: @listsHeader; border-bottom-color: @listHeader;',
			'input:not(.color),.camaLessForm input[type="radio"] ~ span': 'color: @foreground; background-color: @background; filter: brightness(0.8); border-color: @foreground;'}});

    var form = [document.getElementById('themes')];
    var callbacks = [callbackThemesClose];
    setTimeout(function() {

	}, 500);
	// Open DB and create form
    openCamaLessDb('RAEfox_camaLESSdb', less, themesTypesNames, themes, form, callbacks);
});<commit_msg>Better preset color themes.<commit_after>document.addEventListener('DOMContentLoaded', function() {

    var themesTypesNames = [];
    themesTypesNames.push('ColorThemes');

    /*
     * By default 2 types of themes: application and RAE search (only background
     * color in this) with 4 themes for the first and 2 for the second.
     * First theme of each type is selected.
     */
    var themes = [];
    themes.push({name: 'ColorThemes', values: [
            {name: 'dark', shownName: 'dark',
                values: {'@background': '#151515', '@foreground': '#BBBBBB',
                        '@links': '#88AAFF', '@linksBackground': 'rgba(87, 187, 255, 0.2)',
                        '@listsHeader': '#FFAA15'}},
            {name: 'black', shownName: 'black',
                values: {'@background': '#000000', '@foreground': '#999999',
                        '@links': '#7799EE', '@linksBackground': 'rgba(65, 165, 235, 0.2)',
                        '@listsHeader': '#EE9900'}},
            {name: 'dawn', shownName: 'dawn',
                values: {'@background': '#BB7700', '@foreground': '#FFDDDD',
                        '@links': '#0022FF', '@linksBackground': 'rgba(87, 40, 0, 0.3)',
                        '@listsHeader': '#AA0000'}},
			{name: 'sunset', shownName: 'sunset',
                values: {'@background': '#660000', '@foreground': '#BB9977',
                        '@links': '#4488FF', '@linksBackground': 'rgba(87, 0, 0, 0.3)',
                        '@listsHeader': '#FFAA00'}},
			{name: 'nightly', shownName: 'nightly',
                values: {'@background': '#001544', '@foreground': '#99BBDD',
                        '@links': '#77AAFF', '@linksBackground': 'rgba(0, 0, 0, 0.3)',
                        '@listsHeader': '#FFAA15'}},
            {name: 'sepia', shownName: 'sepia',
                values: {'@background': '#CCCCAA', '@foreground': '#000000',
                        '@links': '#0000BB', '@linksBackground': 'rgba(0, 213, 255, 0.3)',
                        '@listsHeader': '#FF4E00'}},
            {name: 'light', shownName: 'light',
                values: {'@background': '#E8E8E8', '@foreground': '#000000',
                        '@links': '#0000BB', '@linksBackground': 'rgba(0, 213, 255, 0.3)',
                        '@listsHeader': '#DD4E00'}}],
		preview: {'this': 'background: @background; color: @foreground !important;',
			'label': 'color: @foreground !important;', 'a': 'color: @links;',
			'section header': 'color: @listsHeader; border-bottom-color: @listsHeader;',
			'input:not(.color),.camaLessForm input[type="radio"] ~ span':
				'color: @foreground; background-color: @background; filter: brightness(0.8); border-color: @foreground;'}});

    var form = [document.getElementById('themes')];
    var callbacks = [callbackThemesClose];
    setTimeout(function() {

	}, 500);
	// Open DB and create form
    openCamaLessDb('RAEfox_camaLESSdb', less, themesTypesNames, themes, form, callbacks);
});<|endoftext|>


<commit_before>if (window.DHT_LOADED){
  alert("Discord History Tracker is already loaded.");
  return;
}

window.DHT_LOADED = true;

if (DISCORD.getSelectedChannel()){
  if (confirm("You ran the script while in a channel, some messages may not be saved correctly. Do you want to go to your Friends list and refresh the page?")){
    window.location = "https://discordapp.com/channels/@me";
    return;
  }
}

// Execution

var cachedRequest;
var untrackedRequests = 0;

DISCORD.setupMessageRequestHook((channel, messages) => {
  if (STATE.isTracking()){
    var info = DISCORD.getSelectedChannel();

    if (info.id == channel){ // Discord has a bug where the message request may be sent without switching channels
      STATE.addDiscordChannel(info.server, info.type, channel, info.channel);
      var hasUpdatedFile = STATE.addDiscordMessages(channel, messages);

      if (STATE.settings.autoscroll){
        DOM.setTimer(() => {
          var action = CONSTANTS.AUTOSCROLL_ACTION_NOTHING;

          if (!hasUpdatedFile){
            action = STATE.settings.afterSavedMsg;
          }
          else if (!DISCORD.hasMoreMessages()){
            action = STATE.settings.afterFirstMsg;
          }

          if ((action === CONSTANTS.AUTOSCROLL_ACTION_SWITCH && !DISCORD.selectNextTextChannel()) || action === CONSTANTS.AUTOSCROLL_ACTION_PAUSE){
            STATE.toggleTracking();
          }
          else{
            DISCORD.loadOlderMessages();
          }
        }, 0);
      }
    }
  }
  else{
    ++untrackedRequests;

    cachedRequest = {
      channel: channel,
      messages: messages
    };
  }
});

STATE.onStateChanged((type, detail) => {
  if (type === "tracking" && detail){
    var info = DISCORD.getSelectedChannel();
    var isCachedRequestValid = cachedRequest && info && cachedRequest.channel == info.id;

    if (untrackedRequests > 1 || (untrackedRequests === 1 && !isCachedRequestValid)){
      if (!confirm("You have "+untrackedRequests+" untracked request"+(untrackedRequests === 1 ? "" : "s")+", some messages may not be saved until you refresh the page. Do you want to proceed anyway?")){
        STATE.toggleTracking();
        return;
      }
    }

    if (isCachedRequestValid){
      STATE.addDiscordChannel(info.server, info.type, cachedRequest.channel, info.channel);
      STATE.addDiscordMessages(cachedRequest.channel, cachedRequest.messages);
      cachedRequest = null;
      --untrackedRequests;
    }

    if (STATE.settings.autoscroll && DISCORD.isInMessageView()){
      if (DISCORD.hasMoreMessages()){
        DISCORD.loadOlderMessages();
      }
      else{
        var action = STATE.settings.afterFirstMsg;

        if ((action === CONSTANTS.AUTOSCROLL_ACTION_SWITCH && !DISCORD.selectNextTextChannel()) || action === CONSTANTS.AUTOSCROLL_ACTION_PAUSE){
          DOM.setTimer(() => STATE.toggleTracking(), 200); // give the user visual feedback after clicking the button before switching off
        }
      }
    }
  }
});

GUI.showController();
GUI.showSettings();
<commit_msg>Add a Discord website check to the tracker<commit_after>if (window.location.href.indexOf("discordapp.com/") === -1){
  if (!confirm("Could not detect Discord in the URL, do you want to run the script anyway?")){
    return;
  }
}

if (window.DHT_LOADED){
  alert("Discord History Tracker is already loaded.");
  return;
}

window.DHT_LOADED = true;

if (DISCORD.getSelectedChannel()){
  if (confirm("You ran the script while in a channel, some messages may not be saved correctly. Do you want to go to your Friends list and refresh the page?")){
    window.location = "https://discordapp.com/channels/@me";
    return;
  }
}

// Execution

var cachedRequest;
var untrackedRequests = 0;

DISCORD.setupMessageRequestHook((channel, messages) => {
  if (STATE.isTracking()){
    var info = DISCORD.getSelectedChannel();

    if (info.id == channel){ // Discord has a bug where the message request may be sent without switching channels
      STATE.addDiscordChannel(info.server, info.type, channel, info.channel);
      var hasUpdatedFile = STATE.addDiscordMessages(channel, messages);

      if (STATE.settings.autoscroll){
        DOM.setTimer(() => {
          var action = CONSTANTS.AUTOSCROLL_ACTION_NOTHING;

          if (!hasUpdatedFile){
            action = STATE.settings.afterSavedMsg;
          }
          else if (!DISCORD.hasMoreMessages()){
            action = STATE.settings.afterFirstMsg;
          }

          if ((action === CONSTANTS.AUTOSCROLL_ACTION_SWITCH && !DISCORD.selectNextTextChannel()) || action === CONSTANTS.AUTOSCROLL_ACTION_PAUSE){
            STATE.toggleTracking();
          }
          else{
            DISCORD.loadOlderMessages();
          }
        }, 0);
      }
    }
  }
  else{
    ++untrackedRequests;

    cachedRequest = {
      channel: channel,
      messages: messages
    };
  }
});

STATE.onStateChanged((type, detail) => {
  if (type === "tracking" && detail){
    var info = DISCORD.getSelectedChannel();
    var isCachedRequestValid = cachedRequest && info && cachedRequest.channel == info.id;

    if (untrackedRequests > 1 || (untrackedRequests === 1 && !isCachedRequestValid)){
      if (!confirm("You have "+untrackedRequests+" untracked request"+(untrackedRequests === 1 ? "" : "s")+", some messages may not be saved until you refresh the page. Do you want to proceed anyway?")){
        STATE.toggleTracking();
        return;
      }
    }

    if (isCachedRequestValid){
      STATE.addDiscordChannel(info.server, info.type, cachedRequest.channel, info.channel);
      STATE.addDiscordMessages(cachedRequest.channel, cachedRequest.messages);
      cachedRequest = null;
      --untrackedRequests;
    }

    if (STATE.settings.autoscroll && DISCORD.isInMessageView()){
      if (DISCORD.hasMoreMessages()){
        DISCORD.loadOlderMessages();
      }
      else{
        var action = STATE.settings.afterFirstMsg;

        if ((action === CONSTANTS.AUTOSCROLL_ACTION_SWITCH && !DISCORD.selectNextTextChannel()) || action === CONSTANTS.AUTOSCROLL_ACTION_PAUSE){
          DOM.setTimer(() => STATE.toggleTracking(), 200); // give the user visual feedback after clicking the button before switching off
        }
      }
    }
  }
});

GUI.showController();
GUI.showSettings();
<|endoftext|>


<commit_before>(function( jQuery ) {

var runtil = /Until$/,
	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
	// Note: This RegExp should be improved, or likely pulled from Sizzle
	rmultiselector = /,/,
	isSimple = /^.[^:#\[\.,]*$/,
	slice = Array.prototype.slice,
	POS = jQuery.expr.match.globalPOS,
	// methods guaranteed to produce a unique set when starting from a unique set
	guaranteedUnique = {
		children: true,
		contents: true,
		next: true,
		prev: true
	};

jQuery.fn.extend({
	find: function( selector ) {
		var self = this,
			i, l;

		if ( typeof selector !== "string" ) {
			return jQuery( selector ).filter(function() {
				for ( i = 0, l = self.length; i < l; i++ ) {
					if ( jQuery.contains( self[ i ], this ) ) {
						return true;
					}
				}
			});
		}

		var ret = this.pushStack( "", "find", selector ),
			length, n, r;

		for ( i = 0, l = this.length; i < l; i++ ) {
			length = ret.length;
			jQuery.find( selector, this[i], ret );

			if ( i > 0 ) {
				// Make sure that the results are unique
				for ( n = length; n < ret.length; n++ ) {
					for ( r = 0; r < length; r++ ) {
						if ( ret[r] === ret[n] ) {
							ret.splice(n--, 1);
							break;
						}
					}
				}
			}
		}

		return ret;
	},

	has: function( target ) {
		var targets = jQuery( target, this );
		return this.filter(function() {
			for ( var i = 0, l = targets.length; i < l; i++ ) {
				if ( jQuery.contains( this, targets[i] ) ) {
					return true;
				}
			}
		});
	},

	not: function( selector ) {
		return this.pushStack( winnow(this, selector, false), "not", selector);
	},

	filter: function( selector ) {
		return this.pushStack( winnow(this, selector, true), "filter", selector );
	},

	is: function( selector ) {
		return !!selector && (
			typeof selector === "string" ?
				// If this is a positional selector, check membership in the returned set
				// so $("p:first").is("p:last") won't return true for a doc with two "p".
				POS.test( selector ) ?
					jQuery( selector, this.context ).index( this[0] ) >= 0 :
					jQuery.filter( selector, this ).length > 0 :
				this.filter( selector ).length > 0 );
	},

	closest: function( selectors, context ) {
		var ret = [], i, l, cur = this[0];

		// Array (deprecated as of jQuery 1.7)
		if ( jQuery.isArray( selectors ) ) {
			var level = 1;

			while ( cur && cur.ownerDocument && cur !== context ) {
				for ( i = 0; i < selectors.length; i++ ) {

					if ( jQuery( cur ).is( selectors[ i ] ) ) {
						ret.push({ selector: selectors[ i ], elem: cur, level: level });
					}
				}

				cur = cur.parentNode;
				level++;
			}

			return ret;
		}

		// String
		var pos = POS.test( selectors ) || typeof selectors !== "string" ?
				jQuery( selectors, context || this.context ) :
				0;

		for ( i = 0, l = this.length; i < l; i++ ) {
			cur = this[i];

			while ( cur ) {
				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
					ret.push( cur );
					break;

				} else {
					cur = cur.parentNode;
					if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
						break;
					}
				}
			}
		}

		ret = ret.length > 1 ? jQuery.unique( ret ) : ret;

		return this.pushStack( ret, "closest", selectors );
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {

		// No argument, return index in parent
		if ( !elem ) {
			return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
		}

		// index in selector
		if ( typeof elem === "string" ) {
			return jQuery.inArray( this[0], jQuery( elem ) );
		}

		// Locate the position of the desired element
		return jQuery.inArray(
			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[0] : elem, this );
	},

	add: function( selector, context ) {
		var set = typeof selector === "string" ?
				jQuery( selector, context ) :
				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
			all = jQuery.merge( this.get(), set );

		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
			all :
			jQuery.unique( all ) );
	},

	andSelf: function() {
		return this.add( this.prevObject );
	}
});

// A painfully simple check to see if an element is disconnected
// from a document (should be improved, where feasible).
function isDisconnected( node ) {
	return !node || !node.parentNode || node.parentNode.nodeType === 11;
}

jQuery.each({
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	parents: function( elem ) {
		return jQuery.dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return jQuery.nth( elem, 2, "nextSibling" );
	},
	prev: function( elem ) {
		return jQuery.nth( elem, 2, "previousSibling" );
	},
	nextAll: function( elem ) {
		return jQuery.dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return jQuery.dir( elem, "previousSibling" );
	},
	nextUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "nextSibling", until );
	},
	prevUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
	},
	children: function( elem ) {
		return jQuery.sibling( elem.firstChild );
	},
	contents: function( elem ) {
		return jQuery.nodeName( elem, "iframe" ) ?
			elem.contentDocument || elem.contentWindow.document :
			jQuery.makeArray( elem.childNodes );
	}
}, function( name, fn ) {
	jQuery.fn[ name ] = function( until, selector ) {
		var ret = jQuery.map( this, fn, until );

		if ( !runtil.test( name ) ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			ret = jQuery.filter( selector, ret );
		}

		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;

		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
			ret = ret.reverse();
		}

		return this.pushStack( ret, name, slice.call( arguments ).join(",") );
	};
});

jQuery.extend({
	filter: function( expr, elems, not ) {
		if ( not ) {
			expr = ":not(" + expr + ")";
		}

		return elems.length === 1 ?
			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
			jQuery.find.matches(expr, elems);
	},

	dir: function( elem, dir, until ) {
		var matched = [],
			cur = elem[ dir ];

		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
			if ( cur.nodeType === 1 ) {
				matched.push( cur );
			}
			cur = cur[dir];
		}
		return matched;
	},

	nth: function( cur, result, dir, elem ) {
		result = result || 1;
		var num = 0;

		for ( ; cur; cur = cur[dir] ) {
			if ( cur.nodeType === 1 && ++num === result ) {
				break;
			}
		}

		return cur;
	},

	sibling: function( n, elem ) {
		var r = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				r.push( n );
			}
		}

		return r;
	}
});

// Implement the identical functionality for filter and not
function winnow( elements, qualifier, keep ) {

	// Can't pass null or undefined to indexOf in Firefox 4
	// Set to 0 to skip string check
	qualifier = qualifier || 0;

	if ( jQuery.isFunction( qualifier ) ) {
		return jQuery.grep(elements, function( elem, i ) {
			var retVal = !!qualifier.call( elem, i, elem );
			return retVal === keep;
		});

	} else if ( qualifier.nodeType ) {
		return jQuery.grep(elements, function( elem, i ) {
			return ( elem === qualifier ) === keep;
		});

	} else if ( typeof qualifier === "string" ) {
		var filtered = jQuery.grep(elements, function( elem ) {
			return elem.nodeType === 1;
		});

		if ( isSimple.test( qualifier ) ) {
			return jQuery.filter(qualifier, filtered, !keep);
		} else {
			qualifier = jQuery.filter( qualifier, filtered );
		}
	}

	return jQuery.grep(elements, function( elem, i ) {
		return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
	});
}

})( jQuery );
<commit_msg>Remove unnecessary arguments from .nth(). Fixes #11720<commit_after>(function( jQuery ) {

var runtil = /Until$/,
	rparentsprev = /^(?:parents|prevUntil|prevAll)/,
	// Note: This RegExp should be improved, or likely pulled from Sizzle
	rmultiselector = /,/,
	isSimple = /^.[^:#\[\.,]*$/,
	slice = Array.prototype.slice,
	POS = jQuery.expr.match.globalPOS,
	// methods guaranteed to produce a unique set when starting from a unique set
	guaranteedUnique = {
		children: true,
		contents: true,
		next: true,
		prev: true
	};

jQuery.fn.extend({
	find: function( selector ) {
		var self = this,
			i, l;

		if ( typeof selector !== "string" ) {
			return jQuery( selector ).filter(function() {
				for ( i = 0, l = self.length; i < l; i++ ) {
					if ( jQuery.contains( self[ i ], this ) ) {
						return true;
					}
				}
			});
		}

		var ret = this.pushStack( "", "find", selector ),
			length, n, r;

		for ( i = 0, l = this.length; i < l; i++ ) {
			length = ret.length;
			jQuery.find( selector, this[i], ret );

			if ( i > 0 ) {
				// Make sure that the results are unique
				for ( n = length; n < ret.length; n++ ) {
					for ( r = 0; r < length; r++ ) {
						if ( ret[r] === ret[n] ) {
							ret.splice(n--, 1);
							break;
						}
					}
				}
			}
		}

		return ret;
	},

	has: function( target ) {
		var targets = jQuery( target, this );
		return this.filter(function() {
			for ( var i = 0, l = targets.length; i < l; i++ ) {
				if ( jQuery.contains( this, targets[i] ) ) {
					return true;
				}
			}
		});
	},

	not: function( selector ) {
		return this.pushStack( winnow(this, selector, false), "not", selector);
	},

	filter: function( selector ) {
		return this.pushStack( winnow(this, selector, true), "filter", selector );
	},

	is: function( selector ) {
		return !!selector && (
			typeof selector === "string" ?
				// If this is a positional selector, check membership in the returned set
				// so $("p:first").is("p:last") won't return true for a doc with two "p".
				POS.test( selector ) ?
					jQuery( selector, this.context ).index( this[0] ) >= 0 :
					jQuery.filter( selector, this ).length > 0 :
				this.filter( selector ).length > 0 );
	},

	closest: function( selectors, context ) {
		var ret = [], i, l, cur = this[0];

		// Array (deprecated as of jQuery 1.7)
		if ( jQuery.isArray( selectors ) ) {
			var level = 1;

			while ( cur && cur.ownerDocument && cur !== context ) {
				for ( i = 0; i < selectors.length; i++ ) {

					if ( jQuery( cur ).is( selectors[ i ] ) ) {
						ret.push({ selector: selectors[ i ], elem: cur, level: level });
					}
				}

				cur = cur.parentNode;
				level++;
			}

			return ret;
		}

		// String
		var pos = POS.test( selectors ) || typeof selectors !== "string" ?
				jQuery( selectors, context || this.context ) :
				0;

		for ( i = 0, l = this.length; i < l; i++ ) {
			cur = this[i];

			while ( cur ) {
				if ( pos ? pos.index(cur) > -1 : jQuery.find.matchesSelector(cur, selectors) ) {
					ret.push( cur );
					break;

				} else {
					cur = cur.parentNode;
					if ( !cur || !cur.ownerDocument || cur === context || cur.nodeType === 11 ) {
						break;
					}
				}
			}
		}

		ret = ret.length > 1 ? jQuery.unique( ret ) : ret;

		return this.pushStack( ret, "closest", selectors );
	},

	// Determine the position of an element within
	// the matched set of elements
	index: function( elem ) {

		// No argument, return index in parent
		if ( !elem ) {
			return ( this[0] && this[0].parentNode ) ? this.prevAll().length : -1;
		}

		// index in selector
		if ( typeof elem === "string" ) {
			return jQuery.inArray( this[0], jQuery( elem ) );
		}

		// Locate the position of the desired element
		return jQuery.inArray(
			// If it receives a jQuery object, the first element is used
			elem.jquery ? elem[0] : elem, this );
	},

	add: function( selector, context ) {
		var set = typeof selector === "string" ?
				jQuery( selector, context ) :
				jQuery.makeArray( selector && selector.nodeType ? [ selector ] : selector ),
			all = jQuery.merge( this.get(), set );

		return this.pushStack( isDisconnected( set[0] ) || isDisconnected( all[0] ) ?
			all :
			jQuery.unique( all ) );
	},

	andSelf: function() {
		return this.add( this.prevObject );
	}
});

// A painfully simple check to see if an element is disconnected
// from a document (should be improved, where feasible).
function isDisconnected( node ) {
	return !node || !node.parentNode || node.parentNode.nodeType === 11;
}

jQuery.each({
	parent: function( elem ) {
		var parent = elem.parentNode;
		return parent && parent.nodeType !== 11 ? parent : null;
	},
	parents: function( elem ) {
		return jQuery.dir( elem, "parentNode" );
	},
	parentsUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "parentNode", until );
	},
	next: function( elem ) {
		return jQuery.nth( elem, "nextSibling" );
	},
	prev: function( elem ) {
		return jQuery.nth( elem, "previousSibling" );
	},
	nextAll: function( elem ) {
		return jQuery.dir( elem, "nextSibling" );
	},
	prevAll: function( elem ) {
		return jQuery.dir( elem, "previousSibling" );
	},
	nextUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "nextSibling", until );
	},
	prevUntil: function( elem, i, until ) {
		return jQuery.dir( elem, "previousSibling", until );
	},
	siblings: function( elem ) {
		return jQuery.sibling( ( elem.parentNode || {} ).firstChild, elem );
	},
	children: function( elem ) {
		return jQuery.sibling( elem.firstChild );
	},
	contents: function( elem ) {
		return jQuery.nodeName( elem, "iframe" ) ?
			elem.contentDocument || elem.contentWindow.document :
			jQuery.makeArray( elem.childNodes );
	}
}, function( name, fn ) {
	jQuery.fn[ name ] = function( until, selector ) {
		var ret = jQuery.map( this, fn, until );

		if ( !runtil.test( name ) ) {
			selector = until;
		}

		if ( selector && typeof selector === "string" ) {
			ret = jQuery.filter( selector, ret );
		}

		ret = this.length > 1 && !guaranteedUnique[ name ] ? jQuery.unique( ret ) : ret;

		if ( (this.length > 1 || rmultiselector.test( selector )) && rparentsprev.test( name ) ) {
			ret = ret.reverse();
		}

		return this.pushStack( ret, name, slice.call( arguments ).join(",") );
	};
});

jQuery.extend({
	filter: function( expr, elems, not ) {
		if ( not ) {
			expr = ":not(" + expr + ")";
		}

		return elems.length === 1 ?
			jQuery.find.matchesSelector(elems[0], expr) ? [ elems[0] ] : [] :
			jQuery.find.matches(expr, elems);
	},

	dir: function( elem, dir, until ) {
		var matched = [],
			cur = elem[ dir ];

		while ( cur && cur.nodeType !== 9 && (until === undefined || cur.nodeType !== 1 || !jQuery( cur ).is( until )) ) {
			if ( cur.nodeType === 1 ) {
				matched.push( cur );
			}
			cur = cur[dir];
		}
		return matched;
	},

	nth: function( cur, dir ) {
		var num = 0;

		for ( ; cur; cur = cur[dir] ) {
			if ( cur.nodeType === 1 && num++ === 1 ) {
				break;
			}
		}

		return cur;
	},

	sibling: function( n, elem ) {
		var r = [];

		for ( ; n; n = n.nextSibling ) {
			if ( n.nodeType === 1 && n !== elem ) {
				r.push( n );
			}
		}

		return r;
	}
});

// Implement the identical functionality for filter and not
function winnow( elements, qualifier, keep ) {

	// Can't pass null or undefined to indexOf in Firefox 4
	// Set to 0 to skip string check
	qualifier = qualifier || 0;

	if ( jQuery.isFunction( qualifier ) ) {
		return jQuery.grep(elements, function( elem, i ) {
			var retVal = !!qualifier.call( elem, i, elem );
			return retVal === keep;
		});

	} else if ( qualifier.nodeType ) {
		return jQuery.grep(elements, function( elem, i ) {
			return ( elem === qualifier ) === keep;
		});

	} else if ( typeof qualifier === "string" ) {
		var filtered = jQuery.grep(elements, function( elem ) {
			return elem.nodeType === 1;
		});

		if ( isSimple.test( qualifier ) ) {
			return jQuery.filter(qualifier, filtered, !keep);
		} else {
			qualifier = jQuery.filter( qualifier, filtered );
		}
	}

	return jQuery.grep(elements, function( elem, i ) {
		return ( jQuery.inArray( elem, qualifier ) >= 0 ) === keep;
	});
}

})( jQuery );
<|endoftext|>


<commit_before>import {combineReducers} from 'redux';
import routingReducer from './routingReducer';
import teamsReducer from './teamsReducers';

const reducers = combineReducers({
    routingReducer,
    teamsReducer
});

export default reducers;<commit_msg>Added new reducers to store<commit_after>import {combineReducers} from 'redux';
import routingReducer from './routingReducer';
import teamsReducer from './teamsReducers';
import questionReducer from './questionReducer';

const reducers = combineReducers({
    routingReducer,
    teamsReducer,
    questionReducer
});

export default reducers;<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations under
// the License.

couchTests.update_documents = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  var designDoc = {
    _id:"_design/update",
    language: "javascript",
    updates: {
      "hello" : stringFun(function(doc, req) {
        log(doc);
        log(req);
        if (!doc) {
          if (req.id) {
            return [
            // Creates a new document with the PUT docid,
            { _id : req.id,
              reqs : [req] },
            // and returns an HTML response to the client.
            "
New World
"];
          };
          //
          return [null, "
Empty World
"];
        };
        // we can update the document inline
        doc.world = "hello";
        // we can record aspects of the request or use them in application logic.
        doc.reqs && doc.reqs.push(req);
        doc.edited_by = req.userCtx;
        return [doc, "
hello doc
"];
      }),
      "in-place" : stringFun(function(doc, req) {
        var field = req.query.field;
        var value = req.query.value;
        var message = "set "+field+" to "+value;
        doc[field] = value;
        return [doc, message];
      }),
      "bump-counter" : stringFun(function(doc, req) {
        if (!doc.counter) doc.counter = 0;
        doc.counter += 1;
        var message = "
bumped it!
";
        return [doc, message];
      }),
      "error" : stringFun(function(doc, req) {
        superFail.badCrash;
      }),
      "xml" : stringFun(function(doc, req) {
        var xml = new XML('<xml></xml>');
        xml.title = doc.title;
        var posted_xml = new XML(req.body);
        doc.via_xml = posted_xml.foo.toString();
        var resp =  {
          "headers" : {
            "Content-Type" : "application/xml"
          },
          "body" : xml.toXMLString()
        };

         return [doc, resp];
       }),
       "get-uuid" : stringFun(function(doc, req) {
         return [null, req.uuid];
       }),
       "code-n-bump" : stringFun(function(doc,req) {
         if (!doc.counter) doc.counter = 0;
         doc.counter += 1;
         var message = "
bumped it!
";
         resp = {"code": 302, "body": message}
         return [doc, resp];
       }),
       "resp-code" : stringFun(function(doc,req) {
         resp = {"code": 302}
         return [null, resp];
       }),
       "binary" : stringFun(function(doc, req) {
         var resp = {
           "headers" : {
             "Content-Type" : "application/octet-stream"
           },
           "base64" : "aGVsbG8gd29ybGQh" // "hello world!" encoded
         };
         return [doc, resp];
       }),
      "empty" : stringFun(function(doc, req) {
        return [{}, 'oops'];
      })
    }
  };
  T(db.save(designDoc).ok);

  var doc = {"word":"plankton", "name":"Rusty"}
  var resp = db.save(doc);
  T(resp.ok);
  var docid = resp.id;
  T(equals(docid, db.last_req.getResponseHeader("X-Couch-Id")));

  // update error
  var xhr = CouchDB.request("POST", "/test_suite_db/_design/update/_update/");
  T(xhr.status == 404, 'Should be missing');
  T(JSON.parse(xhr.responseText).reason == "Invalid path.");

  // hello update world
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/hello/"+docid);
  T(xhr.status == 201);
  T(xhr.responseText == "
hello doc
");
  T(/charset=utf-8/.test(xhr.getResponseHeader("Content-Type")));
  T(equals(docid, xhr.getResponseHeader("X-Couch-Id")));

  doc = db.open(docid);
  T(doc.world == "hello");

  // Fix for COUCHDB-379
  T(equals(xhr.getResponseHeader("Server").substr(0,7), "CouchDB"));

  // hello update world (no docid)
  xhr = CouchDB.request("POST", "/test_suite_db/_design/update/_update/hello");
  T(xhr.status == 200);
  T(xhr.responseText == "
Empty World
");

  // no GET allowed
  xhr = CouchDB.request("GET", "/test_suite_db/_design/update/_update/hello");
  // T(xhr.status == 405); // TODO allow qs to throw error code as well as error message
  T(JSON.parse(xhr.responseText).error == "method_not_allowed");

  // // hello update world (non-existing docid)
  xhr = CouchDB.request("GET", "/test_suite_db/nonExistingDoc");
  T(xhr.status == 404);
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/hello/nonExistingDoc");
  T(xhr.status == 201);
  T(xhr.responseText == "
New World
");
  xhr = CouchDB.request("GET", "/test_suite_db/nonExistingDoc");
  T(xhr.status == 200);

  // in place update
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/in-place/"+docid+'?field=title&value=test');
  T(xhr.status == 201);
  T(xhr.responseText == "set title to test");
  doc = db.open(docid);
  T(doc.title == "test");

  // bump counter
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/bump-counter/"+docid, {
    headers : {"X-Couch-Full-Commit":"true"}
  });
  T(xhr.status == 201);
  T(xhr.responseText == "
bumped it!
");
  doc = db.open(docid);
  T(doc.counter == 1);

  // _update honors full commit if you need it to
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/bump-counter/"+docid, {
    headers : {"X-Couch-Full-Commit":"true"}
  });

  var NewRev = xhr.getResponseHeader("X-Couch-Update-NewRev");
  doc = db.open(docid);
  T(doc['_rev'] == NewRev);

  T(doc.counter == 2);

  // parse xml
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/xml/"+docid, {
    headers : {"X-Couch-Full-Commit":"true"},
    "body" : '<xml><foo>bar</foo></xml>'
  });
  T(xhr.status == 201);
  T(xhr.responseText == "<xml>\n  <title>test</title>\n</xml>");

  doc = db.open(docid);
  T(doc.via_xml == "bar");

  // Server provides UUID when POSTing without an ID in the URL
  xhr = CouchDB.request("POST", "/test_suite_db/_design/update/_update/get-uuid/");
  T(xhr.status == 200);
  T(xhr.responseText.length == 32);

  // COUCHDB-1229 - allow slashes in doc ids for update handlers
  // /db/_design/doc/_update/handler/doc/id

  var doc = {
      _id:"with/slash",
      counter:1
  };
  db.save(doc);
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/bump-counter/with/slash");
  TEquals(201, xhr.status, "should return a 200 status");
  TEquals("
bumped it!
", xhr.responseText, "should report bumping");

  var doc = db.open("with/slash");
  TEquals(2, doc.counter, "counter should be 2");

  // COUCHDB-648 - the code in the JSON response should be honored

  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/code-n-bump/"+docid, {
    headers : {"X-Couch-Full-Commit":"true"}
  });
  T(xhr.status == 302);
  T(xhr.responseText == "
bumped it!
");
  doc = db.open(docid);
  T(doc.counter == 3);

  xhr = CouchDB.request("POST", "/test_suite_db/_design/update/_update/resp-code/");
  T(xhr.status == 302);

  // base64 response
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/binary/"+docid, {
    headers : {"X-Couch-Full-Commit":"false"},
    body    : 'rubbish'
  });
  T(xhr.status == 201);
  T(xhr.responseText == "hello world!");
  T(/application\/octet-stream/.test(xhr.getResponseHeader("Content-Type")));

  // Insert doc with empty id
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/empty/foo");
  TEquals(400, xhr.status);
  TEquals("Document id must not be empty", JSON.parse(xhr.responseText).reason);

};
<commit_msg>Revert "Document Id and Rev in response headers" patch<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License.  You may obtain a copy
// of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
// License for the specific language governing permissions and limitations under
// the License.

couchTests.update_documents = function(debug) {
  var db = new CouchDB("test_suite_db", {"X-Couch-Full-Commit":"false"});
  db.deleteDb();
  db.createDb();
  if (debug) debugger;

  var designDoc = {
    _id:"_design/update",
    language: "javascript",
    updates: {
      "hello" : stringFun(function(doc, req) {
        log(doc);
        log(req);
        if (!doc) {
          if (req.id) {
            return [
            // Creates a new document with the PUT docid,
            { _id : req.id,
              reqs : [req] },
            // and returns an HTML response to the client.
            "
New World
"];
          };
          //
          return [null, "
Empty World
"];
        };
        // we can update the document inline
        doc.world = "hello";
        // we can record aspects of the request or use them in application logic.
        doc.reqs && doc.reqs.push(req);
        doc.edited_by = req.userCtx;
        return [doc, "
hello doc
"];
      }),
      "in-place" : stringFun(function(doc, req) {
        var field = req.query.field;
        var value = req.query.value;
        var message = "set "+field+" to "+value;
        doc[field] = value;
        return [doc, message];
      }),
      "bump-counter" : stringFun(function(doc, req) {
        if (!doc.counter) doc.counter = 0;
        doc.counter += 1;
        var message = "
bumped it!
";
        return [doc, message];
      }),
      "error" : stringFun(function(doc, req) {
        superFail.badCrash;
      }),
      "xml" : stringFun(function(doc, req) {
        var xml = new XML('<xml></xml>');
        xml.title = doc.title;
        var posted_xml = new XML(req.body);
        doc.via_xml = posted_xml.foo.toString();
        var resp =  {
          "headers" : {
            "Content-Type" : "application/xml"
          },
          "body" : xml.toXMLString()
        };

         return [doc, resp];
       }),
       "get-uuid" : stringFun(function(doc, req) {
         return [null, req.uuid];
       }),
       "code-n-bump" : stringFun(function(doc,req) {
         if (!doc.counter) doc.counter = 0;
         doc.counter += 1;
         var message = "
bumped it!
";
         resp = {"code": 302, "body": message}
         return [doc, resp];
       }),
       "resp-code" : stringFun(function(doc,req) {
         resp = {"code": 302}
         return [null, resp];
       }),
       "binary" : stringFun(function(doc, req) {
         var resp = {
           "headers" : {
             "Content-Type" : "application/octet-stream"
           },
           "base64" : "aGVsbG8gd29ybGQh" // "hello world!" encoded
         };
         return [doc, resp];
       }),
      "empty" : stringFun(function(doc, req) {
        return [{}, 'oops'];
      })
    }
  };
  T(db.save(designDoc).ok);

  var doc = {"word":"plankton", "name":"Rusty"}
  var resp = db.save(doc);
  T(resp.ok);
  var docid = resp.id;

  // update error
  var xhr = CouchDB.request("POST", "/test_suite_db/_design/update/_update/");
  T(xhr.status == 404, 'Should be missing');
  T(JSON.parse(xhr.responseText).reason == "Invalid path.");

  // hello update world
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/hello/"+docid);
  T(xhr.status == 201);
  T(xhr.responseText == "
hello doc
");
  T(/charset=utf-8/.test(xhr.getResponseHeader("Content-Type")))

  doc = db.open(docid);
  T(doc.world == "hello");

  // Fix for COUCHDB-379
  T(equals(xhr.getResponseHeader("Server").substr(0,7), "CouchDB"));

  // hello update world (no docid)
  xhr = CouchDB.request("POST", "/test_suite_db/_design/update/_update/hello");
  T(xhr.status == 200);
  T(xhr.responseText == "
Empty World
");

  // no GET allowed
  xhr = CouchDB.request("GET", "/test_suite_db/_design/update/_update/hello");
  // T(xhr.status == 405); // TODO allow qs to throw error code as well as error message
  T(JSON.parse(xhr.responseText).error == "method_not_allowed");

  // // hello update world (non-existing docid)
  xhr = CouchDB.request("GET", "/test_suite_db/nonExistingDoc");
  T(xhr.status == 404);
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/hello/nonExistingDoc");
  T(xhr.status == 201);
  T(xhr.responseText == "
New World
");
  xhr = CouchDB.request("GET", "/test_suite_db/nonExistingDoc");
  T(xhr.status == 200);

  // in place update
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/in-place/"+docid+'?field=title&value=test');
  T(xhr.status == 201);
  T(xhr.responseText == "set title to test");
  doc = db.open(docid);
  T(doc.title == "test");

  // bump counter
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/bump-counter/"+docid, {
    headers : {"X-Couch-Full-Commit":"true"}
  });
  T(xhr.status == 201);
  T(xhr.responseText == "
bumped it!
");
  doc = db.open(docid);
  T(doc.counter == 1);

  // _update honors full commit if you need it to
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/bump-counter/"+docid, {
    headers : {"X-Couch-Full-Commit":"true"}
  });

  var NewRev = xhr.getResponseHeader("X-Couch-Update-NewRev");
  doc = db.open(docid);
  T(doc['_rev'] == NewRev);

  T(doc.counter == 2);

  // parse xml
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/xml/"+docid, {
    headers : {"X-Couch-Full-Commit":"true"},
    "body" : '<xml><foo>bar</foo></xml>'
  });
  T(xhr.status == 201);
  T(xhr.responseText == "<xml>\n  <title>test</title>\n</xml>");

  doc = db.open(docid);
  T(doc.via_xml == "bar");

  // Server provides UUID when POSTing without an ID in the URL
  xhr = CouchDB.request("POST", "/test_suite_db/_design/update/_update/get-uuid/");
  T(xhr.status == 200);
  T(xhr.responseText.length == 32);

  // COUCHDB-1229 - allow slashes in doc ids for update handlers
  // /db/_design/doc/_update/handler/doc/id

  var doc = {
      _id:"with/slash",
      counter:1
  };
  db.save(doc);
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/bump-counter/with/slash");
  TEquals(201, xhr.status, "should return a 200 status");
  TEquals("
bumped it!
", xhr.responseText, "should report bumping");

  var doc = db.open("with/slash");
  TEquals(2, doc.counter, "counter should be 2");

  // COUCHDB-648 - the code in the JSON response should be honored

  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/code-n-bump/"+docid, {
    headers : {"X-Couch-Full-Commit":"true"}
  });
  T(xhr.status == 302);
  T(xhr.responseText == "
bumped it!
");
  doc = db.open(docid);
  T(doc.counter == 3);

  xhr = CouchDB.request("POST", "/test_suite_db/_design/update/_update/resp-code/");
  T(xhr.status == 302);

  // base64 response
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/binary/"+docid, {
    headers : {"X-Couch-Full-Commit":"false"},
    body    : 'rubbish'
  });
  T(xhr.status == 201);
  T(xhr.responseText == "hello world!");
  T(/application\/octet-stream/.test(xhr.getResponseHeader("Content-Type")));

  // Insert doc with empty id
  xhr = CouchDB.request("PUT", "/test_suite_db/_design/update/_update/empty/foo");
  TEquals(400, xhr.status);
  TEquals("Document id must not be empty", JSON.parse(xhr.responseText).reason);

};
<|endoftext|>


<commit_before>/* eslint no-console:0 max-len:0 */
import fs from 'fs';
import path from 'path';

import mversion from 'mversion';

import semver from 'semver';
import currentVersion from '../src/version.js';

if (!process.env.VERSION) {
  throw new Error('bump: Usage is VERSION=MAJOR.MINOR.PATCH scripts/bump-package-version.js');
}
let newVersion = process.env.VERSION;

if (!semver.valid(newVersion)) {
  throw new Error('bump: Provided new version (' + newVersion + ') is not a valid version per semver');
}

if (semver.gte(currentVersion, newVersion)) {
  throw new Error('bump: Provided new version is not higher than current version (' + newVersion + ' <= ' + currentVersion + ')');
}

console.log('Bumping ' + newVersion);

console.log('..Updating src/version.js');

let versionFile = path.join(__dirname, '../src/version.js');
let newContent = "export default '" + newVersion + "';\n";
fs.writeFileSync(versionFile, newContent);

console.log('..Updating package.json, npm-shrinwrap.json');

mversion.update(newVersion);
<commit_msg>chore(release): remove mention to shrinkwrap<commit_after>/* eslint no-console:0 max-len:0 */
import fs from 'fs';
import path from 'path';

import mversion from 'mversion';

import semver from 'semver';
import currentVersion from '../src/version.js';

if (!process.env.VERSION) {
  throw new Error('bump: Usage is VERSION=MAJOR.MINOR.PATCH scripts/bump-package-version.js');
}
let newVersion = process.env.VERSION;

if (!semver.valid(newVersion)) {
  throw new Error('bump: Provided new version (' + newVersion + ') is not a valid version per semver');
}

if (semver.gte(currentVersion, newVersion)) {
  throw new Error('bump: Provided new version is not higher than current version (' + newVersion + ' <= ' + currentVersion + ')');
}

console.log('Bumping ' + newVersion);

console.log('..Updating src/version.js');

let versionFile = path.join(__dirname, '../src/version.js');
let newContent = "export default '" + newVersion + "';\n";
fs.writeFileSync(versionFile, newContent);

console.log('..Updating package.json');

mversion.update(newVersion);
<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name touristifyApp.controller:ShowDataCtrl
 * @description
 * # ShowDataCtrl
 * Controller of the touristifyApp
 */
 angular.module('touristifyApp')
 .controller('ShowDataCtrl', function ($scope, $http) {

   $scope.people = null;
   $http.get('data/people.json').success(function(data){
    $scope.people = data;
    var length = $scope.people;
    var total =0;
    var avarage ;

    for (var i = 0; i < data.length; i++) {
      total += data[i].age;
      avarage = total/(i+1);
    }

    $scope.avarage= Math.round(avarage);

  });

 });
<commit_msg>wawawiwa<commit_after>'use strict';

/**
 * @ngdoc function
 * @name touristifyApp.controller:ShowDataCtrl
 * @description
 * # ShowDataCtrl
 * Controller of the touristifyApp
 */
 angular.module('touristifyApp')
 .controller('ShowDataCtrl', function ($scope, $http) {

   $scope.people = null;
   $http.get('data/people.json').success(function(data){
    $scope.people = data;
    var length = $scope.people;
    var total =0;
    var avarage ;
    var counter=0;
   $scope.lowLimit = 50;

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

      total += data[i].age;
      avarage = total/(i+1);

      if( data[i].age >=  $scope.lowLimit ){
        counter ++;
      }
      console.log(counter);
    }

    $scope.avarage= Math.round(avarage);

  });

 });
<|endoftext|>


<commit_before>//Modified from: https://github.com/mikeal/githubarchive

var util = require('util')
  , stream = require('stream')
  , path = require('path')
  , fs = require('fs')
  , zlib = require('zlib')
  , jsonstream = require('JSONStream')
  , timezone = require('timezone')
  , request = require('request').defaults({pool:{maxSockets:1}})
  ;

//http://nickfishman.com/post/49533681471/nodejs-http-requests-with-gzip-deflate-compression
var headers = {
  "accept-encoding" : "gzip,deflate",
}

var options = {
  headers: headers
}

function CallbackStream (cb) {
  this.readable = true
  this.writable = true
  this.cb = cb
}
util.inherits(CallbackStream, stream.Stream)
CallbackStream.prototype.write = function (chunk) {
  this.emit('data', chunk)
}
CallbackStream.prototype.end = function () {
  this.emit('close')
  this.cb()
}
CallbackStream.prototype.destory = function () {}

module.exports = function (arg) {
  if (arg.slice(0, 'http://'.length) === 'http://' || arg.slice(0, 'http://'.length) === 'http://') {
    return module.exports.request(arg)
  }
  return module.exports.readFile(arg)
}

module.exports.languages = function (cb) {
  var languages = {}
  var s = new CallbackStream(function () {
    cb(null, languages)
  })
  s.languages = languages
  s.on('data', function (d) {
    if (!d.repository) return
    if (!languages[d.repository.language]) languages[d.repository.language] = 0
    languages[d.repository.language] += 1
  })
  s.on('error', cb)
  return wrap(s)
}

module.exports.users = function (cb) {
  var users = {}
  var s = new CallbackStream(function () {
    cb(null, users)
  })
  s.users = users
  s.on('data', function (d) {
    if (!s.users[d.actor]) s.users[d.actor] = {}
  })
  s.on('error', cb)
  return wrap(s)
}

module.exports.MyParser = function (cb) {
  var commits = {}
  var s = new CallbackStream(function () {
    cb(null, commits)
  })
  s.commits = {}
  var actorname="";
  s.on("data", function (d) {
    if (d.type === "PushEvent") {
    	d.payload.shas.forEach(function (sha) {
	    //console.log("Processing ===> " + sha[0] + " " + d.actor_attributes.name + " URL ===> " + d.repository.url);
            var info = {};
            //Handle empty name attribute
            if (d.actor_attributes.name != null && d.actor_attributes.name != 'undefined'){
            	actorname = d.actor_attributes.name;
            }
            else {
            	actorname =  d.actor_attributes.login;
                //console.log ("### Caught no name " + d.actor_attributes.login);
            }
    		info = {
   				created_at: d.created_at,
                    full_name: d.repository.full_name,
    				name: d.repository.name,
    				url: d.repository.url,
    				language: d.repository.language,
    				description: d.repository.description,
                    watchers: d.repository.watchers_count,
                    stargazers: d.repository.stargazers_count,
                    forks: d.repository.forks_count,
                    issues: d.repository.open_issues_count,
                    owner: d.repository.owner,
                    organization: d.repository.organization,
                    //actor: sha[3],
                    actorlogin: d.actor_attributes.login,
                    actorname:  actorname,
                    ref: d.payload.ref,
                    master_branch: d.repository.master_branch,
                    comment: sha[2]
    				};
    		//Check formatted JSON
    		//http://jsonformatter.curiousconcept.com
    		//http://codebeautify.org/view/jsonviewer
    		s.commits[sha[0]] = info;
    	}) //end foreach sha
    }  //end 'PushEvent'
  }) //end s.on('data')
  s.on('error', cb)
  return wrap(s)
}

function wrap (obj) {
  Object.keys(module.exports).forEach(function (i) {
    obj[i] = function () { return obj.pipe(module.exports[i].apply(module.exports, arguments)) }
  })
  obj.once('write', function () {
    Object.keys(module.exports).forEach(function (i) {
      obj[i] = function () { throw new Error('Cannot ask for new parsing after the first write.') }
    })
  })
  obj.on('end', function () {
    Object.keys(module.exports).forEach(function (i) {
      obj[i] = function () { throw new Error('Cannot ask for new parsing after the stream has ended.') }
    })
  })
  return obj
}

module.exports.request = function (url) {
  return wrap(request(url).pipe(zlib.createGunzip()).pipe(jsonstream.parse()))
}

module.exports.readFile = function (path, options) {
  var f = fs.createReadStream(path)
    , z = new zlib.createGunzip()
    , j = jsonstream.parse()

  if (options.gzip !== false) {
    f.pipe(z)
    z.pipe(j)
  } else {
    f.pipe(j)
  }

  return wrap(j)
}

module.exports.range = function (start, end) {
  // I get Access Denied for any range I try to use in the HTTP interface
  // this is why we do a GET per hour and pipe them all together.
  // This also solves some timeout and throttling issues.
  var timestamps = []
  if (end < start) throw new Error('end is before start')
  console.log(start, end)
  var s = new Date(start)
  while (end > s) {
    timestamps.push(timezone(s, '%Y-%m-%d-%k').replace(/\ /g, ''))
    s.setHours(s.getHours()+1)
  }

  var output = new CallbackStream(function () {}) // noop for end

  timestamps.forEach(function (ts) {
    var r = request('http://data.githubarchive.org/'+ts+'.json.gz')
    r.on('response', function (resp) {
      output.emit('timerange', ts)
      if (resp.statusCode !== 200) {
        console.error('not 200', 'http://data.githubarchive.org/'+ts+'.json.gz')
        return
      }

      var z = new zlib.createGunzip()
        , j = jsonstream.parse()
        ;
      j.on('data', function (obj) {
        var created = new Date(obj.created_at)
        if (created < start) return
        if (created > end) return
        output.emit('data', obj)
      })
      resp.pipe(z)
      z.pipe(j)

      if (timestamps.indexOf(ts) === timestamps.length - 1) j.on('end', output.end.bind(output))
    })
  })

  return wrap(output)
}

<commit_msg>Modify logic to handle requests based on Nick Fishman post<commit_after>//Modified from: https://github.com/mikeal/githubarchive

var util = require('util')
  , stream = require('stream')
  , path = require('path')
  , fs = require('fs')
  , zlib = require('zlib')
  , jsonstream = require('JSONStream')
  , timezone = require('timezone')
  , request = require('request').defaults({pool:{maxSockets:1}})
  ;

//http://nickfishman.com/post/49533681471/nodejs-http-requests-with-gzip-deflate-compression
var headers = {
  "accept-encoding" : "gzip,deflate",
}

var options = {
  headers: headers
}

function CallbackStream (cb) {
  this.readable = true
  this.writable = true
  this.cb = cb
}
util.inherits(CallbackStream, stream.Stream)
CallbackStream.prototype.write = function (chunk) {
  this.emit('data', chunk)
}
CallbackStream.prototype.end = function () {
  this.emit('close')
  this.cb()
}
CallbackStream.prototype.destory = function () {}

module.exports = function (arg) {
  if (arg.slice(0, 'http://'.length) === 'http://' || arg.slice(0, 'http://'.length) === 'http://') {
    return module.exports.request(arg)
  }
  return module.exports.readFile(arg)
}

module.exports.languages = function (cb) {
  var languages = {}
  var s = new CallbackStream(function () {
    cb(null, languages)
  })
  s.languages = languages
  s.on('data', function (d) {
    if (!d.repository) return
    if (!languages[d.repository.language]) languages[d.repository.language] = 0
    languages[d.repository.language] += 1
  })
  s.on('error', cb)
  return wrap(s)
}

module.exports.users = function (cb) {
  var users = {}
  var s = new CallbackStream(function () {
    cb(null, users)
  })
  s.users = users
  s.on('data', function (d) {
    if (!s.users[d.actor]) s.users[d.actor] = {}
  })
  s.on('error', cb)
  return wrap(s)
}

module.exports.MyParser = function (cb) {
  var commits = {}
  var s = new CallbackStream(function () {
    cb(null, commits)
  })
  s.commits = {}
  var actorname="";
  s.on("data", function (d) {
    if (d.type === "PushEvent") {
    	d.payload.shas.forEach(function (sha) {
	    //console.log("Processing ===> " + sha[0] + " " + d.actor_attributes.name + " URL ===> " + d.repository.url);
            var info = {};
            //Handle empty name attribute
            if (d.actor_attributes.name != null && d.actor_attributes.name != 'undefined'){
            	actorname = d.actor_attributes.name;
            }
            else {
            	actorname =  d.actor_attributes.login;
                //console.log ("### Caught no name " + d.actor_attributes.login);
            }
    		info = {
   				created_at: d.created_at,
                    full_name: d.repository.full_name,
    				name: d.repository.name,
    				url: d.repository.url,
    				language: d.repository.language,
    				description: d.repository.description,
                    watchers: d.repository.watchers_count,
                    stargazers: d.repository.stargazers_count,
                    forks: d.repository.forks_count,
                    issues: d.repository.open_issues_count,
                    owner: d.repository.owner,
                    organization: d.repository.organization,
                    //actor: sha[3],
                    actorlogin: d.actor_attributes.login,
                    actorname:  actorname,
                    ref: d.payload.ref,
                    master_branch: d.repository.master_branch,
                    comment: sha[2]
    				};
    		//Check formatted JSON
    		//http://jsonformatter.curiousconcept.com
    		//http://codebeautify.org/view/jsonviewer
    		s.commits[sha[0]] = info;
    	}) //end foreach sha
    }  //end 'PushEvent'
  }) //end s.on('data')
  s.on('error', cb)
  return wrap(s)
}

function wrap (obj) {
  Object.keys(module.exports).forEach(function (i) {
    obj[i] = function () { return obj.pipe(module.exports[i].apply(module.exports, arguments)) }
  })
  obj.once('write', function () {
    Object.keys(module.exports).forEach(function (i) {
      obj[i] = function () { throw new Error('Cannot ask for new parsing after the first write.') }
    })
  })
  obj.on('end', function () {
    Object.keys(module.exports).forEach(function (i) {
      obj[i] = function () { throw new Error('Cannot ask for new parsing after the stream has ended.') }
    })
  })
  return obj
}

module.exports.request = function (url) {
  // http://nickfishman.com/post/49533681471/nodejs-http-requests-with-gzip-deflate-compression
  var headers = {
  "accept-charset" : "ISO-8859-1,utf-8;q=0.7,*;q=0.3",
  "accept-language" : "en-US,en;q=0.8",
  "accept" : "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
  "user-agent" : "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_6_8) AppleWebKit/537.13+ (KHTML, like Gecko) Version/5.1.7 Safari/534.57.2",
  "accept-encoding" : "gzip,deflate",
  }
  var options = {
  url: url,
  headers: headers
  }
  return wrap(request(options).pipe(zlib.createGunzip()).pipe(jsonstream.parse()))
}

module.exports.readFile = function (path, options) {

  var f = fs.createReadStream(path)
    , z = new zlib.createGunzip()
    , j = jsonstream.parse()

  if (options.gzip !== false) {
    f.pipe(z)
    z.pipe(j)
  } else {
    f.pipe(j)
  }

  return wrap(j)
}

module.exports.range = function (start, end) {
  // I get Access Denied for any range I try to use in the HTTP interface
  // this is why we do a GET per hour and pipe them all together.
  // This also solves some timeout and throttling issues.
  var timestamps = []
  if (end < start) throw new Error('end is before start')
  console.log(start, end)
  var s = new Date(start)
  while (end > s) {
    timestamps.push(timezone(s, '%Y-%m-%d-%k').replace(/\ /g, ''))
    s.setHours(s.getHours()+1)
  }

  var output = new CallbackStream(function () {}) // noop for end

  timestamps.forEach(function (ts) {
    var r = request('http://data.githubarchive.org/'+ts+'.json.gz')
    r.on('response', function (resp) {
      output.emit('timerange', ts)
      if (resp.statusCode !== 200) {
        console.error('not 200', 'http://data.githubarchive.org/'+ts+'.json.gz')
        return
      }

      var z = new zlib.createGunzip()
        , j = jsonstream.parse()
        ;
      j.on('data', function (obj) {
        var created = new Date(obj.created_at)
        if (created < start) return
        if (created > end) return
        output.emit('data', obj)
      })
      resp.pipe(z)
      z.pipe(j)

      if (timestamps.indexOf(ts) === timestamps.length - 1) j.on('end', output.end.bind(output))
    })
  })

  return wrap(output)
}

<|endoftext|>


<commit_before>//This document!
$( document ).ready(function() {
    console.log( "ready!" );
});
<commit_msg>I added another comment!!<commit_after>//This document!
//Another Comment!!
$( document ).ready(function() {
    console.log( "ready!" );
});
<|endoftext|>


<commit_before>'use strict';

var db           = require('larvitdb'),
    log          = require('winston'),
    async        = require('async'),
    events       = require('events'),
    slugify      = require('underscore.string/slugify'),
    eventEmitter = new events.EventEmitter(),
    dbChecked    = false;

// Create database tables if they are missing
function createTablesIfNotExists(cb) {
	var sql;

	sql = 'CREATE TABLE IF NOT EXISTS `blog_entries` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `published` datetime DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;';
	db.query(sql, function(err) {
		if (err) {
			cb(err);
			return;
		}

		sql = 'CREATE TABLE IF NOT EXISTS `blog_entriesData` (`entryId` int(10) unsigned NOT NULL, `lang` char(2) CHARACTER SET ascii NOT NULL, `header` varchar(191) COLLATE utf8mb4_unicode_ci, `body` text COLLATE utf8mb4_unicode_ci, `slug` varchar(255) CHARACTER SET ascii, PRIMARY KEY (`entryId`,`lang`), UNIQUE KEY `lang_slug` (`lang`,`slug`), CONSTRAINT `blog_entriesData_ibfk_1` FOREIGN KEY (`entryId`) REFERENCES `blog_entries` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;';
		db.query(sql, function(err) {
			if (err) {
				cb(err);
				return;
			}

			dbChecked = true;
			eventEmitter.emit('checked');
		});
	});
}
createTablesIfNotExists();

/**
 * Get blog entries
 *
 * @param obj options - { // All options are optional!
 *                        'langs': ['sv', 'en'],
 *                        'publishedAfter': dateObj,
 *                        'ids': [32,4],
 *                        'limit': 10,
 *                        'offset': 20
 *                      }
 * @param func cb - callback(err, entries)
 */
function getEntries(options, cb) {
	var tmpEntries = {},
	    dbFields   = [],
	    entries    = [],
	    sql,
	    i;

	if (typeof options === 'function') {
		cb      = options;
		options = {};
	}

	log.debug('larvitblog: getEntries() - Called with options: "' + JSON.stringify(options) + '"');

	if (options.langs !== undefined && ! (options.langs instanceof Array))
		options.langs = [options.langs];

	if (options.ids !== undefined && ! (options.ids instanceof Array))
		options.ids = [options.ids];

	// Make sure there is an invalid ID in the id list if it is empty
	// Since the most logical thing to do is replying with an empty set
	if (options.ids instanceof Array && options.ids.length === 0)
		options.ids.push(- 1);

	if (options.limit === undefined)
		options.limit = 10;

	// Make sure the database tables exists before going further!
	if ( ! dbChecked) {
		log.debug('larvitblog: getEntries() - Database not checked, rerunning this method when event have been emitted.');
		eventEmitter.on('checked', function() {
			log.debug('larvitblog: getEntries() - Database check event received, rerunning getEntries().');
			getEntries(options, cb);
		});

		return;
	}

	sql  = 'SELECT ed.*, e.id, e.created, e.published\n';
	sql += 'FROM blog_entries e\n';
	sql += '	LEFT JOIN blog_entriesData ed ON ed.entryId = e.id\n';
	sql += 'WHERE 1 + 1\n';

	// Only get post contents with selected languages
	if (options.langs !== undefined) {
		sql += '	AND ed.lang IN (';

		i = 0;
		while (options.langs[i] !== undefined) {
			sql += '?,';
			dbFields.push(options.langs[i]);

			i ++;
		}

		sql = sql.substring(0, sql.length - 1) + ')\n';
	}

	// Only get posts with given ids
	if (options.ids !== undefined) {
		sql += '	AND e.id IN (';

		i = 0;
		while (options.ids[i] !== undefined) {
			sql += '?,';
			dbFields.push(options.ids[i]);

			i ++;
		}

		sql = sql.substring(0, sql.length - 1) + ')\n';
	}

	// Only get posts published after a certain date
	if (options.publishedAfter) {
		sql += '	AND e.published > ?\n';
		dbFields(options.publishedAfter);
	}

	sql += 'ORDER BY e.published DESC, ed.lang\n';
	sql += 'LIMIT ' + parseInt(options.limit) + '\n';

	if (options.offset !== undefined)
		sql += ' OFFSET ' + parseInt(options.offset);

	db.query(sql, dbFields, function(err, rows) {
		var entryId,
		    i;

		if (err) {
			cb(err);
			return;
		}

		i = 0;
		while (rows[i] !== undefined) {
			if (tmpEntries[rows[i].id] === undefined) {
				tmpEntries[rows[i].id] = {
					'id': rows[i].id,
					'created': rows[i].created,
					'published': rows[i].published,
					'langs': {}
				};
			}

			tmpEntries[rows[i].id].langs[rows[i].lang] = {
				'header': rows[i].header,
				'body': rows[i].body,
				'slug': rows[i].slug
			};

			i ++;
		}

		for (entryId in tmpEntries) {
			entries.push(tmpEntries[entryId]);
		}

		cb(null, entries);
	});
};

function rmEntry(id, cb) {
	db.query('DELETE FROM blog_entriesData WHERE entryId = ?', [id], function(err) {
		if (err) {
			cb(err);
			return;
		}

		db.query('DELETE FROM blog_entries WHERE id = ?', [id], cb);
	});
}

/**
 * Save an entry
 *
 * @param obj data - { // All options are optional!
 *                     'id': 1323,
 *                     'published': dateObj,
 *                     'langs': {
 *                       'en': {
 *                         'header': 'foo',
 *                         'slug': 'bar',
 *                         'body': 'lots of foo and bars'
 *                       },
 *                       'sv' ...
 *                     }
 *                   }
 * @param func cb(err, entry) - the entry will be a row from getEntries()
 */
function saveEntry(data, cb) {
	var tasks = [],
	    lang;

	if (typeof data === 'function') {
		cb   = data;
		data = {};
	}

	log.verbose('larvitblog: saveEntry() - Running with data. "' + JSON.stringify(data) + '"');

	// Make sure the database tables exists before going further!
	if ( ! dbChecked) {
		log.debug('larvitblog: saveEntry() - Database not checked, rerunning this method when event have been emitted.');
		eventEmitter.on('checked', function() {
			log.debug('larvitblog: saveEntry() - Database check event received, rerunning saveEntry().');
			exports.saveEntry(data, cb);
		});

		return;
	}

	// Create a new post id is not set
	if (data.id === undefined) {
		tasks.push(function(cb) {
			var sql      = 'INSERT INTO blog_entries (created',
				  dbFields = [];

			if (data.published)
				sql += ', published';

			sql += ') VALUES(NOW()';

			if (data.published) {
				sql += ',?';
				dbFields.push(data.published);
			}

			sql += ');';

			db.query(sql, dbFields, function(err, result) {
				if (err) {
					cb(err);
					return;
				}

				log.debug('larvitblog: saveEntry() - New blog entry created with id: "' + result.insertId + '"');
				data.id = result.insertId;
				cb();
			});
		});
	} else {
		// Erase previous data
		tasks.push(function(cb) {
			db.query('DELETE FROM blog_entriesData WHERE entryId = ?', [parseInt(data.id)], cb);
		});

		// Set published
		tasks.push(function(cb) {
			var sql      = 'UPDATE blog_entries SET published = ? WHERE id = ?',
			    dbFields = [data.published, data.id];

			db.query(sql, dbFields, cb);
		});
	}

	// We need to declare this outside the loop because of async operations
	function addEntryData(lang, header, body, slug) {
		tasks.push(function(cb) {
			var sql      = 'INSERT INTO blog_entriesData (entryId, lang, header, body, slug) VALUES(?,?,?,?,?);',
			    dbFields = [data.id, lang, header, body, slug];

			db.query(sql, dbFields, cb);
		});
	}

	// Add content data
	if (data.langs) {
		for (lang in data.langs) {
			if (data.langs[lang].slug)
				data.langs[lang].slug = slugify(data.langs[lang].slug);

			if (data.langs[lang].header || data.langs[lang].body)
				addEntryData(lang, data.langs[lang].header, data.langs[lang].body, data.langs[lang].slug);
		}
	}

	async.series(tasks, function(err) {
		if (err) {
			cb(err);
			return;
		}

		// Re-read this entry from the database to be sure to get the right deal!
		getEntries({'ids': data.id}, function(err, entries) {
			if (err) {
				cb(err);
				return;
			}

			cb(null, entries[0]);
		});
	});
};

exports.getEntries = getEntries;
exports.rmEntry    = rmEntry;
exports.saveEntry  = saveEntry;<commit_msg>Added support for slugs selector and error reporting for database creation function<commit_after>'use strict';

var db           = require('larvitdb'),
    log          = require('winston'),
    async        = require('async'),
    events       = require('events'),
    slugify      = require('underscore.string/slugify'),
    eventEmitter = new events.EventEmitter(),
    dbChecked    = false;

// Create database tables if they are missing
function createTablesIfNotExists(cb) {
	var sql;

	sql = 'CREATE TABLE IF NOT EXISTS `blog_entries` (`id` int(10) unsigned NOT NULL AUTO_INCREMENT, `created` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `published` datetime DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;';
	db.query(sql, function(err) {
		if (err) {
			cb(err);
			return;
		}

		sql = 'CREATE TABLE IF NOT EXISTS `blog_entriesData` (`entryId` int(10) unsigned NOT NULL, `lang` char(2) CHARACTER SET ascii NOT NULL, `header` varchar(191) COLLATE utf8mb4_unicode_ci, `body` text COLLATE utf8mb4_unicode_ci, `slug` varchar(255) CHARACTER SET ascii, PRIMARY KEY (`entryId`,`lang`), UNIQUE KEY `lang_slug` (`lang`,`slug`), CONSTRAINT `blog_entriesData_ibfk_1` FOREIGN KEY (`entryId`) REFERENCES `blog_entries` (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;';
		db.query(sql, function(err) {
			if (err) {
				cb(err);
				return;
			}

			dbChecked = true;
			eventEmitter.emit('checked');
		});
	});
}
createTablesIfNotExists(function(err) {
	log.error('larvitblog: createTablesIfNotExists() - Database error: ' + err.message);
});

/**
 * Get blog entries
 *
 * @param obj options - { // All options are optional!
 *                        'langs': ['sv', 'en'],
 *                        'slugs': ['blu', 'bla'],
 *                        'publishedAfter': dateObj,
 *                        'ids': [32,4],
 *                        'limit': 10,
 *                        'offset': 20
 *                      }
 * @param func cb - callback(err, entries)
 */
function getEntries(options, cb) {
	var tmpEntries = {},
	    dbFields   = [],
	    entries    = [],
	    sql,
	    i;

	if (typeof options === 'function') {
		cb      = options;
		options = {};
	}

	log.debug('larvitblog: getEntries() - Called with options: "' + JSON.stringify(options) + '"');

	// Make sure options that should be arrays actually are arrays
	// This will simplify our lives in the SQL builder below
	if (options.langs !== undefined && ! (options.langs instanceof Array))
		options.langs = [options.langs];

	if (options.ids !== undefined && ! (options.ids instanceof Array))
		options.ids = [options.ids];

	if (options.slugs !== undefined && ! (options.slugs instanceof Array))
		options.slugs = [options.slugs];

	// Make sure there is an invalid ID in the id list if it is empty
	// Since the most logical thing to do is replying with an empty set
	if (options.ids instanceof Array && options.ids.length === 0)
		options.ids.push(- 1);

	if (options.limit === undefined)
		options.limit = 10;

	// Make sure the database tables exists before going further!
	if ( ! dbChecked) {
		log.debug('larvitblog: getEntries() - Database not checked, rerunning this method when event have been emitted.');
		eventEmitter.on('checked', function() {
			log.debug('larvitblog: getEntries() - Database check event received, rerunning getEntries().');
			getEntries(options, cb);
		});

		return;
	}

	sql  = 'SELECT ed.*, e.id, e.created, e.published\n';
	sql += 'FROM blog_entries e\n';
	sql += '	LEFT JOIN blog_entriesData ed ON ed.entryId = e.id\n';
	sql += 'WHERE 1 + 1\n';

	// Only get post contents with selected languages
	if (options.langs !== undefined) {
		sql += '	AND ed.lang IN (';

		i = 0;
		while (options.langs[i] !== undefined) {
			sql += '?,';
			dbFields.push(options.langs[i]);

			i ++;
		}

		sql = sql.substring(0, sql.length - 1) + ')\n';
	}

	// Only get posts with the current slugs
	if (options.slugs !== undefined) {
		sql += '	AND e.id IN (SELECT entryId FROM blog_entriesData WHERE slug IN (';

		i = 0;
		while (options.slugs[i] !== undefined) {
			sql += '?,';
			dbFields(options.slugs[i]);

			i ++;
		}

		sql = sql.substring(0, sql.length - 1) + ')\n';
	}

	// Only get posts with given ids
	if (options.ids !== undefined) {
		sql += '	AND e.id IN (';

		i = 0;
		while (options.ids[i] !== undefined) {
			sql += '?,';
			dbFields.push(options.ids[i]);

			i ++;
		}

		sql = sql.substring(0, sql.length - 1) + ')\n';
	}

	// Only get posts published after a certain date
	if (options.publishedAfter) {
		sql += '	AND e.published > ?\n';
		dbFields(options.publishedAfter);
	}

	sql += 'ORDER BY e.published DESC, ed.lang\n';
	sql += 'LIMIT ' + parseInt(options.limit) + '\n';

	if (options.offset !== undefined)
		sql += ' OFFSET ' + parseInt(options.offset);

	db.query(sql, dbFields, function(err, rows) {
		var entryId,
		    i;

		if (err) {
			cb(err);
			return;
		}

		i = 0;
		while (rows[i] !== undefined) {
			if (tmpEntries[rows[i].id] === undefined) {
				tmpEntries[rows[i].id] = {
					'id': rows[i].id,
					'created': rows[i].created,
					'published': rows[i].published,
					'langs': {}
				};
			}

			tmpEntries[rows[i].id].langs[rows[i].lang] = {
				'header': rows[i].header,
				'body': rows[i].body,
				'slug': rows[i].slug
			};

			i ++;
		}

		for (entryId in tmpEntries) {
			entries.push(tmpEntries[entryId]);
		}

		cb(null, entries);
	});
};

function rmEntry(id, cb) {
	db.query('DELETE FROM blog_entriesData WHERE entryId = ?', [id], function(err) {
		if (err) {
			cb(err);
			return;
		}

		db.query('DELETE FROM blog_entries WHERE id = ?', [id], cb);
	});
}

/**
 * Save an entry
 *
 * @param obj data - { // All options are optional!
 *                     'id': 1323,
 *                     'published': dateObj,
 *                     'langs': {
 *                       'en': {
 *                         'header': 'foo',
 *                         'slug': 'bar',
 *                         'body': 'lots of foo and bars'
 *                       },
 *                       'sv' ...
 *                     }
 *                   }
 * @param func cb(err, entry) - the entry will be a row from getEntries()
 */
function saveEntry(data, cb) {
	var tasks = [],
	    lang;

	if (typeof data === 'function') {
		cb   = data;
		data = {};
	}

	log.verbose('larvitblog: saveEntry() - Running with data. "' + JSON.stringify(data) + '"');

	// Make sure the database tables exists before going further!
	if ( ! dbChecked) {
		log.debug('larvitblog: saveEntry() - Database not checked, rerunning this method when event have been emitted.');
		eventEmitter.on('checked', function() {
			log.debug('larvitblog: saveEntry() - Database check event received, rerunning saveEntry().');
			exports.saveEntry(data, cb);
		});

		return;
	}

	// Create a new post id is not set
	if (data.id === undefined) {
		tasks.push(function(cb) {
			var sql      = 'INSERT INTO blog_entries (created',
				  dbFields = [];

			if (data.published)
				sql += ', published';

			sql += ') VALUES(NOW()';

			if (data.published) {
				sql += ',?';
				dbFields.push(data.published);
			}

			sql += ');';

			db.query(sql, dbFields, function(err, result) {
				if (err) {
					cb(err);
					return;
				}

				log.debug('larvitblog: saveEntry() - New blog entry created with id: "' + result.insertId + '"');
				data.id = result.insertId;
				cb();
			});
		});
	} else {
		// Erase previous data
		tasks.push(function(cb) {
			db.query('DELETE FROM blog_entriesData WHERE entryId = ?', [parseInt(data.id)], cb);
		});

		// Set published
		tasks.push(function(cb) {
			var sql      = 'UPDATE blog_entries SET published = ? WHERE id = ?',
			    dbFields = [data.published, data.id];

			db.query(sql, dbFields, cb);
		});
	}

	// We need to declare this outside the loop because of async operations
	function addEntryData(lang, header, body, slug) {
		tasks.push(function(cb) {
			var sql      = 'INSERT INTO blog_entriesData (entryId, lang, header, body, slug) VALUES(?,?,?,?,?);',
			    dbFields = [data.id, lang, header, body, slug];

			db.query(sql, dbFields, cb);
		});
	}

	// Add content data
	if (data.langs) {
		for (lang in data.langs) {
			if (data.langs[lang].slug)
				data.langs[lang].slug = slugify(data.langs[lang].slug);

			if (data.langs[lang].header || data.langs[lang].body)
				addEntryData(lang, data.langs[lang].header, data.langs[lang].body, data.langs[lang].slug);
		}
	}

	async.series(tasks, function(err) {
		if (err) {
			cb(err);
			return;
		}

		// Re-read this entry from the database to be sure to get the right deal!
		getEntries({'ids': data.id}, function(err, entries) {
			if (err) {
				cb(err);
				return;
			}

			cb(null, entries[0]);
		});
	});
};

exports.getEntries = getEntries;
exports.rmEntry    = rmEntry;
exports.saveEntry  = saveEntry;<|endoftext|>