incubator-blur-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From amccu...@apache.org
Subject [12/50] [abbrv] Moved the UI directory and starting to get the server side working... still broken
Date Sat, 31 May 2014 14:21:45 GMT
http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.search.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.search.js b/contrib/blur-console/src/main/webapp/js/blurconsole.search.js
new file mode 100644
index 0000000..5035ac0
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.search.js
@@ -0,0 +1,299 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+/*global blurconsole:false, confirm:false */
+blurconsole.search = (function () {
+	'use strict';
+	var configMap = {
+		view : 'views/search.tpl.html',
+		superQueryMap: {
+			'rowrow' : 'Search Row / Retrieve Row',
+			'recordrow' : 'Search Record / Retrieve Row',
+			'recordrecord' : 'Search Record / Retrieve Record'
+		},
+		optionsHtml:
+			'<label for="superQuery">Search & Retrieve</label>' +
+			'<select id="superQuery">' +
+				'<option value="rowrow">Search Row / Retrieve Row</option>' +
+				'<option value="recordrow">Search Record / Retrieve Row</option>' +
+				'<option value="recordrecord">Search Record / Retrieve Record</option>' +
+			'</select>'
+	},
+	stateMap = {
+		$container : null,
+		$currentTable : null,
+		$currentQuery : null,
+		$schemaForCurrentTable : null,
+		$start : 0,
+		$fetch : 10,
+		$filter : null,
+		$rowRecordOption : 'rowrow'
+	},
+	jqueryMap = {},
+	setJqueryMap, initModule, unloadModule, drawResultHolders, drawResults, registerPageEvents, unregisterPageEvents,
+	sendSearch, showOptions, reviewTables, loadTableList, getMoreData, fixPanelWidths, updateOptionPopover, updateOptionDisplay,
+	persistOptions;
+
+	setJqueryMap = function() {
+		var $container = stateMap.$container;
+		jqueryMap = {
+			$container : $container,
+			$queryField : $('#queryField'),
+			$tableField : $('#tableChooser'),
+			$tableSelectorStatusOption : $('#statusOption'),
+			$tableWarning : $('#tableGoneWarning'),
+			$resultsHolder : $('#results'),
+			$optionsDisplay : $('#searchOptionsDisplay'),
+			$countHolder : $('#resultCount')
+		};
+	};
+
+	registerPageEvents = function() {
+		$('#searchTrigger').on('click', sendSearch);
+		$('#results').on('shown.bs.collapse', '.panel-collapse:not(.loaded)', getMoreData);
+		$('#results').on('click', '.nextPage', getMoreData);
+		$('#searchOptionsTrigger').popover({
+			html: true,
+			placement: 'bottom',
+			title: 'Extra Search Options',
+			container: 'body',
+			content: configMap.optionsHtml
+		});
+		$('#searchOptionsTrigger').on('shown.bs.popover', updateOptionPopover);
+		$(document).on('change', '.popover select', persistOptions);
+	};
+
+	unregisterPageEvents = function() {
+		$('#searchTrigger').off('click');
+		$('#results').off('shown.bs.collapse');
+		$('#results').off('click');
+		$('#searchOptionsTrigger').popover('destroy');
+		$('#searchOptionsTrigger').off('shown.bs.popover');
+		$(document).off('change');
+	};
+
+	updateOptionDisplay = function() {
+		var displayText = '';
+
+		displayText += configMap.superQueryMap[stateMap.$rowRecordOption];
+
+		jqueryMap.$optionsDisplay.html(displayText);
+	};
+
+	updateOptionPopover = function() {
+		if ($('#superQuery').length > 0) {
+			$('#superQuery').val(stateMap.$rowRecordOption);
+		}
+	};
+
+	persistOptions = function() {
+		var resendSearch = false;
+		if (jqueryMap.$resultsHolder.children().length > 0) {
+			if (confirm('You have existing results on the screen, changing the search options will erase your results.  Continue?')) {
+				resendSearch = true;
+			} else {
+				$('#superQuery').val(stateMap.$rowRecordOption);
+				return false;
+			}
+		}
+		stateMap.$rowRecordOption = $('#superQuery').val();
+		if (resendSearch) {
+			sendSearch();
+		}
+		updateOptionDisplay();
+		$('#searchOptionsTrigger').popover('hide');
+	};
+
+	sendSearch = function() {
+		stateMap.$currentTable = jqueryMap.$tableField.val();
+		stateMap.$currentQuery = jqueryMap.$queryField.val();
+
+		blurconsole.shell.changeAnchorPart({
+			tab: 'search',
+			_tab: {
+				query: encodeURIComponent(stateMap.$currentQuery),
+				table: stateMap.$currentTable,
+				rr: stateMap.$rowRecordOption
+			}
+		});
+
+		drawResultHolders();
+
+		blurconsole.model.search.runSearch(stateMap.$currentQuery, stateMap.$currentTable, {start: 0, fetch: 10});
+	};
+
+	getMoreData = function() {
+		var family = $(this).attr('href') ? $(this).attr('href').substring(1) : $(this).attr('id');
+		blurconsole.model.search.loadMoreResults(family);
+		return false;
+	};
+
+	showOptions = function() {
+
+	};
+
+	reviewTables = function() {
+		var tableFound = false, tableMap;
+
+		if (stateMap.$currentTable) {
+			tableMap = blurconsole.model.tables.getAllEnabledTables();
+			$.each(tableMap, function(cluster, tables){
+				var tableList = $.map(tables, function(t){ return t.name; });
+				if (tableList.indexOf(stateMap.$currentTable) > -1) {
+					tableFound = true;
+				}
+			});
+		}
+
+		if (tableFound) {
+			jqueryMap.$tableWarning.hide();
+			loadTableList();
+		} else if (stateMap.$currentTable) {
+			jqueryMap.$tableWarning.show();
+		} else {
+			loadTableList();
+		}
+	};
+
+	drawResultHolders = function() {
+		var familyMarkup = '', allFamilies, extraFamilies = [], parsedFamilies = blurconsole.utils.findFamilies(stateMap.$currentQuery), sortedFamilies;
+
+		jqueryMap.$resultsHolder.html('');
+
+		// Redraw families
+		allFamilies = blurconsole.model.tables.getFamilies(stateMap.$currentTable);
+		extraFamilies = blurconsole.utils.reject(allFamilies, function(fam){ return parsedFamilies.indexOf(fam) >= 0; });
+
+		parsedFamilies.sort();
+		extraFamilies.sort();
+
+		sortedFamilies = parsedFamilies.concat(extraFamilies);
+
+		$.each(sortedFamilies, function(i, fam) {
+			var famId = blurconsole.browserUtils.cleanId(fam);
+			familyMarkup += '<div class="panel panel-default"><div class="panel-heading">';
+			familyMarkup += '<h4 class="panel-title"><a data-toggle="collapse" data-parent="#results" href="#' + famId + '">' + fam + '</a></h4></div>';
+			familyMarkup += '<div id="' + famId + '" class="panel-collapse collapse' + (parsedFamilies.indexOf(fam) >= 0 ? ' in' : '') + '">';
+			familyMarkup += '<div class="panel-body"><img src="img/ajax-loader.gif"></div></div></div>';
+		});
+
+		jqueryMap.$resultsHolder.html(familyMarkup);
+		fixPanelWidths();
+	};
+
+	fixPanelWidths = function() {
+		var allPanels = jqueryMap.$resultsHolder.find('.panel-collapse');
+		if (allPanels.length > 0) {
+			var width = $(allPanels[0]).width();
+			allPanels.width(width);
+		}
+	};
+
+	drawResults = function(evt, families) {
+		var results = blurconsole.model.search.getResults();
+		jqueryMap.$countHolder.html('<small>Found ' + blurconsole.model.search.getTotal() + ' total results</small>');
+
+		$.each(families, function(i, fam) {
+			var famResults = results[fam],
+				famId = '#' + blurconsole.browserUtils.cleanId(fam),
+				famHolder = $(famId + ' .panel-body'), table = '', cols;
+
+			cols = blurconsole.utils.keys(famResults[0]);
+			cols.sort();
+
+			table += '<table class="table table-condensed table-hover table-bordered"><thead><tr>';
+			$.each(cols, function(i, col) {
+				table += '<th>' + col + '</th>';
+			});
+			table += '</tr></thead><tbody>';
+			$.each(famResults, function(i, row) {
+				table += '<tr>';
+				$.each(cols, function(c, col) {
+					table += '<td>' + (row[col] || '') + '</td>';
+				});
+				table += '</tr>';
+			});
+			table += '</tbody></table>';
+
+			if (famResults.length < blurconsole.model.search.getTotal()) {
+				table += '<div class="pull-right"><a href="' + famId + '" class="btn btn-primary nextPage">Load More...</a></div>';
+			}
+
+			famHolder.html(table);
+			if (!$(famId).hasClass('loaded')) {
+				$(famId).addClass('loaded');
+			}
+		});
+		fixPanelWidths();
+	};
+
+	loadTableList = function() {
+		var tableMap = blurconsole.model.tables.getAllEnabledTables();
+
+		jqueryMap.$tableSelectorStatusOption.html('Loading Tables...');
+		jqueryMap.$tableField.find('optgroup').remove();
+
+		$.each(tableMap, function(cluster, tables) {
+			var optGroupString;
+
+			optGroupString = '<optgroup label="' + cluster + '">';
+			$.each(tables, function(t, table){
+				optGroupString += '<option value="' + table.name + '"' + (table.name === stateMap.$currentTable ? ' selected' : '') + '>' + table.name + '</option>';
+			});
+			optGroupString += '</optgroup>';
+			jqueryMap.$tableField.append(optGroupString);
+		});
+
+		jqueryMap.$tableSelectorStatusOption.html('Choose Table');
+	};
+
+	initModule = function($container) {
+		$container.load(configMap.view, function() {
+			stateMap.$container = $container;
+			setJqueryMap();
+			$.gevent.subscribe(jqueryMap.$container, 'tables-updated', reviewTables);
+			$.gevent.subscribe(jqueryMap.$container, 'results-updated', drawResults);
+			registerPageEvents();
+			loadTableList();
+
+			var startupMap = $.uriAnchor.makeAnchorMap();
+
+			if (startupMap._tab) {
+				stateMap.$currentQuery = startupMap._tab.query;
+				jqueryMap.$queryField.val(stateMap.$currentQuery);
+				stateMap.$currentTable = startupMap._tab.table;
+				jqueryMap.$tableField.val(stateMap.$currentTable);
+				stateMap.$rowRecordOption = startupMap._tab.rr;
+			}
+
+			updateOptionDisplay();
+			stateMap.loaded = true;
+		});
+		return true;
+	};
+
+	unloadModule = function() {
+		$.gevent.unsubscribe(jqueryMap.$container, 'tables-updated');
+		unregisterPageEvents();
+	};
+
+	return {
+		initModule : initModule,
+		unloadModule : unloadModule
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.shell.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.shell.js b/contrib/blur-console/src/main/webapp/js/blurconsole.shell.js
new file mode 100644
index 0000000..ee19283
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.shell.js
@@ -0,0 +1,180 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+
+/**
+ * blurconsole.shell.js
+ * Shell module for Blur Console
+ */
+/* global blurconsole:false, $:false */
+blurconsole.shell = (function () {
+	'use strict';
+	var configMap = {
+		anchorSchemaMap : {
+			tab : { dashboard : true, tables : true, queries : true, search : true },
+			_tab : { query: true, table: true, rr: true }
+		},
+		defaultTab : 'dashboard',
+		allTabs : ['dashboard', 'tables', 'queries', 'search']
+	},
+	stateMap = {
+		$container : null,
+		currentTab : null,
+		anchorMap  : {}
+	},
+	jqueryMap = {},
+	copyAnchorMap, setJqueryMap, switchView,
+	changeAnchorPart, onHashChange,
+	onClickTab, initModule;
+
+	copyAnchorMap = function () {
+		return $.extend( true, {}, stateMap.anchorMap );
+	};
+
+	setJqueryMap = function () {
+		var $container = stateMap.$container;
+		jqueryMap = {
+			$container   : $container,
+			$sideNavTabs : $('.side-nav a')
+		};
+	};
+
+	switchView = function ( tab ) {
+		var i;
+
+		if (stateMap.currentTab !== tab) {
+			for ( i = 0; i < configMap.allTabs.length; i++ ) {
+				if (blurconsole[configMap.allTabs[i]]) {
+					blurconsole[configMap.allTabs[i]].unloadModule();
+				}
+			}
+
+			stateMap.currentTab = tab;
+			jqueryMap.$sideNavTabs.removeClass('active');
+			jqueryMap.$sideNavTabs.filter('a[href$="' + tab + '"]').addClass('active');
+			if (blurconsole[tab]) {
+				blurconsole[tab].initModule( jqueryMap.$container );
+			}
+		}
+
+		return true;
+	};
+
+	changeAnchorPart = function ( argMap ) {
+		var anchorMapRevise = copyAnchorMap(),
+			boolReturn = true,
+			keyName, keyNameDep;
+
+		KEYVAL:
+		for ( keyName in argMap ) {
+			if ( argMap.hasOwnProperty( keyName ) ) {
+				if ( keyName.indexOf( '_' ) === 0 ) { continue KEYVAL; }
+				anchorMapRevise[keyName] = argMap[keyName];
+				keyNameDep = '_' + keyName;
+				if ( argMap[keyNameDep] ) {
+					anchorMapRevise[keyNameDep] = argMap[keyNameDep];
+				} else {
+					delete anchorMapRevise[keyNameDep];
+					delete anchorMapRevise['_s' + keyNameDep];
+				}
+			}
+		}
+
+		try {
+			$.uriAnchor.setAnchor( anchorMapRevise );
+		} catch ( error ) {
+			$.uriAnchor.setAnchor( stateMap.anchorMap, null, true );
+			boolReturn = false;
+		}
+
+		return boolReturn;
+	};
+
+	onHashChange = function () {
+		var anchorMapPrevious = copyAnchorMap(),
+			anchorMapProposed,
+			_sTabPrevious, _sTabProposed,
+			sTabProposed;
+
+		try { anchorMapProposed = $.uriAnchor.makeAnchorMap(); }
+		catch ( error ) {
+			$.uriAnchor.setAnchor( anchorMapPrevious, null, true );
+			return false;
+		}
+
+		stateMap.anchorMap = anchorMapProposed;
+
+		_sTabPrevious = anchorMapPrevious._s_tab; // jshint ignore:line
+		_sTabProposed = anchorMapProposed._s_tab; // jshint ignore:line
+
+		if ( ! anchorMapPrevious || _sTabPrevious !== _sTabProposed ){
+			sTabProposed = anchorMapProposed.tab;
+			switch ( sTabProposed ) {
+				case 'dashboard':
+				case 'tables':
+				case 'queries':
+				case 'search':
+					switchView( sTabProposed );
+					break;
+				default:
+					$.uriAnchor.setAnchor( anchorMapPrevious, null, true );
+			}
+		}
+
+		return false;
+	};
+
+	onClickTab = function ( ) {
+		var target = $(this);
+		changeAnchorPart({
+			tab : target.attr('href').substring(2)
+		});
+		return false;
+	};
+
+	initModule = function( $container ) {
+		stateMap.$container = $container;
+		setJqueryMap();
+
+		blurconsole.schema.initModule();
+
+		$('.side-nav li').tooltip();
+
+		jqueryMap.$sideNavTabs.click( onClickTab );
+
+		$.uriAnchor.configModule({
+			schema_map : configMap.anchorSchemaMap // jshint ignore:line
+		});
+
+		$(window).bind('hashchange', onHashChange).trigger('hashchange');
+
+		var startupMap = $.uriAnchor.makeAnchorMap();
+
+		if ( !startupMap.tab ) {
+			changeAnchorPart({
+				tab: configMap.defaultTab
+			});
+		}
+	};
+
+	return {
+		initModule: initModule,
+		changeAnchorPart : changeAnchorPart
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.tables.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.tables.js b/contrib/blur-console/src/main/webapp/js/blurconsole.tables.js
new file mode 100644
index 0000000..cb2a6f4
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.tables.js
@@ -0,0 +1,223 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+
+/*global blurconsole:false */
+blurconsole.tables = (function () {
+	'use strict';
+	var configMap = {
+		view : 'views/tables.tpl.html',
+		enabledDef : [
+			{label:'Table Name', key: function(row){
+				return row.name + ' <i class="glyphicon glyphicon-exclamation-sign" data-table="' + row.name + '" style="display:none" title="Activity detected"></i>';
+			}},
+			{label:'Row Count', key: 'rowCount'},
+			{label:'Record Count', key: 'recordCount'},
+			{label:'Actions', key: function(row) {
+				var actions = '', table = row.name;
+				actions += '<a href="#" class="schemaTrigger btn btn-default" data-name="' + table + '"><i class="glyphicon glyphicon-list-alt"></i> Schema</a> ';
+				actions += '<a href="#" class="disableTrigger btn btn-danger" data-name="' + table + '"><i class="glyphicon glyphicon-cloud-download"></i> Disable</a> ';
+				return actions;
+			}}
+		],
+		disabledDef : [
+			{label:'Table Name', key:'name'},
+			{label:'Actions', key: function(row) {
+				var actions = '', table = row.name;
+				actions += '<a href="#" class="enableTrigger btn btn-default" data-name="' + table + '"><i class="glyphicon glyphicon-cloud-upload"></i> Enable</a> ';
+				actions += '<a href="#" class="deleteTrigger btn btn-danger" data-name="' + table + '"><i class="glyphicon glyphicon-trash"></i> Delete</a> ';
+				return actions;
+			}}
+		]
+	},
+	stateMap = { $container : null },
+	jqueryMap = {},
+	setJqueryMap, initModule, unloadModule, updateTableList, buildTabs, waitForData, registerPageEvents, unregisterPageEvents, updateActivityIndicators;
+
+	setJqueryMap = function() {
+		var $container = stateMap.$container;
+		jqueryMap = {
+			$container : $container,
+			$tableInfoHolder : $('#tableInfoHolder'),
+			$tables : {}
+		};
+	};
+
+	unloadModule = function() {
+		$.gevent.unsubscribe(jqueryMap.$container, 'tables-updated');
+		$.gevent.unsubscribe(jqueryMap.$container, 'queries-updated');
+		unregisterPageEvents();
+	};
+
+	initModule = function($container) {
+		$container.load(configMap.view, function() {
+			stateMap.$container = $container;
+			setJqueryMap();
+			$.gevent.subscribe(jqueryMap.$container, 'tables-updated', updateTableList);
+			$.gevent.subscribe(jqueryMap.$container, 'queries-updated', updateActivityIndicators);
+			waitForData();
+			registerPageEvents();
+		});
+		return true;
+	};
+
+	waitForData = function() {
+		if (blurconsole.model.tables.getClusters().length > 0) {
+			buildTabs();
+		} else {
+			setTimeout(waitForData, 100);
+		}
+	};
+
+	buildTabs = function() {
+		var clusters, tabMarkup, paneMarkup, needsTabs;
+
+		clusters = blurconsole.model.tables.getClusters();
+		needsTabs = clusters.length > 1;
+
+		if (needsTabs) {
+			tabMarkup = '<ul class="nav nav-tabs">';
+			tabMarkup += $.map(clusters, function(cluster, idx) {
+				return '<li class="' + (idx === 0 ? 'active' : '') + '"><a href="#' + cluster + '_pane" data-toggle="tab">' + cluster + ' <i class="glyphicon glyphicon-exclamation-sign" style="display:none" title="Activity detected"></i></a></li>';
+			}).join('');
+			tabMarkup += '</ul>';
+
+			jqueryMap.$tableInfoHolder.html($(tabMarkup));
+		}
+
+		paneMarkup = needsTabs ? '<div class="tab-content">' : '';
+		paneMarkup += $.map(clusters, function(cluster, idx) {
+			return '<div id="' + cluster + '_pane" class="tab-pane' + (idx === 0 ? ' active' : '') + '"><h3>Enabled Tables</h3><div class="enabledSection"></div><h3>Disabled Tables</h3><div class="disabledSection"></div></div>';
+		}).join('');
+		paneMarkup += needsTabs ? '</div>' : '';
+
+		if (needsTabs) {
+			jqueryMap.$tableInfoHolder.append(paneMarkup);
+		} else {
+			jqueryMap.$tableInfoHolder.html(paneMarkup);
+		}
+
+		$.each(clusters, function(idx, cluster){
+			var clusterPane = $('#' + cluster + '_pane');
+			clusterPane.find('.enabledSection').html(blurconsole.browserUtils.table(configMap.enabledDef, blurconsole.model.tables.getEnabledTables(cluster)));
+			clusterPane.find('.disabledSection').html(blurconsole.browserUtils.table(configMap.disabledDef, blurconsole.model.tables.getDisabledTables(cluster)));
+		});
+	};
+
+	updateTableList = function() {
+		var clusters = blurconsole.model.tables.getClusters();
+
+		$.each(clusters, function(idx, cluster) {
+			var clusterPane = $('#' + cluster + '_pane'), enabledSection, disabledSection;
+			enabledSection = clusterPane.find('.enabledSection');
+			disabledSection = clusterPane.find('.disabledSection');
+
+			if (enabledSection.length > 0) {
+				enabledSection.html(blurconsole.browserUtils.table(configMap.enabledDef, blurconsole.model.tables.getEnabledTables(cluster)));
+			}
+			if (disabledSection.length > 0) {
+				disabledSection.html(blurconsole.browserUtils.table(configMap.disabledDef, blurconsole.model.tables.getDisabledTables(cluster)));
+			}
+		});
+	};
+
+	registerPageEvents = function() {
+		// Tab control
+		jqueryMap.$tableInfoHolder.on('click', 'ul.nav a', function(e) {
+			e.preventDefault();
+			$(this).tab('show');
+		});
+
+		// View Schema
+		jqueryMap.$tableInfoHolder.on('click', 'a.schemaTrigger', function() {
+			$.gevent.publish('schema-show', $(this).data('name'));
+			return false;
+		});
+
+		// Disable Table
+		jqueryMap.$tableInfoHolder.on('click', 'a.disableTrigger', function() {
+			blurconsole.model.tables.disableTable($(this).data('name'));
+			return false;
+		});
+
+		// Enable Table
+		jqueryMap.$tableInfoHolder.on('click', 'a.enableTrigger', function() {
+			blurconsole.model.tables.enableTable($(this).data('name'));
+			return false;
+		});
+
+		// Delete Table
+		jqueryMap.$tableInfoHolder.on('click', 'a.deleteTrigger', function() {
+			var tableName = $(this).data('name');
+			var modalContent = blurconsole.browserUtils.modal('confirmDelete', 'Confirm Table Deletion', 'You are about to delete table ' + tableName + '.  Are you sure you want to do this? If so, do you also want to delete the underlying table data?', [
+				{classes: 'btn-warning tableOnly', label: 'Table Only'},
+				{classes: 'btn-danger tableAndData', label: 'Table And Data'},
+				{classes: 'btn-default cancel', label: 'Cancel', data: {dismiss:'modal'}}
+			], 'medium');
+
+			var modal = $(modalContent).modal().on('shown.bs.modal', function(e){
+				$(e.currentTarget).on('click', '.tableOnly', function() {
+					blurconsole.model.tables.deleteTable(tableName, false);
+					modal.modal('hide');
+				}).on('click', '.tableAndData', function() {
+					blurconsole.model.tables.deleteTable(tableName, true);
+					modal.modal('hide');
+				});
+			}).on('hidden.bs.modal', function(e) {
+				$(e.currentTarget).remove();
+			});
+			return false;
+		});
+	};
+
+	unregisterPageEvents = function() {
+		if (jqueryMap.$tableInfoHolder) {
+			jqueryMap.$tableInfoHolder.off();
+		}
+	};
+
+	updateActivityIndicators = function() {
+		var clusters = blurconsole.model.tables.getClusters();
+
+		$.each(clusters, function(i, cluster) {
+			var clusterHasActivity = false,
+				tables = blurconsole.model.tables.getEnabledTables(cluster);
+
+			$.each(tables, function(i, table){
+				if (blurconsole.model.queries.tableHasActivity(table.name)) {
+					clusterHasActivity = true;
+					$('i[data-table="' + table.name + '"]').show();
+				} else {
+					$('i[data-table="' + table.name + '"]').hide();
+				}
+			});
+
+			if (clusterHasActivity) {
+				$('a[href="#' + cluster +'_pane"] i').show();
+			} else {
+				$('a[href="#' + cluster +'_pane"] i').hide();
+			}
+		});
+	};
+
+	return {
+		initModule : initModule,
+		unloadModule : unloadModule
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/blurconsole.utils.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/blurconsole.utils.js b/contrib/blur-console/src/main/webapp/js/blurconsole.utils.js
new file mode 100644
index 0000000..216079c
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/blurconsole.utils.js
@@ -0,0 +1,91 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+/*global blurconsole:false */
+blurconsole.utils = (function(){
+	'use strict';
+	var inject, unique, equals, keys, findFamilies, reject;
+
+	inject = function(collection, initial, block) {
+		if (collection === null || collection.length === 0) {
+			return initial;
+		}
+
+		var accumulator = initial || collection[0];
+		$.each(collection, function(idx, item) {
+			accumulator = block(accumulator, item);
+		});
+
+		return accumulator;
+	};
+
+	unique = function(collection, sort) {
+		var uniqueList = [];
+
+		$.each(collection, function(idx, item){
+			if (uniqueList.indexOf(item) === -1) {
+				uniqueList.push(item);
+			}
+		});
+
+		if (sort) {
+			uniqueList.sort();
+		}
+
+		return uniqueList;
+	};
+
+	equals = function(obj1, obj2) {
+		return JSON.stringify(obj1) === JSON.stringify(obj2);
+	};
+
+	keys = function(map) {
+		return $.map(map, function(v, key){ return key; });
+	};
+
+	findFamilies = function(query) {
+		// Determine regex to find column families in lucene query
+		var matches = query.match(/[^ \(\)\+\-]+(\w+)\.\w+:/g);
+		var families = [];
+		$.each(matches, function(idx, match) {
+			families.push(match.split('.')[0]);
+		});
+		return families;
+	};
+
+	reject = function(collection, block) {
+		var newArray = [];
+		$.each(collection, function(i, item){
+			if (!block(item)) {
+				newArray.push(item);
+			}
+		});
+		return newArray;
+	};
+
+	return {
+		inject: inject,
+		reduce: inject,
+		unique: unique,
+		equals: equals,
+		keys: keys,
+		findFamilies: findFamilies,
+		reject: reject
+	};
+}());
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/utils/jquery.event.gevent.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/utils/jquery.event.gevent.js b/contrib/blur-console/src/main/webapp/js/utils/jquery.event.gevent.js
new file mode 100755
index 0000000..db78a3b
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/utils/jquery.event.gevent.js
@@ -0,0 +1,140 @@
+/*
+ * jQuery global custom event plugin (gevent)
+ *
+ * Copyright (c) 2013 Michael S. Mikowski
+ * (mike[dot]mikowski[at]gmail[dotcom])
+ *
+ * Dual licensed under the MIT or GPL Version 2
+ * http://jquery.org/license
+ *
+ * Versions
+ *  0.1.5 - initial release
+ *  0.1.6 - enhanced publishEvent (publish) method pass
+ *          a non-array variable as the second argument
+ *          to a subscribed function (the first argument
+ *          is always the event object).
+ *  0.1.7-10
+ *        - documentation changes
+ *
+*/
+
+/*jslint         browser : true, continue : true,
+  devel  : true, indent  : 2,    maxerr   : 50,
+  newcap : true, nomen   : true, plusplus : true,
+  regexp : true, sloppy  : true, vars     : false,
+  white  : true
+*/
+/*global jQuery */
+
+(function ( $ ) {
+  'use strict';
+  $.gevent = ( function () {
+    //---------------- BEGIN MODULE SCOPE VARIABLES --------------
+    var
+      subscribeEvent, publishEvent, unsubscribeEvent,
+      $customSubMap = {}
+      ;
+    //----------------- END MODULE SCOPE VARIABLES ---------------
+
+    //------------------- BEGIN PUBLIC METHODS -------------------
+    // BEGIN public method /publishEvent/
+    // Example  :
+    //   $.gevent.publish(
+    //     'spa-model-msg-receive',
+    //     [ { user : 'fred', msg : 'Hi gang' } ]
+    //   );
+    // Purpose  :
+    //   Publish an event with an optional list of arguments
+    //   which a subscribed handler will receive after the event object.
+    // Arguments (positional)
+    //   * 0 ( event_name )  - The global event name
+    //   * 2 ( data )        - Optional data to be passed as argument(s)
+    //                         to subscribed functions after the event
+    //                         object. Provide an array for multiple
+    //                         arguments.
+    // Throws   : none
+    // Returns  : none
+    //
+    publishEvent = function ( event_name, data ) {
+      var data_list;
+
+      if ( ! $customSubMap[ event_name ] ){ return false; }
+
+      if ( data ){
+        data_list = Array.isArray( data ) ? data : [ data ];
+        $customSubMap[ event_name ].trigger( event_name, data_list );
+        return true;
+      }
+
+      $customSubMap[ event_name ].trigger( event_name );
+      return true;
+    };
+    // END public method /publishEvent/
+
+    // BEGIN public method /subscribeEvent/
+    // Example  :
+    //   $.gevent.subscribe(
+    //     $( '#msg' ),
+    //     'spa-msg-receive',
+    //     onModelMsgReceive
+    //   );
+    // Purpose  :
+    //   Subscribe a function to a published event on a jQuery collection
+    // Arguments (positional)
+    //   * 0 ( $collection ) - The jQuery collection on which to bind event
+    //   * 1 ( event_name )  - The global event name
+    //   * 2 ( fn ) - The function to bound to the event on the collection
+    // Throws   : none
+    // Returns  : none
+    //
+    subscribeEvent = function ( $collection, event_name, fn ) {
+      $collection.on( event_name, fn );
+
+      if ( ! $customSubMap[ event_name ] ) {
+        $customSubMap[ event_name ] = $collection;
+      }
+      else {
+        $customSubMap[ event_name ]
+          = $customSubMap[ event_name ].add( $collection );
+      }
+    };
+    // END public method /subscribeEvent/
+
+    // BEGIN public method /unsubscribeEvent/
+    // Example  :
+    //   $.gevent.unsubscribe(
+    //     $( '#msg' ),
+    //     'spa-model-msg-receive'
+    //   );
+    // Purpose  :
+    //   Remove a binding for the named event on a provided collection
+    // Arguments (positional)
+    //   * 0 ( $collection ) - The jQuery collection on which to bind event
+    //   * 1 ( event_name )  - The global event name
+    // Throws   : none
+    // Returns  : none
+    //
+    unsubscribeEvent = function ( $collection, event_name ) {
+      if ( ! $customSubMap[ event_name ] ){ return false; }
+
+      $customSubMap[ event_name ]
+        = $customSubMap[ event_name ].not( $collection );
+
+      if ( $customSubMap[ event_name ].length === 0 ){
+        delete $customSubMap[ event_name ];
+      }
+
+      return true;
+    };
+    // END public method /unsubscribeEvent/
+    //------------------- END PUBLIC METHODS ---------------------
+
+    // return public methods
+    return {
+      publish     : publishEvent,
+      subscribe   : subscribeEvent,
+      unsubscribe : unsubscribeEvent
+    };
+  }());
+}( jQuery ));
+

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/js/utils/jquery.uriAnchor.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/js/utils/jquery.uriAnchor.js b/contrib/blur-console/src/main/webapp/js/utils/jquery.uriAnchor.js
new file mode 100755
index 0000000..9060ea1
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/js/utils/jquery.uriAnchor.js
@@ -0,0 +1,518 @@
+/*
+ * Jquery plugin for state managment through the URI anchor (hash fragment)
+ *
+ * Copyright (c) 2013 Michael S. Mikowski
+ * (mike[dot]mikowski[at]gmail[dotcom])
+ *
+ * Dual licensed under the MIT or GPL Version 2
+ * http://jquery.org/license
+ *
+ * Versions
+ *  1.1.1-3 - Initial jQuery plugin site releases
+ *
+*/
+
+/*jslint         browser : true, continue : true,
+  devel  : true, indent  : 2,    maxerr   : 50,
+  newcap : true, nomen   : true, plusplus : true,
+  regexp : true, sloppy  : true, vars     : false,
+  white  : true
+*/
+
+/*global jQuery */
+
+(function ($) {
+  $.uriAnchor = ( function ( ) {
+    //---------------- BEGIN MODULE SCOPE VARIABLES --------------
+    var
+      configMap = {
+        regex_anchor_clean1 : /^[#!]*/,
+        regex_anchor_clean2 : /\?[^?]*$/,
+        settable_map_key    : { schema_map : true },
+        schema_map          : null
+      },
+
+      getErrorReject,   getVarType,       getCleanAnchorString,
+      parseStringToMap, makeAnchorString, setAnchor,
+      makeAnchorMap,    configModule
+      ;
+    //----------------- END MODULE SCOPE VARIABLES ---------------
+
+    //------------------- BEGIN UTILITY METHODS ------------------
+    getErrorReject = function ( message  ) {
+      var error     = new Error();
+      error.name    = 'Anchor Schema Reject';
+      error.message = message;
+      return error;
+    };
+
+    // Begin public method /getVarType/
+    // Returns 'Object', 'Array', 'String', 'Number', 'Boolean', 'Undefined'
+    getVarType = function ( data  ) {
+      if ( data === undefined  ) { return 'Undefined'; }
+      if ( data === null  ) { return 'Null'; }
+      return {}.toString.call( data ).slice( 8, -1 );
+    };
+    // End public method /getVarType/
+
+    // Begin internal utility to clean bookmark
+    getCleanAnchorString = function () {
+      return String( document.location.hash )
+        // remove any leading pounds or bangs
+        .replace( configMap.regex_anchor_clean1 , '' )
+        // snip off after question-mark ( a ClickStreet bug )
+        .replace( configMap.regex_anchor_clean2 , '' )
+        ;
+    };
+    // End internal utility to clean bookmark
+
+    // Begin internal utility /parseStringToMap/
+    parseStringToMap = function ( arg_map  ) {
+      var
+        input_string    = arg_map.input_string    || '',
+        delimit_char    = arg_map.delimit_char    || '&',
+        delimit_kv_char = arg_map.delimit_kv_char || '=',
+        output_map      = {},
+
+        splitter_array, i, key_val_array
+        ;
+
+      splitter_array = input_string.split( delimit_char );
+
+      for ( i = 0; i < splitter_array.length; i++  ) {
+        key_val_array = splitter_array[i].split( delimit_kv_char );
+
+        if ( key_val_array.length === 1  ) {
+          output_map[decodeURIComponent( key_val_array[0] )] = true;
+        }
+        else if ( key_val_array.length === 2  ) {
+          output_map[decodeURIComponent( key_val_array[0] )]
+            = decodeURIComponent( key_val_array[1] )
+            ;
+        }
+      }
+      return output_map;
+    };
+    // End internal utility /parseStringToMap/
+
+    // Begin utility /makeAnchorString/
+    // -- all the heavy lifting for setAnchor ( see below )
+    // Converts a map into the anchor component as described
+    // in setAnchor
+    makeAnchorString = function ( anchor_map_in, option_map_in  ) {
+      var
+        anchor_map          = anchor_map_in || {},
+        option_map          = option_map_in || {},
+        delimit_char        = option_map.delimit_char        || '&',
+        delimit_kv_char     = option_map.delimit_kv_char     || '=',
+        sub_delimit_char    = option_map.sub_delimit_char    || ':',
+        dep_delimit_char    = option_map.dep_delimit_char    || '|',
+        dep_kv_delimit_char = option_map.dep_kv_delimit_char || ',',
+        schema_map         = configMap.schema_map,
+        key_val_array       = [],
+
+        schema_map_val, schema_map_dep, schema_map_dep_val,
+        key_name, key_value, class_name, output_kv_string,
+        sub_key_name, dep_map, dep_key_name, dep_key_value,
+        dep_class_name,
+
+        dep_kv_array
+        ;
+
+      if ( getVarType( anchor_map ) !== 'Object' ) {
+        return false;
+      }
+
+      for ( key_name in anchor_map  ) {
+        // filter out inherited properties
+        if ( anchor_map.hasOwnProperty( key_name ) ) {
+
+          // skip empty and dependent keys
+          if ( ! key_name  ) { continue;}
+          if ( key_name.indexOf( '_' ) === 0 ) { continue;}
+
+          // check against anchor schema if provided
+          if ( schema_map  ) {
+            if ( ! schema_map[key_name] ) {
+              throw getErrorReject(
+                'Independent key |'
+                + key_name + '| not authorized by anchor schema'
+              );
+            }
+          }
+
+          output_kv_string   = '';
+          key_value   = anchor_map[key_name];
+
+          if ( key_value === undefined ) { key_value = ''; }
+
+          class_name = getVarType( key_value  );
+
+          // check against anchor schema map of allowable
+          // values is provided
+          if ( schema_map  ) {
+            schema_map_val = schema_map[key_name];
+            if ( getVarType( schema_map_val ) === 'Object'
+              && ! schema_map_val[String( key_value )]
+            ) {
+              throw getErrorReject(
+                'Independent key-value pair |'
+                + key_name + '|' + String( key_value )
+                + '| not authorized by anchor schema'
+              );
+            }
+          }
+
+          // Booleans, we skip false
+          if ( class_name === 'Boolean'  ) {
+            if ( key_value ) { output_kv_string += encodeURIComponent( key_name ); }
+          }
+          // String and Number
+          else {
+             output_kv_string
+                += encodeURIComponent( key_name )
+                +  delimit_kv_char
+                +  encodeURIComponent( key_value )
+                ;
+          }
+
+          sub_key_name = '_' + key_name;
+          if ( anchor_map.hasOwnProperty( sub_key_name ) ) {
+            dep_map      = anchor_map[sub_key_name];
+            dep_kv_array = [];
+
+            if ( schema_map  ) {
+              schema_map_dep = schema_map[sub_key_name];
+              if ( ! schema_map_dep  ) {
+                throw getErrorReject(
+                  'Dependent key |' + sub_key_name
+                  + '| not authorized by anchor schema'
+                );
+              }
+            }
+            else {
+              schema_map_dep = null;
+            }
+
+            for ( dep_key_name in dep_map  ) {
+              if ( dep_map.hasOwnProperty( dep_key_name ) ) {
+                dep_key_value = dep_map[dep_key_name];
+                dep_class_name = getVarType( dep_key_value  );
+
+                if ( schema_map_dep  ) {
+                  schema_map_dep_val = schema_map_dep[dep_key_name];
+                  if ( getVarType( schema_map_dep_val ) === 'Object'
+                    && ! schema_map_dep_val[String( dep_key_value )]
+                  ) {
+                    throw getErrorReject(
+                      'Dependent key-value pair |'
+                      + dep_key_name + '|' + String( dep_key_value )
+                      + '| not authorized by anchor schema'
+                    );
+                  }
+                }
+
+                // Booleans, we skip false
+                if ( class_name === 'Boolean'  ) {
+                  if ( dep_key_value === true  ) {
+                    dep_kv_array.push( encodeURIComponent( dep_key_name ));
+                  }
+                }
+                // String and Number
+                else {
+                  dep_kv_array.push(
+                    encodeURIComponent( dep_key_name )
+                    + dep_kv_delimit_char
+                    + encodeURIComponent( dep_key_value )
+                  );
+                }
+              }
+            }
+            // append dependent arguments if there are any
+            if ( dep_kv_array.length > 0  ) {
+              output_kv_string
+                += sub_delimit_char + dep_kv_array.join( dep_delimit_char )
+              ;
+            }
+          }
+          key_val_array.push( output_kv_string );
+        }
+      }
+
+      return key_val_array.join( delimit_char );
+    };
+    // End utility /makeAnchorString/
+    //-------------------- END UTILITY METHODS -------------------
+
+    //------------------- BEGIN PUBLIC METHODS -------------------
+    // Begin public method /setAnchor/
+    // Purpose     :
+    //   Sets Anchor component of the URI from a Map
+    //   (The Anchor component is also known as the
+    //   'hash fragment' or 'bookmark component')
+    // Arguments  : positional -
+    //   * 1 ( anchor_map )   : The map to be encoded to the URI anchor
+    //   * 2 ( option_map )   : map of options
+    //   * 3 ( replace_flag )  : boolean flag to replace the URI
+    //     When true, the URI is replaced, which means the prior URI
+    //     is not entered into the browser history
+    // Environment : Expects the document.location browser object
+    // Settings    : none
+    // Returns     : boolean: true on success, false on failure
+    // Throws      : none
+    // Discussion  :
+    //
+    //  The first positional argument, anchor_map, may be a simple map:
+    //    $.uriAnchor.setAnchor({
+    //      page   : 'profile',
+    //      slider : 'confirm',
+    //      color  : 'red'
+    //    });
+    //
+    //  This changes the URI anchor to:
+    //     #!page=profile&slider=confirm&color=red
+    //
+    //  All these arguments are independent, that is, they can vary
+    //  independent of each other. We also support dependent values -
+    //  values that depend on others.
+    //
+    //  An independent argument key has no '_' prefix.  The same key name,
+    //  prefixed by an '_', holds the arguments that are dependent on
+    //  an independent argument.  The dependent key always points
+    //  to a map.  Consider:
+    //
+    //    $.uriAnchor.setAnchor({
+    //      page   : 'profile',
+    //      _page  : {
+    //        uname   : 'wendy',
+    //        online  : 'today'
+    //      }
+    //    });
+    //
+    //  This changes the URI Anchor to:
+    //    #!page=profile:uname,wendy|online,today
+    //
+    //  Only independent keys and their matching dependent keys are
+    //  processed.  All other keys are ignored.  Importantly, this includes
+    //  keys of the form _s_/key/ ( e.g. '_s_page' ) returned by makeAnchorMap
+    //
+    //  Setting a more complex anchor map is illustrated below:
+    //    $.uriAnchor.setAnchor({
+    //      page : 'profile',
+    //      _page : {
+    //        uname   : 'wendy',
+    //        online  : 'today'
+    //      },
+    //      slider  : 'confirm',
+    //      _slider : {
+    //       text   : 'hello',
+    //       pretty : false
+    //      },
+    //      color : 'red'
+    //    });
+    //
+    //  This sets the URI Anchor to:
+    //     #!page=profile:uname,wendy|online,today&slider=confirm:text,hello\
+    //       |pretty,false&color=red
+    //
+    //   Options: The second positional argument tp this method, option_map,
+    //   provides a number of options for delimiters:
+    //     * delimit_char     : delimiter independent args
+    //       Defaults to '&'
+    //     * delimit_kv_char  : delimiter key-value of independent args
+    //       Defaults to '='
+    //     * sub_delimit_char : delimiter independent and dependent args
+    //       Defaults to ':'
+    //     * dep_delimit_char : delimiter between key-value of dependent args
+    //       Defaults to '|'
+    //     * dep_kv_delimit_char : key-value delimiter for dependent args.
+    //       Defaults to ','
+    //
+    //   Boolean values ( as part of a key-value pair ) are convert into
+    //     the stings 'true' or 'false'.
+    //
+    //  Validation:
+    //
+    //  As of 1.0, the ability to optionally check the validity of the
+    //  Anchor against a schema has been included.  Since we don't expect
+    //  the allowable schema to change during run-time, we use a
+    //  module configuration to set the schema, like so:
+    //
+    //    $uriAnchor.configModule({
+    //      schema_map : {
+    //        page    : { profile : true, pdf : true },
+    //        _page   : {
+    //          uname   : true,
+    //          online  : { 'today','yesterday','earlier' }
+    //        },
+    //        slider  : { confirm : 'deny' },
+    //        _slider : { text : 'goodbye' },
+    //        color   : { red : true, green : true, blue : true }
+    //      }
+    //    });
+    //
+    //  This check occurs only during setting of the Anchor, not
+    //  during its parsing ( See makeAnchorMap )
+    //
+    //  The replace_flag instructs the routine to replace the uri,
+    //  discarding browser history
+    //
+    setAnchor = function ( anchor_map, option_map, replace_flag  ) {
+      var
+        anchor_string = makeAnchorString( anchor_map, option_map  ),
+        uri_array, uri_string
+        ;
+
+      uri_array = document.location.href.split( '#',2 );
+      uri_string = anchor_string
+        ? uri_array[0] + '#!' + anchor_string : uri_array[0]
+        ;
+
+      if ( replace_flag  ) {
+        if ( anchor_string  ) {
+          document.location.replace( uri_array[0] + '#!' + anchor_string );
+        }
+        else {
+          document.location.replace( uri_array[0] );
+        }
+        return true;
+      }
+      // we replace the full href so that jquery recognizes the uri
+      // change
+      document.location.href = uri_string;
+    };
+    // End public method /setAnchor/
+
+    // Begin public method /makeAnchorMap/
+    // Purpose     : Parses URI anchor and returns as map
+    // Arguments  : none
+    // Environment : Expects the document.location browser object
+    // Settings    : none
+    // Returns     : Map
+    // Throws      : none
+    //
+    // Discussion :
+    //   Parses the browser URI anchor into a map using the same
+    //   rules used to set the anchor in the method setAnchor
+    //   ( see above ).
+    //
+    //   This method creates an additional key type, _s_<indendent_arg>
+    //   for each independent argument with dependent arguments.
+    //
+    //   These keys point to a string representation of the independent
+    //   argument along with all its dependent arguments.
+    //
+    //   These values are ignored by setAnchor, but they are useful
+    //   for routines using setAnchor to check if a part of the anchor
+    //   has changed.
+    //
+    // Example:
+    //   If the browser URI Anchor looks like this:
+    //     #!page=profile:uname,wendy|online,true&slider=confirm:text,hello\
+    //     |pretty,false&color=red
+    //
+    //   Then calling $.uriAnchor.makeAnchorMap();
+    //   will return a map that looks like so:
+    //
+    //     { page : 'profile',
+    //       _page : {
+    //         uname   : 'wendy',
+    //         online  : 'today'
+    //       },
+    //       _s_page : 'profile:uname,wendy|online,today',
+    //       slider  : 'confirm',
+    //       _slider : {
+    //        text   : 'hello',
+    //        pretty : false
+    //       },
+    //       _s_slider : 'confirm:text,hello|pretty,false',
+    //       color : 'red'
+    //     };
+    //
+
+    makeAnchorMap = function () {
+      var
+        anchor_string = getCleanAnchorString(),
+        anchor_map, idx, keys_array, key_name, key_value, dep_array
+        ;
+
+      if ( anchor_string === ''  ) { return {}; }
+
+      // first pass decompose
+      anchor_map = parseStringToMap({
+        input_string     : anchor_string,
+        delimit_char     : '&',
+        delimit_kv_char  : '='
+      });
+
+      // extract keys to prevent run-away recursion when
+      // adding keys to anchor_map, below
+      keys_array = [];
+      for ( key_name in anchor_map  ) {
+        if ( anchor_map.hasOwnProperty( key_name ) ) {
+          keys_array.push( key_name );
+        }
+      }
+
+      for ( idx = 0; idx < keys_array.length; idx++  ) {
+        key_name  = keys_array[idx];
+        key_value = anchor_map[key_name];
+
+        if ( getVarType( key_value ) !== 'String' || key_name === ''
+        ) { continue; }
+
+        // include string representation with all dependent keys and values
+        anchor_map[ '_s_' + key_name ] = key_value;
+
+        dep_array = key_value.split( ':' );
+
+        if ( dep_array[1] && dep_array[1] !== '' ) {
+          anchor_map[key_name] = dep_array[0];
+
+          anchor_map[ '_' + key_name ] = parseStringToMap({
+            input_string    : dep_array[1],
+            delimit_char    : '|',
+            delimit_kv_char : ','
+          });
+        }
+      }
+      return anchor_map;
+    };
+    // End public method /makeAnchorMap/
+
+    // Begin public method /configModule/
+    // Set configuration options
+    configModule = function ( arg_map  ) {
+      var
+        settable_map = configMap.settable_map_key,
+        key_name, error
+        ;
+
+      for ( key_name in arg_map ) {
+        if ( arg_map.hasOwnProperty( key_name )) {
+          if ( settable_map.hasOwnProperty( key_name )) {
+            configMap[key_name] = arg_map[key_name];
+          }
+          else {
+            error         = new Error();
+            error.name    = 'Bad Input';
+            error.message = 'Setting config key |'
+              + key_name + '| is not supported';
+            throw error;
+          }
+        }
+      }
+    };
+    // End public method /configModule/
+
+    // return public methods
+    return {
+      configModule     : configModule,
+      getVarType       : getVarType,
+      makeAnchorMap   : makeAnchorMap,
+      makeAnchorString : makeAnchorString,
+      setAnchor        : setAnchor
+    };
+    //------------------- END PUBLIC METHODS ---------------------
+  }());
+} ( jQuery ));

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/karma.conf.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/karma.conf.js b/contrib/blur-console/src/main/webapp/karma.conf.js
new file mode 100644
index 0000000..8d5d69b
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/karma.conf.js
@@ -0,0 +1,85 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+
+module.exports = function(config) {
+    // karma start --coverage [coverageType]
+    // http://karma-runner.github.io/0.8/config/converage.html
+
+    var karmaConfig = {
+        basePath: '',
+        frameworks: ['mocha'],
+        files: [
+            // Source
+            {pattern: 'js/**/*.js', included: false},
+
+            // Images
+            {pattern: 'img/**/*.*', included: false},
+
+            // Included libs
+            'libs/jquery/jquery.js',
+
+            // Libraries
+            {pattern: 'libs/**/*.js', included: false},
+
+            // Test Files
+            {pattern: 'test/unit/spec/**/*.js', included: false},
+
+            // Test Mocks
+            {pattern: 'test/unit/mocks/**/*.js', included: false},
+            {pattern: 'test/unit/utils/**/*.js', included: false},
+
+            // Test Runner
+            'test/unit/runner/testRunner.js'
+        ],
+        exclude: [],
+        reporters: ['dots'],
+        port: 9876,
+        colors: true,
+        logLevel: config.LOG_WARN,
+        autoWatch: true,
+        browsers: ['Chrome', 'Firefox'],
+        captureTimeout: 60000,
+        singleRun: false
+    },
+    coverageType = 'html',
+    coverage = process.argv.filter(function(a, index) {
+        if (a == '--coverage') {
+            if ((index + 1) < process.argv.length) {
+                coverageType = process.argv[index + 1];
+            }
+            return true;
+        }
+        return false;
+    }).length;
+
+    if (coverage) {
+        karmaConfig.preprocessors = {
+            'js/*.js': 'coverage',
+            'js/**/*.js': 'coverage'
+        };
+        karmaConfig.reporters.push('coverage');
+        karmaConfig.coverageReporter = {
+            type: coverageType,
+            dir: 'build/coverage/'
+        };
+    }
+
+    config.set(karmaConfig);
+};

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/package.json
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/package.json b/contrib/blur-console/src/main/webapp/package.json
new file mode 100644
index 0000000..fdfa815
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/package.json
@@ -0,0 +1,44 @@
+{
+  "name": "blur-console",
+  "version": "2.0.0",
+  "description": "Managment and Monitoring Console for Apache Blur",
+  "main": "karma.conf.js",
+  "repository": "https://git-wip-us.apache.org/repos/asf/incubator-blur.git",
+  "directories": {
+    "test": "test"
+  },
+  "dependencies": {},
+  "devDependencies": {
+    "grunt": "~0.4.1",
+    "grunt-bower-task": "~0.3.4",
+    "grunt-contrib-clean": "~0.5.0",
+    "grunt-contrib-jshint": "~0.8.0",
+    "grunt-contrib-sass": "~0.4.0",
+    "grunt-contrib-watch": "~0.6.1",
+    "grunt-exec": "~0.4.2",
+    "grunt-karma": "~0.8.2",
+    "grunt-mocha-selenium": "git://github.com/jharwig/grunt-mocha-selenium",
+    "grunt-notify": "~0.2.20",
+    "jshint": "~2.3.0",
+    "karma": "~0.12.1",
+    "karma-chrome-launcher": "~0.1.2",
+    "karma-coverage": "~0.2.1",
+    "karma-firefox-launcher": "~0.1.3",
+    "karma-mocha": "~0.1.3",
+    "karma-mocha-reporter": "~0.2.2",
+    "karma-osx-reporter": "~0.0.4",
+    "karma-phantomjs-launcher": "~0.1.2",
+    "karma-script-launcher": "~0.1.0",
+    "load-grunt-tasks": "~0.2.0",
+    "time-grunt": "~0.2.0",
+    "grunt-contrib-connect": "~0.5.0"
+  },
+  "scripts": {
+    "test": "karma start --single-run"
+  },
+  "author": "",
+  "license": "Apache 2.0",
+  "engines": {
+    "node": ">=0.8.0"
+  }
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/sass/_colors.scss
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/sass/_colors.scss b/contrib/blur-console/src/main/webapp/sass/_colors.scss
new file mode 100644
index 0000000..fe5ed23
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/sass/_colors.scss
@@ -0,0 +1,24 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ */
+
+$silver: #CCC;
+$black: #000;
+$san-marino: #4c66a4;
+$white: #FFF;
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/sass/blurconsole.dashboard.scss
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/sass/blurconsole.dashboard.scss b/contrib/blur-console/src/main/webapp/sass/blurconsole.dashboard.scss
new file mode 100644
index 0000000..1b583ec
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/sass/blurconsole.dashboard.scss
@@ -0,0 +1,50 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ */
+.simple-chart {
+	min-height : 200px;
+	min-width : 200px;
+	max-height : 300px;
+	max-width : 300px;
+	margin-left : auto;
+	margin-right : auto;
+}
+
+.wide-chart {
+	min-height : 100px;
+	min-width : 200px;
+	max-height : 200px;
+	max-width : 1000px;
+	margin-left : auto;
+	margin-right : auto;
+}
+
+.swapper-trigger {
+	cursor : pointer;
+}
+
+.swapper-info {
+	min-height : 200px;
+	min-width : 200px;
+	max-height : 300px;
+	max-width : 300px;
+	margin-left : auto;
+	margin-right : auto;
+	overflow: auto;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/sass/blurconsole.queries.scss
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/sass/blurconsole.queries.scss b/contrib/blur-console/src/main/webapp/sass/blurconsole.queries.scss
new file mode 100644
index 0000000..e473517
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/sass/blurconsole.queries.scss
@@ -0,0 +1,22 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+
+#filterOptions {
+	margin-bottom: 5px;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/sass/blurconsole.schema.scss
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/sass/blurconsole.schema.scss b/contrib/blur-console/src/main/webapp/sass/blurconsole.schema.scss
new file mode 100644
index 0000000..5036569
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/sass/blurconsole.schema.scss
@@ -0,0 +1,38 @@
+/*
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+.modal .schemaColumnDef {
+	display: none;
+	&.in {
+		display: block;
+	}
+	strong {
+		width: 140px;
+		display: inline-block;
+	}
+}
+
+.modal .schemaColumnTerms {
+	display: none;
+	.termList {
+		margin-top: 5px;
+		.searchTrigger {
+			cursor: pointer;
+		}
+	}
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/sass/blurconsole.scss
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/sass/blurconsole.scss b/contrib/blur-console/src/main/webapp/sass/blurconsole.scss
new file mode 100644
index 0000000..70fa5d7
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/sass/blurconsole.scss
@@ -0,0 +1,30 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ */
+
+$icon-font-path: "/libs/twbs-bootstrap-sass/vendor/assets/fonts/bootstrap/";
+
+@import 'twbs-bootstrap-sass/vendor/assets/stylesheets/bootstrap';
+@import 'colors';
+@import 'blurconsole.shell';
+@import 'blurconsole.dashboard';
+@import 'blurconsole.schema';
+@import 'blurconsole.queries';
+@import 'blurconsole.search';
+

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/sass/blurconsole.search.scss
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/sass/blurconsole.search.scss b/contrib/blur-console/src/main/webapp/sass/blurconsole.search.scss
new file mode 100644
index 0000000..2cffc29
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/sass/blurconsole.search.scss
@@ -0,0 +1,31 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ */
+
+#results {
+	.panel-collapse {
+		padding: 5px;
+		overflow-x: auto;
+	}
+}
+
+#resultCount {
+	padding-left: 30px;
+	font-style: italic;
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/sass/blurconsole.shell.scss
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/sass/blurconsole.shell.scss b/contrib/blur-console/src/main/webapp/sass/blurconsole.shell.scss
new file mode 100644
index 0000000..a258fa4
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/sass/blurconsole.shell.scss
@@ -0,0 +1,75 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ */
+
+.browsehappy {
+    margin: 0.2em 0;
+    background: $silver;
+    color: $black;
+    padding: 0.2em 0;
+}
+
+.input-group-btn > .btn {
+  height: $input-height-base;
+}
+
+/* Space out content a bit */
+body {
+    padding: 70px 10px 20px 50px;
+}
+
+/* Top Navigation */
+nav.navbar-fixed-top {
+    background-color: $san-marino;
+    .navbar-brand {
+        color: $white;
+    }
+}
+
+/* Side Navigation */
+.side-nav {
+    ul {
+        position: fixed !important;
+        width: 40px;
+        overflow-y: hidden;
+        white-space: nowrap;
+        background-color: #232937;
+        height: 100%;
+        top: 50px;
+        left: 0;
+        list-style: none;
+        padding-left: 0;
+        li {
+            position: relative;
+            display: block;
+            a {
+                padding: 10px;
+                color: $silver;
+                margin-right: 0;
+                font-size: 20px;
+                position: relative;
+                display: block;
+                &.active {
+                    background-color: $white;
+                    color: $black;
+                }
+            }
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/test/.bowerrc
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/test/.bowerrc b/contrib/blur-console/src/main/webapp/test/.bowerrc
new file mode 100644
index 0000000..44491d3
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/test/.bowerrc
@@ -0,0 +1,3 @@
+{
+    "directory": "bower_components"
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/test/bower.json
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/test/bower.json b/contrib/blur-console/src/main/webapp/test/bower.json
new file mode 100644
index 0000000..4a7bafd
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/test/bower.json
@@ -0,0 +1,10 @@
+{
+  "name": "ui",
+  "private": true,
+  "dependencies": {
+    "chai": "~1.8.0",
+    "mocha": "~1.14.0",
+    "blanket":"~1.1.5"
+  },
+  "devDependencies": {}
+}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/test/index.html
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/test/index.html b/contrib/blur-console/src/main/webapp/test/index.html
new file mode 100644
index 0000000..569cdc0
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/test/index.html
@@ -0,0 +1,60 @@
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ -->
+<!doctype html>
+<html>
+<head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge">
+    <title>Mocha Spec Runner</title>
+    <link rel="stylesheet" href="bower_components/mocha/mocha.css">
+
+    <script src="bower_components/chai/chai.js"></script>
+    <script src="bower_components/mocha/mocha.js"></script>
+
+    <!-- include source files here... -->
+    <script src="bower_components/jquery/dist/jquery.js"></script>
+    <script src="app/scripts/blurconsole.js"></script>
+    <script src="app/scripts/blurconsole.utils.js"></script>
+
+    <script src="bower_components/blanket/dist/qunit/blanket.js" data-cover-flags="branchTracking" data-cover-only="//scripts/"></script>
+    <script src="../node_modules/grunt-blanket-mocha/support/mocha-blanket.js"></script>
+
+    <script>
+        var assert = chai.assert;
+        var expect = chai.expect;
+        var should = chai.should();
+
+        mocha.setup('bdd');
+
+        if (window.PHANTOMJS) {
+            blanket.options("reporter", "../node_modules/grunt-blanket-mocha/support/grunt-reporter.js");
+        }
+    </script>
+
+    <!-- include spec files here... -->
+    <script src="spec/test.js"></script>
+    <script src="spec/utils.js"></script>
+</head>
+<body>
+    <div id="mocha"></div>
+
+    <script>mocha.run()</script>
+</body>
+</html>

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/test/spec/test.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/test/spec/test.js b/contrib/blur-console/src/main/webapp/test/spec/test.js
new file mode 100644
index 0000000..9ac8df8
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/test/spec/test.js
@@ -0,0 +1,32 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+/* global describe, it */
+
+(function () {
+    'use strict';
+
+    describe('Give it some context', function () {
+        describe('maybe a bit more context here', function () {
+            it('should run here few assertions', function () {
+
+            });
+        });
+    });
+})();

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/test/spec/utils.js
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/test/spec/utils.js b/contrib/blur-console/src/main/webapp/test/spec/utils.js
new file mode 100644
index 0000000..927567d
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/test/spec/utils.js
@@ -0,0 +1,32 @@
+/*
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+*/
+/* global describe, it, assert, blurconsole */
+
+(function () {
+    'use strict';
+
+    describe('Test blurconsole.utils', function () {
+        describe('inject', function () {
+            it('[1,2,3,4,5] should be 15 with simple summing', function () {
+                assert(blurconsole.utils.inject([1,2,3,4,5], 0, function(sum, item){ return sum + item; }));
+            });
+        });
+    });
+})();

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/views/dashboard.tpl.html
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/views/dashboard.tpl.html b/contrib/blur-console/src/main/webapp/views/dashboard.tpl.html
new file mode 100644
index 0000000..0590690
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/views/dashboard.tpl.html
@@ -0,0 +1,61 @@
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ -->
+
+<div id="slow-query-warnings" class="alert alert-danger hidden">
+	<strong>Heads Up!</strong>
+	Queries have been running for longer than a minute.
+</div>
+
+<div class="row">
+	<div class="col-sm-8">
+		<div class="row">
+			<div class="col-sm-6 text-center swapper-parent">
+					<h4>Zookeepers <small><i class="glyphicon glyphicon-retweet swapper-trigger" title="Swap Chart/Info"></i></small></h4>
+					<div id="zookeeperNodes" class="simple-chart swapper-chart"><img src="img/ajax-loader.gif"></div>
+					<div id="zookeeperInfo" class="swapper-info hidden"></div>
+			</div>
+			<div class="col-sm-6 text-center swapper-parent">
+				<h4>Controllers <small><i class="glyphicon glyphicon-retweet swapper-trigger" title="Swap Chart/Info"></i></small></h4>
+				<div id="controllerNodes" class="simple-chart swapper-chart"><img src="img/ajax-loader.gif"></div>
+				<div id="controllerInfo" class="swapper-info hidden"></div>
+			</div>
+		</div>
+		<div class="row">
+			<div class="col-sm-12 text-center">
+				<h4>Query Load</h4>
+				<div id="queryLoad" class="wide-chart"><img src="img/ajax-loader.gif"></div>
+			</div>
+		</div>
+	</div>
+	<div class="col-sm-4">
+		<div class="row">
+			<div class="col-sm-12 text-center">
+				<h4>Shards</h4>
+				<div id="shardNodes"><img src="img/ajax-loader.gif"></div>
+			</div>
+		</div>
+		<div class="row">
+			<div class="col-sm-12 text-center">
+				<h4>Tables</h4>
+				<div id="tableCounts" class="simple-chart"><img src="img/ajax-loader.gif"></div>
+			</div>
+		</div>
+	</div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/views/queries.tpl.html
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/views/queries.tpl.html b/contrib/blur-console/src/main/webapp/views/queries.tpl.html
new file mode 100644
index 0000000..cda6d89
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/views/queries.tpl.html
@@ -0,0 +1,40 @@
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ -->
+<div class="row">
+	<div id="tableHolder" class="col-sm-4">
+
+	</div>
+	<div class="col-sm-8">
+		<div class="row">
+			<div id="filterOptions" class="col-sm-12">
+				<div class="input-group col-sm-4 pull-right">
+					<input class="form-control filterText" placeholder="Filter" type="text">
+					<span class="input-group-btn">
+						<button class="btn btn-default filterTrigger" type="button">Go!</button>
+					</span>
+				</div>
+			</div>
+			<div id="queryHolder" class="col-sm-12">
+
+			</div>
+		</div>
+
+	</div>
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/views/search.tpl.html
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/views/search.tpl.html b/contrib/blur-console/src/main/webapp/views/search.tpl.html
new file mode 100644
index 0000000..3a58fe4
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/views/search.tpl.html
@@ -0,0 +1,50 @@
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ -->
+
+<div id="tableGoneWarning" class="alert alert-warning" style="display:none"><strong>Heads Up!</strong> The table that is currently being used for search is no longer enabled!</div>
+<div class="well">
+	<div class="container-fluid">
+		<div class="row">
+			<div class="col-xs-6">
+				<div class="input-group">
+					<input type="text" class="form-control" placeholder="Query" id="queryField">
+					<span class="input-group-btn">
+	        			<button class="btn btn-default" type="button" id="searchTrigger">Go!</button>
+	      			</span>
+				</div>
+			</div>
+			<div class="col-xs-2">
+				<select class="form-control" id="tableChooser">
+					<option value="" id="statusOption">Loading Tables....</option>
+				</select>
+			</div>
+			<button class="btn btn-default" type="button" id="searchOptionsTrigger">
+				<i class="glyphicon glyphicon-cog"></i>
+			</button>
+			<span id="searchOptionsDisplay"></span>
+		</div>
+		<div class="row">
+			<div id="resultCount" class="col-xs-2"></div>
+		</div>
+	</div>
+</div>
+<div id="results">
+
+</div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/main/webapp/views/tables.tpl.html
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/main/webapp/views/tables.tpl.html b/contrib/blur-console/src/main/webapp/views/tables.tpl.html
new file mode 100644
index 0000000..e950dd3
--- /dev/null
+++ b/contrib/blur-console/src/main/webapp/views/tables.tpl.html
@@ -0,0 +1,20 @@
+<!--
+
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+ -->
+<div id="tableInfoHolder"><img src="img/ajax-loader.gif"></div>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/test/java/org/apache/blur/console/ConsoleTestBase.java
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/test/java/org/apache/blur/console/ConsoleTestBase.java b/contrib/blur-console/src/test/java/org/apache/blur/console/ConsoleTestBase.java
index 4d34fc2..813df6c 100644
--- a/contrib/blur-console/src/test/java/org/apache/blur/console/ConsoleTestBase.java
+++ b/contrib/blur-console/src/test/java/org/apache/blur/console/ConsoleTestBase.java
@@ -29,13 +29,13 @@ import org.junit.BeforeClass;
 public class ConsoleTestBase {
 	protected static MiniCluster cluster;
 	protected static String TABLE_PATH = new File("./test-data/test-tables").getAbsolutePath();
-	
+
 	@BeforeClass
 	public static void startup() {
 		cluster = new MiniCluster();
 		cluster.startBlurCluster(new File("./test-data").getAbsolutePath(), 1, 1);
 	}
-	
+
 	@AfterClass
 	public static void shutdown() throws IOException {
 		cluster.shutdownBlurCluster();
@@ -44,7 +44,7 @@ public class ConsoleTestBase {
 			FileUtils.deleteDirectory(file);
 		}
 	}
-	
+
 	protected void setupConfigIfNeeded() throws IOException {
 		if (Config.getBlurConfig() == null) {
 			Config.setupConfig();

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/src/test/java/org/apache/blur/console/util/HttpUtilTest.java
----------------------------------------------------------------------
diff --git a/contrib/blur-console/src/test/java/org/apache/blur/console/util/HttpUtilTest.java b/contrib/blur-console/src/test/java/org/apache/blur/console/util/HttpUtilTest.java
index 20ef7fd..6985e80 100644
--- a/contrib/blur-console/src/test/java/org/apache/blur/console/util/HttpUtilTest.java
+++ b/contrib/blur-console/src/test/java/org/apache/blur/console/util/HttpUtilTest.java
@@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals;
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.util.Collection;
 import java.util.Locale;
 
 import javax.servlet.ServletOutputStream;
@@ -104,7 +105,7 @@ public class HttpUtilTest {
 		public void flushBuffer() throws IOException {}
 		@Override
 		public void setStatus(int sc, String sm) {}
-		@Override
+        @Override
 		public void setIntHeader(String name, int value) {}
 		@Override
 		public void setHeader(String name, String value) {}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/ui/.bowerrc
----------------------------------------------------------------------
diff --git a/contrib/blur-console/ui/.bowerrc b/contrib/blur-console/ui/.bowerrc
deleted file mode 100644
index ba0accc..0000000
--- a/contrib/blur-console/ui/.bowerrc
+++ /dev/null
@@ -1,3 +0,0 @@
-{
-    "directory": "app/bower_components"
-}

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/ui/.editorconfig
----------------------------------------------------------------------
diff --git a/contrib/blur-console/ui/.editorconfig b/contrib/blur-console/ui/.editorconfig
deleted file mode 100644
index 8a80734..0000000
--- a/contrib/blur-console/ui/.editorconfig
+++ /dev/null
@@ -1,21 +0,0 @@
-# EditorConfig helps developers define and maintain consistent
-# coding styles between different editors and IDEs
-# editorconfig.org
-
-root = true
-
-
-[*]
-
-# Change these settings to your own preference
-indent_style = space
-indent_size = 4
-
-# We recommend you to keep these unchanged
-end_of_line = lf
-charset = utf-8
-trim_trailing_whitespace = true
-insert_final_newline = true
-
-[*.md]
-trim_trailing_whitespace = false

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/ui/.gitattributes
----------------------------------------------------------------------
diff --git a/contrib/blur-console/ui/.gitattributes b/contrib/blur-console/ui/.gitattributes
deleted file mode 100644
index 2125666..0000000
--- a/contrib/blur-console/ui/.gitattributes
+++ /dev/null
@@ -1 +0,0 @@
-* text=auto
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/ui/.gitignore
----------------------------------------------------------------------
diff --git a/contrib/blur-console/ui/.gitignore b/contrib/blur-console/ui/.gitignore
deleted file mode 100644
index 45d0917..0000000
--- a/contrib/blur-console/ui/.gitignore
+++ /dev/null
@@ -1,6 +0,0 @@
-node_modules
-dist
-.tmp
-.sass-cache
-app/bower_components
-test/bower_components

http://git-wip-us.apache.org/repos/asf/incubator-blur/blob/d276fd61/contrib/blur-console/ui/.jshintrc
----------------------------------------------------------------------
diff --git a/contrib/blur-console/ui/.jshintrc b/contrib/blur-console/ui/.jshintrc
deleted file mode 100644
index abc9b0a..0000000
--- a/contrib/blur-console/ui/.jshintrc
+++ /dev/null
@@ -1,21 +0,0 @@
-{
-    "node": true,
-    "browser": true,
-    "esnext": true,
-    "bitwise": true,
-    "camelcase": false,
-    "curly": true,
-    "eqeqeq": true,
-    "immed": true,
-    "indent": 4,
-    "latedef": true,
-    "newcap": true,
-    "noarg": true,
-    "quotmark": "single",
-    "undef": true,
-    "unused": true,
-    "strict": true,
-    "trailing": true,
-    "smarttabs": true,
-    "jquery": true
-}


Mime
View raw message