<commit_before>(function() {

	var filterExactValue = function(key, value, rdev) {
		return rdev.attributes[key] === value;
	};

	var defaultRemote = function(key, value) {
		return [key, value];
	};

	var FILTERS = {};

	var getFilterList = function(app) {

		var f = {

			severity: {
				label: O5._t("Severity"),
				local: filterExactValue,
				remote: defaultRemote,
				widget: 'select',
				choices: O5.RoadEventFieldsLookup.severity.choices
			},

			event_type: {
				label: O5.RoadEventFieldsLookup.event_type.label,
				local: filterExactValue,
				remote: defaultRemote,
				widget: 'select',
				choices: O5.RoadEventFieldsLookup.event_type.choices
			},

			status: {
				label: O5._t('Status'),
				local: function(key, value, rdev) {
					value = value.toUpperCase();
					return value === 'ALL' || value === rdev.get('status');
				},
				remote: defaultRemote,
				widget: 'select',
				choices: [
					['ACTIVE', O5._t('Active')],
					['ARCHIVED', O5._t('Archived')],
					['ALL', O5._t('All')]
				]
			},

			date: {
				label: O5._t('Date'),
				remote: function (key, value) {
					return [
						'in_effect_on',
						value + 'T00:00' + ',' + value + 'T23:59'
					];
				},
				local: function(key, value, rdev) {
					return rdev.parseSchedule().inEffectOn(moment(value));
				},
				widget: 'date'
			}
		};

		if (app.settings.jurisdictions && app.settings.jurisdictions.length) {
			f.jurisdiction = {
				label: O5._t("Jurisdiction"),
				local: function(key, value, rdev) {
					return rdev.getJurisdictionID() === value;
				},
				remote: defaultRemote,
				choices: function() {
					return _.map(O5.app.settings.jurisdictions, function(jur) {
						return [jur.id, jur.id];
					});
				},
				widget: 'select'
			};
		}

		if (app.settings.areas && app.settings.areas.length) {
			f.area_id = {
				label: O5._t("Area"),
				local: function(key, value, rdev) {
					return _.any(rdev.get('areas') || [], function(area) { return area.id === value; });
				},
				remote: defaultRemote,
				choices: app.settings.areas,
				widget: 'select'
			};
		}

		// PLUGIN HOOK
		app.trigger('filter-list', {
			'filters': f
		});

		return f;
	};

	/**
	 * Split a list of filters into remote/local.
	 */
	var analyzeFilters = function(filters) {
		var r = {
			localFilters: {},
			remoteFilters: {},
			filterableLocally: true
		};
		_.each(filters, function(val, type) {
			if (FILTERS[type].local) {
				r.localFilters[type] = val;
			}
			else {
				r.remoteFilters[type] = val;
				r.filterableLocally = false;
			}
		});
		return r;
	};

	// How often to check for updates, in milliseconds
	var POLL_INTERVAL = 30000;

	/**
	 * The public interface to filtering.
	 * 
	 * Maintains a list of previously-seen filters, and figures out the best way
	 * to calculate a given filter.
	 */
	var FilterManager = function(opts) {
		this.app = opts.app;
		this.history = [];
		this.lastServerFetch = null;

		// Get the list of filters
		FILTERS = getFilterList(this.app);
		this.app.FILTERS = FILTERS;

		// Hook into events on the RoadEvents collection
		var self = this;
		this.app.events.on('add', function(event, collection, options) {
			var fs = null;
			if (options) fs = options.sourceFilteredSet;
			if (fs) {
				fs.forceAdd(event);
				if (fs !== self.activeSet && !self.activeSet.evaluateEvent(event, false, fs)) {
					event.setInternal('visible', false);
				}
			}
			else {
				if (!self.activeSet.evaluateEvent(event)) {
					event.setInternal('visible', false);
				}
			}
			for (var i = 0; i < self.history.length; i ++) {
				if (self.history[i] !== self.activeSet) {
					self.history[i].evaluateEvent(event, false, fs);
				}
			}
		});
		this.app.events.on('remove', function(event) {
			self.activeSet.forceRemove(event);
			_.each(self.history, function(fs) {
				fs.forceRemove(event);
			});
		});
		this.app.events.on('change', function(event) {
			// If an event changes, test it against the active FilteredSet
			// to see if it should still be visible.
			var vis = self.activeSet.evaluateEvent(event, true);
			if (vis !== event.internal.visible) {
				event.setInternal('visible', vis);
			}
			// And test it against the history, so those sets remain up-to-date
			// if we want to reuse them later.
			for (var i = 0; i < self.history.length; i ++) {
				if (self.history[i] !== self.activeSet) {
					self.history[i].evaluateEvent(event, true);
				}
			}
		});

		this.setFilters({});
		this.allEventsSet = new FilteredSet({
			manager: this,
			filterState: {status: 'ALL'}
		});
		this.setPollTimeout();
	};

	_.extend(FilterManager.prototype, {

		_addToHistory: function(fs) {
			this.history.push(fs);
		},

		getCurrentFilters: function() {
			return _.clone(this.activeSet.filterState);
		},<commit_msg>Fix filtering bug (filters including archived events wouldn't work after a background poll had taken place)<commit_after>(function() {

	var filterExactValue = function(key, value, rdev) {
		return rdev.attributes[key] === value;
	};

	var defaultRemote = function(key, value) {
		return [key, value];
	};

	var FILTERS = {};

	var getFilterList = function(app) {

		var f = {

			severity: {
				label: O5._t("Severity"),
				local: filterExactValue,
				remote: defaultRemote,
				widget: 'select',
				choices: O5.RoadEventFieldsLookup.severity.choices
			},

			event_type: {
				label: O5.RoadEventFieldsLookup.event_type.label,
				local: filterExactValue,
				remote: defaultRemote,
				widget: 'select',
				choices: O5.RoadEventFieldsLookup.event_type.choices
			},

			status: {
				label: O5._t('Status'),
				local: function(key, value, rdev) {
					value = value.toUpperCase();
					return value === 'ALL' || value === rdev.get('status');
				},
				remote: defaultRemote,
				widget: 'select',
				choices: [
					['ACTIVE', O5._t('Active')],
					['ARCHIVED', O5._t('Archived')],
					['ALL', O5._t('All')]
				]
			},

			date: {
				label: O5._t('Date'),
				remote: function (key, value) {
					return [
						'in_effect_on',
						value + 'T00:00' + ',' + value + 'T23:59'
					];
				},
				local: function(key, value, rdev) {
					return rdev.parseSchedule().inEffectOn(moment(value));
				},
				widget: 'date'
			}
		};

		if (app.settings.jurisdictions && app.settings.jurisdictions.length) {
			f.jurisdiction = {
				label: O5._t("Jurisdiction"),
				local: function(key, value, rdev) {
					return rdev.getJurisdictionID() === value;
				},
				remote: defaultRemote,
				choices: function() {
					return _.map(O5.app.settings.jurisdictions, function(jur) {
						return [jur.id, jur.id];
					});
				},
				widget: 'select'
			};
		}

		if (app.settings.areas && app.settings.areas.length) {
			f.area_id = {
				label: O5._t("Area"),
				local: function(key, value, rdev) {
					return _.any(rdev.get('areas') || [], function(area) { return area.id === value; });
				},
				remote: defaultRemote,
				choices: app.settings.areas,
				widget: 'select'
			};
		}

		// PLUGIN HOOK
		app.trigger('filter-list', {
			'filters': f
		});

		return f;
	};

	/**
	 * Split a list of filters into remote/local.
	 */
	var analyzeFilters = function(filters) {
		var r = {
			localFilters: {},
			remoteFilters: {},
			filterableLocally: true
		};
		_.each(filters, function(val, type) {
			if (FILTERS[type].local) {
				r.localFilters[type] = val;
			}
			else {
				r.remoteFilters[type] = val;
				r.filterableLocally = false;
			}
		});
		return r;
	};

	// How often to check for updates, in milliseconds
	var POLL_INTERVAL = 30000;

	/**
	 * The public interface to filtering.
	 * 
	 * Maintains a list of previously-seen filters, and figures out the best way
	 * to calculate a given filter.
	 */
	var FilterManager = function(opts) {
		this.app = opts.app;
		this.history = [];
		this.lastServerFetch = null;

		// Get the list of filters
		FILTERS = getFilterList(this.app);
		this.app.FILTERS = FILTERS;

		// Hook into events on the RoadEvents collection
		var self = this;
		this.app.events.on('add', function(event, collection, options) {
			var fs = null;
			if (options) fs = options.sourceFilteredSet;
			if (fs) {
				fs.forceAdd(event);
				if (fs !== self.activeSet && !self.activeSet.evaluateEvent(event, false, fs)) {
					event.setInternal('visible', false);
				}
			}
			else {
				if (!self.activeSet.evaluateEvent(event)) {
					event.setInternal('visible', false);
				}
			}
			for (var i = 0; i < self.history.length; i ++) {
				if (self.history[i] !== self.activeSet) {
					self.history[i].evaluateEvent(event, false, fs);
				}
			}
		});
		this.app.events.on('remove', function(event) {
			self.activeSet.forceRemove(event);
			_.each(self.history, function(fs) {
				fs.forceRemove(event);
			});
		});
		this.app.events.on('change', function(event) {
			// If an event changes, test it against the active FilteredSet
			// to see if it should still be visible.
			var vis = self.activeSet.evaluateEvent(event, true);
			if (vis !== event.internal.visible) {
				event.setInternal('visible', vis);
			}
			// And test it against the history, so those sets remain up-to-date
			// if we want to reuse them later.
			for (var i = 0; i < self.history.length; i ++) {
				if (self.history[i] !== self.activeSet) {
					self.history[i].evaluateEvent(event, true);
				}
			}
		});

		this.setFilters({});

		this.allEventsSet = new FilteredSet({
			manager: this,
			filterState: {status: 'ALL'}
		});
		// The allEventsSet is used when polling for updates;
		// however, we don't start by fetching all events, 
		// so we never want to add it the history of completed
		// sets.
		this.allEventsSet.excludeFromHistory = true;
		this.setPollTimeout();
	};

	_.extend(FilterManager.prototype, {

		_addToHistory: function(fs) {
			if (!fs.excludeFromHistory)
				this.history.push(fs);
		},

		getCurrentFilters: function() {
			return _.clone(this.activeSet.filterState);
		},
{'fraction_non_alphanumeric': 0.15491819834376894, 'fraction_numerical': 0.005453443748737629, 'mean_word_length': 2.928203094010313, 'pattern_counts': {'":': 0, '<': 7, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2597781', 'n_tokens_mistral': 4200, 'n_tokens_neox': 3348, 'n_words': 763}