diff --git a/.gitignore b/.gitignore
index 6f4d056..4f002b6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -35,9 +35,12 @@ circle/*.key
 circle/*.pem
 
 # collected static files:
-circle/static
 circle/static_collected
+circle/bower_components
 
 # jsi18n files
 jsi18n
 scripts.rc
+
+# less
+*.css
diff --git a/circle/bower.json b/circle/bower.json
new file mode 100644
index 0000000..cae36cf
--- /dev/null
+++ b/circle/bower.json
@@ -0,0 +1,23 @@
+{
+  "name": "circle",
+  "version": "0.0.0",
+  "license": "GPL",
+  "private": true,
+  "ignore": [
+    "**/.*",
+    "node_modules",
+    "bower_components",
+    "test",
+    "tests"
+  ],
+  "dependencies": {
+    "bootstrap": "~3.2.0",
+    "fontawesome": "~4.2.0",
+    "jquery": "~2.1.1",
+    "no-vnc": "*",
+    "jquery-knob": "~1.2.9",
+    "jquery-simple-slider": "https://github.com/BME-IK/jquery-simple-slider.git",
+    "bootbox": "~4.3.0",
+    "intro.js": "0.9.0"
+  }
+}
diff --git a/circle/bower_components/.gitkeep b/circle/bower_components/.gitkeep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circle/bower_components/.gitkeep
diff --git a/circle/circle/settings/base.py b/circle/circle/settings/base.py
index 3e7b86e..c51e91c 100644
--- a/circle/circle/settings/base.py
+++ b/circle/circle/settings/base.py
@@ -160,10 +160,88 @@ STATICFILES_FINDERS = (
     'django.contrib.staticfiles.finders.AppDirectoriesFinder',
 )
 ########## END STATIC FILE CONFIGURATION
+STATICFILES_DIRS = [normpath(join(SITE_ROOT, 'bower_components'))]
 
 p = normpath(join(SITE_ROOT, '../../site-circle/static'))
 if exists(p):
-    STATICFILES_DIRS = (p, )
+    STATICFILES_DIRS.append(p)
+
+STATICFILES_STORAGE = 'pipeline.storage.PipelineCachedStorage'
+PIPELINE_COMPILERS = (
+    'pipeline.compilers.less.LessCompiler',
+)
+PIPELINE_CSS_COMPRESSOR = 'pipeline.compressors.yuglify.YuglifyCompressor'
+PIPELINE_JS_COMPRESSOR = 'pipeline.compressors.slimit.SlimItCompressor'
+PIPELINE_DISABLE_WRAPPER = True
+PIPELINE_LESS_ARGUMENTS = u'--include-path={}'.format(':'.join(STATICFILES_DIRS))
+PIPELINE_CSS = {
+    "all": {"source_filenames": (
+        "compile_bootstrap.less",
+        "bootstrap/dist/css/bootstrap-theme.css",
+        "fontawesome/css/font-awesome.css",
+        "jquery-simple-slider/css/simple-slider.css",
+        "intro.js/introjs.css",
+        "template.less",
+        "dashboard/dashboard.less",
+        "network/network.less",
+        "autocomplete_light/style.css",
+    ),
+        "output_filename": "all.css",
+    }
+}
+PIPELINE_JS = {
+    "all": {"source_filenames": (
+        # "jquery/dist/jquery.js",  # included separately
+        "bootbox/bootbox.js",
+        "bootstrap/dist/js/bootstrap.js",
+        "intro.js/intro.js",
+        "jquery-knob/dist/jquery.knob.min.js",
+        "jquery-simple-slider/js/simple-slider.js",
+        "dashboard/dashboard.js",
+        "dashboard/group-details.js",
+        "dashboard/group-list.js",
+        "dashboard/js/stupidtable.min.js",  # no bower file
+        "dashboard/node-create.js",
+        "dashboard/node-details.js",
+        "dashboard/node-list.js",
+        "dashboard/profile.js",
+        "dashboard/store.js",
+        "dashboard/template-list.js",
+        "dashboard/vm-common.js",
+        "dashboard/vm-create.js",
+        "dashboard/vm-list.js",
+        "js/host.js",
+        "js/network.js",
+        "js/switch-port.js",
+        "autocomplete_light/autocomplete.js",
+        "autocomplete_light/widget.js",
+        "autocomplete_light/addanother.js",
+        "autocomplete_light/text_widget.js",
+        "autocomplete_light/remote.js",
+    ),
+        "output_filename": "all.js",
+    },
+    "vm-detail": {"source_filenames": (
+        "dashboard/vm-details.js",
+        "no-vnc/include/util.js",
+        "no-vnc/include/webutil.js",
+        "no-vnc/include/base64.js",
+        "no-vnc/include/websock.js",
+        "no-vnc/include/des.js",
+        "no-vnc/include/keysym.js",
+        "no-vnc/include/keysymdef.js",
+        "no-vnc/include/keyboard.js",
+        "no-vnc/include/input.js",
+        "no-vnc/include/display.js",
+        "no-vnc/include/jsunzip.js",
+        "no-vnc/include/rfb.js",
+        "dashboard/vm-console.js",
+        "dashboard/vm-tour.js",
+    ),
+        "output_filename": "vm-detail.js",
+    },
+}
+
 
 
 ########## SECRET CONFIGURATION
@@ -266,6 +344,7 @@ THIRD_PARTY_APPS = (
     'statici18n',
     'django_sshkey',
     'autocomplete_light',
+    'pipeline',
 )
 
 # Apps specific for this project go here.
diff --git a/circle/circle/settings/local.py b/circle/circle/settings/local.py
index 1d5cb37..dd82156 100644
--- a/circle/circle/settings/local.py
+++ b/circle/circle/settings/local.py
@@ -109,3 +109,7 @@ CRISPY_FAIL_SILENTLY = not DEBUG
 if DEBUG:
     from django.dispatch import Signal
     Signal.send_robust = Signal.send
+
+PIPELINE_DISABLED_COMPILERS = (
+    'pipeline.compilers.less.LessCompiler',
+)
diff --git a/circle/circle/settings/test.py b/circle/circle/settings/test.py
index 7130c42..50ce958 100644
--- a/circle/circle/settings/test.py
+++ b/circle/circle/settings/test.py
@@ -58,3 +58,6 @@ for i in LOCAL_APPS:
     LOGGING['loggers'][i] = {'handlers': ['console'], 'level': level}
 # Forbid store usage
 STORE_URL = ""
+
+# buildbot doesn't love pipeline
+STATICFILES_STORAGE = 'django.contrib.staticfiles.storage.StaticFilesStorage'
diff --git a/circle/common/management/__init__.py b/circle/common/management/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circle/common/management/__init__.py
diff --git a/circle/common/management/commands/__init__.py b/circle/common/management/commands/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/circle/common/management/commands/__init__.py
diff --git a/circle/common/management/commands/compileless.py b/circle/common/management/commands/compileless.py
new file mode 100644
index 0000000..0168974
--- /dev/null
+++ b/circle/common/management/commands/compileless.py
@@ -0,0 +1,11 @@
+from django.core.management.base import BaseCommand
+
+from common.management.commands.watch import LessUtils
+
+
+class Command(BaseCommand):
+    help = "Compiles all LESS files."
+
+    def handle(self, *args, **kwargs):
+        print("Compiling LESS")
+        LessUtils.initial_compile()
diff --git a/circle/common/management/commands/watch.py b/circle/common/management/commands/watch.py
new file mode 100644
index 0000000..e0889a3
--- /dev/null
+++ b/circle/common/management/commands/watch.py
@@ -0,0 +1,86 @@
+import subprocess
+import os
+import pyinotify
+
+from django.core.management.base import BaseCommand
+from django.conf import settings
+
+STATIC_FILES = u'--include-path={}'.format(':'.join(settings.STATICFILES_DIRS))
+IGNORED_FOLDERS = ("static_collected", "bower_components", )
+
+
+class LessUtils(object):
+    @staticmethod
+    def less_path_to_css_path(pathname):
+        return "%s.css" % pathname[:-1 * len(".less")]
+
+    @staticmethod
+    def compile_less(less_pathname, css_pathname):
+        cmd = ["lessc", STATIC_FILES, less_pathname, css_pathname]
+
+        print("\n%s" % ("=" * 30))
+        print("Compiling: %s" % os.path.basename(less_pathname))
+
+        try:
+            subprocess.check_output(cmd)
+        except subprocess.CalledProcessError as e:
+            print(e.output)
+        else:
+            print("Successfully compiled:\n%s\n->\n%s" % (
+                less_pathname, css_pathname))
+
+    @staticmethod
+    def initial_compile():
+        """ Walks through the project looking for LESS files
+        and compiles them into CSS.
+        """
+        for root, dirs, files in os.walk(settings.SITE_ROOT):
+            for f in files:
+                if not f.endswith(".less"):
+                    continue
+
+                relpath = os.path.relpath(root, settings.SITE_ROOT)
+                if relpath.startswith(IGNORED_FOLDERS):
+                    continue
+
+                less_pathname = "%s/%s" % (root, f)
+                css_pathname = LessUtils.less_path_to_css_path(less_pathname)
+                LessUtils.compile_less(less_pathname, css_pathname)
+
+    @staticmethod
+    def start_watch():
+        """ Watches for changes in LESS files recursively from the
+        project's root and compiles the files
+        """
+        wm = pyinotify.WatchManager()
+
+        class EventHandler(pyinotify.ProcessEvent):
+            def process_IN_MODIFY(self, event):
+                if not event.name.endswith(".less"):
+                    return
+
+                relpath = os.path.relpath(event.pathname, settings.SITE_ROOT)
+                if relpath.startswith(IGNORED_FOLDERS):
+                    return
+
+                css_pathname = LessUtils.less_path_to_css_path(event.pathname)
+                LessUtils.compile_less(event.pathname, css_pathname)
+
+        handler = EventHandler()
+        notifier = pyinotify.Notifier(wm, handler)
+        wm.add_watch(settings.SITE_ROOT, pyinotify.IN_MODIFY, rec=True)
+        notifier.loop()
+
+
+class Command(BaseCommand):
+    help = "Compiles all LESS files then watches for changes."
+
+    def handle(self, *args, **kwargs):
+        # for first run compile everything
+        print("Initial LESS compiles")
+        LessUtils.initial_compile()
+        print("\n%s\n" % ("=" * 30))
+        print("End of initial LESS compiles\n")
+
+        # after first run watch less files
+        LessUtils.start_watch()
diff --git a/circle/dashboard/static/compile_bootstrap.less b/circle/dashboard/static/compile_bootstrap.less
new file mode 100644
index 0000000..63f0e12
--- /dev/null
+++ b/circle/dashboard/static/compile_bootstrap.less
@@ -0,0 +1,55 @@
+// Core variables and mixins
+@import "bootstrap/less/variables.less";
+
+// Custom variables
+@navbar-height: 45px;
+
+@import "bootstrap/less/mixins.less";
+
+// Reset and dependencies
+@import "bootstrap/less/normalize.less";
+@import "bootstrap/less/print.less";
+// we don't use these, also they make collectstatic fail ...
+// @import "bootstrap/less/glyphicons.less";
+
+// Core CSS
+@import "bootstrap/less/scaffolding.less";
+@import "bootstrap/less/type.less";
+@import "bootstrap/less/code.less";
+@import "bootstrap/less/grid.less";
+@import "bootstrap/less/tables.less";
+@import "bootstrap/less/forms.less";
+@import "bootstrap/less/buttons.less";
+
+// Components
+@import "bootstrap/less/component-animations.less";
+@import "bootstrap/less/dropdowns.less";
+@import "bootstrap/less/button-groups.less";
+@import "bootstrap/less/input-groups.less";
+@import "bootstrap/less/navs.less";
+@import "bootstrap/less/navbar.less";
+@import "bootstrap/less/breadcrumbs.less";
+@import "bootstrap/less/pagination.less";
+@import "bootstrap/less/pager.less";
+@import "bootstrap/less/labels.less";
+@import "bootstrap/less/badges.less";
+@import "bootstrap/less/jumbotron.less";
+@import "bootstrap/less/thumbnails.less";
+@import "bootstrap/less/alerts.less";
+@import "bootstrap/less/progress-bars.less";
+@import "bootstrap/less/media.less";
+@import "bootstrap/less/list-group.less";
+@import "bootstrap/less/panels.less";
+@import "bootstrap/less/responsive-embed.less";
+@import "bootstrap/less/wells.less";
+@import "bootstrap/less/close.less";
+
+// Components w/ JavaScript
+@import "bootstrap/less/modals.less";
+@import "bootstrap/less/tooltip.less";
+@import "bootstrap/less/popovers.less";
+@import "bootstrap/less/carousel.less";
+
+// Utility classes
+@import "bootstrap/less/utilities.less";
+@import "bootstrap/less/responsive-utilities.less";
diff --git a/circle/dashboard/static/dashboard/bootstrap-slider/bootstrap-slider.js b/circle/dashboard/static/dashboard/bootstrap-slider/bootstrap-slider.js
deleted file mode 100644
index 0e5a433..0000000
--- a/circle/dashboard/static/dashboard/bootstrap-slider/bootstrap-slider.js
+++ /dev/null
@@ -1,391 +0,0 @@
-/* =========================================================
- * bootstrap-slider.js v2.0.0
- * http://www.eyecon.ro/bootstrap-slider
- * =========================================================
- * Copyright 2012 Stefan Petre
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ========================================================= */
- 
-!function( $ ) {
-
-	var Slider = function(element, options) {
-		this.element = $(element);
-		this.picker = $('<div class="slider">'+
-							'<div class="slider-track">'+
-								'<div class="slider-selection"></div>'+
-								'<div class="slider-handle"></div>'+
-								'<div class="slider-handle"></div>'+
-							'</div>'+
-							'<div class="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>'+
-						'</div>')
-							.insertBefore(this.element)
-							.append(this.element);
-		this.id = this.element.data('slider-id')||options.id;
-		if (this.id) {
-			this.picker[0].id = this.id;
-		}
-
-		if (typeof Modernizr !== 'undefined' && Modernizr.touch) {
-			this.touchCapable = true;
-		}
-
-		var tooltip = this.element.data('slider-tooltip')||options.tooltip;
-
-		this.tooltip = this.picker.find('.tooltip');
-		this.tooltipInner = this.tooltip.find('div.tooltip-inner');
-
-		this.orientation = this.element.data('slider-orientation')||options.orientation;
-		switch(this.orientation) {
-			case 'vertical':
-				this.picker.addClass('slider-vertical');
-				this.stylePos = 'top';
-				this.mousePos = 'pageY';
-				this.sizePos = 'offsetHeight';
-				this.tooltip.addClass('right')[0].style.left = '100%';
-				break;
-			default:
-				this.picker
-					.addClass('slider-horizontal')
-					.css('width', this.element.outerWidth());
-				this.orientation = 'horizontal';
-				this.stylePos = 'left';
-				this.mousePos = 'pageX';
-				this.sizePos = 'offsetWidth';
-				this.tooltip.addClass('top')[0].style.top = -this.tooltip.outerHeight() - 14 + 'px';
-				break;
-		}
-
-		this.min = this.element.data('slider-min')||options.min;
-		this.max = this.element.data('slider-max')||options.max;
-		this.step = this.element.data('slider-step')||options.step;
-		this.value = this.element.data('slider-value')||options.value;
-		if (this.value[1]) {
-			this.range = true;
-		}
-
-		this.selection = this.element.data('slider-selection')||options.selection;
-		this.selectionEl = this.picker.find('.slider-selection');
-		if (this.selection === 'none') {
-			this.selectionEl.addClass('hide');
-		}
-		this.selectionElStyle = this.selectionEl[0].style;
-
-
-		this.handle1 = this.picker.find('.slider-handle:first');
-		this.handle1Stype = this.handle1[0].style;
-		this.handle2 = this.picker.find('.slider-handle:last');
-		this.handle2Stype = this.handle2[0].style;
-
-		var handle = this.element.data('slider-handle')||options.handle;
-		switch(handle) {
-			case 'round':
-				this.handle1.addClass('round');
-				this.handle2.addClass('round');
-				break
-			case 'triangle':
-				this.handle1.addClass('triangle');
-				this.handle2.addClass('triangle');
-				break
-		}
-
-		if (this.range) {
-			this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
-			this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
-		} else {
-			this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
-			this.handle2.addClass('hide');
-			if (this.selection == 'after') {
-				this.value[1] = this.max;
-			} else {
-				this.value[1] = this.min;
-			}
-		}
-		this.diff = this.max - this.min;
-		this.percentage = [
-			(this.value[0]-this.min)*100/this.diff,
-			(this.value[1]-this.min)*100/this.diff,
-			this.step*100/this.diff
-		];
-
-		this.offset = this.picker.offset();
-		this.size = this.picker[0][this.sizePos];
-
-		this.formater = options.formater;
-
-		this.layout();
-
-		if (this.touchCapable) {
-			// Touch: Bind touch events:
-			this.picker.on({
-				touchstart: $.proxy(this.mousedown, this)
-			});
-		} else {
-			this.picker.on({
-				mousedown: $.proxy(this.mousedown, this)
-			});
-		}
-
-		if (tooltip === 'show') {
-			this.picker.on({
-				mouseenter: $.proxy(this.showTooltip, this),
-				mouseleave: $.proxy(this.hideTooltip, this)
-			});
-		} else {
-			this.tooltip.addClass('hide');
-		}
-	};
-
-	Slider.prototype = {
-		constructor: Slider,
-
-		over: false,
-		inDrag: false,
-		
-		showTooltip: function(){
-			this.tooltip.addClass('in');
-			//var left = Math.round(this.percent*this.width);
-			//this.tooltip.css('left', left - this.tooltip.outerWidth()/2);
-			this.over = true;
-		},
-		
-		hideTooltip: function(){
-			if (this.inDrag === false) {
-				this.tooltip.removeClass('in');
-			}
-			this.over = false;
-		},
-
-		layout: function(){
-			this.handle1Stype[this.stylePos] = this.percentage[0]+'%';
-			this.handle2Stype[this.stylePos] = this.percentage[1]+'%';
-			if (this.orientation == 'vertical') {
-				this.selectionElStyle.top = Math.min(this.percentage[0], this.percentage[1]) +'%';
-				this.selectionElStyle.height = Math.abs(this.percentage[0] - this.percentage[1]) +'%';
-			} else {
-				this.selectionElStyle.left = Math.min(this.percentage[0], this.percentage[1]) +'%';
-				this.selectionElStyle.width = Math.abs(this.percentage[0] - this.percentage[1]) +'%';
-			}
-			if (this.range) {
-				this.tooltipInner.text(
-					this.formater(this.value[0]) + 
-					' : ' + 
-					this.formater(this.value[1])
-				);
-				this.tooltip[0].style[this.stylePos] = this.size * (this.percentage[0] + (this.percentage[1] - this.percentage[0])/2)/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
-			} else {
-				this.tooltipInner.text(
-					this.formater(this.value[0])
-				);
-				this.tooltip[0].style[this.stylePos] = this.size * this.percentage[0]/100 - (this.orientation === 'vertical' ? this.tooltip.outerHeight()/2 : this.tooltip.outerWidth()/2) +'px';
-			}
-		},
-
-		mousedown: function(ev) {
-                        if (this.element[0].disabled) {
-                            return false;
-                        }
-
-			// Touch: Get the original event:
-			if (this.touchCapable && ev.type === 'touchstart') {
-				ev = ev.originalEvent;
-			}
-
-			this.offset = this.picker.offset();
-			this.size = this.picker[0][this.sizePos];
-
-			var percentage = this.getPercentage(ev);
-
-			if (this.range) {
-				var diff1 = Math.abs(this.percentage[0] - percentage);
-				var diff2 = Math.abs(this.percentage[1] - percentage);
-				this.dragged = (diff1 < diff2) ? 0 : 1;
-			} else {
-				this.dragged = 0;
-			}
-
-			this.percentage[this.dragged] = percentage;
-			this.layout();
-
-			if (this.touchCapable) {
-				// Touch: Bind touch events:
-				$(document).on({
-					touchmove: $.proxy(this.mousemove, this),
-					touchend: $.proxy(this.mouseup, this)
-				});
-			} else {
-				$(document).on({
-					mousemove: $.proxy(this.mousemove, this),
-					mouseup: $.proxy(this.mouseup, this)
-				});
-			}
-
-			this.inDrag = true;
-			var val = this.calculateValue();
-			this.element.trigger({
-					type: 'slideStart',
-					value: val
-				}).trigger({
-					type: 'slide',
-					value: val
-				});
-			return false;
-		},
-
-		mousemove: function(ev) {
-			
-			// Touch: Get the original event:
-			if (this.touchCapable && ev.type === 'touchmove') {
-				ev = ev.originalEvent;
-			}
-
-			var percentage = this.getPercentage(ev);
-			if (this.range) {
-				if (this.dragged === 0 && this.percentage[1] < percentage) {
-					this.percentage[0] = this.percentage[1];
-					this.dragged = 1;
-				} else if (this.dragged === 1 && this.percentage[0] > percentage) {
-					this.percentage[1] = this.percentage[0];
-					this.dragged = 0;
-				}
-			}
-			this.percentage[this.dragged] = percentage;
-			this.layout();
-			var val = this.calculateValue();
-			this.element
-				.trigger({
-					type: 'slide',
-					value: val
-				})
-				.data('value', val)
-				.prop('value', val);
-			return false;
-		},
-
-		mouseup: function(ev) {
-			if (this.touchCapable) {
-				// Touch: Bind touch events:
-				$(document).off({
-					touchmove: this.mousemove,
-					touchend: this.mouseup
-				});
-			} else {
-				$(document).off({
-					mousemove: this.mousemove,
-					mouseup: this.mouseup
-				});
-			}
-
-			this.inDrag = false;
-			if (this.over == false) {
-				this.hideTooltip();
-			}
-			this.element;
-			var val = this.calculateValue();
-			this.element
-				.trigger({
-					type: 'slideStop',
-					value: val
-				})
-				.data('value', val)
-				.prop('value', val);
-			return false;
-		},
-
-		calculateValue: function() {
-			var val;
-			if (this.range) {
-				val = [
-					(this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step),
-					(this.min + Math.round((this.diff * this.percentage[1]/100)/this.step)*this.step)
-				];
-				this.value = val;
-			} else {
-				val = (this.min + Math.round((this.diff * this.percentage[0]/100)/this.step)*this.step);
-				this.value = [val, this.value[1]];
-			}
-			return val;
-		},
-
-		getPercentage: function(ev) {
-			if (this.touchCapable) {
-				ev = ev.touches[0];
-			}
-			var percentage = (ev[this.mousePos] - this.offset[this.stylePos])*100/this.size;
-			percentage = Math.round(percentage/this.percentage[2])*this.percentage[2];
-			return Math.max(0, Math.min(100, percentage));
-		},
-
-		getValue: function() {
-			if (this.range) {
-				return this.value;
-			}
-			return this.value[0];
-		},
-
-		setValue: function(val) {
-			this.value = val;
-
-			if (this.range) {
-				this.value[0] = Math.max(this.min, Math.min(this.max, this.value[0]));
-				this.value[1] = Math.max(this.min, Math.min(this.max, this.value[1]));
-			} else {
-				this.value = [ Math.max(this.min, Math.min(this.max, this.value))];
-				this.handle2.addClass('hide');
-				if (this.selection == 'after') {
-					this.value[1] = this.max;
-				} else {
-					this.value[1] = this.min;
-				}
-			}
-			this.diff = this.max - this.min;
-			this.percentage = [
-				(this.value[0]-this.min)*100/this.diff,
-				(this.value[1]-this.min)*100/this.diff,
-				this.step*100/this.diff
-			];
-			this.layout();
-		}
-	};
-
-	$.fn.slider = function ( option, val ) {
-		return this.each(function () {
-			var $this = $(this),
-				data = $this.data('slider'),
-				options = typeof option === 'object' && option;
-			if (!data)  {
-				$this.data('slider', (data = new Slider(this, $.extend({}, $.fn.slider.defaults,options))));
-			}
-			if (typeof option == 'string') {
-				data[option](val);
-			}
-		})
-	};
-
-	$.fn.slider.defaults = {
-		min: 0,
-		max: 10,
-		step: 1,
-		orientation: 'horizontal',
-		value: 5,
-		selection: 'before',
-		tooltip: 'show',
-		handle: 'round',
-		formater: function(value) {
-			return value;
-		}
-	};
-
-	$.fn.slider.Constructor = Slider;
-
-}( window.jQuery );
\ No newline at end of file
diff --git a/circle/dashboard/static/dashboard/bootstrap-slider/less/slider.less b/circle/dashboard/static/dashboard/bootstrap-slider/less/slider.less
deleted file mode 100644
index 2dc9c85..0000000
--- a/circle/dashboard/static/dashboard/bootstrap-slider/less/slider.less
+++ /dev/null
@@ -1,104 +0,0 @@
-/*!
- * Slider for Bootstrap
- *
- * Copyright 2012 Stefan Petre
- * Licensed under the Apache License v2.0
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- */
-
-.slider {
-	display: inline-block;
-	vertical-align: middle;
-	position: relative;
-	&.slider-horizontal {
-		width: 210px;
-		height: @baseLineHeight;
-		.slider-track {
-			height: @baseLineHeight/2;
-			width: 100%;
-			margin-top: -@baseLineHeight/4;
-			top: 50%;
-			left: 0;
-		}
-		.slider-selection {
-			height: 100%;
-			top: 0;
-			bottom: 0;
-		}
-		.slider-handle {
-			margin-left: -@baseLineHeight/2;
-			margin-top: -@baseLineHeight/4;
-			&.triangle {
-    			border-width: 0 @baseLineHeight/2 @baseLineHeight/2 @baseLineHeight/2;
-				width: 0;
-				height: 0;
-				border-bottom-color: #0480be;
-				margin-top: 0;
-			}
-		}
-	}
-	&.slider-vertical {
-		height: 210px;
-		width: @baseLineHeight;
-		.slider-track {
-			width: @baseLineHeight/2;
-			height: 100%;
-			margin-left: -@baseLineHeight/4;
-			left: 50%;
-			top: 0;
-		}
-		.slider-selection {
-			width: 100%;
-			left: 0;
-			top: 0;
-			bottom: 0;
-		}
-		.slider-handle {
-			margin-left: -@baseLineHeight/4;
-			margin-top: -@baseLineHeight/2;
-			&.triangle {
-				border-width: @baseLineHeight/2 0 @baseLineHeight/2 @baseLineHeight/2;
-				width: 1px;
-				height: 1px;
-				border-left-color: #0480be;
-				margin-left: 0;
-			}
-		}
-	}
-	input {
-		display: none;
-	}
-	.tooltip-inner {
-		white-space: nowrap;
-	}
-}
-.slider-track {
-	position: absolute;
-	cursor: pointer;
-	#gradient > .vertical(#f5f5f5, #f9f9f9);
-	.box-shadow(inset 0 1px 2px rgba(0,0,0,.1));
-	.border-radius(@baseBorderRadius);
-}
-.slider-selection {
-	position: absolute;
-	#gradient > .vertical(#f9f9f9, #f5f5f5);
-	.box-shadow(inset 0 -1px 0 rgba(0,0,0,.15));
-	.box-sizing(border-box);
-	.border-radius(@baseBorderRadius);
-}
-.slider-handle {
-	position: absolute;
-	width: @baseLineHeight;
-	height: @baseLineHeight;
-	#gradient > .vertical(#149bdf, #0480be);
-	.box-shadow(~"inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05)");
-	opacity: 0.8;
-	border: 0px solid transparent;
-	&.round {
-		.border-radius(@baseLineHeight);
-	}
-	&.triangle {
-		background: transparent none;
-	}
-}
\ No newline at end of file
diff --git a/circle/dashboard/static/dashboard/bootstrap-slider/slider.css b/circle/dashboard/static/dashboard/bootstrap-slider/slider.css
deleted file mode 100644
index f6b699c..0000000
--- a/circle/dashboard/static/dashboard/bootstrap-slider/slider.css
+++ /dev/null
@@ -1,205 +0,0 @@
-/*!
- * Slider for Bootstrap
- *
- * Copyright 2012 Stefan Petre
- * Licensed under the Apache License v2.0
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- */
-.slider {
-  display: inline-block;
-  vertical-align: middle;
-  position: relative;
-}
-.slider.slider-horizontal {
-  width: 210px;
-  height: 20px;
-}
-.slider.slider-horizontal .slider-track {
-  height: 10px;
-  width: 100%;
-  margin-top: -5px;
-  top: 50%;
-  left: 0;
-}
-.slider.slider-horizontal .slider-selection {
-  height: 100%;
-  top: 0;
-  bottom: 0;
-}
-.slider.slider-horizontal .slider-handle {
-  margin-left: -10px;
-  margin-top: -5px;
-}
-.slider.slider-horizontal .slider-handle.triangle {
-  border-width: 0 10px 10px 10px;
-  width: 0;
-  height: 0;
-  border-bottom-color: #0480be;
-  margin-top: 0;
-}
-.slider.slider-vertical {
-  height: 210px;
-  width: 20px;
-}
-.slider.slider-vertical .slider-track {
-  width: 10px;
-  height: 100%;
-  margin-left: -5px;
-  left: 50%;
-  top: 0;
-}
-.slider.slider-vertical .slider-selection {
-  width: 100%;
-  left: 0;
-  top: 0;
-  bottom: 0;
-}
-.slider.slider-vertical .slider-handle {
-  margin-left: -5px;
-  margin-top: -10px;
-}
-.slider.slider-vertical .slider-handle.triangle {
-  border-width: 10px 0 10px 10px;
-  width: 1px;
-  height: 1px;
-  border-left-color: #0480be;
-  margin-left: 0;
-}
-.slider input {
-  display: none;
-}
-.slider .tooltip-inner {
-  white-space: nowrap;
-}
-.slider-track {
-  position: absolute;
-  cursor: pointer;
-  background-color: #f7f7f7;
-  background-image: -moz-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));
-  background-image: -webkit-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: -o-linear-gradient(top, #f5f5f5, #f9f9f9);
-  background-image: linear-gradient(to bottom, #f5f5f5, #f9f9f9);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);
-  -webkit-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-  -moz-box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-  box-shadow: inset 0 1px 2px rgba(0, 0, 0, 0.1);
-  -webkit-border-radius: 4px;
-  -moz-border-radius: 4px;
-  border-radius: 4px;
-}
-.slider-selection {
-  position: absolute;
-  background-color: #f7f7f7;
-  background-image: -moz-linear-gradient(top, #f9f9f9, #f5f5f5);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#f9f9f9), to(#f5f5f5));
-  background-image: -webkit-linear-gradient(top, #f9f9f9, #f5f5f5);
-  background-image: -o-linear-gradient(top, #f9f9f9, #f5f5f5);
-  background-image: linear-gradient(to bottom, #f9f9f9, #f5f5f5);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff9f9f9', endColorstr='#fff5f5f5', GradientType=0);
-  -webkit-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-  -moz-box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-  box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  box-sizing: border-box;
-  -webkit-border-radius: 4px;
-  -moz-border-radius: 4px;
-  border-radius: 4px;
-}
-.slider-handle {
-  position: absolute;
-  width: 20px;
-  height: 20px;
-  background-color: #0e90d2;
-  background-image: -moz-linear-gradient(top, #149bdf, #0480be);
-  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));
-  background-image: -webkit-linear-gradient(top, #149bdf, #0480be);
-  background-image: -o-linear-gradient(top, #149bdf, #0480be);
-  background-image: linear-gradient(to bottom, #149bdf, #0480be);
-  background-repeat: repeat-x;
-  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);
-  -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
-  -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
-  box-shadow: inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);
-  opacity: 0.8;
-  border: 0px solid transparent;
-}
-.slider-handle.round {
-  -webkit-border-radius: 20px;
-  -moz-border-radius: 20px;
-  border-radius: 20px;
-}
-.slider-handle.triangle {
-  background: transparent none;
-}
-
-/* custom */
-
-.slider-handle, .slider-handle:hover {
-    background-color: #3071a9;
-    opacity: 1;
-    width: 8px;
-    height: 26px;
-    margin-top: -4px!important;
-    margin-left: -6px !important;
-
-     border-radius: 0px;
-    -moz-border-radius: 0px;
-    -webkit-border-radius: 0px;
-
-    text-shadow: 0 1px 0 #fff;
-    background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
-    background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
-    background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
-    background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
-    background-repeat: repeat-x;
-    border-color: #2d6ca2;
-    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
-}
-
-.slider-handle:hover {
-    background: #428bca;
-    background-image: none;
-    border-color: #2d6ca2;
-}
-
-
-.slider-track, .slider-selection {
-    height: 20px !important;
-      background: #ccc;
-  background: -webkit-linear-gradient(top, #bbb, #ddd);
-  background: -moz-linear-gradient(top, #bbb, #ddd);
-  background: linear-gradient(top, #bbb, #ddd);
-
-  -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
-  -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
-  box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
-
-  -webkit-border-radius: 4px;
-  -moz-border-radius: 4px;
-  border-radius: 4px;
-
-  border: 1px solid #aaa;
-}
-
-
-.slider-selection {
-    background-color: #8DCA09;
-  background: -webkit-linear-gradient(top, #8DCA09, #72A307);
-  background: -moz-linear-gradient(top, #8DCA09, #72A307);
-  background: linear-gradient(top, #8DCA09, #72A307);
-  border-color: #496805;
-}
-
-.vm-slider {
-    width: 300px;
-}
-
-.output {
-  padding-left: 10px;
-  font-weight: bold;
-}
diff --git a/circle/dashboard/static/dashboard/dashboard.js b/circle/dashboard/static/dashboard/dashboard.js
index 0ecada8..3184931 100644
--- a/circle/dashboard/static/dashboard/dashboard.js
+++ b/circle/dashboard/static/dashboard/dashboard.js
@@ -3,8 +3,8 @@ $(function () {
     var template = $(this).data("template");
     $.ajax({
       type: 'GET',
-      url: '/dashboard/vm/create/' + (typeof template === "undefined" ? '' : '?template=' + template), 
-      success: function(data) { 
+      url: '/dashboard/vm/create/' + (typeof template === "undefined" ? '' : '?template=' + template),
+      success: function(data) {
         $('body').append(data);
         vmCreateLoaded();
         addSliderMiscs();
@@ -16,12 +16,12 @@ $(function () {
     });
     return false;
   });
- 
+
   $('.node-create').click(function(e) {
     $.ajax({
       type: 'GET',
-      url: '/dashboard/node/create/', 
-      success: function(data) { 
+      url: '/dashboard/node/create/',
+      success: function(data) {
         $('body').append(data);
         nodeCreateLoaded();
         addSliderMiscs();
@@ -68,8 +68,8 @@ $(function () {
   $('.template-choose').click(function(e) {
     $.ajax({
       type: 'GET',
-      url: '/dashboard/template/choose/', 
-      success: function(data) { 
+      url: '/dashboard/template/choose/',
+      success: function(data) {
         $('body').append(data);
         $('#create-modal').modal('show');
         $('#create-modal').on('hidden.bs.modal', function() {
@@ -137,10 +137,10 @@ $(function () {
     var pk = $(this).data("vm");
     if(star.hasClass("fa-star-o")) {
       star.removeClass("fa-star-o").addClass("fa-star");
-      star.prop("title", "Unfavourite");
+      star.prop("title", gettext("Unfavourite"));
     } else {
       star.removeClass("fa-star").addClass("fa-star-o");
-      star.prop("title", "Mark as favourite");
+      star.prop("title", gettext("Mark as favourite"));
     }
     $.ajax({
       url: "/dashboard/favourite/",
@@ -169,7 +169,7 @@ $(function () {
   $('.vm-delete').click(function() {
     var vm_pk = $(this).data('vm-pk');
     var dir = window.location.pathname.indexOf('list') == -1;
-    addModalConfirmation(deleteObject, 
+    addModalConfirmation(deleteObject,
       { 'url': '/dashboard/vm/delete/' + vm_pk + '/',
         'data': [],
         'pk': vm_pk,
@@ -177,11 +177,11 @@ $(function () {
         'redirect': dir});
     return false;
   });
-  
+
   /* for disk remove buttons */
   $('.disk-remove').click(function() {
     var disk_pk = $(this).data('disk-pk');
-    addModalConfirmation(deleteObject, 
+    addModalConfirmation(deleteObject,
       { 'url': '/dashboard/disk/' + disk_pk + '/remove/',
         'data': [],
         'pk': disk_pk,
@@ -194,13 +194,13 @@ $(function () {
   $('.node-delete').click(function() {
     var node_pk = $(this).data('node-pk');
     var dir = window.location.pathname.indexOf('list') == -1;
-    addModalConfirmation(deleteObject, 
+    addModalConfirmation(deleteObject,
       { 'url': '/dashboard/node/delete/' + node_pk + '/',
         'data': [],
         'pk': node_pk,
         'type': "node",
         'redirect': dir});
-    
+
     return false;
   });
 
@@ -209,8 +209,8 @@ $(function () {
     var node_pk = $(this).data('node-pk');
     var postto = $(this).attr('href');
     var dir = window.location.pathname.indexOf('list') == -1;
-    addModalConfirmation(function(){}, 
-      { 'url': postto, 
+    addModalConfirmation(function(){},
+      { 'url': postto,
         'data': [],
         'pk': node_pk,
         'type': "node",
@@ -223,18 +223,18 @@ $(function () {
   $('.group-delete').click(function() {
     var group_pk = $(this).data('group-pk');
     var dir = window.location.pathname.indexOf('list') == -1;
-    addModalConfirmation(deleteObject, 
+    addModalConfirmation(deleteObject,
       { 'url': '/dashboard/group/delete/' + group_pk + '/',
         'data': [],
         'type': "group",
         'pk': group_pk,
         'redirect': dir});
-    
+
     return false;
   });
 
  /* search for vms */
-  var my_vms = []
+  var my_vms = [];
   $("#dashboard-vm-search-input").keyup(function(e) {
     // if my_vms is empty get a list of our vms
     if(my_vms.length < 1) {
@@ -257,7 +257,7 @@ $(function () {
     }
 
     input = $("#dashboard-vm-search-input").val().toLowerCase();
-    var search_result = []
+    var search_result = [];
     var html = '';
     for(var i in my_vms) {
       if(my_vms[i].name.indexOf(input) != -1 || my_vms[i].host.indexOf(input) != -1) {
@@ -270,7 +270,7 @@ $(function () {
                              search_result[i].owner ? search_result[i].owner : search_result[i].host, search_result[i].icon,
                              search_result[i].status, search_result[i].fav,
                              (search_result.length < 5));
-    if(search_result.length == 0)
+    if(search_result.length === 0)
       html += '<div class="list-group-item list-group-item-last">' + gettext("No result") + '</div>';
     $("#dashboard-vm-list").html(html);
     $('.title-favourite').tooltip({'placement': 'right'});
@@ -286,7 +286,7 @@ $(function () {
   });
 
   /* search for nodes */
-  var my_nodes = []
+  var my_nodes = [];
   $("#dashboard-node-search-input").keyup(function(e) {
     // if my_nodes is empty get a list of our nodes
     if(my_nodes.length < 1) {
@@ -306,29 +306,29 @@ $(function () {
     }
 
     input = $("#dashboard-node-search-input").val().toLowerCase();
-    var search_result = []
+    var search_result = [];
     var html = '';
     for(var i in my_nodes) {
       if(my_nodes[i].name.indexOf(input) != -1) {
         search_result.push(my_nodes[i]);
       }
     }
-    for(var i=0; i<5 && i<search_result.length; i++)
+    for(i=0; i<5 && i<search_result.length; i++)
       html += generateNodeHTML(search_result[i].name,
                              search_result[i].icon, search_result[i].status,
                              search_result[i].url,
                              (search_result.length < 5));
-    if(search_result.length == 0)
+    if(search_result.length === 0)
       html += '<div class="list-group-item list-group-item-last">' + gettext("No result") + '</div>';
     $("#dashboard-node-list").html(html);
 
     html = '';
 
-    for(var i=0; i<5 && i<search_result.length; i++)
+    for(i=0; i<5 && i<search_result.length; i++)
       html += generateNodeTagHTML(search_result[i].name,
                              search_result[i].icon, search_result[i].status,
                              search_result[i].label, search_result[i].url);
-    if(search_result.length == 0)
+    if(search_result.length === 0)
       html += '<div class="list-group-item list-group-item-last">' + gettext("No result") + '</div>';
     $("#dashboard-node-taglist").html(html);
 
@@ -342,7 +342,7 @@ $(function () {
   });
 
   /* search for groups */
-  var my_groups = []
+  var my_groups = [];
   $("#dashboard-group-search-input").keyup(function(e) {
     // if my_groups is empty get a list of our groups
       if(my_groups.length < 1) {
@@ -359,16 +359,16 @@ $(function () {
     }
 
     input = $("#dashboard-group-search-input").val().toLowerCase();
-    var search_result = []
+    var search_result = [];
     var html = '';
     for(var i in my_groups) {
       if(my_groups[i].name.indexOf(input) != -1) {
         search_result.push(my_groups[i]);
       }
     }
-    for(var i=0; i<5 && i<search_result.length; i++)
+    for(i=0; i<5 && i<search_result.length; i++)
       html += generateGroupHTML(search_result[i].url, search_result[i].name, search_result.length < 5);
-    if(search_result.length == 0)
+    if(search_result.length === 0)
       html += '<div class="list-group-item list-group-item-last">No result</div>';
     $("#dashboard-group-list").html(html);
 
@@ -388,16 +388,16 @@ $(function () {
   });
 
   /* don't close notifications window on missclick */
-  $(document).on("click", ".notification-messages", function(e) {
+  $(document).on("click", "#notification-messages", function(e) {
     if($(e.target).closest("a").length)
-      return true
+      return true;
     else
       return false;
   });
 
   $("#notification-button a").click(function() {
-    $('.notification-messages').load("/dashboard/notifications/");
-    $('#notification-button a span[class*="badge-pulse"]').remove();  
+    $('#notification-messages').load("/dashboard/notifications/");
+    $('#notification-button a span[class*="badge-pulse"]').remove();
   });
   
   /* on the client confirmation button fire the clientInstalledAction */
@@ -446,12 +446,12 @@ function generateVmHTML(pk, name, host, icon, _status, fav, is_last) {
           '<i class="fa ' + icon + '" title="' + _status + '"></i> ' + safe_tags_replace(name) +
         '</span>' + 
         '<small class="text-muted"> ' + host + '</small>' +
-        '<div class="pull-right dashboard-vm-favourite" data-vm="' + pk + '">' +  
-          (fav ? '<i class="fa fa-star text-primary title-favourite" title="Unfavourite"></i>' :
-          '<i class="fa fa-star-o text-primary title-favourite" title="Mark as favorite"></i>' ) +
-        '</div>' +                                                               
-      '<div style="clear: both;"></div>' +                                       
-      '</a>';     
+        '<div class="pull-right dashboard-vm-favourite" data-vm="' + pk + '">' +
+          (fav ? '<i class="fa fa-star text-primary title-favourite" title="' + gettext("Unfavourite") + '"></i>' :
+          '<i class="fa fa-star-o text-primary title-favourite" title="' + gettext("Mark as favorite") + '"></i>' ) +
+        '</div>' +
+      '<div style="clear: both;"></div>' +
+      '</a>';
 }
 
 function generateGroupHTML(url, name, is_last) {
@@ -478,7 +478,7 @@ function generateNodeTagHTML(name, icon, _status, label , url) {
 /* copare vm-s by fav, pk order */
 function compareVmByFav(a, b) {
   if(a.fav && b.fav) {
-    return a.pk < b.pk ? -1 : 1; 
+    return a.pk < b.pk ? -1 : 1;
   }
   else if(a.fav && !b.fav) {
     return -1;
@@ -487,13 +487,13 @@ function compareVmByFav(a, b) {
     return 1;
   }
   else
-    return a.pk < b.pk ? -1 : 1; 
+    return a.pk < b.pk ? -1 : 1;
 }
 
 $(document).on('shown.bs.tab', 'a[href="#resources"]', function (e) {
   $(".cpu-priority-input").trigger("change");
   $(".cpu-count-input, .ram-input").trigger("input");
-})
+});
 
 function addSliderMiscs() {
   // set max values based on inputs
@@ -524,7 +524,7 @@ function addSliderMiscs() {
     if(!val) return;
     $(".cpu-count-slider").simpleSlider("setValue", val);
   });
-  
+
 
   var ram_fire = false;
   $(".ram-slider").bind("slider:changed", function (event, data) {
@@ -562,21 +562,21 @@ function setDefaultSliderValues() {
 function deleteObject(data) {
   $.ajax({
     type: 'POST',
-    data: {'redirect': data['redirect']},
-    url: data['url'],
-    headers: {"X-CSRFToken": getCookie('csrftoken')}, 
-    success: function(re, textStatus, xhr) { 
-      if(!data['redirect']) {
+    data: {'redirect': data.redirect},
+    url: data.url,
+    headers: {"X-CSRFToken": getCookie('csrftoken')},
+    success: function(re, textStatus, xhr) {
+      if(!data.redirect) {
         selected = [];
-        addMessage(re['message'], 'success');
+        addMessage(re.message, 'success');
         if(data.type === "disk") {
           // no need to remove them from DOM
           $('a[data-disk-pk="' + data.pk + '"]').parent("li").fadeOut();
           $('a[data-disk-pk="' + data.pk + '"]').parent("h4").fadeOut();
-        } 
-        else { 
-          $('a[data-'+data['type']+'-pk="' + data['pk'] + '"]').closest('tr').fadeOut(function() {
-            $(this).remove();  
+        }
+        else {
+          $('a[data-'+data.type+'-pk="' + data.pk + '"]').closest('tr').fadeOut(function() {
+            $(this).remove();
           });
         }
       } else {
@@ -584,32 +584,33 @@ function deleteObject(data) {
       }
     },
     error: function(xhr, textStatus, error) {
-      addMessage('Uh oh :(', 'danger')
+      addMessage('Uh oh :(', 'danger');
     }
   });
 }
 
 function massDeleteVm(data) {
-  $.ajax({                                                                
-      traditional: true,                                                    
-      url: data['url'],                                    
-      headers: {"X-CSRFToken": getCookie('csrftoken')},                     
-      type: 'POST',                                                         
-      data: {'vms': data['data']['v']},                                  
-      success: function(re, textStatus, xhr) {                            
-        for(var i=0; i< data['data']['v'].length; i++)                               
-          $('.vm-list-table tbody tr[data-vm-pk="' + data['data']['v'][i] + '"]').fadeOut(500, function() {
-            selected = [];                                                  
-            // reset group buttons                                          
-            $('.vm-list-group-control a').attr('disabled', true);           
-            $(this).remove();                                               
-          }); 
-        addMessage(re['message'], 'success');                         
-      },                                                                    
-      error: function(xhr, textStatus, error) {                             
-        // TODO this                                                        
-      }                                                                     
-    });          
+  f = function() {
+    selected = [];
+    // reset group buttons
+    $('.vm-list-group-control a').attr('disabled', true);
+    $(this).remove();
+  };
+  $.ajax({
+      traditional: true,
+      url: data.url,
+      headers: {"X-CSRFToken": getCookie('csrftoken')},
+      type: 'POST',
+      data: {'vms': data.data.v},
+      success: function(re, textStatus, xhr) {
+        for(var i=0; i< data.data.v.length; i++)
+          $('.vm-list-table tbody tr[data-vm-pk="' + data.data.v[i] + '"]').fadeOut(500, f);
+        addMessage(re.message, 'success');
+      },
+      error: function(xhr, textStatus, error) {
+        // TODO this
+      }
+    });
 }
 
 
@@ -627,8 +628,8 @@ function addMessage(text, type) {
 function addModalConfirmation(func, data) {
   $.ajax({
     type: 'GET',
-    url: data['url'],
-    data: jQuery.param(data['data']),
+    url: data.url,
+    data: jQuery.param(data.data),
     success: function(result) {
       $('body').append(result);
       $('#confirmation-modal').modal('show');
@@ -649,28 +650,6 @@ function clientInstalledAction(location) {
   $('#confirmation-modal').modal("hide");
 }
 
-// for AJAX calls
-/**                                                                         
- * Getter for user cookies                                                  
- * @param  {String} name Cookie name                                        
- * @return {String}      Cookie value                                       
- */                                                                         
-                                                                            
-function getCookie(name) {                                                  
-  var cookieValue = null;                                                   
-  if (document.cookie && document.cookie != '') {                           
-    var cookies = document.cookie.split(';');                               
-    for (var i = 0; i < cookies.length; i++) {                              
-      var cookie = jQuery.trim(cookies[i]);                                 
-      if (cookie.substring(0, name.length + 1) == (name + '=')) {           
-        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
-        break;                                                              
-      }                                                                     
-    }                                                                       
-  }                                                                         
-  return cookieValue;                                                       
-}
-
 function setCookie(name, value, seconds, path) {
   if (seconds!=null) {
     var today = new Date();
@@ -694,6 +673,46 @@ function getParameterByName(name) {
     return results == null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
 }
 
+// for AJAX calls
+/**
+ * Getter for user cookies
+ * @param  {String} name Cookie name
+ * @return {String}      Cookie value
+ */
+
+function getCookie(name) {
+  var cookieValue = null;
+  if (document.cookie && document.cookie !== '') {
+    var cookies = document.cookie.split(';');
+    for (var i = 0; i < cookies.length; i++) {
+      var cookie = jQuery.trim(cookies[i]);
+      if (cookie.substring(0, name.length + 1) == (name + '=')) {
+        cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
+        break;
+      }
+    }
+  }
+  return cookieValue;
+}
+
+function csrfSafeMethod(method) {
+  // these HTTP methods do not require CSRF protection
+  return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
+}
+$.ajaxSetup({
+  beforeSend: function(xhr, settings) {
+    if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
+      xhr.setRequestHeader("X-CSRFToken", getCookie("csrftoken"));
+    }
+  }
+});
+
+/* for autocomplete */
+$(function() {
+  yourlabs.TextWidget.prototype.getValue = function(choice) {
+    return choice.children().html();
+  }
+});
 
 var tagsToReplace = {
     '&': '&amp;',
diff --git a/circle/dashboard/static/dashboard/dashboard.css b/circle/dashboard/static/dashboard/dashboard.less
similarity index 91%
rename from circle/dashboard/static/dashboard/dashboard.css
rename to circle/dashboard/static/dashboard/dashboard.less
index 1e00494..f0191cd 100644
--- a/circle/dashboard/static/dashboard/dashboard.css
+++ b/circle/dashboard/static/dashboard/dashboard.less
@@ -364,9 +364,11 @@ a.hover-black {
   display: block;
 }
 
-.notification-messages {
+#notification-messages {
   padding: 10px 8px;
   width: 350px;
+  right: 0;
+  left: auto;
 }
 
 .notification-message {
@@ -375,7 +377,7 @@ a.hover-black {
   border-bottom: 1px dotted #D3D3D3;
 }
 
-.notification-messages .notification-message:last-child {
+#notification-messages .notification-message:last-child {
   margin-bottom: 0px;
   padding: 0px;
   border-bottom: none;
@@ -390,6 +392,15 @@ a.hover-black {
   cursor: pointer;
 }
 
+#notification-button a.dropdown-toggle {
+  color: white;
+  font-size: 12px;
+}
+
+#notification-button {
+  margin-right: 15px;
+}
+
 #vm-migrate-node-list {
   list-style: none;
 }
@@ -950,6 +961,48 @@ textarea[name="new_members"] {
 #vm-list-search, #vm-mass-ops {
   margin-top: 8px;
 }
+.list-group-item-last {
+  border-bottom: 1px solid #ddd !important;
+}
+
+.slider {
+  display: inline-block;
+}
+.slider .track {
+  height: 20px;
+  top: 50%;
+}
+.slider > .dragger, .slider > .dragger:hover {
+  border-radius: 0px;
+  -moz-border-radius: 0px;
+  -webkit-border-radius: 0px;
+  width: 8px;
+  height: 24px;
+  margin-top: -12px!important;
+  text-shadow: 0 1px 0 #fff;
+  background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
+  background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
+  background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
+  background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
+  background-repeat: repeat-x;
+  border-color: #2d6ca2;
+  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
+}
+.slider > .dragger:hover {
+  background-color: #3071a9;
+  background-image: none;
+  border-color: #2d6ca2;
+}
+.slider > .highlight-track {
+  height: 20px;
+  top: 50%;
+}
+.slider > .track, .slider > .highlight-track {
+  border-radius: 5px;
+}
+.slider {
+  width: 100%;
+}
 
 #vm-list-search-checkbox {
   margin-top: -1px;
@@ -1051,3 +1104,50 @@ textarea[name="new_members"] {
   white-space: nowrap;
   text-align: center;
 }
+
+/* for introjs
+ * newer version has this fixed
+ * but it doesn't work w bootstrap 3.2.0
+ */
+.introjs-helperLayer *,
+.introjs-helperLayer *:before,
+.introjs-helperLayer *:after {
+  -webkit-box-sizing: content-box;
+    -moz-box-sizing: content-box;
+      -ms-box-sizing: content-box;
+      -o-box-sizing: content-box;
+          box-sizing: content-box;
+}
+
+.node-list-table .monitor {
+  .progress {
+    position: relative;
+    width: 150px;
+    height: 16px;
+    margin-bottom: 4px;
+    margin-top: 0px;
+    background-image: linear-gradient(to bottom, #BBEBEB 0px, #F5F5F5 100%);
+  }
+  .progress-bar-text {
+    position: absolute;
+    top: -1px;
+    display: block;
+    width: 100%;
+    color: white;
+    /* outline */
+    text-shadow:
+      -1px -1px 0 #000,
+      1px -1px 0 #000,
+      -1px 1px 0 #000,
+      1px 1px 0 #000;
+    font-size: 13px;
+  }
+}
+
+.infobtn {
+  cursor: help;
+
+  &:hover {
+    background-position: 0 0px;
+  }
+}
diff --git a/circle/dashboard/static/dashboard/group-details.js b/circle/dashboard/static/dashboard/group-details.js
index 664619f..ac1578d 100644
--- a/circle/dashboard/static/dashboard/group-details.js
+++ b/circle/dashboard/static/dashboard/group-details.js
@@ -51,14 +51,14 @@
 function removeMember(data) {
   $.ajax({
     type: 'POST',
-    url: data['url'],
+    url: data.url,
     headers: {"X-CSRFToken": getCookie('csrftoken')},
     success: function(re, textStatus, xhr) {
-    data['tr'].fadeOut(function() {
+    data.tr.fadeOut(function() {
 	    $(this).remove();});
     },
     error: function(xhr, textStatus, error) {
-      addMessage('Uh oh :(', 'danger')
+      addMessage('Uh oh :(', 'danger');
     }
   });
 }
diff --git a/circle/dashboard/static/dashboard/group-list.js b/circle/dashboard/static/dashboard/group-list.js
index d5159e5..4fec8cf 100644
--- a/circle/dashboard/static/dashboard/group-list.js
+++ b/circle/dashboard/static/dashboard/group-list.js
@@ -8,7 +8,7 @@ $(function() {
 
   /* rename ajax */
   $('.group-list-rename-submit').click(function() {
-    var row = $(this).closest("tr")
+    var row = $(this).closest("tr");
     var name = $('#group-list-rename-name', row).val();
     var url = '/dashboard/group/' + row.children("td:first-child").text().replace(" ", "") + '/';
     $.ajax({
@@ -17,12 +17,12 @@ $(function() {
       data: {'new_name': name},
       headers: {"X-CSRFToken": getCookie('csrftoken')},
       success: function(data, textStatus, xhr) {
-        
+
         $("#group-list-column-name", row).html(
           $("<a/>", {
             'class': "real-link",
-            href: "/dashboard/group/" + data['group_pk'] + "/",
-            text: data['new_name']
+            href: "/dashboard/group/" + data.group_pk + "/",
+            text: data.new_name
           })
         ).show();
         $('#group-list-rename', row).hide();
diff --git a/circle/dashboard/static/dashboard/introjs/intro.min.js b/circle/dashboard/static/dashboard/introjs/intro.min.js
deleted file mode 100644
index e152d52..0000000
--- a/circle/dashboard/static/dashboard/introjs/intro.min.js
+++ /dev/null
@@ -1,27 +0,0 @@
-(function(p,f){"object"===typeof exports?f(exports):"function"===typeof define&&define.amd?define(["exports"],f):f(p)})(this,function(p){function f(a){this._targetElement=a;this._options={nextLabel:"Next &rarr;",prevLabel:"&larr; Back",skipLabel:"Skip",doneLabel:"Done",tooltipPosition:"bottom",tooltipClass:"",exitOnEsc:!0,exitOnOverlayClick:!0,showStepNumbers:!0,keyboardNavigation:!0,showButtons:!0,showBullets:!0,scrollToElement:!0,overlayOpacity:0.8}}function r(a){if(null==a||"object"!=typeof a||
-"undefined"!=typeof a.nodeType)return a;var b={},c;for(c in a)b[c]=r(a[c]);return b}function s(){this._direction="forward";"undefined"===typeof this._currentStep?this._currentStep=0:++this._currentStep;if(this._introItems.length<=this._currentStep)"function"===typeof this._introCompleteCallback&&this._introCompleteCallback.call(this),t.call(this,this._targetElement);else{var a=this._introItems[this._currentStep];"undefined"!==typeof this._introBeforeChangeCallback&&this._introBeforeChangeCallback.call(this,
-a.element);A.call(this,a)}}function x(){this._direction="backward";if(0===this._currentStep)return!1;var a=this._introItems[--this._currentStep];"undefined"!==typeof this._introBeforeChangeCallback&&this._introBeforeChangeCallback.call(this,a.element);A.call(this,a)}function t(a){var b=a.querySelector(".introjs-overlay");if(null!=b){b.style.opacity=0;setTimeout(function(){b.parentNode&&b.parentNode.removeChild(b)},500);(a=a.querySelector(".introjs-helperLayer"))&&a.parentNode.removeChild(a);(a=document.querySelector(".introjsFloatingElement"))&&
-a.parentNode.removeChild(a);if(a=document.querySelector(".introjs-showElement"))a.className=a.className.replace(/introjs-[a-zA-Z]+/g,"").replace(/^\s+|\s+$/g,"");if((a=document.querySelectorAll(".introjs-fixParent"))&&0<a.length)for(var c=a.length-1;0<=c;c--)a[c].className=a[c].className.replace(/introjs-fixParent/g,"").replace(/^\s+|\s+$/g,"");window.removeEventListener?window.removeEventListener("keydown",this._onKeyDown,!0):document.detachEvent&&document.detachEvent("onkeydown",this._onKeyDown);
-this._currentStep=void 0}}function B(a,b,c,d){var e="";b.style.top=null;b.style.right=null;b.style.bottom=null;b.style.left=null;b.style.marginLeft=null;b.style.marginTop=null;c.style.display="inherit";"undefined"!=typeof d&&null!=d&&(d.style.top=null,d.style.left=null);if(this._introItems[this._currentStep])switch(e=this._introItems[this._currentStep],e="string"===typeof e.tooltipClass?e.tooltipClass:this._options.tooltipClass,b.className=("introjs-tooltip "+e).replace(/^\s+|\s+$/g,""),currentTooltipPosition=
-this._introItems[this._currentStep].position,currentTooltipPosition){case "top":b.style.left="15px";b.style.top="-"+(h(b).height+10)+"px";c.className="introjs-arrow bottom";break;case "right":b.style.left=h(a).width+20+"px";c.className="introjs-arrow left";break;case "left":!0==this._options.showStepNumbers&&(b.style.top="15px");b.style.right=h(a).width+20+"px";c.className="introjs-arrow right";break;case "floating":c.style.display="none";a=h(b);b.style.left="50%";b.style.top="50%";b.style.marginLeft=
-"-"+a.width/2+"px";b.style.marginTop="-"+a.height/2+"px";"undefined"!=typeof d&&null!=d&&(d.style.left="-"+(a.width/2+18)+"px",d.style.top="-"+(a.height/2+18)+"px");break;case "bottom-right-aligned":c.className="introjs-arrow top-right";b.style.right="0px";b.style.bottom="-"+(h(b).height+10)+"px";break;case "bottom-middle-aligned":d=h(a);a=h(b);c.className="introjs-arrow top-middle";b.style.left=d.width/2-a.width/2+"px";b.style.bottom="-"+(a.height+10)+"px";break;default:b.style.bottom="-"+(h(b).height+
-10)+"px",c.className="introjs-arrow top"}}function v(a){if(a&&this._introItems[this._currentStep]){var b=this._introItems[this._currentStep],c=h(b.element),d=10;"floating"==b.position&&(d=0);a.setAttribute("style","width: "+(c.width+d)+"px; height:"+(c.height+d)+"px; top:"+(c.top-5)+"px;left: "+(c.left-5)+"px;")}}function A(a){var b;"undefined"!==typeof this._introChangeCallback&&this._introChangeCallback.call(this,a.element);var c=this,d=document.querySelector(".introjs-helperLayer");h(a.element);
-if(null!=d){var e=d.querySelector(".introjs-helperNumberLayer"),C=d.querySelector(".introjs-tooltiptext"),g=d.querySelector(".introjs-arrow"),y=d.querySelector(".introjs-tooltip"),k=d.querySelector(".introjs-skipbutton"),n=d.querySelector(".introjs-prevbutton"),l=d.querySelector(".introjs-nextbutton");y.style.opacity=0;if(null!=e&&(b=this._introItems[0<=a.step-2?a.step-2:0],null!=b&&"forward"==this._direction&&"floating"==b.position||"backward"==this._direction&&"floating"==a.position))e.style.opacity=
-0;v.call(c,d);var m=document.querySelectorAll(".introjs-fixParent");if(m&&0<m.length)for(b=m.length-1;0<=b;b--)m[b].className=m[b].className.replace(/introjs-fixParent/g,"").replace(/^\s+|\s+$/g,"");b=document.querySelector(".introjs-showElement");b.className=b.className.replace(/introjs-[a-zA-Z]+/g,"").replace(/^\s+|\s+$/g,"");c._lastShowElementTimer&&clearTimeout(c._lastShowElementTimer);c._lastShowElementTimer=setTimeout(function(){null!=e&&(e.innerHTML=a.step);C.innerHTML=a.intro;B.call(c,a.element,
-y,g,e);d.querySelector(".introjs-bullets li > a.active").className="";d.querySelector('.introjs-bullets li > a[data-stepnumber="'+a.step+'"]').className="active";y.style.opacity=1;e&&(e.style.opacity=1)},350)}else{var k=document.createElement("div"),m=document.createElement("div"),j=document.createElement("div"),n=document.createElement("div"),l=document.createElement("div"),f=document.createElement("div");k.className="introjs-helperLayer";v.call(c,k);this._targetElement.appendChild(k);m.className=
-"introjs-arrow";n.className="introjs-tooltiptext";n.innerHTML=a.intro;l.className="introjs-bullets";!1===this._options.showBullets&&(l.style.display="none");var p=document.createElement("ul");b=0;for(var u=this._introItems.length;b<u;b++){var r=document.createElement("li"),q=document.createElement("a");q.onclick=function(){c.goToStep(this.getAttribute("data-stepnumber"))};0===b&&(q.className="active");q.href="javascript:void(0);";q.innerHTML="&nbsp;";q.setAttribute("data-stepnumber",this._introItems[b].step);
-r.appendChild(q);p.appendChild(r)}l.appendChild(p);f.className="introjs-tooltipbuttons";!1===this._options.showButtons&&(f.style.display="none");j.className="introjs-tooltip";j.appendChild(n);j.appendChild(l);if(!0==this._options.showStepNumbers){var w=document.createElement("span");w.className="introjs-helperNumberLayer";w.innerHTML=a.step;k.appendChild(w)}j.appendChild(m);k.appendChild(j);l=document.createElement("a");l.onclick=function(){c._introItems.length-1!=c._currentStep&&s.call(c)};l.href=
-"javascript:void(0);";l.innerHTML=this._options.nextLabel;n=document.createElement("a");n.onclick=function(){0!=c._currentStep&&x.call(c)};n.href="javascript:void(0);";n.innerHTML=this._options.prevLabel;k=document.createElement("a");k.className="introjs-button introjs-skipbutton";k.href="javascript:void(0);";k.innerHTML=this._options.skipLabel;k.onclick=function(){c._introItems.length-1==c._currentStep&&"function"===typeof c._introCompleteCallback&&c._introCompleteCallback.call(c);c._introItems.length-
-1!=c._currentStep&&"function"===typeof c._introExitCallback&&c._introExitCallback.call(c);t.call(c,c._targetElement)};f.appendChild(k);1<this._introItems.length&&(f.appendChild(n),f.appendChild(l));j.appendChild(f);B.call(c,a.element,j,m,w)}0==this._currentStep&&1<this._introItems.length?(n.className="introjs-button introjs-prevbutton introjs-disabled",l.className="introjs-button introjs-nextbutton",k.innerHTML=this._options.skipLabel):this._introItems.length-1==this._currentStep||1==this._introItems.length?
-(k.innerHTML=this._options.doneLabel,n.className="introjs-button introjs-prevbutton",l.className="introjs-button introjs-nextbutton introjs-disabled"):(n.className="introjs-button introjs-prevbutton",l.className="introjs-button introjs-nextbutton",k.innerHTML=this._options.skipLabel);l.focus();a.element.className+=" introjs-showElement";b=z(a.element,"position");"absolute"!==b&&"relative"!==b&&(a.element.className+=" introjs-relativePosition");for(b=a.element.parentNode;null!=b&&"body"!==b.tagName.toLowerCase();){m=
-z(b,"z-index");j=parseFloat(z(b,"opacity"));if(/[0-9]+/.test(m)||1>j)b.className+=" introjs-fixParent";b=b.parentNode}b=a.element.getBoundingClientRect();!(0<=b.top&&0<=b.left&&b.bottom+80<=window.innerHeight&&b.right<=window.innerWidth)&&!0===this._options.scrollToElement&&(j=a.element.getBoundingClientRect(),b=void 0!=window.innerWidth?window.innerHeight:document.documentElement.clientHeight,m=j.bottom-(j.bottom-j.top),j=j.bottom-b,0>m||a.element.clientHeight>b?window.scrollBy(0,m-30):window.scrollBy(0,
-j+100));"undefined"!==typeof this._introAfterChangeCallback&&this._introAfterChangeCallback.call(this,a.element)}function z(a,b){var c="";a.currentStyle?c=a.currentStyle[b]:document.defaultView&&document.defaultView.getComputedStyle&&(c=document.defaultView.getComputedStyle(a,null).getPropertyValue(b));return c&&c.toLowerCase?c.toLowerCase():c}function D(a){var b=document.createElement("div"),c="",d=this;b.className="introjs-overlay";if("body"===a.tagName.toLowerCase())c+="top: 0;bottom: 0; left: 0;right: 0;position: fixed;",
-b.setAttribute("style",c);else{var e=h(a);e&&(c+="width: "+e.width+"px; height:"+e.height+"px; top:"+e.top+"px;left: "+e.left+"px;",b.setAttribute("style",c))}a.appendChild(b);b.onclick=function(){!0==d._options.exitOnOverlayClick&&(t.call(d,a),void 0!=d._introExitCallback&&d._introExitCallback.call(d))};setTimeout(function(){c+="opacity: "+d._options.overlayOpacity.toString()+";";b.setAttribute("style",c)},10);return!0}function h(a){var b={};b.width=a.offsetWidth;b.height=a.offsetHeight;for(var c=
-0,d=0;a&&!isNaN(a.offsetLeft)&&!isNaN(a.offsetTop);)c+=a.offsetLeft,d+=a.offsetTop,a=a.offsetParent;b.top=d;b.left=c;return b}var u=function(a){if("object"===typeof a)return new f(a);if("string"===typeof a){if(a=document.querySelector(a))return new f(a);throw Error("There is no element with given selector.");}return new f(document.body)};u.version="0.9.0";u.fn=f.prototype={clone:function(){return new f(this)},setOption:function(a,b){this._options[a]=b;return this},setOptions:function(a){var b=this._options,
-c={},d;for(d in b)c[d]=b[d];for(d in a)c[d]=a[d];this._options=c;return this},start:function(){a:{var a=this._targetElement,b=[],c=this;if(this._options.steps)for(var d=[],e=0,d=this._options.steps.length;e<d;e++){var f=r(this._options.steps[e]);f.step=b.length+1;"string"===typeof f.element&&(f.element=document.querySelector(f.element));if("undefined"===typeof f.element||null==f.element){var g=document.querySelector(".introjsFloatingElement");null==g&&(g=document.createElement("div"),g.className=
-"introjsFloatingElement",document.body.appendChild(g));f.element=g;f.position="floating"}null!=f.element&&b.push(f)}else{d=a.querySelectorAll("*[data-intro]");if(1>d.length)break a;e=0;for(f=d.length;e<f;e++){var g=d[e],h=parseInt(g.getAttribute("data-step"),10);0<h&&(b[h-1]={element:g,intro:g.getAttribute("data-intro"),step:parseInt(g.getAttribute("data-step"),10),tooltipClass:g.getAttribute("data-tooltipClass"),position:g.getAttribute("data-position")||this._options.tooltipPosition})}e=h=0;for(f=
-d.length;e<f;e++)if(g=d[e],null==g.getAttribute("data-step")){for(;"undefined"!=typeof b[h];)h++;b[h]={element:g,intro:g.getAttribute("data-intro"),step:h+1,tooltipClass:g.getAttribute("data-tooltipClass"),position:g.getAttribute("data-position")||this._options.tooltipPosition}}}e=[];for(d=0;d<b.length;d++)b[d]&&e.push(b[d]);b=e;b.sort(function(a,b){return a.step-b.step});c._introItems=b;D.call(c,a)&&(s.call(c),a.querySelector(".introjs-skipbutton"),a.querySelector(".introjs-nextbutton"),c._onKeyDown=
-function(b){if(27===b.keyCode&&!0==c._options.exitOnEsc)t.call(c,a),void 0!=c._introExitCallback&&c._introExitCallback.call(c);else if(37===b.keyCode)x.call(c);else if(39===b.keyCode||13===b.keyCode)s.call(c),b.preventDefault?b.preventDefault():b.returnValue=!1},c._onResize=function(){v.call(c,document.querySelector(".introjs-helperLayer"))},window.addEventListener?(this._options.keyboardNavigation&&window.addEventListener("keydown",c._onKeyDown,!0),window.addEventListener("resize",c._onResize,!0)):
-document.attachEvent&&(this._options.keyboardNavigation&&document.attachEvent("onkeydown",c._onKeyDown),document.attachEvent("onresize",c._onResize)))}return this},goToStep:function(a){this._currentStep=a-2;"undefined"!==typeof this._introItems&&s.call(this);return this},nextStep:function(){s.call(this);return this},previousStep:function(){x.call(this);return this},exit:function(){t.call(this,this._targetElement)},refresh:function(){v.call(this,document.querySelector(".introjs-helperLayer"));return this},
-onbeforechange:function(a){if("function"===typeof a)this._introBeforeChangeCallback=a;else throw Error("Provided callback for onbeforechange was not a function");return this},onchange:function(a){if("function"===typeof a)this._introChangeCallback=a;else throw Error("Provided callback for onchange was not a function.");return this},onafterchange:function(a){if("function"===typeof a)this._introAfterChangeCallback=a;else throw Error("Provided callback for onafterchange was not a function");return this},
-oncomplete:function(a){if("function"===typeof a)this._introCompleteCallback=a;else throw Error("Provided callback for oncomplete was not a function.");return this},onexit:function(a){if("function"===typeof a)this._introExitCallback=a;else throw Error("Provided callback for onexit was not a function.");return this}};return p.introJs=u});
diff --git a/circle/dashboard/static/dashboard/introjs/introjs.min.css b/circle/dashboard/static/dashboard/introjs/introjs.min.css
deleted file mode 100644
index 70ed6e6..0000000
--- a/circle/dashboard/static/dashboard/introjs/introjs.min.css
+++ /dev/null
@@ -1,12 +0,0 @@
-.introjs-overlay{position:absolute;z-index:999999;background-color:#000;opacity:0;background:-moz-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-webkit-gradient(radial,center center,0px,center center,100%,color-stop(0%,rgba(0,0,0,0.4)),color-stop(100%,rgba(0,0,0,0.9)));background:-webkit-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-o-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:-ms-radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);background:radial-gradient(center,ellipse cover,rgba(0,0,0,0.4) 0,rgba(0,0,0,0.9) 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#66000000',endColorstr='#e6000000',GradientType=1);-ms-filter:"alpha(opacity=50)";filter:alpha(opacity=50);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-fixParent{z-index:auto !important;opacity:1.0 !important}.introjs-showElement,tr.introjs-showElement>td,tr.introjs-showElement>th{z-index:9999999 !important}.introjs-relativePosition,tr.introjs-showElement>td,tr.introjs-showElement>th{position:relative}.introjs-helperLayer{position:absolute;z-index:9999998;background-color:#FFF;background-color:rgba(255,255,255,.9);border:1px solid #777;border:1px solid rgba(0,0,0,.5);border-radius:4px;box-shadow:0 2px 15px rgba(0,0,0,.4);-webkit-transition:all .3s ease-out;-moz-transition:all .3s ease-out;-ms-transition:all .3s ease-out;-o-transition:all .3s ease-out;transition:all .3s ease-out}.introjs-helperNumberLayer{position:absolute;top:-16px;left:-16px;z-index:9999999999 !important;padding:2px;font-family:Arial,verdana,tahoma;font-size:13px;font-weight:bold;color:white;text-align:center;text-shadow:1px 1px 1px rgba(0,0,0,.3);background:#ff3019;background:-webkit-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-webkit-gradient(linear,left top,left bottom,color-stop(0%,#ff3019),color-stop(100%,#cf0404));background:-moz-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-ms-linear-gradient(top,#ff3019 0,#cf0404 100%);background:-o-linear-gradient(top,#ff3019 0,#cf0404 100%);background:linear-gradient(to bottom,#ff3019 0,#cf0404 100%);width:20px;height:20px;line-height:20px;border:3px solid white;border-radius:50%;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3019',endColorstr='#cf0404',GradientType=0);filter:progid:DXImageTransform.Microsoft.Shadow(direction=135,strength=2,color=ff0000);box-shadow:0 2px 5px rgba(0,0,0,.4)}.introjs-arrow{border:5px solid white;content:'';position:absolute}.introjs-arrow.top{top:-10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-right{top:-10px;right:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.top-middle{top:-10px;left:50%;margin-left:-5px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:white;border-left-color:transparent}.introjs-arrow.right{right:-10px;top:10px;border-top-color:transparent;border-right-color:transparent;border-bottom-color:transparent;border-left-color:white}.introjs-arrow.bottom{bottom:-10px;border-top-color:white;border-right-color:transparent;border-bottom-color:transparent;border-left-color:transparent}.introjs-arrow.left{left:-10px;top:10px;border-top-color:transparent;border-right-color:white;border-bottom-color:transparent;border-left-color:transparent}.introjs-tooltip{position:absolute;padding:10px;background-color:white;min-width:200px;max-width:300px;border-radius:3px;box-shadow:0 1px 10px rgba(0,0,0,.4);-webkit-transition:opacity .1s ease-out;-moz-transition:opacity .1s ease-out;-ms-transition:opacity .1s ease-out;-o-transition:opacity .1s ease-out;transition:opacity .1s ease-out}.introjs-tooltipbuttons{text-align:right}.introjs-button{position:relative;overflow:visible;display:inline-block;padding:.3em .8em;border:1px solid #d4d4d4;margin:0;text-decoration:none;text-shadow:1px 1px 0 #fff;font:11px/normal sans-serif;color:#333;white-space:nowrap;cursor:pointer;outline:0;background-color:#ececec;background-image:-webkit-gradient(linear,0 0,0 100%,from(#f4f4f4),to(#ececec));background-image:-moz-linear-gradient(#f4f4f4,#ececec);background-image:-o-linear-gradient(#f4f4f4,#ececec);background-image:linear-gradient(#f4f4f4,#ececec);-webkit-background-clip:padding;-moz-background-clip:padding;-o-background-clip:padding-box;-webkit-border-radius:.2em;-moz-border-radius:.2em;border-radius:.2em;zoom:1;*display:inline;margin-top:10px}.introjs-button:hover{border-color:#bcbcbc;text-decoration:none;box-shadow:0 1px 1px #e3e3e3}.introjs-button:focus,.introjs-button:active{background-image:-webkit-gradient(linear,0 0,0 100%,from(#ececec),to(#f4f4f4));background-image:-moz-linear-gradient(#ececec,#f4f4f4);background-image:-o-linear-gradient(#ececec,#f4f4f4);background-image:linear-gradient(#ececec,#f4f4f4)}.introjs-button::-moz-focus-inner{padding:0;border:0}.introjs-skipbutton{margin-right:5px;color:#7a7a7a}.introjs-prevbutton{-webkit-border-radius:.2em 0 0 .2em;-moz-border-radius:.2em 0 0 .2em;border-radius:.2em 0 0 .2em;border-right:0}.introjs-nextbutton{-webkit-border-radius:0 .2em .2em 0;-moz-border-radius:0 .2em .2em 0;border-radius:0 .2em .2em 0}.introjs-disabled,.introjs-disabled:hover,.introjs-disabled:focus{color:#9a9a9a;border-color:#d4d4d4;box-shadow:none;cursor:default;background-color:#f4f4f4;background-image:none;text-decoration:none}.introjs-bullets{text-align:center}.introjs-bullets ul{clear:both;margin:15px auto 0;padding:0;display:inline-block}.introjs-bullets ul li{list-style:none;float:left;margin:0 2px}.introjs-bullets ul li a{display:block;width:6px;height:6px;background:#ccc;border-radius:10px;-moz-border-radius:10px;-webkit-border-radius:10px;text-decoration:none}.introjs-bullets ul li a:hover{background:#999}.introjs-bullets ul li a.active{background:#999}.introjsFloatingElement{position:absolute;height:0;width:0;left:50%;top:50%}
-
-
-.introjs-helperLayer *,
-.introjs-helperLayer *:before,
-.introjs-helperLayer *:after {
-  -webkit-box-sizing: content-box;
-    -moz-box-sizing: content-box;
-      -ms-box-sizing: content-box;
-      -o-box-sizing: content-box;
-          box-sizing: content-box;
-}
diff --git a/circle/dashboard/static/dashboard/js/jquery.knob.js b/circle/dashboard/static/dashboard/js/jquery.knob.js
deleted file mode 100644
index ae36b6b..0000000
--- a/circle/dashboard/static/dashboard/js/jquery.knob.js
+++ /dev/null
@@ -1,685 +0,0 @@
-/*!jQuery Knob*/
-/**
- * Downward compatible, touchable dial
- *
- * Version: 1.2.0 (15/07/2012)
- * Requires: jQuery v1.7+
- *
- * Copyright (c) 2012 Anthony Terrien
- * Under MIT and GPL licenses:
- *  http://www.opensource.org/licenses/mit-license.php
- *  http://www.gnu.org/licenses/gpl.html
- *
- * Thanks to vor, eskimoblood, spiffistan, FabrizioC
- */
-(function($) {
-
-    /**
-     * Kontrol library
-     */
-    "use strict";
-
-    /**
-     * Definition of globals and core
-     */
-    var k = {}, // kontrol
-        max = Math.max,
-        min = Math.min;
-
-    k.c = {};
-    k.c.d = $(document);
-    k.c.t = function (e) {
-        return e.originalEvent.touches.length - 1;
-    };
-
-    /**
-     * Kontrol Object
-     *
-     * Definition of an abstract UI control
-     *
-     * Each concrete component must call this one.
-     * <code>
-     * k.o.call(this);
-     * </code>
-     */
-    k.o = function () {
-        var s = this;
-
-        this.o = null; // array of options
-        this.$ = null; // jQuery wrapped element
-        this.i = null; // mixed HTMLInputElement or array of HTMLInputElement
-        this.g = null; // 2D graphics context for 'pre-rendering'
-        this.v = null; // value ; mixed array or integer
-        this.cv = null; // change value ; not commited value
-        this.x = 0; // canvas x position
-        this.y = 0; // canvas y position
-        this.$c = null; // jQuery canvas element
-        this.c = null; // rendered canvas context
-        this.t = 0; // touches index
-        this.isInit = false;
-        this.fgColor = null; // main color
-        this.pColor = null; // previous color
-        this.dH = null; // draw hook
-        this.cH = null; // change hook
-        this.eH = null; // cancel hook
-        this.rH = null; // release hook
-        this.scale = 1; // scale factor
-
-        this.run = function () {
-            var cf = function (e, conf) {
-                var k;
-                for (k in conf) {
-                    s.o[k] = conf[k];
-                }
-                s.init();
-                s._configure()
-                 ._draw();
-            };
-
-            if(this.$.data('kontroled')) return;
-            this.$.data('kontroled', true);
-
-            this.extend();
-            this.o = $.extend(
-                {
-                    // Config
-                    min : this.$.data('min') || 0,
-                    max : this.$.data('max') || 100,
-                    stopper : true,
-                    readOnly : this.$.data('readonly'),
-
-                    // UI
-                    cursor : (this.$.data('cursor') === true && 30)
-                                || this.$.data('cursor')
-                                || 0,
-                    thickness : this.$.data('thickness') || 0.35,
-                    lineCap : this.$.data('linecap') || 'butt',
-                    width : this.$.data('width') || 200,
-                    height : this.$.data('height') || 200,
-                    displayInput : this.$.data('displayinput') == null || this.$.data('displayinput'),
-                    displayPrevious : this.$.data('displayprevious'),
-                    fgColor : this.$.data('fgcolor') || '#87CEEB',
-                    inputColor: this.$.data('inputcolor') || this.$.data('fgcolor') || '#87CEEB',
-                    inline : false,
-                    step : this.$.data('step') || 1,
-
-                    // Hooks
-                    draw : null, // function () {}
-                    change : null, // function (value) {}
-                    cancel : null, // function () {}
-                    release : null, // function (value) {}
-                    error : null // function () {}
-                }, this.o
-            );
-
-            // routing value
-            if(this.$.is('fieldset')) {
-
-                // fieldset = array of integer
-                this.v = {};
-                this.i = this.$.find('input')
-                this.i.each(function(k) {
-                    var $this = $(this);
-                    s.i[k] = $this;
-                    s.v[k] = $this.val();
-
-                    $this.bind(
-                        'change'
-                        , function () {
-                            var val = {};
-                            val[k] = $this.val();
-                            s.val(val);
-                        }
-                    );
-                });
-                this.$.find('legend').remove();
-
-            } else {
-                // input = integer
-                this.i = this.$;
-                this.v = this.$.val();
-                (this.v == '') && (this.v = this.o.min);
-
-                this.$.bind(
-                    'change'
-                    , function () {
-                        s.val(s._validate(s.$.val()));
-                    }
-                );
-            }
-
-            (!this.o.displayInput) && this.$.hide();
-
-            this.$c = $('<canvas width="' +
-                            this.o.width + 'px" height="' +
-                            this.o.height + 'px"></canvas>');
-            
-            this.c = this.$c[0].getContext? this.$c[0].getContext('2d') : null;
-			
-            if (!this.c) {
-                this.o.error && this.o.error();
-                return;
-            }
-
-            this.$
-                .wrap($('<div style="' + (this.o.inline ? 'display:inline;' : '') +
-                        'width:' + this.o.width + 'px;height:' +
-                        this.o.height + 'px;"></div>'))
-                .before(this.$c);
-
-            this.scale = (window.devicePixelRatio || 1) /
-                        (
-                            this.c.webkitBackingStorePixelRatio ||
-                            this.c.mozBackingStorePixelRatio ||
-                            this.c.msBackingStorePixelRatio ||
-                            this.c.oBackingStorePixelRatio ||
-                            this.c.backingStorePixelRatio || 1
-                        );
-            if (this.scale !== 1) {
-                this.$c[0].width = this.$c[0].width * this.scale;
-                this.$c[0].height = this.$c[0].height * this.scale;
-                this.$c.width(this.o.width);
-                this.$c.height(this.o.height);
-            }
-
-            if (this.v instanceof Object) {
-                this.cv = {};
-                this.copy(this.v, this.cv);
-            } else {
-                this.cv = this.v;
-            }
-
-            this.$
-                .bind("configure", cf)
-                .parent()
-                .bind("configure", cf);
-
-            this._listen()
-                ._configure()
-                ._xy()
-                .init();
-
-            this.isInit = true;
-
-            this._draw();
-
-            return this;
-        };
-
-        this._draw = function () {
-
-            // canvas pre-rendering
-            var d = true,
-                c = document.createElement('canvas');
-
-            c.width = s.o.width * s.scale;
-            c.height = s.o.height * s.scale;
-
-            s.g = c.getContext('2d');
-
-            s.clear();
-
-            s.dH
-            && (d = s.dH());
-
-            (d !== false) && s.draw();
-
-            s.c.drawImage(c, 0, 0);
-            c = null;
-        };
-
-        this._touch = function (e) {
-
-            var touchMove = function (e) {
-
-                var v = s.xy2val(
-                            e.originalEvent.touches[s.t].pageX,
-                            e.originalEvent.touches[s.t].pageY
-                            );
-
-                if (v == s.cv) return;
-
-                if (
-                    s.cH
-                    && (s.cH(v) === false)
-                ) return;
-
-
-                s.change(s._validate(v));
-                s._draw();
-            };
-
-            // get touches index
-            this.t = k.c.t(e);
-
-            // First touch
-            touchMove(e);
-
-            // Touch events listeners
-            k.c.d
-                .bind("touchmove.k", touchMove)
-                .bind(
-                    "touchend.k"
-                    , function () {
-                        k.c.d.unbind('touchmove.k touchend.k');
-
-                        if (
-                            s.rH
-                            && (s.rH(s.cv) === false)
-                        ) return;
-
-                        s.val(s.cv);
-                    }
-                );
-
-            return this;
-        };
-
-        this._mouse = function (e) {
-
-            var mouseMove = function (e) {
-                var v = s.xy2val(e.pageX, e.pageY);
-                if (v == s.cv) return;
-
-                if (
-                    s.cH
-                    && (s.cH(v) === false)
-                ) return;
-
-                s.change(s._validate(v));
-                s._draw();
-            };
-
-            // First click
-            mouseMove(e);
-
-            // Mouse events listeners
-            k.c.d
-                .bind("mousemove.k", mouseMove)
-                .bind(
-                    // Escape key cancel current change
-                    "keyup.k"
-                    , function (e) {
-                        if (e.keyCode === 27) {
-                            k.c.d.unbind("mouseup.k mousemove.k keyup.k");
-
-                            if (
-                                s.eH
-                                && (s.eH() === false)
-                            ) return;
-
-                            s.cancel();
-                        }
-                    }
-                )
-                .bind(
-                    "mouseup.k"
-                    , function (e) {
-                        k.c.d.unbind('mousemove.k mouseup.k keyup.k');
-
-                        if (
-                            s.rH
-                            && (s.rH(s.cv) === false)
-                        ) return;
-
-                        s.val(s.cv);
-                    }
-                );
-
-            return this;
-        };
-
-        this._xy = function () {
-            var o = this.$c.offset();
-            this.x = o.left;
-            this.y = o.top;
-            return this;
-        };
-
-        this._listen = function () {
-
-            if (!this.o.readOnly) {
-                this.$c
-                    .bind(
-                        "mousedown"
-                        , function (e) {
-                            e.preventDefault();
-                            s._xy()._mouse(e);
-                         }
-                    )
-                    .bind(
-                        "touchstart"
-                        , function (e) {
-                            e.preventDefault();
-                            s._xy()._touch(e);
-                         }
-                    );
-                this.listen();
-            } else {
-                this.$.attr('readonly', 'readonly');
-            }
-
-            return this;
-        };
-
-        this._configure = function () {
-
-            // Hooks
-            if (this.o.draw) this.dH = this.o.draw;
-            if (this.o.change) this.cH = this.o.change;
-            if (this.o.cancel) this.eH = this.o.cancel;
-            if (this.o.release) this.rH = this.o.release;
-
-            if (this.o.displayPrevious) {
-                this.pColor = this.h2rgba(this.o.fgColor, "0.4");
-                this.fgColor = this.h2rgba(this.o.fgColor, "0.6");
-            } else {
-                this.fgColor = this.o.fgColor;
-            }
-
-            return this;
-        };
-
-        this._clear = function () {
-            this.$c[0].width = this.$c[0].width;
-        };
-
-        this._validate = function(v) {
-            return (~~ (((v < 0) ? -0.5 : 0.5) + (v/this.o.step))) * this.o.step;
-        };
-
-        // Abstract methods
-        this.listen = function () {}; // on start, one time
-        this.extend = function () {}; // each time configure triggered
-        this.init = function () {}; // each time configure triggered
-        this.change = function (v) {}; // on change
-        this.val = function (v) {}; // on release
-        this.xy2val = function (x, y) {}; //
-        this.draw = function () {}; // on change / on release
-        this.clear = function () { this._clear(); };
-
-        // Utils
-        this.h2rgba = function (h, a) {
-            var rgb;
-            h = h.substring(1,7)
-            rgb = [parseInt(h.substring(0,2),16)
-                   ,parseInt(h.substring(2,4),16)
-                   ,parseInt(h.substring(4,6),16)];
-            return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")";
-        };
-
-        this.copy = function (f, t) {
-            for (var i in f) { t[i] = f[i]; }
-        };
-    };
-
-
-    /**
-     * k.Dial
-     */
-    k.Dial = function () {
-        k.o.call(this);
-
-        this.startAngle = null;
-        this.xy = null;
-        this.radius = null;
-        this.lineWidth = null;
-        this.cursorExt = null;
-        this.w2 = null;
-        this.PI2 = 2*Math.PI;
-
-        this.extend = function () {
-            this.o = $.extend(
-                {
-                    bgColor : this.$.data('bgcolor') || '#EEEEEE',
-                    angleOffset : this.$.data('angleoffset') || 0,
-                    angleArc : this.$.data('anglearc') || 360,
-                    inline : true
-                }, this.o
-            );
-        };
-
-        this.val = function (v) {
-            if (null != v) {
-                this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v;
-                this.v = this.cv;
-                this.$.val(this.v);
-                this._draw();
-            } else {
-                return this.v;
-            }
-        };
-
-        this.xy2val = function (x, y) {
-            var a, ret;
-
-            a = Math.atan2(
-                        x - (this.x + this.w2)
-                        , - (y - this.y - this.w2)
-                    ) - this.angleOffset;
-
-            if(this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) {
-                // if isset angleArc option, set to min if .5 under min
-                a = 0;
-            } else if (a < 0) {
-                a += this.PI2;
-            }
-
-            ret = ~~ (0.5 + (a * (this.o.max - this.o.min) / this.angleArc))
-                    + this.o.min;
-
-            this.o.stopper
-            && (ret = max(min(ret, this.o.max), this.o.min));
-
-            return ret;
-        };
-
-        this.listen = function () {
-            // bind MouseWheel
-            var s = this,
-                mw = function (e) {
-                            e.preventDefault();
-                            var ori = e.originalEvent
-                                ,deltaX = ori.detail || ori.wheelDeltaX
-                                ,deltaY = ori.detail || ori.wheelDeltaY
-                                ,v = parseInt(s.$.val()) + (deltaX>0 || deltaY>0 ? s.o.step : deltaX<0 || deltaY<0 ? -s.o.step : 0);
-
-                            if (
-                                s.cH
-                                && (s.cH(v) === false)
-                            ) return;
-
-                            s.val(v);
-                        }
-                , kval, to, m = 1, kv = {37:-s.o.step, 38:s.o.step, 39:s.o.step, 40:-s.o.step};
-
-            this.$
-                .bind(
-                    "keydown"
-                    ,function (e) {
-                        var kc = e.keyCode;
-
-                        // numpad support
-                        if(kc >= 96 && kc <= 105) {
-                            kc = e.keyCode = kc - 48;
-                        }
-
-                        kval = parseInt(String.fromCharCode(kc));
-
-                        if (isNaN(kval)) {
-
-                            (kc !== 13)         // enter
-                            && (kc !== 8)       // bs
-                            && (kc !== 9)       // tab
-                            && (kc !== 189)     // -
-                            && e.preventDefault();
-
-                            // arrows
-                            if ($.inArray(kc,[37,38,39,40]) > -1) {
-                                e.preventDefault();
-
-                                var v = parseInt(s.$.val()) + kv[kc] * m;
-
-                                s.o.stopper
-                                && (v = max(min(v, s.o.max), s.o.min));
-
-                                s.change(v);
-                                s._draw();
-
-                                // long time keydown speed-up
-                                to = window.setTimeout(
-                                    function () { m*=2; }
-                                    ,30
-                                );
-                            }
-                        }
-                    }
-                )
-                .bind(
-                    "keyup"
-                    ,function (e) {
-                        if (isNaN(kval)) {
-                            if (to) {
-                                window.clearTimeout(to);
-                                to = null;
-                                m = 1;
-                                s.val(s.$.val());
-                            }
-                        } else {
-                            // kval postcond
-                            (s.$.val() > s.o.max && s.$.val(s.o.max))
-                            || (s.$.val() < s.o.min && s.$.val(s.o.min));
-                        }
-
-                    }
-                );
-
-            this.$c.bind("mousewheel DOMMouseScroll", mw);
-            this.$.bind("mousewheel DOMMouseScroll", mw)
-        };
-
-        this.init = function () {
-
-            if (
-                this.v < this.o.min
-                || this.v > this.o.max
-            ) this.v = this.o.min;
-
-            this.$.val(this.v);
-            this.w2 = this.o.width / 2;
-            this.cursorExt = this.o.cursor / 100;
-            this.xy = this.w2 * this.scale;
-            this.lineWidth = this.xy * this.o.thickness;
-            this.lineCap = this.o.lineCap;
-            this.radius = this.xy - this.lineWidth / 2;
-
-            this.o.angleOffset
-            && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset);
-
-            this.o.angleArc
-            && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc);
-
-            // deg to rad
-            this.angleOffset = this.o.angleOffset * Math.PI / 180;
-            this.angleArc = this.o.angleArc * Math.PI / 180;
-
-            // compute start and end angles
-            this.startAngle = 1.5 * Math.PI + this.angleOffset;
-            this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc;
-
-            var s = max(
-                            String(Math.abs(this.o.max)).length
-                            , String(Math.abs(this.o.min)).length
-                            , 2
-                            ) + 2;
-
-            this.o.displayInput
-                && this.i.css({
-                        'width' : ((this.o.width / 2 + 4) >> 0) + 'px'
-                        ,'height' : ((this.o.width / 3) >> 0) + 'px'
-                        ,'position' : 'absolute'
-                        ,'vertical-align' : 'middle'
-                        ,'margin-top' : ((this.o.width / 3) >> 0) + 'px'
-                        ,'margin-left' : '-' + ((this.o.width * 3 / 4 + 2) >> 0) + 'px'
-                        ,'border' : 0
-                        ,'background' : 'none'
-                        ,'font' : 'bold ' + ((this.o.width / s) >> 0) + 'px Arial'
-                        ,'text-align' : 'center'
-                        ,'color' : this.o.inputColor || this.o.fgColor
-                        ,'padding' : '0px'
-                        ,'-webkit-appearance': 'none'
-                        })
-                || this.i.css({
-                        'width' : '0px'
-                        ,'visibility' : 'hidden'
-                        });
-        };
-
-        this.change = function (v) {
-            this.cv = v;
-            this.$.val(v);
-        };
-
-        this.angle = function (v) {
-            return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min);
-        };
-
-        this.draw = function () {
-
-            var c = this.g,                 // context
-                a = this.angle(this.cv)    // Angle
-                , sat = this.startAngle     // Start angle
-                , eat = sat + a             // End angle
-                , sa, ea                    // Previous angles
-                , r = 1;
-
-            c.lineWidth = this.lineWidth;
-
-            c.lineCap = this.lineCap;
-
-            this.o.cursor
-                && (sat = eat - this.cursorExt)
-                && (eat = eat + this.cursorExt);
-
-            c.beginPath();
-                c.strokeStyle = this.o.bgColor;
-                c.arc(this.xy, this.xy, this.radius, this.endAngle, this.startAngle, true);
-            c.stroke();
-
-            if (this.o.displayPrevious) {
-                ea = this.startAngle + this.angle(this.v);
-                sa = this.startAngle;
-                this.o.cursor
-                    && (sa = ea - this.cursorExt)
-                    && (ea = ea + this.cursorExt);
-
-                c.beginPath();
-                    c.strokeStyle = this.pColor;
-                    c.arc(this.xy, this.xy, this.radius, sa, ea, false);
-                c.stroke();
-                r = (this.cv == this.v);
-            }
-
-            c.beginPath();
-                c.strokeStyle = r ? this.o.fgColor : this.fgColor ;
-                c.arc(this.xy, this.xy, this.radius, sat, eat, false);
-            c.stroke();
-        };
-
-        this.cancel = function () {
-            this.val(this.v);
-        };
-    };
-
-    $.fn.dial = $.fn.knob = function (o) {
-        return this.each(
-            function () {
-                var d = new k.Dial();
-                d.o = o;
-                d.$ = $(this);
-                d.run();
-            }
-        ).parent();
-    };
-
-})(jQuery);
\ No newline at end of file
diff --git a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/css/simple-slider.css b/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/css/simple-slider.css
deleted file mode 100644
index 953ebf2..0000000
--- a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/css/simple-slider.css
+++ /dev/null
@@ -1,102 +0,0 @@
-.slider {
-  width: 300px;
-}
-
-.slider > .dragger {
-  background: #8DCA09;
-  background: -webkit-linear-gradient(top, #8DCA09, #72A307);
-  background: -moz-linear-gradient(top, #8DCA09, #72A307);
-  background: linear-gradient(top, #8DCA09, #72A307);
-
-  -webkit-box-shadow: inset 0 2px 2px rgba(255,255,255,0.5), 0 2px 8px rgba(0,0,0,0.2);
-  -moz-box-shadow: inset 0 2px 2px rgba(255,255,255,0.5), 0 2px 8px rgba(0,0,0,0.2);
-  box-shadow: inset 0 2px 2px rgba(255,255,255,0.5), 0 2px 8px rgba(0,0,0,0.2);
-
-  -webkit-border-radius: 10px;
-  -moz-border-radius: 10px;
-  border-radius: 10px;
-
-  border: 1px solid #496805;
-  width: 16px;
-  height: 16px;
-}
-
-.slider > .dragger:hover {
-  background: -webkit-linear-gradient(top, #8DCA09, #8DCA09);
-}
-
-
-.slider > .track, .slider > .highlight-track {
-  background: #ccc;
-  background: -webkit-linear-gradient(top, #bbb, #ddd);
-  background: -moz-linear-gradient(top, #bbb, #ddd);
-  background: linear-gradient(top, #bbb, #ddd);
-
-  -webkit-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
-  -moz-box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
-  box-shadow: inset 0 2px 4px rgba(0,0,0,0.1);
-
-  -webkit-border-radius: 8px;
-  -moz-border-radius: 8px;
-  border-radius: 8px;
-
-  border: 1px solid #aaa;
-  height: 4px;
-}
-
-.slider > .highlight-track {
-	background-color: #8DCA09;
-	background: -webkit-linear-gradient(top, #8DCA09, #72A307);
-	background: -moz-linear-gradient(top, #8DCA09, #72A307);
-	background: linear-gradient(top, #8DCA09, #72A307);
-	
-	border-color: #496805;
-}
-
-
-
-.slider {
-    display: inline-block;
-}
-.slider .track {
-    height: 20px;
-    top: 50%;
-}
-.slider > .dragger, .slider > .dragger:hover {
-    border-radius: 0px;
-    -moz-border-radius: 0px;
-    -webkit-border-radius: 0px;
-    width: 8px;
-    height: 24px;
-    margin-top: -12px!important;
-    text-shadow: 0 1px 0 #fff;
-    background-image: -webkit-gradient(linear, left 0%, left 100%, from(#428bca), to(#3071a9));
-    background-image: -webkit-linear-gradient(top, #428bca, 0%, #3071a9, 100%);
-    background-image: -moz-linear-gradient(top, #428bca 0%, #3071a9 100%);
-    background-image: linear-gradient(to bottom, #428bca 0%, #3071a9 100%);
-    background-repeat: repeat-x;
-    border-color: #2d6ca2;
-    filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff428bca', endColorstr='#ff3071a9', GradientType=0);
-}
-.slider > .dragger:hover {
-    background-color: #3071a9;
-    background-image: none;
-    border-color: #2d6ca2;
-}
-
-.slider > .highlight-track {
-    height: 20px;
-    top: 50%;
-}
-.slider + .output {
-
-}
-
-.slider > .track, .slider > .highlight-track {
-border-radius: 5px;
-}
-
-/* review this later */
-.slider {
-  width: 100%;
-}
diff --git a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.js b/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.js
deleted file mode 100644
index 2592270..0000000
--- a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.js
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- jQuery Simple Slider
-
- Copyright (c) 2012, 2013 James Smith (http://loopj.com)
- Copyright (c) 2013 Maarten van Grootel (http://maatenvangrootel.nl)
- Copyright (c) 2013 Nathan Hunzaker (http://natehunzaker.com)
- Copyright (c) 2013 Erik J. Nedwidek (http://github.com/nedwidek)
-
- Licensed under the MIT license (http://mit-license.org/)
-*/
-
-var __slice = [].slice,
-  __indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
-
-(function($, window) {
-  var SimpleSlider;
-  SimpleSlider = (function() {
-
-    function SimpleSlider(input, options) {
-      var ratio,
-        _this = this;
-      this.input = input;
-      this.defaultOptions = {
-        animate: true,
-        snapMid: false,
-        classPrefix: null,
-        classSuffix: null,
-        theme: null,
-        highlight: false,
-        showScale: false
-      };
-      if(typeof options == 'undefined') {
-        options = this.loadDataOptions();
-      }
-      this.settings = $.extend({}, this.defaultOptions, options);
-      if (this.settings.theme) {
-        this.settings.classSuffix = "-" + this.settings.theme;
-      }
-      this.input.hide();
-      this.slider = $("<div>").addClass("slider" + (this.settings.classSuffix || "")).css({
-        position: "relative",
-        userSelect: "none",
-        boxSizing: "border-box"
-      }).insertBefore(this.input);
-      if (this.input.attr("id")) {
-        this.slider.attr("id", this.input.attr("id") + "-slider");
-      }
-      this.track = this.createDivElement("track").css({
-        width: "100%"
-      });
-      if (this.settings.highlight) {
-        this.highlightTrack = this.createDivElement("highlight-track").css({
-          width: "0"
-        });
-      }
-      this.dragger = this.createDivElement("dragger");
-      this.slider.css({
-        minHeight: this.dragger.outerHeight(),
-        marginLeft: this.dragger.outerWidth() / 2,
-        marginRight: this.dragger.outerWidth() / 2
-      });
-      this.track.css({
-        marginTop: this.track.outerHeight() / -2
-      });
-      if (this.settings.highlight) {
-        this.highlightTrack.css({
-          marginTop: this.track.outerHeight() / -2
-        });
-      }
-      this.dragger.css({
-        marginTop: this.dragger.outerWidth() / -2,
-        marginLeft: this.dragger.outerWidth() / -2
-      });
-      this.track.mousedown(function(e) {
-        return _this.trackEvent(e);
-      });
-      if (this.settings.highlight) {
-        this.highlightTrack.mousedown(function(e) {
-          return _this.trackEvent(e);
-        });
-      }
-      this.dragger.mousedown(function(e) {
-        if (e.which !== 1 || _this.settings.disabled) {
-          return;
-        }
-        _this.dragging = true;
-        _this.dragger.addClass("dragging");
-        _this.domDrag(e.pageX, e.pageY);
-        return false;
-      });
-      $("body").mousemove(function(e) {
-        if (_this.dragging) {
-          _this.domDrag(e.pageX, e.pageY);
-          return $("body").css({
-            cursor: "pointer"
-          });
-        }
-      }).mouseup(function(e) {
-        if (_this.dragging) {
-          _this.dragging = false;
-          _this.dragger.removeClass("dragging");
-          return $("body").css({
-            cursor: "auto"
-          });
-        }
-      });
-      this.pagePos = 0;
-      if (this.input.val() === "") {
-        this.value = this.getRange().min;
-        this.input.val(this.value);
-      } else {
-        this.value = this.nearestValidValue(this.input.val());
-      }
-      this.setSliderPositionFromValue(this.value);
-      ratio = this.valueToRatio(this.value);
-      if (this.settings.showScale) {
-        this.scale = this.createDivElement("scale");
-        this.minScale = this.createSpanElement("min-scale", this.scale);
-        this.maxScale = this.createSpanElement("max-scale", this.scale);
-
-        range = this.getRange();
-
-        this.minScale.html(range.min);
-        this.maxScale.html(range.max);
-
-        this.scale.css('marginTop', function(index, currentValue) {
-            return (parseInt(currentValue, 10)  + this.previousSibling.offsetHeight / 2) + 'px';
-        });
-      }
-      this.input.trigger("slider:ready", {
-        value: this.value,
-        ratio: ratio,
-        position: ratio * this.slider.outerWidth(),
-        el: this.slider
-      });
-    }
-
-    SimpleSlider.prototype.loadDataOptions = function() {
-      var options = {};
-      allowedValues = this.input.data("slider-values");
-      if (allowedValues) {
-        options.allowedValues = (function() {
-          var _i, _len, _ref, _results;
-          _ref = allowedValues.split(",");
-          _results = [];
-          for (_i = 0, _len = _ref.length; _i < _len; _i++) {
-            x = _ref[_i];
-            _results.push(parseFloat(x));
-          }
-          return _results;
-        })();
-      }
-      if (this.input.data("slider-range")) {
-        options.range = this.input.data("slider-range").split(",");
-      }
-      if (this.input.data("slider-step")) {
-        options.step = this.input.data("slider-step");
-      }
-      options.snap = this.input.data("slider-snap");
-      options.equalSteps = this.input.data("slider-equal-steps");
-      if (this.input.data("slider-theme")) {
-        options.theme = this.input.data("slider-theme");
-      }
-      if (this.input.attr("data-slider-highlight")) {
-        options.highlight = this.input.data("slider-highlight");
-      }
-      if (this.input.data("slider-animate") != null) {
-        options.animate = this.input.data("slider-animate");
-      }
-      if (this.input.data("slider-showscale") != null) {
-        options.showScale = this.input.data("slider-showscale");
-      }
-      if (this.input.data("slider-disabled")) {
-        options.disabled = this.input.data("slider-disabled");
-      }
-      return options;
-    }
-
-    SimpleSlider.prototype.createDivElement = function(classname) {
-      var item;
-      item = $("<div>").addClass(classname).css({
-        position: "absolute",
-        top: "50%",
-        userSelect: "none",
-        cursor: "pointer"
-      }).appendTo(this.slider);
-      return item;
-    };
-
-    SimpleSlider.prototype.createSpanElement = function(classname, parent) {
-      var item;
-      item = $("<span>").addClass(classname).appendTo(parent);
-      return item;
-    };
-
-    SimpleSlider.prototype.setRatio = function(ratio) {
-      var value;
-      ratio = Math.min(1, ratio);
-      ratio = Math.max(0, ratio);
-      value = this.ratioToValue(ratio);
-      this.setSliderPositionFromValue(value);
-      return this.valueChanged(value, ratio, "setRatio");
-    };
-
-    SimpleSlider.prototype.setValue = function(value) {
-      var ratio;
-      value = this.nearestValidValue(value);
-      ratio = this.valueToRatio(value);
-      this.setSliderPositionFromValue(value);
-      return this.valueChanged(value, ratio, "setValue");
-    };
-
-    SimpleSlider.prototype.setDisabled = function(value) {
-      this.settings.disabled = value;
-    }
-
-    SimpleSlider.prototype.trackEvent = function(e) {
-      if (e.which !== 1 || this.settings.disabled) {
-        return;
-      }
-      this.domDrag(e.pageX, e.pageY, true);
-      this.dragging = true;
-      return false;
-    };
-
-    SimpleSlider.prototype.domDrag = function(pageX, pageY, animate) {
-      var pagePos, ratio, value;
-      if (animate == null) {
-        animate = false;
-      }
-      pagePos = pageX - this.slider.offset().left;
-      pagePos = Math.min(this.slider.outerWidth(), pagePos);
-      pagePos = Math.max(0, pagePos);
-      if (this.pagePos !== pagePos) {
-        this.pagePos = pagePos;
-        ratio = pagePos / this.slider.outerWidth();
-        value = this.ratioToValue(ratio);
-        this.valueChanged(value, ratio, "domDrag");
-        if (this.settings.snap) {
-          return this.setSliderPositionFromValue(value, animate);
-        } else {
-          return this.setSliderPosition(pagePos, animate);
-        }
-      }
-    };
-
-    SimpleSlider.prototype.setSliderPosition = function(position, animate) {
-      if (animate == null) {
-        animate = false;
-      }
-      if (animate && this.settings.animate) {
-        this.dragger.animate({
-          left: position
-        }, 200);
-        if (this.settings.highlight) {
-          return this.highlightTrack.animate({
-            width: position
-          }, 200);
-        }
-      } else {
-        this.dragger.css({
-          left: position
-        });
-        if (this.settings.highlight) {
-          return this.highlightTrack.css({
-            width: position
-          });
-        }
-      }
-    };
-
-    SimpleSlider.prototype.setSliderPositionFromValue = function(value, animate) {
-      var ratio;
-      if (animate == null) {
-        animate = false;
-      }
-      ratio = this.valueToRatio(value);
-      return this.setSliderPosition(ratio * this.slider.outerWidth(), animate);
-    };
-
-    SimpleSlider.prototype.getRange = function() {
-      if (this.settings.allowedValues) {
-        return {
-          min: Math.min.apply(Math, this.settings.allowedValues),
-          max: Math.max.apply(Math, this.settings.allowedValues)
-        };
-      } else if (this.settings.range) {
-        return {
-          min: parseFloat(this.settings.range[0]),
-          max: parseFloat(this.settings.range[1])
-        };
-      } else {
-        return {
-          min: 0,
-          max: 1
-        };
-      }
-    };
-
-    SimpleSlider.prototype.nearestValidValue = function(rawValue) {
-      var closest, maxSteps, range, steps;
-      range = this.getRange();
-      rawValue = Math.min(range.max, rawValue);
-      rawValue = Math.max(range.min, rawValue);
-      if (this.settings.allowedValues) {
-        closest = null;
-        $.each(this.settings.allowedValues, function() {
-          if (closest === null || Math.abs(this - rawValue) < Math.abs(closest - rawValue)) {
-            return closest = this;
-          }
-        });
-        return closest;
-      } else if (this.settings.step) {
-        maxSteps = (range.max - range.min) / this.settings.step;
-        steps = Math.floor((rawValue - range.min) / this.settings.step);
-        if ((rawValue - range.min) % this.settings.step > this.settings.step / 2 && steps < maxSteps) {
-          steps += 1;
-        }
-        return steps * this.settings.step + range.min;
-      } else {
-        return rawValue;
-      }
-    };
-
-    SimpleSlider.prototype.valueToRatio = function(value) {
-      var allowedVal, closest, closestIdx, idx, range, _i, _len, _ref;
-      if (this.settings.equalSteps) {
-        _ref = this.settings.allowedValues;
-        for (idx = _i = 0, _len = _ref.length; _i < _len; idx = ++_i) {
-          allowedVal = _ref[idx];
-          if (!(typeof closest !== "undefined" && closest !== null) || Math.abs(allowedVal - value) < Math.abs(closest - value)) {
-            closest = allowedVal;
-            closestIdx = idx;
-          }
-        }
-        if (this.settings.snapMid) {
-          return (closestIdx + 0.5) / this.settings.allowedValues.length;
-        } else {
-          return closestIdx / (this.settings.allowedValues.length - 1);
-        }
-      } else {
-        range = this.getRange();
-        return (value - range.min) / (range.max - range.min);
-      }
-    };
-
-    SimpleSlider.prototype.ratioToValue = function(ratio) {
-      var idx, range, rawValue, step, steps;
-      if (this.settings.equalSteps) {
-        steps = this.settings.allowedValues.length;
-        step = Math.round(ratio * steps - 0.5);
-        idx = Math.min(step, this.settings.allowedValues.length - 1);
-        return this.settings.allowedValues[idx];
-      } else {
-        range = this.getRange();
-        rawValue = ratio * (range.max - range.min) + range.min;
-        return this.nearestValidValue(rawValue);
-      }
-    };
-
-    SimpleSlider.prototype.valueChanged = function(value, ratio, trigger) {
-      var eventData;
-      if (value.toString() === this.value.toString()) {
-        return;
-      }
-      this.value = value;
-      eventData = {
-        value: value,
-        ratio: ratio,
-        position: ratio * this.slider.outerWidth(),
-        trigger: trigger,
-        el: this.slider
-      };
-      return this.input.val(value).trigger($.Event("change", eventData)).trigger("slider:changed", eventData);
-    };
-
-    return SimpleSlider;
-
-  })();
-  $.extend($.fn, {
-    simpleSlider: function() {
-      var params, publicMethods, settingsOrMethod;
-      settingsOrMethod = arguments[0], params = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
-      publicMethods = ["setRatio", "setValue", "setDisabled", ];
-      return $(this).each(function() {
-        var obj, settings;
-        if (settingsOrMethod && __indexOf.call(publicMethods, settingsOrMethod) >= 0) {
-          obj = $(this).data("slider-object");
-          return obj[settingsOrMethod].apply(obj, params);
-        } else {
-          settings = settingsOrMethod;
-          return $(this).data("slider-object", new SimpleSlider($(this), settings));
-        }
-      });
-    }
-  });
-  
-  /*
-  return $(function() {
-    return $("[data-slider]").each(function() {
-      var $el, allowedValues, settings, x;
-      $el = $(this);
-      return $el.simpleSlider();
-    });
-  });
-  */
-})(this.jQuery || this.Zepto, this);
diff --git a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.min.js b/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.min.js
deleted file mode 100644
index fbdb6e3..0000000
--- a/circle/dashboard/static/dashboard/loopj-jquery-simple-slider/js/simple-slider.min.js
+++ /dev/null
@@ -1,11 +0,0 @@
-/*
- * jQuery Simple Slider: Unobtrusive Numerical Slider
- * Version 1.0.0
- *
- * Copyright (c) 2013 James Smith (http://loopj.com)
- *
- * Licensed under the MIT license (http://mit-license.org/)
- *
- */
-
-var __slice=[].slice,__indexOf=[].indexOf||function(c){for(var b=0,a=this.length;b<a;b++){if(b in this&&this[b]===c){return b}}return -1};(function(c,a){var b;b=(function(){function d(e,f){var g,h=this;this.input=e;this.defaultOptions={animate:true,snapMid:false,classPrefix:null,classSuffix:null,theme:null,highlight:false,showScale:false};if(typeof f=="undefined"){f=this.loadDataOptions()}this.settings=c.extend({},this.defaultOptions,f);if(this.settings.theme){this.settings.classSuffix="-"+this.settings.theme}this.input.hide();this.slider=c("<div>").addClass("slider"+(this.settings.classSuffix||"")).css({position:"relative",userSelect:"none",boxSizing:"border-box"}).insertBefore(this.input);if(this.input.attr("id")){this.slider.attr("id",this.input.attr("id")+"-slider")}this.track=this.createDivElement("track").css({width:"100%"});if(this.settings.highlight){this.highlightTrack=this.createDivElement("highlight-track").css({width:"0"})}this.dragger=this.createDivElement("dragger");this.slider.css({minHeight:this.dragger.outerHeight(),marginLeft:this.dragger.outerWidth()/2,marginRight:this.dragger.outerWidth()/2});this.track.css({marginTop:this.track.outerHeight()/-2});if(this.settings.highlight){this.highlightTrack.css({marginTop:this.track.outerHeight()/-2})}this.dragger.css({marginTop:this.dragger.outerWidth()/-2,marginLeft:this.dragger.outerWidth()/-2});this.track.mousedown(function(i){return h.trackEvent(i)});if(this.settings.highlight){this.highlightTrack.mousedown(function(i){return h.trackEvent(i)})}this.dragger.mousedown(function(i){if(i.which!==1){return}h.dragging=true;h.dragger.addClass("dragging");h.domDrag(i.pageX,i.pageY);return false});c("body").mousemove(function(i){if(h.dragging){h.domDrag(i.pageX,i.pageY);return c("body").css({cursor:"pointer"})}}).mouseup(function(i){if(h.dragging){h.dragging=false;h.dragger.removeClass("dragging");return c("body").css({cursor:"auto"})}});this.pagePos=0;if(this.input.val()===""){this.value=this.getRange().min;this.input.val(this.value)}else{this.value=this.nearestValidValue(this.input.val())}this.setSliderPositionFromValue(this.value);g=this.valueToRatio(this.value);if(this.settings.showScale){this.scale=this.createDivElement("scale");this.minScale=this.createSpanElement("min-scale",this.scale);this.maxScale=this.createSpanElement("max-scale",this.scale);range=this.getRange();this.minScale.html(range.min);this.maxScale.html(range.max);this.scale.css("marginTop",function(i,j){return(parseInt(j,10)+this.previousSibling.offsetHeight/2)+"px"})}this.input.trigger("slider:ready",{value:this.value,ratio:g,position:g*this.slider.outerWidth(),el:this.slider})}d.prototype.loadDataOptions=function(){var e={};allowedValues=this.input.data("slider-values");if(allowedValues){e.allowedValues=(function(){var i,g,h,f;h=allowedValues.split(",");f=[];for(i=0,g=h.length;i<g;i++){x=h[i];f.push(parseFloat(x))}return f})()}if(this.input.data("slider-range")){e.range=this.input.data("slider-range").split(",")}if(this.input.data("slider-step")){e.step=this.input.data("slider-step")}e.snap=this.input.data("slider-snap");e.equalSteps=this.input.data("slider-equal-steps");if(this.input.data("slider-theme")){e.theme=this.input.data("slider-theme")}if(this.input.attr("data-slider-highlight")){e.highlight=this.input.data("slider-highlight")}if(this.input.data("slider-animate")!=null){e.animate=this.input.data("slider-animate")}if(this.input.data("slider-showscale")!=null){e.showScale=this.input.data("slider-showscale")}return e};d.prototype.createDivElement=function(f){var e;e=c("<div>").addClass(f).css({position:"absolute",top:"50%",userSelect:"none",cursor:"pointer"}).appendTo(this.slider);return e};d.prototype.createSpanElement=function(g,e){var f;f=c("<span>").addClass(g).appendTo(e);return f};d.prototype.setRatio=function(e){var f;e=Math.min(1,e);e=Math.max(0,e);f=this.ratioToValue(e);this.setSliderPositionFromValue(f);return this.valueChanged(f,e,"setRatio")};d.prototype.setValue=function(f){var e;f=this.nearestValidValue(f);e=this.valueToRatio(f);this.setSliderPositionFromValue(f);return this.valueChanged(f,e,"setValue")};d.prototype.trackEvent=function(f){if(f.which!==1){return}this.domDrag(f.pageX,f.pageY,true);this.dragging=true;return false};d.prototype.domDrag=function(i,g,e){var f,h,j;if(e==null){e=false}f=i-this.slider.offset().left;f=Math.min(this.slider.outerWidth(),f);f=Math.max(0,f);if(this.pagePos!==f){this.pagePos=f;h=f/this.slider.outerWidth();j=this.ratioToValue(h);this.valueChanged(j,h,"domDrag");if(this.settings.snap){return this.setSliderPositionFromValue(j,e)}else{return this.setSliderPosition(f,e)}}};d.prototype.setSliderPosition=function(e,f){if(f==null){f=false}if(f&&this.settings.animate){this.dragger.animate({left:e},200);if(this.settings.highlight){return this.highlightTrack.animate({width:e},200)}}else{this.dragger.css({left:e});if(this.settings.highlight){return this.highlightTrack.css({width:e})}}};d.prototype.setSliderPositionFromValue=function(g,e){var f;if(e==null){e=false}f=this.valueToRatio(g);return this.setSliderPosition(f*this.slider.outerWidth(),e)};d.prototype.getRange=function(){if(this.settings.allowedValues){return{min:Math.min.apply(Math,this.settings.allowedValues),max:Math.max.apply(Math,this.settings.allowedValues)}}else{if(this.settings.range){return{min:parseFloat(this.settings.range[0]),max:parseFloat(this.settings.range[1])}}else{return{min:0,max:1}}}};d.prototype.nearestValidValue=function(i){var h,g,f,e;f=this.getRange();i=Math.min(f.max,i);i=Math.max(f.min,i);if(this.settings.allowedValues){h=null;c.each(this.settings.allowedValues,function(){if(h===null||Math.abs(this-i)<Math.abs(h-i)){return h=this}});return h}else{if(this.settings.step){g=(f.max-f.min)/this.settings.step;e=Math.floor((i-f.min)/this.settings.step);if((i-f.min)%this.settings.step>this.settings.step/2&&e<g){e+=1}return e*this.settings.step+f.min}else{return i}}};d.prototype.valueToRatio=function(l){var f,e,j,m,i,g,k,h;if(this.settings.equalSteps){h=this.settings.allowedValues;for(m=g=0,k=h.length;g<k;m=++g){f=h[m];if(!(typeof e!=="undefined"&&e!==null)||Math.abs(f-l)<Math.abs(e-l)){e=f;j=m}}if(this.settings.snapMid){return(j+0.5)/this.settings.allowedValues.length}else{return j/(this.settings.allowedValues.length-1)}}else{i=this.getRange();return(l-i.min)/(i.max-i.min)}};d.prototype.ratioToValue=function(h){var e,g,j,i,f;if(this.settings.equalSteps){f=this.settings.allowedValues.length;i=Math.round(h*f-0.5);e=Math.min(i,this.settings.allowedValues.length-1);return this.settings.allowedValues[e]}else{g=this.getRange();j=h*(g.max-g.min)+g.min;return this.nearestValidValue(j)}};d.prototype.valueChanged=function(h,f,e){var g;if(h.toString()===this.value.toString()){return}this.value=h;g={value:h,ratio:f,position:f*this.slider.outerWidth(),trigger:e,el:this.slider};return this.input.val(h).trigger(c.Event("change",g)).trigger("slider:changed",g)};return d})();c.extend(c.fn,{simpleSlider:function(){var e,d,f;f=arguments[0],e=2<=arguments.length?__slice.call(arguments,1):[];d=["setRatio","setValue"];return c(this).each(function(){var h,g;if(f&&__indexOf.call(d,f)>=0){h=c(this).data("slider-object");return h[f].apply(h,e)}else{g=f;return c(this).data("slider-object",new b(c(this),g))}})}});return c(function(){return c("[data-slider]").each(function(){var e,g,f,d;e=c(this);return e.simpleSlider()})})})(this.jQuery||this.Zepto,this);
diff --git a/circle/dashboard/static/dashboard/node-details.js b/circle/dashboard/static/dashboard/node-details.js
index 832a33c..9725ce6 100644
--- a/circle/dashboard/static/dashboard/node-details.js
+++ b/circle/dashboard/static/dashboard/node-details.js
@@ -17,7 +17,7 @@ $(function() {
       success: function(data, textStatus, xhr) {
         $("#node-details-h1-name").text(data['new_name']).show();
         $('#node-details-rename').hide();
-        // addMessage(data['message'], "success");
+        // addMessage(data.message, "success");
       },
       error: function(xhr, textStatus, error) {
         addMessage("Error during renaming!", "danger");
@@ -34,7 +34,7 @@ $(function() {
   $('.node-enable').click(function() {
     var node_pk = $(this).data('node-pk');
     var dir = window.location.pathname.indexOf('list') == -1;
-    addModalConfirmation(changeNodeStatus, 
+    addModalConfirmation(changeNodeStatus,
       { 'url': '/dashboard/node/status/' + node_pk + '/',
         'data': [],
         'pk': node_pk,
@@ -51,17 +51,17 @@ $(function() {
     $.ajax({
       type: 'POST',
       url: location.href,
-      headers: {"X-CSRFToken": getCookie('csrftoken')}, 
+      headers: {"X-CSRFToken": getCookie('csrftoken')},
       data: {'to_remove': to_remove},
       success: function(re) {
-        if(re['message'].toLowerCase() == "success") {
+        if(re.message.toLowerCase() == "success") {
           $(clicked).closest(".label").fadeOut(500, function() {
             $(this).remove();
           });
         }
       },
       error: function() {
-        addMessage(re['message'], 'danger');
+        addMessage(re.message, 'danger');
       }
 
     });
@@ -73,18 +73,18 @@ $(function() {
 function changeNodeStatus(data) {
   $.ajax({
     type: 'POST',
-    url: data['url'],
+    url: data.url,
     headers: {"X-CSRFToken": getCookie('csrftoken')},
     success: function(re, textStatus, xhr) {
-      if(!data['redirect']) {
+      if(!data.redirect) {
         selected = [];
-        addMessage(re['message'], 'success');
+        addMessage(re.message, 'success');
       } else {
         window.location.replace('/dashboard');
       }
     },
     error: function(xhr, textStatus, error) {
-      addMessage('Uh oh :(', 'danger')
+      addMessage('Uh oh :(', 'danger');
     }
   });
 }
diff --git a/circle/dashboard/static/dashboard/node-list.js b/circle/dashboard/static/dashboard/node-list.js
index 9fbea33..fcc3283 100644
--- a/circle/dashboard/static/dashboard/node-list.js
+++ b/circle/dashboard/static/dashboard/node-list.js
@@ -4,19 +4,16 @@ $(function() {
   });
 
   // find disabled nodes, set danger (red) on the rows
-  function colortable() 
+  function colortable()
   {
-	var tr= $('.false').closest("tr");
-	tr.addClass('danger');
-	var tr= $('.true').closest("tr");
-	tr.removeClass('danger');
+	$('.false').closest("tr").addClass('danger');
+	$('.true').closest("tr").removeClass('danger');
   }
 
-
   function statuschangeSuccess(tr){
    var tspan=tr.children('.enabled').children();
     var buttons=tr.children('.actions').children('.btn-group').children('.dropdown-menu').children('li').children('.node-enable');
- 
+
     buttons.each(function(index){
       if ($(this).css("display")=="block"){
           $(this).css("display","none");
@@ -24,12 +21,12 @@ $(function() {
       else{
          $(this).css("display","block");
         }
-    }); 
+    });
     if(tspan.hasClass("false")){
           tspan.removeClass("false");
 	  tspan.addClass("true");
  	  tspan.text("✔");
-      } 
+      }
   else{
   	  tspan.removeClass("true");
 	  tspan.addClass("false");
diff --git a/circle/dashboard/static/dashboard/novnc/base64.js b/circle/dashboard/static/dashboard/novnc/base64.js
deleted file mode 100644
index 5a6890a..0000000
--- a/circle/dashboard/static/dashboard/novnc/base64.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-// From: http://hg.mozilla.org/mozilla-central/raw-file/ec10630b1a54/js/src/devtools/jint/sunspider/string-base64.js
-
-/*jslint white: false, bitwise: false, plusplus: false */
-/*global console */
-
-var Base64 = {
-
-/* Convert data (an array of integers) to a Base64 string. */
-toBase64Table : 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split(''),
-base64Pad     : '=',
-
-encode: function (data) {
-    "use strict";
-    var result = '';
-    var toBase64Table = Base64.toBase64Table;
-    var length = data.length
-    var lengthpad = (length%3);
-    var i = 0, j = 0;
-    // Convert every three bytes to 4 ascii characters.
-  /* BEGIN LOOP */
-    for (i = 0; i < (length - 2); i += 3) {
-        result += toBase64Table[data[i] >> 2];
-        result += toBase64Table[((data[i] & 0x03) << 4) + (data[i+1] >> 4)];
-        result += toBase64Table[((data[i+1] & 0x0f) << 2) + (data[i+2] >> 6)];
-        result += toBase64Table[data[i+2] & 0x3f];
-    }
-  /* END LOOP */
-
-    // Convert the remaining 1 or 2 bytes, pad out to 4 characters.
-    if (lengthpad === 2) {
-        j = length - lengthpad;
-        result += toBase64Table[data[j] >> 2];
-        result += toBase64Table[((data[j] & 0x03) << 4) + (data[j+1] >> 4)];
-        result += toBase64Table[(data[j+1] & 0x0f) << 2];
-        result += toBase64Table[64];
-    } else if (lengthpad === 1) {
-        j = length - lengthpad;
-        result += toBase64Table[data[j] >> 2];
-        result += toBase64Table[(data[j] & 0x03) << 4];
-        result += toBase64Table[64];
-        result += toBase64Table[64];
-    }
-
-    return result;
-},
-
-/* Convert Base64 data to a string */
-toBinaryTable : [
-    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
-    -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
-    52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1, 0,-1,-1,
-    -1, 0, 1, 2,  3, 4, 5, 6,  7, 8, 9,10, 11,12,13,14,
-    15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1,
-    -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40,
-    41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1
-],
-
-decode: function (data, offset) {
-    "use strict";
-    offset = typeof(offset) !== 'undefined' ? offset : 0;
-    var toBinaryTable = Base64.toBinaryTable;
-    var base64Pad = Base64.base64Pad;
-    var result, result_length, idx, i, c, padding;
-    var leftbits = 0; // number of bits decoded, but yet to be appended
-    var leftdata = 0; // bits decoded, but yet to be appended
-    var data_length = data.indexOf('=') - offset;
-
-    if (data_length < 0) { data_length = data.length - offset; }
-
-    /* Every four characters is 3 resulting numbers */
-    result_length = (data_length >> 2) * 3 + Math.floor((data_length%4)/1.5);
-    result = new Array(result_length);
-
-    // Convert one by one.
-  /* BEGIN LOOP */
-    for (idx = 0, i = offset; i < data.length; i++) {
-        c = toBinaryTable[data.charCodeAt(i) & 0x7f];
-        padding = (data.charAt(i) === base64Pad);
-        // Skip illegal characters and whitespace
-        if (c === -1) {
-            console.error("Illegal character code " + data.charCodeAt(i) + " at position " + i);
-            continue;
-        }
-        
-        // Collect data into leftdata, update bitcount
-        leftdata = (leftdata << 6) | c;
-        leftbits += 6;
-
-        // If we have 8 or more bits, append 8 bits to the result
-        if (leftbits >= 8) {
-            leftbits -= 8;
-            // Append if not padding.
-            if (!padding) {
-                result[idx++] = (leftdata >> leftbits) & 0xff;
-            }
-            leftdata &= (1 << leftbits) - 1;
-        }
-    }
-  /* END LOOP */
-
-    // If there are any bits left, the base64 string was corrupted
-    if (leftbits) {
-        throw {name: 'Base64-Error', 
-               message: 'Corrupted base64 string'};
-    }
-
-    return result;
-}
-
-}; /* End of Base64 namespace */
diff --git a/circle/dashboard/static/dashboard/novnc/des.js b/circle/dashboard/static/dashboard/novnc/des.js
deleted file mode 100644
index 1f95285..0000000
--- a/circle/dashboard/static/dashboard/novnc/des.js
+++ /dev/null
@@ -1,273 +0,0 @@
-/*
- * Ported from Flashlight VNC ActionScript implementation:
- *     http://www.wizhelp.com/flashlight-vnc/
- *
- * Full attribution follows:
- *
- * -------------------------------------------------------------------------
- *
- * This DES class has been extracted from package Acme.Crypto for use in VNC.
- * The unnecessary odd parity code has been removed.
- *
- * These changes are:
- *  Copyright (C) 1999 AT&T Laboratories Cambridge.  All Rights Reserved.
- *
- * This software is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
-
- * DesCipher - the DES encryption method
- *
- * The meat of this code is by Dave Zimmerman <dzimm@widget.com>, and is:
- *
- * Copyright (c) 1996 Widget Workshop, Inc. All Rights Reserved.
- *
- * Permission to use, copy, modify, and distribute this software
- * and its documentation for NON-COMMERCIAL or COMMERCIAL purposes and
- * without fee is hereby granted, provided that this copyright notice is kept 
- * intact. 
- * 
- * WIDGET WORKSHOP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
- * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
- * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
- * PARTICULAR PURPOSE, OR NON-INFRINGEMENT. WIDGET WORKSHOP SHALL NOT BE LIABLE
- * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
- * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
- * 
- * THIS SOFTWARE IS NOT DESIGNED OR INTENDED FOR USE OR RESALE AS ON-LINE
- * CONTROL EQUIPMENT IN HAZARDOUS ENVIRONMENTS REQUIRING FAIL-SAFE
- * PERFORMANCE, SUCH AS IN THE OPERATION OF NUCLEAR FACILITIES, AIRCRAFT
- * NAVIGATION OR COMMUNICATION SYSTEMS, AIR TRAFFIC CONTROL, DIRECT LIFE
- * SUPPORT MACHINES, OR WEAPONS SYSTEMS, IN WHICH THE FAILURE OF THE
- * SOFTWARE COULD LEAD DIRECTLY TO DEATH, PERSONAL INJURY, OR SEVERE
- * PHYSICAL OR ENVIRONMENTAL DAMAGE ("HIGH RISK ACTIVITIES").  WIDGET WORKSHOP
- * SPECIFICALLY DISCLAIMS ANY EXPRESS OR IMPLIED WARRANTY OF FITNESS FOR
- * HIGH RISK ACTIVITIES.
- *
- *
- * The rest is:
- *
- * Copyright (C) 1996 by Jef Poskanzer <jef@acme.com>.  All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * Visit the ACME Labs Java page for up-to-date versions of this and other
- * fine Java utilities: http://www.acme.com/java/
- */
-
-"use strict";
-/*jslint white: false, bitwise: false, plusplus: false */
-
-function DES(passwd) {
-
-// Tables, permutations, S-boxes, etc.
-var PC2 = [13,16,10,23, 0, 4, 2,27,14, 5,20, 9,22,18,11, 3,
-           25, 7,15, 6,26,19,12, 1,40,51,30,36,46,54,29,39,
-           50,44,32,47,43,48,38,55,33,52,45,41,49,35,28,31 ],
-    totrot = [ 1, 2, 4, 6, 8,10,12,14,15,17,19,21,23,25,27,28],
-    z = 0x0, a,b,c,d,e,f, SP1,SP2,SP3,SP4,SP5,SP6,SP7,SP8,
-    keys = [];
-
-a=1<<16; b=1<<24; c=a|b; d=1<<2; e=1<<10; f=d|e;
-SP1 = [c|e,z|z,a|z,c|f,c|d,a|f,z|d,a|z,z|e,c|e,c|f,z|e,b|f,c|d,b|z,z|d,
-       z|f,b|e,b|e,a|e,a|e,c|z,c|z,b|f,a|d,b|d,b|d,a|d,z|z,z|f,a|f,b|z,
-       a|z,c|f,z|d,c|z,c|e,b|z,b|z,z|e,c|d,a|z,a|e,b|d,z|e,z|d,b|f,a|f,
-       c|f,a|d,c|z,b|f,b|d,z|f,a|f,c|e,z|f,b|e,b|e,z|z,a|d,a|e,z|z,c|d];
-a=1<<20; b=1<<31; c=a|b; d=1<<5; e=1<<15; f=d|e;
-SP2 = [c|f,b|e,z|e,a|f,a|z,z|d,c|d,b|f,b|d,c|f,c|e,b|z,b|e,a|z,z|d,c|d,
-       a|e,a|d,b|f,z|z,b|z,z|e,a|f,c|z,a|d,b|d,z|z,a|e,z|f,c|e,c|z,z|f,
-       z|z,a|f,c|d,a|z,b|f,c|z,c|e,z|e,c|z,b|e,z|d,c|f,a|f,z|d,z|e,b|z,
-       z|f,c|e,a|z,b|d,a|d,b|f,b|d,a|d,a|e,z|z,b|e,z|f,b|z,c|d,c|f,a|e];
-a=1<<17; b=1<<27; c=a|b; d=1<<3; e=1<<9; f=d|e;
-SP3 = [z|f,c|e,z|z,c|d,b|e,z|z,a|f,b|e,a|d,b|d,b|d,a|z,c|f,a|d,c|z,z|f,
-       b|z,z|d,c|e,z|e,a|e,c|z,c|d,a|f,b|f,a|e,a|z,b|f,z|d,c|f,z|e,b|z,
-       c|e,b|z,a|d,z|f,a|z,c|e,b|e,z|z,z|e,a|d,c|f,b|e,b|d,z|e,z|z,c|d,
-       b|f,a|z,b|z,c|f,z|d,a|f,a|e,b|d,c|z,b|f,z|f,c|z,a|f,z|d,c|d,a|e];
-a=1<<13; b=1<<23; c=a|b; d=1<<0; e=1<<7; f=d|e;
-SP4 = [c|d,a|f,a|f,z|e,c|e,b|f,b|d,a|d,z|z,c|z,c|z,c|f,z|f,z|z,b|e,b|d,
-       z|d,a|z,b|z,c|d,z|e,b|z,a|d,a|e,b|f,z|d,a|e,b|e,a|z,c|e,c|f,z|f,
-       b|e,b|d,c|z,c|f,z|f,z|z,z|z,c|z,a|e,b|e,b|f,z|d,c|d,a|f,a|f,z|e,
-       c|f,z|f,z|d,a|z,b|d,a|d,c|e,b|f,a|d,a|e,b|z,c|d,z|e,b|z,a|z,c|e];
-a=1<<25; b=1<<30; c=a|b; d=1<<8; e=1<<19; f=d|e;
-SP5 = [z|d,a|f,a|e,c|d,z|e,z|d,b|z,a|e,b|f,z|e,a|d,b|f,c|d,c|e,z|f,b|z,
-       a|z,b|e,b|e,z|z,b|d,c|f,c|f,a|d,c|e,b|d,z|z,c|z,a|f,a|z,c|z,z|f,
-       z|e,c|d,z|d,a|z,b|z,a|e,c|d,b|f,a|d,b|z,c|e,a|f,b|f,z|d,a|z,c|e,
-       c|f,z|f,c|z,c|f,a|e,z|z,b|e,c|z,z|f,a|d,b|d,z|e,z|z,b|e,a|f,b|d];
-a=1<<22; b=1<<29; c=a|b; d=1<<4; e=1<<14; f=d|e;
-SP6 = [b|d,c|z,z|e,c|f,c|z,z|d,c|f,a|z,b|e,a|f,a|z,b|d,a|d,b|e,b|z,z|f,
-       z|z,a|d,b|f,z|e,a|e,b|f,z|d,c|d,c|d,z|z,a|f,c|e,z|f,a|e,c|e,b|z,
-       b|e,z|d,c|d,a|e,c|f,a|z,z|f,b|d,a|z,b|e,b|z,z|f,b|d,c|f,a|e,c|z,
-       a|f,c|e,z|z,c|d,z|d,z|e,c|z,a|f,z|e,a|d,b|f,z|z,c|e,b|z,a|d,b|f];
-a=1<<21; b=1<<26; c=a|b; d=1<<1; e=1<<11; f=d|e;
-SP7 = [a|z,c|d,b|f,z|z,z|e,b|f,a|f,c|e,c|f,a|z,z|z,b|d,z|d,b|z,c|d,z|f,
-       b|e,a|f,a|d,b|e,b|d,c|z,c|e,a|d,c|z,z|e,z|f,c|f,a|e,z|d,b|z,a|e,
-       b|z,a|e,a|z,b|f,b|f,c|d,c|d,z|d,a|d,b|z,b|e,a|z,c|e,z|f,a|f,c|e,
-       z|f,b|d,c|f,c|z,a|e,z|z,z|d,c|f,z|z,a|f,c|z,z|e,b|d,b|e,z|e,a|d];
-a=1<<18; b=1<<28; c=a|b; d=1<<6; e=1<<12; f=d|e;
-SP8 = [b|f,z|e,a|z,c|f,b|z,b|f,z|d,b|z,a|d,c|z,c|f,a|e,c|e,a|f,z|e,z|d,
-       c|z,b|d,b|e,z|f,a|e,a|d,c|d,c|e,z|f,z|z,z|z,c|d,b|d,b|e,a|f,a|z,
-       a|f,a|z,c|e,z|e,z|d,c|d,z|e,a|f,b|e,z|d,b|d,c|z,c|d,b|z,a|z,b|f,
-       z|z,c|f,a|d,b|d,c|z,b|e,b|f,z|z,c|f,a|e,a|e,z|f,z|f,a|d,b|z,c|e];
-
-// Set the key.
-function setKeys(keyBlock) {
-    var i, j, l, m, n, o, pc1m = [], pcr = [], kn = [],
-        raw0, raw1, rawi, KnLi;
-
-    for (j = 0, l = 56; j < 56; ++j, l-=8) {
-        l += l<-5 ? 65 : l<-3 ? 31 : l<-1 ? 63 : l===27 ? 35 : 0; // PC1
-        m = l & 0x7;
-        pc1m[j] = ((keyBlock[l >>> 3] & (1<<m)) !== 0) ? 1: 0;
-    }
-
-    for (i = 0; i < 16; ++i) {
-        m = i << 1;
-        n = m + 1;
-        kn[m] = kn[n] = 0;
-        for (o=28; o<59; o+=28) {
-            for (j = o-28; j < o; ++j) {
-                l = j + totrot[i];
-                if (l < o) {
-                    pcr[j] = pc1m[l];
-                } else {
-                    pcr[j] = pc1m[l - 28];
-                }
-            }
-        }
-        for (j = 0; j < 24; ++j) {
-            if (pcr[PC2[j]] !== 0) {
-                kn[m] |= 1<<(23-j);
-            }
-            if (pcr[PC2[j + 24]] !== 0) {
-                kn[n] |= 1<<(23-j);
-            }
-        }
-    }
-
-    // cookey
-    for (i = 0, rawi = 0, KnLi = 0; i < 16; ++i) {
-        raw0 = kn[rawi++];
-        raw1 = kn[rawi++];
-        keys[KnLi] = (raw0 & 0x00fc0000) << 6;
-        keys[KnLi] |= (raw0 & 0x00000fc0) << 10;
-        keys[KnLi] |= (raw1 & 0x00fc0000) >>> 10;
-        keys[KnLi] |= (raw1 & 0x00000fc0) >>> 6;
-        ++KnLi;
-        keys[KnLi] = (raw0 & 0x0003f000) << 12;
-        keys[KnLi] |= (raw0 & 0x0000003f) << 16;
-        keys[KnLi] |= (raw1 & 0x0003f000) >>> 4;
-        keys[KnLi] |= (raw1 & 0x0000003f);
-        ++KnLi;
-    }
-}
-
-// Encrypt 8 bytes of text
-function enc8(text) {
-    var i = 0, b = text.slice(), fval, keysi = 0,
-        l, r, x; // left, right, accumulator
-
-    // Squash 8 bytes to 2 ints
-    l = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
-    r = b[i++]<<24 | b[i++]<<16 | b[i++]<<8 | b[i++];
-
-    x = ((l >>> 4) ^ r) & 0x0f0f0f0f;
-    r ^= x;
-    l ^= (x << 4);
-    x = ((l >>> 16) ^ r) & 0x0000ffff;
-    r ^= x;
-    l ^= (x << 16);
-    x = ((r >>> 2) ^ l) & 0x33333333;
-    l ^= x;
-    r ^= (x << 2);
-    x = ((r >>> 8) ^ l) & 0x00ff00ff;
-    l ^= x;
-    r ^= (x << 8);
-    r = (r << 1) | ((r >>> 31) & 1);
-    x = (l ^ r) & 0xaaaaaaaa;
-    l ^= x;
-    r ^= x;
-    l = (l << 1) | ((l >>> 31) & 1);
-
-    for (i = 0; i < 8; ++i) {
-        x = (r << 28) | (r >>> 4);
-        x ^= keys[keysi++];
-        fval =  SP7[x & 0x3f];
-        fval |= SP5[(x >>> 8) & 0x3f];
-        fval |= SP3[(x >>> 16) & 0x3f];
-        fval |= SP1[(x >>> 24) & 0x3f];
-        x = r ^ keys[keysi++];
-        fval |= SP8[x & 0x3f];
-        fval |= SP6[(x >>> 8) & 0x3f];
-        fval |= SP4[(x >>> 16) & 0x3f];
-        fval |= SP2[(x >>> 24) & 0x3f];
-        l ^= fval;
-        x = (l << 28) | (l >>> 4);
-        x ^= keys[keysi++];
-        fval =  SP7[x & 0x3f];
-        fval |= SP5[(x >>> 8) & 0x3f];
-        fval |= SP3[(x >>> 16) & 0x3f];
-        fval |= SP1[(x >>> 24) & 0x3f];
-        x = l ^ keys[keysi++];
-        fval |= SP8[x & 0x0000003f];
-        fval |= SP6[(x >>> 8) & 0x3f];
-        fval |= SP4[(x >>> 16) & 0x3f];
-        fval |= SP2[(x >>> 24) & 0x3f];
-        r ^= fval;
-    }
-
-    r = (r << 31) | (r >>> 1);
-    x = (l ^ r) & 0xaaaaaaaa;
-    l ^= x;
-    r ^= x;
-    l = (l << 31) | (l >>> 1);
-    x = ((l >>> 8) ^ r) & 0x00ff00ff;
-    r ^= x;
-    l ^= (x << 8);
-    x = ((l >>> 2) ^ r) & 0x33333333;
-    r ^= x;
-    l ^= (x << 2);
-    x = ((r >>> 16) ^ l) & 0x0000ffff;
-    l ^= x;
-    r ^= (x << 16);
-    x = ((r >>> 4) ^ l) & 0x0f0f0f0f;
-    l ^= x;
-    r ^= (x << 4);
-
-    // Spread ints to bytes
-    x = [r, l];
-    for (i = 0; i < 8; i++) {
-        b[i] = (x[i>>>2] >>> (8*(3 - (i%4)))) % 256;
-        if (b[i] < 0) { b[i] += 256; } // unsigned
-    }
-    return b;
-}
-
-// Encrypt 16 bytes of text using passwd as key
-function encrypt(t) {
-    return enc8(t.slice(0,8)).concat(enc8(t.slice(8,16)));
-}
-
-setKeys(passwd);             // Setup keys
-return {'encrypt': encrypt}; // Public interface
-
-} // function DES
diff --git a/circle/dashboard/static/dashboard/novnc/display.js b/circle/dashboard/static/dashboard/novnc/display.js
deleted file mode 100644
index 9f2d6b8..0000000
--- a/circle/dashboard/static/dashboard/novnc/display.js
+++ /dev/null
@@ -1,770 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-/*jslint browser: true, white: false, bitwise: false */
-/*global Util, Base64, changeCursor */
-
-function Display(defaults) {
-"use strict";
-
-var that           = {},  // Public API methods
-    conf           = {},  // Configuration attributes
-
-    // Private Display namespace variables
-    c_ctx          = null,
-    c_forceCanvas  = false,
-
-    // Queued drawing actions for in-order rendering
-    renderQ        = [],
-
-    // Predefine function variables (jslint)
-    imageDataGet, rgbImageData, bgrxImageData, cmapImageData,
-    setFillColor, rescale, scan_renderQ,
-
-    // The full frame buffer (logical canvas) size
-    fb_width        = 0,
-    fb_height       = 0,
-    // The visible "physical canvas" viewport
-    viewport       = {'x': 0, 'y': 0, 'w' : 0, 'h' : 0 },
-    cleanRect      = {'x1': 0, 'y1': 0, 'x2': -1, 'y2': -1},
-
-    c_prevStyle    = "",
-    tile           = null,
-    tile16x16      = null,
-    tile_x         = 0,
-    tile_y         = 0;
-
-
-// Configuration attributes
-Util.conf_defaults(conf, that, defaults, [
-    ['target',      'wo', 'dom',  null, 'Canvas element for rendering'],
-    ['context',     'ro', 'raw',  null, 'Canvas 2D context for rendering (read-only)'],
-    ['logo',        'rw', 'raw',  null, 'Logo to display when cleared: {"width": width, "height": height, "data": data}'],
-    ['true_color',  'rw', 'bool', true, 'Use true-color pixel data'],
-    ['colourMap',   'rw', 'arr',  [], 'Colour map array (when not true-color)'],
-    ['scale',       'rw', 'float', 1.0, 'Display area scale factor 0.0 - 1.0'],
-    ['viewport',    'rw', 'bool', false, 'Use a viewport set with viewportChange()'],
-    ['width',       'rw', 'int', null, 'Display area width'],
-    ['height',      'rw', 'int', null, 'Display area height'],
-
-    ['render_mode', 'ro', 'str', '', 'Canvas rendering mode (read-only)'],
-
-    ['prefer_js',   'rw', 'str', null, 'Prefer Javascript over canvas methods'],
-    ['cursor_uri',  'rw', 'raw', null, 'Can we render cursor using data URI']
-    ]);
-
-// Override some specific getters/setters
-that.get_context = function () { return c_ctx; };
-
-that.set_scale = function(scale) { rescale(scale); };
-
-that.set_width = function (val) { that.resize(val, fb_height); };
-that.get_width = function() { return fb_width; };
-
-that.set_height = function (val) { that.resize(fb_width, val); };
-that.get_height = function() { return fb_height; };
-
-
-
-//
-// Private functions
-//
-
-// Create the public API interface
-function constructor() {
-    Util.Debug(">> Display.constructor");
-
-    var c, func, i, curDat, curSave,
-        has_imageData = false, UE = Util.Engine;
-
-    if (! conf.target) { throw("target must be set"); }
-
-    if (typeof conf.target === 'string') {
-        throw("target must be a DOM element");
-    }
-
-    c = conf.target;
-
-    if (! c.getContext) { throw("no getContext method"); }
-
-    if (! c_ctx) { c_ctx = c.getContext('2d'); }
-
-    Util.Debug("User Agent: " + navigator.userAgent);
-    if (UE.gecko) { Util.Debug("Browser: gecko " + UE.gecko); }
-    if (UE.webkit) { Util.Debug("Browser: webkit " + UE.webkit); }
-    if (UE.trident) { Util.Debug("Browser: trident " + UE.trident); }
-    if (UE.presto) { Util.Debug("Browser: presto " + UE.presto); }
-
-    that.clear();
-
-    // Check canvas features
-    if ('createImageData' in c_ctx) {
-        conf.render_mode = "canvas rendering";
-    } else {
-        throw("Canvas does not support createImageData");
-    }
-    if (conf.prefer_js === null) {
-        Util.Info("Prefering javascript operations");
-        conf.prefer_js = true;
-    }
-
-    // Initialize cached tile imageData
-    tile16x16 = c_ctx.createImageData(16, 16);
-
-    /*
-     * Determine browser support for setting the cursor via data URI
-     * scheme
-     */
-    curDat = [];
-    for (i=0; i < 8 * 8 * 4; i += 1) {
-        curDat.push(255);
-    }
-    try {
-        curSave = c.style.cursor;
-        changeCursor(conf.target, curDat, curDat, 2, 2, 8, 8);
-        if (c.style.cursor) {
-            if (conf.cursor_uri === null) {
-                conf.cursor_uri = true;
-            }
-            Util.Info("Data URI scheme cursor supported");
-        } else {
-            if (conf.cursor_uri === null) {
-                conf.cursor_uri = false;
-            }
-            Util.Warn("Data URI scheme cursor not supported");
-        }
-        c.style.cursor = curSave;
-    } catch (exc2) { 
-        Util.Error("Data URI scheme cursor test exception: " + exc2);
-        conf.cursor_uri = false;
-    }
-
-    Util.Debug("<< Display.constructor");
-    return that ;
-}
-
-rescale = function(factor) {
-    var c, tp, x, y, 
-        properties = ['transform', 'WebkitTransform', 'MozTransform', null];
-    c = conf.target;
-    tp = properties.shift();
-    while (tp) {
-        if (typeof c.style[tp] !== 'undefined') {
-            break;
-        }
-        tp = properties.shift();
-    }
-
-    if (tp === null) {
-        Util.Debug("No scaling support");
-        return;
-    }
-
-
-    if (typeof(factor) === "undefined") {
-        factor = conf.scale;
-    } else if (factor > 1.0) {
-        factor = 1.0;
-    } else if (factor < 0.1) {
-        factor = 0.1;
-    }
-
-    if (conf.scale === factor) {
-        //Util.Debug("Display already scaled to '" + factor + "'");
-        return;
-    }
-
-    conf.scale = factor;
-    x = c.width - c.width * factor;
-    y = c.height - c.height * factor;
-    c.style[tp] = "scale(" + conf.scale + ") translate(-" + x + "px, -" + y + "px)";
-};
-
-setFillColor = function(color) {
-    var bgr, newStyle;
-    if (conf.true_color) {
-        bgr = color;
-    } else {
-        bgr = conf.colourMap[color[0]];
-    }
-    newStyle = "rgb(" + bgr[2] + "," + bgr[1] + "," + bgr[0] + ")";
-    if (newStyle !== c_prevStyle) {
-        c_ctx.fillStyle = newStyle;
-        c_prevStyle = newStyle;
-    }
-};
-
-
-//
-// Public API interface functions
-//
-
-// Shift and/or resize the visible viewport
-that.viewportChange = function(deltaX, deltaY, width, height) {
-    var c = conf.target, v = viewport, cr = cleanRect,
-        saveImg = null, saveStyle, x1, y1, vx2, vy2, w, h;
-
-    if (!conf.viewport) {
-        Util.Debug("Setting viewport to full display region");
-        deltaX = -v.w; // Clamped later if out of bounds
-        deltaY = -v.h; // Clamped later if out of bounds
-        width = fb_width;
-        height = fb_height;
-    }
-
-    if (typeof(deltaX) === "undefined") { deltaX = 0; }
-    if (typeof(deltaY) === "undefined") { deltaY = 0; }
-    if (typeof(width) === "undefined") { width = v.w; }
-    if (typeof(height) === "undefined") { height = v.h; }
-
-    // Size change
-
-    if (width > fb_width) { width = fb_width; }
-    if (height > fb_height) { height = fb_height; }
-
-    if ((v.w !== width) || (v.h !== height)) {
-        // Change width
-        if ((width < v.w) && (cr.x2 > v.x + width -1)) {
-            cr.x2 = v.x + width - 1;
-        }
-        v.w = width;
-
-        // Change height
-        if ((height < v.h) && (cr.y2 > v.y + height -1)) {
-            cr.y2 = v.y + height - 1;
-        }
-        v.h = height;
-
-
-        if (v.w > 0 && v.h > 0 && c.width > 0 && c.height > 0) {
-            saveImg = c_ctx.getImageData(0, 0,
-                    (c.width < v.w) ? c.width : v.w,
-                    (c.height < v.h) ? c.height : v.h);
-        }
-
-        c.width = v.w;
-        c.height = v.h;
-
-        if (saveImg) {
-            c_ctx.putImageData(saveImg, 0, 0);
-        }
-    }
-
-    vx2 = v.x + v.w - 1;
-    vy2 = v.y + v.h - 1;
-
-
-    // Position change
-
-    if ((deltaX < 0) && ((v.x + deltaX) < 0)) {
-        deltaX = - v.x;
-    }
-    if ((vx2 + deltaX) >= fb_width) {
-        deltaX -= ((vx2 + deltaX) - fb_width + 1);
-    }
-
-    if ((v.y + deltaY) < 0) {
-        deltaY = - v.y;
-    }
-    if ((vy2 + deltaY) >= fb_height) {
-        deltaY -= ((vy2 + deltaY) - fb_height + 1);
-    }
-
-    if ((deltaX === 0) && (deltaY === 0)) {
-        //Util.Debug("skipping viewport change");
-        return;
-    }
-    Util.Debug("viewportChange deltaX: " + deltaX + ", deltaY: " + deltaY);
-
-    v.x += deltaX;
-    vx2 += deltaX;
-    v.y += deltaY;
-    vy2 += deltaY;
-
-    // Update the clean rectangle
-    if (v.x > cr.x1) {
-        cr.x1 = v.x;
-    }
-    if (vx2 < cr.x2) {
-        cr.x2 = vx2;
-    }
-    if (v.y > cr.y1) {
-        cr.y1 = v.y;
-    }
-    if (vy2 < cr.y2) {
-        cr.y2 = vy2;
-    }
-
-    if (deltaX < 0) {
-        // Shift viewport left, redraw left section
-        x1 = 0;
-        w = - deltaX;
-    } else {
-        // Shift viewport right, redraw right section
-        x1 = v.w - deltaX;
-        w = deltaX;
-    }
-    if (deltaY < 0) {
-        // Shift viewport up, redraw top section
-        y1 = 0;
-        h = - deltaY;
-    } else {
-        // Shift viewport down, redraw bottom section
-        y1 = v.h - deltaY;
-        h = deltaY;
-    }
-
-    // Copy the valid part of the viewport to the shifted location
-    saveStyle = c_ctx.fillStyle;
-    c_ctx.fillStyle = "rgb(255,255,255)";
-    if (deltaX !== 0) {
-        //that.copyImage(0, 0, -deltaX, 0, v.w, v.h);
-        //that.fillRect(x1, 0, w, v.h, [255,255,255]);
-        c_ctx.drawImage(c, 0, 0, v.w, v.h, -deltaX, 0, v.w, v.h);
-        c_ctx.fillRect(x1, 0, w, v.h);
-    }
-    if (deltaY !== 0) {
-        //that.copyImage(0, 0, 0, -deltaY, v.w, v.h);
-        //that.fillRect(0, y1, v.w, h, [255,255,255]);
-        c_ctx.drawImage(c, 0, 0, v.w, v.h, 0, -deltaY, v.w, v.h);
-        c_ctx.fillRect(0, y1, v.w, h);
-    }
-    c_ctx.fillStyle = saveStyle;
-};
-
-
-// Return a map of clean and dirty areas of the viewport and reset the
-// tracking of clean and dirty areas.
-//
-// Returns: {'cleanBox':   {'x': x, 'y': y, 'w': w, 'h': h},
-//           'dirtyBoxes': [{'x': x, 'y': y, 'w': w, 'h': h}, ...]}
-that.getCleanDirtyReset = function() {
-    var v = viewport, c = cleanRect, cleanBox, dirtyBoxes = [],
-        vx2 = v.x + v.w - 1, vy2 = v.y + v.h - 1;
-
-
-    // Copy the cleanRect
-    cleanBox = {'x': c.x1, 'y': c.y1,
-                'w': c.x2 - c.x1 + 1, 'h': c.y2 - c.y1 + 1};
-
-    if ((c.x1 >= c.x2) || (c.y1 >= c.y2)) {
-        // Whole viewport is dirty
-        dirtyBoxes.push({'x': v.x, 'y': v.y, 'w': v.w, 'h': v.h});
-    } else {
-        // Redraw dirty regions
-        if (v.x < c.x1) {
-            // left side dirty region
-            dirtyBoxes.push({'x': v.x, 'y': v.y,
-                             'w': c.x1 - v.x + 1, 'h': v.h});
-        }
-        if (vx2 > c.x2) {
-            // right side dirty region
-            dirtyBoxes.push({'x': c.x2 + 1, 'y': v.y,
-                             'w': vx2 - c.x2, 'h': v.h});
-        }
-        if (v.y < c.y1) {
-            // top/middle dirty region
-            dirtyBoxes.push({'x': c.x1, 'y': v.y,
-                             'w': c.x2 - c.x1 + 1, 'h': c.y1 - v.y});
-        }
-        if (vy2 > c.y2) {
-            // bottom/middle dirty region
-            dirtyBoxes.push({'x': c.x1, 'y': c.y2 + 1,
-                             'w': c.x2 - c.x1 + 1, 'h': vy2 - c.y2});
-        }
-    }
-
-    // Reset the cleanRect to the whole viewport
-    cleanRect = {'x1': v.x, 'y1': v.y,
-                 'x2': v.x + v.w - 1, 'y2': v.y + v.h - 1};
-
-    return {'cleanBox': cleanBox, 'dirtyBoxes': dirtyBoxes};
-};
-
-// Translate viewport coordinates to absolute coordinates
-that.absX = function(x) {
-    return x + viewport.x;
-};
-that.absY = function(y) {
-    return y + viewport.y;
-};
-
-
-that.resize = function(width, height) {
-    c_prevStyle    = "";
-
-    fb_width = width;
-    fb_height = height;
-
-    rescale(conf.scale);
-    that.viewportChange();
-};
-
-that.clear = function() {
-
-    if (conf.logo) {
-        that.resize(conf.logo.width, conf.logo.height);
-        that.blitStringImage(conf.logo.data, 0, 0);
-    } else {
-        that.resize(640, 20);
-        c_ctx.clearRect(0, 0, viewport.w, viewport.h);
-    }
-
-    renderQ = [];
-
-    // No benefit over default ("source-over") in Chrome and firefox
-    //c_ctx.globalCompositeOperation = "copy";
-};
-
-that.fillRect = function(x, y, width, height, color) {
-    setFillColor(color);
-    c_ctx.fillRect(x - viewport.x, y - viewport.y, width, height);
-};
-
-that.copyImage = function(old_x, old_y, new_x, new_y, w, h) {
-    var x1 = old_x - viewport.x, y1 = old_y - viewport.y,
-        x2 = new_x - viewport.x, y2 = new_y  - viewport.y;
-    c_ctx.drawImage(conf.target, x1, y1, w, h, x2, y2, w, h);
-};
-
-
-// Start updating a tile
-that.startTile = function(x, y, width, height, color) {
-    var data, bgr, red, green, blue, i;
-    tile_x = x;
-    tile_y = y;
-    if ((width === 16) && (height === 16)) {
-        tile = tile16x16;
-    } else {
-        tile = c_ctx.createImageData(width, height);
-    }
-    data = tile.data;
-    if (conf.prefer_js) {
-        if (conf.true_color) {
-            bgr = color;
-        } else {
-            bgr = conf.colourMap[color[0]];
-        }
-        red = bgr[2];
-        green = bgr[1];
-        blue = bgr[0];
-        for (i = 0; i < (width * height * 4); i+=4) {
-            data[i    ] = red;
-            data[i + 1] = green;
-            data[i + 2] = blue;
-            data[i + 3] = 255;
-        }
-    } else {
-        that.fillRect(x, y, width, height, color);
-    }
-};
-
-// Update sub-rectangle of the current tile
-that.subTile = function(x, y, w, h, color) {
-    var data, p, bgr, red, green, blue, width, j, i, xend, yend;
-    if (conf.prefer_js) {
-        data = tile.data;
-        width = tile.width;
-        if (conf.true_color) {
-            bgr = color;
-        } else {
-            bgr = conf.colourMap[color[0]];
-        }
-        red = bgr[2];
-        green = bgr[1];
-        blue = bgr[0];
-        xend = x + w;
-        yend = y + h;
-        for (j = y; j < yend; j += 1) {
-            for (i = x; i < xend; i += 1) {
-                p = (i + (j * width) ) * 4;
-                data[p    ] = red;
-                data[p + 1] = green;
-                data[p + 2] = blue;
-                data[p + 3] = 255;
-            }   
-        } 
-    } else {
-        that.fillRect(tile_x + x, tile_y + y, w, h, color);
-    }
-};
-
-// Draw the current tile to the screen
-that.finishTile = function() {
-    if (conf.prefer_js) {
-        c_ctx.putImageData(tile, tile_x - viewport.x, tile_y - viewport.y);
-    }
-    // else: No-op, if not prefer_js then already done by setSubTile
-};
-
-rgbImageData = function(x, y, vx, vy, width, height, arr, offset) {
-    var img, i, j, data;
-    /*
-    if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
-        (x - v.x + width < 0) || (y - v.y + height < 0)) {
-        // Skipping because outside of viewport
-        return;
-    }
-    */
-    img = c_ctx.createImageData(width, height);
-    data = img.data;
-    for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+3) {
-        data[i    ] = arr[j    ];
-        data[i + 1] = arr[j + 1];
-        data[i + 2] = arr[j + 2];
-        data[i + 3] = 255; // Set Alpha
-    }
-    c_ctx.putImageData(img, x - vx, y - vy);
-};
-
-bgrxImageData = function(x, y, vx, vy, width, height, arr, offset) {
-    var img, i, j, data;
-    /*
-    if ((x - v.x >= v.w) || (y - v.y >= v.h) ||
-        (x - v.x + width < 0) || (y - v.y + height < 0)) {
-        // Skipping because outside of viewport
-        return;
-    }
-    */
-    img = c_ctx.createImageData(width, height);
-    data = img.data;
-    for (i=0, j=offset; i < (width * height * 4); i=i+4, j=j+4) {
-        data[i    ] = arr[j + 2];
-        data[i + 1] = arr[j + 1];
-        data[i + 2] = arr[j    ];
-        data[i + 3] = 255; // Set Alpha
-    }
-    c_ctx.putImageData(img, x - vx, y - vy);
-};
-
-cmapImageData = function(x, y, vx, vy, width, height, arr, offset) {
-    var img, i, j, data, bgr, cmap;
-    img = c_ctx.createImageData(width, height);
-    data = img.data;
-    cmap = conf.colourMap;
-    for (i=0, j=offset; i < (width * height * 4); i+=4, j+=1) {
-        bgr = cmap[arr[j]];
-        data[i    ] = bgr[2];
-        data[i + 1] = bgr[1];
-        data[i + 2] = bgr[0];
-        data[i + 3] = 255; // Set Alpha
-    }
-    c_ctx.putImageData(img, x - vx, y - vy);
-};
-
-that.blitImage = function(x, y, width, height, arr, offset) {
-    if (conf.true_color) {
-        bgrxImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
-    } else {
-        cmapImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
-    }
-};
-
-that.blitRgbImage = function(x, y, width, height, arr, offset) {
-    if (conf.true_color) {
-        rgbImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
-    } else {
-        // prolly wrong...
-        cmapImageData(x, y, viewport.x, viewport.y, width, height, arr, offset);
-    }
-};
-
-that.blitStringImage = function(str, x, y) {
-    var img = new Image();
-    img.onload = function () {
-        c_ctx.drawImage(img, x - viewport.x, y - viewport.y);
-    };
-    img.src = str;
-};
-
-// Wrap ctx.drawImage but relative to viewport
-that.drawImage = function(img, x, y) {
-    c_ctx.drawImage(img, x - viewport.x, y - viewport.y);
-};
-
-that.renderQ_push = function(action) {
-    renderQ.push(action);
-    if (renderQ.length === 1) {
-        // If this can be rendered immediately it will be, otherwise
-        // the scanner will start polling the queue (every
-        // requestAnimationFrame interval)
-        scan_renderQ();
-    }
-};
-
-scan_renderQ = function() {
-    var a, ready = true;
-    while (ready && renderQ.length > 0) {
-        a = renderQ[0];
-        switch (a.type) {
-            case 'copy':
-                that.copyImage(a.old_x, a.old_y, a.x, a.y, a.width, a.height);
-                break;
-            case 'fill':
-                that.fillRect(a.x, a.y, a.width, a.height, a.color);
-                break;
-            case 'blit':
-                that.blitImage(a.x, a.y, a.width, a.height, a.data, 0);
-                break;
-            case 'blitRgb':
-                that.blitRgbImage(a.x, a.y, a.width, a.height, a.data, 0);
-                break;
-            case 'img':    
-                if (a.img.complete) {
-                    that.drawImage(a.img, a.x, a.y);
-                } else {
-                    // We need to wait for this image to 'load'
-                    // to keep things in-order
-                    ready = false;
-                }
-                break;
-        }
-        if (ready) {
-            a = renderQ.shift();
-        }
-    }
-    if (renderQ.length > 0) {
-        requestAnimFrame(scan_renderQ);
-    }
-};
-
-
-that.changeCursor = function(pixels, mask, hotx, hoty, w, h) {
-    if (conf.cursor_uri === false) {
-        Util.Warn("changeCursor called but no cursor data URI support");
-        return;
-    }
-
-    if (conf.true_color) {
-        changeCursor(conf.target, pixels, mask, hotx, hoty, w, h);
-    } else {
-        changeCursor(conf.target, pixels, mask, hotx, hoty, w, h, conf.colourMap);
-    }
-};
-
-that.defaultCursor = function() {
-    conf.target.style.cursor = "default";
-};
-
-return constructor();  // Return the public API interface
-
-}  // End of Display()
-
-
-/* Set CSS cursor property using data URI encoded cursor file */
-function changeCursor(target, pixels, mask, hotx, hoty, w0, h0, cmap) {
-    "use strict";
-    var cur = [], rgb, IHDRsz, RGBsz, ANDsz, XORsz, url, idx, alpha, x, y;
-    //Util.Debug(">> changeCursor, x: " + hotx + ", y: " + hoty + ", w0: " + w0 + ", h0: " + h0);
-
-    var w = w0;
-    var h = h0;
-    if (h < w)
-        h = w;                 // increase h to make it square
-    else
-        w = h;                 // increace w to make it square
-
-    // Push multi-byte little-endian values
-    cur.push16le = function (num) {
-        this.push((num     ) & 0xFF,
-                  (num >> 8) & 0xFF  );
-    };
-    cur.push32le = function (num) {
-        this.push((num      ) & 0xFF,
-                  (num >>  8) & 0xFF,
-                  (num >> 16) & 0xFF,
-                  (num >> 24) & 0xFF  );
-    };
-
-    IHDRsz = 40;
-    RGBsz = w * h * 4;
-    XORsz = Math.ceil( (w * h) / 8.0 );
-    ANDsz = Math.ceil( (w * h) / 8.0 );
-
-    // Main header
-    cur.push16le(0);      // 0: Reserved
-    cur.push16le(2);      // 2: .CUR type
-    cur.push16le(1);      // 4: Number of images, 1 for non-animated ico
-
-    // Cursor #1 header (ICONDIRENTRY)
-    cur.push(w);          // 6: width
-    cur.push(h);          // 7: height
-    cur.push(0);          // 8: colors, 0 -> true-color
-    cur.push(0);          // 9: reserved
-    cur.push16le(hotx);   // 10: hotspot x coordinate
-    cur.push16le(hoty);   // 12: hotspot y coordinate
-    cur.push32le(IHDRsz + RGBsz + XORsz + ANDsz);
-                          // 14: cursor data byte size
-    cur.push32le(22);     // 18: offset of cursor data in the file
-
-
-    // Cursor #1 InfoHeader (ICONIMAGE/BITMAPINFO)
-    cur.push32le(IHDRsz); // 22: Infoheader size
-    cur.push32le(w);      // 26: Cursor width
-    cur.push32le(h*2);    // 30: XOR+AND height
-    cur.push16le(1);      // 34: number of planes
-    cur.push16le(32);     // 36: bits per pixel
-    cur.push32le(0);      // 38: Type of compression
-
-    cur.push32le(XORsz + ANDsz); // 43: Size of Image
-                                 // Gimp leaves this as 0
-
-    cur.push32le(0);      // 46: reserved
-    cur.push32le(0);      // 50: reserved
-    cur.push32le(0);      // 54: reserved
-    cur.push32le(0);      // 58: reserved
-
-    // 62: color data (RGBQUAD icColors[])
-    for (y = h-1; y >= 0; y -= 1) {
-        for (x = 0; x < w; x += 1) {
-            if (x >= w0 || y >= h0) {
-                cur.push(0);          // blue
-                cur.push(0);          // green
-                cur.push(0);          // red
-                cur.push(0);          // alpha
-            } else {
-                idx = y * Math.ceil(w0 / 8) + Math.floor(x/8);
-                alpha = (mask[idx] << (x % 8)) & 0x80 ? 255 : 0;
-                if (cmap) {
-                    idx = (w0 * y) + x;
-                    rgb = cmap[pixels[idx]];
-                    cur.push(rgb[2]);          // blue
-                    cur.push(rgb[1]);          // green
-                    cur.push(rgb[0]);          // red
-                    cur.push(alpha);           // alpha
-                } else {
-                    idx = ((w0 * y) + x) * 4;
-                    cur.push(pixels[idx + 2]); // blue
-                    cur.push(pixels[idx + 1]); // green
-                    cur.push(pixels[idx    ]); // red
-                    cur.push(alpha);           // alpha
-                }
-            }
-        }
-    }
-
-    // XOR/bitmask data (BYTE icXOR[])
-    // (ignored, just needs to be right size)
-    for (y = 0; y < h; y += 1) {
-        for (x = 0; x < Math.ceil(w / 8); x += 1) {
-            cur.push(0x00);
-        }
-    }
-
-    // AND/bitmask data (BYTE icAND[])
-    // (ignored, just needs to be right size)
-    for (y = 0; y < h; y += 1) {
-        for (x = 0; x < Math.ceil(w / 8); x += 1) {
-            cur.push(0x00);
-        }
-    }
-
-    url = "data:image/x-icon;base64," + Base64.encode(cur);
-    target.style.cursor = "url(" + url + ") " + hotx + " " + hoty + ", default";
-    //Util.Debug("<< changeCursor, cur.length: " + cur.length);
-}
diff --git a/circle/dashboard/static/dashboard/novnc/input.js b/circle/dashboard/static/dashboard/novnc/input.js
deleted file mode 100644
index 8f0c650..0000000
--- a/circle/dashboard/static/dashboard/novnc/input.js
+++ /dev/null
@@ -1,1980 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2013 Samuel Mannehed for Cendio AB
- * Licensed under MPL 2.0 or any later version (see LICENSE.txt)
- */
-
-/*jslint browser: true, white: false, bitwise: false */
-/*global window, Util */
-
-
-//
-// Keyboard event handler
-//
-
-function Keyboard(defaults) {
-"use strict";
-
-var that           = {},  // Public API methods
-    conf           = {},  // Configuration attributes
-
-    keyDownList    = [];         // List of depressed keys 
-                                 // (even if they are happy)
-
-// Configuration attributes
-Util.conf_defaults(conf, that, defaults, [
-    ['target',      'wo', 'dom',  document, 'DOM element that captures keyboard input'],
-    ['focused',     'rw', 'bool', true, 'Capture and send key events'],
-
-    ['onKeyPress',  'rw', 'func', null, 'Handler for key press/release']
-    ]);
-
-
-// 
-// Private functions
-//
-
-// From the event keyCode return the keysym value for keys that need
-// to be suppressed otherwise they may trigger unintended browser
-// actions
-function getKeysymSpecial(evt) {
-    var keysym = null;
-
-    switch ( evt.keyCode ) {
-        // These generate a keyDown and keyPress in Firefox and Opera
-        case 8         : keysym = 0xFF08; break; // BACKSPACE
-        case 13        : keysym = 0xFF0D; break; // ENTER
-
-        // This generates a keyDown and keyPress in Opera
-        case 9         : keysym = 0xFF09; break; // TAB
-        default        :                  break;
-    }
-
-    if (evt.type === 'keydown') {
-        switch ( evt.keyCode ) {
-            case 27        : keysym = 0xFF1B; break; // ESCAPE
-            case 46        : keysym = 0xFFFF; break; // DELETE
-
-            case 36        : keysym = 0xFF50; break; // HOME
-            case 35        : keysym = 0xFF57; break; // END
-            case 33        : keysym = 0xFF55; break; // PAGE_UP
-            case 34        : keysym = 0xFF56; break; // PAGE_DOWN
-            case 45        : keysym = 0xFF63; break; // INSERT
-                                                     // '-' during keyPress
-            case 37        : keysym = 0xFF51; break; // LEFT
-            case 38        : keysym = 0xFF52; break; // UP
-            case 39        : keysym = 0xFF53; break; // RIGHT
-            case 40        : keysym = 0xFF54; break; // DOWN
-            case 16        : keysym = 0xFFE1; break; // SHIFT
-            case 17        : keysym = 0xFFE3; break; // CONTROL
-            //case 18        : keysym = 0xFFE7; break; // Left Meta (Mac Option)
-            case 18        : keysym = 0xFFE9; break; // Left ALT (Mac Command)
-
-            case 112       : keysym = 0xFFBE; break; // F1
-            case 113       : keysym = 0xFFBF; break; // F2
-            case 114       : keysym = 0xFFC0; break; // F3
-            case 115       : keysym = 0xFFC1; break; // F4
-            case 116       : keysym = 0xFFC2; break; // F5
-            case 117       : keysym = 0xFFC3; break; // F6
-            case 118       : keysym = 0xFFC4; break; // F7
-            case 119       : keysym = 0xFFC5; break; // F8
-            case 120       : keysym = 0xFFC6; break; // F9
-            case 121       : keysym = 0xFFC7; break; // F10
-            case 122       : keysym = 0xFFC8; break; // F11
-            case 123       : keysym = 0xFFC9; break; // F12
-
-            case 225       : keysym = 0xFE03; break; // AltGr
-            case 91       : keysym = 0xFFEC; break; // Super_R (Win Key)
-            case 93       : keysym = 0xFF67; break; // Menu (Win Menu)
-
-            default        :                  break;
-        }
-    }
-
-    if ((!keysym) && (evt.ctrlKey || evt.altKey)) {
-        if ((typeof(evt.which) !== "undefined") && (evt.which > 0)) {
-            keysym = evt.which;
-        } else {
-            // IE9 always
-            // Firefox and Opera when ctrl/alt + special
-            Util.Warn("which not set, using keyCode");
-            keysym = evt.keyCode;
-        }
-
-        /* Remap symbols */
-        switch (keysym) {
-            case 186       : keysym = 59; break; // ;  (IE)
-            case 187       : keysym = 61; break; // =  (IE)
-            case 188       : keysym = 44; break; // ,  (Mozilla, IE)
-            case 109       :                     // -  (Mozilla, Opera)
-                if (Util.Engine.gecko || Util.Engine.presto) {
-                            keysym = 45; }
-                                        break;
-            case 173       :                     // -  (Mozilla)
-                if (Util.Engine.gecko) {
-                            keysym = 45; }
-                                        break;
-            case 189       : keysym = 45; break; // -  (IE)
-            case 190       : keysym = 46; break; // .  (Mozilla, IE)
-            case 191       : keysym = 47; break; // /  (Mozilla, IE)
-            case 192       : keysym = 96; break; // `  (Mozilla, IE)
-            case 219       : keysym = 91; break; // [  (Mozilla, IE)
-            case 220       : keysym = 92; break; // \  (Mozilla, IE)
-            case 221       : keysym = 93; break; // ]  (Mozilla, IE)
-            case 222       : keysym = 39; break; // '  (Mozilla, IE)
-        }
-        
-        /* Remap shifted and unshifted keys */
-        if (!!evt.shiftKey) {
-            switch (keysym) {
-                case 48        : keysym = 41 ; break; // )  (shifted 0)
-                case 49        : keysym = 33 ; break; // !  (shifted 1)
-                case 50        : keysym = 64 ; break; // @  (shifted 2)
-                case 51        : keysym = 35 ; break; // #  (shifted 3)
-                case 52        : keysym = 36 ; break; // $  (shifted 4)
-                case 53        : keysym = 37 ; break; // %  (shifted 5)
-                case 54        : keysym = 94 ; break; // ^  (shifted 6)
-                case 55        : keysym = 38 ; break; // &  (shifted 7)
-                case 56        : keysym = 42 ; break; // *  (shifted 8)
-                case 57        : keysym = 40 ; break; // (  (shifted 9)
-
-                case 59        : keysym = 58 ; break; // :  (shifted `)
-                case 61        : keysym = 43 ; break; // +  (shifted ;)
-                case 44        : keysym = 60 ; break; // <  (shifted ,)
-                case 45        : keysym = 95 ; break; // _  (shifted -)
-                case 46        : keysym = 62 ; break; // >  (shifted .)
-                case 47        : keysym = 63 ; break; // ?  (shifted /)
-                case 96        : keysym = 126; break; // ~  (shifted `)
-                case 91        : keysym = 123; break; // {  (shifted [)
-                case 92        : keysym = 124; break; // |  (shifted \)
-                case 93        : keysym = 125; break; // }  (shifted ])
-                case 39        : keysym = 34 ; break; // "  (shifted ')
-            }
-        } else if ((keysym >= 65) && (keysym <=90)) {
-            /* Remap unshifted A-Z */
-            keysym += 32;
-        } else if (evt.keyLocation === 3) {
-            // numpad keys
-            switch (keysym) {
-                case 96 : keysym = 48; break; // 0
-                case 97 : keysym = 49; break; // 1
-                case 98 : keysym = 50; break; // 2
-                case 99 : keysym = 51; break; // 3
-                case 100: keysym = 52; break; // 4
-                case 101: keysym = 53; break; // 5
-                case 102: keysym = 54; break; // 6
-                case 103: keysym = 55; break; // 7
-                case 104: keysym = 56; break; // 8
-                case 105: keysym = 57; break; // 9
-                case 109: keysym = 45; break; // -
-                case 110: keysym = 46; break; // .
-                case 111: keysym = 47; break; // /
-            }
-        }
-    }
-
-    return keysym;
-}
-
-/* Translate DOM keyPress event to keysym value */
-function getKeysym(evt) {
-    var keysym, msg;
-
-    if (typeof(evt.which) !== "undefined") {
-        // WebKit, Firefox, Opera
-        keysym = evt.which;
-    } else {
-        // IE9
-        Util.Warn("which not set, using keyCode");
-        keysym = evt.keyCode;
-    }
-
-    if ((keysym > 255) && (keysym < 0xFF00)) {
-        msg = "Mapping character code " + keysym;
-        // Map Unicode outside Latin 1 to X11 keysyms
-        keysym = unicodeTable[keysym];
-        if (typeof(keysym) === 'undefined') {
-           keysym = 0; 
-        }
-        Util.Debug(msg + " to " + keysym);
-    }
-
-    return keysym;
-}
-
-function show_keyDownList(kind) {
-    var c;
-    var msg = "keyDownList (" + kind + "):\n";
-    for (c = 0; c < keyDownList.length; c++) {
-        msg = msg + "    " + c + " - keyCode: " + keyDownList[c].keyCode +
-              " - which: " + keyDownList[c].which + "\n";
-    }
-    Util.Debug(msg);
-}
-
-function copyKeyEvent(evt) {
-    var members = ['type', 'keyCode', 'charCode', 'which',
-                   'altKey', 'ctrlKey', 'shiftKey',
-                   'keyLocation', 'keyIdentifier'], i, obj = {};
-    for (i = 0; i < members.length; i++) {
-        if (typeof(evt[members[i]]) !== "undefined") {
-            obj[members[i]] = evt[members[i]];
-        }
-    }
-    return obj;
-}
-
-function pushKeyEvent(fevt) {
-    keyDownList.push(fevt);
-}
-
-function getKeyEvent(keyCode, pop) {
-    var i, fevt = null;
-    for (i = keyDownList.length-1; i >= 0; i--) {
-        if (keyDownList[i].keyCode === keyCode) {
-            if ((typeof(pop) !== "undefined") && (pop)) {
-                fevt = keyDownList.splice(i, 1)[0];
-            } else {
-                fevt = keyDownList[i];
-            }
-            break;
-        }
-    }
-    return fevt;
-}
-
-function ignoreKeyEvent(evt) {
-    // Blarg. Some keys have a different keyCode on keyDown vs keyUp
-    if (evt.keyCode === 229) {
-        // French AZERTY keyboard dead key.
-        // Lame thing is that the respective keyUp is 219 so we can't
-        // properly ignore the keyUp event
-        return true;
-    }
-    return false;
-}
-
-
-//
-// Key Event Handling:
-//
-// There are several challenges when dealing with key events:
-//   - The meaning and use of keyCode, charCode and which depends on
-//     both the browser and the event type (keyDown/Up vs keyPress).
-//   - We cannot automatically determine the keyboard layout
-//   - The keyDown and keyUp events have a keyCode value that has not
-//     been translated by modifier keys.
-//   - The keyPress event has a translated (for layout and modifiers)
-//     character code but the attribute containing it differs. keyCode
-//     contains the translated value in WebKit (Chrome/Safari), Opera
-//     11 and IE9. charCode contains the value in WebKit and Firefox.
-//     The which attribute contains the value on WebKit, Firefox and
-//     Opera 11.
-//   - The keyDown/Up keyCode value indicates (sort of) the physical
-//     key was pressed but only for standard US layout. On a US
-//     keyboard, the '-' and '_' characters are on the same key and
-//     generate a keyCode value of 189. But on an AZERTY keyboard even
-//     though they are different physical keys they both still
-//     generate a keyCode of 189!
-//   - To prevent a key event from propagating to the browser and
-//     causing unwanted default actions (such as closing a tab,
-//     opening a menu, shifting focus, etc) we must suppress this
-//     event in both keyDown and keyPress because not all key strokes
-//     generate on a keyPress event. Also, in WebKit and IE9
-//     suppressing the keyDown prevents a keyPress but other browsers
-//     still generated a keyPress even if keyDown is suppressed.
-//
-// For safe key events, we wait until the keyPress event before
-// reporting a key down event. For unsafe key events, we report a key
-// down event when the keyDown event fires and we suppress any further
-// actions (including keyPress).
-//
-// In order to report a key up event that matches what we reported
-// for the key down event, we keep a list of keys that are currently
-// down. When the keyDown event happens, we add the key event to the
-// list. If it is a safe key event, then we update the which attribute
-// in the most recent item on the list when we received a keyPress
-// event (keyPress should immediately follow keyDown). When we
-// received a keyUp event we search for the event on the list with
-// a matching keyCode and we report the character code using the value
-// in the 'which' attribute that was stored with that key.
-//
-
-function onKeyDown(e) {
-    if (! conf.focused) {
-        return true;
-    }
-    var fevt = null, evt = (e ? e : window.event),
-        keysym = null, suppress = false;
-    //Util.Debug("onKeyDown kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
-
-    fevt = copyKeyEvent(evt);
-
-    keysym = getKeysymSpecial(evt);
-    // Save keysym decoding for use in keyUp
-    fevt.keysym = keysym;
-    if (keysym) {
-        // If it is a key or key combination that might trigger
-        // browser behaviors or it has no corresponding keyPress
-        // event, then send it immediately
-        if (conf.onKeyPress && !ignoreKeyEvent(evt)) {
-            Util.Debug("onKeyPress down, keysym: " + keysym +
-                   " (onKeyDown key: " + evt.keyCode +
-                   ", which: " + evt.which + ")");
-            conf.onKeyPress(keysym, 1, evt);
-        }
-        suppress = true;
-    }
-
-    if (! ignoreKeyEvent(evt)) {
-        // Add it to the list of depressed keys
-        pushKeyEvent(fevt);
-        //show_keyDownList('down');
-    }
-
-    if (suppress) {
-        // Suppress bubbling/default actions
-        Util.stopEvent(e);
-        return false;
-    } else {
-        // Allow the event to bubble and become a keyPress event which
-        // will have the character code translated
-        return true;
-    }
-}
-
-function onKeyPress(e) {
-    if (! conf.focused) {
-        return true;
-    }
-    var evt = (e ? e : window.event),
-        kdlen = keyDownList.length, keysym = null;
-    //Util.Debug("onKeyPress kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
-    
-    if (((evt.which !== "undefined") && (evt.which === 0)) ||
-        (getKeysymSpecial(evt))) {
-        // Firefox and Opera generate a keyPress event even if keyDown
-        // is suppressed. But the keys we want to suppress will have
-        // either:
-        //     - the which attribute set to 0
-        //     - getKeysymSpecial() will identify it
-        Util.Debug("Ignoring special key in keyPress");
-        Util.stopEvent(e);
-        return false;
-    }
-
-    keysym = getKeysym(evt);
-
-    // Modify the the which attribute in the depressed keys list so
-    // that the keyUp event will be able to have the character code
-    // translation available.
-    if (kdlen > 0) {
-        keyDownList[kdlen-1].keysym = keysym;
-    } else {
-        Util.Warn("keyDownList empty when keyPress triggered");
-    }
-
-    //show_keyDownList('press');
-    
-    // Send the translated keysym
-    if (conf.onKeyPress && (keysym > 0)) {
-        Util.Debug("onKeyPress down, keysym: " + keysym +
-                   " (onKeyPress key: " + evt.keyCode +
-                   ", which: " + evt.which + ")");
-        conf.onKeyPress(keysym, 1, evt);
-    }
-
-    // Stop keypress events just in case
-    Util.stopEvent(e);
-    return false;
-}
-
-function onKeyUp(e) {
-    if (! conf.focused) {
-        return true;
-    }
-    var fevt = null, evt = (e ? e : window.event), keysym;
-    //Util.Debug("onKeyUp   kC:" + evt.keyCode + " cC:" + evt.charCode + " w:" + evt.which);
-
-    fevt = getKeyEvent(evt.keyCode, true);
-    
-    if (fevt) {
-        keysym = fevt.keysym;
-    } else {
-        Util.Warn("Key event (keyCode = " + evt.keyCode +
-                ") not found on keyDownList");
-        keysym = 0;
-    }
-
-    //show_keyDownList('up');
-
-    if (conf.onKeyPress && (keysym > 0)) {
-        //Util.Debug("keyPress up,   keysym: " + keysym +
-        //        " (key: " + evt.keyCode + ", which: " + evt.which + ")");
-        Util.Debug("onKeyPress up, keysym: " + keysym +
-                   " (onKeyPress key: " + evt.keyCode +
-                   ", which: " + evt.which + ")");
-        conf.onKeyPress(keysym, 0, evt);
-    }
-    Util.stopEvent(e);
-    return false;
-}
-
-function allKeysUp() {
-    Util.Debug(">> Keyboard.allKeysUp");
-    if (keyDownList.length > 0) {
-        Util.Info("Releasing pressed/down keys");
-    }
-    var i, keysym, fevt = null;
-    for (i = keyDownList.length-1; i >= 0; i--) {
-        fevt = keyDownList.splice(i, 1)[0];
-        keysym = fevt.keysym;
-        if (conf.onKeyPress && (keysym > 0)) {
-            Util.Debug("allKeysUp, keysym: " + keysym +
-                    " (keyCode: " + fevt.keyCode +
-                    ", which: " + fevt.which + ")");
-            conf.onKeyPress(keysym, 0, fevt);
-        }
-    }
-    Util.Debug("<< Keyboard.allKeysUp");
-    return;
-}
-
-//
-// Public API interface functions
-//
-
-that.grab = function() {
-    //Util.Debug(">> Keyboard.grab");
-    var c = conf.target;
-
-    Util.addEvent(c, 'keydown', onKeyDown);
-    Util.addEvent(c, 'keyup', onKeyUp);
-    Util.addEvent(c, 'keypress', onKeyPress);
-
-    // Release (key up) if window loses focus
-    Util.addEvent(window, 'blur', allKeysUp);
-
-    //Util.Debug("<< Keyboard.grab");
-};
-
-that.ungrab = function() {
-    //Util.Debug(">> Keyboard.ungrab");
-    var c = conf.target;
-
-    Util.removeEvent(c, 'keydown', onKeyDown);
-    Util.removeEvent(c, 'keyup', onKeyUp);
-    Util.removeEvent(c, 'keypress', onKeyPress);
-    Util.removeEvent(window, 'blur', allKeysUp);
-
-    // Release (key up) all keys that are in a down state
-    allKeysUp();
-
-    //Util.Debug(">> Keyboard.ungrab");
-};
-
-return that;  // Return the public API interface
-
-}  // End of Keyboard()
-
-
-//
-// Mouse event handler
-//
-
-function Mouse(defaults) {
-"use strict";
-
-var that           = {},  // Public API methods
-    conf           = {},  // Configuration attributes
-    mouseCaptured  = false;
-
-var doubleClickTimer = null,
-    lastTouchPos = null;
-
-// Configuration attributes
-Util.conf_defaults(conf, that, defaults, [
-    ['target',         'ro', 'dom',  document, 'DOM element that captures mouse input'],
-    ['focused',        'rw', 'bool', true, 'Capture and send mouse clicks/movement'],
-    ['scale',          'rw', 'float', 1.0, 'Viewport scale factor 0.0 - 1.0'],
-
-    ['onMouseButton',  'rw', 'func', null, 'Handler for mouse button click/release'],
-    ['onMouseMove',    'rw', 'func', null, 'Handler for mouse movement'],
-    ['touchButton',    'rw', 'int', 1, 'Button mask (1, 2, 4) for touch devices (0 means ignore clicks)']
-    ]);
-
-function captureMouse() {
-    // capturing the mouse ensures we get the mouseup event
-    if (conf.target.setCapture) {
-        conf.target.setCapture();
-    }
-
-    // some browsers give us mouseup events regardless,
-    // so if we never captured the mouse, we can disregard the event
-    mouseCaptured = true;
-}
-
-function releaseMouse() {
-    if (conf.target.releaseCapture) {
-        conf.target.releaseCapture();
-    }
-    mouseCaptured = false;
-}
-// 
-// Private functions
-//
-
-function resetDoubleClickTimer() {
-    doubleClickTimer = null;
-}
-
-function onMouseButton(e, down) {
-    var evt, pos, bmask;
-    if (! conf.focused) {
-        return true;
-    }
-    evt = (e ? e : window.event);
-    pos = Util.getEventPosition(e, conf.target, conf.scale);
-
-    if (e.touches || e.changedTouches) {
-        // Touch device
-
-        // When two touches occur within 500 ms of each other and are
-        // closer than 20 pixels together a double click is triggered.
-        if (down == 1) {
-            if (doubleClickTimer == null) {
-                lastTouchPos = pos;
-            } else {
-                clearTimeout(doubleClickTimer); 
-
-                // When the distance between the two touches is small enough
-                // force the position of the latter touch to the position of
-                // the first.
-
-                var xs = lastTouchPos.x - pos.x;
-                var ys = lastTouchPos.y - pos.y;
-                var d = Math.sqrt((xs * xs) + (ys * ys));
-
-                // The goal is to trigger on a certain physical width, the
-                // devicePixelRatio brings us a bit closer but is not optimal.
-                if (d < 20 * window.devicePixelRatio) {
-                    pos = lastTouchPos;
-                }
-            }
-            doubleClickTimer = setTimeout(resetDoubleClickTimer, 500);
-        }
-        bmask = conf.touchButton;
-        // If bmask is set
-    } else if (evt.which) {
-        /* everything except IE */
-        bmask = 1 << evt.button;
-    } else {
-        /* IE including 9 */
-        bmask = (evt.button & 0x1) +      // Left
-                (evt.button & 0x2) * 2 +  // Right
-                (evt.button & 0x4) / 2;   // Middle
-    }
-    //Util.Debug("mouse " + pos.x + "," + pos.y + " down: " + down +
-    //           " bmask: " + bmask + "(evt.button: " + evt.button + ")");
-    if (conf.onMouseButton) {
-        Util.Debug("onMouseButton " + (down ? "down" : "up") +
-                   ", x: " + pos.x + ", y: " + pos.y + ", bmask: " + bmask);
-        conf.onMouseButton(pos.x, pos.y, down, bmask);
-    }
-    Util.stopEvent(e);
-    return false;
-}
-
-function onMouseDown(e) {
-    captureMouse();
-    onMouseButton(e, 1);
-}
-
-function onMouseUp(e) {
-    if (!mouseCaptured) {
-        return;
-    }
-
-    onMouseButton(e, 0);
-    releaseMouse();
-}
-
-function onMouseWheel(e) {
-    var evt, pos, bmask, wheelData;
-    if (! conf.focused) {
-        return true;
-    }
-    evt = (e ? e : window.event);
-    pos = Util.getEventPosition(e, conf.target, conf.scale);
-    wheelData = evt.detail ? evt.detail * -1 : evt.wheelDelta / 40;
-    if (wheelData > 0) {
-        bmask = 1 << 3;
-    } else {
-        bmask = 1 << 4;
-    }
-    //Util.Debug('mouse scroll by ' + wheelData + ':' + pos.x + "," + pos.y);
-    if (conf.onMouseButton) {
-        conf.onMouseButton(pos.x, pos.y, 1, bmask);
-        conf.onMouseButton(pos.x, pos.y, 0, bmask);
-    }
-    Util.stopEvent(e);
-    return false;
-}
-
-function onMouseMove(e) {
-    var evt, pos;
-    if (! conf.focused) {
-        return true;
-    }
-    evt = (e ? e : window.event);
-    pos = Util.getEventPosition(e, conf.target, conf.scale);
-    //Util.Debug('mouse ' + evt.which + '/' + evt.button + ' up:' + pos.x + "," + pos.y);
-    if (conf.onMouseMove) {
-        conf.onMouseMove(pos.x, pos.y);
-    }
-    Util.stopEvent(e);
-    return false;
-}
-
-function onMouseDisable(e) {
-    var evt, pos;
-    if (! conf.focused) {
-        return true;
-    }
-    evt = (e ? e : window.event);
-    pos = Util.getEventPosition(e, conf.target, conf.scale);
-    /* Stop propagation if inside canvas area */
-    if ((pos.realx >= 0) && (pos.realy >= 0) &&
-        (pos.realx < conf.target.offsetWidth) &&
-        (pos.realy < conf.target.offsetHeight)) {
-        //Util.Debug("mouse event disabled");
-        Util.stopEvent(e);
-        return false;
-    }
-    //Util.Debug("mouse event not disabled");
-    return true;
-}
-
-//
-// Public API interface functions
-//
-
-that.grab = function() {
-    //Util.Debug(">> Mouse.grab");
-    var c = conf.target;
-
-    if ('ontouchstart' in document.documentElement) {
-        Util.addEvent(c, 'touchstart', onMouseDown);
-        Util.addEvent(window, 'touchend', onMouseUp);
-        Util.addEvent(c, 'touchend', onMouseUp);
-        Util.addEvent(c, 'touchmove', onMouseMove);
-    } else {
-        Util.addEvent(c, 'mousedown', onMouseDown);
-        Util.addEvent(window, 'mouseup', onMouseUp);
-        Util.addEvent(c, 'mouseup', onMouseUp);
-        Util.addEvent(c, 'mousemove', onMouseMove);
-        Util.addEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
-                onMouseWheel);
-    }
-
-    /* Work around right and middle click browser behaviors */
-    Util.addEvent(document, 'click', onMouseDisable);
-    Util.addEvent(document.body, 'contextmenu', onMouseDisable);
-
-    //Util.Debug("<< Mouse.grab");
-};
-
-that.ungrab = function() {
-    //Util.Debug(">> Mouse.ungrab");
-    var c = conf.target;
-
-    if ('ontouchstart' in document.documentElement) {
-        Util.removeEvent(c, 'touchstart', onMouseDown);
-        Util.removeEvent(window, 'touchend', onMouseUp);
-        Util.removeEvent(c, 'touchend', onMouseUp);
-        Util.removeEvent(c, 'touchmove', onMouseMove);
-    } else {
-        Util.removeEvent(c, 'mousedown', onMouseDown);
-        Util.removeEvent(window, 'mouseup', onMouseUp);
-        Util.removeEvent(c, 'mouseup', onMouseUp);
-        Util.removeEvent(c, 'mousemove', onMouseMove);
-        Util.removeEvent(c, (Util.Engine.gecko) ? 'DOMMouseScroll' : 'mousewheel',
-                onMouseWheel);
-    }
-
-    /* Work around right and middle click browser behaviors */
-    Util.removeEvent(document, 'click', onMouseDisable);
-    Util.removeEvent(document.body, 'contextmenu', onMouseDisable);
-
-    //Util.Debug(">> Mouse.ungrab");
-};
-
-return that;  // Return the public API interface
-
-}  // End of Mouse()
-
-
-/*
- * Browser keypress to X11 keysym for Unicode characters > U+00FF
- */
-unicodeTable = {
-    0x0104 : 0x01a1,
-    0x02D8 : 0x01a2,
-    0x0141 : 0x01a3,
-    0x013D : 0x01a5,
-    0x015A : 0x01a6,
-    0x0160 : 0x01a9,
-    0x015E : 0x01aa,
-    0x0164 : 0x01ab,
-    0x0179 : 0x01ac,
-    0x017D : 0x01ae,
-    0x017B : 0x01af,
-    0x0105 : 0x01b1,
-    0x02DB : 0x01b2,
-    0x0142 : 0x01b3,
-    0x013E : 0x01b5,
-    0x015B : 0x01b6,
-    0x02C7 : 0x01b7,
-    0x0161 : 0x01b9,
-    0x015F : 0x01ba,
-    0x0165 : 0x01bb,
-    0x017A : 0x01bc,
-    0x02DD : 0x01bd,
-    0x017E : 0x01be,
-    0x017C : 0x01bf,
-    0x0154 : 0x01c0,
-    0x0102 : 0x01c3,
-    0x0139 : 0x01c5,
-    0x0106 : 0x01c6,
-    0x010C : 0x01c8,
-    0x0118 : 0x01ca,
-    0x011A : 0x01cc,
-    0x010E : 0x01cf,
-    0x0110 : 0x01d0,
-    0x0143 : 0x01d1,
-    0x0147 : 0x01d2,
-    0x0150 : 0x01d5,
-    0x0158 : 0x01d8,
-    0x016E : 0x01d9,
-    0x0170 : 0x01db,
-    0x0162 : 0x01de,
-    0x0155 : 0x01e0,
-    0x0103 : 0x01e3,
-    0x013A : 0x01e5,
-    0x0107 : 0x01e6,
-    0x010D : 0x01e8,
-    0x0119 : 0x01ea,
-    0x011B : 0x01ec,
-    0x010F : 0x01ef,
-    0x0111 : 0x01f0,
-    0x0144 : 0x01f1,
-    0x0148 : 0x01f2,
-    0x0151 : 0x01f5,
-    0x0171 : 0x01fb,
-    0x0159 : 0x01f8,
-    0x016F : 0x01f9,
-    0x0163 : 0x01fe,
-    0x02D9 : 0x01ff,
-    0x0126 : 0x02a1,
-    0x0124 : 0x02a6,
-    0x0130 : 0x02a9,
-    0x011E : 0x02ab,
-    0x0134 : 0x02ac,
-    0x0127 : 0x02b1,
-    0x0125 : 0x02b6,
-    0x0131 : 0x02b9,
-    0x011F : 0x02bb,
-    0x0135 : 0x02bc,
-    0x010A : 0x02c5,
-    0x0108 : 0x02c6,
-    0x0120 : 0x02d5,
-    0x011C : 0x02d8,
-    0x016C : 0x02dd,
-    0x015C : 0x02de,
-    0x010B : 0x02e5,
-    0x0109 : 0x02e6,
-    0x0121 : 0x02f5,
-    0x011D : 0x02f8,
-    0x016D : 0x02fd,
-    0x015D : 0x02fe,
-    0x0138 : 0x03a2,
-    0x0156 : 0x03a3,
-    0x0128 : 0x03a5,
-    0x013B : 0x03a6,
-    0x0112 : 0x03aa,
-    0x0122 : 0x03ab,
-    0x0166 : 0x03ac,
-    0x0157 : 0x03b3,
-    0x0129 : 0x03b5,
-    0x013C : 0x03b6,
-    0x0113 : 0x03ba,
-    0x0123 : 0x03bb,
-    0x0167 : 0x03bc,
-    0x014A : 0x03bd,
-    0x014B : 0x03bf,
-    0x0100 : 0x03c0,
-    0x012E : 0x03c7,
-    0x0116 : 0x03cc,
-    0x012A : 0x03cf,
-    0x0145 : 0x03d1,
-    0x014C : 0x03d2,
-    0x0136 : 0x03d3,
-    0x0172 : 0x03d9,
-    0x0168 : 0x03dd,
-    0x016A : 0x03de,
-    0x0101 : 0x03e0,
-    0x012F : 0x03e7,
-    0x0117 : 0x03ec,
-    0x012B : 0x03ef,
-    0x0146 : 0x03f1,
-    0x014D : 0x03f2,
-    0x0137 : 0x03f3,
-    0x0173 : 0x03f9,
-    0x0169 : 0x03fd,
-    0x016B : 0x03fe,
-    0x1E02 : 0x1001e02,
-    0x1E03 : 0x1001e03,
-    0x1E0A : 0x1001e0a,
-    0x1E80 : 0x1001e80,
-    0x1E82 : 0x1001e82,
-    0x1E0B : 0x1001e0b,
-    0x1EF2 : 0x1001ef2,
-    0x1E1E : 0x1001e1e,
-    0x1E1F : 0x1001e1f,
-    0x1E40 : 0x1001e40,
-    0x1E41 : 0x1001e41,
-    0x1E56 : 0x1001e56,
-    0x1E81 : 0x1001e81,
-    0x1E57 : 0x1001e57,
-    0x1E83 : 0x1001e83,
-    0x1E60 : 0x1001e60,
-    0x1EF3 : 0x1001ef3,
-    0x1E84 : 0x1001e84,
-    0x1E85 : 0x1001e85,
-    0x1E61 : 0x1001e61,
-    0x0174 : 0x1000174,
-    0x1E6A : 0x1001e6a,
-    0x0176 : 0x1000176,
-    0x0175 : 0x1000175,
-    0x1E6B : 0x1001e6b,
-    0x0177 : 0x1000177,
-    0x0152 : 0x13bc,
-    0x0153 : 0x13bd,
-    0x0178 : 0x13be,
-    0x203E : 0x047e,
-    0x3002 : 0x04a1,
-    0x300C : 0x04a2,
-    0x300D : 0x04a3,
-    0x3001 : 0x04a4,
-    0x30FB : 0x04a5,
-    0x30F2 : 0x04a6,
-    0x30A1 : 0x04a7,
-    0x30A3 : 0x04a8,
-    0x30A5 : 0x04a9,
-    0x30A7 : 0x04aa,
-    0x30A9 : 0x04ab,
-    0x30E3 : 0x04ac,
-    0x30E5 : 0x04ad,
-    0x30E7 : 0x04ae,
-    0x30C3 : 0x04af,
-    0x30FC : 0x04b0,
-    0x30A2 : 0x04b1,
-    0x30A4 : 0x04b2,
-    0x30A6 : 0x04b3,
-    0x30A8 : 0x04b4,
-    0x30AA : 0x04b5,
-    0x30AB : 0x04b6,
-    0x30AD : 0x04b7,
-    0x30AF : 0x04b8,
-    0x30B1 : 0x04b9,
-    0x30B3 : 0x04ba,
-    0x30B5 : 0x04bb,
-    0x30B7 : 0x04bc,
-    0x30B9 : 0x04bd,
-    0x30BB : 0x04be,
-    0x30BD : 0x04bf,
-    0x30BF : 0x04c0,
-    0x30C1 : 0x04c1,
-    0x30C4 : 0x04c2,
-    0x30C6 : 0x04c3,
-    0x30C8 : 0x04c4,
-    0x30CA : 0x04c5,
-    0x30CB : 0x04c6,
-    0x30CC : 0x04c7,
-    0x30CD : 0x04c8,
-    0x30CE : 0x04c9,
-    0x30CF : 0x04ca,
-    0x30D2 : 0x04cb,
-    0x30D5 : 0x04cc,
-    0x30D8 : 0x04cd,
-    0x30DB : 0x04ce,
-    0x30DE : 0x04cf,
-    0x30DF : 0x04d0,
-    0x30E0 : 0x04d1,
-    0x30E1 : 0x04d2,
-    0x30E2 : 0x04d3,
-    0x30E4 : 0x04d4,
-    0x30E6 : 0x04d5,
-    0x30E8 : 0x04d6,
-    0x30E9 : 0x04d7,
-    0x30EA : 0x04d8,
-    0x30EB : 0x04d9,
-    0x30EC : 0x04da,
-    0x30ED : 0x04db,
-    0x30EF : 0x04dc,
-    0x30F3 : 0x04dd,
-    0x309B : 0x04de,
-    0x309C : 0x04df,
-    0x06F0 : 0x10006f0,
-    0x06F1 : 0x10006f1,
-    0x06F2 : 0x10006f2,
-    0x06F3 : 0x10006f3,
-    0x06F4 : 0x10006f4,
-    0x06F5 : 0x10006f5,
-    0x06F6 : 0x10006f6,
-    0x06F7 : 0x10006f7,
-    0x06F8 : 0x10006f8,
-    0x06F9 : 0x10006f9,
-    0x066A : 0x100066a,
-    0x0670 : 0x1000670,
-    0x0679 : 0x1000679,
-    0x067E : 0x100067e,
-    0x0686 : 0x1000686,
-    0x0688 : 0x1000688,
-    0x0691 : 0x1000691,
-    0x060C : 0x05ac,
-    0x06D4 : 0x10006d4,
-    0x0660 : 0x1000660,
-    0x0661 : 0x1000661,
-    0x0662 : 0x1000662,
-    0x0663 : 0x1000663,
-    0x0664 : 0x1000664,
-    0x0665 : 0x1000665,
-    0x0666 : 0x1000666,
-    0x0667 : 0x1000667,
-    0x0668 : 0x1000668,
-    0x0669 : 0x1000669,
-    0x061B : 0x05bb,
-    0x061F : 0x05bf,
-    0x0621 : 0x05c1,
-    0x0622 : 0x05c2,
-    0x0623 : 0x05c3,
-    0x0624 : 0x05c4,
-    0x0625 : 0x05c5,
-    0x0626 : 0x05c6,
-    0x0627 : 0x05c7,
-    0x0628 : 0x05c8,
-    0x0629 : 0x05c9,
-    0x062A : 0x05ca,
-    0x062B : 0x05cb,
-    0x062C : 0x05cc,
-    0x062D : 0x05cd,
-    0x062E : 0x05ce,
-    0x062F : 0x05cf,
-    0x0630 : 0x05d0,
-    0x0631 : 0x05d1,
-    0x0632 : 0x05d2,
-    0x0633 : 0x05d3,
-    0x0634 : 0x05d4,
-    0x0635 : 0x05d5,
-    0x0636 : 0x05d6,
-    0x0637 : 0x05d7,
-    0x0638 : 0x05d8,
-    0x0639 : 0x05d9,
-    0x063A : 0x05da,
-    0x0640 : 0x05e0,
-    0x0641 : 0x05e1,
-    0x0642 : 0x05e2,
-    0x0643 : 0x05e3,
-    0x0644 : 0x05e4,
-    0x0645 : 0x05e5,
-    0x0646 : 0x05e6,
-    0x0647 : 0x05e7,
-    0x0648 : 0x05e8,
-    0x0649 : 0x05e9,
-    0x064A : 0x05ea,
-    0x064B : 0x05eb,
-    0x064C : 0x05ec,
-    0x064D : 0x05ed,
-    0x064E : 0x05ee,
-    0x064F : 0x05ef,
-    0x0650 : 0x05f0,
-    0x0651 : 0x05f1,
-    0x0652 : 0x05f2,
-    0x0653 : 0x1000653,
-    0x0654 : 0x1000654,
-    0x0655 : 0x1000655,
-    0x0698 : 0x1000698,
-    0x06A4 : 0x10006a4,
-    0x06A9 : 0x10006a9,
-    0x06AF : 0x10006af,
-    0x06BA : 0x10006ba,
-    0x06BE : 0x10006be,
-    0x06CC : 0x10006cc,
-    0x06D2 : 0x10006d2,
-    0x06C1 : 0x10006c1,
-    0x0492 : 0x1000492,
-    0x0493 : 0x1000493,
-    0x0496 : 0x1000496,
-    0x0497 : 0x1000497,
-    0x049A : 0x100049a,
-    0x049B : 0x100049b,
-    0x049C : 0x100049c,
-    0x049D : 0x100049d,
-    0x04A2 : 0x10004a2,
-    0x04A3 : 0x10004a3,
-    0x04AE : 0x10004ae,
-    0x04AF : 0x10004af,
-    0x04B0 : 0x10004b0,
-    0x04B1 : 0x10004b1,
-    0x04B2 : 0x10004b2,
-    0x04B3 : 0x10004b3,
-    0x04B6 : 0x10004b6,
-    0x04B7 : 0x10004b7,
-    0x04B8 : 0x10004b8,
-    0x04B9 : 0x10004b9,
-    0x04BA : 0x10004ba,
-    0x04BB : 0x10004bb,
-    0x04D8 : 0x10004d8,
-    0x04D9 : 0x10004d9,
-    0x04E2 : 0x10004e2,
-    0x04E3 : 0x10004e3,
-    0x04E8 : 0x10004e8,
-    0x04E9 : 0x10004e9,
-    0x04EE : 0x10004ee,
-    0x04EF : 0x10004ef,
-    0x0452 : 0x06a1,
-    0x0453 : 0x06a2,
-    0x0451 : 0x06a3,
-    0x0454 : 0x06a4,
-    0x0455 : 0x06a5,
-    0x0456 : 0x06a6,
-    0x0457 : 0x06a7,
-    0x0458 : 0x06a8,
-    0x0459 : 0x06a9,
-    0x045A : 0x06aa,
-    0x045B : 0x06ab,
-    0x045C : 0x06ac,
-    0x0491 : 0x06ad,
-    0x045E : 0x06ae,
-    0x045F : 0x06af,
-    0x2116 : 0x06b0,
-    0x0402 : 0x06b1,
-    0x0403 : 0x06b2,
-    0x0401 : 0x06b3,
-    0x0404 : 0x06b4,
-    0x0405 : 0x06b5,
-    0x0406 : 0x06b6,
-    0x0407 : 0x06b7,
-    0x0408 : 0x06b8,
-    0x0409 : 0x06b9,
-    0x040A : 0x06ba,
-    0x040B : 0x06bb,
-    0x040C : 0x06bc,
-    0x0490 : 0x06bd,
-    0x040E : 0x06be,
-    0x040F : 0x06bf,
-    0x044E : 0x06c0,
-    0x0430 : 0x06c1,
-    0x0431 : 0x06c2,
-    0x0446 : 0x06c3,
-    0x0434 : 0x06c4,
-    0x0435 : 0x06c5,
-    0x0444 : 0x06c6,
-    0x0433 : 0x06c7,
-    0x0445 : 0x06c8,
-    0x0438 : 0x06c9,
-    0x0439 : 0x06ca,
-    0x043A : 0x06cb,
-    0x043B : 0x06cc,
-    0x043C : 0x06cd,
-    0x043D : 0x06ce,
-    0x043E : 0x06cf,
-    0x043F : 0x06d0,
-    0x044F : 0x06d1,
-    0x0440 : 0x06d2,
-    0x0441 : 0x06d3,
-    0x0442 : 0x06d4,
-    0x0443 : 0x06d5,
-    0x0436 : 0x06d6,
-    0x0432 : 0x06d7,
-    0x044C : 0x06d8,
-    0x044B : 0x06d9,
-    0x0437 : 0x06da,
-    0x0448 : 0x06db,
-    0x044D : 0x06dc,
-    0x0449 : 0x06dd,
-    0x0447 : 0x06de,
-    0x044A : 0x06df,
-    0x042E : 0x06e0,
-    0x0410 : 0x06e1,
-    0x0411 : 0x06e2,
-    0x0426 : 0x06e3,
-    0x0414 : 0x06e4,
-    0x0415 : 0x06e5,
-    0x0424 : 0x06e6,
-    0x0413 : 0x06e7,
-    0x0425 : 0x06e8,
-    0x0418 : 0x06e9,
-    0x0419 : 0x06ea,
-    0x041A : 0x06eb,
-    0x041B : 0x06ec,
-    0x041C : 0x06ed,
-    0x041D : 0x06ee,
-    0x041E : 0x06ef,
-    0x041F : 0x06f0,
-    0x042F : 0x06f1,
-    0x0420 : 0x06f2,
-    0x0421 : 0x06f3,
-    0x0422 : 0x06f4,
-    0x0423 : 0x06f5,
-    0x0416 : 0x06f6,
-    0x0412 : 0x06f7,
-    0x042C : 0x06f8,
-    0x042B : 0x06f9,
-    0x0417 : 0x06fa,
-    0x0428 : 0x06fb,
-    0x042D : 0x06fc,
-    0x0429 : 0x06fd,
-    0x0427 : 0x06fe,
-    0x042A : 0x06ff,
-    0x0386 : 0x07a1,
-    0x0388 : 0x07a2,
-    0x0389 : 0x07a3,
-    0x038A : 0x07a4,
-    0x03AA : 0x07a5,
-    0x038C : 0x07a7,
-    0x038E : 0x07a8,
-    0x03AB : 0x07a9,
-    0x038F : 0x07ab,
-    0x0385 : 0x07ae,
-    0x2015 : 0x07af,
-    0x03AC : 0x07b1,
-    0x03AD : 0x07b2,
-    0x03AE : 0x07b3,
-    0x03AF : 0x07b4,
-    0x03CA : 0x07b5,
-    0x0390 : 0x07b6,
-    0x03CC : 0x07b7,
-    0x03CD : 0x07b8,
-    0x03CB : 0x07b9,
-    0x03B0 : 0x07ba,
-    0x03CE : 0x07bb,
-    0x0391 : 0x07c1,
-    0x0392 : 0x07c2,
-    0x0393 : 0x07c3,
-    0x0394 : 0x07c4,
-    0x0395 : 0x07c5,
-    0x0396 : 0x07c6,
-    0x0397 : 0x07c7,
-    0x0398 : 0x07c8,
-    0x0399 : 0x07c9,
-    0x039A : 0x07ca,
-    0x039B : 0x07cb,
-    0x039C : 0x07cc,
-    0x039D : 0x07cd,
-    0x039E : 0x07ce,
-    0x039F : 0x07cf,
-    0x03A0 : 0x07d0,
-    0x03A1 : 0x07d1,
-    0x03A3 : 0x07d2,
-    0x03A4 : 0x07d4,
-    0x03A5 : 0x07d5,
-    0x03A6 : 0x07d6,
-    0x03A7 : 0x07d7,
-    0x03A8 : 0x07d8,
-    0x03A9 : 0x07d9,
-    0x03B1 : 0x07e1,
-    0x03B2 : 0x07e2,
-    0x03B3 : 0x07e3,
-    0x03B4 : 0x07e4,
-    0x03B5 : 0x07e5,
-    0x03B6 : 0x07e6,
-    0x03B7 : 0x07e7,
-    0x03B8 : 0x07e8,
-    0x03B9 : 0x07e9,
-    0x03BA : 0x07ea,
-    0x03BB : 0x07eb,
-    0x03BC : 0x07ec,
-    0x03BD : 0x07ed,
-    0x03BE : 0x07ee,
-    0x03BF : 0x07ef,
-    0x03C0 : 0x07f0,
-    0x03C1 : 0x07f1,
-    0x03C3 : 0x07f2,
-    0x03C2 : 0x07f3,
-    0x03C4 : 0x07f4,
-    0x03C5 : 0x07f5,
-    0x03C6 : 0x07f6,
-    0x03C7 : 0x07f7,
-    0x03C8 : 0x07f8,
-    0x03C9 : 0x07f9,
-    0x23B7 : 0x08a1,
-    0x2320 : 0x08a4,
-    0x2321 : 0x08a5,
-    0x23A1 : 0x08a7,
-    0x23A3 : 0x08a8,
-    0x23A4 : 0x08a9,
-    0x23A6 : 0x08aa,
-    0x239B : 0x08ab,
-    0x239D : 0x08ac,
-    0x239E : 0x08ad,
-    0x23A0 : 0x08ae,
-    0x23A8 : 0x08af,
-    0x23AC : 0x08b0,
-    0x2264 : 0x08bc,
-    0x2260 : 0x08bd,
-    0x2265 : 0x08be,
-    0x222B : 0x08bf,
-    0x2234 : 0x08c0,
-    0x221D : 0x08c1,
-    0x221E : 0x08c2,
-    0x2207 : 0x08c5,
-    0x223C : 0x08c8,
-    0x2243 : 0x08c9,
-    0x21D4 : 0x08cd,
-    0x21D2 : 0x08ce,
-    0x2261 : 0x08cf,
-    //0x221A : 0x08d6,
-    0x2282 : 0x08da,
-    0x2283 : 0x08db,
-    0x2229 : 0x08dc,
-    0x222A : 0x08dd,
-    0x2227 : 0x08de,
-    0x2228 : 0x08df,
-    //0x2202 : 0x08ef,
-    0x0192 : 0x08f6,
-    0x2190 : 0x08fb,
-    0x2191 : 0x08fc,
-    0x2192 : 0x08fd,
-    0x2193 : 0x08fe,
-    0x25C6 : 0x09e0,
-    0x2592 : 0x09e1,
-    0x2409 : 0x09e2,
-    0x240C : 0x09e3,
-    0x240D : 0x09e4,
-    0x240A : 0x09e5,
-    0x2424 : 0x09e8,
-    0x240B : 0x09e9,
-    0x2518 : 0x09ea,
-    0x2510 : 0x09eb,
-    0x250C : 0x09ec,
-    0x2514 : 0x09ed,
-    0x253C : 0x09ee,
-    0x23BA : 0x09ef,
-    0x23BB : 0x09f0,
-    0x2500 : 0x09f1,
-    0x23BC : 0x09f2,
-    0x23BD : 0x09f3,
-    0x251C : 0x09f4,
-    0x2524 : 0x09f5,
-    0x2534 : 0x09f6,
-    0x252C : 0x09f7,
-    0x2502 : 0x09f8,
-    0x2003 : 0x0aa1,
-    0x2002 : 0x0aa2,
-    0x2004 : 0x0aa3,
-    0x2005 : 0x0aa4,
-    0x2007 : 0x0aa5,
-    0x2008 : 0x0aa6,
-    0x2009 : 0x0aa7,
-    0x200A : 0x0aa8,
-    0x2014 : 0x0aa9,
-    0x2013 : 0x0aaa,
-    0x2026 : 0x0aae,
-    0x2025 : 0x0aaf,
-    0x2153 : 0x0ab0,
-    0x2154 : 0x0ab1,
-    0x2155 : 0x0ab2,
-    0x2156 : 0x0ab3,
-    0x2157 : 0x0ab4,
-    0x2158 : 0x0ab5,
-    0x2159 : 0x0ab6,
-    0x215A : 0x0ab7,
-    0x2105 : 0x0ab8,
-    0x2012 : 0x0abb,
-    0x215B : 0x0ac3,
-    0x215C : 0x0ac4,
-    0x215D : 0x0ac5,
-    0x215E : 0x0ac6,
-    0x2122 : 0x0ac9,
-    0x2018 : 0x0ad0,
-    0x2019 : 0x0ad1,
-    0x201C : 0x0ad2,
-    0x201D : 0x0ad3,
-    0x211E : 0x0ad4,
-    0x2032 : 0x0ad6,
-    0x2033 : 0x0ad7,
-    0x271D : 0x0ad9,
-    0x2663 : 0x0aec,
-    0x2666 : 0x0aed,
-    0x2665 : 0x0aee,
-    0x2720 : 0x0af0,
-    0x2020 : 0x0af1,
-    0x2021 : 0x0af2,
-    0x2713 : 0x0af3,
-    0x2717 : 0x0af4,
-    0x266F : 0x0af5,
-    0x266D : 0x0af6,
-    0x2642 : 0x0af7,
-    0x2640 : 0x0af8,
-    0x260E : 0x0af9,
-    0x2315 : 0x0afa,
-    0x2117 : 0x0afb,
-    0x2038 : 0x0afc,
-    0x201A : 0x0afd,
-    0x201E : 0x0afe,
-    0x22A4 : 0x0bc2,
-    0x230A : 0x0bc4,
-    0x2218 : 0x0bca,
-    0x2395 : 0x0bcc,
-    0x22A5 : 0x0bce,
-    0x25CB : 0x0bcf,
-    0x2308 : 0x0bd3,
-    0x22A3 : 0x0bdc,
-    0x22A2 : 0x0bfc,
-    0x2017 : 0x0cdf,
-    0x05D0 : 0x0ce0,
-    0x05D1 : 0x0ce1,
-    0x05D2 : 0x0ce2,
-    0x05D3 : 0x0ce3,
-    0x05D4 : 0x0ce4,
-    0x05D5 : 0x0ce5,
-    0x05D6 : 0x0ce6,
-    0x05D7 : 0x0ce7,
-    0x05D8 : 0x0ce8,
-    0x05D9 : 0x0ce9,
-    0x05DA : 0x0cea,
-    0x05DB : 0x0ceb,
-    0x05DC : 0x0cec,
-    0x05DD : 0x0ced,
-    0x05DE : 0x0cee,
-    0x05DF : 0x0cef,
-    0x05E0 : 0x0cf0,
-    0x05E1 : 0x0cf1,
-    0x05E2 : 0x0cf2,
-    0x05E3 : 0x0cf3,
-    0x05E4 : 0x0cf4,
-    0x05E5 : 0x0cf5,
-    0x05E6 : 0x0cf6,
-    0x05E7 : 0x0cf7,
-    0x05E8 : 0x0cf8,
-    0x05E9 : 0x0cf9,
-    0x05EA : 0x0cfa,
-    0x0E01 : 0x0da1,
-    0x0E02 : 0x0da2,
-    0x0E03 : 0x0da3,
-    0x0E04 : 0x0da4,
-    0x0E05 : 0x0da5,
-    0x0E06 : 0x0da6,
-    0x0E07 : 0x0da7,
-    0x0E08 : 0x0da8,
-    0x0E09 : 0x0da9,
-    0x0E0A : 0x0daa,
-    0x0E0B : 0x0dab,
-    0x0E0C : 0x0dac,
-    0x0E0D : 0x0dad,
-    0x0E0E : 0x0dae,
-    0x0E0F : 0x0daf,
-    0x0E10 : 0x0db0,
-    0x0E11 : 0x0db1,
-    0x0E12 : 0x0db2,
-    0x0E13 : 0x0db3,
-    0x0E14 : 0x0db4,
-    0x0E15 : 0x0db5,
-    0x0E16 : 0x0db6,
-    0x0E17 : 0x0db7,
-    0x0E18 : 0x0db8,
-    0x0E19 : 0x0db9,
-    0x0E1A : 0x0dba,
-    0x0E1B : 0x0dbb,
-    0x0E1C : 0x0dbc,
-    0x0E1D : 0x0dbd,
-    0x0E1E : 0x0dbe,
-    0x0E1F : 0x0dbf,
-    0x0E20 : 0x0dc0,
-    0x0E21 : 0x0dc1,
-    0x0E22 : 0x0dc2,
-    0x0E23 : 0x0dc3,
-    0x0E24 : 0x0dc4,
-    0x0E25 : 0x0dc5,
-    0x0E26 : 0x0dc6,
-    0x0E27 : 0x0dc7,
-    0x0E28 : 0x0dc8,
-    0x0E29 : 0x0dc9,
-    0x0E2A : 0x0dca,
-    0x0E2B : 0x0dcb,
-    0x0E2C : 0x0dcc,
-    0x0E2D : 0x0dcd,
-    0x0E2E : 0x0dce,
-    0x0E2F : 0x0dcf,
-    0x0E30 : 0x0dd0,
-    0x0E31 : 0x0dd1,
-    0x0E32 : 0x0dd2,
-    0x0E33 : 0x0dd3,
-    0x0E34 : 0x0dd4,
-    0x0E35 : 0x0dd5,
-    0x0E36 : 0x0dd6,
-    0x0E37 : 0x0dd7,
-    0x0E38 : 0x0dd8,
-    0x0E39 : 0x0dd9,
-    0x0E3A : 0x0dda,
-    0x0E3F : 0x0ddf,
-    0x0E40 : 0x0de0,
-    0x0E41 : 0x0de1,
-    0x0E42 : 0x0de2,
-    0x0E43 : 0x0de3,
-    0x0E44 : 0x0de4,
-    0x0E45 : 0x0de5,
-    0x0E46 : 0x0de6,
-    0x0E47 : 0x0de7,
-    0x0E48 : 0x0de8,
-    0x0E49 : 0x0de9,
-    0x0E4A : 0x0dea,
-    0x0E4B : 0x0deb,
-    0x0E4C : 0x0dec,
-    0x0E4D : 0x0ded,
-    0x0E50 : 0x0df0,
-    0x0E51 : 0x0df1,
-    0x0E52 : 0x0df2,
-    0x0E53 : 0x0df3,
-    0x0E54 : 0x0df4,
-    0x0E55 : 0x0df5,
-    0x0E56 : 0x0df6,
-    0x0E57 : 0x0df7,
-    0x0E58 : 0x0df8,
-    0x0E59 : 0x0df9,
-    0x0587 : 0x1000587,
-    0x0589 : 0x1000589,
-    0x055D : 0x100055d,
-    0x058A : 0x100058a,
-    0x055C : 0x100055c,
-    0x055B : 0x100055b,
-    0x055E : 0x100055e,
-    0x0531 : 0x1000531,
-    0x0561 : 0x1000561,
-    0x0532 : 0x1000532,
-    0x0562 : 0x1000562,
-    0x0533 : 0x1000533,
-    0x0563 : 0x1000563,
-    0x0534 : 0x1000534,
-    0x0564 : 0x1000564,
-    0x0535 : 0x1000535,
-    0x0565 : 0x1000565,
-    0x0536 : 0x1000536,
-    0x0566 : 0x1000566,
-    0x0537 : 0x1000537,
-    0x0567 : 0x1000567,
-    0x0538 : 0x1000538,
-    0x0568 : 0x1000568,
-    0x0539 : 0x1000539,
-    0x0569 : 0x1000569,
-    0x053A : 0x100053a,
-    0x056A : 0x100056a,
-    0x053B : 0x100053b,
-    0x056B : 0x100056b,
-    0x053C : 0x100053c,
-    0x056C : 0x100056c,
-    0x053D : 0x100053d,
-    0x056D : 0x100056d,
-    0x053E : 0x100053e,
-    0x056E : 0x100056e,
-    0x053F : 0x100053f,
-    0x056F : 0x100056f,
-    0x0540 : 0x1000540,
-    0x0570 : 0x1000570,
-    0x0541 : 0x1000541,
-    0x0571 : 0x1000571,
-    0x0542 : 0x1000542,
-    0x0572 : 0x1000572,
-    0x0543 : 0x1000543,
-    0x0573 : 0x1000573,
-    0x0544 : 0x1000544,
-    0x0574 : 0x1000574,
-    0x0545 : 0x1000545,
-    0x0575 : 0x1000575,
-    0x0546 : 0x1000546,
-    0x0576 : 0x1000576,
-    0x0547 : 0x1000547,
-    0x0577 : 0x1000577,
-    0x0548 : 0x1000548,
-    0x0578 : 0x1000578,
-    0x0549 : 0x1000549,
-    0x0579 : 0x1000579,
-    0x054A : 0x100054a,
-    0x057A : 0x100057a,
-    0x054B : 0x100054b,
-    0x057B : 0x100057b,
-    0x054C : 0x100054c,
-    0x057C : 0x100057c,
-    0x054D : 0x100054d,
-    0x057D : 0x100057d,
-    0x054E : 0x100054e,
-    0x057E : 0x100057e,
-    0x054F : 0x100054f,
-    0x057F : 0x100057f,
-    0x0550 : 0x1000550,
-    0x0580 : 0x1000580,
-    0x0551 : 0x1000551,
-    0x0581 : 0x1000581,
-    0x0552 : 0x1000552,
-    0x0582 : 0x1000582,
-    0x0553 : 0x1000553,
-    0x0583 : 0x1000583,
-    0x0554 : 0x1000554,
-    0x0584 : 0x1000584,
-    0x0555 : 0x1000555,
-    0x0585 : 0x1000585,
-    0x0556 : 0x1000556,
-    0x0586 : 0x1000586,
-    0x055A : 0x100055a,
-    0x10D0 : 0x10010d0,
-    0x10D1 : 0x10010d1,
-    0x10D2 : 0x10010d2,
-    0x10D3 : 0x10010d3,
-    0x10D4 : 0x10010d4,
-    0x10D5 : 0x10010d5,
-    0x10D6 : 0x10010d6,
-    0x10D7 : 0x10010d7,
-    0x10D8 : 0x10010d8,
-    0x10D9 : 0x10010d9,
-    0x10DA : 0x10010da,
-    0x10DB : 0x10010db,
-    0x10DC : 0x10010dc,
-    0x10DD : 0x10010dd,
-    0x10DE : 0x10010de,
-    0x10DF : 0x10010df,
-    0x10E0 : 0x10010e0,
-    0x10E1 : 0x10010e1,
-    0x10E2 : 0x10010e2,
-    0x10E3 : 0x10010e3,
-    0x10E4 : 0x10010e4,
-    0x10E5 : 0x10010e5,
-    0x10E6 : 0x10010e6,
-    0x10E7 : 0x10010e7,
-    0x10E8 : 0x10010e8,
-    0x10E9 : 0x10010e9,
-    0x10EA : 0x10010ea,
-    0x10EB : 0x10010eb,
-    0x10EC : 0x10010ec,
-    0x10ED : 0x10010ed,
-    0x10EE : 0x10010ee,
-    0x10EF : 0x10010ef,
-    0x10F0 : 0x10010f0,
-    0x10F1 : 0x10010f1,
-    0x10F2 : 0x10010f2,
-    0x10F3 : 0x10010f3,
-    0x10F4 : 0x10010f4,
-    0x10F5 : 0x10010f5,
-    0x10F6 : 0x10010f6,
-    0x1E8A : 0x1001e8a,
-    0x012C : 0x100012c,
-    0x01B5 : 0x10001b5,
-    0x01E6 : 0x10001e6,
-    0x01D2 : 0x10001d1,
-    0x019F : 0x100019f,
-    0x1E8B : 0x1001e8b,
-    0x012D : 0x100012d,
-    0x01B6 : 0x10001b6,
-    0x01E7 : 0x10001e7,
-    //0x01D2 : 0x10001d2,
-    0x0275 : 0x1000275,
-    0x018F : 0x100018f,
-    0x0259 : 0x1000259,
-    0x1E36 : 0x1001e36,
-    0x1E37 : 0x1001e37,
-    0x1EA0 : 0x1001ea0,
-    0x1EA1 : 0x1001ea1,
-    0x1EA2 : 0x1001ea2,
-    0x1EA3 : 0x1001ea3,
-    0x1EA4 : 0x1001ea4,
-    0x1EA5 : 0x1001ea5,
-    0x1EA6 : 0x1001ea6,
-    0x1EA7 : 0x1001ea7,
-    0x1EA8 : 0x1001ea8,
-    0x1EA9 : 0x1001ea9,
-    0x1EAA : 0x1001eaa,
-    0x1EAB : 0x1001eab,
-    0x1EAC : 0x1001eac,
-    0x1EAD : 0x1001ead,
-    0x1EAE : 0x1001eae,
-    0x1EAF : 0x1001eaf,
-    0x1EB0 : 0x1001eb0,
-    0x1EB1 : 0x1001eb1,
-    0x1EB2 : 0x1001eb2,
-    0x1EB3 : 0x1001eb3,
-    0x1EB4 : 0x1001eb4,
-    0x1EB5 : 0x1001eb5,
-    0x1EB6 : 0x1001eb6,
-    0x1EB7 : 0x1001eb7,
-    0x1EB8 : 0x1001eb8,
-    0x1EB9 : 0x1001eb9,
-    0x1EBA : 0x1001eba,
-    0x1EBB : 0x1001ebb,
-    0x1EBC : 0x1001ebc,
-    0x1EBD : 0x1001ebd,
-    0x1EBE : 0x1001ebe,
-    0x1EBF : 0x1001ebf,
-    0x1EC0 : 0x1001ec0,
-    0x1EC1 : 0x1001ec1,
-    0x1EC2 : 0x1001ec2,
-    0x1EC3 : 0x1001ec3,
-    0x1EC4 : 0x1001ec4,
-    0x1EC5 : 0x1001ec5,
-    0x1EC6 : 0x1001ec6,
-    0x1EC7 : 0x1001ec7,
-    0x1EC8 : 0x1001ec8,
-    0x1EC9 : 0x1001ec9,
-    0x1ECA : 0x1001eca,
-    0x1ECB : 0x1001ecb,
-    0x1ECC : 0x1001ecc,
-    0x1ECD : 0x1001ecd,
-    0x1ECE : 0x1001ece,
-    0x1ECF : 0x1001ecf,
-    0x1ED0 : 0x1001ed0,
-    0x1ED1 : 0x1001ed1,
-    0x1ED2 : 0x1001ed2,
-    0x1ED3 : 0x1001ed3,
-    0x1ED4 : 0x1001ed4,
-    0x1ED5 : 0x1001ed5,
-    0x1ED6 : 0x1001ed6,
-    0x1ED7 : 0x1001ed7,
-    0x1ED8 : 0x1001ed8,
-    0x1ED9 : 0x1001ed9,
-    0x1EDA : 0x1001eda,
-    0x1EDB : 0x1001edb,
-    0x1EDC : 0x1001edc,
-    0x1EDD : 0x1001edd,
-    0x1EDE : 0x1001ede,
-    0x1EDF : 0x1001edf,
-    0x1EE0 : 0x1001ee0,
-    0x1EE1 : 0x1001ee1,
-    0x1EE2 : 0x1001ee2,
-    0x1EE3 : 0x1001ee3,
-    0x1EE4 : 0x1001ee4,
-    0x1EE5 : 0x1001ee5,
-    0x1EE6 : 0x1001ee6,
-    0x1EE7 : 0x1001ee7,
-    0x1EE8 : 0x1001ee8,
-    0x1EE9 : 0x1001ee9,
-    0x1EEA : 0x1001eea,
-    0x1EEB : 0x1001eeb,
-    0x1EEC : 0x1001eec,
-    0x1EED : 0x1001eed,
-    0x1EEE : 0x1001eee,
-    0x1EEF : 0x1001eef,
-    0x1EF0 : 0x1001ef0,
-    0x1EF1 : 0x1001ef1,
-    0x1EF4 : 0x1001ef4,
-    0x1EF5 : 0x1001ef5,
-    0x1EF6 : 0x1001ef6,
-    0x1EF7 : 0x1001ef7,
-    0x1EF8 : 0x1001ef8,
-    0x1EF9 : 0x1001ef9,
-    0x01A0 : 0x10001a0,
-    0x01A1 : 0x10001a1,
-    0x01AF : 0x10001af,
-    0x01B0 : 0x10001b0,
-    0x20A0 : 0x10020a0,
-    0x20A1 : 0x10020a1,
-    0x20A2 : 0x10020a2,
-    0x20A3 : 0x10020a3,
-    0x20A4 : 0x10020a4,
-    0x20A5 : 0x10020a5,
-    0x20A6 : 0x10020a6,
-    0x20A7 : 0x10020a7,
-    0x20A8 : 0x10020a8,
-    0x20A9 : 0x10020a9,
-    0x20AA : 0x10020aa,
-    0x20AB : 0x10020ab,
-    0x20AC : 0x20ac,
-    0x2070 : 0x1002070,
-    0x2074 : 0x1002074,
-    0x2075 : 0x1002075,
-    0x2076 : 0x1002076,
-    0x2077 : 0x1002077,
-    0x2078 : 0x1002078,
-    0x2079 : 0x1002079,
-    0x2080 : 0x1002080,
-    0x2081 : 0x1002081,
-    0x2082 : 0x1002082,
-    0x2083 : 0x1002083,
-    0x2084 : 0x1002084,
-    0x2085 : 0x1002085,
-    0x2086 : 0x1002086,
-    0x2087 : 0x1002087,
-    0x2088 : 0x1002088,
-    0x2089 : 0x1002089,
-    0x2202 : 0x1002202,
-    0x2205 : 0x1002205,
-    0x2208 : 0x1002208,
-    0x2209 : 0x1002209,
-    0x220B : 0x100220B,
-    0x221A : 0x100221A,
-    0x221B : 0x100221B,
-    0x221C : 0x100221C,
-    0x222C : 0x100222C,
-    0x222D : 0x100222D,
-    0x2235 : 0x1002235,
-    0x2245 : 0x1002248,
-    0x2247 : 0x1002247,
-    0x2262 : 0x1002262,
-    0x2263 : 0x1002263,
-    0x2800 : 0x1002800,
-    0x2801 : 0x1002801,
-    0x2802 : 0x1002802,
-    0x2803 : 0x1002803,
-    0x2804 : 0x1002804,
-    0x2805 : 0x1002805,
-    0x2806 : 0x1002806,
-    0x2807 : 0x1002807,
-    0x2808 : 0x1002808,
-    0x2809 : 0x1002809,
-    0x280a : 0x100280a,
-    0x280b : 0x100280b,
-    0x280c : 0x100280c,
-    0x280d : 0x100280d,
-    0x280e : 0x100280e,
-    0x280f : 0x100280f,
-    0x2810 : 0x1002810,
-    0x2811 : 0x1002811,
-    0x2812 : 0x1002812,
-    0x2813 : 0x1002813,
-    0x2814 : 0x1002814,
-    0x2815 : 0x1002815,
-    0x2816 : 0x1002816,
-    0x2817 : 0x1002817,
-    0x2818 : 0x1002818,
-    0x2819 : 0x1002819,
-    0x281a : 0x100281a,
-    0x281b : 0x100281b,
-    0x281c : 0x100281c,
-    0x281d : 0x100281d,
-    0x281e : 0x100281e,
-    0x281f : 0x100281f,
-    0x2820 : 0x1002820,
-    0x2821 : 0x1002821,
-    0x2822 : 0x1002822,
-    0x2823 : 0x1002823,
-    0x2824 : 0x1002824,
-    0x2825 : 0x1002825,
-    0x2826 : 0x1002826,
-    0x2827 : 0x1002827,
-    0x2828 : 0x1002828,
-    0x2829 : 0x1002829,
-    0x282a : 0x100282a,
-    0x282b : 0x100282b,
-    0x282c : 0x100282c,
-    0x282d : 0x100282d,
-    0x282e : 0x100282e,
-    0x282f : 0x100282f,
-    0x2830 : 0x1002830,
-    0x2831 : 0x1002831,
-    0x2832 : 0x1002832,
-    0x2833 : 0x1002833,
-    0x2834 : 0x1002834,
-    0x2835 : 0x1002835,
-    0x2836 : 0x1002836,
-    0x2837 : 0x1002837,
-    0x2838 : 0x1002838,
-    0x2839 : 0x1002839,
-    0x283a : 0x100283a,
-    0x283b : 0x100283b,
-    0x283c : 0x100283c,
-    0x283d : 0x100283d,
-    0x283e : 0x100283e,
-    0x283f : 0x100283f,
-    0x2840 : 0x1002840,
-    0x2841 : 0x1002841,
-    0x2842 : 0x1002842,
-    0x2843 : 0x1002843,
-    0x2844 : 0x1002844,
-    0x2845 : 0x1002845,
-    0x2846 : 0x1002846,
-    0x2847 : 0x1002847,
-    0x2848 : 0x1002848,
-    0x2849 : 0x1002849,
-    0x284a : 0x100284a,
-    0x284b : 0x100284b,
-    0x284c : 0x100284c,
-    0x284d : 0x100284d,
-    0x284e : 0x100284e,
-    0x284f : 0x100284f,
-    0x2850 : 0x1002850,
-    0x2851 : 0x1002851,
-    0x2852 : 0x1002852,
-    0x2853 : 0x1002853,
-    0x2854 : 0x1002854,
-    0x2855 : 0x1002855,
-    0x2856 : 0x1002856,
-    0x2857 : 0x1002857,
-    0x2858 : 0x1002858,
-    0x2859 : 0x1002859,
-    0x285a : 0x100285a,
-    0x285b : 0x100285b,
-    0x285c : 0x100285c,
-    0x285d : 0x100285d,
-    0x285e : 0x100285e,
-    0x285f : 0x100285f,
-    0x2860 : 0x1002860,
-    0x2861 : 0x1002861,
-    0x2862 : 0x1002862,
-    0x2863 : 0x1002863,
-    0x2864 : 0x1002864,
-    0x2865 : 0x1002865,
-    0x2866 : 0x1002866,
-    0x2867 : 0x1002867,
-    0x2868 : 0x1002868,
-    0x2869 : 0x1002869,
-    0x286a : 0x100286a,
-    0x286b : 0x100286b,
-    0x286c : 0x100286c,
-    0x286d : 0x100286d,
-    0x286e : 0x100286e,
-    0x286f : 0x100286f,
-    0x2870 : 0x1002870,
-    0x2871 : 0x1002871,
-    0x2872 : 0x1002872,
-    0x2873 : 0x1002873,
-    0x2874 : 0x1002874,
-    0x2875 : 0x1002875,
-    0x2876 : 0x1002876,
-    0x2877 : 0x1002877,
-    0x2878 : 0x1002878,
-    0x2879 : 0x1002879,
-    0x287a : 0x100287a,
-    0x287b : 0x100287b,
-    0x287c : 0x100287c,
-    0x287d : 0x100287d,
-    0x287e : 0x100287e,
-    0x287f : 0x100287f,
-    0x2880 : 0x1002880,
-    0x2881 : 0x1002881,
-    0x2882 : 0x1002882,
-    0x2883 : 0x1002883,
-    0x2884 : 0x1002884,
-    0x2885 : 0x1002885,
-    0x2886 : 0x1002886,
-    0x2887 : 0x1002887,
-    0x2888 : 0x1002888,
-    0x2889 : 0x1002889,
-    0x288a : 0x100288a,
-    0x288b : 0x100288b,
-    0x288c : 0x100288c,
-    0x288d : 0x100288d,
-    0x288e : 0x100288e,
-    0x288f : 0x100288f,
-    0x2890 : 0x1002890,
-    0x2891 : 0x1002891,
-    0x2892 : 0x1002892,
-    0x2893 : 0x1002893,
-    0x2894 : 0x1002894,
-    0x2895 : 0x1002895,
-    0x2896 : 0x1002896,
-    0x2897 : 0x1002897,
-    0x2898 : 0x1002898,
-    0x2899 : 0x1002899,
-    0x289a : 0x100289a,
-    0x289b : 0x100289b,
-    0x289c : 0x100289c,
-    0x289d : 0x100289d,
-    0x289e : 0x100289e,
-    0x289f : 0x100289f,
-    0x28a0 : 0x10028a0,
-    0x28a1 : 0x10028a1,
-    0x28a2 : 0x10028a2,
-    0x28a3 : 0x10028a3,
-    0x28a4 : 0x10028a4,
-    0x28a5 : 0x10028a5,
-    0x28a6 : 0x10028a6,
-    0x28a7 : 0x10028a7,
-    0x28a8 : 0x10028a8,
-    0x28a9 : 0x10028a9,
-    0x28aa : 0x10028aa,
-    0x28ab : 0x10028ab,
-    0x28ac : 0x10028ac,
-    0x28ad : 0x10028ad,
-    0x28ae : 0x10028ae,
-    0x28af : 0x10028af,
-    0x28b0 : 0x10028b0,
-    0x28b1 : 0x10028b1,
-    0x28b2 : 0x10028b2,
-    0x28b3 : 0x10028b3,
-    0x28b4 : 0x10028b4,
-    0x28b5 : 0x10028b5,
-    0x28b6 : 0x10028b6,
-    0x28b7 : 0x10028b7,
-    0x28b8 : 0x10028b8,
-    0x28b9 : 0x10028b9,
-    0x28ba : 0x10028ba,
-    0x28bb : 0x10028bb,
-    0x28bc : 0x10028bc,
-    0x28bd : 0x10028bd,
-    0x28be : 0x10028be,
-    0x28bf : 0x10028bf,
-    0x28c0 : 0x10028c0,
-    0x28c1 : 0x10028c1,
-    0x28c2 : 0x10028c2,
-    0x28c3 : 0x10028c3,
-    0x28c4 : 0x10028c4,
-    0x28c5 : 0x10028c5,
-    0x28c6 : 0x10028c6,
-    0x28c7 : 0x10028c7,
-    0x28c8 : 0x10028c8,
-    0x28c9 : 0x10028c9,
-    0x28ca : 0x10028ca,
-    0x28cb : 0x10028cb,
-    0x28cc : 0x10028cc,
-    0x28cd : 0x10028cd,
-    0x28ce : 0x10028ce,
-    0x28cf : 0x10028cf,
-    0x28d0 : 0x10028d0,
-    0x28d1 : 0x10028d1,
-    0x28d2 : 0x10028d2,
-    0x28d3 : 0x10028d3,
-    0x28d4 : 0x10028d4,
-    0x28d5 : 0x10028d5,
-    0x28d6 : 0x10028d6,
-    0x28d7 : 0x10028d7,
-    0x28d8 : 0x10028d8,
-    0x28d9 : 0x10028d9,
-    0x28da : 0x10028da,
-    0x28db : 0x10028db,
-    0x28dc : 0x10028dc,
-    0x28dd : 0x10028dd,
-    0x28de : 0x10028de,
-    0x28df : 0x10028df,
-    0x28e0 : 0x10028e0,
-    0x28e1 : 0x10028e1,
-    0x28e2 : 0x10028e2,
-    0x28e3 : 0x10028e3, 
-    0x28e4 : 0x10028e4,
-    0x28e5 : 0x10028e5,
-    0x28e6 : 0x10028e6,
-    0x28e7 : 0x10028e7,
-    0x28e8 : 0x10028e8,
-    0x28e9 : 0x10028e9,
-    0x28ea : 0x10028ea,
-    0x28eb : 0x10028eb,
-    0x28ec : 0x10028ec,
-    0x28ed : 0x10028ed,
-    0x28ee : 0x10028ee,
-    0x28ef : 0x10028ef,
-    0x28f0 : 0x10028f0,
-    0x28f1 : 0x10028f1,
-    0x28f2 : 0x10028f2,
-    0x28f3 : 0x10028f3,
-    0x28f4 : 0x10028f4,
-    0x28f5 : 0x10028f5,
-    0x28f6 : 0x10028f6,
-    0x28f7 : 0x10028f7,
-    0x28f8 : 0x10028f8,
-    0x28f9 : 0x10028f9,
-    0x28fa : 0x10028fa,
-    0x28fb : 0x10028fb,
-    0x28fc : 0x10028fc,
-    0x28fd : 0x10028fd,
-    0x28fe : 0x10028fe,
-    0x28ff : 0x10028ff
-};
diff --git a/circle/dashboard/static/dashboard/novnc/jsunzip.js b/circle/dashboard/static/dashboard/novnc/jsunzip.js
deleted file mode 100755
index 8968f86..0000000
--- a/circle/dashboard/static/dashboard/novnc/jsunzip.js
+++ /dev/null
@@ -1,676 +0,0 @@
-/*
- * JSUnzip
- *
- * Copyright (c) 2011 by Erik Moller
- * All Rights Reserved
- *
- * This software is provided 'as-is', without any express
- * or implied warranty.  In no event will the authors be
- * held liable for any damages arising from the use of
- * this software.
- *
- * Permission is granted to anyone to use this software
- * for any purpose, including commercial applications,
- * and to alter it and redistribute it freely, subject to
- * the following restrictions:
- *
- * 1. The origin of this software must not be
- *    misrepresented; you must not claim that you
- *    wrote the original software. If you use this
- *    software in a product, an acknowledgment in
- *    the product documentation would be appreciated
- *    but is not required.
- *
- * 2. Altered source versions must be plainly marked
- *    as such, and must not be misrepresented as
- *    being the original software.
- *
- * 3. This notice may not be removed or altered from
- *    any source distribution.
- */
- 
-var tinf;
-
-function JSUnzip() {
-
-    this.getInt = function(offset, size) {
-        switch (size) {
-        case 4:
-            return  (this.data.charCodeAt(offset + 3) & 0xff) << 24 | 
-                    (this.data.charCodeAt(offset + 2) & 0xff) << 16 | 
-                    (this.data.charCodeAt(offset + 1) & 0xff) << 8 | 
-                    (this.data.charCodeAt(offset + 0) & 0xff);
-            break;
-        case 2:
-            return  (this.data.charCodeAt(offset + 1) & 0xff) << 8 | 
-                    (this.data.charCodeAt(offset + 0) & 0xff);
-            break;
-        default:
-            return this.data.charCodeAt(offset) & 0xff;
-            break;
-        }
-    };
-
-    this.getDOSDate = function(dosdate, dostime) {
-        var day = dosdate & 0x1f;
-        var month = ((dosdate >> 5) & 0xf) - 1;
-        var year = 1980 + ((dosdate >> 9) & 0x7f)
-        var second = (dostime & 0x1f) * 2;
-        var minute = (dostime >> 5) & 0x3f;
-        hour = (dostime >> 11) & 0x1f;
-        return new Date(year, month, day, hour, minute, second);
-    }
-
-    this.open = function(data) {
-        this.data = data;
-        this.files = [];
-
-        if (this.data.length < 22)
-            return { 'status' : false, 'error' : 'Invalid data' };
-        var endOfCentralDirectory = this.data.length - 22;
-        while (endOfCentralDirectory >= 0 && this.getInt(endOfCentralDirectory, 4) != 0x06054b50)
-            --endOfCentralDirectory;
-        if (endOfCentralDirectory < 0)
-            return { 'status' : false, 'error' : 'Invalid data' };
-        if (this.getInt(endOfCentralDirectory + 4, 2) != 0 || this.getInt(endOfCentralDirectory + 6, 2) != 0)
-            return { 'status' : false, 'error' : 'No multidisk support' };
-
-        var entriesInThisDisk = this.getInt(endOfCentralDirectory + 8, 2);
-        var centralDirectoryOffset = this.getInt(endOfCentralDirectory + 16, 4);
-        var globalCommentLength = this.getInt(endOfCentralDirectory + 20, 2);
-        this.comment = this.data.slice(endOfCentralDirectory + 22, endOfCentralDirectory + 22 + globalCommentLength);
-
-        var fileOffset = centralDirectoryOffset;
-
-        for (var i = 0; i < entriesInThisDisk; ++i) {
-            if (this.getInt(fileOffset + 0, 4) != 0x02014b50)
-                return { 'status' : false, 'error' : 'Invalid data' };
-            if (this.getInt(fileOffset + 6, 2) > 20)
-                return { 'status' : false, 'error' : 'Unsupported version' };
-            if (this.getInt(fileOffset + 8, 2) & 1)
-                return { 'status' : false, 'error' : 'Encryption not implemented' };
-
-            var compressionMethod = this.getInt(fileOffset + 10, 2);
-            if (compressionMethod != 0 && compressionMethod != 8)
-                return { 'status' : false, 'error' : 'Unsupported compression method' };
-
-            var lastModFileTime = this.getInt(fileOffset + 12, 2);
-            var lastModFileDate = this.getInt(fileOffset + 14, 2);
-            var lastModifiedDate = this.getDOSDate(lastModFileDate, lastModFileTime);
-
-            var crc = this.getInt(fileOffset + 16, 4);
-            // TODO: crc
-
-            var compressedSize = this.getInt(fileOffset + 20, 4);
-            var uncompressedSize = this.getInt(fileOffset + 24, 4);
-
-            var fileNameLength = this.getInt(fileOffset + 28, 2);
-            var extraFieldLength = this.getInt(fileOffset + 30, 2);
-            var fileCommentLength = this.getInt(fileOffset + 32, 2);
-
-            var relativeOffsetOfLocalHeader = this.getInt(fileOffset + 42, 4);
-
-            var fileName = this.data.slice(fileOffset + 46, fileOffset + 46 + fileNameLength);
-            var fileComment = this.data.slice(fileOffset + 46 + fileNameLength + extraFieldLength, fileOffset + 46 + fileNameLength + extraFieldLength + fileCommentLength);
-
-            if (this.getInt(relativeOffsetOfLocalHeader + 0, 4) != 0x04034b50)
-                return { 'status' : false, 'error' : 'Invalid data' };
-            var localFileNameLength = this.getInt(relativeOffsetOfLocalHeader + 26, 2);
-            var localExtraFieldLength = this.getInt(relativeOffsetOfLocalHeader + 28, 2);
-            var localFileContent = relativeOffsetOfLocalHeader + 30 + localFileNameLength + localExtraFieldLength;
-
-            this.files[fileName] = 
-            {
-                'fileComment' : fileComment,
-                'compressionMethod' : compressionMethod,
-                'compressedSize' : compressedSize,
-                'uncompressedSize' : uncompressedSize,
-                'localFileContent' : localFileContent,
-                'lastModifiedDate' : lastModifiedDate
-            };
-
-            fileOffset += 46 + fileNameLength + extraFieldLength + fileCommentLength;
-        }
-        return { 'status' : true }
-    };     
-    
-
-    this.read = function(fileName) {
-        var fileInfo = this.files[fileName];
-        if (fileInfo) {
-            if (fileInfo.compressionMethod == 8) {
-                if (!tinf) {
-                    tinf = new TINF();
-                    tinf.init();
-                }
-                var result = tinf.uncompress(this.data, fileInfo.localFileContent);
-                if (result.status == tinf.OK)
-                    return { 'status' : true, 'data' : result.data };
-                else
-                    return { 'status' : false, 'error' : result.error };
-            } else {
-                return { 'status' : true, 'data' : this.data.slice(fileInfo.localFileContent, fileInfo.localFileContent + fileInfo.uncompressedSize) };
-            }
-        }
-        return { 'status' : false, 'error' : "File '" + fileName + "' doesn't exist in zip" };
-    };
-    
-};
-
-
-
-/*
- * tinflate  -  tiny inflate
- *
- * Copyright (c) 2003 by Joergen Ibsen / Jibz
- * All Rights Reserved
- *
- * http://www.ibsensoftware.com/
- *
- * This software is provided 'as-is', without any express
- * or implied warranty.  In no event will the authors be
- * held liable for any damages arising from the use of
- * this software.
- *
- * Permission is granted to anyone to use this software
- * for any purpose, including commercial applications,
- * and to alter it and redistribute it freely, subject to
- * the following restrictions:
- *
- * 1. The origin of this software must not be
- *    misrepresented; you must not claim that you
- *    wrote the original software. If you use this
- *    software in a product, an acknowledgment in
- *    the product documentation would be appreciated
- *    but is not required.
- *
- * 2. Altered source versions must be plainly marked
- *    as such, and must not be misrepresented as
- *    being the original software.
- *
- * 3. This notice may not be removed or altered from
- *    any source distribution.
- */
-
-/*
- * tinflate javascript port by Erik Moller in May 2011.
- * emoller@opera.com
- * 
- * read_bits() patched by mike@imidio.com to allow
- * reading more then 8 bits (needed in some zlib streams)
- */
-
-"use strict";
-
-function TINF() {
-    
-this.OK = 0;
-this.DATA_ERROR = (-3);
-this.WINDOW_SIZE = 32768;
-
-/* ------------------------------ *
- * -- internal data structures -- *
- * ------------------------------ */
-
-this.TREE = function() {
-   this.table = new Array(16);  /* table of code length counts */
-   this.trans = new Array(288); /* code -> symbol translation table */
-};
-
-this.DATA = function(that) {
-   this.source = '';
-   this.sourceIndex = 0;
-   this.tag = 0;
-   this.bitcount = 0;
-
-   this.dest = [];
-   
-   this.history = [];
-
-   this.ltree = new that.TREE(); /* dynamic length/symbol tree */
-   this.dtree = new that.TREE(); /* dynamic distance tree */
-};
-
-/* --------------------------------------------------- *
- * -- uninitialized global data (static structures) -- *
- * --------------------------------------------------- */
-
-this.sltree = new this.TREE(); /* fixed length/symbol tree */
-this.sdtree = new this.TREE(); /* fixed distance tree */
-
-/* extra bits and base tables for length codes */
-this.length_bits = new Array(30);
-this.length_base = new Array(30);
-
-/* extra bits and base tables for distance codes */
-this.dist_bits = new Array(30);
-this.dist_base = new Array(30);
-
-/* special ordering of code length codes */
-this.clcidx = [
-   16, 17, 18, 0, 8, 7, 9, 6,
-   10, 5, 11, 4, 12, 3, 13, 2,
-   14, 1, 15
-];
-
-/* ----------------------- *
- * -- utility functions -- *
- * ----------------------- */
-
-/* build extra bits and base tables */
-this.build_bits_base = function(bits, base, delta, first)
-{
-   var i, sum;
-
-   /* build bits table */
-   for (i = 0; i < delta; ++i) bits[i] = 0;
-   for (i = 0; i < 30 - delta; ++i) bits[i + delta] = Math.floor(i / delta);
-
-   /* build base table */
-   for (sum = first, i = 0; i < 30; ++i)
-   {
-      base[i] = sum;
-      sum += 1 << bits[i];
-   }
-}
-
-/* build the fixed huffman trees */
-this.build_fixed_trees = function(lt, dt)
-{
-   var i;
-
-   /* build fixed length tree */
-   for (i = 0; i < 7; ++i) lt.table[i] = 0;
-
-   lt.table[7] = 24;
-   lt.table[8] = 152;
-   lt.table[9] = 112;
-
-   for (i = 0; i < 24; ++i) lt.trans[i] = 256 + i;
-   for (i = 0; i < 144; ++i) lt.trans[24 + i] = i;
-   for (i = 0; i < 8; ++i) lt.trans[24 + 144 + i] = 280 + i;
-   for (i = 0; i < 112; ++i) lt.trans[24 + 144 + 8 + i] = 144 + i;
-
-   /* build fixed distance tree */
-   for (i = 0; i < 5; ++i) dt.table[i] = 0;
-
-   dt.table[5] = 32;
-
-   for (i = 0; i < 32; ++i) dt.trans[i] = i;
-}
-
-/* given an array of code lengths, build a tree */
-this.build_tree = function(t, lengths, loffset, num)
-{
-   var offs = new Array(16);
-   var i, sum;
-
-   /* clear code length count table */
-   for (i = 0; i < 16; ++i) t.table[i] = 0;
-
-   /* scan symbol lengths, and sum code length counts */
-   for (i = 0; i < num; ++i) t.table[lengths[loffset + i]]++;
-
-   t.table[0] = 0;
-
-   /* compute offset table for distribution sort */
-   for (sum = 0, i = 0; i < 16; ++i)
-   {
-      offs[i] = sum;
-      sum += t.table[i];
-   }
-
-   /* create code->symbol translation table (symbols sorted by code) */
-   for (i = 0; i < num; ++i)
-   {
-      if (lengths[loffset + i]) t.trans[offs[lengths[loffset + i]]++] = i;
-   }
-}
-
-/* ---------------------- *
- * -- decode functions -- *
- * ---------------------- */
-
-/* get one bit from source stream */
-this.getbit = function(d)
-{
-   var bit;
-
-   /* check if tag is empty */
-   if (!d.bitcount--)
-   {
-      /* load next tag */
-      d.tag = d.source[d.sourceIndex++] & 0xff;
-      d.bitcount = 7;
-   }
-
-   /* shift bit out of tag */
-   bit = d.tag & 0x01;
-   d.tag >>= 1;
-
-   return bit;
-}
-
-/* read a num bit value from a stream and add base */
-function read_bits_direct(source, bitcount, tag, idx, num)
-{
-    var val = 0;
-    while (bitcount < 24) {
-        tag = tag | (source[idx++] & 0xff) << bitcount;
-        bitcount += 8;
-    }
-    val = tag & (0xffff >> (16 - num));
-    tag >>= num;
-    bitcount -= num;
-    return [bitcount, tag, idx, val];
-}
-this.read_bits = function(d, num, base)
-{
-    if (!num)
-        return base;
-
-    var ret = read_bits_direct(d.source, d.bitcount, d.tag, d.sourceIndex, num);
-    d.bitcount = ret[0];
-    d.tag = ret[1];
-    d.sourceIndex = ret[2];
-    return ret[3] + base;
-}
-
-/* given a data stream and a tree, decode a symbol */
-this.decode_symbol = function(d, t)
-{
-    while (d.bitcount < 16) {
-        d.tag = d.tag | (d.source[d.sourceIndex++] & 0xff) << d.bitcount;
-        d.bitcount += 8;
-    }
-    
-    var sum = 0, cur = 0, len = 0;
-    do {
-        cur = 2 * cur + ((d.tag & (1 << len)) >> len);
-
-        ++len;
-
-        sum += t.table[len];
-        cur -= t.table[len];
-
-    } while (cur >= 0);
-
-    d.tag >>= len;
-    d.bitcount -= len;
-
-    return t.trans[sum + cur];
-}
-
-/* given a data stream, decode dynamic trees from it */
-this.decode_trees = function(d, lt, dt)
-{
-   var code_tree = new this.TREE();
-   var lengths = new Array(288+32);
-   var hlit, hdist, hclen;
-   var i, num, length;
-
-   /* get 5 bits HLIT (257-286) */
-   hlit = this.read_bits(d, 5, 257);
-
-   /* get 5 bits HDIST (1-32) */
-   hdist = this.read_bits(d, 5, 1);
-
-   /* get 4 bits HCLEN (4-19) */
-   hclen = this.read_bits(d, 4, 4);
-
-   for (i = 0; i < 19; ++i) lengths[i] = 0;
-
-   /* read code lengths for code length alphabet */
-   for (i = 0; i < hclen; ++i)
-   {
-      /* get 3 bits code length (0-7) */
-      var clen = this.read_bits(d, 3, 0);
-
-      lengths[this.clcidx[i]] = clen;
-   }
-
-   /* build code length tree */
-   this.build_tree(code_tree, lengths, 0, 19);
-
-   /* decode code lengths for the dynamic trees */
-   for (num = 0; num < hlit + hdist; )
-   {
-      var sym = this.decode_symbol(d, code_tree);
-
-      switch (sym)
-      {
-      case 16:
-         /* copy previous code length 3-6 times (read 2 bits) */
-         {
-            var prev = lengths[num - 1];
-            for (length = this.read_bits(d, 2, 3); length; --length)
-            {
-               lengths[num++] = prev;
-            }
-         }
-         break;
-      case 17:
-         /* repeat code length 0 for 3-10 times (read 3 bits) */
-         for (length = this.read_bits(d, 3, 3); length; --length)
-         {
-            lengths[num++] = 0;
-         }
-         break;
-      case 18:
-         /* repeat code length 0 for 11-138 times (read 7 bits) */
-         for (length = this.read_bits(d, 7, 11); length; --length)
-         {
-            lengths[num++] = 0;
-         }
-         break;
-      default:
-         /* values 0-15 represent the actual code lengths */
-         lengths[num++] = sym;
-         break;
-      }
-   }
-
-   /* build dynamic trees */
-   this.build_tree(lt, lengths, 0, hlit);
-   this.build_tree(dt, lengths, hlit, hdist);
-}
-
-/* ----------------------------- *
- * -- block inflate functions -- *
- * ----------------------------- */
-
-/* given a stream and two trees, inflate a block of data */
-this.inflate_block_data = function(d, lt, dt)
-{
-   // js optimization.
-   var ddest = d.dest;
-   var ddestlength = ddest.length;
-
-   while (1)
-   {
-      var sym = this.decode_symbol(d, lt);
-
-      /* check for end of block */
-      if (sym == 256)
-      {
-         return this.OK;
-      }
-
-      if (sym < 256)
-      {
-         ddest[ddestlength++] = sym; // ? String.fromCharCode(sym);
-         d.history.push(sym);
-      } else {
-
-         var length, dist, offs;
-         var i;
-
-         sym -= 257;
-
-         /* possibly get more bits from length code */
-         length = this.read_bits(d, this.length_bits[sym], this.length_base[sym]);
-
-         dist = this.decode_symbol(d, dt);
-
-         /* possibly get more bits from distance code */
-         offs = d.history.length - this.read_bits(d, this.dist_bits[dist], this.dist_base[dist]);
-
-         if (offs < 0)
-             throw ("Invalid zlib offset " + offs);
-         
-         /* copy match */
-         for (i = offs; i < offs + length; ++i) {
-            //ddest[ddestlength++] = ddest[i];
-            ddest[ddestlength++] = d.history[i];
-            d.history.push(d.history[i]);
-         }
-      }
-   }
-}
-
-/* inflate an uncompressed block of data */
-this.inflate_uncompressed_block = function(d)
-{
-   var length, invlength;
-   var i;
-
-   if (d.bitcount > 7) {
-       var overflow = Math.floor(d.bitcount / 8);
-       d.sourceIndex -= overflow;
-       d.bitcount = 0;
-       d.tag = 0;
-   }
-   
-   /* get length */
-   length = d.source[d.sourceIndex+1];
-   length = 256*length + d.source[d.sourceIndex];
-
-   /* get one's complement of length */
-   invlength = d.source[d.sourceIndex+3];
-   invlength = 256*invlength + d.source[d.sourceIndex+2];
-
-   /* check length */
-   if (length != (~invlength & 0x0000ffff)) return this.DATA_ERROR;
-
-   d.sourceIndex += 4;
-
-   /* copy block */
-   for (i = length; i; --i) {
-       d.history.push(d.source[d.sourceIndex]);
-       d.dest[d.dest.length] = d.source[d.sourceIndex++];
-   }
-
-   /* make sure we start next block on a byte boundary */
-   d.bitcount = 0;
-
-   return this.OK;
-}
-
-/* inflate a block of data compressed with fixed huffman trees */
-this.inflate_fixed_block = function(d)
-{
-   /* decode block using fixed trees */
-   return this.inflate_block_data(d, this.sltree, this.sdtree);
-}
-
-/* inflate a block of data compressed with dynamic huffman trees */
-this.inflate_dynamic_block = function(d)
-{
-   /* decode trees from stream */
-   this.decode_trees(d, d.ltree, d.dtree);
-
-   /* decode block using decoded trees */
-   return this.inflate_block_data(d, d.ltree, d.dtree);
-}
-
-/* ---------------------- *
- * -- public functions -- *
- * ---------------------- */
-
-/* initialize global (static) data */
-this.init = function()
-{
-   /* build fixed huffman trees */
-   this.build_fixed_trees(this.sltree, this.sdtree);
-
-   /* build extra bits and base tables */
-   this.build_bits_base(this.length_bits, this.length_base, 4, 3);
-   this.build_bits_base(this.dist_bits, this.dist_base, 2, 1);
-
-   /* fix a special case */
-   this.length_bits[28] = 0;
-   this.length_base[28] = 258;
-
-   this.reset();   
-}
-
-this.reset = function()
-{
-   this.d = new this.DATA(this);
-   delete this.header;
-}
-
-/* inflate stream from source to dest */
-this.uncompress = function(source, offset)
-{
-
-   var d = this.d;
-   var bfinal;
-
-   /* initialise data */
-   d.source = source;
-   d.sourceIndex = offset;
-   d.bitcount = 0;
-
-   d.dest = [];
-
-   // Skip zlib header at start of stream
-   if (typeof this.header == 'undefined') {
-       this.header = this.read_bits(d, 16, 0);
-       /* byte 0: 0x78, 7 = 32k window size, 8 = deflate */
-       /* byte 1: check bits for header and other flags */
-   }
-
-   var blocks = 0;
-   
-   do {
-
-      var btype;
-      var res;
-
-      /* read final block flag */
-      bfinal = this.getbit(d);
-
-      /* read block type (2 bits) */
-      btype = this.read_bits(d, 2, 0);
-
-      /* decompress block */
-      switch (btype)
-      {
-      case 0:
-         /* decompress uncompressed block */
-         res = this.inflate_uncompressed_block(d);
-         break;
-      case 1:
-         /* decompress block with fixed huffman trees */
-         res = this.inflate_fixed_block(d);
-         break;
-      case 2:
-         /* decompress block with dynamic huffman trees */
-         res = this.inflate_dynamic_block(d);
-         break;
-      default:
-         return { 'status' : this.DATA_ERROR };
-      }
-
-      if (res != this.OK) return { 'status' : this.DATA_ERROR };
-      blocks++;
-      
-   } while (!bfinal && d.sourceIndex < d.source.length);
-
-   d.history = d.history.slice(-this.WINDOW_SIZE);
-   
-   return { 'status' : this.OK, 'data' : d.dest };
-}
-
-};
diff --git a/circle/dashboard/static/dashboard/novnc/logo.js b/circle/dashboard/static/dashboard/novnc/logo.js
deleted file mode 100644
index befa598..0000000
--- a/circle/dashboard/static/dashboard/novnc/logo.js
+++ /dev/null
@@ -1 +0,0 @@
-noVNC_logo = {"width": 640, "height": 435, "data": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAGzCAYAAAC/y6a9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAStAAAErQBBHTWggAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAACAASURBVHic7N13fBvlwQfw3522ZMm2vPdIGCFkA4GyoYyGsCmjk+7dQksHL2/H2/dtC4W2tLTlfelu2VA2lEILFCgQIHEGJCQkdjzkLdmWZGvfvX8oOkmJEy/pNO73/Xz44DtLzz2RT7qfnnXC8uXLZUxDlqfdnUYQhIP+bjbPn+5xhypzrmUf6rGzOc5cjzVduXN9/nTPyfRrMt/jzOcY05U5n3L2f95s/34LPW4m/p6FbLp/73xe+5nKnWuZs/07ZOOcnusx5nucbJU727LneuxslDmdTBxn/2NmusyEuZS7kHMxG/XP5Gf3TOVmQzY+u/PhPMnkMcSsH5WIiIiI8goDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHGMAASERERaQwDIBEREZHG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"};
diff --git a/circle/dashboard/static/dashboard/novnc/playback.js b/circle/dashboard/static/dashboard/novnc/playback.js
deleted file mode 100644
index 7756529..0000000
--- a/circle/dashboard/static/dashboard/novnc/playback.js
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- */
-
-"use strict";
-/*jslint browser: true, white: false */
-/*global Util, VNC_frame_data, finish */
-
-var rfb, mode, test_state, frame_idx, frame_length,
-    iteration, iterations, istart_time,
-
-    // Pre-declarations for jslint
-    send_array, next_iteration, queue_next_packet, do_packet;
-
-// Override send_array
-send_array = function (arr) {
-    // Stub out send_array
-};
-
-next_iteration = function () {
-    if (iteration === 0) {
-        frame_length = VNC_frame_data.length;
-        test_state = 'running';
-    } else {
-        rfb.disconnect();
-    }
-    
-    if (test_state !== 'running') { return; }
-
-    iteration += 1;
-    if (iteration > iterations) {
-        finish();
-        return;
-    }
-
-    frame_idx = 0;
-    istart_time = (new Date()).getTime();
-    rfb.connect('test', 0, "bogus");
-
-    queue_next_packet();
-
-};
-
-queue_next_packet = function () {
-    var frame, foffset, toffset, delay;
-    if (test_state !== 'running') { return; }
-
-    frame = VNC_frame_data[frame_idx];
-    while ((frame_idx < frame_length) && (frame.charAt(0) === "}")) {
-        //Util.Debug("Send frame " + frame_idx);
-        frame_idx += 1;
-        frame = VNC_frame_data[frame_idx];
-    }
-
-    if (frame === 'EOF') {
-        Util.Debug("Finished, found EOF");
-        next_iteration();
-        return;
-    }
-    if (frame_idx >= frame_length) {
-        Util.Debug("Finished, no more frames");
-        next_iteration();
-        return;
-    }
-
-    if (mode === 'realtime') {
-        foffset = frame.slice(1, frame.indexOf('{', 1));
-        toffset = (new Date()).getTime() - istart_time;
-        delay = foffset - toffset;
-        if (delay < 1) {
-            delay = 1;
-        }
-
-        setTimeout(do_packet, delay);
-    } else {
-        setTimeout(do_packet, 1);
-    }
-};
-
-var bytes_processed = 0;
-
-do_packet = function () {
-    //Util.Debug("Processing frame: " + frame_idx);
-    var frame = VNC_frame_data[frame_idx],
-        start = frame.indexOf('{', 1) + 1;
-    bytes_processed += frame.length - start;
-    if (VNC_frame_encoding === 'binary') {
-        var u8 = new Uint8Array(frame.length - start);
-        for (var i = 0; i < frame.length - start; i++) {
-            u8[i] = frame.charCodeAt(start + i);
-        }
-        rfb.recv_message({'data' : u8});
-    } else {
-        rfb.recv_message({'data' : frame.slice(start)});
-    }
-    frame_idx += 1;
-
-    queue_next_packet();
-};
-
diff --git a/circle/dashboard/static/dashboard/novnc/rfb.js b/circle/dashboard/static/dashboard/novnc/rfb.js
deleted file mode 100644
index 16ae76d..0000000
--- a/circle/dashboard/static/dashboard/novnc/rfb.js
+++ /dev/null
@@ -1,1872 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2013 Samuel Mannehed for Cendio AB
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- *
- * TIGHT decoder portion:
- * (c) 2012 Michael Tinglof, Joe Balaz, Les Piech (Mercuri.ca)
- */
-
-/*jslint white: false, browser: true, bitwise: false, plusplus: false */
-/*global window, Util, Display, Keyboard, Mouse, Websock, Websock_native, Base64, DES */
-
-
-function RFB(defaults) {
-"use strict";
-
-var that           = {},  // Public API methods
-    conf           = {},  // Configuration attributes
-
-    // Pre-declare private functions used before definitions (jslint)
-    init_vars, updateState, fail, handle_message,
-    init_msg, normal_msg, framebufferUpdate, print_stats,
-
-    pixelFormat, clientEncodings, fbUpdateRequest, fbUpdateRequests,
-    keyEvent, pointerEvent, clientCutText,
-
-    getTightCLength, extract_data_uri,
-    keyPress, mouseButton, mouseMove,
-
-    checkEvents,  // Overridable for testing
-
-
-    //
-    // Private RFB namespace variables
-    //
-    rfb_host       = '',
-    rfb_port       = 5900,
-    rfb_password   = '',
-    rfb_path       = '',
-
-    rfb_state      = 'disconnected',
-    rfb_version    = 0,
-    rfb_max_version= 3.8,
-    rfb_auth_scheme= '',
-
-
-    // In preference order
-    encodings      = [
-        ['COPYRECT',         0x01 ],
-        ['TIGHT',            0x07 ],
-        ['TIGHT_PNG',        -260 ],
-        ['HEXTILE',          0x05 ],
-        ['RRE',              0x02 ],
-        ['RAW',              0x00 ],
-        ['DesktopSize',      -223 ],
-        ['Cursor',           -239 ],
-
-        // Psuedo-encoding settings
-        //['JPEG_quality_lo',   -32 ],
-        ['JPEG_quality_med',    -26 ],
-        //['JPEG_quality_hi',   -23 ],
-        //['compress_lo',      -255 ],
-        ['compress_hi',        -247 ],
-        ['last_rect',          -224 ]
-        ],
-
-    encHandlers    = {},
-    encNames       = {}, 
-    encStats       = {},     // [rectCnt, rectCntTot]
-
-    ws             = null,   // Websock object
-    display        = null,   // Display object
-    keyboard       = null,   // Keyboard input handler object
-    mouse          = null,   // Mouse input handler object
-    sendTimer      = null,   // Send Queue check timer
-    connTimer      = null,   // connection timer
-    disconnTimer   = null,   // disconnection timer
-    msgTimer       = null,   // queued handle_message timer
-
-    // Frame buffer update state
-    FBU            = {
-        rects          : 0,
-        subrects       : 0,  // RRE
-        lines          : 0,  // RAW
-        tiles          : 0,  // HEXTILE
-        bytes          : 0,
-        x              : 0,
-        y              : 0,
-        width          : 0, 
-        height         : 0,
-        encoding       : 0,
-        subencoding    : -1,
-        background     : null,
-        zlibs          : []   // TIGHT zlib streams
-    },
-
-    fb_Bpp         = 4,
-    fb_depth       = 3,
-    fb_width       = 0,
-    fb_height      = 0,
-    fb_name        = "",
-
-    last_req_time  = 0,
-    rre_chunk_sz   = 100,
-
-    timing         = {
-        last_fbu       : 0,
-        fbu_total      : 0,
-        fbu_total_cnt  : 0,
-        full_fbu_total : 0,
-        full_fbu_cnt   : 0,
-
-        fbu_rt_start   : 0,
-        fbu_rt_total   : 0,
-        fbu_rt_cnt     : 0,
-        pixels         : 0
-    },
-
-    test_mode        = false,
-
-    def_con_timeout  = Websock_native ? 2 : 5,
-
-    /* Mouse state */
-    mouse_buttonMask = 0,
-    mouse_arr        = [],
-    viewportDragging = false,
-    viewportDragPos  = {};
-
-// Configuration attributes
-Util.conf_defaults(conf, that, defaults, [
-    ['target',             'wo', 'dom', null, 'VNC display rendering Canvas object'],
-    ['focusContainer',     'wo', 'dom', document, 'DOM element that captures keyboard input'],
-
-    ['encrypt',            'rw', 'bool', false, 'Use TLS/SSL/wss encryption'],
-    ['true_color',         'rw', 'bool', true,  'Request true color pixel data'],
-    ['local_cursor',       'rw', 'bool', false, 'Request locally rendered cursor'],
-    ['shared',             'rw', 'bool', true,  'Request shared mode'],
-    ['view_only',          'rw', 'bool', false, 'Disable client mouse/keyboard'],
-
-    ['connectTimeout',     'rw', 'int', def_con_timeout, 'Time (s) to wait for connection'],
-    ['disconnectTimeout',  'rw', 'int', 3,    'Time (s) to wait for disconnection'],
-
-    // UltraVNC repeater ID to connect to
-    ['repeaterID',         'rw', 'str',  '',    'RepeaterID to connect to'],
-
-    ['viewportDrag',       'rw', 'bool', false, 'Move the viewport on mouse drags'],
-
-    ['check_rate',         'rw', 'int', 217,  'Timing (ms) of send/receive check'],
-    ['fbu_req_rate',       'rw', 'int', 1413, 'Timing (ms) of frameBufferUpdate requests'],
-
-    // Callback functions
-    ['onUpdateState',      'rw', 'func', function() { },
-        'onUpdateState(rfb, state, oldstate, statusMsg): RFB state update/change '],
-    ['onPasswordRequired', 'rw', 'func', function() { },
-        'onPasswordRequired(rfb): VNC password is required '],
-    ['onClipboard',        'rw', 'func', function() { },
-        'onClipboard(rfb, text): RFB clipboard contents received'],
-    ['onBell',             'rw', 'func', function() { },
-        'onBell(rfb): RFB Bell message received '],
-    ['onFBUReceive',       'rw', 'func', function() { },
-        'onFBUReceive(rfb, fbu): RFB FBU received but not yet processed '],
-    ['onFBUComplete',      'rw', 'func', function() { },
-        'onFBUComplete(rfb, fbu): RFB FBU received and processed '],
-    ['onFBResize',         'rw', 'func', function() { },
-        'onFBResize(rfb, width, height): frame buffer resized'],
-    ['onDesktopName',      'rw', 'func', function() { },
-        'onDesktopName(rfb, name): desktop name received'],
-
-    // These callback names are deprecated
-    ['updateState',        'rw', 'func', function() { },
-        'obsolete, use onUpdateState'],
-    ['clipboardReceive',   'rw', 'func', function() { },
-        'obsolete, use onClipboard']
-    ]);
-
-
-// Override/add some specific configuration getters/setters
-that.set_local_cursor = function(cursor) {
-    if ((!cursor) || (cursor in {'0':1, 'no':1, 'false':1})) {
-        conf.local_cursor = false;
-    } else {
-        if (display.get_cursor_uri()) {
-            conf.local_cursor = true;
-        } else {
-            Util.Warn("Browser does not support local cursor");
-        }
-    }
-};
-
-// These are fake configuration getters
-that.get_display = function() { return display; };
-
-that.get_keyboard = function() { return keyboard; };
-
-that.get_mouse = function() { return mouse; };
-
-
-
-//
-// Setup routines
-//
-
-// Create the public API interface and initialize values that stay
-// constant across connect/disconnect
-function constructor() {
-    var i, rmode;
-    Util.Debug(">> RFB.constructor");
-
-    // Create lookup tables based encoding number
-    for (i=0; i < encodings.length; i+=1) {
-        encHandlers[encodings[i][1]] = encHandlers[encodings[i][0]];
-        encNames[encodings[i][1]] = encodings[i][0];
-        encStats[encodings[i][1]] = [0, 0];
-    }
-    // Initialize display, mouse, keyboard, and websock
-    try {
-        display   = new Display({'target': conf.target});
-    } catch (exc) {
-        Util.Error("Display exception: " + exc);
-        updateState('fatal', "No working Display");
-    }
-    keyboard = new Keyboard({'target': conf.focusContainer,
-                                'onKeyPress': keyPress});
-    mouse    = new Mouse({'target': conf.target,
-                            'onMouseButton': mouseButton,
-                            'onMouseMove': mouseMove});
-
-    rmode = display.get_render_mode();
-
-    ws = new Websock();
-    ws.on('message', handle_message);
-    ws.on('open', function() {
-        if (rfb_state === "connect") {
-            updateState('ProtocolVersion', "Starting VNC handshake");
-        } else {
-            fail("Got unexpected WebSockets connection");
-        }
-    });
-    ws.on('close', function(e) {
-        Util.Warn("WebSocket on-close event");
-        var msg = "";
-        if (e.code) {
-            msg = " (code: " + e.code;
-            if (e.reason) {
-                msg += ", reason: " + e.reason;
-            }
-            msg += ")";
-        }
-        if (rfb_state === 'disconnect') {
-            updateState('disconnected', 'VNC disconnected' + msg);
-        } else if (rfb_state === 'ProtocolVersion') {
-            fail('Failed to connect to server' + msg);
-        } else if (rfb_state in {'failed':1, 'disconnected':1}) {
-            Util.Error("Received onclose while disconnected" + msg);
-        } else  {
-            fail('Server disconnected' + msg);
-        }
-    });
-    ws.on('error', function(e) {
-        Util.Warn("WebSocket on-error event");
-        //fail("WebSock reported an error");
-    });
-
-
-    init_vars();
-
-    /* Check web-socket-js if no builtin WebSocket support */
-    if (Websock_native) {
-        Util.Info("Using native WebSockets");
-        updateState('loaded', 'noVNC ready: native WebSockets, ' + rmode);
-    } else {
-        Util.Warn("Using web-socket-js bridge. Flash version: " +
-                  Util.Flash.version);
-        if ((! Util.Flash) ||
-            (Util.Flash.version < 9)) {
-            updateState('fatal', "WebSockets or <a href='http://get.adobe.com/flashplayer'>Adobe Flash<\/a> is required");
-        } else if (document.location.href.substr(0, 7) === "file://") {
-            updateState('fatal',
-                    "'file://' URL is incompatible with Adobe Flash");
-        } else {
-            updateState('loaded', 'noVNC ready: WebSockets emulation, ' + rmode);
-        }
-    }
-
-    Util.Debug("<< RFB.constructor");
-    return that;  // Return the public API interface
-}
-
-function connect() {
-    Util.Debug(">> RFB.connect");
-    var uri;
-    
-    if (typeof UsingSocketIO !== "undefined") {
-        uri = "http://" + rfb_host + ":" + rfb_port + "/" + rfb_path;
-    } else {
-        if (conf.encrypt) {
-            uri = "wss://";
-        } else {
-            uri = "ws://";
-        }
-        uri += rfb_host + ":" + rfb_port + "/" + rfb_path;
-    }
-    Util.Info("connecting to " + uri);
-    // TODO: make protocols a configurable
-    ws.open(uri, ['binary', 'base64']);
-
-    Util.Debug("<< RFB.connect");
-}
-
-// Initialize variables that are reset before each connection
-init_vars = function() {
-    var i;
-
-    /* Reset state */
-    ws.init();
-
-    FBU.rects        = 0;
-    FBU.subrects     = 0;  // RRE and HEXTILE
-    FBU.lines        = 0;  // RAW
-    FBU.tiles        = 0;  // HEXTILE
-    FBU.zlibs        = []; // TIGHT zlib encoders
-    mouse_buttonMask = 0;
-    mouse_arr        = [];
-
-    // Clear the per connection encoding stats
-    for (i=0; i < encodings.length; i+=1) {
-        encStats[encodings[i][1]][0] = 0;
-    }
-    
-    for (i=0; i < 4; i++) {
-        //FBU.zlibs[i] = new InflateStream();
-        FBU.zlibs[i] = new TINF();
-        FBU.zlibs[i].init();
-    }
-};
-
-// Print statistics
-print_stats = function() {
-    var i, s;
-    Util.Info("Encoding stats for this connection:");
-    for (i=0; i < encodings.length; i+=1) {
-        s = encStats[encodings[i][1]];
-        if ((s[0] + s[1]) > 0) {
-            Util.Info("    " + encodings[i][0] + ": " +
-                      s[0] + " rects");
-        }
-    }
-    Util.Info("Encoding stats since page load:");
-    for (i=0; i < encodings.length; i+=1) {
-        s = encStats[encodings[i][1]];
-        if ((s[0] + s[1]) > 0) {
-            Util.Info("    " + encodings[i][0] + ": " +
-                      s[1] + " rects");
-        }
-    }
-};
-
-//
-// Utility routines
-//
-
-
-/*
- * Page states:
- *   loaded       - page load, equivalent to disconnected
- *   disconnected - idle state
- *   connect      - starting to connect (to ProtocolVersion)
- *   normal       - connected
- *   disconnect   - starting to disconnect
- *   failed       - abnormal disconnect
- *   fatal        - failed to load page, or fatal error
- *
- * RFB protocol initialization states:
- *   ProtocolVersion 
- *   Security
- *   Authentication
- *   password     - waiting for password, not part of RFB
- *   SecurityResult
- *   ClientInitialization - not triggered by server message
- *   ServerInitialization (to normal)
- */
-updateState = function(state, statusMsg) {
-    var func, cmsg, oldstate = rfb_state;
-
-    if (state === oldstate) {
-        /* Already here, ignore */
-        Util.Debug("Already in state '" + state + "', ignoring.");
-        return;
-    }
-
-    /* 
-     * These are disconnected states. A previous connect may
-     * asynchronously cause a connection so make sure we are closed.
-     */
-    if (state in {'disconnected':1, 'loaded':1, 'connect':1,
-                  'disconnect':1, 'failed':1, 'fatal':1}) {
-        if (sendTimer) {
-            clearInterval(sendTimer);
-            sendTimer = null;
-        }
-
-        if (msgTimer) {
-            clearInterval(msgTimer);
-            msgTimer = null;
-        }
-
-        if (display && display.get_context()) {
-            keyboard.ungrab();
-            mouse.ungrab();
-            display.defaultCursor();
-            if ((Util.get_logging() !== 'debug') ||
-                (state === 'loaded')) {
-                // Show noVNC logo on load and when disconnected if
-                // debug is off
-                display.clear();
-            }
-        }
-
-        ws.close();
-    }
-
-    if (oldstate === 'fatal') {
-        Util.Error("Fatal error, cannot continue");
-    }
-
-    if ((state === 'failed') || (state === 'fatal')) {
-        func = Util.Error;
-    } else {
-        func = Util.Warn;
-    }
-
-    cmsg = typeof(statusMsg) !== 'undefined' ? (" Msg: " + statusMsg) : "";
-    func("New state '" + state + "', was '" + oldstate + "'." + cmsg);
-
-    if ((oldstate === 'failed') && (state === 'disconnected')) {
-        // Do disconnect action, but stay in failed state
-        rfb_state = 'failed';
-    } else {
-        rfb_state = state;
-    }
-
-    if (connTimer && (rfb_state !== 'connect')) {
-        Util.Debug("Clearing connect timer");
-        clearInterval(connTimer);
-        connTimer = null;
-    }
-
-    if (disconnTimer && (rfb_state !== 'disconnect')) {
-        Util.Debug("Clearing disconnect timer");
-        clearInterval(disconnTimer);
-        disconnTimer = null;
-    }
-
-    switch (state) {
-    case 'normal':
-        if ((oldstate === 'disconnected') || (oldstate === 'failed')) {
-            Util.Error("Invalid transition from 'disconnected' or 'failed' to 'normal'");
-        }
-
-        break;
-
-
-    case 'connect':
-        
-        connTimer = setTimeout(function () {
-                fail("Connect timeout");
-            }, conf.connectTimeout * 1000);
-
-        init_vars();
-        connect();
-
-        // WebSocket.onopen transitions to 'ProtocolVersion'
-        break;
-
-
-    case 'disconnect':
-
-        if (! test_mode) {
-            disconnTimer = setTimeout(function () {
-                    fail("Disconnect timeout");
-                }, conf.disconnectTimeout * 1000);
-        }
-
-        print_stats();
-
-        // WebSocket.onclose transitions to 'disconnected'
-        break;
-
-
-    case 'failed':
-        if (oldstate === 'disconnected') {
-            Util.Error("Invalid transition from 'disconnected' to 'failed'");
-        }
-        if (oldstate === 'normal') {
-            Util.Error("Error while connected.");
-        }
-        if (oldstate === 'init') {
-            Util.Error("Error while initializing.");
-        }
-
-        // Make sure we transition to disconnected
-        setTimeout(function() { updateState('disconnected'); }, 50);
-
-        break;
-
-
-    default:
-        // No state change action to take
-
-    }
-
-    if ((oldstate === 'failed') && (state === 'disconnected')) {
-        // Leave the failed message
-        conf.updateState(that, state, oldstate); // Obsolete
-        conf.onUpdateState(that, state, oldstate);
-    } else {
-        conf.updateState(that, state, oldstate, statusMsg); // Obsolete
-        conf.onUpdateState(that, state, oldstate, statusMsg);
-    }
-};
-
-fail = function(msg) {
-    updateState('failed', msg);
-    return false;
-};
-
-handle_message = function() {
-    //Util.Debug(">> handle_message ws.rQlen(): " + ws.rQlen());
-    //Util.Debug("ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
-    if (ws.rQlen() === 0) {
-        Util.Warn("handle_message called on empty receive queue");
-        return;
-    }
-    switch (rfb_state) {
-    case 'disconnected':
-    case 'failed':
-        Util.Error("Got data while disconnected");
-        break;
-    case 'normal':
-        if (normal_msg() && ws.rQlen() > 0) {
-            // true means we can continue processing
-            // Give other events a chance to run
-            if (msgTimer === null) {
-                Util.Debug("More data to process, creating timer");
-                msgTimer = setTimeout(function () {
-                            msgTimer = null;
-                            handle_message();
-                        }, 10);
-            } else {
-                Util.Debug("More data to process, existing timer");
-            }
-        }
-        break;
-    default:
-        init_msg();
-        break;
-    }
-};
-
-
-function genDES(password, challenge) {
-    var i, passwd = [];
-    for (i=0; i < password.length; i += 1) {
-        passwd.push(password.charCodeAt(i));
-    }
-    return (new DES(passwd)).encrypt(challenge);
-}
-
-function flushClient() {
-    if (mouse_arr.length > 0) {
-        //send(mouse_arr.concat(fbUpdateRequests()));
-        ws.send(mouse_arr);
-        setTimeout(function() {
-                ws.send(fbUpdateRequests());
-            }, 50);
-
-        mouse_arr = [];
-        return true;
-    } else {
-        return false;
-    }
-}
-
-// overridable for testing
-checkEvents = function() {
-    var now;
-    if (rfb_state === 'normal' && !viewportDragging) {
-        if (! flushClient()) {
-            now = new Date().getTime();
-            if (now > last_req_time + conf.fbu_req_rate) {
-                last_req_time = now;
-                ws.send(fbUpdateRequests());
-            }
-        }
-    }
-    setTimeout(checkEvents, conf.check_rate);
-};
-
-keyPress = function(keysym, down) {
-    var arr;
-
-    if (conf.view_only) { return; } // View only, skip keyboard events
-
-    arr = keyEvent(keysym, down);
-    arr = arr.concat(fbUpdateRequests());
-    ws.send(arr);
-};
-
-mouseButton = function(x, y, down, bmask) {
-    if (down) {
-        mouse_buttonMask |= bmask;
-    } else {
-        mouse_buttonMask ^= bmask;
-    }
-
-    if (conf.viewportDrag) {
-        if (down && !viewportDragging) {
-            viewportDragging = true;
-            viewportDragPos = {'x': x, 'y': y};
-
-            // Skip sending mouse events
-            return;
-        } else {
-            viewportDragging = false;
-            ws.send(fbUpdateRequests()); // Force immediate redraw
-        }
-    }
-
-    if (conf.view_only) { return; } // View only, skip mouse events
-
-    mouse_arr = mouse_arr.concat(
-            pointerEvent(display.absX(x), display.absY(y)) );
-    flushClient();
-};
-
-mouseMove = function(x, y) {
-    //Util.Debug('>> mouseMove ' + x + "," + y);
-    var deltaX, deltaY;
-
-    if (viewportDragging) {
-        //deltaX = x - viewportDragPos.x; // drag viewport
-        deltaX = viewportDragPos.x - x; // drag frame buffer
-        //deltaY = y - viewportDragPos.y; // drag viewport
-        deltaY = viewportDragPos.y - y; // drag frame buffer
-        viewportDragPos = {'x': x, 'y': y};
-
-        display.viewportChange(deltaX, deltaY);
-
-        // Skip sending mouse events
-        return;
-    }
-
-    if (conf.view_only) { return; } // View only, skip mouse events
-
-    mouse_arr = mouse_arr.concat(
-            pointerEvent(display.absX(x), display.absY(y)) );
-};
-
-
-//
-// Server message handlers
-//
-
-// RFB/VNC initialisation message handler
-init_msg = function() {
-    //Util.Debug(">> init_msg [rfb_state '" + rfb_state + "']");
-
-    var strlen, reason, length, sversion, cversion, repeaterID,
-        i, types, num_types, challenge, response, bpp, depth,
-        big_endian, red_max, green_max, blue_max, red_shift,
-        green_shift, blue_shift, true_color, name_length, is_repeater;
-
-    //Util.Debug("ws.rQ (" + ws.rQlen() + ") " + ws.rQslice(0));
-    switch (rfb_state) {
-
-    case 'ProtocolVersion' :
-        if (ws.rQlen() < 12) {
-            return fail("Incomplete protocol version");
-        }
-        sversion = ws.rQshiftStr(12).substr(4,7);
-        Util.Info("Server ProtocolVersion: " + sversion);
-        is_repeater = 0;
-        switch (sversion) {
-            case "000.000": is_repeater = 1; break; // UltraVNC repeater
-            case "003.003": rfb_version = 3.3; break;
-            case "003.006": rfb_version = 3.3; break;  // UltraVNC
-            case "003.889": rfb_version = 3.3; break;  // Apple Remote Desktop
-            case "003.007": rfb_version = 3.7; break;
-            case "003.008": rfb_version = 3.8; break;
-            case "004.000": rfb_version = 3.8; break;  // Intel AMT KVM
-            case "004.001": rfb_version = 3.8; break;  // RealVNC 4.6
-            default:
-                return fail("Invalid server version " + sversion);
-        }
-        if (is_repeater) { 
-            repeaterID = conf.repeaterID;
-            while (repeaterID.length < 250) {
-                repeaterID += "\0";
-            }
-            ws.send_string(repeaterID);
-            break;
-        }
-        if (rfb_version > rfb_max_version) { 
-            rfb_version = rfb_max_version;
-        }
-
-        if (! test_mode) {
-            sendTimer = setInterval(function() {
-                    // Send updates either at a rate of one update
-                    // every 50ms, or whatever slower rate the network
-                    // can handle.
-                    ws.flush();
-                }, 50);
-        }
-
-        cversion = "00" + parseInt(rfb_version,10) +
-                   ".00" + ((rfb_version * 10) % 10);
-        ws.send_string("RFB " + cversion + "\n");
-        updateState('Security', "Sent ProtocolVersion: " + cversion);
-        break;
-
-    case 'Security' :
-        if (rfb_version >= 3.7) {
-            // Server sends supported list, client decides 
-            num_types = ws.rQshift8();
-            if (ws.rQwait("security type", num_types, 1)) { return false; }
-            if (num_types === 0) {
-                strlen = ws.rQshift32();
-                reason = ws.rQshiftStr(strlen);
-                return fail("Security failure: " + reason);
-            }
-            rfb_auth_scheme = 0;
-            types = ws.rQshiftBytes(num_types);
-            Util.Debug("Server security types: " + types);
-            for (i=0; i < types.length; i+=1) {
-                if ((types[i] > rfb_auth_scheme) && (types[i] < 3)) {
-                    rfb_auth_scheme = types[i];
-                }
-            }
-            if (rfb_auth_scheme === 0) {
-                return fail("Unsupported security types: " + types);
-            }
-            
-            ws.send([rfb_auth_scheme]);
-        } else {
-            // Server decides
-            if (ws.rQwait("security scheme", 4)) { return false; }
-            rfb_auth_scheme = ws.rQshift32();
-        }
-        updateState('Authentication',
-                "Authenticating using scheme: " + rfb_auth_scheme);
-        init_msg();  // Recursive fallthrough (workaround JSLint complaint)
-        break;
-
-    // Triggered by fallthough, not by server message
-    case 'Authentication' :
-        //Util.Debug("Security auth scheme: " + rfb_auth_scheme);
-        switch (rfb_auth_scheme) {
-            case 0:  // connection failed
-                if (ws.rQwait("auth reason", 4)) { return false; }
-                strlen = ws.rQshift32();
-                reason = ws.rQshiftStr(strlen);
-                return fail("Auth failure: " + reason);
-            case 1:  // no authentication
-                if (rfb_version >= 3.8) {
-                    updateState('SecurityResult');
-                    return;
-                }
-                // Fall through to ClientInitialisation
-                break;
-            case 2:  // VNC authentication
-                if (rfb_password.length === 0) {
-                    // Notify via both callbacks since it is kind of
-                    // a RFB state change and a UI interface issue.
-                    updateState('password', "Password Required");
-                    conf.onPasswordRequired(that);
-                    return;
-                }
-                if (ws.rQwait("auth challenge", 16)) { return false; }
-                challenge = ws.rQshiftBytes(16);
-                //Util.Debug("Password: " + rfb_password);
-                //Util.Debug("Challenge: " + challenge +
-                //           " (" + challenge.length + ")");
-                response = genDES(rfb_password, challenge);
-                //Util.Debug("Response: " + response +
-                //           " (" + response.length + ")");
-                
-                //Util.Debug("Sending DES encrypted auth response");
-                ws.send(response);
-                updateState('SecurityResult');
-                return;
-            default:
-                fail("Unsupported auth scheme: " + rfb_auth_scheme);
-                return;
-        }
-        updateState('ClientInitialisation', "No auth required");
-        init_msg();  // Recursive fallthrough (workaround JSLint complaint)
-        break;
-
-    case 'SecurityResult' :
-        if (ws.rQwait("VNC auth response ", 4)) { return false; }
-        switch (ws.rQshift32()) {
-            case 0:  // OK
-                // Fall through to ClientInitialisation
-                break;
-            case 1:  // failed
-                if (rfb_version >= 3.8) {
-                    length = ws.rQshift32();
-                    if (ws.rQwait("SecurityResult reason", length, 8)) {
-                        return false;
-                    }
-                    reason = ws.rQshiftStr(length);
-                    fail(reason);
-                } else {
-                    fail("Authentication failed");
-                }
-                return;
-            case 2:  // too-many
-                return fail("Too many auth attempts");
-        }
-        updateState('ClientInitialisation', "Authentication OK");
-        init_msg();  // Recursive fallthrough (workaround JSLint complaint)
-        break;
-
-    // Triggered by fallthough, not by server message
-    case 'ClientInitialisation' :
-        ws.send([conf.shared ? 1 : 0]); // ClientInitialisation
-        updateState('ServerInitialisation', "Authentication OK");
-        break;
-
-    case 'ServerInitialisation' :
-        if (ws.rQwait("server initialization", 24)) { return false; }
-
-        /* Screen size */
-        fb_width  = ws.rQshift16();
-        fb_height = ws.rQshift16();
-
-        /* PIXEL_FORMAT */
-        bpp            = ws.rQshift8();
-        depth          = ws.rQshift8();
-        big_endian     = ws.rQshift8();
-        true_color     = ws.rQshift8();
-
-        red_max        = ws.rQshift16();
-        green_max      = ws.rQshift16();
-        blue_max       = ws.rQshift16();
-        red_shift      = ws.rQshift8();
-        green_shift    = ws.rQshift8();
-        blue_shift     = ws.rQshift8();
-        ws.rQshiftStr(3); // padding
-
-        Util.Info("Screen: " + fb_width + "x" + fb_height + 
-                  ", bpp: " + bpp + ", depth: " + depth +
-                  ", big_endian: " + big_endian +
-                  ", true_color: " + true_color +
-                  ", red_max: " + red_max +
-                  ", green_max: " + green_max +
-                  ", blue_max: " + blue_max +
-                  ", red_shift: " + red_shift +
-                  ", green_shift: " + green_shift +
-                  ", blue_shift: " + blue_shift);
-
-        if (big_endian !== 0) {
-            Util.Warn("Server native endian is not little endian");
-        }
-        if (red_shift !== 16) {
-            Util.Warn("Server native red-shift is not 16");
-        }
-        if (blue_shift !== 0) {
-            Util.Warn("Server native blue-shift is not 0");
-        }
-
-        /* Connection name/title */
-        name_length   = ws.rQshift32();
-        fb_name = ws.rQshiftStr(name_length);
-        conf.onDesktopName(that, fb_name);
-        
-        if (conf.true_color && fb_name === "Intel(r) AMT KVM")
-        {
-            Util.Warn("Intel AMT KVM only support 8/16 bit depths. Disabling true color");
-            conf.true_color = false;
-        }
-
-        display.set_true_color(conf.true_color);
-        conf.onFBResize(that, fb_width, fb_height);
-        display.resize(fb_width, fb_height);
-        keyboard.grab();
-        mouse.grab();
-
-        if (conf.true_color) {
-            fb_Bpp           = 4;
-            fb_depth         = 3;
-        } else {
-            fb_Bpp           = 1;
-            fb_depth         = 1;
-        }
-
-        response = pixelFormat();
-        response = response.concat(clientEncodings());
-        response = response.concat(fbUpdateRequests());
-        timing.fbu_rt_start = (new Date()).getTime();
-        timing.pixels = 0;
-        ws.send(response);
-        
-        /* Start pushing/polling */
-        setTimeout(checkEvents, conf.check_rate);
-
-        if (conf.encrypt) {
-            updateState('normal', "Connected (encrypted) to: " + fb_name);
-        } else {
-            updateState('normal', "Connected (unencrypted) to: " + fb_name);
-        }
-        break;
-    }
-    //Util.Debug("<< init_msg");
-};
-
-
-/* Normal RFB/VNC server message handler */
-normal_msg = function() {
-    //Util.Debug(">> normal_msg");
-
-    var ret = true, msg_type, length, text,
-        c, first_colour, num_colours, red, green, blue;
-
-    if (FBU.rects > 0) {
-        msg_type = 0;
-    } else {
-        msg_type = ws.rQshift8();
-    }
-    switch (msg_type) {
-    case 0:  // FramebufferUpdate
-        ret = framebufferUpdate(); // false means need more data
-        break;
-    case 1:  // SetColourMapEntries
-        Util.Debug("SetColourMapEntries");
-        ws.rQshift8();  // Padding
-        first_colour = ws.rQshift16(); // First colour
-        num_colours = ws.rQshift16();
-        if (ws.rQwait("SetColourMapEntries", num_colours*6, 6)) { return false; }
-        
-        for (c=0; c < num_colours; c+=1) { 
-            red = ws.rQshift16();
-            //Util.Debug("red before: " + red);
-            red = parseInt(red / 256, 10);
-            //Util.Debug("red after: " + red);
-            green = parseInt(ws.rQshift16() / 256, 10);
-            blue = parseInt(ws.rQshift16() / 256, 10);
-            display.set_colourMap([blue, green, red], first_colour + c);
-        }
-        Util.Debug("colourMap: " + display.get_colourMap());
-        Util.Info("Registered " + num_colours + " colourMap entries");
-        //Util.Debug("colourMap: " + display.get_colourMap());
-        break;
-    case 2:  // Bell
-        Util.Debug("Bell");
-        conf.onBell(that);
-        break;
-    case 3:  // ServerCutText
-        Util.Debug("ServerCutText");
-        if (ws.rQwait("ServerCutText header", 7, 1)) { return false; }
-        ws.rQshiftBytes(3);  // Padding
-        length = ws.rQshift32();
-        if (ws.rQwait("ServerCutText", length, 8)) { return false; }
-
-        text = ws.rQshiftStr(length);
-        conf.clipboardReceive(that, text); // Obsolete
-        conf.onClipboard(that, text);
-        break;
-    default:
-        fail("Disconnected: illegal server message type " + msg_type);
-        Util.Debug("ws.rQslice(0,30):" + ws.rQslice(0,30));
-        break;
-    }
-    //Util.Debug("<< normal_msg");
-    return ret;
-};
-
-framebufferUpdate = function() {
-    var now, hdr, fbu_rt_diff, ret = true;
-
-    if (FBU.rects === 0) {
-        //Util.Debug("New FBU: ws.rQslice(0,20): " + ws.rQslice(0,20));
-        if (ws.rQwait("FBU header", 3)) {
-            ws.rQunshift8(0);  // FBU msg_type
-            return false;
-        }
-        ws.rQshift8();  // padding
-        FBU.rects = ws.rQshift16();
-        //Util.Debug("FramebufferUpdate, rects:" + FBU.rects);
-        FBU.bytes = 0;
-        timing.cur_fbu = 0;
-        if (timing.fbu_rt_start > 0) {
-            now = (new Date()).getTime();
-            Util.Info("First FBU latency: " + (now - timing.fbu_rt_start));
-        }
-    }
-
-    while (FBU.rects > 0) {
-        if (rfb_state !== "normal") {
-            return false;
-        }
-        if (ws.rQwait("FBU", FBU.bytes)) { return false; }
-        if (FBU.bytes === 0) {
-            if (ws.rQwait("rect header", 12)) { return false; }
-            /* New FramebufferUpdate */
-
-            hdr = ws.rQshiftBytes(12);
-            FBU.x      = (hdr[0] << 8) + hdr[1];
-            FBU.y      = (hdr[2] << 8) + hdr[3];
-            FBU.width  = (hdr[4] << 8) + hdr[5];
-            FBU.height = (hdr[6] << 8) + hdr[7];
-            FBU.encoding = parseInt((hdr[8] << 24) + (hdr[9] << 16) +
-                                    (hdr[10] << 8) +  hdr[11], 10);
-
-            conf.onFBUReceive(that,
-                    {'x': FBU.x, 'y': FBU.y,
-                     'width': FBU.width, 'height': FBU.height,
-                     'encoding': FBU.encoding,
-                     'encodingName': encNames[FBU.encoding]});
-
-            if (encNames[FBU.encoding]) {
-                // Debug:
-                /*
-                var msg =  "FramebufferUpdate rects:" + FBU.rects;
-                msg += " x: " + FBU.x + " y: " + FBU.y;
-                msg += " width: " + FBU.width + " height: " + FBU.height;
-                msg += " encoding:" + FBU.encoding;
-                msg += "(" + encNames[FBU.encoding] + ")";
-                msg += ", ws.rQlen(): " + ws.rQlen();
-                Util.Debug(msg);
-                */
-            } else {
-                fail("Disconnected: unsupported encoding " +
-                    FBU.encoding);
-                return false;
-            }
-        }
-
-        timing.last_fbu = (new Date()).getTime();
-
-        ret = encHandlers[FBU.encoding]();
-
-        now = (new Date()).getTime();
-        timing.cur_fbu += (now - timing.last_fbu);
-
-        if (ret) {
-            encStats[FBU.encoding][0] += 1;
-            encStats[FBU.encoding][1] += 1;
-            timing.pixels += FBU.width * FBU.height;
-        }
-
-        if (timing.pixels >= (fb_width * fb_height)) {
-            if (((FBU.width === fb_width) &&
-                        (FBU.height === fb_height)) ||
-                    (timing.fbu_rt_start > 0)) {
-                timing.full_fbu_total += timing.cur_fbu;
-                timing.full_fbu_cnt += 1;
-                Util.Info("Timing of full FBU, cur: " +
-                          timing.cur_fbu + ", total: " +
-                          timing.full_fbu_total + ", cnt: " +
-                          timing.full_fbu_cnt + ", avg: " +
-                          (timing.full_fbu_total /
-                              timing.full_fbu_cnt));
-            }
-            if (timing.fbu_rt_start > 0) {
-                fbu_rt_diff = now - timing.fbu_rt_start;
-                timing.fbu_rt_total += fbu_rt_diff;
-                timing.fbu_rt_cnt += 1;
-                Util.Info("full FBU round-trip, cur: " +
-                          fbu_rt_diff + ", total: " +
-                          timing.fbu_rt_total + ", cnt: " +
-                          timing.fbu_rt_cnt + ", avg: " +
-                          (timing.fbu_rt_total /
-                              timing.fbu_rt_cnt));
-                timing.fbu_rt_start = 0;
-            }
-        }
-        if (! ret) {
-            return ret; // false ret means need more data
-        }
-    }
-
-    conf.onFBUComplete(that,
-            {'x': FBU.x, 'y': FBU.y,
-                'width': FBU.width, 'height': FBU.height,
-                'encoding': FBU.encoding,
-                'encodingName': encNames[FBU.encoding]});
-
-    return true; // We finished this FBU
-};
-
-//
-// FramebufferUpdate encodings
-//
-
-encHandlers.RAW = function display_raw() {
-    //Util.Debug(">> display_raw (" + ws.rQlen() + " bytes)");
-
-    var cur_y, cur_height;
-
-    if (FBU.lines === 0) {
-        FBU.lines = FBU.height;
-    }
-    FBU.bytes = FBU.width * fb_Bpp; // At least a line
-    if (ws.rQwait("RAW", FBU.bytes)) { return false; }
-    cur_y = FBU.y + (FBU.height - FBU.lines);
-    cur_height = Math.min(FBU.lines,
-                          Math.floor(ws.rQlen()/(FBU.width * fb_Bpp)));
-    display.blitImage(FBU.x, cur_y, FBU.width, cur_height,
-            ws.get_rQ(), ws.get_rQi());
-    ws.rQshiftBytes(FBU.width * cur_height * fb_Bpp);
-    FBU.lines -= cur_height;
-
-    if (FBU.lines > 0) {
-        FBU.bytes = FBU.width * fb_Bpp; // At least another line
-    } else {
-        FBU.rects -= 1;
-        FBU.bytes = 0;
-    }
-    //Util.Debug("<< display_raw (" + ws.rQlen() + " bytes)");
-    return true;
-};
-
-encHandlers.COPYRECT = function display_copy_rect() {
-    //Util.Debug(">> display_copy_rect");
-
-    var old_x, old_y;
-
-    FBU.bytes = 4;
-    if (ws.rQwait("COPYRECT", 4)) { return false; }
-    display.renderQ_push({
-            'type': 'copy',
-            'old_x': ws.rQshift16(),
-            'old_y': ws.rQshift16(),
-            'x': FBU.x,
-            'y': FBU.y,
-            'width': FBU.width,
-            'height': FBU.height});
-    FBU.rects -= 1;
-    FBU.bytes = 0;
-    return true;
-};
-
-encHandlers.RRE = function display_rre() {
-    //Util.Debug(">> display_rre (" + ws.rQlen() + " bytes)");
-    var color, x, y, width, height, chunk;
-
-    if (FBU.subrects === 0) {
-        FBU.bytes = 4+fb_Bpp;
-        if (ws.rQwait("RRE", 4+fb_Bpp)) { return false; }
-        FBU.subrects = ws.rQshift32();
-        color = ws.rQshiftBytes(fb_Bpp); // Background
-        display.fillRect(FBU.x, FBU.y, FBU.width, FBU.height, color);
-    }
-    while ((FBU.subrects > 0) && (ws.rQlen() >= (fb_Bpp + 8))) {
-        color = ws.rQshiftBytes(fb_Bpp);
-        x = ws.rQshift16();
-        y = ws.rQshift16();
-        width = ws.rQshift16();
-        height = ws.rQshift16();
-        display.fillRect(FBU.x + x, FBU.y + y, width, height, color);
-        FBU.subrects -= 1;
-    }
-    //Util.Debug("   display_rre: rects: " + FBU.rects +
-    //           ", FBU.subrects: " + FBU.subrects);
-
-    if (FBU.subrects > 0) {
-        chunk = Math.min(rre_chunk_sz, FBU.subrects);
-        FBU.bytes = (fb_Bpp + 8) * chunk;
-    } else {
-        FBU.rects -= 1;
-        FBU.bytes = 0;
-    }
-    //Util.Debug("<< display_rre, FBU.bytes: " + FBU.bytes);
-    return true;
-};
-
-encHandlers.HEXTILE = function display_hextile() {
-    //Util.Debug(">> display_hextile");
-    var subencoding, subrects, color, cur_tile,
-        tile_x, x, w, tile_y, y, h, xy, s, sx, sy, wh, sw, sh,
-        rQ = ws.get_rQ(), rQi = ws.get_rQi(); 
-
-    if (FBU.tiles === 0) {
-        FBU.tiles_x = Math.ceil(FBU.width/16);
-        FBU.tiles_y = Math.ceil(FBU.height/16);
-        FBU.total_tiles = FBU.tiles_x * FBU.tiles_y;
-        FBU.tiles = FBU.total_tiles;
-    }
-
-    /* FBU.bytes comes in as 1, ws.rQlen() at least 1 */
-    while (FBU.tiles > 0) {
-        FBU.bytes = 1;
-        if (ws.rQwait("HEXTILE subencoding", FBU.bytes)) { return false; }
-        subencoding = rQ[rQi];  // Peek
-        if (subencoding > 30) { // Raw
-            fail("Disconnected: illegal hextile subencoding " + subencoding);
-            //Util.Debug("ws.rQslice(0,30):" + ws.rQslice(0,30));
-            return false;
-        }
-        subrects = 0;
-        cur_tile = FBU.total_tiles - FBU.tiles;
-        tile_x = cur_tile % FBU.tiles_x;
-        tile_y = Math.floor(cur_tile / FBU.tiles_x);
-        x = FBU.x + tile_x * 16;
-        y = FBU.y + tile_y * 16;
-        w = Math.min(16, (FBU.x + FBU.width) - x);
-        h = Math.min(16, (FBU.y + FBU.height) - y);
-
-        /* Figure out how much we are expecting */
-        if (subencoding & 0x01) { // Raw
-            //Util.Debug("   Raw subencoding");
-            FBU.bytes += w * h * fb_Bpp;
-        } else {
-            if (subencoding & 0x02) { // Background
-                FBU.bytes += fb_Bpp;
-            }
-            if (subencoding & 0x04) { // Foreground
-                FBU.bytes += fb_Bpp;
-            }
-            if (subencoding & 0x08) { // AnySubrects
-                FBU.bytes += 1;   // Since we aren't shifting it off
-                if (ws.rQwait("hextile subrects header", FBU.bytes)) { return false; }
-                subrects = rQ[rQi + FBU.bytes-1]; // Peek
-                if (subencoding & 0x10) { // SubrectsColoured
-                    FBU.bytes += subrects * (fb_Bpp + 2);
-                } else {
-                    FBU.bytes += subrects * 2;
-                }
-            }
-        }
-
-        /*
-        Util.Debug("   tile:" + cur_tile + "/" + (FBU.total_tiles - 1) +
-              " (" + tile_x + "," + tile_y + ")" +
-              " [" + x + "," + y + "]@" + w + "x" + h +
-              ", subenc:" + subencoding +
-              "(last: " + FBU.lastsubencoding + "), subrects:" +
-              subrects +
-              ", ws.rQlen():" + ws.rQlen() + ", FBU.bytes:" + FBU.bytes +
-              " last:" + ws.rQslice(FBU.bytes-10, FBU.bytes) +
-              " next:" + ws.rQslice(FBU.bytes-1, FBU.bytes+10));
-        */
-        if (ws.rQwait("hextile", FBU.bytes)) { return false; }
-
-        /* We know the encoding and have a whole tile */
-        FBU.subencoding = rQ[rQi];
-        rQi += 1;
-        if (FBU.subencoding === 0) {
-            if (FBU.lastsubencoding & 0x01) {
-                /* Weird: ignore blanks after RAW */
-                Util.Debug("     Ignoring blank after RAW");
-            } else {
-                display.fillRect(x, y, w, h, FBU.background);
-            }
-        } else if (FBU.subencoding & 0x01) { // Raw
-            display.blitImage(x, y, w, h, rQ, rQi);
-            rQi += FBU.bytes - 1;
-        } else {
-            if (FBU.subencoding & 0x02) { // Background
-                FBU.background = rQ.slice(rQi, rQi + fb_Bpp);
-                rQi += fb_Bpp;
-            }
-            if (FBU.subencoding & 0x04) { // Foreground
-                FBU.foreground = rQ.slice(rQi, rQi + fb_Bpp);
-                rQi += fb_Bpp;
-            }
-
-            display.startTile(x, y, w, h, FBU.background);
-            if (FBU.subencoding & 0x08) { // AnySubrects
-                subrects = rQ[rQi];
-                rQi += 1;
-                for (s = 0; s < subrects; s += 1) {
-                    if (FBU.subencoding & 0x10) { // SubrectsColoured
-                        color = rQ.slice(rQi, rQi + fb_Bpp);
-                        rQi += fb_Bpp;
-                    } else {
-                        color = FBU.foreground;
-                    }
-                    xy = rQ[rQi];
-                    rQi += 1;
-                    sx = (xy >> 4);
-                    sy = (xy & 0x0f);
-
-                    wh = rQ[rQi];
-                    rQi += 1;
-                    sw = (wh >> 4)   + 1;
-                    sh = (wh & 0x0f) + 1;
-
-                    display.subTile(sx, sy, sw, sh, color);
-                }
-            }
-            display.finishTile();
-        }
-        ws.set_rQi(rQi);
-        FBU.lastsubencoding = FBU.subencoding;
-        FBU.bytes = 0;
-        FBU.tiles -= 1;
-    }
-
-    if (FBU.tiles === 0) {
-        FBU.rects -= 1;
-    }
-
-    //Util.Debug("<< display_hextile");
-    return true;
-};
-
-
-// Get 'compact length' header and data size
-getTightCLength = function (arr) {
-    var header = 1, data = 0;
-    data += arr[0] & 0x7f;
-    if (arr[0] & 0x80) {
-        header += 1;
-        data += (arr[1] & 0x7f) << 7;
-        if (arr[1] & 0x80) {
-            header += 1;
-            data += arr[2] << 14;
-        }
-    }
-    return [header, data];
-};
-
-function display_tight(isTightPNG) {
-    //Util.Debug(">> display_tight");
-
-    if (fb_depth === 1) {
-        fail("Tight protocol handler only implements true color mode");
-    }
-
-    var ctl, cmode, clength, color, img, data;
-    var filterId = -1, resetStreams = 0, streamId = -1;
-    var rQ = ws.get_rQ(), rQi = ws.get_rQi(); 
-
-    FBU.bytes = 1; // compression-control byte
-    if (ws.rQwait("TIGHT compression-control", FBU.bytes)) { return false; }
-
-    var checksum = function(data) {
-        var sum=0, i;
-        for (i=0; i<data.length;i++) {
-            sum += data[i];
-            if (sum > 65536) sum -= 65536;
-        }
-        return sum;
-    }
-
-    var decompress = function(data) {
-        for (var i=0; i<4; i++) {
-            if ((resetStreams >> i) & 1) {
-                FBU.zlibs[i].reset();
-                Util.Info("Reset zlib stream " + i);
-            }
-        }
-        var uncompressed = FBU.zlibs[streamId].uncompress(data, 0);
-        if (uncompressed.status !== 0) {
-            Util.Error("Invalid data in zlib stream");
-        }
-        //Util.Warn("Decompressed " + data.length + " to " +
-        //    uncompressed.data.length + " checksums " +
-        //    checksum(data) + ":" + checksum(uncompressed.data));
-
-        return uncompressed.data;
-    }
-
-    var indexedToRGB = function (data, numColors, palette, width, height) {
-        // Convert indexed (palette based) image data to RGB
-        // TODO: reduce number of calculations inside loop
-        var dest = [];
-        var x, y, b, w, w1, dp, sp;
-        if (numColors === 2) {
-            w = Math.floor((width + 7) / 8);
-            w1 = Math.floor(width / 8);
-            for (y = 0; y < height; y++) {
-                for (x = 0; x < w1; x++) {
-                    for (b = 7; b >= 0; b--) {
-                        dp = (y*width + x*8 + 7-b) * 3;
-                        sp = (data[y*w + x] >> b & 1) * 3;
-                        dest[dp  ] = palette[sp  ];
-                        dest[dp+1] = palette[sp+1];
-                        dest[dp+2] = palette[sp+2];
-                    }
-                }
-                for (b = 7; b >= 8 - width % 8; b--) {
-                    dp = (y*width + x*8 + 7-b) * 3;
-                    sp = (data[y*w + x] >> b & 1) * 3;
-                    dest[dp  ] = palette[sp  ];
-                    dest[dp+1] = palette[sp+1];
-                    dest[dp+2] = palette[sp+2];
-                }
-            }
-        } else {
-            for (y = 0; y < height; y++) {
-                for (x = 0; x < width; x++) {
-                    dp = (y*width + x) * 3;
-                    sp = data[y*width + x] * 3;
-                    dest[dp  ] = palette[sp  ];
-                    dest[dp+1] = palette[sp+1];
-                    dest[dp+2] = palette[sp+2];
-                }
-            }
-        }
-        return dest;
-    };
-    var handlePalette = function() {
-        var numColors = rQ[rQi + 2] + 1;
-        var paletteSize = numColors * fb_depth; 
-        FBU.bytes += paletteSize;
-        if (ws.rQwait("TIGHT palette " + cmode, FBU.bytes)) { return false; }
-
-        var bpp = (numColors <= 2) ? 1 : 8;
-        var rowSize = Math.floor((FBU.width * bpp + 7) / 8);
-        var raw = false;
-        if (rowSize * FBU.height < 12) {
-            raw = true;
-            clength = [0, rowSize * FBU.height];
-        } else {
-            clength = getTightCLength(ws.rQslice(3 + paletteSize,
-                                                 3 + paletteSize + 3));
-        }
-        FBU.bytes += clength[0] + clength[1];
-        if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
-
-        // Shift ctl, filter id, num colors, palette entries, and clength off
-        ws.rQshiftBytes(3); 
-        var palette = ws.rQshiftBytes(paletteSize);
-        ws.rQshiftBytes(clength[0]);
-
-        if (raw) {
-            data = ws.rQshiftBytes(clength[1]);
-        } else {
-            data = decompress(ws.rQshiftBytes(clength[1]));
-        }
-
-        // Convert indexed (palette based) image data to RGB
-        var rgb = indexedToRGB(data, numColors, palette, FBU.width, FBU.height);
-
-        // Add it to the render queue
-        display.renderQ_push({
-                'type': 'blitRgb',
-                'data': rgb,
-                'x': FBU.x,
-                'y': FBU.y,
-                'width': FBU.width,
-                'height': FBU.height});
-        return true;
-    }
-
-    var handleCopy = function() {
-        var raw = false;
-        var uncompressedSize = FBU.width * FBU.height * fb_depth;
-        if (uncompressedSize < 12) {
-            raw = true;
-            clength = [0, uncompressedSize];
-        } else {
-            clength = getTightCLength(ws.rQslice(1, 4));
-        }
-        FBU.bytes = 1 + clength[0] + clength[1];
-        if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
-
-        // Shift ctl, clength off
-        ws.rQshiftBytes(1 + clength[0]);
-
-        if (raw) {
-            data = ws.rQshiftBytes(clength[1]);
-        } else {
-            data = decompress(ws.rQshiftBytes(clength[1]));
-        }
-
-        display.renderQ_push({
-                'type': 'blitRgb',
-                'data': data,
-                'x': FBU.x,
-                'y': FBU.y,
-                'width': FBU.width,
-                'height': FBU.height});
-        return true;
-    }
-
-    ctl = ws.rQpeek8();
-
-    // Keep tight reset bits
-    resetStreams = ctl & 0xF;
-
-    // Figure out filter
-    ctl = ctl >> 4; 
-    streamId = ctl & 0x3;
-
-    if (ctl === 0x08)      cmode = "fill";
-    else if (ctl === 0x09) cmode = "jpeg";
-    else if (ctl === 0x0A) cmode = "png";
-    else if (ctl & 0x04)   cmode = "filter";
-    else if (ctl < 0x04)   cmode = "copy";
-    else return fail("Illegal tight compression received, ctl: " + ctl);
-
-    if (isTightPNG && (cmode === "filter" || cmode === "copy")) {
-        return fail("filter/copy received in tightPNG mode");
-    }
-
-    switch (cmode) {
-        // fill uses fb_depth because TPIXELs drop the padding byte
-        case "fill":   FBU.bytes += fb_depth; break; // TPIXEL
-        case "jpeg":   FBU.bytes += 3;        break; // max clength
-        case "png":    FBU.bytes += 3;        break; // max clength
-        case "filter": FBU.bytes += 2;        break; // filter id + num colors if palette
-        case "copy":                          break;
-    }
-
-    if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
-
-    //Util.Debug("   ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
-    //Util.Debug("   cmode: " + cmode);
-
-    // Determine FBU.bytes
-    switch (cmode) {
-    case "fill":
-        ws.rQshift8(); // shift off ctl
-        color = ws.rQshiftBytes(fb_depth);
-        display.renderQ_push({
-                'type': 'fill',
-                'x': FBU.x,
-                'y': FBU.y,
-                'width': FBU.width,
-                'height': FBU.height,
-                'color': [color[2], color[1], color[0]] });
-        break;
-    case "png":
-    case "jpeg":
-        clength = getTightCLength(ws.rQslice(1, 4));
-        FBU.bytes = 1 + clength[0] + clength[1]; // ctl + clength size + jpeg-data
-        if (ws.rQwait("TIGHT " + cmode, FBU.bytes)) { return false; }
-
-        // We have everything, render it
-        //Util.Debug("   jpeg, ws.rQlen(): " + ws.rQlen() + ", clength[0]: " +
-        //           clength[0] + ", clength[1]: " + clength[1]);
-        ws.rQshiftBytes(1 + clength[0]); // shift off ctl + compact length
-        img = new Image();
-        img.src = "data:image/" + cmode +
-            extract_data_uri(ws.rQshiftBytes(clength[1]));
-        display.renderQ_push({
-                'type': 'img',
-                'img': img,
-                'x': FBU.x,
-                'y': FBU.y});
-        img = null;
-        break;
-    case "filter":
-        filterId = rQ[rQi + 1];
-        if (filterId === 1) {
-            if (!handlePalette()) { return false; }
-        } else {
-            // Filter 0, Copy could be valid here, but servers don't send it as an explicit filter
-            // Filter 2, Gradient is valid but not used if jpeg is enabled
-            throw("Unsupported tight subencoding received, filter: " + filterId);
-        }
-        break;
-    case "copy":
-        if (!handleCopy()) { return false; }
-        break;
-    }
-
-    FBU.bytes = 0;
-    FBU.rects -= 1;
-    //Util.Debug("   ending ws.rQslice(0,20): " + ws.rQslice(0,20) + " (" + ws.rQlen() + ")");
-    //Util.Debug("<< display_tight_png");
-    return true;
-}
-
-extract_data_uri = function(arr) {
-    //var i, stra = [];
-    //for (i=0; i< arr.length; i += 1) {
-    //    stra.push(String.fromCharCode(arr[i]));
-    //}
-    //return "," + escape(stra.join(''));
-    return ";base64," + Base64.encode(arr);
-};
-
-encHandlers.TIGHT = function () { return display_tight(false); };
-encHandlers.TIGHT_PNG = function () { return display_tight(true); };
-
-encHandlers.last_rect = function last_rect() {
-    //Util.Debug(">> last_rect");
-    FBU.rects = 0;
-    //Util.Debug("<< last_rect");
-    return true;
-};
-
-encHandlers.DesktopSize = function set_desktopsize() {
-    Util.Debug(">> set_desktopsize");
-    fb_width = FBU.width;
-    fb_height = FBU.height;
-    conf.onFBResize(that, fb_width, fb_height);
-    display.resize(fb_width, fb_height);
-    timing.fbu_rt_start = (new Date()).getTime();
-    // Send a new non-incremental request
-    ws.send(fbUpdateRequests());
-
-    FBU.bytes = 0;
-    FBU.rects -= 1;
-
-    Util.Debug("<< set_desktopsize");
-    return true;
-};
-
-encHandlers.Cursor = function set_cursor() {
-    var x, y, w, h, pixelslength, masklength;
-    Util.Debug(">> set_cursor");
-    x = FBU.x;  // hotspot-x
-    y = FBU.y;  // hotspot-y
-    w = FBU.width;
-    h = FBU.height;
-
-    pixelslength = w * h * fb_Bpp;
-    masklength = Math.floor((w + 7) / 8) * h;
-
-    FBU.bytes = pixelslength + masklength;
-    if (ws.rQwait("cursor encoding", FBU.bytes)) { return false; }
-
-    //Util.Debug("   set_cursor, x: " + x + ", y: " + y + ", w: " + w + ", h: " + h);
-
-    display.changeCursor(ws.rQshiftBytes(pixelslength),
-                            ws.rQshiftBytes(masklength),
-                            x, y, w, h);
-
-    FBU.bytes = 0;
-    FBU.rects -= 1;
-
-    Util.Debug("<< set_cursor");
-    return true;
-};
-
-encHandlers.JPEG_quality_lo = function set_jpeg_quality() {
-    Util.Error("Server sent jpeg_quality pseudo-encoding");
-};
-
-encHandlers.compress_lo = function set_compress_level() {
-    Util.Error("Server sent compress level pseudo-encoding");
-};
-
-/*
- * Client message routines
- */
-
-pixelFormat = function() {
-    //Util.Debug(">> pixelFormat");
-    var arr;
-    arr = [0];     // msg-type
-    arr.push8(0);  // padding
-    arr.push8(0);  // padding
-    arr.push8(0);  // padding
-
-    arr.push8(fb_Bpp * 8); // bits-per-pixel
-    arr.push8(fb_depth * 8); // depth
-    arr.push8(0);  // little-endian
-    arr.push8(conf.true_color ? 1 : 0);  // true-color
-
-    arr.push16(255);  // red-max
-    arr.push16(255);  // green-max
-    arr.push16(255);  // blue-max
-    arr.push8(16);    // red-shift
-    arr.push8(8);     // green-shift
-    arr.push8(0);     // blue-shift
-
-    arr.push8(0);     // padding
-    arr.push8(0);     // padding
-    arr.push8(0);     // padding
-    //Util.Debug("<< pixelFormat");
-    return arr;
-};
-
-clientEncodings = function() {
-    //Util.Debug(">> clientEncodings");
-    var arr, i, encList = [];
-
-    for (i=0; i<encodings.length; i += 1) {
-        if ((encodings[i][0] === "Cursor") &&
-            (! conf.local_cursor)) {
-            Util.Debug("Skipping Cursor pseudo-encoding");
-
-        // TODO: remove this when we have tight+non-true-color
-        } else if ((encodings[i][0] === "TIGHT") && 
-                   (! conf.true_color)) {
-            Util.Warn("Skipping tight, only support with true color");
-        } else {
-            //Util.Debug("Adding encoding: " + encodings[i][0]);
-            encList.push(encodings[i][1]);
-        }
-    }
-
-    arr = [2];     // msg-type
-    arr.push8(0);  // padding
-
-    arr.push16(encList.length); // encoding count
-    for (i=0; i < encList.length; i += 1) {
-        arr.push32(encList[i]);
-    }
-    //Util.Debug("<< clientEncodings: " + arr);
-    return arr;
-};
-
-fbUpdateRequest = function(incremental, x, y, xw, yw) {
-    //Util.Debug(">> fbUpdateRequest");
-    if (typeof(x) === "undefined") { x = 0; }
-    if (typeof(y) === "undefined") { y = 0; }
-    if (typeof(xw) === "undefined") { xw = fb_width; }
-    if (typeof(yw) === "undefined") { yw = fb_height; }
-    var arr;
-    arr = [3];  // msg-type
-    arr.push8(incremental);
-    arr.push16(x);
-    arr.push16(y);
-    arr.push16(xw);
-    arr.push16(yw);
-    //Util.Debug("<< fbUpdateRequest");
-    return arr;
-};
-
-// Based on clean/dirty areas, generate requests to send
-fbUpdateRequests = function() {
-    var cleanDirty = display.getCleanDirtyReset(),
-        arr = [], i, cb, db;
-
-    cb = cleanDirty.cleanBox;
-    if (cb.w > 0 && cb.h > 0) {
-        // Request incremental for clean box
-        arr = arr.concat(fbUpdateRequest(1, cb.x, cb.y, cb.w, cb.h));
-    }
-    for (i = 0; i < cleanDirty.dirtyBoxes.length; i++) {
-        db = cleanDirty.dirtyBoxes[i];
-        // Force all (non-incremental for dirty box
-        arr = arr.concat(fbUpdateRequest(0, db.x, db.y, db.w, db.h));
-    }
-    return arr;
-};
-
-
-
-keyEvent = function(keysym, down) {
-    //Util.Debug(">> keyEvent, keysym: " + keysym + ", down: " + down);
-    var arr;
-    arr = [4];  // msg-type
-    arr.push8(down);
-    arr.push16(0);
-    arr.push32(keysym);
-    //Util.Debug("<< keyEvent");
-    return arr;
-};
-
-pointerEvent = function(x, y) {
-    //Util.Debug(">> pointerEvent, x,y: " + x + "," + y +
-    //           " , mask: " + mouse_buttonMask);
-    var arr;
-    arr = [5];  // msg-type
-    arr.push8(mouse_buttonMask);
-    arr.push16(x);
-    arr.push16(y);
-    //Util.Debug("<< pointerEvent");
-    return arr;
-};
-
-clientCutText = function(text) {
-    //Util.Debug(">> clientCutText");
-    var arr, i, n;
-    arr = [6];     // msg-type
-    arr.push8(0);  // padding
-    arr.push8(0);  // padding
-    arr.push8(0);  // padding
-    arr.push32(text.length);
-    n = text.length;
-    for (i=0; i < n; i+=1) {
-        arr.push(text.charCodeAt(i));
-    }
-    //Util.Debug("<< clientCutText:" + arr);
-    return arr;
-};
-
-
-
-//
-// Public API interface functions
-//
-
-that.connect = function(host, port, password, path) {
-    //Util.Debug(">> connect");
-
-    rfb_host       = host;
-    rfb_port       = port;
-    rfb_password   = (password !== undefined)   ? password : "";
-    rfb_path       = (path !== undefined) ? path : "";
-
-    if ((!rfb_host) || (!rfb_port)) {
-        return fail("Must set host and port");
-    }
-
-    updateState('connect');
-    //Util.Debug("<< connect");
-
-};
-
-that.disconnect = function() {
-    //Util.Debug(">> disconnect");
-    updateState('disconnect', 'Disconnecting');
-    //Util.Debug("<< disconnect");
-};
-
-that.sendPassword = function(passwd) {
-    rfb_password = passwd;
-    rfb_state = "Authentication";
-    setTimeout(init_msg, 1);
-};
-
-that.sendCtrlAltDel = function() {
-    if (rfb_state !== "normal" || conf.view_only) { return false; }
-    Util.Info("Sending Ctrl-Alt-Del");
-    var arr = [];
-    arr = arr.concat(keyEvent(0xFFE3, 1)); // Control
-    arr = arr.concat(keyEvent(0xFFE9, 1)); // Alt
-    arr = arr.concat(keyEvent(0xFFFF, 1)); // Delete
-    arr = arr.concat(keyEvent(0xFFFF, 0)); // Delete
-    arr = arr.concat(keyEvent(0xFFE9, 0)); // Alt
-    arr = arr.concat(keyEvent(0xFFE3, 0)); // Control
-    arr = arr.concat(fbUpdateRequests());
-    ws.send(arr);
-};
-
-// Send a key press. If 'down' is not specified then send a down key
-// followed by an up key.
-that.sendKey = function(code, down) {
-    if (rfb_state !== "normal" || conf.view_only) { return false; }
-    var arr = [];
-    if (typeof down !== 'undefined') {
-        Util.Info("Sending key code (" + (down ? "down" : "up") + "): " + code);
-        arr = arr.concat(keyEvent(code, down ? 1 : 0));
-    } else {
-        Util.Info("Sending key code (down + up): " + code);
-        arr = arr.concat(keyEvent(code, 1));
-        arr = arr.concat(keyEvent(code, 0));
-    }
-    arr = arr.concat(fbUpdateRequests());
-    ws.send(arr);
-};
-
-that.clipboardPasteFrom = function(text) {
-    if (rfb_state !== "normal") { return; }
-    //Util.Debug(">> clipboardPasteFrom: " + text.substr(0,40) + "...");
-    ws.send(clientCutText(text));
-    //Util.Debug("<< clipboardPasteFrom");
-};
-
-// Override internal functions for testing
-that.testMode = function(override_send, data_mode) {
-    test_mode = true;
-    that.recv_message = ws.testMode(override_send, data_mode);
-
-    checkEvents = function () { /* Stub Out */ };
-    that.connect = function(host, port, password) {
-            rfb_host = host;
-            rfb_port = port;
-            rfb_password = password;
-            init_vars();
-            updateState('ProtocolVersion', "Starting VNC handshake");
-        };
-};
-
-
-return constructor();  // Return the public API interface
-
-}  // End of RFB()
diff --git a/circle/dashboard/static/dashboard/novnc/ui.js b/circle/dashboard/static/dashboard/novnc/ui.js
deleted file mode 100644
index b933d31..0000000
--- a/circle/dashboard/static/dashboard/novnc/ui.js
+++ /dev/null
@@ -1,761 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Copyright (C) 2013 Samuel Mannehed for Cendio AB
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-"use strict";
-/*jslint white: false, browser: true */
-/*global window, $D, Util, WebUtil, RFB, Display */
-
-// Load supporting scripts
-window.onscriptsload = function () { UI.load(); };
-Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
-                   "input.js", "display.js", "jsunzip.js", "rfb.js"]);
-
-var UI = {
-
-rfb_state : 'loaded',
-settingsOpen : false,
-connSettingsOpen : false,
-popupStatusOpen : false,
-clipboardOpen: false,
-keyboardVisible: false,
-
-// Setup rfb object, load settings from browser storage, then call
-// UI.init to setup the UI/menus
-load: function (callback) {
-    WebUtil.initSettings(UI.start, callback);
-},
-
-// Render default UI and initialize settings menu
-start: function(callback) {
-    var html = '', i, sheet, sheets, llevels, port;
-
-    // Stylesheet selection dropdown
-    sheet = WebUtil.selectStylesheet();
-    sheets = WebUtil.getStylesheets();
-    for (i = 0; i < sheets.length; i += 1) {
-        UI.addOption($D('noVNC_stylesheet'),sheets[i].title, sheets[i].title);
-    }
-
-    // Logging selection dropdown
-    llevels = ['error', 'warn', 'info', 'debug'];
-    for (i = 0; i < llevels.length; i += 1) {
-        UI.addOption($D('noVNC_logging'),llevels[i], llevels[i]);
-    }
-
-    // Settings with immediate effects
-    UI.initSetting('logging', 'warn');
-    WebUtil.init_logging(UI.getSetting('logging'));
-
-    UI.initSetting('stylesheet', 'default');
-    WebUtil.selectStylesheet(null);
-    // call twice to get around webkit bug
-    WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
-
-    // if port == 80 (or 443) then it won't be present and should be
-    // set manually
-    port = window.location.port;
-    if (!port) {
-        if (window.location.protocol.substring(0,5) == 'https') {            
-            port = 443;
-        }
-        else if (window.location.protocol.substring(0,4) == 'http') {            
-            port = 80;
-        }
-    }
-
-    /* Populate the controls if defaults are provided in the URL */
-    UI.initSetting('host', window.location.hostname);
-    UI.initSetting('port', port);
-    UI.initSetting('password', '');
-    UI.initSetting('encrypt', (window.location.protocol === "https:"));
-    UI.initSetting('true_color', true);
-    UI.initSetting('cursor', false);
-    UI.initSetting('shared', true);
-    UI.initSetting('view_only', false);
-    UI.initSetting('connectTimeout', 2);
-    UI.initSetting('path', 'websockify');
-    UI.initSetting('repeaterID', '');
-
-    UI.rfb = RFB({'target': $D('noVNC_canvas'),
-                  'onUpdateState': UI.updateState,
-                  'onClipboard': UI.clipReceive,
-                  'onDesktopName': UI.updateDocumentTitle});
-    UI.updateVisualState();
-
-    // Unfocus clipboard when over the VNC area
-    //$D('VNC_screen').onmousemove = function () {
-    //         var keyboard = UI.rfb.get_keyboard();
-    //        if ((! keyboard) || (! keyboard.get_focused())) {
-    //            $D('VNC_clipboard_text').blur();
-    //         }
-    //    };
-
-    // Show mouse selector buttons on touch screen devices
-    if ('ontouchstart' in document.documentElement) {
-        // Show mobile buttons
-        $D('noVNC_mobile_buttons').style.display = "inline";
-        UI.setMouseButton();
-        // Remove the address bar
-        setTimeout(function() { window.scrollTo(0, 1); }, 100);
-        UI.forceSetting('clip', true);
-        $D('noVNC_clip').disabled = true;
-    } else {
-        UI.initSetting('clip', false);
-    }
-
-    //iOS Safari does not support CSS position:fixed.
-    //This detects iOS devices and enables javascript workaround.
-    if ((navigator.userAgent.match(/iPhone/i)) ||
-        (navigator.userAgent.match(/iPod/i)) ||
-        (navigator.userAgent.match(/iPad/i))) {
-        //UI.setOnscroll();
-        //UI.setResize();
-    }
-    UI.setBarPosition();
-
-    $D('noVNC_host').focus();
-
-    UI.setViewClip();
-    Util.addEvent(window, 'resize', UI.setViewClip);
-
-    Util.addEvent(window, 'beforeunload', function () {
-        if (UI.rfb_state === 'normal') {
-            return "You are currently connected.";
-        }
-    } );
-
-    // Show description by default when hosted at for kanaka.github.com
-    if (location.host === "kanaka.github.com") {
-        // Open the description dialog
-        $D('noVNC_description').style.display = "block";
-    } else {
-        // Open the connect panel on first load
-        UI.toggleConnectPanel();
-    }
-
-    // Add mouse event click/focus/blur event handlers to the UI
-    UI.addMouseHandlers();
-
-    if (typeof callback === "function") {
-        callback(UI.rfb);
-    }
-},
-
-addMouseHandlers: function() {
-    // Setup interface handlers that can't be inline
-    $D("noVNC_view_drag_button").onclick = UI.setViewDrag;
-    $D("noVNC_mouse_button0").onclick = function () { UI.setMouseButton(1); };
-    $D("noVNC_mouse_button1").onclick = function () { UI.setMouseButton(2); };
-    $D("noVNC_mouse_button2").onclick = function () { UI.setMouseButton(4); };
-    $D("noVNC_mouse_button4").onclick = function () { UI.setMouseButton(0); };
-    $D("showKeyboard").onclick = UI.showKeyboard;
-    //$D("keyboardinput").onkeydown = function (event) { onKeyDown(event); };
-    $D("keyboardinput").onblur = UI.keyInputBlur;
-
-    $D("sendCtrlAltDelButton").onclick = UI.sendCtrlAltDel;
-    $D("noVNC_status").onclick = UI.togglePopupStatusPanel;
-    $D("noVNC_popup_status_panel").onclick = UI.togglePopupStatusPanel;
-    $D("clipboardButton").onclick = UI.toggleClipboardPanel;
-    $D("settingsButton").onclick = UI.toggleSettingsPanel;
-    $D("connectButton").onclick = UI.toggleConnectPanel;
-    $D("disconnectButton").onclick = UI.disconnect;
-    $D("descriptionButton").onclick = UI.toggleConnectPanel;
-
-    $D("noVNC_clipboard_text").onfocus = UI.displayBlur;
-    $D("noVNC_clipboard_text").onblur = UI.displayFocus;
-    $D("noVNC_clipboard_text").onchange = UI.clipSend;
-    $D("noVNC_clipboard_clear_button").onclick = UI.clipClear;
-
-    $D("noVNC_settings_menu").onmouseover = UI.displayBlur;
-    $D("noVNC_settings_menu").onmouseover = UI.displayFocus;
-    $D("noVNC_apply").onclick = UI.settingsApply;
-
-    $D("noVNC_connect_button").onclick = UI.connect;
-},
-
-// Read form control compatible setting from cookie
-getSetting: function(name) {
-    var val, ctrl = $D('noVNC_' + name);
-    val = WebUtil.readSetting(name);
-    if (val !== null && ctrl.type === 'checkbox') {
-        if (val.toString().toLowerCase() in {'0':1, 'no':1, 'false':1}) {
-            val = false;
-        } else {
-            val = true;
-        }
-    }
-    return val;
-},
-
-// Update cookie and form control setting. If value is not set, then
-// updates from control to current cookie setting.
-updateSetting: function(name, value) {
-
-    var i, ctrl = $D('noVNC_' + name);
-    // Save the cookie for this session
-    if (typeof value !== 'undefined') {
-        WebUtil.writeSetting(name, value);
-    }
-
-    // Update the settings control
-    value = UI.getSetting(name);
-
-    if (ctrl.type === 'checkbox') {
-        ctrl.checked = value;
-
-    } else if (typeof ctrl.options !== 'undefined') {
-        for (i = 0; i < ctrl.options.length; i += 1) {
-            if (ctrl.options[i].value === value) {
-                ctrl.selectedIndex = i;
-                break;
-            }
-        }
-    } else {
-        /*Weird IE9 error leads to 'null' appearring
-        in textboxes instead of ''.*/
-        if (value === null) {
-            value = "";
-        }
-        ctrl.value = value;
-    }
-},
-
-// Save control setting to cookie
-saveSetting: function(name) {
-    var val, ctrl = $D('noVNC_' + name);
-    if (ctrl.type === 'checkbox') {
-        val = ctrl.checked;
-    } else if (typeof ctrl.options !== 'undefined') {
-        val = ctrl.options[ctrl.selectedIndex].value;
-    } else {
-        val = ctrl.value;
-    }
-    WebUtil.writeSetting(name, val);
-    //Util.Debug("Setting saved '" + name + "=" + val + "'");
-    return val;
-},
-
-// Initial page load read/initialization of settings
-initSetting: function(name, defVal) {
-    var val;
-
-    // Check Query string followed by cookie
-    val = WebUtil.getQueryVar(name);
-    if (val === null) {
-        val = WebUtil.readSetting(name, defVal);
-    }
-    UI.updateSetting(name, val);
- //Util.Debug("Setting '" + name + "' initialized to '" + val + "'");
-    return val;
-},
-
-// Force a setting to be a certain value
-forceSetting: function(name, val) {
-    UI.updateSetting(name, val);
-    return val;
-},
-
-
-// Show the popup status panel
-togglePopupStatusPanel: function() {
-    var psp = $D('noVNC_popup_status_panel');
-    if (UI.popupStatusOpen === true) {
-        psp.style.display = "none";
-        UI.popupStatusOpen = false;
-    } else {
-        psp.innerHTML = $D('noVNC_status').innerHTML;
-        psp.style.display = "block";
-        psp.style.left = window.innerWidth/2 - 
-            parseInt(window.getComputedStyle(psp, false).width)/2 -30 + "px";
-        UI.popupStatusOpen = true;
-    }
-},
-
-// Show the clipboard panel
-toggleClipboardPanel: function() {
-    // Close the description panel
-    $D('noVNC_description').style.display = "none";
-    // Close settings if open
-    if (UI.settingsOpen === true) {
-        UI.settingsApply();
-        UI.closeSettingsMenu();
-    }
-    // Close connection settings if open
-    if (UI.connSettingsOpen === true) {
-        UI.toggleConnectPanel();
-    }
-    // Close popup status panel if open
-    if (UI.popupStatusOpen === true) {
-        UI.togglePopupStatusPanel();
-    }
-    // Toggle Clipboard Panel
-    if (UI.clipboardOpen === true) {
-        $D('noVNC_clipboard').style.display = "none";
-        $D('clipboardButton').className = "noVNC_status_button";
-        UI.clipboardOpen = false;
-    } else {
-        $D('noVNC_clipboard').style.display = "block";
-        $D('clipboardButton').className = "noVNC_status_button_selected";
-        UI.clipboardOpen = true;
-    }
-},
-
-// Show the connection settings panel/menu
-toggleConnectPanel: function() {
-    // Close the description panel
-    $D('noVNC_description').style.display = "none";
-    // Close connection settings if open
-    if (UI.settingsOpen === true) {
-        UI.settingsApply();
-        UI.closeSettingsMenu();
-        $D('connectButton').className = "noVNC_status_button";
-    }
-    // Close clipboard panel if open
-    if (UI.clipboardOpen === true) {
-        UI.toggleClipboardPanel();
-    }
-    // Close popup status panel if open
-    if (UI.popupStatusOpen === true) {
-        UI.togglePopupStatusPanel();
-    }
-
-    // Toggle Connection Panel
-    if (UI.connSettingsOpen === true) {
-        $D('noVNC_controls').style.display = "none";
-        $D('connectButton').className = "noVNC_status_button";
-        UI.connSettingsOpen = false;
-        UI.saveSetting('host');
-        UI.saveSetting('port');
-        //UI.saveSetting('password');
-    } else {
-        $D('noVNC_controls').style.display = "block";
-        $D('connectButton').className = "noVNC_status_button_selected";
-        UI.connSettingsOpen = true;
-        $D('noVNC_host').focus();
-    }
-},
-
-// Toggle the settings menu:
-//   On open, settings are refreshed from saved cookies.
-//   On close, settings are applied
-toggleSettingsPanel: function() {
-    // Close the description panel
-    $D('noVNC_description').style.display = "none";
-    if (UI.settingsOpen) {
-        UI.settingsApply();
-        UI.closeSettingsMenu();
-    } else {
-        UI.updateSetting('encrypt');
-        UI.updateSetting('true_color');
-        if (UI.rfb.get_display().get_cursor_uri()) {
-            UI.updateSetting('cursor');
-        } else {
-            UI.updateSetting('cursor', false);
-            $D('noVNC_cursor').disabled = true;
-        }
-        UI.updateSetting('clip');
-        UI.updateSetting('shared');
-        UI.updateSetting('view_only');
-        UI.updateSetting('connectTimeout');
-        UI.updateSetting('path');
-        UI.updateSetting('repeaterID');
-        UI.updateSetting('stylesheet');
-        UI.updateSetting('logging');
-
-        UI.openSettingsMenu();
-    }
-},
-
-// Open menu
-openSettingsMenu: function() {
-    // Close the description panel
-    $D('noVNC_description').style.display = "none";
-    // Close clipboard panel if open
-    if (UI.clipboardOpen === true) {
-        UI.toggleClipboardPanel();
-    }
-    // Close connection settings if open
-    if (UI.connSettingsOpen === true) {
-        UI.toggleConnectPanel();
-    }
-    // Close popup status panel if open
-    if (UI.popupStatusOpen === true) {
-        UI.togglePopupStatusPanel();
-    }
-    $D('noVNC_settings').style.display = "block";
-    $D('settingsButton').className = "noVNC_status_button_selected";
-    UI.settingsOpen = true;
-},
-
-// Close menu (without applying settings)
-closeSettingsMenu: function() {
-    $D('noVNC_settings').style.display = "none";
-    $D('settingsButton').className = "noVNC_status_button";
-    UI.settingsOpen = false;
-},
-
-// Save/apply settings when 'Apply' button is pressed
-settingsApply: function() {
-    //Util.Debug(">> settingsApply");
-    UI.saveSetting('encrypt');
-    UI.saveSetting('true_color');
-    if (UI.rfb.get_display().get_cursor_uri()) {
-        UI.saveSetting('cursor');
-    }
-    UI.saveSetting('clip');
-    UI.saveSetting('shared');
-    UI.saveSetting('view_only');
-    UI.saveSetting('connectTimeout');
-    UI.saveSetting('path');
-    UI.saveSetting('repeaterID');
-    UI.saveSetting('stylesheet');
-    UI.saveSetting('logging');
-
-    // Settings with immediate (non-connected related) effect
-    WebUtil.selectStylesheet(UI.getSetting('stylesheet'));
-    WebUtil.init_logging(UI.getSetting('logging'));
-    UI.setViewClip();
-    UI.setViewDrag(UI.rfb.get_viewportDrag());
-    //Util.Debug("<< settingsApply");
-},
-
-
-
-setPassword: function() {
-    UI.rfb.sendPassword($D('noVNC_password').value);
-    //Reset connect button.
-    $D('noVNC_connect_button').value = "Connect";
-    $D('noVNC_connect_button').onclick = UI.Connect;
-    //Hide connection panel.
-    UI.toggleConnectPanel();
-    return false;
-},
-
-sendCtrlAltDel: function() {
-    UI.rfb.sendCtrlAltDel();
-},
-
-setMouseButton: function(num) {
-    var b, blist = [0, 1,2,4], button;
-
-    if (typeof num === 'undefined') {
-        // Disable mouse buttons
-        num = -1;
-    }
-    if (UI.rfb) {
-        UI.rfb.get_mouse().set_touchButton(num);
-    }
-
-    for (b = 0; b < blist.length; b++) {
-        button = $D('noVNC_mouse_button' + blist[b]);
-        if (blist[b] === num) {
-            button.style.display = "";
-        } else {
-            button.style.display = "none";
-            /*
-            button.style.backgroundColor = "black";
-            button.style.color = "lightgray";
-            button.style.backgroundColor = "";
-            button.style.color = "";
-            */
-        }
-    }
-},
-
-updateState: function(rfb, state, oldstate, msg) {
-    var s, sb, c, d, cad, vd, klass;
-    UI.rfb_state = state;
-    switch (state) {
-        case 'failed':
-        case 'fatal':
-            klass = "noVNC_status_error";
-            break;
-        case 'normal':
-            klass = "noVNC_status_normal";
-            break;
-        case 'disconnected':
-            $D('noVNC_logo').style.display = "block";
-            // Fall through
-        case 'loaded':
-            klass = "noVNC_status_normal";
-            break;
-        case 'password':
-            UI.toggleConnectPanel();
-
-            $D('noVNC_connect_button').value = "Send Password";
-            $D('noVNC_connect_button').onclick = UI.setPassword;
-            $D('noVNC_password').focus();
-
-            klass = "noVNC_status_warn";
-            break;
-        default:
-            klass = "noVNC_status_warn";
-            break;
-    }
-
-    if (typeof(msg) !== 'undefined') {
-        $D('noVNC-control-bar').setAttribute("class", klass);
-        $D('noVNC_status').innerHTML = msg;
-    }
-
-    UI.updateVisualState();
-},
-
-// Disable/enable controls depending on connection state
-updateVisualState: function() {
-    var connected = UI.rfb_state === 'normal' ? true : false;
-
-    //Util.Debug(">> updateVisualState");
-    $D('noVNC_encrypt').disabled = connected;
-    $D('noVNC_true_color').disabled = connected;
-    if (UI.rfb && UI.rfb.get_display() &&
-        UI.rfb.get_display().get_cursor_uri()) {
-        $D('noVNC_cursor').disabled = connected;
-    } else {
-        UI.updateSetting('cursor', false);
-        $D('noVNC_cursor').disabled = true;
-    }
-    $D('noVNC_shared').disabled = connected;
-    $D('noVNC_view_only').disabled = connected;
-    $D('noVNC_connectTimeout').disabled = connected;
-    $D('noVNC_path').disabled = connected;
-    $D('noVNC_repeaterID').disabled = connected;
-
-    if (connected) {
-        UI.setViewClip();
-        UI.setMouseButton(1);
-        $D('clipboardButton').style.display = "inline";
-        $D('showKeyboard').style.display = "inline";
-        $D('sendCtrlAltDelButton').style.display = "inline";
-    } else {
-        UI.setMouseButton();
-        $D('clipboardButton').style.display = "none";
-        $D('showKeyboard').style.display = "none";
-        $D('sendCtrlAltDelButton').style.display = "none";
-    }
-    // State change disables viewport dragging.
-    // It is enabled (toggled) by direct click on the button
-    UI.setViewDrag(false);
-
-    switch (UI.rfb_state) {
-        case 'fatal':
-        case 'failed':
-        case 'loaded':
-        case 'disconnected':
-            $D('connectButton').style.display = "";
-            $D('disconnectButton').style.display = "none";
-            break;
-        default:
-            $D('connectButton').style.display = "none";
-            $D('disconnectButton').style.display = "";
-            break;
-    }
-
-    //Util.Debug("<< updateVisualState");
-},
-
-
-// Display the desktop name in the document title
-updateDocumentTitle: function(rfb, name) {
-    document.title = name + " - noVNC";
-},
-
-
-clipReceive: function(rfb, text) {
-    Util.Debug(">> UI.clipReceive: " + text.substr(0,40) + "...");
-    $D('noVNC_clipboard_text').value = text;
-    Util.Debug("<< UI.clipReceive");
-},
-
-
-connect: function() {
-    var host, port, password, path;
-
-    UI.closeSettingsMenu();
-    UI.toggleConnectPanel();
-
-    host = $D('noVNC_host').value;
-    port = $D('noVNC_port').value;
-    password = $D('noVNC_password').value;
-    path = $D('noVNC_path').value;
-    if ((!host) || (!port)) {
-        throw("Must set host and port");
-    }
-
-    UI.rfb.set_encrypt(UI.getSetting('encrypt'));
-    UI.rfb.set_true_color(UI.getSetting('true_color'));
-    UI.rfb.set_local_cursor(UI.getSetting('cursor'));
-    UI.rfb.set_shared(UI.getSetting('shared'));
-    UI.rfb.set_view_only(UI.getSetting('view_only'));
-    UI.rfb.set_connectTimeout(UI.getSetting('connectTimeout'));
-    UI.rfb.set_repeaterID(UI.getSetting('repeaterID'));
-
-    UI.rfb.connect(host, port, password, path);
-
-    //Close dialog.
-    setTimeout(UI.setBarPosition, 100);
-    $D('noVNC_logo').style.display = "none";
-},
-
-disconnect: function() {
-    UI.closeSettingsMenu();
-    UI.rfb.disconnect();
-
-    $D('noVNC_logo').style.display = "block";
-    UI.connSettingsOpen = false;
-    UI.toggleConnectPanel();
-},
-
-displayBlur: function() {
-    UI.rfb.get_keyboard().set_focused(false);
-    UI.rfb.get_mouse().set_focused(false);
-},
-
-displayFocus: function() {
-    UI.rfb.get_keyboard().set_focused(true);
-    UI.rfb.get_mouse().set_focused(true);
-},
-
-clipClear: function() {
-    $D('noVNC_clipboard_text').value = "";
-    UI.rfb.clipboardPasteFrom("");
-},
-
-clipSend: function() {
-    var text = $D('noVNC_clipboard_text').value;
-    Util.Debug(">> UI.clipSend: " + text.substr(0,40) + "...");
-    UI.rfb.clipboardPasteFrom(text);
-    Util.Debug("<< UI.clipSend");
-},
-
-
-// Enable/disable and configure viewport clipping
-setViewClip: function(clip) {
-    var display, cur_clip, pos, new_w, new_h;
-
-    if (UI.rfb) {
-        display = UI.rfb.get_display();
-    } else {
-        return;
-    }
-
-    cur_clip = display.get_viewport();
-
-    if (typeof(clip) !== 'boolean') {
-        // Use current setting
-        clip = UI.getSetting('clip');
-    }
-
-    if (clip && !cur_clip) {
-        // Turn clipping on
-        UI.updateSetting('clip', true);
-    } else if (!clip && cur_clip) {
-        // Turn clipping off
-        UI.updateSetting('clip', false);
-        display.set_viewport(false);
-        $D('noVNC_canvas').style.position = 'static';
-        display.viewportChange();
-    }
-    if (UI.getSetting('clip')) {
-        // If clipping, update clipping settings
-        $D('noVNC_canvas').style.position = 'absolute';
-        pos = Util.getPosition($D('noVNC_canvas'));
-        new_w = window.innerWidth - pos.x;
-        new_h = window.innerHeight - pos.y;
-        display.set_viewport(true);
-        display.viewportChange(0, 0, new_w, new_h);
-    }
-},
-
-// Toggle/set/unset the viewport drag/move button
-setViewDrag: function(drag) {
-    var vmb = $D('noVNC_view_drag_button');
-    if (!UI.rfb) { return; }
-
-    if (UI.rfb_state === 'normal' &&
-        UI.rfb.get_display().get_viewport()) {
-        vmb.style.display = "inline";
-    } else {
-        vmb.style.display = "none";
-    }
-
-    if (typeof(drag) === "undefined" ||
-        typeof(drag) === "object") {
-        // If not specified, then toggle
-        drag = !UI.rfb.get_viewportDrag();
-    }
-    if (drag) {
-        vmb.className = "noVNC_status_button_selected";
-        UI.rfb.set_viewportDrag(true);
-    } else {
-        vmb.className = "noVNC_status_button";
-        UI.rfb.set_viewportDrag(false);
-    }
-},
-
-// On touch devices, show the OS keyboard
-showKeyboard: function() {
-    if(UI.keyboardVisible === false) {
-        $D('keyboardinput').focus();
-        UI.keyboardVisible = true;
-        $D('showKeyboard').className = "noVNC_status_button_selected";
-    } else if(UI.keyboardVisible === true) {
-        $D('keyboardinput').blur();
-        $D('showKeyboard').className = "noVNC_status_button";
-        UI.keyboardVisible = false;
-    }
-},
-
-keyInputBlur: function() {
-    $D('showKeyboard').className = "noVNC_status_button";
-    //Weird bug in iOS if you change keyboardVisible
-    //here it does not actually occur so next time
-    //you click keyboard icon it doesnt work.
-    setTimeout(function() { UI.setKeyboard(); },100);
-},
-
-setKeyboard: function() {
-    UI.keyboardVisible = false;
-},
-
-// iOS < Version 5 does not support position fixed. Javascript workaround:
-setOnscroll: function() {
-    window.onscroll = function() {
-        UI.setBarPosition();
-    };
-},
-
-setResize: function () {
-    window.onResize = function() {
-        UI.setBarPosition();
-    };
-},
-
-//Helper to add options to dropdown.
-addOption: function(selectbox,text,value )
-{
-    var optn = document.createElement("OPTION");
-    optn.text = text;
-    optn.value = value;
-    selectbox.options.add(optn);
-},
-
-setBarPosition: function() {
-    $D('noVNC-control-bar').style.top = (window.pageYOffset) + 'px';
-    $D('noVNC_mobile_buttons').style.left = (window.pageXOffset) + 'px';
-
-    var vncwidth = $D('noVNC_screen').style.offsetWidth;
-    $D('noVNC-control-bar').style.width = vncwidth + 'px';
-}
-
-};
-
-
-
-
diff --git a/circle/dashboard/static/dashboard/novnc/util.js b/circle/dashboard/static/dashboard/novnc/util.js
deleted file mode 100644
index 8893591..0000000
--- a/circle/dashboard/static/dashboard/novnc/util.js
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-"use strict";
-/*jslint bitwise: false, white: false */
-/*global window, console, document, navigator, ActiveXObject */
-
-// Globals defined here
-var Util = {};
-
-
-/*
- * Make arrays quack
- */
-
-Array.prototype.push8 = function (num) {
-    this.push(num & 0xFF);
-};
-
-Array.prototype.push16 = function (num) {
-    this.push((num >> 8) & 0xFF,
-              (num     ) & 0xFF  );
-};
-Array.prototype.push32 = function (num) {
-    this.push((num >> 24) & 0xFF,
-              (num >> 16) & 0xFF,
-              (num >>  8) & 0xFF,
-              (num      ) & 0xFF  );
-};
-
-// IE does not support map (even in IE9)
-//This prototype is provided by the Mozilla foundation and
-//is distributed under the MIT license.
-//http://www.ibiblio.org/pub/Linux/LICENSES/mit.license
-if (!Array.prototype.map)
-{
-  Array.prototype.map = function(fun /*, thisp*/)
-  {
-    var len = this.length;
-    if (typeof fun != "function")
-      throw new TypeError();
-
-    var res = new Array(len);
-    var thisp = arguments[1];
-    for (var i = 0; i < len; i++)
-    {
-      if (i in this)
-        res[i] = fun.call(thisp, this[i], i, this);
-    }
-
-    return res;
-  };
-}
-
-// 
-// requestAnimationFrame shim with setTimeout fallback
-//
-
-window.requestAnimFrame = (function(){
-    return  window.requestAnimationFrame       || 
-            window.webkitRequestAnimationFrame || 
-            window.mozRequestAnimationFrame    || 
-            window.oRequestAnimationFrame      || 
-            window.msRequestAnimationFrame     || 
-            function(callback){
-                window.setTimeout(callback, 1000 / 60);
-            };
-})();
-
-/* 
- * ------------------------------------------------------
- * Namespaced in Util
- * ------------------------------------------------------
- */
-
-/*
- * Logging/debug routines
- */
-
-Util._log_level = 'warn';
-Util.init_logging = function (level) {
-    if (typeof level === 'undefined') {
-        level = Util._log_level;
-    } else {
-        Util._log_level = level;
-    }
-    if (typeof window.console === "undefined") {
-        if (typeof window.opera !== "undefined") {
-            window.console = {
-                'log'  : window.opera.postError,
-                'warn' : window.opera.postError,
-                'error': window.opera.postError };
-        } else {
-            window.console = {
-                'log'  : function(m) {},
-                'warn' : function(m) {},
-                'error': function(m) {}};
-        }
-    }
-
-    Util.Debug = Util.Info = Util.Warn = Util.Error = function (msg) {};
-    switch (level) {
-        case 'debug': Util.Debug = function (msg) { console.log(msg); };
-        case 'info':  Util.Info  = function (msg) { console.log(msg); };
-        case 'warn':  Util.Warn  = function (msg) { console.warn(msg); };
-        case 'error': Util.Error = function (msg) { console.error(msg); };
-        case 'none':
-            break;
-        default:
-            throw("invalid logging type '" + level + "'");
-    }
-};
-Util.get_logging = function () {
-    return Util._log_level;
-};
-// Initialize logging level
-Util.init_logging();
-
-
-// Set configuration default for Crockford style function namespaces
-Util.conf_default = function(cfg, api, defaults, v, mode, type, defval, desc) {
-    var getter, setter;
-
-    // Default getter function
-    getter = function (idx) {
-        if ((type in {'arr':1, 'array':1}) &&
-            (typeof idx !== 'undefined')) {
-            return cfg[v][idx];
-        } else {
-            return cfg[v];
-        }
-    };
-
-    // Default setter function
-    setter = function (val, idx) {
-        if (type in {'boolean':1, 'bool':1}) {
-            if ((!val) || (val in {'0':1, 'no':1, 'false':1})) {
-                val = false;
-            } else {
-                val = true;
-            }
-        } else if (type in {'integer':1, 'int':1}) {
-            val = parseInt(val, 10);
-        } else if (type === 'str') {
-            val = String(val);
-        } else if (type === 'func') {
-            if (!val) {
-                val = function () {};
-            }
-        }
-        if (typeof idx !== 'undefined') {
-            cfg[v][idx] = val;
-        } else {
-            cfg[v] = val;
-        }
-    };
-
-    // Set the description
-    api[v + '_description'] = desc;
-
-    // Set the getter function
-    if (typeof api['get_' + v] === 'undefined') {
-        api['get_' + v] = getter;
-    }
-
-    // Set the setter function with extra sanity checks
-    if (typeof api['set_' + v] === 'undefined') {
-        api['set_' + v] = function (val, idx) {
-            if (mode in {'RO':1, 'ro':1}) {
-                throw(v + " is read-only");
-            } else if ((mode in {'WO':1, 'wo':1}) &&
-                       (typeof cfg[v] !== 'undefined')) {
-                throw(v + " can only be set once");
-            }
-            setter(val, idx);
-        };
-    }
-
-    // Set the default value
-    if (typeof defaults[v] !== 'undefined') {
-        defval = defaults[v];
-    } else if ((type in {'arr':1, 'array':1}) &&
-            (! (defval instanceof Array))) {
-        defval = [];
-    }
-    // Coerce existing setting to the right type
-    //Util.Debug("v: " + v + ", defval: " + defval + ", defaults[v]: " + defaults[v]);
-    setter(defval);
-};
-
-// Set group of configuration defaults
-Util.conf_defaults = function(cfg, api, defaults, arr) {
-    var i;
-    for (i = 0; i < arr.length; i++) {
-        Util.conf_default(cfg, api, defaults, arr[i][0], arr[i][1],
-                arr[i][2], arr[i][3], arr[i][4]);
-    }
-};
-
-
-/*
- * Cross-browser routines
- */
-
-
-// Dynamically load scripts without using document.write()
-// Reference: http://unixpapa.com/js/dyna.html
-//
-// Handles the case where load_scripts is invoked from a script that
-// itself is loaded via load_scripts. Once all scripts are loaded the
-// window.onscriptsloaded handler is called (if set).
-Util.get_include_uri = function() {
-    return (typeof INCLUDE_URI !== "undefined") ? INCLUDE_URI : "include/";
-}
-Util._loading_scripts = [];
-Util._pending_scripts = [];
-Util.load_scripts = function(files) {
-    var head = document.getElementsByTagName('head')[0], script,
-        ls = Util._loading_scripts, ps = Util._pending_scripts;
-    for (var f=0; f<files.length; f++) {
-        script = document.createElement('script');
-        script.type = 'text/javascript';
-        script.src = Util.get_include_uri() + files[f];
-        //console.log("loading script: " + script.src);
-        script.onload = script.onreadystatechange = function (e) {
-            while (ls.length > 0 && (ls[0].readyState === 'loaded' ||
-                                     ls[0].readyState === 'complete')) {
-                // For IE, append the script to trigger execution
-                var s = ls.shift();
-                //console.log("loaded script: " + s.src);
-                head.appendChild(s);
-            }
-            if (!this.readyState ||
-                (Util.Engine.presto && this.readyState === 'loaded') ||
-                this.readyState === 'complete') {
-                if (ps.indexOf(this) >= 0) {
-                    this.onload = this.onreadystatechange = null;
-                    //console.log("completed script: " + this.src);
-                    ps.splice(ps.indexOf(this), 1);
-
-                    // Call window.onscriptsload after last script loads
-                    if (ps.length === 0 && window.onscriptsload) {
-                        window.onscriptsload();
-                    }
-                }
-            }
-        };
-        // In-order script execution tricks
-        if (Util.Engine.trident) {
-            // For IE wait until readyState is 'loaded' before
-            // appending it which will trigger execution
-            // http://wiki.whatwg.org/wiki/Dynamic_Script_Execution_Order
-            ls.push(script);
-        } else {
-            // For webkit and firefox set async=false and append now
-            // https://developer.mozilla.org/en-US/docs/HTML/Element/script
-            script.async = false;
-            head.appendChild(script);
-        }
-        ps.push(script);
-    }
-}
-
-// Get DOM element position on page
-Util.getPosition = function (obj) {
-    var x = 0, y = 0;
-    if (obj.offsetParent) {
-        do {
-            x += obj.offsetLeft;
-            y += obj.offsetTop;
-            obj = obj.offsetParent;
-        } while (obj);
-    }
-    return {'x': x, 'y': y};
-};
-
-// Get mouse event position in DOM element
-Util.getEventPosition = function (e, obj, scale) {
-    var evt, docX, docY, pos;
-    //if (!e) evt = window.event;
-    evt = (e ? e : window.event);
-    evt = (evt.changedTouches ? evt.changedTouches[0] : evt.touches ? evt.touches[0] : evt);
-    if (evt.pageX || evt.pageY) {
-        docX = evt.pageX;
-        docY = evt.pageY;
-    } else if (evt.clientX || evt.clientY) {
-        docX = evt.clientX + document.body.scrollLeft +
-            document.documentElement.scrollLeft;
-        docY = evt.clientY + document.body.scrollTop +
-            document.documentElement.scrollTop;
-    }
-    pos = Util.getPosition(obj);
-    if (typeof scale === "undefined") {
-        scale = 1;
-    }
-    var realx = docX - pos.x;
-    var realy = docY - pos.y;
-    var x = Math.max(Math.min(realx, obj.width-1), 0);
-    var y = Math.max(Math.min(realy, obj.height-1), 0);
-    return {'x': x / scale, 'y': y / scale, 'realx': realx / scale, 'realy': realy / scale};
-};
-
-
-// Event registration. Based on: http://www.scottandrew.com/weblog/articles/cbs-events
-Util.addEvent = function (obj, evType, fn){
-    if (obj.attachEvent){
-        var r = obj.attachEvent("on"+evType, fn);
-        return r;
-    } else if (obj.addEventListener){
-        obj.addEventListener(evType, fn, false); 
-        return true;
-    } else {
-        throw("Handler could not be attached");
-    }
-};
-
-Util.removeEvent = function(obj, evType, fn){
-    if (obj.detachEvent){
-        var r = obj.detachEvent("on"+evType, fn);
-        return r;
-    } else if (obj.removeEventListener){
-        obj.removeEventListener(evType, fn, false);
-        return true;
-    } else {
-        throw("Handler could not be removed");
-    }
-};
-
-Util.stopEvent = function(e) {
-    if (e.stopPropagation) { e.stopPropagation(); }
-    else                   { e.cancelBubble = true; }
-
-    if (e.preventDefault)  { e.preventDefault(); }
-    else                   { e.returnValue = false; }
-};
-
-
-// Set browser engine versions. Based on mootools.
-Util.Features = {xpath: !!(document.evaluate), air: !!(window.runtime), query: !!(document.querySelector)};
-
-Util.Engine = {
-    // Version detection break in Opera 11.60 (errors on arguments.callee.caller reference)
-    //'presto': (function() {
-    //         return (!window.opera) ? false : ((arguments.callee.caller) ? 960 : ((document.getElementsByClassName) ? 950 : 925)); }()),
-    'presto': (function() { return (!window.opera) ? false : true; }()),
-
-    'trident': (function() {
-            return (!window.ActiveXObject) ? false : ((window.XMLHttpRequest) ? ((document.querySelectorAll) ? 6 : 5) : 4); }()),
-    'webkit': (function() {
-            try { return (navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); } catch (e) { return false; } }()),
-    //'webkit': (function() {
-    //        return ((typeof navigator.taintEnabled !== "unknown") && navigator.taintEnabled) ? false : ((Util.Features.xpath) ? ((Util.Features.query) ? 525 : 420) : 419); }()),
-    'gecko': (function() {
-            return (!document.getBoxObjectFor && window.mozInnerScreenX == null) ? false : ((document.getElementsByClassName) ? 19 : 18); }())
-};
-if (Util.Engine.webkit) {
-    // Extract actual webkit version if available
-    Util.Engine.webkit = (function(v) {
-            var re = new RegExp('WebKit/([0-9\.]*) ');
-            v = (navigator.userAgent.match(re) || ['', v])[1];
-            return parseFloat(v, 10);
-        })(Util.Engine.webkit);
-}
-
-Util.Flash = (function(){
-    var v, version;
-    try {
-        v = navigator.plugins['Shockwave Flash'].description;
-    } catch(err1) {
-        try {
-            v = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
-        } catch(err2) {
-            v = '0 r0';
-        }
-    }
-    version = v.match(/\d+/g);
-    return {version: parseInt(version[0] || 0 + '.' + version[1], 10) || 0, build: parseInt(version[2], 10) || 0};
-}()); 
diff --git a/circle/dashboard/static/dashboard/novnc/websock.js b/circle/dashboard/static/dashboard/novnc/websock.js
deleted file mode 100644
index 01a24c3..0000000
--- a/circle/dashboard/static/dashboard/novnc/websock.js
+++ /dev/null
@@ -1,422 +0,0 @@
-/*
- * Websock: high-performance binary WebSockets
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * Websock is similar to the standard WebSocket object but Websock
- * enables communication with raw TCP sockets (i.e. the binary stream)
- * via websockify. This is accomplished by base64 encoding the data
- * stream between Websock and websockify.
- *
- * Websock has built-in receive queue buffering; the message event
- * does not contain actual data but is simply a notification that
- * there is new data available. Several rQ* methods are available to
- * read binary data off of the receive queue.
- */
-
-/*jslint browser: true, bitwise: false, plusplus: false */
-/*global Util, Base64 */
-
-
-// Load Flash WebSocket emulator if needed
-
-// To force WebSocket emulator even when native WebSocket available
-//window.WEB_SOCKET_FORCE_FLASH = true;
-// To enable WebSocket emulator debug:
-//window.WEB_SOCKET_DEBUG=1;
-
-if (window.WebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
-    Websock_native = true;
-} else if (window.MozWebSocket && !window.WEB_SOCKET_FORCE_FLASH) {
-    Websock_native = true;
-    window.WebSocket = window.MozWebSocket;
-} else {
-    /* no builtin WebSocket so load web_socket.js */
-
-    Websock_native = false;
-    (function () {
-        window.WEB_SOCKET_SWF_LOCATION = Util.get_include_uri() +
-                    "web-socket-js/WebSocketMain.swf";
-        if (Util.Engine.trident) {
-            Util.Debug("Forcing uncached load of WebSocketMain.swf");
-            window.WEB_SOCKET_SWF_LOCATION += "?" + Math.random();
-        }
-        Util.load_scripts(["web-socket-js/swfobject.js",
-                           "web-socket-js/web_socket.js"]);
-    }());
-}
-
-
-function Websock() {
-"use strict";
-
-var api = {},         // Public API
-    websocket = null, // WebSocket object
-    mode = 'base64',  // Current WebSocket mode: 'binary', 'base64'
-    rQ = [],          // Receive queue
-    rQi = 0,          // Receive queue index
-    rQmax = 10000,    // Max receive queue size before compacting
-    sQ = [],          // Send queue
-
-    eventHandlers = {
-        'message' : function() {},
-        'open'    : function() {},
-        'close'   : function() {},
-        'error'   : function() {}
-    },
-
-    test_mode = false;
-
-
-//
-// Queue public functions
-//
-
-function get_sQ() {
-    return sQ;
-}
-
-function get_rQ() {
-    return rQ;
-}
-function get_rQi() {
-    return rQi;
-}
-function set_rQi(val) {
-    rQi = val;
-}
-
-function rQlen() {
-    return rQ.length - rQi;
-}
-
-function rQpeek8() {
-    return (rQ[rQi]      );
-}
-function rQshift8() {
-    return (rQ[rQi++]      );
-}
-function rQunshift8(num) {
-    if (rQi === 0) {
-        rQ.unshift(num);
-    } else {
-        rQi -= 1;
-        rQ[rQi] = num;
-    }
-
-}
-function rQshift16() {
-    return (rQ[rQi++] <<  8) +
-           (rQ[rQi++]      );
-}
-function rQshift32() {
-    return (rQ[rQi++] << 24) +
-           (rQ[rQi++] << 16) +
-           (rQ[rQi++] <<  8) +
-           (rQ[rQi++]      );
-}
-function rQshiftStr(len) {
-    if (typeof(len) === 'undefined') { len = rQlen(); }
-    var arr = rQ.slice(rQi, rQi + len);
-    rQi += len;
-    return String.fromCharCode.apply(null, arr);
-}
-function rQshiftBytes(len) {
-    if (typeof(len) === 'undefined') { len = rQlen(); }
-    rQi += len;
-    return rQ.slice(rQi-len, rQi);
-}
-
-function rQslice(start, end) {
-    if (end) {
-        return rQ.slice(rQi + start, rQi + end);
-    } else {
-        return rQ.slice(rQi + start);
-    }
-}
-
-// Check to see if we must wait for 'num' bytes (default to FBU.bytes)
-// to be available in the receive queue. Return true if we need to
-// wait (and possibly print a debug message), otherwise false.
-function rQwait(msg, num, goback) {
-    var rQlen = rQ.length - rQi; // Skip rQlen() function call
-    if (rQlen < num) {
-        if (goback) {
-            if (rQi < goback) {
-                throw("rQwait cannot backup " + goback + " bytes");
-            }
-            rQi -= goback;
-        }
-        //Util.Debug("   waiting for " + (num-rQlen) +
-        //           " " + msg + " byte(s)");
-        return true;  // true means need more data
-    }
-    return false;
-}
-
-//
-// Private utility routines
-//
-
-function encode_message() {
-    if (mode === 'binary') {
-        // Put in a binary arraybuffer
-        return (new Uint8Array(sQ)).buffer;
-    } else {
-        // base64 encode
-        return Base64.encode(sQ);
-    }
-}
-
-function decode_message(data) {
-    //Util.Debug(">> decode_message: " + data);
-    if (mode === 'binary') {
-        // push arraybuffer values onto the end
-        var u8 = new Uint8Array(data);
-        for (var i = 0; i < u8.length; i++) {
-            rQ.push(u8[i]);
-        }
-    } else {
-        // base64 decode and concat to the end
-        rQ = rQ.concat(Base64.decode(data, 0));
-    }
-    //Util.Debug(">> decode_message, rQ: " + rQ);
-}
-
-
-//
-// Public Send functions
-//
-
-function flush() {
-    if (websocket.bufferedAmount !== 0) {
-        Util.Debug("bufferedAmount: " + websocket.bufferedAmount);
-    }
-    if (websocket.bufferedAmount < api.maxBufferedAmount) {
-        //Util.Debug("arr: " + arr);
-        //Util.Debug("sQ: " + sQ);
-        if (sQ.length > 0) {
-            websocket.send(encode_message(sQ));
-            sQ = [];
-        }
-        return true;
-    } else {
-        Util.Info("Delaying send, bufferedAmount: " +
-                websocket.bufferedAmount);
-        return false;
-    }
-}
-
-// overridable for testing
-function send(arr) {
-    //Util.Debug(">> send_array: " + arr);
-    sQ = sQ.concat(arr);
-    return flush();
-}
-
-function send_string(str) {
-    //Util.Debug(">> send_string: " + str);
-    api.send(str.split('').map(
-        function (chr) { return chr.charCodeAt(0); } ) );
-}
-
-//
-// Other public functions
-
-function recv_message(e) {
-    //Util.Debug(">> recv_message: " + e.data.length);
-
-    try {
-        decode_message(e.data);
-        if (rQlen() > 0) {
-            eventHandlers.message();
-            // Compact the receive queue
-            if (rQ.length > rQmax) {
-                //Util.Debug("Compacting receive queue");
-                rQ = rQ.slice(rQi);
-                rQi = 0;
-            }
-        } else {
-            Util.Debug("Ignoring empty message");
-        }
-    } catch (exc) {
-        if (typeof exc.stack !== 'undefined') {
-            Util.Warn("recv_message, caught exception: " + exc.stack);
-        } else if (typeof exc.description !== 'undefined') {
-            Util.Warn("recv_message, caught exception: " + exc.description);
-        } else {
-            Util.Warn("recv_message, caught exception:" + exc);
-        }
-        if (typeof exc.name !== 'undefined') {
-            eventHandlers.error(exc.name + ": " + exc.message);
-        } else {
-            eventHandlers.error(exc);
-        }
-    }
-    //Util.Debug("<< recv_message");
-}
-
-
-// Set event handlers
-function on(evt, handler) { 
-    eventHandlers[evt] = handler;
-}
-
-function init(protocols) {
-    rQ         = [];
-    rQi        = 0;
-    sQ         = [];
-    websocket  = null;
-
-    var bt = false,
-        wsbt = false,
-        try_binary = false;
-
-    // Check for full typed array support
-    if (('Uint8Array' in window) &&
-        ('set' in Uint8Array.prototype)) {
-        bt = true;
-    }
-
-    // Check for full binary type support in WebSockets
-    // TODO: this sucks, the property should exist on the prototype
-    // but it does not.
-    try {
-        if (bt && ('binaryType' in (new WebSocket("ws://localhost:17523")))) {
-            Util.Info("Detected binaryType support in WebSockets");
-            wsbt = true;
-        }
-    } catch (exc) {
-        // Just ignore failed test localhost connections
-    }
-
-    // Default protocols if not specified
-    if (typeof(protocols) === "undefined") {
-        if (wsbt) {
-            protocols = ['binary', 'base64'];
-        } else {
-            protocols = 'base64';
-        }
-    }
-
-    // If no binary support, make sure it was not requested
-    if (!wsbt) {
-        if (protocols === 'binary') {
-            throw("WebSocket binary sub-protocol requested but not supported");
-        }
-        if (typeof(protocols) === "object") {
-            var new_protocols = [];
-            for (var i = 0; i < protocols.length; i++) {
-                if (protocols[i] === 'binary') {
-                    Util.Error("Skipping unsupported WebSocket binary sub-protocol");
-                } else {
-                    new_protocols.push(protocols[i]);
-                }
-            }
-            if (new_protocols.length > 0) {
-                protocols = new_protocols;
-            } else {
-                throw("Only WebSocket binary sub-protocol was requested and not supported.");
-            }
-        }
-    }
-
-    return protocols;
-}
-
-function open(uri, protocols) {
-    protocols = init(protocols);
-
-    if (test_mode) {
-        websocket = {};
-    } else {
-        websocket = new WebSocket(uri, protocols);
-        if (protocols.indexOf('binary') >= 0) {
-            websocket.binaryType = 'arraybuffer';
-        }
-    }
-
-    websocket.onmessage = recv_message;
-    websocket.onopen = function() {
-        Util.Debug(">> WebSock.onopen");
-        if (websocket.protocol) {
-            mode = websocket.protocol;
-            Util.Info("Server chose sub-protocol: " + websocket.protocol);
-        } else {
-            mode = 'base64';
-            Util.Error("Server select no sub-protocol!: " + websocket.protocol);
-        }
-        eventHandlers.open();
-        Util.Debug("<< WebSock.onopen");
-    };
-    websocket.onclose = function(e) {
-        Util.Debug(">> WebSock.onclose");
-        eventHandlers.close(e);
-        Util.Debug("<< WebSock.onclose");
-    };
-    websocket.onerror = function(e) {
-        Util.Debug(">> WebSock.onerror: " + e);
-        eventHandlers.error(e);
-        Util.Debug("<< WebSock.onerror");
-    };
-}
-
-function close() {
-    if (websocket) {
-        if ((websocket.readyState === WebSocket.OPEN) ||
-            (websocket.readyState === WebSocket.CONNECTING)) {
-            Util.Info("Closing WebSocket connection");
-            websocket.close();
-        }
-        websocket.onmessage = function (e) { return; };
-    }
-}
-
-// Override internal functions for testing
-// Takes a send function, returns reference to recv function
-function testMode(override_send, data_mode) {
-    test_mode = true;
-    mode = data_mode;
-    api.send = override_send;
-    api.close = function () {};
-    return recv_message;
-}
-
-function constructor() {
-    // Configuration settings
-    api.maxBufferedAmount = 200;
-
-    // Direct access to send and receive queues
-    api.get_sQ       = get_sQ;
-    api.get_rQ       = get_rQ;
-    api.get_rQi      = get_rQi;
-    api.set_rQi      = set_rQi;
-
-    // Routines to read from the receive queue
-    api.rQlen        = rQlen;
-    api.rQpeek8      = rQpeek8;
-    api.rQshift8     = rQshift8;
-    api.rQunshift8   = rQunshift8;
-    api.rQshift16    = rQshift16;
-    api.rQshift32    = rQshift32;
-    api.rQshiftStr   = rQshiftStr;
-    api.rQshiftBytes = rQshiftBytes;
-    api.rQslice      = rQslice;
-    api.rQwait       = rQwait;
-
-    api.flush        = flush;
-    api.send         = send;
-    api.send_string  = send_string;
-
-    api.on           = on;
-    api.init         = init;
-    api.open         = open;
-    api.close        = close;
-    api.testMode     = testMode;
-
-    return api;
-}
-
-return constructor();
-
-}
diff --git a/circle/dashboard/static/dashboard/novnc/webutil.js b/circle/dashboard/static/dashboard/novnc/webutil.js
deleted file mode 100644
index ebf8e89..0000000
--- a/circle/dashboard/static/dashboard/novnc/webutil.js
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * noVNC: HTML5 VNC client
- * Copyright (C) 2012 Joel Martin
- * Licensed under MPL 2.0 (see LICENSE.txt)
- *
- * See README.md for usage and integration instructions.
- */
-
-"use strict";
-/*jslint bitwise: false, white: false */
-/*global Util, window, document */
-
-// Globals defined here
-var WebUtil = {}, $D;
-
-/*
- * Simple DOM selector by ID
- */
-if (!window.$D) {
-    window.$D = function (id) {
-        if (document.getElementById) {
-            return document.getElementById(id);
-        } else if (document.all) {
-            return document.all[id];
-        } else if (document.layers) {
-            return document.layers[id];
-        }
-        return undefined;
-    };
-}
-
-
-/* 
- * ------------------------------------------------------
- * Namespaced in WebUtil
- * ------------------------------------------------------
- */
-
-// init log level reading the logging HTTP param
-WebUtil.init_logging = function(level) {
-    if (typeof level !== "undefined") {
-        Util._log_level = level;
-    } else {
-        Util._log_level = (document.location.href.match(
-            /logging=([A-Za-z0-9\._\-]*)/) ||
-            ['', Util._log_level])[1];
-    }
-    Util.init_logging();
-};
-
-
-WebUtil.dirObj = function (obj, depth, parent) {
-    var i, msg = "", val = "";
-    if (! depth) { depth=2; }
-    if (! parent) { parent= ""; }
-
-    // Print the properties of the passed-in object 
-    for (i in obj) {
-        if ((depth > 1) && (typeof obj[i] === "object")) { 
-            // Recurse attributes that are objects
-            msg += WebUtil.dirObj(obj[i], depth-1, parent + "." + i);
-        } else {
-            //val = new String(obj[i]).replace("\n", " ");
-            if (typeof(obj[i]) === "undefined") {
-                val = "undefined";
-            } else {
-                val = obj[i].toString().replace("\n", " ");
-            }
-            if (val.length > 30) {
-                val = val.substr(0,30) + "...";
-            } 
-            msg += parent + "." + i + ": " + val + "\n";
-        }
-    }
-    return msg;
-};
-
-// Read a query string variable
-WebUtil.getQueryVar = function(name, defVal) {
-    var re = new RegExp('[?][^#]*' + name + '=([^&#]*)'),
-        match = document.location.href.match(re);
-    if (typeof defVal === 'undefined') { defVal = null; }
-    if (match) {
-        return decodeURIComponent(match[1]);
-    } else {
-        return defVal;
-    }
-};
-
-
-/*
- * Cookie handling. Dervied from: http://www.quirksmode.org/js/cookies.html
- */
-
-// No days means only for this browser session
-WebUtil.createCookie = function(name,value,days) {
-    var date, expires;
-    if (days) {
-        date = new Date();
-        date.setTime(date.getTime()+(days*24*60*60*1000));
-        expires = "; expires="+date.toGMTString();
-    }
-    else {
-        expires = "";
-    }
-    document.cookie = name+"="+value+expires+"; path=/";
-};
-
-WebUtil.readCookie = function(name, defaultValue) {
-    var i, c, nameEQ = name + "=", ca = document.cookie.split(';');
-    for(i=0; i < ca.length; i += 1) {
-        c = ca[i];
-        while (c.charAt(0) === ' ') { c = c.substring(1,c.length); }
-        if (c.indexOf(nameEQ) === 0) { return c.substring(nameEQ.length,c.length); }
-    }
-    return (typeof defaultValue !== 'undefined') ? defaultValue : null;
-};
-
-WebUtil.eraseCookie = function(name) {
-    WebUtil.createCookie(name,"",-1);
-};
-
-/*
- * Setting handling.
- */
-
-WebUtil.initSettings = function(callback) {
-    var callbackArgs = Array.prototype.slice.call(arguments, 1);
-    if (window.chrome && window.chrome.storage) {
-        window.chrome.storage.sync.get(function (cfg) {
-            WebUtil.settings = cfg;
-            console.log(WebUtil.settings);
-            if (callback) {
-                callback.apply(this, callbackArgs);
-            }
-        });
-    } else {
-        // No-op
-        if (callback) {
-            callback.apply(this, callbackArgs);
-        }
-    }
-};
-
-// No days means only for this browser session
-WebUtil.writeSetting = function(name, value) {
-    if (window.chrome && window.chrome.storage) {
-        //console.log("writeSetting:", name, value);
-        if (WebUtil.settings[name] !== value) {
-            WebUtil.settings[name] = value;
-            window.chrome.storage.sync.set(WebUtil.settings);
-        }
-    } else {
-        localStorage.setItem(name, value);
-    }
-};
-
-WebUtil.readSetting = function(name, defaultValue) {
-    var value;
-    if (window.chrome && window.chrome.storage) {
-        value = WebUtil.settings[name];
-    } else {
-        value = localStorage.getItem(name);
-    }
-    if (typeof value === "undefined") {
-        value = null;
-    }
-    if (value === null && typeof defaultValue !== undefined) {
-        return defaultValue;
-    } else {
-        return value;
-    }
-};
-
-WebUtil.eraseSetting = function(name) {
-    if (window.chrome && window.chrome.storage) {
-        window.chrome.storage.sync.remove(name);
-        delete WebUtil.settings[name];
-    } else {
-        localStorage.removeItem(name);
-    }
-};
-
-/*
- * Alternate stylesheet selection
- */
-WebUtil.getStylesheets = function() { var i, links, sheets = [];
-    links = document.getElementsByTagName("link");
-    for (i = 0; i < links.length; i += 1) {
-        if (links[i].title &&
-            links[i].rel.toUpperCase().indexOf("STYLESHEET") > -1) {
-            sheets.push(links[i]);
-        }
-    }
-    return sheets;
-};
-
-// No sheet means try and use value from cookie, null sheet used to
-// clear all alternates.
-WebUtil.selectStylesheet = function(sheet) {
-    var i, link, sheets = WebUtil.getStylesheets();
-    if (typeof sheet === 'undefined') {
-        sheet = 'default';
-    }
-    for (i=0; i < sheets.length; i += 1) {
-        link = sheets[i];
-        if (link.title === sheet) {    
-            Util.Debug("Using stylesheet " + sheet);
-            link.disabled = false;
-        } else {
-            //Util.Debug("Skipping stylesheet " + link.title);
-            link.disabled = true;
-        }
-    }
-    return sheet;
-};
diff --git a/circle/dashboard/static/dashboard/profile.js b/circle/dashboard/static/dashboard/profile.js
index 553e375..690936c 100644
--- a/circle/dashboard/static/dashboard/profile.js
+++ b/circle/dashboard/static/dashboard/profile.js
@@ -7,10 +7,10 @@ $(function() {
     $.ajax({
       type: 'POST',
       url:"/dashboard/profile/" + user + "/use_gravatar/",
-      headers: {"X-CSRFToken": getCookie('csrftoken')}, 
+      headers: {"X-CSRFToken": getCookie('csrftoken')},
       success: function(re) {
         if(re.new_avatar_url) {
-          $("#dashboard-profile-avatar").prop("src", re.new_avatar_url);  
+          $("#dashboard-profile-avatar").prop("src", re.new_avatar_url);
         }
       },
       error: function(xhr, textStatus, error) {
diff --git a/circle/dashboard/static/dashboard/store.js b/circle/dashboard/static/dashboard/store.js
index 1970ddc..e921ae0 100644
--- a/circle/dashboard/static/dashboard/store.js
+++ b/circle/dashboard/static/dashboard/store.js
@@ -25,18 +25,18 @@ $(function() {
     $('#store-upload-form button[type="submit"] i').addClass("fa-spinner fa-spin");
     var current_dir = $("#store-upload-form").find('[name="current_dir"]').val();
     $.get($("#store-upload-form").data("action") + "?current_dir=" + current_dir, function(result) {
-      $("#store-upload-form").get(0).setAttribute("action", result['url']);
+      $("#store-upload-form").get(0).setAttribute("action", result.url);
       $("#store-upload-form").submit();
     });
 
     return false;
   });
-  
+
   /* "fake" browse button */
   $("#store-list-container").on("click", "#store-upload-browse", function() {
     $('#store-upload-form input[type="file"]').click();
   });
-  
+
   $("#store-list-container").on("change", "#store-upload-file", function() {
     var input = $(this);
     var numFiles = input.get(0).files ? input.get(0).files.length : 1;
diff --git a/circle/dashboard/static/dashboard/template-list.js b/circle/dashboard/static/dashboard/template-list.js
index a3e45ff..1c6ac21 100644
--- a/circle/dashboard/static/dashboard/template-list.js
+++ b/circle/dashboard/static/dashboard/template-list.js
@@ -20,7 +20,7 @@ $(function() {
     });
     return false;
   });
-  
+
   /* template table sort */
   var ttable = $(".template-list-table").stupidtable();
 
@@ -37,7 +37,7 @@ $(function() {
 
   // only if js is enabled
   $(".template-list-table thead th").css("cursor", "pointer");
-  
+
   $(".template-list-table th a").on("click", function(event) {
     if(!$(this).closest("th").data("sort")) return true;
     event.preventDefault();
@@ -49,16 +49,16 @@ $(function() {
 function deleteTemplate(data) {
   $.ajax({
     type: 'POST',
-    url: data['url'],
-    headers: {"X-CSRFToken": getCookie('csrftoken')}, 
-    success: function(re, textStatus, xhr) { 
-      addMessage(re['message'], 'success');
-      $('a[data-template-pk="' + data['template_pk'] + '"]').closest('tr').fadeOut(function() {
+    url: data.url,
+    headers: {"X-CSRFToken": getCookie('csrftoken')},
+    success: function(re, textStatus, xhr) {
+      addMessage(re.message, 'success');
+      $('a[data-template-pk="' + data.template_pk + '"]').closest('tr').fadeOut(function() {
         $(this).remove();
       });
     },
     error: function(xhr, textStatus, error) {
-      addMessage('Uh oh :(', 'danger')
+      addMessage('Uh oh :(', 'danger');
     }
   });
 }
@@ -68,16 +68,16 @@ function deleteTemplate(data) {
 function deleteLease(data) {
   $.ajax({
     type: 'POST',
-    url: data['url'],
-    headers: {"X-CSRFToken": getCookie('csrftoken')}, 
-    success: function(re, textStatus, xhr) { 
-      addMessage(re['message'], 'success');
-      $('a[data-lease-pk="' + data['lease_pk'] + '"]').closest('tr').fadeOut(function() {
+    url: data.url,
+    headers: {"X-CSRFToken": getCookie('csrftoken')},
+    success: function(re, textStatus, xhr) {
+      addMessage(re.message, 'success');
+      $('a[data-lease-pk="' + data.lease_pk + '"]').closest('tr').fadeOut(function() {
         $(this).remove();
       });
     },
     error: function(xhr, textStatus, error) {
-      addMessage('Uh oh :(', 'danger')
+      addMessage('Uh oh :(', 'danger');
     }
   });
 }
diff --git a/circle/dashboard/static/dashboard/vm-common.js b/circle/dashboard/static/dashboard/vm-common.js
index 10111e8..cc749f1 100644
--- a/circle/dashboard/static/dashboard/vm-common.js
+++ b/circle/dashboard/static/dashboard/vm-common.js
@@ -66,7 +66,7 @@ $(function() {
       },
       error: function(xhr, textStatus, error) {
         $('#confirmation-modal').modal("hide");
-        
+
         if (xhr.status == 500) {
           addMessage("500 Internal Server Error", "danger");
         } else {
diff --git a/circle/dashboard/static/dashboard/vm-console.js b/circle/dashboard/static/dashboard/vm-console.js
index 15a75f9..b4da004 100644
--- a/circle/dashboard/static/dashboard/vm-console.js
+++ b/circle/dashboard/static/dashboard/vm-console.js
@@ -1,12 +1,12 @@
 $(function() {
   "use strict";
 
-  Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
-                     "input.js", "display.js", "jsunzip.js", "rfb.js"]);
+  // Util.load_scripts(["webutil.js", "base64.js", "websock.js", "des.js",
+  //                    "input.js", "display.js", "jsunzip.js", "rfb.js"]);
   var rfb;
 
   function updateState(rfb, state, oldstate, msg) {
-      $('#_console .btn-toolbar button').attr('disabled', !(state === "normal"));
+      $('#_console .btn-toolbar button').attr('disabled', (state !== "normal"));
       rfb.sendKey(0xffe3); // press and release ctrl to kill screensaver
 
       if (typeof(msg) !== 'undefined') {
@@ -20,7 +20,7 @@ $(function() {
           rfb = 0;
       }
       $("#vm-info-pane").fadeIn();
-      $("#vm-detail-pane").removeClass("col-md-12");
+      $("#vm-detail-pane").removeClass("col-md-12").addClass("col-md-8");
   });
   $('#sendCtrlAltDelButton').click(function() {
       rfb.sendCtrlAltDel(); return false;});
@@ -35,20 +35,20 @@ $(function() {
       var host, port, password, path;
 
       $("#vm-info-pane").hide();
-      $("#vm-detail-pane").addClass("col-md-12");
+      $("#vm-detail-pane").removeClass("col-md-8").addClass("col-md-12");
       WebUtil.init_logging('warn');
 
       host = window.location.hostname;
       if (window.location.port == 8080) {
           port = 9999;
       } else {
-          port = window.location.port == "" ? "443" : window.location.port;
+          port = window.location.port === "" ? "443" : window.location.port;
       }
       password = '';
       $('#_console .btn-toolbar button').attr('disabled', true);
       $('#noVNC_status').html('Retreiving authorization token.');
       $.get(VNC_URL, function(data) {
-          if (data.indexOf('vnc') != 0) {
+          if (data.indexOf('vnc') !== 0) {
               $('#noVNC_status').html('No authorization token received.');
           }
           else {
@@ -58,13 +58,13 @@ $(function() {
                              'local_cursor': true,
                              'shared':       true,
                              'view_only':    false,
-                             'updateState':  updateState});
+                             'onUpdateState':  updateState});
               rfb.connect(host, port, password, data);
       }
       }).fail(function(){
           $('#noVNC_status').html("Can't connect to console.");
       });
   });
-  if (window.location.hash == "#console")
-      window.onscriptsload = function(){$('a[href$="console"]').click();};
+  if (window.location.hash === "#console")
+    $('a[href$="console"]').trigger("click");
 });
diff --git a/circle/dashboard/static/dashboard/vm-create.js b/circle/dashboard/static/dashboard/vm-create.js
index cdbb550..681af5e 100644
--- a/circle/dashboard/static/dashboard/vm-create.js
+++ b/circle/dashboard/static/dashboard/vm-create.js
@@ -18,7 +18,7 @@ function vmCreateLoaded() {
 
   $(".customize-vm").click(function() {
     var template = $(this).data("template-pk");
-  
+
     $.get("/dashboard/vm/create/?template=" + template, function(data) {
         var r = $('#create-modal'); r.next('div').remove(); r.remove();
         $('body').append(data);
@@ -34,7 +34,7 @@ function vmCreateLoaded() {
     });
     return false;
   });
-  
+
   /* start vm button clicks */
   $('.vm-create-start').click(function() {
     template = $(this).data("template-pk");
@@ -60,7 +60,7 @@ function vmCreateLoaded() {
       },
       error: function(xhr, textStatus, error) {
         var r = $('#create-modal'); r.next('div').remove(); r.remove();
-        
+
         if (xhr.status == 500) {
           addMessage("500 Internal Server Error", "danger");
         } else {
@@ -77,7 +77,7 @@ function vmCreateLoaded() {
     var now = $(this).attr('aria-valuenow');
     var siz = (now-min)*100/(max-min);
     $(this).css('width', siz+'%');
-  }); 
+  });
 
 }
 
@@ -93,18 +93,18 @@ function vmCustomizeLoaded() {
     // remove the hex chars
     name = name.substring(name.indexOf(" "), name.length);
 
-    if ($('#vm-create-network-list').children('span').length < 1) { 
+    if ($('#vm-create-network-list').children('span').length < 1) {
       $('#vm-create-network-list').html('');
-    }  
+    }
     $('#vm-create-network-list').append(
       vmCreateNetworkLabel(vlan_pk, name, managed)
     );
-    
+
     /* select the network in the hidden network select */
     $('#vm-create-network-add-vlan option[value="' + vlan_pk + '"]').prop('selected', true);
 
     $('option:selected', $('#vm-create-network-add-select')).remove();
-    
+
     /* add dummy text if no more networks are available */
     if($('#vm-create-network-add-select option').length < 1) {
       $('#vm-create-network-add-button').attr('disabled', true);
@@ -117,23 +117,23 @@ function vmCustomizeLoaded() {
   /* remove network */
   // event for network remove button (icon, X)
   $('body').on('click', '.vm-create-remove-network', function() {
-    var vlan_pk = ($(this).parent('span').prop('id')).replace('vlan-', '')
+    var vlan_pk = ($(this).parent('span').prop('id')).replace('vlan-', '');
     // if it's "blue" then it's managed, kinda not cool
     var managed = $(this).parent('span').hasClass('label-primary');
 
     $(this).parent('span').fadeOut(500, function() {
       /* if ther are no more vlans disabled the add button */
-      if($('#vm-create-network-add-select option')[0].value == -1) {   
-        $('#vm-create-network-add-button').attr('disabled', false);            
+      if($('#vm-create-network-add-select option')[0].value == -1) {
+        $('#vm-create-network-add-button').attr('disabled', false);
         $('#vm-create-network-add-select').html('');
       }
-      
+
       /* remove the network label */
-      $(this).remove(); 
+      $(this).remove();
 
       var vlan_name = $(this).text();
 
-      var html = '<option data-managed="' + (managed ? 1 : 0) + '" value="' + vlan_pk + '">'+ 
+      var html = '<option data-managed="' + (managed ? 1 : 0) + '" value="' + vlan_pk + '">'+
                  (managed ? "&#xf0ac;": "&#xf0c1;") + vlan_name + '</option>';
       $('#vm-create-network-add-select').append(html);
 
@@ -148,7 +148,7 @@ function vmCustomizeLoaded() {
 
   /* copy networks from hidden select */
   $('#vm-create-network-add-vlan option').each(function() {
-    var managed = $(this).text().indexOf("mana") == 0;
+    var managed = $(this).text().indexOf("mana") === 0;
     var raw_text = $(this).text();
     var pk = $(this).val();
     if(managed) {
@@ -157,7 +157,7 @@ function vmCustomizeLoaded() {
       text = raw_text.replace("unmanaged -", "&#xf0c1;");
     }
     var html = '<option data-managed="' + (managed ? 1 : 0) + '" value="' + pk + '">' + text + '</option>';
-  
+
     if($('#vm-create-network-list span').length < 1) {
       $("#vm-create-network-list").html("");
     }
@@ -180,7 +180,7 @@ function vmCustomizeLoaded() {
     vlans.push({
       'name': $(this).text().replace("unmanaged -", "&#xf0c1;").replace("managed -", "&#xf0ac;"),
       'pk': parseInt($(this).val()),
-      'managed': $(this).text().indexOf("mana") == 0,
+      'managed': $(this).text().indexOf("mana") === 0,
     });
   });
 
@@ -250,7 +250,7 @@ function vmCustomizeLoaded() {
       },
       error: function(xhr, textStatus, error) {
         var r = $('#create-modal'); r.next('div').remove(); r.remove();
-        
+
         if (xhr.status == 500) {
           addMessage("500 Internal Server Error", "danger");
         } else {
@@ -262,8 +262,8 @@ function vmCustomizeLoaded() {
   });
 
   /* for no js stuff */
-  $('.no-js-hidden').show();                                                
-  $('.js-hidden').hide(); 
+  $('.no-js-hidden').show();
+  $('.js-hidden').hide();
 
 }
 
diff --git a/circle/dashboard/static/dashboard/vm-details.js b/circle/dashboard/static/dashboard/vm-details.js
index e851d86..d0422e7 100644
--- a/circle/dashboard/static/dashboard/vm-details.js
+++ b/circle/dashboard/static/dashboard/vm-details.js
@@ -1,6 +1,7 @@
 var show_all = false;
 var in_progress = false;
 var activity_hash = 5;
+var Websock_native; // not sure
 var reload_vm_detail = false;
 
 $(function() {
@@ -42,7 +43,7 @@ $(function() {
     var vm = $(this).data("vm");
     $.ajax({
       type: 'POST',
-      url: "/dashboard/vm/" + vm + "/op/resources_change/", 
+      url: "/dashboard/vm/" + vm + "/op/resources_change/",
       data: $('#vm-details-resources-form').serialize(),
       success: function(data, textStatus, xhr) {
         if(data.success) {
@@ -58,7 +59,7 @@ $(function() {
           addMessage("500 Internal Server Error", "danger");
         } else {
           addMessage(xhr.status + " Unknown Error", "danger");
-        }  
+        }
       }
     });
     e.preventDefault();
@@ -71,17 +72,17 @@ $(function() {
     $.ajax({
       type: 'POST',
       url: location.href,
-      headers: {"X-CSRFToken": getCookie('csrftoken')}, 
+      headers: {"X-CSRFToken": getCookie('csrftoken')},
       data: {'to_remove': to_remove},
       success: function(re) {
-        if(re['message'].toLowerCase() == "success") {
+        if(re.message.toLowerCase() == "success") {
           $(clicked).closest(".label").fadeOut(500, function() {
             $(this).remove();
           });
         }
       },
       error: function() {
-        addMessage(re['message'], 'danger');
+        addMessage(re.message, 'danger');
       }
 
     });
@@ -90,7 +91,7 @@ $(function() {
 
   /* remove port */
   $('.vm-details-remove-port').click(function() {
-    addModalConfirmation(removePort, 
+    addModalConfirmation(removePort,
       {
         'url': $(this).prop("href"),
         'data': [],
@@ -101,7 +102,7 @@ $(function() {
 
   /* for js fallback */
   $("#vm-details-pw-show").parent("div").children("input").prop("type", "password");
-  
+
   /* show password */
   $("#vm-details-pw-show").click(function() {
     var input = $(this).parent("div").children("input");
@@ -150,7 +151,7 @@ $(function() {
         }
       });
     } else {
-      $("#vm-details-pw-confirm").fadeOut(); 
+      $("#vm-details-pw-confirm").fadeOut();
     }
     return false;
   });
@@ -170,7 +171,7 @@ $(function() {
   /* for interface remove buttons */
   $('.interface-remove').click(function() {
     var interface_pk = $(this).data('interface-pk');
-    addModalConfirmation(removeInterface, 
+    addModalConfirmation(removeInterface,
       { 'url': '/dashboard/interface/' + interface_pk + '/delete/',
         'data': [],
         'pk': interface_pk,
@@ -183,15 +184,15 @@ $(function() {
   function removeInterface(data) {
     $.ajax({
       type: 'POST',
-      url: data['url'],
-      headers: {"X-CSRFToken": getCookie('csrftoken')}, 
-      success: function(re, textStatus, xhr) { 
+      url: data.url,
+      headers: {"X-CSRFToken": getCookie('csrftoken')},
+      success: function(re, textStatus, xhr) {
         /* remove the html element */
         $('a[data-interface-pk="' + data.pk + '"]').closest("div").fadeOut();
         location.reload();
       },
       error: function(xhr, textStatus, error) {
-        addMessage('Uh oh :(', 'danger')
+        addMessage('Uh oh :(', 'danger');
       }
     });
   }
@@ -221,12 +222,12 @@ $(function() {
       data: {'new_name': name},
       headers: {"X-CSRFToken": getCookie('csrftoken')},
       success: function(data, textStatus, xhr) {
-        $(".vm-details-home-edit-name").text(data['new_name']).show();
+        $(".vm-details-home-edit-name").text(data.new_name).show();
         $(".vm-details-home-edit-name").parent("div").show();
         $(".vm-details-home-edit-name-click").show();
         $(".vm-details-home-rename-form-div").hide();
         // update the inputs too
-        $(".vm-details-rename-submit").parent("span").prev("input").val(data['new_name']);  
+        $(".vm-details-rename-submit").parent("span").prev("input").val(data.new_name);
       },
       error: function(xhr, textStatus, error) {
         addMessage("Error during renaming!", "danger");
@@ -234,7 +235,7 @@ $(function() {
     });
     return false;
   });
-  
+
   /* update description click */
   $(".vm-details-home-edit-description-click").click(function(e) {
     $(".vm-details-home-edit-description-click").hide();
@@ -246,7 +247,7 @@ $(function() {
     ta.val(tmp)
     e.preventDefault();
   });
-  
+
   /* description update ajax */
   $('.vm-details-description-submit').click(function() {
     var description = $(this).prev("textarea").val();
@@ -256,14 +257,14 @@ $(function() {
       data: {'new_description': description},
       headers: {"X-CSRFToken": getCookie('csrftoken')},
       success: function(data, textStatus, xhr) {
-        var new_desc = data['new_description'];
-        /* we can't simply use $.text, because we need new lines */ 
+        var new_desc = data.new_description;
+        /* we can't simply use $.text, because we need new lines */
         var tagsToReplace = {
           '&': "&amp;",
           '<': "&lt;",
           '>': "&gt;",
         };
-        
+
         new_desc = new_desc.replace(/[&<>]/g, function(tag) {
           return tagsToReplace[tag] || tag;
         });
@@ -273,7 +274,7 @@ $(function() {
         $(".vm-details-home-edit-description-click").show();
         $("#vm-details-home-description").hide();
         // update the textareia
-        $("vm-details-home-description textarea").text(data['new_description']);  
+        $("vm-details-home-description textarea").text(data.new_description);
       },
       error: function(xhr, textStatus, error) {
         addMessage("Error during renaming!", "danger");
@@ -300,8 +301,8 @@ $(function() {
     .find("i").removeClass("fa-spinner fa-spin");
 
   });
-    
-  
+
+
   // screenshot close
   $("#vm-console-screenshot button").click(function() {
     $(this).parent("div").slideUp();
@@ -340,15 +341,15 @@ $(function() {
 function removePort(data) {
   $.ajax({
     type: 'POST',
-    url: data['url'],
+    url: data.url,
     headers: {"X-CSRFToken": getCookie('csrftoken')},
     success: function(re, textStatus, xhr) {
-      $("a[data-rule=" + data['rule'] + "]").each(function() {
+      $("a[data-rule=" + data.rule + "]").each(function() {
         $(this).closest("tr").fadeOut(500, function() {
           $(this).remove();
         });
       });
-      addMessage(re['message'], "success");
+      addMessage(re.message, "success");
     },
     error: function(xhr, textStatus, error) {
 
@@ -374,23 +375,23 @@ function checkNewActivity(runs) {
     url: '/dashboard/vm/' + instance + '/activity/',
     data: {'show_all': show_all},
     success: function(data) {
-      var new_activity_hash = (data['activities'] + "").hashCode();
+      var new_activity_hash = (data.activities + "").hashCode();
       if(new_activity_hash != activity_hash) {
-        $("#activity-refresh").html(data['activities']);
+        $("#activity-refresh").html(data.activities);
       }
       activity_hash = new_activity_hash;
 
-      $("#ops").html(data['ops']);
-      $("#disk-ops").html(data['disk_ops']);
+      $("#ops").html(data.ops);
+      $("#disk-ops").html(data.disk_ops);
       $("[title]").tooltip();
 
       /* changing the status text */
       var icon = $("#vm-details-state i");
-      if(data['is_new_state']) {
+      if(data.is_new_state) {
         if(!icon.hasClass("fa-spin"))
           icon.prop("class", "fa fa-spinner fa-spin");
       } else {
-        icon.prop("class", "fa " + data['icon']);
+        icon.prop("class", "fa " + data.icon);
       }
       $("#vm-details-state").data("status", data['status']);
       $("#vm-details-state span").html(data['human_readable_status'].toUpperCase());
@@ -406,7 +407,7 @@ function checkNewActivity(runs) {
         $("[data-target=#_console]").attr("data-toggle", "_pill").attr("href", "#").parent("li").addClass("disabled");
       }
 
-      if(data['status'] == "STOPPED" || data['status'] == "PENDING") {
+      if(data.status == "STOPPED" || data.status == "PENDING") {
         $(".change-resources-button").prop("disabled", false);
         $(".change-resources-help").hide();
       } else {
@@ -416,7 +417,7 @@ function checkNewActivity(runs) {
 
       if(runs > 0 && decideActivityRefresh()) {
         setTimeout(
-          function() {checkNewActivity(runs + 1)}, 
+          function() {checkNewActivity(runs + 1);},
           1000 + Math.exp(runs * 0.05)
         );
       } else {
@@ -433,7 +434,7 @@ function checkNewActivity(runs) {
 
 String.prototype.hashCode = function() {
   var hash = 0, i, chr, len;
-  if (this.length == 0) return hash;
+  if (this.length === 0) return hash;
   for (i = 0, len = this.length; i < len; i++) {
     chr   = this.charCodeAt(i);
     hash  = ((hash << 5) - hash) + chr;
diff --git a/circle/dashboard/static/dashboard/vm-list.js b/circle/dashboard/static/dashboard/vm-list.js
index b9d9ded..f4a73a4 100644
--- a/circle/dashboard/static/dashboard/vm-list.js
+++ b/circle/dashboard/static/dashboard/vm-list.js
@@ -25,7 +25,7 @@ $(function() {
       retval = false;
     } else if(shiftDown) {
       if(selected.length > 0) {
-        start = selected[selected.length - 1]['index'] + 1;
+        start = selected[selected.length - 1].index + 1;
         end = $(this).index();
 
         if(start > end) {
@@ -101,7 +101,7 @@ $(function() {
   });
 
 
-  $("body").on("click", "#op-form-send", function() {
+  $("body").on("click", "#mass-op-form-send", function() {
     var url = $(this).closest("form").prop("action");
     $(this).find("i").prop("class", "fa fa-fw fa-spinner fa-spin");
 
diff --git a/circle/dashboard/static/template.css b/circle/dashboard/static/template.less
similarity index 78%
rename from circle/dashboard/static/template.css
rename to circle/dashboard/static/template.less
index 8ce2de7..3f23f1a 100644
--- a/circle/dashboard/static/template.css
+++ b/circle/dashboard/static/template.less
@@ -23,46 +23,6 @@ html {
   padding-right: 15px;
 }
 
-/* values for 45px tall navbar */
-.navbar {
-  min-height: 45px;
-}
-
-.navbar-brand {
-  height: 45px;
-  padding: 12.5px 12.5px;
-}
-
-.navbar-toggle {
-  margin-top: 5.5px;
-  margin-bottom: 5.5px;
-}
-
-.navbar-form {
-  margin-top: 5.5px;
-  margin-bottom: 5.5px;
-}
-
-.navbar-btn {
-  margin-top: 5.5px;
-  margin-bottom: 5.5px;
-}
-
-.navbar-btn.btn-sm {
-  margin-top: 7.5px;
-  margin-bottom: 7.5px;
-}
-.navbar-btn.btn-xs {
-  margin-top: 11.5px;
-  margin-bottom: 11.5px;
-}
-.navbar-text {
-  margin-top: 12.5px;
-  margin-bottom: 12.5px;
-}
-
-/* --- */
-
 /* Responsive: Portrait tablets and up */
 @media screen and (min-width: 768px) {
   /* Let the jumbotron breathe */
diff --git a/circle/dashboard/templates/base.html b/circle/dashboard/templates/base.html
index ccee162..58fbd43 100644
--- a/circle/dashboard/templates/base.html
+++ b/circle/dashboard/templates/base.html
@@ -1,4 +1,6 @@
 {% load i18n %}
+{% load staticfiles %}
+{% load compressed %}
 <!DOCTYPE html>
 <html lang="{{lang}}">
   <head>
@@ -6,14 +8,11 @@
     <meta name="viewport" content="width=device-width, initial-scale=1.0">
     <meta name="description" content="">
     <meta name="author" content="">
-    <link rel="icon" type="image/png" href="{{ STATIC_URL}}dashboard/img/favicon.png"/>
+    <link rel="icon" type="image/png" href="{% static "dashboard/img/favicon.png" %}"/>
 
     <title>{% block title %}{% block title-page %}{% endblock %} | {% block title-site %}CIRCLE{% endblock %}{% endblock %}</title>
 
-    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css">
-    <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap-theme.min.css">
-    <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.2.0/css/font-awesome.min.css" rel="stylesheet">
-    <link rel="stylesheet" href="{{ STATIC_URL }}/template.css">
+    {% compressed_css 'all' %}
 
     <!-- HTML5 shim, for IE6-8 support of HTML5 elements -->
     <!--[if lt IE 9]>
@@ -67,11 +66,9 @@
     </footer>
   </body>
 
-  <script src="//code.jquery.com/jquery-1.11.1.min.js"></script>
-  <script src="{{ STATIC_URL }}dashboard/loopj-jquery-simple-slider/js/simple-slider.js"></script>
-  <script src="//netdna.bootstrapcdn.com/bootstrap/3.0.0/js/bootstrap.min.js"></script>
+  <script src="{% static "jquery/dist/jquery.min.js" %}"></script>
   <script src="{{ STATIC_URL }}jsi18n/{{ LANGUAGE_CODE }}/djangojs.js"></script>
-  {% include 'autocomplete_light/static.html' %}
+  {% compressed_js 'all' %}
 
   {% block extra_script %}
   {% endblock %}
@@ -81,11 +78,4 @@
 
   {% block extra_etc %}
   {% endblock %}
-
-<script>
-yourlabs.TextWidget.prototype.getValue = function(choice) {
-    return choice.children().html();
-}
-</script>
-
 </html>
diff --git a/circle/dashboard/templates/dashboard/_vm-create-1.html b/circle/dashboard/templates/dashboard/_vm-create-1.html
index 8aae5c3..f8ecd62 100644
--- a/circle/dashboard/templates/dashboard/_vm-create-1.html
+++ b/circle/dashboard/templates/dashboard/_vm-create-1.html
@@ -81,7 +81,7 @@
   .progress {
     position: relative;
     width: 200px;
-    height: 12px;
+    height: 16px;
     margin-bottom: 0px;
     margin-top: 5px;
   }
diff --git a/circle/dashboard/templates/dashboard/base.html b/circle/dashboard/templates/dashboard/base.html
index cd7e0dd..0bcddf1 100644
--- a/circle/dashboard/templates/dashboard/base.html
+++ b/circle/dashboard/templates/dashboard/base.html
@@ -1,13 +1,11 @@
 {% extends "base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 
 {% block title-site %}Dashboard | CIRCLE{% endblock %}
 
 
 {% block extra_link %}
-  <link rel="stylesheet" href="{{ STATIC_URL }}dashboard/loopj-jquery-simple-slider/css/simple-slider.css"/>
-  <link rel="stylesheet" href="{{ STATIC_URL }}dashboard/introjs/introjs.min.css">
-  <link href="{{ STATIC_URL }}dashboard/dashboard.css" rel="stylesheet">
   {% block extra_link_2 %}{% endblock %}
 {% endblock %}
 
@@ -22,14 +20,14 @@
 {% if user.is_authenticated and user.pk and not request.token_user %}
   <ul class="nav navbar-nav pull-right">
     <li class="dropdown" id="notification-button">
-      <a href="{% url "dashboard.views.notifications" %}" style="color: white; font-size: 12px;"
+      <a href="{% url "dashboard.views.notifications" %}"
         class="dropdown-toggle" data-toggle="dropdown">
         {% trans "Notifications" %}
         {% if NEW_NOTIFICATIONS_COUNT > 0 %}
           <span class="badge badge-pulse">{{ NEW_NOTIFICATIONS_COUNT }}</span>
         {% endif %}
       </a>
-      <ul class="dropdown-menu notification-messages">
+      <ul class="dropdown-menu" id="notification-messages">
           <li>{% trans "Loading..." %}</li>
       </ul>
     </li>
@@ -38,7 +36,7 @@
   <a class="navbar-brand pull-right" href="{% url "logout" %}?next={% url "login" %}" style="color: white; font-size: 10px;">
     <i class="fa fa-sign-out"></i> {% trans "Log out" %}
   </a>
-  <a class="navbar-brand pull-right" href="{% url "dashboard.views.profile-preferences" %}" title="{% trans "User profile" %}" style="color: white; font-size: 10px;">
+  <a class="navbar-brand pull-right" href="{% url "dashboard.views.profile-preferences" %}" style="color: white; font-size: 10px;">
     <i class="fa fa-user"></i>
     {% include "dashboard/_display-name.html" with user=user show_org=True %}
   </a>
@@ -52,9 +50,3 @@
 {% endif %}
 
 {% endblock %}
-
-
-{% block extra_script %}
-  <script src="{{ STATIC_URL }}dashboard/js/jquery.knob.js"></script>
-  <script src="{{ STATIC_URL }}dashboard/dashboard.js"></script>
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/group-detail.html b/circle/dashboard/templates/dashboard/group-detail.html
index 22e1350..0e0cdfd 100644
--- a/circle/dashboard/templates/dashboard/group-detail.html
+++ b/circle/dashboard/templates/dashboard/group-detail.html
@@ -164,7 +164,3 @@
   </div>
 </div>
 {% endblock %}
-
-{% block extra_js %}
-  <script type="text/javascript" src="{% static "dashboard/group-details.js" %}"></script>
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/group-list.html b/circle/dashboard/templates/dashboard/group-list.html
index a47f2cd..e7a43ee 100644
--- a/circle/dashboard/templates/dashboard/group-list.html
+++ b/circle/dashboard/templates/dashboard/group-list.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 {% load render_table from django_tables2 %}
 
@@ -23,7 +24,3 @@
   </div>
 </div>
 {% endblock %}
-
-{% block extra_js %}
-  <script src="{{ STATIC_URL}}dashboard/group-list.js"></script>
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/index-groups.html b/circle/dashboard/templates/dashboard/index-groups.html
index e1aba82..72380ba 100644
--- a/circle/dashboard/templates/dashboard/index-groups.html
+++ b/circle/dashboard/templates/dashboard/index-groups.html
@@ -2,7 +2,7 @@
 <div class="panel panel-default">
   <div class="panel-heading">
     <div class="pull-right toolbar">
-      <span class="btn btn-default btn-xs infobtn" title="{% trans "List of groups that you have access to." %}"><i class="fa fa-info-circle"></i></span>
+      <span class="btn btn-default btn-xs infobtn" data-container="body" title="{% trans "List of groups that you have access to." %}"><i class="fa fa-info-circle"></i></span>
     </div>
     <h3 class="no-margin"><i class="fa fa-group"></i> {% trans "Groups" %}</h3>
   </div>
@@ -17,13 +17,17 @@
     </div>
     <div href="#" class="list-group-item list-group-footer text-right">
       <div class="row">
-        <div class="col-sm-6 col-xs-6 input-group input-group-sm">
-          <input id="dashboard-group-search-input" type="text" class="form-control" placeholder="{% trans "Search..." %}" />
-          <div class="input-group-btn">
-            <button type="submit" class="form-control btn btn-primary"><i class="fa fa-search"></i></button>
-          </div>
+        <div class="col-xs-6">
+          <form action="{% url "dashboard.views.group-list" %}" method="GET" id="dashboard-group-search-form">
+            <div class="input-group input-group-sm">
+              <input id="dashboard-group-search-input" name="s" type="text" class="form-control" placeholder="{% trans "Search..." %}" />
+              <div class="input-group-btn">
+                <button type="submit" class="form-control btn btn-primary"><i class="fa fa-search"></i></button>
+              </div>
+            </div>
+          </form>
         </div>
-        <div class="col-sm-6 text-right">
+        <div class="col-xs-6 text-right">
           <a class="btn btn-primary btn-xs" href="{% url "dashboard.views.group-list" %}">
             <i class="fa fa-chevron-circle-right"></i>
             {% if more_groups > 0 %}
diff --git a/circle/dashboard/templates/dashboard/index-nodes.html b/circle/dashboard/templates/dashboard/index-nodes.html
index 8574869..6f44b1e 100644
--- a/circle/dashboard/templates/dashboard/index-nodes.html
+++ b/circle/dashboard/templates/dashboard/index-nodes.html
@@ -8,7 +8,7 @@
         <a href="#index-list-view" data-index-box="node" class="btn btn-default btn-xs disabled"
           data-container="body"><i class="fa fa-list"></i></a>
       </div>
-      <span class="btn btn-default btn-xs infobtn" title="{% trans "List of compute nodes, also called worker nodes or hypervisors, which run the virtual machines." %}">
+      <span class="btn btn-default btn-xs infobtn" data-container="body" title="{% trans "List of compute nodes, also called worker nodes or hypervisors, which run the virtual machines." %}">
         <i class="fa fa-info-circle"></i>
       </span>
     </div>
@@ -56,16 +56,21 @@
 
   <div href="#" class="list-group-item list-group-footer">
     <div class="row">
-      <div class="col-sm-6 col-xs-6 input-group input-group-sm">
-        <input id="dashboard-node-search-input" type="text" class="form-control"
-         placeholder="{% trans "Search..." %}" />
-        <div class="input-group-btn">
-          <button type="submit" class="btn btn-primary" title="{% trans "Search" %}" data-container="body">
-            <i class="fa fa-search"></i>
-          </button>
-        </div>
+      <div class="col-xs-6">
+        <form action="{% url "dashboard.views.node-list" %}" method="GET"
+          id="dashboard-node-search-form">
+          <div class="input-group input-group-sm">
+            <input id="dashboard-node-search-input" type="text" class="form-control"
+             placeholder="{% trans "Search..." %}" />
+            <div class="input-group-btn">
+              <button type="submit" class="btn btn-primary" title="{% trans "Search" %}" data-container="body">
+                <i class="fa fa-search"></i>
+              </button>
+            </div>
+          </div>
+        </form>
       </div>
-      <div class="col-sm-6 text-right">
+      <div class="col-xs-6 text-right">
         <a class="btn btn-primary btn-xs" href="{% url "dashboard.views.node-list" %}">
           <i class="fa fa-chevron-circle-right"></i>
           {% if more_nodes > 0 %}
diff --git a/circle/dashboard/templates/dashboard/index-templates.html b/circle/dashboard/templates/dashboard/index-templates.html
index f4b1b17..82eeb57 100644
--- a/circle/dashboard/templates/dashboard/index-templates.html
+++ b/circle/dashboard/templates/dashboard/index-templates.html
@@ -1,7 +1,7 @@
 {% load i18n %}
 <div class="panel panel-default">
   <div class="panel-heading">
-    <span class="btn btn-default btn-xs infobtn pull-right" title="{% trans "List of VM templates that are available for you. You can create new ones from scratch or customize existing ones (preferred)." %}">
+    <span class="btn btn-default btn-xs infobtn pull-right" data-container="body" title="{% trans "List of VM templates that are available for you. You can create new ones from scratch or customize existing ones (preferred)." %}">
       <i class="fa fa-info-circle"></i>
     </span>
     <h3 class="no-margin"><i class="fa fa-puzzle-piece"></i> {% trans "Templates" %}
@@ -16,7 +16,10 @@
           <i class="fa fa-{{ t.os_type }}"></i> {{ t.name }}
         </span>
         <small class="text-muted index-template-list-system">{{ t.system }}</small>
-        <div class="pull-right vm-create" data-template="{{ t.pk }}"><i title="{% trans "Start vm instance" %}" class="fa fa-play"></i></div>
+        <div class="pull-right vm-create" data-template="{{ t.pk }}">
+          <i data-container="body" title="{% trans "Start VM instance" %}" 
+            class="fa fa-play"></i>
+        </div>
         <div class="clearfix"></div>
       </a>
       {% empty %}
diff --git a/circle/dashboard/templates/dashboard/index-vm.html b/circle/dashboard/templates/dashboard/index-vm.html
index 0d780a6..694239a 100644
--- a/circle/dashboard/templates/dashboard/index-vm.html
+++ b/circle/dashboard/templates/dashboard/index-vm.html
@@ -10,7 +10,7 @@
           data-container="body"
           title="{% trans "list view" %}"><i class="fa fa-list"></i></a>
       </div>
-      <span class="btn btn-default btn-xs infobtn" title="{% trans "List of your current virtual machines. Favourited ones are ahead of others." %}"><i class="fa fa-info-circle"></i></span>
+      <span class="btn btn-default btn-xs infobtn" data-container="body" title="{% trans "List of your current virtual machines. Favourited ones are ahead of others." %}"><i class="fa fa-info-circle"></i></span>
     </div>
     <h3 class="no-margin">
       <i class="fa fa-desktop"></i> {% trans "Virtual machines" %}
@@ -44,23 +44,20 @@
         </div>
       {% endfor %}
     </div>
-    <style>
-      .list-group-item-last {
-        border-bottom: 1px solid #ddd !important;
-      }
-    </style>
     <div href="#" class="list-group-item list-group-footer">
       <div class="row">
+        <div class="col-xs-6">
         <form action="{% url "dashboard.views.vm-list" %}" method="GET" id="dashboard-vm-search-form">
-          <div class="col-sm-6 col-xs-6 input-group input-group-sm">
-            <input id="dashboard-vm-search-input" type="text" class="form-control" name="s"
+          <div class="input-group input-group-sm">
+            <input id="dashboard-vm-search-input" type="text" class="form-control" name="s" 
             placeholder="{% trans "Search..." %}" />
             <div class="input-group-btn">
               <button type="submit" class="form-control btn btn-primary"><i class="fa fa-search"></i></button>
             </div>
           </div>
         </form>
-        <div class="col-sm-6 text-right">
+        </div>
+        <div class="col-xs-6 text-right">
           <a class="btn btn-primary btn-xs" href="{% url "dashboard.views.vm-list" %}">
             <i class="fa fa-chevron-circle-right"></i>
             {% if more_instances > 0 %}
diff --git a/circle/dashboard/templates/dashboard/index.html b/circle/dashboard/templates/dashboard/index.html
index 16dfea1..0400fc5 100644
--- a/circle/dashboard/templates/dashboard/index.html
+++ b/circle/dashboard/templates/dashboard/index.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 
 {% block title-page %}{% trans "Index" %}{% endblock %}
@@ -50,8 +51,3 @@
   </div>
 </div>
 {% endblock %}
-
-{% block extra_js %}
-<script src="{{ STATIC_URL }}dashboard/vm-create.js"></script>
-<script src="{{ STATIC_URL }}dashboard/node-create.js"></script>
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/mass-operate.html b/circle/dashboard/templates/dashboard/mass-operate.html
index 33d6e83..0c9baa7 100644
--- a/circle/dashboard/templates/dashboard/mass-operate.html
+++ b/circle/dashboard/templates/dashboard/mass-operate.html
@@ -31,7 +31,7 @@ Do you want to perform the <strong>{{op}}</strong> operation on the following {{
   <div class="pull-right">
     <a class="btn btn-default" href="{% url "dashboard.views.vm-list" %}"
      data-dismiss="modal">{% trans "Cancel" %}</a>
-    <button class="btn btn-{{ opview.effect }}" type="submit" id="op-form-send">
+    <button class="btn btn-{{ opview.effect }}" type="submit" id="mass-op-form-send">
       {% if opview.icon %}<i class="fa fa-fw fa-{{opview.icon}}"></i> {% endif %}{{ opview.name|capfirst }}
     </button>
   </div>
diff --git a/circle/dashboard/templates/dashboard/node-detail.html b/circle/dashboard/templates/dashboard/node-detail.html
index b7ddc48..177cb47 100644
--- a/circle/dashboard/templates/dashboard/node-detail.html
+++ b/circle/dashboard/templates/dashboard/node-detail.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 
 {% block title-page %}{{ node.name }} | {% trans "Node" %}{% endblock %}
@@ -96,7 +97,3 @@
   </div>
 </div>
 {% endblock %}
-
-{% block extra_js %}
-  <script src="{{ STATIC_URL}}dashboard/node-details.js"></script>
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/node-list.html b/circle/dashboard/templates/dashboard/node-list.html
index 16ce23b..070b180 100644
--- a/circle/dashboard/templates/dashboard/node-list.html
+++ b/circle/dashboard/templates/dashboard/node-list.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 {% load render_table from django_tables2 %}
 
@@ -39,7 +40,3 @@
 </div><!-- .row -->
 
 {% endblock %}
-
-{% block extra_js %}
-  <script src="{{ STATIC_URL}}dashboard/node-list.js"></script>
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/node-list/column-monitor.html b/circle/dashboard/templates/dashboard/node-list/column-monitor.html
index f955db2..77a37a9 100644
--- a/circle/dashboard/templates/dashboard/node-list/column-monitor.html
+++ b/circle/dashboard/templates/dashboard/node-list/column-monitor.html
@@ -2,7 +2,7 @@
 {% load i18n %}
 
 <i class="fa fa-gears"></i> {% trans "CPU" %}
- <div class="progress pull-right">
+<div class="progress pull-right">
   <div class="progress-bar progress-bar-success" role="progressbar"
     aria-valuenow="{{ record.cpu_usage|stringformat:"f" }}"
     aria-valuemin="0" aria-valuemax="1"
@@ -13,12 +13,14 @@
       {% else %}
         -
       {% endif %}
-   </span>
+    </span>
   </div>
- </div>
+</div>
+
 <br>
+
 <i class="fa fa-ticket"></i> {% trans "Memory" %}
- <div class="progress pull-right">
+<div class="progress pull-right">
   <div class="progress-bar" role="progressbar"
     aria-valuenow="{{ record.ram_usage|stringformat:"f" }}"
     aria-valuemin="0" aria-valuemax="100"
@@ -31,29 +33,4 @@
       {% endif %}
     </span>
   </div>
- </div>
-<style>
-  .progress {
-    position: relative;
-    width: 150px;
-    height: 16px;
-    margin-bottom: 4px;
-    margin-top: 0px;
-    background-image: linear-gradient(to bottom, #BBEBEB 0px, #F5F5F5 100%);
-  }
-  .progress-bar-text {
-    position: absolute;
-    display: block;
-    width: 100%;
-    color: white;
-    /* outline */
-    text-shadow:
-      -1px -1px 0 #000,
-      1px -1px 0 #000,
-      -1px 1px 0 #000,
-      1px 1px 0 #000;
-    font-size: 13px;
-  }
-</style>
-
-
+</div>
diff --git a/circle/dashboard/templates/dashboard/nojs-wrapper.html b/circle/dashboard/templates/dashboard/nojs-wrapper.html
index e5f87c2..7ec7b87 100644
--- a/circle/dashboard/templates/dashboard/nojs-wrapper.html
+++ b/circle/dashboard/templates/dashboard/nojs-wrapper.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 
 {% block content %}
   <div class="body-content">
@@ -14,9 +15,3 @@
     </div>
   </div>
 {% endblock %}
-
-{% block extra_js %}
-  {% if template == "dashboard/_vm-create-1.html" or template == "dashboard/_vm-create-2.html" %}
-    <script src="{{ STATIC_URL }}dashboard/vm-create.js"></script>
-  {% endif %}
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/profile.html b/circle/dashboard/templates/dashboard/profile.html
index 7e10e62..5c2a07a 100644
--- a/circle/dashboard/templates/dashboard/profile.html
+++ b/circle/dashboard/templates/dashboard/profile.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 {% load crispy_forms_tags %}
 
@@ -111,7 +112,3 @@
 </div>
 
 {% endblock %}
-
-{% block extra_js %}
-  <script src="{{ STATIC_URL }}dashboard/profile.js"></script>
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/store/index-files.html b/circle/dashboard/templates/dashboard/store/index-files.html
index 4930924..92cb582 100644
--- a/circle/dashboard/templates/dashboard/store/index-files.html
+++ b/circle/dashboard/templates/dashboard/store/index-files.html
@@ -3,10 +3,11 @@
 <div class="panel panel-default">
   <div class="panel-heading">
     <span class="btn btn-default btn-xs infobtn pull-right store-action-button" 
-      title="{% trans "A list of your most recent files." %}">
+      title="{% trans "A list of your most recent files." %}"
+      data-container="body">
       <i class="fa fa-info-circle"></i>
     </span>
-    <span class="btn btn-default btn-xs pull-right" 
+    <span class="btn btn-default btn-xs pull-right" data-container="body"
       title="
       {% blocktrans with used=files.quota.readable_used soft=files.quota.readable_soft hard=files.quota.readable_hard %}
       You are currently using {{ used }}, your soft limit is {{ soft }}, your hard limit is {{ hard }}.
@@ -20,7 +21,8 @@
     <div id="dashboard-files-toplist">
     {% for t in files.toplist %}
     {% if t.TYPE == "F" %}
-      <div class="list-group-item">
+      <div class="list-group-item
+        {% if forloop.last and files.toplist|length < 5 %}list-group-item-last{% endif %}">
         <i class="fa fa-{{ t.icon }} dashboard-toplist-icon"></i> 
         <div class="store-list-item-name">
           {{ t.NAME }}
@@ -37,7 +39,8 @@
       </div>
     {% else %}
     <a href="{% url "dashboard.views.store-list" %}?directory={{ t.path }}" 
-      class="list-group-item">
+      class="list-group-item
+      {% if forloop.last and files.toplist|length < 5 %}list-group-item-last{% endif %}">
       <i class="fa fa-{{ t.icon }} dashboard-toplist-icon"></i>
         <div class="store-list-item-name">
         {{ t.NAME }}
diff --git a/circle/dashboard/templates/dashboard/store/list.html b/circle/dashboard/templates/dashboard/store/list.html
index d0702ac..1cd33dc 100644
--- a/circle/dashboard/templates/dashboard/store/list.html
+++ b/circle/dashboard/templates/dashboard/store/list.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 
 {% block title-page %}{% trans "List" %} | {% trans "Store" %}{% endblock %}
@@ -17,26 +18,23 @@
     <div class="progress-bar" role="progressbar" 
       aria-valuenow="{{ quota.used }}" aria-valuemin="0" aria-valuemax="{{ quota.hard }}" 
       style="width: {% widthratio quota.used quota.hard 100 %}%; min-width: 150px;">
-      <div style="padding-top: 2px;">
+      <div>
         {% blocktrans with used=quota.readable_used %}
           {{ used }} used
         {% endblocktrans %}
       </div>
     </div>
 
-    <div class="progress-marker" id="progress-marker-hard" data-placement="left"
+    <div class="progress-marker" id="progress-marker-hard" data-placement="top"
+      data-container="body"
       title="{% trans "Hard limit" %}: {{ quota.readable_hard }}">
     </div>
-    <div class="progress-marker" id="progress-marker-soft" style="background: orange; 
+    <div class="progress-marker" id="progress-marker-soft" style="background: orange;
       left: {% widthratio quota.soft quota.hard 100 %}%"
       title="{% trans "Soft limit" %}: {{ quota.readable_soft }}"
-      data-placement="top">
+      data-placement="top" data-container="body">
     </div>
   </div>
 </div>
 
 {% endblock %}
-
-{% block extra_js %}
-  <script src="{{ STATIC_URL}}dashboard/store.js"></script>
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/template-edit.html b/circle/dashboard/templates/dashboard/template-edit.html
index 64963e7..83b7f06 100644
--- a/circle/dashboard/templates/dashboard/template-edit.html
+++ b/circle/dashboard/templates/dashboard/template-edit.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 {% load sizefieldtags %}
 {% load crispy_forms_tags %}
@@ -152,6 +153,4 @@
       $("#hint_id_num_cores, #hint_id_priority, #hint_id_ram_size").hide();
     });
   </script>
-
-  <script src="{{ STATIC_URL }}dashboard/disk-list.js"></script>
 {% endblock %}
diff --git a/circle/dashboard/templates/dashboard/template-list.html b/circle/dashboard/templates/dashboard/template-list.html
index 29ec340..e768096 100644
--- a/circle/dashboard/templates/dashboard/template-list.html
+++ b/circle/dashboard/templates/dashboard/template-list.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 {% load render_table from django_tables2 %}
 
@@ -75,8 +76,3 @@
 </div>
 {% endif %}
 {% endblock %}
-
-{% block extra_js %}
-  <script src="{{ STATIC_URL}}dashboard/template-list.js"></script>
-  <script src="{{ STATIC_URL}}dashboard/js/stupidtable.min.js"></script>
-{% endblock %}
diff --git a/circle/dashboard/templates/dashboard/vm-detail.html b/circle/dashboard/templates/dashboard/vm-detail.html
index ef7752a..b757677 100644
--- a/circle/dashboard/templates/dashboard/vm-detail.html
+++ b/circle/dashboard/templates/dashboard/vm-detail.html
@@ -1,5 +1,7 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
+{% load compressed %}
 
 {% block title-page %}{{ instance.name }} | vm{% endblock %}
 
@@ -227,10 +229,5 @@
 {% endblock %}
 
 {% block extra_js %}
-  <script src="{{ STATIC_URL }}dashboard/introjs/intro.min.js"></script>
-  <script src="{{ STATIC_URL }}dashboard/vm-details.js"></script>
-  <script src="{{ STATIC_URL }}dashboard/vm-common.js"></script>
-  <script src="{{ STATIC_URL }}dashboard/vm-console.js"></script>
-  <script src="{{ STATIC_URL }}dashboard/disk-list.js"></script>
-  <script src="{{ STATIC_URL }}dashboard/vm-tour.js"></script>
+  {% compressed_js 'vm-detail' %}
 {% endblock %}
diff --git a/circle/dashboard/templates/dashboard/vm-detail/console.html b/circle/dashboard/templates/dashboard/vm-detail/console.html
index e58cf07..a9a71ae 100644
--- a/circle/dashboard/templates/dashboard/vm-detail/console.html
+++ b/circle/dashboard/templates/dashboard/vm-detail/console.html
@@ -1,4 +1,5 @@
 {% load i18n %}
+{% load staticfiles %}
 <div class="btn-toolbar">
 {% if perms.vm.access_console %}
   <button id="sendCtrlAltDelButton" class="btn btn-danger btn-sm">{% trans "Send Ctrl+Alt+Del" %}</button>
@@ -22,9 +23,8 @@
 <canvas id="noVNC_canvas" width="640px" height="20px">Canvas not supported.
 </canvas>
 
-<script src="{{ STATIC_URL }}dashboard/novnc/util.js"></script>
 <script>
-  var INCLUDE_URI = '{{ STATIC_URL }}dashboard/novnc/';
+  var INCLUDE_URI = '{% static "no-vnc/include/" %}';
   var VNC_URL = "{{ vnc_url }}";
 </script>
 {% endif %}
diff --git a/circle/dashboard/templates/dashboard/vm-list.html b/circle/dashboard/templates/dashboard/vm-list.html
index c7bc1dc..9cb56c8 100644
--- a/circle/dashboard/templates/dashboard/vm-list.html
+++ b/circle/dashboard/templates/dashboard/vm-list.html
@@ -1,4 +1,5 @@
 {% extends "dashboard/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 
 {% block title-page %}{% trans "Virtual machines" %}{% endblock %}
@@ -154,8 +155,3 @@
 </div>
 
 {% endblock %}
-
-{% block extra_js %}
-  <script src="{{ STATIC_URL}}dashboard/vm-list.js"></script>
-  <script src="{{ STATIC_URL}}dashboard/js/stupidtable.min.js"></script>
-{% endblock %}
diff --git a/circle/fabfile.py b/circle/fabfile.py
index 4c595ff..4e616bc 100755
--- a/circle/fabfile.py
+++ b/circle/fabfile.py
@@ -34,6 +34,15 @@ def pip(env, req):
         run("pip install -r %s" % req)
 
 
+def bower(component=None):
+    "Install bower component"
+    with cd("~/circle/circle"):
+        if component:
+            run("bower install %s" % component)
+        else:
+            run("bower install")
+
+
 @roles('portal')
 def migrate():
     "Run db migrations"
@@ -110,6 +119,7 @@ def update_portal(test=False, git=True):
             pull()
         cleanup()
         pip("circle", "~/circle/requirements.txt")
+        bower()
         migrate()
         compile_things()
         if test:
diff --git a/circle/network/static/js/host.js b/circle/network/static/js/host.js
index 997d65c..b63636c 100644
--- a/circle/network/static/js/host.js
+++ b/circle/network/static/js/host.js
@@ -1,4 +1,4 @@
-$('i[class="fa fa-times"]').click(function() {
+$('#small_rule_table i[class="fa fa-times"]').click(function() {
     href = $(this).parent('a').attr('href');
     csrf = getCookie('csrftoken');
     var click_this = this;
diff --git a/circle/network/static/js/select2-3.4.0/LICENSE b/circle/network/static/js/select2-3.4.0/LICENSE
deleted file mode 100644
index 3c98f3d..0000000
--- a/circle/network/static/js/select2-3.4.0/LICENSE
+++ /dev/null
@@ -1,18 +0,0 @@
-Copyright 2012 Igor Vaynberg
-
-Version: @@ver@@ Timestamp: @@timestamp@@
-
-This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
-General Public License version 2 (the "GPL License"). You may choose either license to govern your
-use of this software only upon the condition that you accept all of the terms of either the Apache
-License or the GPL License.
-
-You may obtain a copy of the Apache License and the GPL License at:
-
-http://www.apache.org/licenses/LICENSE-2.0
-http://www.gnu.org/licenses/gpl-2.0.html
-
-Unless required by applicable law or agreed to in writing, software distributed under the Apache License
-or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
-either express or implied. See the Apache License and the GPL License for the specific language governing
-permissions and limitations under the Apache License and the GPL License.
\ No newline at end of file
diff --git a/circle/network/static/js/select2-3.4.0/README.md b/circle/network/static/js/select2-3.4.0/README.md
deleted file mode 100644
index 12e2492..0000000
--- a/circle/network/static/js/select2-3.4.0/README.md
+++ /dev/null
@@ -1,83 +0,0 @@
-Select2
-=================
-
-Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.
-
-To get started checkout examples and documentation at http://ivaynberg.github.com/select2
-
-What Usecases Does Select2 Support
--------------------------------------------------
-
-* Enhances native selects with search
-* Enhances native selects with a better multi-select interface
-* Loading data from javascript: easily load items via ajax and have them searchable
-* Nested optgroups: native selects only support one level of nested, Select2 does not have this restriction
-* Tagging: ability to add new items on the fly
-* Working with large remote datesets: ability to partially load a dataset based on the search term
-* Paging of large datasets: easy support for loading more pages when the results are scrolled to the end
-* Templating: support for custom rendering of results and selections
-
-Browser Compatibility
---------------------
-* IE 8+ (7 mostly works except for [issue with z-index](https://github.com/ivaynberg/select2/issues/37))
-* Chrome 8+
-* Firefox 3.5+
-* Safari 3+
-* Opera 10.6+
-
-Integrations
-------------
-
-* [Wicket-Select2](https://github.com/ivaynberg/wicket-select2) (Java / [Apache Wicket](http://wicket.apache.org))
-* [select2-rails](https://github.com/argerim/select2-rails) (Ruby on Rails)
-* [AngularUI](http://angular-ui.github.com/#directives-select2) ([AngularJS](angularjs.org))
-* [Django](https://github.com/applegrew/django-select2)
-* [Symfony](https://github.com/19Gerhard85/sfSelect2WidgetsPlugin)
-* [Bootstrap](https://github.com/t0m/select2-bootstrap-css) (CSS skin)
-* [Yii](https://github.com/tonybolzan/yii-select2)
-
-Internationalization (i18n)
----------------------------
-
-Select2 supports multiple languages by simply including the right
-language JS file (`select2_locale_it.js`, `select2_locale_nl.js` etc.).
-
-Missing a language? Just copy `select2_locale_en.js.template`, translate
-it and make a pull request back to Select2 here on Github.
-
-Bug tracker
------------
-
-Have a bug? Please create an issue here on GitHub!
-
-https://github.com/ivaynberg/select2/issues
-
-Mailing list
-------------
-
-Have a question? Ask on our mailing list!
-
-select2@googlegroups.com
-
-https://groups.google.com/d/forum/select2
-
-
-Copyright and License
----------------------
-
-Copyright 2012 Igor Vaynberg
-
-This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU 
-General Public License version 2 (the "GPL License"). You may choose either license to govern your 
-use of this software only upon the condition that you accept all of the terms of either the Apache 
-License or the GPL License. 
-
-You may obtain a copy of the Apache License and the GPL License in the LICENSE file, or at:
-
-http://www.apache.org/licenses/LICENSE-2.0
-http://www.gnu.org/licenses/gpl-2.0.html
-
-Unless required by applicable law or agreed to in writing, software distributed under the Apache License 
-or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
-either express or implied. See the Apache License and the GPL License for the specific language governing 
-permissions and limitations under the Apache License and the GPL License.
diff --git a/circle/network/static/js/select2-3.4.0/component.json b/circle/network/static/js/select2-3.4.0/component.json
deleted file mode 100644
index 4c7337f..0000000
--- a/circle/network/static/js/select2-3.4.0/component.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
-    "name": "select2",
-    "version": "3.4.0",
-    "main": ["select2.js", "select2.css", "select2.png", "select2x2.png", "select2-spinner.gif"],
-    "dependencies": {
-        "jquery": ">= 1.7.1"
-    }
-}
diff --git a/circle/network/static/js/select2-3.4.0/release.sh b/circle/network/static/js/select2-3.4.0/release.sh
deleted file mode 100755
index 0a315ab..0000000
--- a/circle/network/static/js/select2-3.4.0/release.sh
+++ /dev/null
@@ -1,69 +0,0 @@
-#!/bin/bash
-set -e
-
-echo -n "Enter the version for this release: "
-
-read ver
-
-if [ ! $ver ]; then 
-	echo "Invalid version."
-	exit
-fi
-
-name="select2"
-js="$name.js"
-mini="$name.min.js"
-css="$name.css"
-release="$name-$ver"
-tag="$ver"
-branch="build-$ver"
-curbranch=`git branch | grep "*" | sed "s/* //"`
-timestamp=$(date)
-tokens="s/@@ver@@/$ver/g;s/\@@timestamp@@/$timestamp/g"
-remote="github"
-
-echo "Updating Version Identifiers"
-
-sed -E -e "s/\"version\": \"([0-9\.]+)\",/\"version\": \"$ver\",/g" -i "" component.json select2.jquery.json
-git add component.json
-git add select2.jquery.json
-git commit -m "modified version identifiers in descriptors for release $ver"
-git push
- 
-git branch "$branch"
-git checkout "$branch"
-
-echo "Tokenizing..."
-
-find . -name "$js" | xargs -I{} sed -e "$tokens" -i "" {} 
-find . -name "$css" | xargs -I{} sed -e "$tokens" -i "" {}
-sed -e "s/latest/$ver/g" -i "" component.json
-
-git add "$js"
-git add "$css"
-
-echo "Minifying..."
-
-echo "/*" > "$mini"
-cat LICENSE | sed "$tokens" >> "$mini"
-echo "*/" >> "$mini"
-
-curl -s \
-	--data-urlencode "js_code@$js" \
-	http://marijnhaverbeke.nl/uglifyjs \
-	>> "$mini"
-
-git add "$mini"
-	
-git commit -m "release $ver"
-
-echo "Tagging..."
-git tag -a "$tag" -m "tagged version $ver"
-git push "$remote" --tags
-
-echo "Cleaning Up..."
-
-git checkout "$curbranch"
-git branch -D "$branch"
-
-echo "Done"
diff --git a/circle/network/static/js/select2-3.4.0/select2-spinner.gif b/circle/network/static/js/select2-3.4.0/select2-spinner.gif
deleted file mode 100644
index 5b33f7e..0000000
Binary files a/circle/network/static/js/select2-3.4.0/select2-spinner.gif and /dev/null differ
diff --git a/circle/network/static/js/select2-3.4.0/select2.jquery.json b/circle/network/static/js/select2-3.4.0/select2.jquery.json
deleted file mode 100644
index b9b114d..0000000
--- a/circle/network/static/js/select2-3.4.0/select2.jquery.json
+++ /dev/null
@@ -1,36 +0,0 @@
-{
-    "name": "select2",
-    "title": "Select2",
-    "description": "Select2 is a jQuery based replacement for select boxes. It supports searching, remote data sets, and infinite scrolling of results.",
-    "keywords": [
-        "select",
-        "autocomplete",
-        "typeahead",
-        "dropdown",
-        "multiselect",
-        "tag",
-        "tagging"
-    ],
-    "version": "3.4.0",
-    "author": {
-        "name": "Igor Vaynberg",
-        "url": "https://github.com/ivaynberg"
-    },
-    "licenses": [
-        {
-            "type": "Apache",
-            "url": "http://www.apache.org/licenses/LICENSE-2.0"
-        },
-        {
-            "type": "GPL v2",
-            "url": "http://www.gnu.org/licenses/gpl-2.0.html"
-        }
-    ],
-    "bugs": "https://github.com/ivaynberg/select2/issues",
-    "homepage": "http://ivaynberg.github.com/select2",
-    "docs": "http://ivaynberg.github.com/select2/",
-    "download": "https://github.com/ivaynberg/select2/tags",
-    "dependencies": {
-        "jquery": ">=1.7.1"
-    }
-}
diff --git a/circle/network/static/js/select2-3.4.0/select2.js b/circle/network/static/js/select2-3.4.0/select2.js
deleted file mode 100644
index 992ba8b..0000000
--- a/circle/network/static/js/select2-3.4.0/select2.js
+++ /dev/null
@@ -1,3054 +0,0 @@
-/*
-Copyright 2012 Igor Vaynberg
-
-Version: 3.4.0 Timestamp: Tue May 14 08:27:33 PDT 2013
-
-This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
-General Public License version 2 (the "GPL License"). You may choose either license to govern your
-use of this software only upon the condition that you accept all of the terms of either the Apache
-License or the GPL License.
-
-You may obtain a copy of the Apache License and the GPL License at:
-
-    http://www.apache.org/licenses/LICENSE-2.0
-    http://www.gnu.org/licenses/gpl-2.0.html
-
-Unless required by applicable law or agreed to in writing, software distributed under the
-Apache License or the GPL Licesnse is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-CONDITIONS OF ANY KIND, either express or implied. See the Apache License and the GPL License for
-the specific language governing permissions and limitations under the Apache License and the GPL License.
-*/
- (function ($) {
- 	if(typeof $.fn.each2 == "undefined"){
- 		$.fn.extend({
- 			/*
-			* 4-10 times faster .each replacement
-			* use it carefully, as it overrides jQuery context of element on each iteration
-			*/
-			each2 : function (c) {
-				var j = $([0]), i = -1, l = this.length;
-				while (
-					++i < l
-					&& (j.context = j[0] = this[i])
-					&& c.call(j[0], i, j) !== false //"this"=DOM, i=index, j=jQuery object
-				);
-				return this;
-			}
- 		});
- 	}
-})(jQuery);
-
-(function ($, undefined) {
-    "use strict";
-    /*global document, window, jQuery, console */
-
-    if (window.Select2 !== undefined) {
-        return;
-    }
-
-    var KEY, AbstractSelect2, SingleSelect2, MultiSelect2, nextUid, sizer,
-        lastMousePosition, $document, scrollBarDimensions,
-
-    KEY = {
-        TAB: 9,
-        ENTER: 13,
-        ESC: 27,
-        SPACE: 32,
-        LEFT: 37,
-        UP: 38,
-        RIGHT: 39,
-        DOWN: 40,
-        SHIFT: 16,
-        CTRL: 17,
-        ALT: 18,
-        PAGE_UP: 33,
-        PAGE_DOWN: 34,
-        HOME: 36,
-        END: 35,
-        BACKSPACE: 8,
-        DELETE: 46,
-        isArrow: function (k) {
-            k = k.which ? k.which : k;
-            switch (k) {
-            case KEY.LEFT:
-            case KEY.RIGHT:
-            case KEY.UP:
-            case KEY.DOWN:
-                return true;
-            }
-            return false;
-        },
-        isControl: function (e) {
-            var k = e.which;
-            switch (k) {
-            case KEY.SHIFT:
-            case KEY.CTRL:
-            case KEY.ALT:
-                return true;
-            }
-
-            if (e.metaKey) return true;
-
-            return false;
-        },
-        isFunctionKey: function (k) {
-            k = k.which ? k.which : k;
-            return k >= 112 && k <= 123;
-        }
-    },
-    MEASURE_SCROLLBAR_TEMPLATE = "<div class='select2-measure-scrollbar'></div>";
-
-    $document = $(document);
-
-    nextUid=(function() { var counter=1; return function() { return counter++; }; }());
-
-    function indexOf(value, array) {
-        var i = 0, l = array.length;
-        for (; i < l; i = i + 1) {
-            if (equal(value, array[i])) return i;
-        }
-        return -1;
-    }
-
-    function measureScrollbar () {
-        var $template = $( MEASURE_SCROLLBAR_TEMPLATE );
-        $template.appendTo('body');
-
-        var dim = {
-            width: $template.width() - $template[0].clientWidth,
-            height: $template.height() - $template[0].clientHeight
-        };
-        $template.remove();
-
-        return dim;
-    }
-
-    /**
-     * Compares equality of a and b
-     * @param a
-     * @param b
-     */
-    function equal(a, b) {
-        if (a === b) return true;
-        if (a === undefined || b === undefined) return false;
-        if (a === null || b === null) return false;
-        if (a.constructor === String) return a+'' === b+''; // IE requires a+'' instead of just a
-        if (b.constructor === String) return b+'' === a+''; // IE requires b+'' instead of just b
-        return false;
-    }
-
-    /**
-     * Splits the string into an array of values, trimming each value. An empty array is returned for nulls or empty
-     * strings
-     * @param string
-     * @param separator
-     */
-    function splitVal(string, separator) {
-        var val, i, l;
-        if (string === null || string.length < 1) return [];
-        val = string.split(separator);
-        for (i = 0, l = val.length; i < l; i = i + 1) val[i] = $.trim(val[i]);
-        return val;
-    }
-
-    function getSideBorderPadding(element) {
-        return element.outerWidth(false) - element.width();
-    }
-
-    function installKeyUpChangeEvent(element) {
-        var key="keyup-change-value";
-        element.on("keydown", function () {
-            if ($.data(element, key) === undefined) {
-                $.data(element, key, element.val());
-            }
-        });
-        element.on("keyup", function () {
-            var val= $.data(element, key);
-            if (val !== undefined && element.val() !== val) {
-                $.removeData(element, key);
-                element.trigger("keyup-change");
-            }
-        });
-    }
-
-    $document.on("mousemove", function (e) {
-        lastMousePosition = {x: e.pageX, y: e.pageY};
-    });
-
-    /**
-     * filters mouse events so an event is fired only if the mouse moved.
-     *
-     * filters out mouse events that occur when mouse is stationary but
-     * the elements under the pointer are scrolled.
-     */
-    function installFilteredMouseMove(element) {
-	    element.on("mousemove", function (e) {
-            var lastpos = lastMousePosition;
-            if (lastpos === undefined || lastpos.x !== e.pageX || lastpos.y !== e.pageY) {
-                $(e.target).trigger("mousemove-filtered", e);
-            }
-        });
-    }
-
-    /**
-     * Debounces a function. Returns a function that calls the original fn function only if no invocations have been made
-     * within the last quietMillis milliseconds.
-     *
-     * @param quietMillis number of milliseconds to wait before invoking fn
-     * @param fn function to be debounced
-     * @param ctx object to be used as this reference within fn
-     * @return debounced version of fn
-     */
-    function debounce(quietMillis, fn, ctx) {
-        ctx = ctx || undefined;
-        var timeout;
-        return function () {
-            var args = arguments;
-            window.clearTimeout(timeout);
-            timeout = window.setTimeout(function() {
-                fn.apply(ctx, args);
-            }, quietMillis);
-        };
-    }
-
-    /**
-     * A simple implementation of a thunk
-     * @param formula function used to lazily initialize the thunk
-     * @return {Function}
-     */
-    function thunk(formula) {
-        var evaluated = false,
-            value;
-        return function() {
-            if (evaluated === false) { value = formula(); evaluated = true; }
-            return value;
-        };
-    };
-
-    function installDebouncedScroll(threshold, element) {
-        var notify = debounce(threshold, function (e) { element.trigger("scroll-debounced", e);});
-        element.on("scroll", function (e) {
-            if (indexOf(e.target, element.get()) >= 0) notify(e);
-        });
-    }
-
-    function focus($el) {
-        if ($el[0] === document.activeElement) return;
-
-        /* set the focus in a 0 timeout - that way the focus is set after the processing
-            of the current event has finished - which seems like the only reliable way
-            to set focus */
-        window.setTimeout(function() {
-            var el=$el[0], pos=$el.val().length, range;
-
-            $el.focus();
-
-            /* make sure el received focus so we do not error out when trying to manipulate the caret.
-                sometimes modals or others listeners may steal it after its set */
-            if ($el.is(":visible") && el === document.activeElement) {
-
-                /* after the focus is set move the caret to the end, necessary when we val()
-                    just before setting focus */
-                if(el.setSelectionRange)
-                {
-                    el.setSelectionRange(pos, pos);
-                }
-                else if (el.createTextRange) {
-                    range = el.createTextRange();
-                    range.collapse(false);
-                    range.select();
-                }
-            }
-        }, 0);
-    }
-
-    function getCursorInfo(el) {
-        el = $(el)[0];
-        var offset = 0;
-        var length = 0;
-        if ('selectionStart' in el) {
-            offset = el.selectionStart;
-            length = el.selectionEnd - offset;
-        } else if ('selection' in document) {
-            el.focus();
-            var sel = document.selection.createRange();
-            length = document.selection.createRange().text.length;
-            sel.moveStart('character', -el.value.length);
-            offset = sel.text.length - length;
-        }
-        return { offset: offset, length: length };
-    }
-
-    function killEvent(event) {
-        event.preventDefault();
-        event.stopPropagation();
-    }
-    function killEventImmediately(event) {
-        event.preventDefault();
-        event.stopImmediatePropagation();
-    }
-
-    function measureTextWidth(e) {
-        if (!sizer){
-        	var style = e[0].currentStyle || window.getComputedStyle(e[0], null);
-        	sizer = $(document.createElement("div")).css({
-	            position: "absolute",
-	            left: "-10000px",
-	            top: "-10000px",
-	            display: "none",
-	            fontSize: style.fontSize,
-	            fontFamily: style.fontFamily,
-	            fontStyle: style.fontStyle,
-	            fontWeight: style.fontWeight,
-	            letterSpacing: style.letterSpacing,
-	            textTransform: style.textTransform,
-	            whiteSpace: "nowrap"
-	        });
-            sizer.attr("class","select2-sizer");
-        	$("body").append(sizer);
-        }
-        sizer.text(e.val());
-        return sizer.width();
-    }
-
-    function syncCssClasses(dest, src, adapter) {
-        var classes, replacements = [], adapted;
-
-        classes = dest.attr("class");
-        if (classes) {
-            classes = '' + classes; // for IE which returns object
-            $(classes.split(" ")).each2(function() {
-                if (this.indexOf("select2-") === 0) {
-                    replacements.push(this);
-                }
-            });
-        }
-        classes = src.attr("class");
-        if (classes) {
-            classes = '' + classes; // for IE which returns object
-            $(classes.split(" ")).each2(function() {
-                if (this.indexOf("select2-") !== 0) {
-                    adapted = adapter(this);
-                    if (adapted) {
-                        replacements.push(this);
-                    }
-                }
-            });
-        }
-        dest.attr("class", replacements.join(" "));
-    }
-
-
-    function markMatch(text, term, markup, escapeMarkup) {
-        var match=text.toUpperCase().indexOf(term.toUpperCase()),
-            tl=term.length;
-
-        if (match<0) {
-            markup.push(escapeMarkup(text));
-            return;
-        }
-
-        markup.push(escapeMarkup(text.substring(0, match)));
-        markup.push("<span class='select2-match'>");
-        markup.push(escapeMarkup(text.substring(match, match + tl)));
-        markup.push("</span>");
-        markup.push(escapeMarkup(text.substring(match + tl, text.length)));
-    }
-
-    /**
-     * Produces an ajax-based query function
-     *
-     * @param options object containing configuration paramters
-     * @param options.params parameter map for the transport ajax call, can contain such options as cache, jsonpCallback, etc. see $.ajax
-     * @param options.transport function that will be used to execute the ajax request. must be compatible with parameters supported by $.ajax
-     * @param options.url url for the data
-     * @param options.data a function(searchTerm, pageNumber, context) that should return an object containing query string parameters for the above url.
-     * @param options.dataType request data type: ajax, jsonp, other datatatypes supported by jQuery's $.ajax function or the transport function if specified
-     * @param options.quietMillis (optional) milliseconds to wait before making the ajaxRequest, helps debounce the ajax function if invoked too often
-     * @param options.results a function(remoteData, pageNumber) that converts data returned form the remote request to the format expected by Select2.
-     *      The expected format is an object containing the following keys:
-     *      results array of objects that will be used as choices
-     *      more (optional) boolean indicating whether there are more results available
-     *      Example: {results:[{id:1, text:'Red'},{id:2, text:'Blue'}], more:true}
-     */
-    function ajax(options) {
-        var timeout, // current scheduled but not yet executed request
-            requestSequence = 0, // sequence used to drop out-of-order responses
-            handler = null,
-            quietMillis = options.quietMillis || 100,
-            ajaxUrl = options.url,
-            self = this;
-
-        return function (query) {
-            window.clearTimeout(timeout);
-            timeout = window.setTimeout(function () {
-                requestSequence += 1; // increment the sequence
-                var requestNumber = requestSequence, // this request's sequence number
-                    data = options.data, // ajax data function
-                    url = ajaxUrl, // ajax url string or function
-                    transport = options.transport || $.fn.select2.ajaxDefaults.transport,
-                    // deprecated - to be removed in 4.0  - use params instead
-                    deprecated = {
-                        type: options.type || 'GET', // set type of request (GET or POST)
-                        cache: options.cache || false,
-                        jsonpCallback: options.jsonpCallback||undefined,
-                        dataType: options.dataType||"json"
-                    },
-                    params = $.extend({}, $.fn.select2.ajaxDefaults.params, deprecated);
-
-                data = data ? data.call(self, query.term, query.page, query.context) : null;
-                url = (typeof url === 'function') ? url.call(self, query.term, query.page, query.context) : url;
-
-                if( null !== handler) { handler.abort(); }
-
-                if (options.params) {
-                    if ($.isFunction(options.params)) {
-                        $.extend(params, options.params.call(self));
-                    } else {
-                        $.extend(params, options.params);
-                    }
-                }
-
-                $.extend(params, {
-                    url: url,
-                    dataType: options.dataType,
-                    data: data,
-                    success: function (data) {
-                        if (requestNumber < requestSequence) {
-                            return;
-                        }
-                        // TODO - replace query.page with query so users have access to term, page, etc.
-                        var results = options.results(data, query.page);
-                        query.callback(results);
-                    }
-                });
-                handler = transport.call(self, params);
-            }, quietMillis);
-        };
-    }
-
-    /**
-     * Produces a query function that works with a local array
-     *
-     * @param options object containing configuration parameters. The options parameter can either be an array or an
-     * object.
-     *
-     * If the array form is used it is assumed that it contains objects with 'id' and 'text' keys.
-     *
-     * If the object form is used ti is assumed that it contains 'data' and 'text' keys. The 'data' key should contain
-     * an array of objects that will be used as choices. These objects must contain at least an 'id' key. The 'text'
-     * key can either be a String in which case it is expected that each element in the 'data' array has a key with the
-     * value of 'text' which will be used to match choices. Alternatively, text can be a function(item) that can extract
-     * the text.
-     */
-    function local(options) {
-        var data = options, // data elements
-            dataText,
-            tmp,
-            text = function (item) { return ""+item.text; }; // function used to retrieve the text portion of a data item that is matched against the search
-
-		 if ($.isArray(data)) {
-            tmp = data;
-            data = { results: tmp };
-        }
-
-		 if ($.isFunction(data) === false) {
-            tmp = data;
-            data = function() { return tmp; };
-        }
-
-        var dataItem = data();
-        if (dataItem.text) {
-            text = dataItem.text;
-            // if text is not a function we assume it to be a key name
-            if (!$.isFunction(text)) {
-                dataText = dataItem.text; // we need to store this in a separate variable because in the next step data gets reset and data.text is no longer available
-                text = function (item) { return item[dataText]; };
-            }
-        }
-
-        return function (query) {
-            var t = query.term, filtered = { results: [] }, process;
-            if (t === "") {
-                query.callback(data());
-                return;
-            }
-
-            process = function(datum, collection) {
-                var group, attr;
-                datum = datum[0];
-                if (datum.children) {
-                    group = {};
-                    for (attr in datum) {
-                        if (datum.hasOwnProperty(attr)) group[attr]=datum[attr];
-                    }
-                    group.children=[];
-                    $(datum.children).each2(function(i, childDatum) { process(childDatum, group.children); });
-                    if (group.children.length || query.matcher(t, text(group), datum)) {
-                        collection.push(group);
-                    }
-                } else {
-                    if (query.matcher(t, text(datum), datum)) {
-                        collection.push(datum);
-                    }
-                }
-            };
-
-            $(data().results).each2(function(i, datum) { process(datum, filtered.results); });
-            query.callback(filtered);
-        };
-    }
-
-    // TODO javadoc
-    function tags(data) {
-        var isFunc = $.isFunction(data);
-        return function (query) {
-            var t = query.term, filtered = {results: []};
-            $(isFunc ? data() : data).each(function () {
-                var isObject = this.text !== undefined,
-                    text = isObject ? this.text : this;
-                if (t === "" || query.matcher(t, text)) {
-                    filtered.results.push(isObject ? this : {id: this, text: this});
-                }
-            });
-            query.callback(filtered);
-        };
-    }
-
-    /**
-     * Checks if the formatter function should be used.
-     *
-     * Throws an error if it is not a function. Returns true if it should be used,
-     * false if no formatting should be performed.
-     *
-     * @param formatter
-     */
-    function checkFormatter(formatter, formatterName) {
-        if ($.isFunction(formatter)) return true;
-        if (!formatter) return false;
-        throw new Error("formatterName must be a function or a falsy value");
-    }
-
-    function evaluate(val) {
-        return $.isFunction(val) ? val() : val;
-    }
-
-    function countResults(results) {
-        var count = 0;
-        $.each(results, function(i, item) {
-            if (item.children) {
-                count += countResults(item.children);
-            } else {
-                count++;
-            }
-        });
-        return count;
-    }
-
-    /**
-     * Default tokenizer. This function uses breaks the input on substring match of any string from the
-     * opts.tokenSeparators array and uses opts.createSearchChoice to create the choice object. Both of those
-     * two options have to be defined in order for the tokenizer to work.
-     *
-     * @param input text user has typed so far or pasted into the search field
-     * @param selection currently selected choices
-     * @param selectCallback function(choice) callback tho add the choice to selection
-     * @param opts select2's opts
-     * @return undefined/null to leave the current input unchanged, or a string to change the input to the returned value
-     */
-    function defaultTokenizer(input, selection, selectCallback, opts) {
-        var original = input, // store the original so we can compare and know if we need to tell the search to update its text
-            dupe = false, // check for whether a token we extracted represents a duplicate selected choice
-            token, // token
-            index, // position at which the separator was found
-            i, l, // looping variables
-            separator; // the matched separator
-
-        if (!opts.createSearchChoice || !opts.tokenSeparators || opts.tokenSeparators.length < 1) return undefined;
-
-        while (true) {
-            index = -1;
-
-            for (i = 0, l = opts.tokenSeparators.length; i < l; i++) {
-                separator = opts.tokenSeparators[i];
-                index = input.indexOf(separator);
-                if (index >= 0) break;
-            }
-
-            if (index < 0) break; // did not find any token separator in the input string, bail
-
-            token = input.substring(0, index);
-            input = input.substring(index + separator.length);
-
-            if (token.length > 0) {
-                token = opts.createSearchChoice(token, selection);
-                if (token !== undefined && token !== null && opts.id(token) !== undefined && opts.id(token) !== null) {
-                    dupe = false;
-                    for (i = 0, l = selection.length; i < l; i++) {
-                        if (equal(opts.id(token), opts.id(selection[i]))) {
-                            dupe = true; break;
-                        }
-                    }
-
-                    if (!dupe) selectCallback(token);
-                }
-            }
-        }
-
-        if (original!==input) return input;
-    }
-
-    /**
-     * Creates a new class
-     *
-     * @param superClass
-     * @param methods
-     */
-    function clazz(SuperClass, methods) {
-        var constructor = function () {};
-        constructor.prototype = new SuperClass;
-        constructor.prototype.constructor = constructor;
-        constructor.prototype.parent = SuperClass.prototype;
-        constructor.prototype = $.extend(constructor.prototype, methods);
-        return constructor;
-    }
-
-    AbstractSelect2 = clazz(Object, {
-
-        // abstract
-        bind: function (func) {
-            var self = this;
-            return function () {
-                func.apply(self, arguments);
-            };
-        },
-
-        // abstract
-        init: function (opts) {
-            var results, search, resultsSelector = ".select2-results", disabled, readonly;
-
-            // prepare options
-            this.opts = opts = this.prepareOpts(opts);
-
-            this.id=opts.id;
-
-            // destroy if called on an existing component
-            if (opts.element.data("select2") !== undefined &&
-                opts.element.data("select2") !== null) {
-                this.destroy();
-            }
-
-            this.container = this.createContainer();
-
-            this.containerId="s2id_"+(opts.element.attr("id") || "autogen"+nextUid());
-            this.containerSelector="#"+this.containerId.replace(/([;&,\.\+\*\~':"\!\^#$%@\[\]\(\)=>\|])/g, '\\$1');
-            this.container.attr("id", this.containerId);
-
-            // cache the body so future lookups are cheap
-            this.body = thunk(function() { return opts.element.closest("body"); });
-
-            syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
-
-            this.container.css(evaluate(opts.containerCss));
-            this.container.addClass(evaluate(opts.containerCssClass));
-
-            this.elementTabIndex = this.opts.element.attr("tabindex");
-
-            // swap container for the element
-            this.opts.element
-                .data("select2", this)
-                .attr("tabindex", "-1")
-                .before(this.container);
-            this.container.data("select2", this);
-
-            this.dropdown = this.container.find(".select2-drop");
-            this.dropdown.addClass(evaluate(opts.dropdownCssClass));
-            this.dropdown.data("select2", this);
-
-            this.results = results = this.container.find(resultsSelector);
-            this.search = search = this.container.find("input.select2-input");
-
-            this.resultsPage = 0;
-            this.context = null;
-
-            // initialize the container
-            this.initContainer();
-
-            installFilteredMouseMove(this.results);
-            this.dropdown.on("mousemove-filtered touchstart touchmove touchend", resultsSelector, this.bind(this.highlightUnderEvent));
-
-            installDebouncedScroll(80, this.results);
-            this.dropdown.on("scroll-debounced", resultsSelector, this.bind(this.loadMoreIfNeeded));
-
-            // do not propagate change event from the search field out of the component
-            $(this.container).on("change", ".select2-input", function(e) {e.stopPropagation();});
-            $(this.dropdown).on("change", ".select2-input", function(e) {e.stopPropagation();});
-
-            // if jquery.mousewheel plugin is installed we can prevent out-of-bounds scrolling of results via mousewheel
-            if ($.fn.mousewheel) {
-                results.mousewheel(function (e, delta, deltaX, deltaY) {
-                    var top = results.scrollTop(), height;
-                    if (deltaY > 0 && top - deltaY <= 0) {
-                        results.scrollTop(0);
-                        killEvent(e);
-                    } else if (deltaY < 0 && results.get(0).scrollHeight - results.scrollTop() + deltaY <= results.height()) {
-                        results.scrollTop(results.get(0).scrollHeight - results.height());
-                        killEvent(e);
-                    }
-                });
-            }
-
-            installKeyUpChangeEvent(search);
-            search.on("keyup-change input paste", this.bind(this.updateResults));
-            search.on("focus", function () { search.addClass("select2-focused"); });
-            search.on("blur", function () { search.removeClass("select2-focused");});
-
-            this.dropdown.on("mouseup", resultsSelector, this.bind(function (e) {
-                if ($(e.target).closest(".select2-result-selectable").length > 0) {
-                    this.highlightUnderEvent(e);
-                    this.selectHighlighted(e);
-                }
-            }));
-
-            // trap all mouse events from leaving the dropdown. sometimes there may be a modal that is listening
-            // for mouse events outside of itself so it can close itself. since the dropdown is now outside the select2's
-            // dom it will trigger the popup close, which is not what we want
-            this.dropdown.on("click mouseup mousedown", function (e) { e.stopPropagation(); });
-
-            if ($.isFunction(this.opts.initSelection)) {
-                // initialize selection based on the current value of the source element
-                this.initSelection();
-
-                // if the user has provided a function that can set selection based on the value of the source element
-                // we monitor the change event on the element and trigger it, allowing for two way synchronization
-                this.monitorSource();
-            }
-
-            if (opts.maximumInputLength !== null) {
-                this.search.attr("maxlength", opts.maximumInputLength);
-            }
-
-            var disabled = opts.element.prop("disabled");
-            if (disabled === undefined) disabled = false;
-            this.enable(!disabled);
-
-            var readonly = opts.element.prop("readonly");
-            if (readonly === undefined) readonly = false;
-            this.readonly(readonly);
-
-            // Calculate size of scrollbar
-            scrollBarDimensions = scrollBarDimensions || measureScrollbar();
-
-            this.autofocus = opts.element.prop("autofocus")
-            opts.element.prop("autofocus", false);
-            if (this.autofocus) this.focus();
-        },
-
-        // abstract
-        destroy: function () {
-            var select2 = this.opts.element.data("select2");
-
-            if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
-
-            if (select2 !== undefined) {
-
-                select2.container.remove();
-                select2.dropdown.remove();
-                select2.opts.element
-                    .removeClass("select2-offscreen")
-                    .removeData("select2")
-                    .off(".select2")
-                    .attr({"tabindex": this.elementTabIndex})
-                    .prop("autofocus", this.autofocus||false)
-                    .show();
-            }
-        },
-
-        // abstract
-        optionToData: function(element) {
-            if (element.is("option")) {
-                return {
-                    id:element.prop("value"),
-                    text:element.text(),
-                    element: element.get(),
-                    css: element.attr("class"),
-                    disabled: element.prop("disabled"),
-                    locked: equal(element.attr("locked"), "locked")
-                };
-            } else if (element.is("optgroup")) {
-                return {
-                    text:element.attr("label"),
-                    children:[],
-                    element: element.get(),
-                    css: element.attr("class")
-                };
-            }
-        },
-
-        // abstract
-        prepareOpts: function (opts) {
-            var element, select, idKey, ajaxUrl, self = this;
-
-            element = opts.element;
-
-            if (element.get(0).tagName.toLowerCase() === "select") {
-                this.select = select = opts.element;
-            }
-
-            if (select) {
-                // these options are not allowed when attached to a select because they are picked up off the element itself
-                $.each(["id", "multiple", "ajax", "query", "createSearchChoice", "initSelection", "data", "tags"], function () {
-                    if (this in opts) {
-                        throw new Error("Option '" + this + "' is not allowed for Select2 when attached to a <select> element.");
-                    }
-                });
-            }
-
-            opts = $.extend({}, {
-                populateResults: function(container, results, query) {
-                    var populate,  data, result, children, id=this.opts.id;
-
-                    populate=function(results, container, depth) {
-
-                        var i, l, result, selectable, disabled, compound, node, label, innerContainer, formatted;
-
-                        results = opts.sortResults(results, container, query);
-
-                        for (i = 0, l = results.length; i < l; i = i + 1) {
-
-                            result=results[i];
-
-                            disabled = (result.disabled === true);
-                            selectable = (!disabled) && (id(result) !== undefined);
-
-                            compound=result.children && result.children.length > 0;
-
-                            node=$("<li></li>");
-                            node.addClass("select2-results-dept-"+depth);
-                            node.addClass("select2-result");
-                            node.addClass(selectable ? "select2-result-selectable" : "select2-result-unselectable");
-                            if (disabled) { node.addClass("select2-disabled"); }
-                            if (compound) { node.addClass("select2-result-with-children"); }
-                            node.addClass(self.opts.formatResultCssClass(result));
-
-                            label=$(document.createElement("div"));
-                            label.addClass("select2-result-label");
-
-                            formatted=opts.formatResult(result, label, query, self.opts.escapeMarkup);
-                            if (formatted!==undefined) {
-                                label.html(formatted);
-                            }
-
-                            node.append(label);
-
-                            if (compound) {
-
-                                innerContainer=$("<ul></ul>");
-                                innerContainer.addClass("select2-result-sub");
-                                populate(result.children, innerContainer, depth+1);
-                                node.append(innerContainer);
-                            }
-
-                            node.data("select2-data", result);
-                            container.append(node);
-                        }
-                    };
-
-                    populate(results, container, 0);
-                }
-            }, $.fn.select2.defaults, opts);
-
-            if (typeof(opts.id) !== "function") {
-                idKey = opts.id;
-                opts.id = function (e) { return e[idKey]; };
-            }
-
-            if ($.isArray(opts.element.data("select2Tags"))) {
-                if ("tags" in opts) {
-                    throw "tags specified as both an attribute 'data-select2-tags' and in options of Select2 " + opts.element.attr("id");
-                }
-                opts.tags=opts.element.data("select2Tags");
-            }
-
-            if (select) {
-                opts.query = this.bind(function (query) {
-                    var data = { results: [], more: false },
-                        term = query.term,
-                        children, firstChild, process;
-
-                    process=function(element, collection) {
-                        var group;
-                        if (element.is("option")) {
-                            if (query.matcher(term, element.text(), element)) {
-                                collection.push(self.optionToData(element));
-                            }
-                        } else if (element.is("optgroup")) {
-                            group=self.optionToData(element);
-                            element.children().each2(function(i, elm) { process(elm, group.children); });
-                            if (group.children.length>0) {
-                                collection.push(group);
-                            }
-                        }
-                    };
-
-                    children=element.children();
-
-                    // ignore the placeholder option if there is one
-                    if (this.getPlaceholder() !== undefined && children.length > 0) {
-                        firstChild = children[0];
-                        if ($(firstChild).text() === "") {
-                            children=children.not(firstChild);
-                        }
-                    }
-
-                    children.each2(function(i, elm) { process(elm, data.results); });
-
-                    query.callback(data);
-                });
-                // this is needed because inside val() we construct choices from options and there id is hardcoded
-                opts.id=function(e) { return e.id; };
-                opts.formatResultCssClass = function(data) { return data.css; };
-            } else {
-                if (!("query" in opts)) {
-
-                    if ("ajax" in opts) {
-                        ajaxUrl = opts.element.data("ajax-url");
-                        if (ajaxUrl && ajaxUrl.length > 0) {
-                            opts.ajax.url = ajaxUrl;
-                        }
-                        opts.query = ajax.call(opts.element, opts.ajax);
-                    } else if ("data" in opts) {
-                        opts.query = local(opts.data);
-                    } else if ("tags" in opts) {
-                        opts.query = tags(opts.tags);
-                        if (opts.createSearchChoice === undefined) {
-                            opts.createSearchChoice = function (term) { return {id: term, text: term}; };
-                        }
-                        if (opts.initSelection === undefined) {
-                            opts.initSelection = function (element, callback) {
-                                var data = [];
-                                $(splitVal(element.val(), opts.separator)).each(function () {
-                                    var id = this, text = this, tags=opts.tags;
-                                    if ($.isFunction(tags)) tags=tags();
-                                    $(tags).each(function() { if (equal(this.id, id)) { text = this.text; return false; } });
-                                    data.push({id: id, text: text});
-                                });
-
-                                callback(data);
-                            };
-                        }
-                    }
-                }
-            }
-            if (typeof(opts.query) !== "function") {
-                throw "query function not defined for Select2 " + opts.element.attr("id");
-            }
-
-            return opts;
-        },
-
-        /**
-         * Monitor the original element for changes and update select2 accordingly
-         */
-        // abstract
-        monitorSource: function () {
-            var el = this.opts.element, sync;
-
-            el.on("change.select2", this.bind(function (e) {
-                if (this.opts.element.data("select2-change-triggered") !== true) {
-                    this.initSelection();
-                }
-            }));
-
-            sync = this.bind(function () {
-
-                var enabled, readonly, self = this;
-
-                // sync enabled state
-
-                var disabled = el.prop("disabled");
-                if (disabled === undefined) disabled = false;
-                this.enable(!disabled);
-
-                var readonly = el.prop("readonly");
-                if (readonly === undefined) readonly = false;
-                this.readonly(readonly);
-
-                syncCssClasses(this.container, this.opts.element, this.opts.adaptContainerCssClass);
-                this.container.addClass(evaluate(this.opts.containerCssClass));
-
-                syncCssClasses(this.dropdown, this.opts.element, this.opts.adaptDropdownCssClass);
-                this.dropdown.addClass(evaluate(this.opts.dropdownCssClass));
-
-            });
-
-            // mozilla and IE
-            el.on("propertychange.select2 DOMAttrModified.select2", sync);
-
-
-            // hold onto a reference of the callback to work around a chromium bug
-            if (this.mutationCallback === undefined) {
-                this.mutationCallback = function (mutations) {
-                    mutations.forEach(sync);
-                }
-            }
-
-            // safari and chrome
-            if (typeof WebKitMutationObserver !== "undefined") {
-                if (this.propertyObserver) { delete this.propertyObserver; this.propertyObserver = null; }
-                this.propertyObserver = new WebKitMutationObserver(this.mutationCallback);
-                this.propertyObserver.observe(el.get(0), { attributes:true, subtree:false });
-            }
-        },
-
-        // abstract
-        triggerSelect: function(data) {
-            var evt = $.Event("select2-selecting", { val: this.id(data), object: data });
-            this.opts.element.trigger(evt);
-            return !evt.isDefaultPrevented();
-        },
-
-        /**
-         * Triggers the change event on the source element
-         */
-        // abstract
-        triggerChange: function (details) {
-
-            details = details || {};
-            details= $.extend({}, details, { type: "change", val: this.val() });
-            // prevents recursive triggering
-            this.opts.element.data("select2-change-triggered", true);
-            this.opts.element.trigger(details);
-            this.opts.element.data("select2-change-triggered", false);
-
-            // some validation frameworks ignore the change event and listen instead to keyup, click for selects
-            // so here we trigger the click event manually
-            this.opts.element.click();
-
-            // ValidationEngine ignorea the change event and listens instead to blur
-            // so here we trigger the blur event manually if so desired
-            if (this.opts.blurOnChange)
-                this.opts.element.blur();
-        },
-
-        //abstract
-        isInterfaceEnabled: function()
-        {
-            return this.enabledInterface === true;
-        },
-
-        // abstract
-        enableInterface: function() {
-            var enabled = this._enabled && !this._readonly,
-                disabled = !enabled;
-
-            if (enabled === this.enabledInterface) return false;
-
-            this.container.toggleClass("select2-container-disabled", disabled);
-            this.close();
-            this.enabledInterface = enabled;
-
-            return true;
-        },
-
-        // abstract
-        enable: function(enabled) {
-            if (enabled === undefined) enabled = true;
-            if (this._enabled === enabled) return false;
-            this._enabled = enabled;
-
-            this.opts.element.prop("disabled", !enabled);
-            this.enableInterface();
-            return true;
-        },
-
-        // abstract
-        readonly: function(enabled) {
-            if (enabled === undefined) enabled = false;
-            if (this._readonly === enabled) return false;
-            this._readonly = enabled;
-
-            this.opts.element.prop("readonly", enabled);
-            this.enableInterface();
-            return true;
-        },
-
-        // abstract
-        opened: function () {
-            return this.container.hasClass("select2-dropdown-open");
-        },
-
-        // abstract
-        positionDropdown: function() {
-            var $dropdown = this.dropdown,
-                offset = this.container.offset(),
-                height = this.container.outerHeight(false),
-                width = this.container.outerWidth(false),
-                dropHeight = $dropdown.outerHeight(false),
-	            viewPortRight = $(window).scrollLeft() + $(window).width(),
-                viewportBottom = $(window).scrollTop() + $(window).height(),
-                dropTop = offset.top + height,
-                dropLeft = offset.left,
-                enoughRoomBelow = dropTop + dropHeight <= viewportBottom,
-                enoughRoomAbove = (offset.top - dropHeight) >= this.body().scrollTop(),
-	            dropWidth = $dropdown.outerWidth(false),
-	            enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight,
-                aboveNow = $dropdown.hasClass("select2-drop-above"),
-                bodyOffset,
-                above,
-                css,
-                resultsListNode;
-
-            if (this.opts.dropdownAutoWidth) {
-                resultsListNode = $('.select2-results', $dropdown)[0];
-                $dropdown.addClass('select2-drop-auto-width');
-                $dropdown.css('width', '');
-                // Add scrollbar width to dropdown if vertical scrollbar is present
-                dropWidth = $dropdown.outerWidth(false) + (resultsListNode.scrollHeight === resultsListNode.clientHeight ? 0 : scrollBarDimensions.width);
-                dropWidth > width ? width = dropWidth : dropWidth = width;
-                enoughRoomOnRight = dropLeft + dropWidth <= viewPortRight;
-            }
-            else {
-                this.container.removeClass('select2-drop-auto-width');
-            }
-
-            //console.log("below/ droptop:", dropTop, "dropHeight", dropHeight, "sum", (dropTop+dropHeight)+" viewport bottom", viewportBottom, "enough?", enoughRoomBelow);
-            //console.log("above/ offset.top", offset.top, "dropHeight", dropHeight, "top", (offset.top-dropHeight), "scrollTop", this.body().scrollTop(), "enough?", enoughRoomAbove);
-
-            // fix positioning when body has an offset and is not position: static
-
-            if (this.body().css('position') !== 'static') {
-                bodyOffset = this.body().offset();
-                dropTop -= bodyOffset.top;
-                dropLeft -= bodyOffset.left;
-            }
-
-            // always prefer the current above/below alignment, unless there is not enough room
-
-            if (aboveNow) {
-                above = true;
-                if (!enoughRoomAbove && enoughRoomBelow) above = false;
-            } else {
-                above = false;
-                if (!enoughRoomBelow && enoughRoomAbove) above = true;
-            }
-
-            if (!enoughRoomOnRight) {
-               dropLeft = offset.left + width - dropWidth;
-            }
-
-            if (above) {
-                dropTop = offset.top - dropHeight;
-                this.container.addClass("select2-drop-above");
-                $dropdown.addClass("select2-drop-above");
-            }
-            else {
-                this.container.removeClass("select2-drop-above");
-                $dropdown.removeClass("select2-drop-above");
-            }
-
-            css = $.extend({
-                top: dropTop,
-                left: dropLeft,
-                width: width
-            }, evaluate(this.opts.dropdownCss));
-
-            $dropdown.css(css);
-        },
-
-        // abstract
-        shouldOpen: function() {
-            var event;
-
-            if (this.opened()) return false;
-
-            if (this._enabled === false || this._readonly === true) return false;
-
-            event = $.Event("select2-opening");
-            this.opts.element.trigger(event);
-            return !event.isDefaultPrevented();
-        },
-
-        // abstract
-        clearDropdownAlignmentPreference: function() {
-            // clear the classes used to figure out the preference of where the dropdown should be opened
-            this.container.removeClass("select2-drop-above");
-            this.dropdown.removeClass("select2-drop-above");
-        },
-
-        /**
-         * Opens the dropdown
-         *
-         * @return {Boolean} whether or not dropdown was opened. This method will return false if, for example,
-         * the dropdown is already open, or if the 'open' event listener on the element called preventDefault().
-         */
-        // abstract
-        open: function () {
-
-            if (!this.shouldOpen()) return false;
-
-            this.opening();
-
-            return true;
-        },
-
-        /**
-         * Performs the opening of the dropdown
-         */
-        // abstract
-        opening: function() {
-            var cid = this.containerId,
-                scroll = "scroll." + cid,
-                resize = "resize."+cid,
-                orient = "orientationchange."+cid,
-                mask;
-
-            this.container.addClass("select2-dropdown-open").addClass("select2-container-active");
-
-            this.clearDropdownAlignmentPreference();
-
-            if(this.dropdown[0] !== this.body().children().last()[0]) {
-                this.dropdown.detach().appendTo(this.body());
-            }
-
-            // create the dropdown mask if doesnt already exist
-            mask = $("#select2-drop-mask");
-            if (mask.length == 0) {
-                mask = $(document.createElement("div"));
-                mask.attr("id","select2-drop-mask").attr("class","select2-drop-mask");
-                mask.hide();
-                mask.appendTo(this.body());
-                mask.on("mousedown touchstart", function (e) {
-                    var dropdown = $("#select2-drop"), self;
-                    if (dropdown.length > 0) {
-                        self=dropdown.data("select2");
-                        if (self.opts.selectOnBlur) {
-                            self.selectHighlighted({noFocus: true});
-                        }
-                        self.close();
-                        e.preventDefault();
-                        e.stopPropagation();
-                    }
-                });
-            }
-
-            // ensure the mask is always right before the dropdown
-            if (this.dropdown.prev()[0] !== mask[0]) {
-                this.dropdown.before(mask);
-            }
-
-            // move the global id to the correct dropdown
-            $("#select2-drop").removeAttr("id");
-            this.dropdown.attr("id", "select2-drop");
-
-            // show the elements
-            mask.css(_makeMaskCss());
-            mask.show();
-            this.dropdown.show();
-            this.positionDropdown();
-
-            this.dropdown.addClass("select2-drop-active");
-            this.ensureHighlightVisible();
-
-            // attach listeners to events that can change the position of the container and thus require
-            // the position of the dropdown to be updated as well so it does not come unglued from the container
-            var that = this;
-            this.container.parents().add(window).each(function () {
-                $(this).on(resize+" "+scroll+" "+orient, function (e) {
-                    $("#select2-drop-mask").css(_makeMaskCss());
-                    that.positionDropdown();
-                });
-            });
-
-            function _makeMaskCss() {
-                return {
-                    width  : Math.max(document.documentElement.scrollWidth,  $(window).width()),
-                    height : Math.max(document.documentElement.scrollHeight, $(window).height())
-                }
-            }
-        },
-
-        // abstract
-        close: function () {
-            if (!this.opened()) return;
-
-            var cid = this.containerId,
-                scroll = "scroll." + cid,
-                resize = "resize."+cid,
-                orient = "orientationchange."+cid;
-
-            // unbind event listeners
-            this.container.parents().add(window).each(function () { $(this).off(scroll).off(resize).off(orient); });
-
-            this.clearDropdownAlignmentPreference();
-
-            $("#select2-drop-mask").hide();
-            this.dropdown.removeAttr("id"); // only the active dropdown has the select2-drop id
-            this.dropdown.hide();
-            this.container.removeClass("select2-dropdown-open");
-            this.results.empty();
-
-
-            this.clearSearch();
-            this.search.removeClass("select2-active");
-            this.opts.element.trigger($.Event("select2-close"));
-        },
-
-        // abstract
-        clearSearch: function () {
-
-        },
-
-        //abstract
-        getMaximumSelectionSize: function() {
-            return evaluate(this.opts.maximumSelectionSize);
-        },
-
-        // abstract
-        ensureHighlightVisible: function () {
-            var results = this.results, children, index, child, hb, rb, y, more;
-
-            index = this.highlight();
-
-            if (index < 0) return;
-
-            if (index == 0) {
-
-                // if the first element is highlighted scroll all the way to the top,
-                // that way any unselectable headers above it will also be scrolled
-                // into view
-
-                results.scrollTop(0);
-                return;
-            }
-
-            children = this.findHighlightableChoices().find('.select2-result-label');
-
-            child = $(children[index]);
-
-            hb = child.offset().top + child.outerHeight(true);
-
-            // if this is the last child lets also make sure select2-more-results is visible
-            if (index === children.length - 1) {
-                more = results.find("li.select2-more-results");
-                if (more.length > 0) {
-                    hb = more.offset().top + more.outerHeight(true);
-                }
-            }
-
-            rb = results.offset().top + results.outerHeight(true);
-            if (hb > rb) {
-                results.scrollTop(results.scrollTop() + (hb - rb));
-            }
-            y = child.offset().top - results.offset().top;
-
-            // make sure the top of the element is visible
-            if (y < 0 && child.css('display') != 'none' ) {
-                results.scrollTop(results.scrollTop() + y); // y is negative
-            }
-        },
-
-        // abstract
-        findHighlightableChoices: function() {
-            return this.results.find(".select2-result-selectable:not(.select2-selected):not(.select2-disabled)");
-        },
-
-        // abstract
-        moveHighlight: function (delta) {
-            var choices = this.findHighlightableChoices(),
-                index = this.highlight();
-
-            while (index > -1 && index < choices.length) {
-                index += delta;
-                var choice = $(choices[index]);
-                if (choice.hasClass("select2-result-selectable") && !choice.hasClass("select2-disabled") && !choice.hasClass("select2-selected")) {
-                    this.highlight(index);
-                    break;
-                }
-            }
-        },
-
-        // abstract
-        highlight: function (index) {
-            var choices = this.findHighlightableChoices(),
-                choice,
-                data;
-
-            if (arguments.length === 0) {
-                return indexOf(choices.filter(".select2-highlighted")[0], choices.get());
-            }
-
-            if (index >= choices.length) index = choices.length - 1;
-            if (index < 0) index = 0;
-
-            this.results.find(".select2-highlighted").removeClass("select2-highlighted");
-
-            choice = $(choices[index]);
-            choice.addClass("select2-highlighted");
-
-            this.ensureHighlightVisible();
-
-            data = choice.data("select2-data");
-            if (data) {
-                this.opts.element.trigger({ type: "select2-highlight", val: this.id(data), choice: data });
-            }
-        },
-
-        // abstract
-        countSelectableResults: function() {
-            return this.findHighlightableChoices().length;
-        },
-
-        // abstract
-        highlightUnderEvent: function (event) {
-            var el = $(event.target).closest(".select2-result-selectable");
-            if (el.length > 0 && !el.is(".select2-highlighted")) {
-        		var choices = this.findHighlightableChoices();
-                this.highlight(choices.index(el));
-            } else if (el.length == 0) {
-                // if we are over an unselectable item remove al highlights
-                this.results.find(".select2-highlighted").removeClass("select2-highlighted");
-            }
-        },
-
-        // abstract
-        loadMoreIfNeeded: function () {
-            var results = this.results,
-                more = results.find("li.select2-more-results"),
-                below, // pixels the element is below the scroll fold, below==0 is when the element is starting to be visible
-                offset = -1, // index of first element without data
-                page = this.resultsPage + 1,
-                self=this,
-                term=this.search.val(),
-                context=this.context;
-
-            if (more.length === 0) return;
-            below = more.offset().top - results.offset().top - results.height();
-
-            if (below <= this.opts.loadMorePadding) {
-                more.addClass("select2-active");
-                this.opts.query({
-                        element: this.opts.element,
-                        term: term,
-                        page: page,
-                        context: context,
-                        matcher: this.opts.matcher,
-                        callback: this.bind(function (data) {
-
-                    // ignore a response if the select2 has been closed before it was received
-                    if (!self.opened()) return;
-
-
-                    self.opts.populateResults.call(this, results, data.results, {term: term, page: page, context:context});
-                    self.postprocessResults(data, false, false);
-
-                    if (data.more===true) {
-                        more.detach().appendTo(results).text(self.opts.formatLoadMore(page+1));
-                        window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
-                    } else {
-                        more.remove();
-                    }
-                    self.positionDropdown();
-                    self.resultsPage = page;
-                    self.context = data.context;
-                })});
-            }
-        },
-
-        /**
-         * Default tokenizer function which does nothing
-         */
-        tokenize: function() {
-
-        },
-
-        /**
-         * @param initial whether or not this is the call to this method right after the dropdown has been opened
-         */
-        // abstract
-        updateResults: function (initial) {
-            var search = this.search,
-                results = this.results,
-                opts = this.opts,
-                data,
-                self = this,
-                input,
-                term = search.val(),
-                lastTerm=$.data(this.container, "select2-last-term");
-
-            // prevent duplicate queries against the same term
-            if (initial !== true && lastTerm && equal(term, lastTerm)) return;
-
-            $.data(this.container, "select2-last-term", term);
-
-            // if the search is currently hidden we do not alter the results
-            if (initial !== true && (this.showSearchInput === false || !this.opened())) {
-                return;
-            }
-
-            function postRender() {
-                results.scrollTop(0);
-                search.removeClass("select2-active");
-                self.positionDropdown();
-            }
-
-            function render(html) {
-                results.html(html);
-                postRender();
-            }
-
-            var maxSelSize = this.getMaximumSelectionSize();
-            if (maxSelSize >=1) {
-                data = this.data();
-                if ($.isArray(data) && data.length >= maxSelSize && checkFormatter(opts.formatSelectionTooBig, "formatSelectionTooBig")) {
-            	    render("<li class='select2-selection-limit'>" + opts.formatSelectionTooBig(maxSelSize) + "</li>");
-            	    return;
-                }
-            }
-
-            if (search.val().length < opts.minimumInputLength) {
-                if (checkFormatter(opts.formatInputTooShort, "formatInputTooShort")) {
-                    render("<li class='select2-no-results'>" + opts.formatInputTooShort(search.val(), opts.minimumInputLength) + "</li>");
-                } else {
-                    render("");
-                }
-                if (initial) this.showSearch(true);
-                return;
-            }
-
-            if (opts.maximumInputLength && search.val().length > opts.maximumInputLength) {
-                if (checkFormatter(opts.formatInputTooLong, "formatInputTooLong")) {
-                    render("<li class='select2-no-results'>" + opts.formatInputTooLong(search.val(), opts.maximumInputLength) + "</li>");
-                } else {
-                    render("");
-                }
-                return;
-            }
-
-            if (opts.formatSearching && this.findHighlightableChoices().length === 0) {
-                render("<li class='select2-searching'>" + opts.formatSearching() + "</li>");
-            }
-
-            search.addClass("select2-active");
-
-            // give the tokenizer a chance to pre-process the input
-            input = this.tokenize();
-            if (input != undefined && input != null) {
-                search.val(input);
-            }
-
-            this.resultsPage = 1;
-
-            opts.query({
-                element: opts.element,
-                    term: search.val(),
-                    page: this.resultsPage,
-                    context: null,
-                    matcher: opts.matcher,
-                    callback: this.bind(function (data) {
-                var def; // default choice
-
-                // ignore a response if the select2 has been closed before it was received
-                if (!this.opened()) {
-                    this.search.removeClass("select2-active");
-                    return;
-                }
-
-                // save context, if any
-                this.context = (data.context===undefined) ? null : data.context;
-                // create a default choice and prepend it to the list
-                if (this.opts.createSearchChoice && search.val() !== "") {
-                    def = this.opts.createSearchChoice.call(null, search.val(), data.results);
-                    if (def !== undefined && def !== null && self.id(def) !== undefined && self.id(def) !== null) {
-                        if ($(data.results).filter(
-                            function () {
-                                return equal(self.id(this), self.id(def));
-                            }).length === 0) {
-                            data.results.unshift(def);
-                        }
-                    }
-                }
-
-                if (data.results.length === 0 && checkFormatter(opts.formatNoMatches, "formatNoMatches")) {
-                    render("<li class='select2-no-results'>" + opts.formatNoMatches(search.val()) + "</li>");
-                    return;
-                }
-
-                results.empty();
-                self.opts.populateResults.call(this, results, data.results, {term: search.val(), page: this.resultsPage, context:null});
-
-                if (data.more === true && checkFormatter(opts.formatLoadMore, "formatLoadMore")) {
-                    results.append("<li class='select2-more-results'>" + self.opts.escapeMarkup(opts.formatLoadMore(this.resultsPage)) + "</li>");
-                    window.setTimeout(function() { self.loadMoreIfNeeded(); }, 10);
-                }
-
-                this.postprocessResults(data, initial);
-
-                postRender();
-
-                this.opts.element.trigger({ type: "select2-loaded", data:data });
-            })});
-        },
-
-        // abstract
-        cancel: function () {
-            this.close();
-        },
-
-        // abstract
-        blur: function () {
-            // if selectOnBlur == true, select the currently highlighted option
-            if (this.opts.selectOnBlur)
-                this.selectHighlighted({noFocus: true});
-
-            this.close();
-            this.container.removeClass("select2-container-active");
-            // synonymous to .is(':focus'), which is available in jquery >= 1.6
-            if (this.search[0] === document.activeElement) { this.search.blur(); }
-            this.clearSearch();
-            this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
-        },
-
-        // abstract
-        focusSearch: function () {
-            focus(this.search);
-        },
-
-        // abstract
-        selectHighlighted: function (options) {
-            var index=this.highlight(),
-                highlighted=this.results.find(".select2-highlighted"),
-                data = highlighted.closest('.select2-result').data("select2-data");
-
-            if (data) {
-                this.highlight(index);
-                this.onSelect(data, options);
-            }
-        },
-
-        // abstract
-        getPlaceholder: function () {
-            return this.opts.element.attr("placeholder") ||
-                this.opts.element.attr("data-placeholder") || // jquery 1.4 compat
-                this.opts.element.data("placeholder") ||
-                this.opts.placeholder;
-        },
-
-        /**
-         * Get the desired width for the container element.  This is
-         * derived first from option `width` passed to select2, then
-         * the inline 'style' on the original element, and finally
-         * falls back to the jQuery calculated element width.
-         */
-        // abstract
-        initContainerWidth: function () {
-            function resolveContainerWidth() {
-                var style, attrs, matches, i, l;
-
-                if (this.opts.width === "off") {
-                    return null;
-                } else if (this.opts.width === "element"){
-                    return this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px';
-                } else if (this.opts.width === "copy" || this.opts.width === "resolve") {
-                    // check if there is inline style on the element that contains width
-                    style = this.opts.element.attr('style');
-                    if (style !== undefined) {
-                        attrs = style.split(';');
-                        for (i = 0, l = attrs.length; i < l; i = i + 1) {
-                            matches = attrs[i].replace(/\s/g, '')
-                                .match(/width:(([-+]?([0-9]*\.)?[0-9]+)(px|em|ex|%|in|cm|mm|pt|pc))/i);
-                            if (matches !== null && matches.length >= 1)
-                                return matches[1];
-                        }
-                    }
-
-                    // next check if css('width') can resolve a width that is percent based, this is sometimes possible
-                    // when attached to input type=hidden or elements hidden via css
-                    style = this.opts.element.css('width');
-                    if (style && style.length > 0) return style;
-
-                    if (this.opts.width === "resolve") {
-                        // finally, fallback on the calculated width of the element
-                        return (this.opts.element.outerWidth(false) === 0 ? 'auto' : this.opts.element.outerWidth(false) + 'px');
-                    }
-
-                    return null;
-                } else if ($.isFunction(this.opts.width)) {
-                    return this.opts.width();
-                } else {
-                    return this.opts.width;
-               }
-            };
-
-            var width = resolveContainerWidth.call(this);
-            if (width !== null) {
-                this.container.css("width", width);
-            }
-        }
-    });
-
-    SingleSelect2 = clazz(AbstractSelect2, {
-
-        // single
-
-		createContainer: function () {
-            var container = $(document.createElement("div")).attr({
-                "class": "select2-container"
-            }).html([
-                "<a href='javascript:void(0)' onclick='return false;' class='select2-choice' tabindex='-1'>",
-                "   <span>&nbsp;</span><abbr class='select2-search-choice-close'></abbr>",
-                "   <div><b></b></div>" ,
-                "</a>",
-                "<input class='select2-focusser select2-offscreen' type='text'/>",
-                "<div class='select2-drop select2-display-none'>" ,
-                "   <div class='select2-search'>" ,
-                "       <input type='text' autocomplete='off' autocorrect='off' autocapitilize='off' spellcheck='false' class='select2-input'/>" ,
-                "   </div>" ,
-                "   <ul class='select2-results'>" ,
-                "   </ul>" ,
-                "</div>"].join(""));
-            return container;
-        },
-
-        // single
-        enableInterface: function() {
-            if (this.parent.enableInterface.apply(this, arguments)) {
-                this.focusser.prop("disabled", !this.isInterfaceEnabled());
-            }
-        },
-
-        // single
-        opening: function () {
-            var el, range;
-            this.parent.opening.apply(this, arguments);
-            if (this.showSearchInput !== false) {
-                // IE appends focusser.val() at the end of field :/ so we manually insert it at the beginning using a range
-                // all other browsers handle this just fine
-
-                this.search.val(this.focusser.val());
-            }
-            this.search.focus();
-            // in IE we have to move the cursor to the end after focussing, otherwise it will be at the beginning and
-            // new text will appear *before* focusser.val()
-            el = this.search.get(0);
-            if (el.createTextRange) {
-                range = el.createTextRange();
-                range.collapse(false);
-                range.select();
-            }
-
-            this.focusser.prop("disabled", true).val("");
-            this.updateResults(true);
-            this.opts.element.trigger($.Event("select2-open"));
-        },
-
-        // single
-        close: function () {
-            if (!this.opened()) return;
-            this.parent.close.apply(this, arguments);
-            this.focusser.removeAttr("disabled");
-            this.focusser.focus();
-        },
-
-        // single
-        focus: function () {
-            if (this.opened()) {
-                this.close();
-            } else {
-                this.focusser.removeAttr("disabled");
-                this.focusser.focus();
-            }
-        },
-
-        // single
-        isFocused: function () {
-            return this.container.hasClass("select2-container-active");
-        },
-
-        // single
-        cancel: function () {
-            this.parent.cancel.apply(this, arguments);
-            this.focusser.removeAttr("disabled");
-            this.focusser.focus();
-        },
-
-        // single
-        initContainer: function () {
-
-            var selection,
-                container = this.container,
-                dropdown = this.dropdown;
-
-            this.showSearch(false);
-
-            this.selection = selection = container.find(".select2-choice");
-
-            this.focusser = container.find(".select2-focusser");
-
-            // rewrite labels from original element to focusser
-            this.focusser.attr("id", "s2id_autogen"+nextUid());
-
-            $("label[for='" + this.opts.element.attr("id") + "']")
-                .attr('for', this.focusser.attr('id'));
-
-            this.focusser.attr("tabindex", this.elementTabIndex);
-
-            this.search.on("keydown", this.bind(function (e) {
-                if (!this.isInterfaceEnabled()) return;
-
-                if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
-                    // prevent the page from scrolling
-                    killEvent(e);
-                    return;
-                }
-
-                switch (e.which) {
-                    case KEY.UP:
-                    case KEY.DOWN:
-                        this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
-                        killEvent(e);
-                        return;
-                    case KEY.ENTER:
-                        this.selectHighlighted();
-                        killEvent(e);
-                        return;
-                    case KEY.TAB:
-                        this.selectHighlighted({noFocus: true});
-                        return;
-                    case KEY.ESC:
-                        this.cancel(e);
-                        killEvent(e);
-                        return;
-                }
-            }));
-
-            this.search.on("blur", this.bind(function(e) {
-                // a workaround for chrome to keep the search field focussed when the scroll bar is used to scroll the dropdown.
-                // without this the search field loses focus which is annoying
-                if (document.activeElement === this.body().get(0)) {
-                    window.setTimeout(this.bind(function() {
-                        this.search.focus();
-                    }), 0);
-                }
-            }));
-
-            this.focusser.on("keydown", this.bind(function (e) {
-                if (!this.isInterfaceEnabled()) return;
-
-                if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e) || e.which === KEY.ESC) {
-                    return;
-                }
-
-                if (this.opts.openOnEnter === false && e.which === KEY.ENTER) {
-                    killEvent(e);
-                    return;
-                }
-
-                if (e.which == KEY.DOWN || e.which == KEY.UP
-                    || (e.which == KEY.ENTER && this.opts.openOnEnter)) {
-                    this.open();
-                    killEvent(e);
-                    return;
-                }
-
-                if (e.which == KEY.DELETE || e.which == KEY.BACKSPACE) {
-                    if (this.opts.allowClear) {
-                        this.clear();
-                    }
-                    killEvent(e);
-                    return;
-                }
-            }));
-
-
-            installKeyUpChangeEvent(this.focusser);
-            this.focusser.on("keyup-change input", this.bind(function(e) {
-                e.stopPropagation();
-                if (this.opened()) return;
-                this.open();
-            }));
-
-            selection.on("mousedown", "abbr", this.bind(function (e) {
-                if (!this.isInterfaceEnabled()) return;
-                this.clear();
-                killEventImmediately(e);
-                this.close();
-                this.selection.focus();
-            }));
-
-            selection.on("mousedown", this.bind(function (e) {
-
-                if (!this.container.hasClass("select2-container-active")) {
-                    this.opts.element.trigger($.Event("select2-focus"));
-                }
-
-                if (this.opened()) {
-                    this.close();
-                } else if (this.isInterfaceEnabled()) {
-                    this.open();
-                }
-
-                killEvent(e);
-            }));
-
-            dropdown.on("mousedown", this.bind(function() { this.search.focus(); }));
-
-            selection.on("focus", this.bind(function(e) {
-                killEvent(e);
-            }));
-
-            this.focusser.on("focus", this.bind(function(){
-                if (!this.container.hasClass("select2-container-active")) {
-                    this.opts.element.trigger($.Event("select2-focus"));
-                }
-                this.container.addClass("select2-container-active");
-            })).on("blur", this.bind(function() {
-                if (!this.opened()) {
-                    this.container.removeClass("select2-container-active");
-                    this.opts.element.trigger($.Event("select2-blur"));
-                }
-            }));
-            this.search.on("focus", this.bind(function(){
-                if (!this.container.hasClass("select2-container-active")) {
-                    this.opts.element.trigger($.Event("select2-focus"));
-                }
-                this.container.addClass("select2-container-active");
-            }));
-
-            this.initContainerWidth();
-            this.opts.element.addClass("select2-offscreen");
-            this.setPlaceholder();
-
-        },
-
-        // single
-        clear: function(triggerChange) {
-            var data=this.selection.data("select2-data");
-            if (data) { // guard against queued quick consecutive clicks
-                this.opts.element.val("");
-                this.selection.find("span").empty();
-                this.selection.removeData("select2-data");
-                this.setPlaceholder();
-
-                if (triggerChange !== false){
-                    this.opts.element.trigger({ type: "select2-removed", val: this.id(data), choice: data });
-                    this.triggerChange({removed:data});
-                }
-            }
-        },
-
-        /**
-         * Sets selection based on source element's value
-         */
-        // single
-        initSelection: function () {
-            var selected;
-            if (this.opts.element.val() === "" && this.opts.element.text() === "") {
-                this.updateSelection([]);
-                this.close();
-                this.setPlaceholder();
-            } else {
-                var self = this;
-                this.opts.initSelection.call(null, this.opts.element, function(selected){
-                    if (selected !== undefined && selected !== null) {
-                        self.updateSelection(selected);
-                        self.close();
-                        self.setPlaceholder();
-                    }
-                });
-            }
-        },
-
-        // single
-        prepareOpts: function () {
-            var opts = this.parent.prepareOpts.apply(this, arguments),
-                self=this;
-
-            if (opts.element.get(0).tagName.toLowerCase() === "select") {
-                // install the selection initializer
-                opts.initSelection = function (element, callback) {
-                    var selected = element.find(":selected");
-                    // a single select box always has a value, no need to null check 'selected'
-                    callback(self.optionToData(selected));
-                };
-            } else if ("data" in opts) {
-                // install default initSelection when applied to hidden input and data is local
-                opts.initSelection = opts.initSelection || function (element, callback) {
-                    var id = element.val();
-                    //search in data by id, storing the actual matching item
-                    var match = null;
-                    opts.query({
-                        matcher: function(term, text, el){
-                            var is_match = equal(id, opts.id(el));
-                            if (is_match) {
-                                match = el;
-                            }
-                            return is_match;
-                        },
-                        callback: !$.isFunction(callback) ? $.noop : function() {
-                            callback(match);
-                        }
-                    });
-                };
-            }
-
-            return opts;
-        },
-
-        // single
-        getPlaceholder: function() {
-            // if a placeholder is specified on a single select without the first empty option ignore it
-            if (this.select) {
-                if (this.select.find("option").first().text() !== "") {
-                    return undefined;
-                }
-            }
-
-            return this.parent.getPlaceholder.apply(this, arguments);
-        },
-
-        // single
-        setPlaceholder: function () {
-            var placeholder = this.getPlaceholder();
-
-            if (this.opts.element.val() === "" && placeholder !== undefined) {
-
-                // check for a first blank option if attached to a select
-                if (this.select && this.select.find("option:first").text() !== "") return;
-
-                this.selection.find("span").html(this.opts.escapeMarkup(placeholder));
-
-                this.selection.addClass("select2-default");
-
-                this.container.removeClass("select2-allowclear");
-            }
-        },
-
-        // single
-        postprocessResults: function (data, initial, noHighlightUpdate) {
-            var selected = 0, self = this, showSearchInput = true;
-
-            // find the selected element in the result list
-
-            this.findHighlightableChoices().each2(function (i, elm) {
-                if (equal(self.id(elm.data("select2-data")), self.opts.element.val())) {
-                    selected = i;
-                    return false;
-                }
-            });
-
-            // and highlight it
-            if (noHighlightUpdate !== false) {
-                this.highlight(selected);
-            }
-
-            // show the search box if this is the first we got the results and there are enough of them for search
-
-            if (initial === true && this.showSearchInput === false) {
-                var min=this.opts.minimumResultsForSearch;
-                if (min>=0) {
-                    this.showSearch(countResults(data.results)>=min);
-                }
-            }
-
-        },
-
-        // single
-        showSearch: function(showSearchInput) {
-            this.showSearchInput = showSearchInput;
-
-            this.dropdown.find(".select2-search").toggleClass("select2-search-hidden", !showSearchInput);
-            this.dropdown.find(".select2-search").toggleClass("select2-offscreen", !showSearchInput);
-            //add "select2-with-searchbox" to the container if search box is shown
-            $(this.dropdown, this.container).toggleClass("select2-with-searchbox", showSearchInput);
-        },
-
-        // single
-        onSelect: function (data, options) {
-
-            if (!this.triggerSelect(data)) { return; }
-
-            var old = this.opts.element.val(),
-                oldData = this.data();
-
-            this.opts.element.val(this.id(data));
-            this.updateSelection(data);
-
-            this.opts.element.trigger({ type: "select2-selected", val: this.id(data), choice: data });
-
-            this.close();
-
-            if (!options || !options.noFocus)
-                this.selection.focus();
-
-            if (!equal(old, this.id(data))) { this.triggerChange({added:data,removed:oldData}); }
-        },
-
-        // single
-        updateSelection: function (data) {
-
-            var container=this.selection.find("span"), formatted;
-
-            this.selection.data("select2-data", data);
-
-            container.empty();
-            formatted=this.opts.formatSelection(data, container);
-            if (formatted !== undefined) {
-                container.append(this.opts.escapeMarkup(formatted));
-            }
-
-            this.selection.removeClass("select2-default");
-
-            if (this.opts.allowClear && this.getPlaceholder() !== undefined) {
-                this.container.addClass("select2-allowclear");
-            }
-        },
-
-        // single
-        val: function () {
-            var val,
-                triggerChange = false,
-                data = null,
-                self = this,
-                oldData = this.data();
-
-            if (arguments.length === 0) {
-                return this.opts.element.val();
-            }
-
-            val = arguments[0];
-
-            if (arguments.length > 1) {
-                triggerChange = arguments[1];
-            }
-
-            if (this.select) {
-                this.select
-                    .val(val)
-                    .find(":selected").each2(function (i, elm) {
-                        data = self.optionToData(elm);
-                        return false;
-                    });
-                this.updateSelection(data);
-                this.setPlaceholder();
-                if (triggerChange) {
-                    this.triggerChange({added: data, removed:oldData});
-                }
-            } else {
-                if (this.opts.initSelection === undefined) {
-                    throw new Error("cannot call val() if initSelection() is not defined");
-                }
-                // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
-                if (!val && val !== 0) {
-                    this.clear(triggerChange);
-                    return;
-                }
-                this.opts.element.val(val);
-                this.opts.initSelection(this.opts.element, function(data){
-                    self.opts.element.val(!data ? "" : self.id(data));
-                    self.updateSelection(data);
-                    self.setPlaceholder();
-                    if (triggerChange) {
-                        self.triggerChange({added: data, removed:oldData});
-                    }
-                });
-            }
-        },
-
-        // single
-        clearSearch: function () {
-            this.search.val("");
-            this.focusser.val("");
-        },
-
-        // single
-        data: function(value, triggerChange) {
-            var data;
-
-            if (arguments.length === 0) {
-                data = this.selection.data("select2-data");
-                if (data == undefined) data = null;
-                return data;
-            } else {
-                if (!value || value === "") {
-                    this.clear(triggerChange);
-                } else {
-                    data = this.data();
-                    this.opts.element.val(!value ? "" : this.id(value));
-                    this.updateSelection(value);
-                    if (triggerChange) {
-                        this.triggerChange({added: value, removed:data});
-                    }
-                }
-            }
-        }
-    });
-
-    MultiSelect2 = clazz(AbstractSelect2, {
-
-        // multi
-        createContainer: function () {
-            var container = $(document.createElement("div")).attr({
-                "class": "select2-container select2-container-multi"
-            }).html([
-                "    <ul class='select2-choices'>",
-                //"<li class='select2-search-choice'><span>California</span><a href="javascript:void(0)" class="select2-search-choice-close"></a></li>" ,
-                "  <li class='select2-search-field'>" ,
-                "    <input type='text' autocomplete='off' autocorrect='off' autocapitilize='off' spellcheck='false' class='select2-input'>" ,
-                "  </li>" ,
-                "</ul>" ,
-                "<div class='select2-drop select2-drop-multi select2-display-none'>" ,
-                "   <ul class='select2-results'>" ,
-                "   </ul>" ,
-                "</div>"].join(""));
-			return container;
-        },
-
-        // multi
-        prepareOpts: function () {
-            var opts = this.parent.prepareOpts.apply(this, arguments),
-                self=this;
-
-            // TODO validate placeholder is a string if specified
-
-            if (opts.element.get(0).tagName.toLowerCase() === "select") {
-                // install sthe selection initializer
-                opts.initSelection = function (element, callback) {
-
-                    var data = [];
-
-                    element.find(":selected").each2(function (i, elm) {
-                        data.push(self.optionToData(elm));
-                    });
-                    callback(data);
-                };
-            } else if ("data" in opts) {
-                // install default initSelection when applied to hidden input and data is local
-                opts.initSelection = opts.initSelection || function (element, callback) {
-                    var ids = splitVal(element.val(), opts.separator);
-                    //search in data by array of ids, storing matching items in a list
-                    var matches = [];
-                    opts.query({
-                        matcher: function(term, text, el){
-                            var is_match = $.grep(ids, function(id) {
-                                return equal(id, opts.id(el));
-                            }).length;
-                            if (is_match) {
-                                matches.push(el);
-                            }
-                            return is_match;
-                        },
-                        callback: !$.isFunction(callback) ? $.noop : function() {
-                            // reorder matches based on the order they appear in the ids array because right now
-                            // they are in the order in which they appear in data array
-                            var ordered = [];
-                            for (var i = 0; i < ids.length; i++) {
-                                var id = ids[i];
-                                for (var j = 0; j < matches.length; j++) {
-                                    var match = matches[j];
-                                    if (equal(id, opts.id(match))) {
-                                        ordered.push(match);
-                                        matches.splice(j, 1);
-                                        break;
-                                    }
-                                }
-                            }
-                            callback(ordered);
-                        }
-                    });
-                };
-            }
-
-            return opts;
-        },
-
-        selectChoice: function (choice) {
-
-            var selected = this.container.find(".select2-search-choice-focus");
-            if (selected.length && choice && choice[0] == selected[0]) {
-
-            } else {
-                if (selected.length) {
-                    this.opts.element.trigger("choice-deselected", selected);
-                }
-                selected.removeClass("select2-search-choice-focus");
-                if (choice && choice.length) {
-                    this.close();
-                    choice.addClass("select2-search-choice-focus");
-                    this.opts.element.trigger("choice-selected", choice);
-                }
-            }
-        },
-
-        // multi
-        initContainer: function () {
-
-            var selector = ".select2-choices", selection;
-
-            this.searchContainer = this.container.find(".select2-search-field");
-            this.selection = selection = this.container.find(selector);
-
-            var _this = this;
-            this.selection.on("mousedown", ".select2-search-choice", function (e) {
-                //killEvent(e);
-                _this.search[0].focus();
-                _this.selectChoice($(this));
-            })
-            //.sortable({
-            //    items: " > li",
-            //    tolerance: "pointer",
-            //    revert: 100
-            //});
-
-            // rewrite labels from original element to focusser
-            this.search.attr("id", "s2id_autogen"+nextUid());
-            $("label[for='" + this.opts.element.attr("id") + "']")
-                .attr('for', this.search.attr('id'));
-
-            this.search.on("input paste", this.bind(function() {
-                if (!this.isInterfaceEnabled()) return;
-                if (!this.opened()) {
-                    this.open();
-                }
-            }));
-
-            this.search.attr("tabindex", this.elementTabIndex);
-
-            this.keydowns = 0;
-            this.search.on("keydown", this.bind(function (e) {
-                if (!this.isInterfaceEnabled()) return;
-
-                ++this.keydowns;
-                var selected = selection.find(".select2-search-choice-focus");
-                var prev = selected.prev(".select2-search-choice:not(.select2-locked)");
-                var next = selected.next(".select2-search-choice:not(.select2-locked)");
-                var pos = getCursorInfo(this.search);
-
-                if (selected.length &&
-                    (e.which == KEY.LEFT || e.which == KEY.RIGHT || e.which == KEY.BACKSPACE || e.which == KEY.DELETE || e.which == KEY.ENTER)) {
-                    var selectedChoice = selected;
-                    if (e.which == KEY.LEFT && prev.length) {
-                        selectedChoice = prev;
-                    }
-                    else if (e.which == KEY.RIGHT) {
-                        selectedChoice = next.length ? next : null;
-                    }
-                    else if (e.which === KEY.BACKSPACE) {
-                        this.unselect(selected.first());
-                        this.search.width(10);
-                        selectedChoice = prev.length ? prev : next;
-                    } else if (e.which == KEY.DELETE) {
-                        this.unselect(selected.first());
-                        this.search.width(10);
-                        selectedChoice = next.length ? next : null;
-                    } else if (e.which == KEY.ENTER) {
-                        selectedChoice = null;
-                    }
-
-                    this.selectChoice(selectedChoice);
-                    killEvent(e);
-                    if (!selectedChoice || !selectedChoice.length) {
-                        this.open();
-                    }
-                    return;
-                } else if (((e.which === KEY.BACKSPACE && this.keydowns == 1)
-                    || e.which == KEY.LEFT) && (pos.offset == 0 && !pos.length)) {
-
-                    this.selectChoice(selection.find(".select2-search-choice:not(.select2-locked)").last());
-                    killEvent(e);
-                    return;
-                } else {
-                    this.selectChoice(null);
-                }
-
-                if (this.opened()) {
-                    switch (e.which) {
-                    case KEY.UP:
-                    case KEY.DOWN:
-                        this.moveHighlight((e.which === KEY.UP) ? -1 : 1);
-                        killEvent(e);
-                        return;
-                    case KEY.ENTER:
-                        this.selectHighlighted();
-                        killEvent(e);
-                        return;
-                    case KEY.TAB:
-                        this.selectHighlighted({noFocus:true});
-                        return;
-                    case KEY.ESC:
-                        this.cancel(e);
-                        killEvent(e);
-                        return;
-                    }
-                }
-
-                if (e.which === KEY.TAB || KEY.isControl(e) || KEY.isFunctionKey(e)
-                 || e.which === KEY.BACKSPACE || e.which === KEY.ESC) {
-                    return;
-                }
-
-                if (e.which === KEY.ENTER) {
-                    if (this.opts.openOnEnter === false) {
-                        return;
-                    } else if (e.altKey || e.ctrlKey || e.shiftKey || e.metaKey) {
-                        return;
-                    }
-                }
-
-                this.open();
-
-                if (e.which === KEY.PAGE_UP || e.which === KEY.PAGE_DOWN) {
-                    // prevent the page from scrolling
-                    killEvent(e);
-                }
-
-                if (e.which === KEY.ENTER) {
-                    // prevent form from being submitted
-                    killEvent(e);
-                }
-
-            }));
-
-            this.search.on("keyup", this.bind(function (e) {
-                this.keydowns = 0;
-                this.resizeSearch();
-            })
-            );
-
-            this.search.on("blur", this.bind(function(e) {
-                this.container.removeClass("select2-container-active");
-                this.search.removeClass("select2-focused");
-                this.selectChoice(null);
-                if (!this.opened()) this.clearSearch();
-                e.stopImmediatePropagation();
-                this.opts.element.trigger($.Event("select2-blur"));
-            }));
-
-            this.container.on("mousedown", selector, this.bind(function (e) {
-                if (!this.isInterfaceEnabled()) return;
-                if ($(e.target).closest(".select2-search-choice").length > 0) {
-                    // clicked inside a select2 search choice, do not open
-                    return;
-                }
-                this.selectChoice(null);
-                this.clearPlaceholder();
-                if (!this.container.hasClass("select2-container-active")) {
-                    this.opts.element.trigger($.Event("select2-focus"));
-                }
-                this.open();
-                this.focusSearch();
-                e.preventDefault();
-            }));
-
-            this.container.on("focus", selector, this.bind(function () {
-                if (!this.isInterfaceEnabled()) return;
-                if (!this.container.hasClass("select2-container-active")) {
-                    this.opts.element.trigger($.Event("select2-focus"));
-                }
-                this.container.addClass("select2-container-active");
-                this.dropdown.addClass("select2-drop-active");
-                this.clearPlaceholder();
-            }));
-
-            this.initContainerWidth();
-            this.opts.element.addClass("select2-offscreen");
-
-            // set the placeholder if necessary
-            this.clearSearch();
-        },
-
-        // multi
-        enableInterface: function() {
-            if (this.parent.enableInterface.apply(this, arguments)) {
-                this.search.prop("disabled", !this.isInterfaceEnabled());
-            }
-        },
-
-        // multi
-        initSelection: function () {
-            var data;
-            if (this.opts.element.val() === "" && this.opts.element.text() === "") {
-                this.updateSelection([]);
-                this.close();
-                // set the placeholder if necessary
-                this.clearSearch();
-            }
-            if (this.select || this.opts.element.val() !== "") {
-                var self = this;
-                this.opts.initSelection.call(null, this.opts.element, function(data){
-                    if (data !== undefined && data !== null) {
-                        self.updateSelection(data);
-                        self.close();
-                        // set the placeholder if necessary
-                        self.clearSearch();
-                    }
-                });
-            }
-        },
-
-        // multi
-        clearSearch: function () {
-            var placeholder = this.getPlaceholder(),
-                maxWidth = this.getMaxSearchWidth();
-
-            if (placeholder !== undefined  && this.getVal().length === 0 && this.search.hasClass("select2-focused") === false) {
-                this.search.val(placeholder).addClass("select2-default");
-                // stretch the search box to full width of the container so as much of the placeholder is visible as possible
-                // we could call this.resizeSearch(), but we do not because that requires a sizer and we do not want to create one so early because of a firefox bug, see #944
-                this.search.width(maxWidth > 0 ? maxWidth : this.container.css("width"));
-            } else {
-                this.search.val("").width(10);
-            }
-        },
-
-        // multi
-        clearPlaceholder: function () {
-            if (this.search.hasClass("select2-default")) {
-                this.search.val("").removeClass("select2-default");
-            }
-        },
-
-        // multi
-        opening: function () {
-            this.clearPlaceholder(); // should be done before super so placeholder is not used to search
-            this.resizeSearch();
-
-            this.parent.opening.apply(this, arguments);
-
-            this.focusSearch();
-
-            this.updateResults(true);
-            this.search.focus();
-            this.opts.element.trigger($.Event("select2-open"));
-        },
-
-        // multi
-        close: function () {
-            if (!this.opened()) return;
-            this.parent.close.apply(this, arguments);
-        },
-
-        // multi
-        focus: function () {
-            this.close();
-            this.search.focus();
-            //this.opts.element.triggerHandler("focus");
-        },
-
-        // multi
-        isFocused: function () {
-            return this.search.hasClass("select2-focused");
-        },
-
-        // multi
-        updateSelection: function (data) {
-            var ids = [], filtered = [], self = this;
-
-            // filter out duplicates
-            $(data).each(function () {
-                if (indexOf(self.id(this), ids) < 0) {
-                    ids.push(self.id(this));
-                    filtered.push(this);
-                }
-            });
-            data = filtered;
-
-            this.selection.find(".select2-search-choice").remove();
-            $(data).each(function () {
-                self.addSelectedChoice(this);
-            });
-            self.postprocessResults();
-        },
-
-        // multi
-        tokenize: function() {
-            var input = this.search.val();
-            input = this.opts.tokenizer(input, this.data(), this.bind(this.onSelect), this.opts);
-            if (input != null && input != undefined) {
-                this.search.val(input);
-                if (input.length > 0) {
-                    this.open();
-                }
-            }
-
-        },
-
-        // multi
-        onSelect: function (data, options) {
-
-            if (!this.triggerSelect(data)) { return; }
-
-            this.addSelectedChoice(data);
-
-            this.opts.element.trigger({ type: "selected", val: this.id(data), choice: data });
-
-            if (this.select || !this.opts.closeOnSelect) this.postprocessResults();
-
-            if (this.opts.closeOnSelect) {
-                this.close();
-                this.search.width(10);
-            } else {
-                if (this.countSelectableResults()>0) {
-                    this.search.width(10);
-                    this.resizeSearch();
-                    if (this.getMaximumSelectionSize() > 0 && this.val().length >= this.getMaximumSelectionSize()) {
-                        // if we reached max selection size repaint the results so choices
-                        // are replaced with the max selection reached message
-                        this.updateResults(true);
-                    }
-                    this.positionDropdown();
-                } else {
-                    // if nothing left to select close
-                    this.close();
-                    this.search.width(10);
-                }
-            }
-
-            // since its not possible to select an element that has already been
-            // added we do not need to check if this is a new element before firing change
-            this.triggerChange({ added: data });
-
-            if (!options || !options.noFocus)
-                this.focusSearch();
-        },
-
-        // multi
-        cancel: function () {
-            this.close();
-            this.focusSearch();
-        },
-
-        addSelectedChoice: function (data) {
-            var enableChoice = !data.locked,
-                enabledItem = $(
-                    "<li class='select2-search-choice'>" +
-                    "    <div></div>" +
-                    "    <a href='#' onclick='return false;' class='select2-search-choice-close' tabindex='-1'></a>" +
-                    "</li>"),
-                disabledItem = $(
-                    "<li class='select2-search-choice select2-locked'>" +
-                    "<div></div>" +
-                    "</li>");
-            var choice = enableChoice ? enabledItem : disabledItem,
-                id = this.id(data),
-                val = this.getVal(),
-                formatted;
-
-            formatted=this.opts.formatSelection(data, choice.find("div"));
-            if (formatted != undefined) {
-                choice.find("div").replaceWith("<div title='"+this.opts.escapeMarkup(formatted)+"'>"+this.opts.escapeMarkup(formatted)+"</div>");
-            }
-
-            if(enableChoice){
-              choice.find(".select2-search-choice-close")
-                  .on("mousedown", killEvent)
-                  .on("click dblclick", this.bind(function (e) {
-                  if (!this.isInterfaceEnabled()) return;
-
-                  $(e.target).closest(".select2-search-choice").fadeOut('fast', this.bind(function(){
-                      this.unselect($(e.target));
-                      this.selection.find(".select2-search-choice-focus").removeClass("select2-search-choice-focus");
-                      this.close();
-                      this.focusSearch();
-                  })).dequeue();
-                  killEvent(e);
-              })).on("focus", this.bind(function () {
-                  if (!this.isInterfaceEnabled()) return;
-                  this.container.addClass("select2-container-active");
-                  this.dropdown.addClass("select2-drop-active");
-              }));
-            }
-
-            choice.data("select2-data", data);
-            choice.insertBefore(this.searchContainer);
-
-            val.push(id);
-            this.setVal(val);
-        },
-
-        // multi
-        unselect: function (selected) {
-            var val = this.getVal(),
-                data,
-                index;
-
-            selected = selected.closest(".select2-search-choice");
-
-            if (selected.length === 0) {
-                throw "Invalid argument: " + selected + ". Must be .select2-search-choice";
-            }
-
-            data = selected.data("select2-data");
-
-            if (!data) {
-                // prevent a race condition when the 'x' is clicked really fast repeatedly the event can be queued
-                // and invoked on an element already removed
-                return;
-            }
-
-            index = indexOf(this.id(data), val);
-
-            if (index >= 0) {
-                val.splice(index, 1);
-                this.setVal(val);
-                if (this.select) this.postprocessResults();
-            }
-            selected.remove();
-
-            this.opts.element.trigger({ type: "removed", val: this.id(data), choice: data });
-            this.triggerChange({ removed: data });
-        },
-
-        // multi
-        postprocessResults: function (data, initial, noHighlightUpdate) {
-            var val = this.getVal(),
-                choices = this.results.find(".select2-result"),
-                compound = this.results.find(".select2-result-with-children"),
-                self = this;
-
-            choices.each2(function (i, choice) {
-                var id = self.id(choice.data("select2-data"));
-                if (indexOf(id, val) >= 0) {
-                    choice.addClass("select2-selected");
-                    // mark all children of the selected parent as selected
-                    choice.find(".select2-result-selectable").addClass("select2-selected");
-                }
-            });
-
-            compound.each2(function(i, choice) {
-                // hide an optgroup if it doesnt have any selectable children
-                if (!choice.is('.select2-result-selectable')
-                    && choice.find(".select2-result-selectable:not(.select2-selected)").length === 0) {
-                    choice.addClass("select2-selected");
-                }
-            });
-
-            if (this.highlight() == -1 && noHighlightUpdate !== false){
-                self.highlight(0);
-            }
-
-            //If all results are chosen render formatNoMAtches
-            if(!this.opts.createSearchChoice && !choices.filter('.select2-result:not(.select2-selected)').length > 0){
-                this.results.append("<li class='select2-no-results'>" + self.opts.formatNoMatches(self.search.val()) + "</li>");
-            }
-
-        },
-
-        // multi
-        getMaxSearchWidth: function() {
-            return this.selection.width() - getSideBorderPadding(this.search);
-        },
-
-        // multi
-        resizeSearch: function () {
-            var minimumWidth, left, maxWidth, containerLeft, searchWidth,
-            	sideBorderPadding = getSideBorderPadding(this.search);
-
-            minimumWidth = measureTextWidth(this.search) + 10;
-
-            left = this.search.offset().left;
-
-            maxWidth = this.selection.width();
-            containerLeft = this.selection.offset().left;
-
-            searchWidth = maxWidth - (left - containerLeft) - sideBorderPadding;
-
-            if (searchWidth < minimumWidth) {
-                searchWidth = maxWidth - sideBorderPadding;
-            }
-
-            if (searchWidth < 40) {
-                searchWidth = maxWidth - sideBorderPadding;
-            }
-
-            if (searchWidth <= 0) {
-              searchWidth = minimumWidth;
-            }
-
-            this.search.width(searchWidth);
-        },
-
-        // multi
-        getVal: function () {
-            var val;
-            if (this.select) {
-                val = this.select.val();
-                return val === null ? [] : val;
-            } else {
-                val = this.opts.element.val();
-                return splitVal(val, this.opts.separator);
-            }
-        },
-
-        // multi
-        setVal: function (val) {
-            var unique;
-            if (this.select) {
-                this.select.val(val);
-            } else {
-                unique = [];
-                // filter out duplicates
-                $(val).each(function () {
-                    if (indexOf(this, unique) < 0) unique.push(this);
-                });
-                this.opts.element.val(unique.length === 0 ? "" : unique.join(this.opts.separator));
-            }
-        },
-
-        // multi
-        buildChangeDetails: function (old, current) {
-            var current = current.slice(0),
-                old = old.slice(0);
-
-            // remove intersection from each array
-            for (var i = 0; i < current.length; i++) {
-                for (var j = 0; j < old.length; j++) {
-                    if (equal(this.opts.id(current[i]), this.opts.id(old[j]))) {
-                        current.splice(i, 1);
-                        i--;
-                        old.splice(j, 1);
-                        j--;
-                    }
-                }
-            }
-
-            return {added: current, removed: old};
-        },
-
-
-        // multi
-        val: function (val, triggerChange) {
-            var oldData, self=this, changeDetails;
-
-            if (arguments.length === 0) {
-                return this.getVal();
-            }
-
-            oldData=this.data();
-            if (!oldData.length) oldData=[];
-
-            // val is an id. !val is true for [undefined,null,'',0] - 0 is legal
-            if (!val && val !== 0) {
-                this.opts.element.val("");
-                this.updateSelection([]);
-                this.clearSearch();
-                if (triggerChange) {
-                    this.triggerChange({added: this.data(), removed: oldData});
-                }
-                return;
-            }
-
-            // val is a list of ids
-            this.setVal(val);
-
-            if (this.select) {
-                this.opts.initSelection(this.select, this.bind(this.updateSelection));
-                if (triggerChange) {
-                    this.triggerChange(this.buildChangeDetails(oldData, this.data()));
-                }
-            } else {
-                if (this.opts.initSelection === undefined) {
-                    throw new Error("val() cannot be called if initSelection() is not defined");
-                }
-
-                this.opts.initSelection(this.opts.element, function(data){
-                    var ids=$(data).map(self.id);
-                    self.setVal(ids);
-                    self.updateSelection(data);
-                    self.clearSearch();
-                    if (triggerChange) {
-                        self.triggerChange(this.buildChangeDetails(oldData, this.data()));
-                    }
-                });
-            }
-            this.clearSearch();
-        },
-
-        // multi
-        onSortStart: function() {
-            if (this.select) {
-                throw new Error("Sorting of elements is not supported when attached to <select>. Attach to <input type='hidden'/> instead.");
-            }
-
-            // collapse search field into 0 width so its container can be collapsed as well
-            this.search.width(0);
-            // hide the container
-            this.searchContainer.hide();
-        },
-
-        // multi
-        onSortEnd:function() {
-
-            var val=[], self=this;
-
-            // show search and move it to the end of the list
-            this.searchContainer.show();
-            // make sure the search container is the last item in the list
-            this.searchContainer.appendTo(this.searchContainer.parent());
-            // since we collapsed the width in dragStarted, we resize it here
-            this.resizeSearch();
-
-            // update selection
-
-            this.selection.find(".select2-search-choice").each(function() {
-                val.push(self.opts.id($(this).data("select2-data")));
-            });
-            this.setVal(val);
-            this.triggerChange();
-        },
-
-        // multi
-        data: function(values, triggerChange) {
-            var self=this, ids, old;
-            if (arguments.length === 0) {
-                 return this.selection
-                     .find(".select2-search-choice")
-                     .map(function() { return $(this).data("select2-data"); })
-                     .get();
-            } else {
-                old = this.data();
-                if (!values) { values = []; }
-                ids = $.map(values, function(e) { return self.opts.id(e); });
-                this.setVal(ids);
-                this.updateSelection(values);
-                this.clearSearch();
-                if (triggerChange) {
-                    this.triggerChange(this.buildChangeDetails(old, this.data()));
-                }
-            }
-        }
-    });
-
-    $.fn.select2 = function () {
-
-        var args = Array.prototype.slice.call(arguments, 0),
-            opts,
-            select2,
-            value, multiple,
-            allowedMethods = ["val", "destroy", "opened", "open", "close", "focus", "isFocused", "container", "onSortStart", "onSortEnd", "enable", "readonly", "positionDropdown", "data"],
-            valueMethods = ["val", "opened", "isFocused", "container", "data"];
-
-        this.each(function () {
-            if (args.length === 0 || typeof(args[0]) === "object") {
-                opts = args.length === 0 ? {} : $.extend({}, args[0]);
-                opts.element = $(this);
-
-                if (opts.element.get(0).tagName.toLowerCase() === "select") {
-                    multiple = opts.element.prop("multiple");
-                } else {
-                    multiple = opts.multiple || false;
-                    if ("tags" in opts) {opts.multiple = multiple = true;}
-                }
-
-                select2 = multiple ? new MultiSelect2() : new SingleSelect2();
-                select2.init(opts);
-            } else if (typeof(args[0]) === "string") {
-
-                if (indexOf(args[0], allowedMethods) < 0) {
-                    throw "Unknown method: " + args[0];
-                }
-
-                value = undefined;
-                select2 = $(this).data("select2");
-                if (select2 === undefined) return;
-                if (args[0] === "container") {
-                    value=select2.container;
-                } else {
-                    value = select2[args[0]].apply(select2, args.slice(1));
-                }
-                if (indexOf(args[0], valueMethods) >= 0) {
-                    return false;
-                }
-            } else {
-                throw "Invalid arguments to select2 plugin: " + args;
-            }
-        });
-        return (value === undefined) ? this : value;
-    };
-
-    // plugin defaults, accessible to users
-    $.fn.select2.defaults = {
-        width: "copy",
-        loadMorePadding: 0,
-        closeOnSelect: true,
-        openOnEnter: true,
-        containerCss: {},
-        dropdownCss: {},
-        containerCssClass: "",
-        dropdownCssClass: "",
-        formatResult: function(result, container, query, escapeMarkup) {
-            var markup=[];
-            markMatch(result.text, query.term, markup, escapeMarkup);
-            return markup.join("");
-        },
-        formatSelection: function (data, container) {
-            return data ? data.text : undefined;
-        },
-        sortResults: function (results, container, query) {
-            return results;
-        },
-        formatResultCssClass: function(data) {return undefined;},
-        formatNoMatches: function () { return "No matches found"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " more character" + (n == 1? "" : "s"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Please delete " + n + " character" + (n == 1? "" : "s"); },
-        formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
-        formatLoadMore: function (pageNumber) { return "Loading more results..."; },
-        formatSearching: function () { return "Searching..."; },
-        minimumResultsForSearch: 0,
-        minimumInputLength: 0,
-        maximumInputLength: null,
-        maximumSelectionSize: 0,
-        id: function (e) { return e.id; },
-        matcher: function(term, text) {
-            return (''+text).toUpperCase().indexOf((''+term).toUpperCase()) >= 0;
-        },
-        separator: ",",
-        tokenSeparators: [],
-        tokenizer: defaultTokenizer,
-        escapeMarkup: function (markup) {
-            var replace_map = {
-                '\\': '&#92;',
-                '&': '&amp;',
-                '<': '&lt;',
-                '>': '&gt;',
-                '"': '&quot;',
-                "'": '&#39;',
-                "/": '&#47;'
-            };
-
-            return String(markup).replace(/[&<>"'\/\\]/g, function (match) {
-                    return replace_map[match];
-            });
-        },
-        blurOnChange: false,
-        selectOnBlur: false,
-        adaptContainerCssClass: function(c) { return c; },
-        adaptDropdownCssClass: function(c) { return null; }
-    };
-
-    $.fn.select2.ajaxDefaults = {
-        transport: $.ajax,
-        params: {
-            type: "GET",
-            cache: false,
-            dataType: "json"
-        }
-    };
-
-    // exports
-    window.Select2 = {
-        query: {
-            ajax: ajax,
-            local: local,
-            tags: tags
-        }, util: {
-            debounce: debounce,
-            markMatch: markMatch
-        }, "class": {
-            "abstract": AbstractSelect2,
-            "single": SingleSelect2,
-            "multi": MultiSelect2
-        }
-    };
-
-}(jQuery));
diff --git a/circle/network/static/js/select2-3.4.0/select2.png b/circle/network/static/js/select2-3.4.0/select2.png
deleted file mode 100644
index 1d804ff..0000000
Binary files a/circle/network/static/js/select2-3.4.0/select2.png and /dev/null differ
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ca.js b/circle/network/static/js/select2-3.4.0/select2_locale_ca.js
deleted file mode 100644
index bdcdaa7..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_ca.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Select2 Catalan translation.
- * 
- * Author: David Planella <david.planella@gmail.com>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "No s'ha trobat cap coincidència"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Introduïu " + n + " caràcter" + (n == 1 ? "" : "s") + " més"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Introduïu " + n + " caràcter" + (n == 1? "" : "s") + "menys"; },
-        formatSelectionTooBig: function (limit) { return "Només podeu seleccionar " + limit + " element" + (limit == 1 ? "" : "s"); },
-        formatLoadMore: function (pageNumber) { return "S'estan carregant més resultats..."; },
-        formatSearching: function () { return "S'està cercant..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_cs.js b/circle/network/static/js/select2-3.4.0/select2_locale_cs.js
deleted file mode 100644
index 2055f08..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_cs.js
+++ /dev/null
@@ -1,49 +0,0 @@
-/**
- * Select2 Czech translation.
- * 
- * Author: Michal Marek <ahoj@michal-marek.cz>
- * Author - sklonovani: David Vallner <david@vallner.net>
- */
-(function ($) {
-    "use strict";
-    // use text for the numbers 2 through 4
-    var smallNumbers = {
-        2: function(masc) { return (masc ? "dva" : "dvě"); },
-        3: function() { return "tři"; },
-        4: function() { return "čtyři"; }
-    }
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Nenalezeny žádné položky"; },
-        formatInputTooShort: function (input, min) {
-            var n = min - input.length;
-            if (n == 1) {
-                return "Prosím zadejte ještě jeden znak";
-            } else if (n <= 4) {
-                return "Prosím zadejte ještě další "+smallNumbers[n](true)+" znaky";
-            } else {
-                return "Prosím zadejte ještě dalších "+n+" znaků";
-            }
-        },
-        formatInputTooLong: function (input, max) {
-            var n = input.length - max;
-            if (n == 1) {
-                return "Prosím zadejte o jeden znak méně";
-            } else if (n <= 4) {
-                return "Prosím zadejte o "+smallNumbers[n](true)+" znaky méně";
-            } else {
-                return "Prosím zadejte o "+n+" znaků méně";
-            }
-        },
-        formatSelectionTooBig: function (limit) {
-            if (limit == 1) {
-                return "Můžete zvolit jen jednu položku";
-            } else if (limit <= 4) {
-                return "Můžete zvolit maximálně "+smallNumbers[limit](false)+" položky";
-            } else {
-                return "Můžete zvolit maximálně "+limit+" položek";
-            }
-        },
-        formatLoadMore: function (pageNumber) { return "Načítavají se další výsledky..."; },
-        formatSearching: function () { return "Vyhledávání..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_da.js b/circle/network/static/js/select2-3.4.0/select2_locale_da.js
deleted file mode 100644
index dbce3e1..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_da.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Select2 Danish translation.
- *
- * Author: Anders Jenbo <anders@jenbo.dk>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Ingen resultater fundet"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Angiv venligst " + n + " tegn mere"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Angiv venligst " + n + " tegn mindre"; },
-        formatSelectionTooBig: function (limit) { return "Du kan kun vælge " + limit + " emne" + (limit === 1 ? "" : "r"); },
-        formatLoadMore: function (pageNumber) { return "Indlæser flere resultater…"; },
-        formatSearching: function () { return "Søger…"; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_de.js b/circle/network/static/js/select2-3.4.0/select2_locale_de.js
deleted file mode 100644
index 01f94ed..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_de.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 German translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Keine Übereinstimmungen gefunden"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Bitte " + n + " Zeichen mehr eingeben"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Bitte " + n + " Zeichen weniger eingeben"; },
-        formatSelectionTooBig: function (limit) { return "Sie können nur " + limit + " Eintr" + (limit === 1 ? "ag" : "äge") + " auswählen"; },
-        formatLoadMore: function (pageNumber) { return "Lade mehr Ergebnisse..."; },
-        formatSearching: function () { return "Suche..."; }
-    });
-})(jQuery);
\ No newline at end of file
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_en.js.template b/circle/network/static/js/select2-3.4.0/select2_locale_en.js.template
deleted file mode 100644
index 260c6c4..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_en.js.template
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Select2 <Language> translation.
- * 
- * Author: Your Name <your@email>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "No matches found"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Please enter " + n + " more character" + (n == 1 ? "" : "s"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Please enter " + n + " less character" + (n == 1? "" : "s"); },
-        formatSelectionTooBig: function (limit) { return "You can only select " + limit + " item" + (limit == 1 ? "" : "s"); },
-        formatLoadMore: function (pageNumber) { return "Loading more results..."; },
-        formatSearching: function () { return "Searching..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_es.js b/circle/network/static/js/select2-3.4.0/select2_locale_es.js
deleted file mode 100644
index 1b0a021..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_es.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 Spanish translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "No se encontraron resultados"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Por favor adicione " + n + " caracter" + (n == 1? "" : "es"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Por favor elimine " + n + " caracter" + (n == 1? "" : "es"); },
-        formatSelectionTooBig: function (limit) { return "Solo puede seleccionar " + limit + " elemento" + (limit == 1 ? "" : "s"); },
-        formatLoadMore: function (pageNumber) { return "Cargando más resultados..."; },
-        formatSearching: function () { return "Buscando..."; }
-    });
-})(jQuery);
\ No newline at end of file
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_et.js b/circle/network/static/js/select2-3.4.0/select2_locale_et.js
deleted file mode 100644
index a4045d2..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_et.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Select2 Estonian translation.
- *
- * Author: Kuldar Kalvik <kuldar@kalvik.ee>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Tulemused puuduvad"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Sisesta " + n + " täht" + (n == 1 ? "" : "e") + " rohkem"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Sisesta " + n + " täht" + (n == 1? "" : "e") + " vähem"; },
-        formatSelectionTooBig: function (limit) { return "Saad vaid " + limit + " tulemus" + (limit == 1 ? "e" : "t") + " valida"; },
-        formatLoadMore: function (pageNumber) { return "Laen tulemusi.."; },
-        formatSearching: function () { return "Otsin.."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_eu.js b/circle/network/static/js/select2-3.4.0/select2_locale_eu.js
deleted file mode 100644
index 05665f5..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_eu.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Select2 Basque translation.
- *
- * Author: Julen Ruiz Aizpuru <julenx at gmail dot com>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () {
-          return "Ez da bat datorrenik aurkitu";
-        },
-        formatInputTooShort: function (input, min) {
-          var n = min - input.length;
-          if (n === 1) {
-            return "Idatzi karaktere bat gehiago";
-          } else {
-            return "Idatzi " + n + " karaktere gehiago";
-          }
-        },
-        formatInputTooLong: function (input, max) {
-          var n = input.length - max;
-          if (n === 1) {
-            return "Idatzi karaktere bat gutxiago";
-          } else {
-            return "Idatzi " + n + " karaktere gutxiago";
-          }
-        },
-        formatSelectionTooBig: function (limit) {
-          if (limit === 1 ) {
-            return "Elementu bakarra hauta dezakezu";
-          } else {
-            return limit + " elementu hauta ditzakezu soilik";
-          }
-        },
-        formatLoadMore: function (pageNumber) {
-          return "Emaitza gehiago kargatzen...";
-        },
-        formatSearching: function () {
-          return "Bilatzen...";
-        }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_fr.js b/circle/network/static/js/select2-3.4.0/select2_locale_fr.js
deleted file mode 100644
index 53c60a6..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_fr.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 French translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Aucun r&eacute;sultat trouv&eacute;"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Merci de saisir " + n + " caract&egrave;re" + (n == 1? "" : "s") + " de plus"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Merci de saisir " + n + " caract&egrave;re" + (n == 1? "" : "s") + " de moins"; },
-        formatSelectionTooBig: function (limit) { return "Vous pouvez seulement s&eacute;lectionner " + limit + " &eacute;l&eacute;ment" + (limit == 1 ? "" : "s"); },
-        formatLoadMore: function (pageNumber) { return "Chargement de r&eacute;sultats suppl&eacute;mentaires..."; },
-        formatSearching: function () { return "Recherche en cours..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_gl.js b/circle/network/static/js/select2-3.4.0/select2_locale_gl.js
deleted file mode 100644
index 1017c20..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_gl.js
+++ /dev/null
@@ -1,43 +0,0 @@
-/**
- * Select2 Galician translation
- * 
- * Author: Leandro Regueiro <leandro.regueiro@gmail.com>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () {
-            return "Non se atoparon resultados";
-        },
-        formatInputTooShort: function (input, min) {
-            var n = min - input.length;
-            if (n === 1) {
-                return "Engada un carácter";
-            } else {
-                return "Engada " + n + " caracteres";
-            }
-        },
-        formatInputTooLong: function (input, max) {
-            var n = input.length - max;
-            if (n === 1) {
-                return "Elimine un carácter";
-            } else {
-                return "Elimine " + n + " caracteres";
-            }
-        },
-        formatSelectionTooBig: function (limit) {
-            if (limit === 1 ) {
-                return "Só pode seleccionar un elemento";
-            } else {
-                return "Só pode seleccionar " + limit + " elementos";
-            }
-        },
-        formatLoadMore: function (pageNumber) {
-            return "Cargando máis resultados...";
-        },
-        formatSearching: function () {
-            return "Buscando...";
-        }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_he.js b/circle/network/static/js/select2-3.4.0/select2_locale_he.js
deleted file mode 100644
index dd72eaa..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_he.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
-* Select2 Hebrew translation.
-*
-* Author: Yakir Sitbon <http://www.yakirs.net/>
-*/
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "לא נמצאו התאמות"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "נא להזין עוד " + n + " תווים נוספים"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "נא להזין פחות " + n + " תווים"; },
-        formatSelectionTooBig: function (limit) { return "ניתן לבחור " + limit + " פריטים"; },
-        formatLoadMore: function (pageNumber) { return "טוען תוצאות נוספות..."; },
-        formatSearching: function () { return "מחפש..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_hr.js b/circle/network/static/js/select2-3.4.0/select2_locale_hr.js
deleted file mode 100644
index b061540..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_hr.js
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * Select2 Croatian translation.
- *
- * Author: Edi Modrić <edi.modric@gmail.com>
- */
-(function ($) {
-    "use strict";
-
-    var specialNumbers = {
-        1: function(n) { return (n % 100 != 11 ? "znak" : "znakova"); },
-        2: function(n) { return (n % 100 != 12 ? "znaka" : "znakova"); },
-        3: function(n) { return (n % 100 != 13 ? "znaka" : "znakova"); },
-        4: function(n) { return (n % 100 != 14 ? "znaka" : "znakova"); }
-    };
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Nema rezultata"; },
-        formatInputTooShort: function (input, min) {
-            var n = min - input.length;
-            var nMod10 = n % 10;
-
-            if (nMod10 > 0 && nMod10 < 5) {
-                return "Unesite još " + n + " " + specialNumbers[nMod10](n);
-            }
-
-            return "Unesite još " + n + " znakova";
-        },
-        formatInputTooLong: function (input, max) {
-            var n = input.length - max;
-            var nMod10 = n % 10;
-
-            if (nMod10 > 0 && nMod10 < 5) {
-                return "Unesite " + n + " " + specialNumbers[nMod10](n) + " manje";
-            }
-
-            return "Unesite " + n + " znakova manje";
-        },
-        formatSelectionTooBig: function (limit) { return "Maksimalan broj odabranih stavki je " + limit; },
-        formatLoadMore: function (pageNumber) { return "Učitavanje rezultata..."; },
-        formatSearching: function () { return "Pretraga..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_hu.js b/circle/network/static/js/select2-3.4.0/select2_locale_hu.js
deleted file mode 100644
index 572dea9..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_hu.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 Hungarian translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Nincs találat."; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Túl rövid. Még " + n + " karakter hiányzik."; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Túl hosszú. " + n + " kerekterrel több mint kellene."; },
-        formatSelectionTooBig: function (limit) { return "Csak " + limit + " elemet lehet kiválasztani."; },
-        formatLoadMore: function (pageNumber) { return "Töltés..."; },
-        formatSearching: function () { return "Keresés..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_is.js b/circle/network/static/js/select2-3.4.0/select2_locale_is.js
deleted file mode 100644
index b10073b..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_is.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Select2 Icelandic translation.
- * 
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Ekkert fannst"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Vinsamlegast skrifið " + n + " staf" + (n == 1 ? "" : "i") + " í viðbót"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Vinsamlegast styttið texta um " + n + " staf" + (n == 1 ? "" : "i"); },
-        formatSelectionTooBig: function (limit) { return "Þú getur aðeins valið " + limit + " atriði"; },
-        formatLoadMore: function (pageNumber) { return "Sæki fleiri niðurstöður..."; }, 
-        formatSearching: function () { return "Leita..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_it.js b/circle/network/static/js/select2-3.4.0/select2_locale_it.js
deleted file mode 100644
index 98369dd..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_it.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 Italian translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Nessuna corrispondenza trovata"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Inserisci ancora " + n + " caratter" + (n == 1? "e" : "i"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Inserisci " + n + " caratter" + (n == 1? "e" : "i") + " in meno"; },
-        formatSelectionTooBig: function (limit) { return "Puoi selezionare solo " + limit + " element" + (limit == 1 ? "o" : "i"); },
-        formatLoadMore: function (pageNumber) { return "Caricamento in corso..."; },
-        formatSearching: function () { return "Ricerca..."; }
-    });
-})(jQuery);
\ No newline at end of file
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ja.js b/circle/network/static/js/select2-3.4.0/select2_locale_ja.js
deleted file mode 100644
index 3fc8074..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_ja.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 Japanese translation.
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "該当項目なし"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "後" + n + "文字入れてください"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "検索文字列が" + n + "文字長すぎます"; },
-        formatSelectionTooBig: function (limit) { return "最多で" + limit + "項目までしか選択できません"; },
-        formatLoadMore: function (pageNumber) { return "読込中・・・"; },
-        formatSearching: function () { return "検索中・・・"; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_lt.js b/circle/network/static/js/select2-3.4.0/select2_locale_lt.js
deleted file mode 100644
index dbb1f09..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_lt.js
+++ /dev/null
@@ -1,29 +0,0 @@
-/**
- * Select2 lithuanian translation.
- * 
- * Author: CRONUS Karmalakas <cronus dot karmalakas at gmail dot com>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Atitikmenų nerasta"; },
-        formatInputTooShort: function (input, min) {
-        	var n = min - input.length,
-        	    suffix = (n % 10 == 1) && (n % 100 != 11) ? 'į' : (((n % 10 >= 2) && ((n % 100 < 10) || (n % 100 >= 20))) ? 'ius' : 'ių');
-        	return "Įrašykite dar " + n + " simbol" + suffix;
-        },
-        formatInputTooLong: function (input, max) {
-        	var n = input.length - max,
-        	    suffix = (n % 10 == 1) && (n % 100 != 11) ? 'į' : (((n % 10 >= 2) && ((n % 100 < 10) || (n % 100 >= 20))) ? 'ius' : 'ių');
-        	return "Pašalinkite " + n + " simbol" + suffix;
-        },
-        formatSelectionTooBig: function (limit) {
-        	var n = limit,
-                suffix = (n % 10 == 1) && (n % 100 != 11) ? 'ą' : (((n % 10 >= 2) && ((n % 100 < 10) || (n % 100 >= 20))) ? 'us' : 'ų');
-        	return "Jūs galite pasirinkti tik " + limit + " element" + suffix;
-        },
-        formatLoadMore: function (pageNumber) { return "Kraunama daugiau rezultatų..."; },
-        formatSearching: function () { return "Ieškoma..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_lv.js b/circle/network/static/js/select2-3.4.0/select2_locale_lv.js
deleted file mode 100644
index 2c05cfd..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_lv.js
+++ /dev/null
@@ -1,16 +0,0 @@
-/**
- * Select2 Latvian translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Sakritību nav"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Lūdzu ievadiet vēl " + n + " simbol" + (n == 11 ? "us" : (/^\d*[1]$/im.test(n)? "u" : "us")); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Lūdzu ievadiet par " + n + " simbol" + (n == 11 ? "iem" : (/^\d*[1]$/im.test(n)? "u" : "iem")) + " mazāk"; },
-        formatSelectionTooBig: function (limit) { return "Jūs varat izvēlēties ne vairāk kā " + limit + " element" + (limit == 11 ? "us" : (/^\d*[1]$/im.test(limit)? "u" : "us")); },
-        formatLoadMore: function (pageNumber) { return "Datu ielāde..."; },
-        formatSearching: function () { return "Meklēšana..."; }
-    });
-	
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_mk.js b/circle/network/static/js/select2-3.4.0/select2_locale_mk.js
deleted file mode 100644
index 69e3981..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_mk.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Select2 Macedonian translation.
- * 
- * Author: Marko Aleksic <psybaron@gmail.com>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Нема пронајдено совпаѓања"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Ве молиме внесете уште " + n + " карактер" + (n == 1 ? "" : "и"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Ве молиме внесете " + n + " помалку карактер" + (n == 1? "" : "и"); },
-        formatSelectionTooBig: function (limit) { return "Можете да изберете само " + limit + " ставк" + (limit == 1 ? "а" : "и"); },
-        formatLoadMore: function (pageNumber) { return "Вчитување резултати..."; },
-        formatSearching: function () { return "Пребарување..."; }
-    });
-})(jQuery);
\ No newline at end of file
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_nl.js b/circle/network/static/js/select2-3.4.0/select2_locale_nl.js
deleted file mode 100644
index 2ee2662..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_nl.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 Dutch translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Geen resultaten gevonden"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Vul " + n + " karakter" + (n == 1? "" : "s") + " meer in"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Vul " + n + " karakter" + (n == 1? "" : "s") + " minder in"; },
-        formatSelectionTooBig: function (limit) { return "Maximaal " + limit + " item" + (limit == 1 ? "" : "s") + " toegestaan"; },
-        formatLoadMore: function (pageNumber) { return "Meer resultaten laden..."; },
-        formatSearching: function () { return "Zoeken..."; },
-    });
-})(jQuery);
\ No newline at end of file
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_no.js b/circle/network/static/js/select2-3.4.0/select2_locale_no.js
deleted file mode 100644
index 0831360..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_no.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Select2 Norwegian translation.
- *
- * Author: Torgeir Veimo <torgeir.veimo@gmail.com>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Ingen treff"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Vennligst skriv inn " + n + (n>1 ? " flere tegn" : " tegn til"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Vennligst fjern " + n + " tegn"; },
-        formatSelectionTooBig: function (limit) { return "Du kan velge maks " + limit + " elementer"; },
-        formatLoadMore: function (pageNumber) { return "Laster flere resultater..."; },
-        formatSearching: function () { return "Søker..."; }
-    });
-})(jQuery);
-
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_pl.js b/circle/network/static/js/select2-3.4.0/select2_locale_pl.js
deleted file mode 100644
index 1d5b327..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_pl.js
+++ /dev/null
@@ -1,37 +0,0 @@
-/**
- * Select2 Polish translation.
- * 
- * Author: Jan Kondratowicz <jan@kondratowicz.pl>
- */
-(function ($) {
-    "use strict";
-    
-    var pl_suffix = function(n) {
-        if(n == 1) return "";
-        if((n%100 > 1 && n%100 < 5) || (n%100 > 20 && n%10 > 1 && n%10 < 5)) return "i";
-        return "ów";
-    };
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () {
-            return "Brak wyników.";
-        },
-        formatInputTooShort: function (input, min) {
-            var n = min - input.length;
-            return "Wpisz jeszcze " + n + " znak" + pl_suffix(n) + ".";
-        },
-        formatInputTooLong: function (input, max) {
-            var n = input.length - max;
-            return "Wpisana fraza jest za długa o " + n + " znak" + pl_suffix(n) + ".";
-        },
-        formatSelectionTooBig: function (limit) {
-            return "Możesz zaznaczyć najwyżej " + limit + " element" + pl_suffix(limit) + ".";
-        },
-        formatLoadMore: function (pageNumber) {
-            return "Ładowanie wyników...";
-        },
-        formatSearching: function () {
-            return "Szukanie...";
-        }
-    });
-})(jQuery);
\ No newline at end of file
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_pt-BR.js b/circle/network/static/js/select2-3.4.0/select2_locale_pt-BR.js
deleted file mode 100644
index 701fb7f..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_pt-BR.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 Brazilian Portuguese translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Nenhum resultado encontrado"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Informe " + n + " caracter" + (n == 1? "" : "es"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Apague " + n + " caracter" + (n == 1? "" : "es"); },
-        formatSelectionTooBig: function (limit) { return "Só é possível selecionar " + limit + " elemento" + (limit == 1 ? "" : "s"); },
-        formatLoadMore: function (pageNumber) { return "Carregando mais resultados..."; },
-        formatSearching: function () { return "Buscando..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_pt-PT.js b/circle/network/static/js/select2-3.4.0/select2_locale_pt-PT.js
deleted file mode 100644
index 008653e..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_pt-PT.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 Portuguese (Portugal) translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Nenhum resultado encontrado"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Introduza " + n + " caracter" + (n == 1 ? "" : "es"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Apague " + n + " caracter" + (n == 1 ? "" : "es"); },
-        formatSelectionTooBig: function (limit) { return "Só é possível selecionar " + limit + " elemento" + (limit == 1 ? "" : "s"); },
-        formatLoadMore: function (pageNumber) { return "A carregar mais resultados..."; },
-        formatSearching: function () { return "A pesquisar..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ro.js b/circle/network/static/js/select2-3.4.0/select2_locale_ro.js
deleted file mode 100644
index 88b3ac4..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_ro.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 Romanian translation.
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Nu a fost găsit nimic"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Vă rugăm să introduceți incă " + n + " caracter" + (n == 1 ? "" : "e"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Vă rugăm să introduceți mai puțin de " + n + " caracter" + (n == 1? "" : "e"); },
-        formatSelectionTooBig: function (limit) { return "Aveți voie să selectați cel mult " + limit + " element" + (limit == 1 ? "" : "e"); },
-        formatLoadMore: function (pageNumber) { return "Se încarcă..."; },
-        formatSearching: function () { return "Căutare..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ru.js b/circle/network/static/js/select2-3.4.0/select2_locale_ru.js
deleted file mode 100644
index 3da956a..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_ru.js
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Select2 Russian translation
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Совпадений не найдено"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Пожалуйста, введите еще " + n + " символ" + (n == 1 ? "" : ((n > 1)&&(n < 5) ? "а" : "ов")); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Пожалуйста, введите на " + n + " символ" + (n == 1 ? "" : ((n > 1)&&(n < 5)? "а" : "ов")) + " меньше"; },
-        formatSelectionTooBig: function (limit) { return "Вы можете выбрать не более " + limit + " элемент" + (limit == 1 ? "а" : "ов"); },
-        formatLoadMore: function (pageNumber) { return "Загрузка данных..."; },
-        formatSearching: function () { return "Поиск..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_sk.js b/circle/network/static/js/select2-3.4.0/select2_locale_sk.js
deleted file mode 100644
index 8d4e46a..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_sk.js
+++ /dev/null
@@ -1,48 +0,0 @@
-/**
- * Select2 Slovak translation.
- *
- * Author: David Vallner <david@vallner.net>
- */
-(function ($) {
-    "use strict";
-    // use text for the numbers 2 through 4
-    var smallNumbers = {
-        2: function(masc) { return (masc ? "dva" : "dve"); },
-        3: function() { return "tri"; },
-        4: function() { return "štyri"; }
-    }
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Nenašli sa žiadne položky"; },
-        formatInputTooShort: function (input, min) {
-            var n = min - input.length;
-            if (n == 1) {
-                return "Prosím zadajte ešte jeden znak";
-            } else if (n <= 4) {
-                return "Prosím zadajte ešte ďalšie "+smallNumbers[n](true)+" znaky";
-            } else {
-                return "Prosím zadajte ešte ďalších "+n+" znakov";
-            }
-        },
-        formatInputTooLong: function (input, max) {
-            var n = input.length - max;
-            if (n == 1) {
-                return "Prosím zadajte o jeden znak menej";
-            } else if (n <= 4) {
-                return "Prosím zadajte o "+smallNumbers[n](true)+" znaky menej";
-            } else {
-                return "Prosím zadajte o "+n+" znakov menej";
-            }
-        },
-        formatSelectionTooBig: function (limit) {
-            if (limit == 1) {
-                return "Môžete zvoliť len jednu položku";
-            } else if (limit <= 4) {
-                return "Môžete zvoliť najviac "+smallNumbers[limit](false)+" položky";
-            } else {
-                return "Môžete zvoliť najviac "+limit+" položiek";
-            }
-        },
-        formatLoadMore: function (pageNumber) { return "Načítavajú sa ďalšie výsledky..."; },
-        formatSearching: function () { return "Vyhľadávanie..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_sv.js b/circle/network/static/js/select2-3.4.0/select2_locale_sv.js
deleted file mode 100644
index 9f09de3..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_sv.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Select2 Swedish translation.
- *
- * Author: Jens Rantil <jens.rantil@telavox.com>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Inga träffar"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Var god skriv in " + n + (n>1 ? " till tecken" : " tecken till"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Var god sudda ut " + n + " tecken"; },
-        formatSelectionTooBig: function (limit) { return "Du kan max välja " + limit + " element"; },
-        formatLoadMore: function (pageNumber) { return "Laddar fler resultat..."; },
-        formatSearching: function () { return "Söker..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_tr.js b/circle/network/static/js/select2-3.4.0/select2_locale_tr.js
deleted file mode 100644
index b47a2fa..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_tr.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Select2 Turkish translation.
- * 
- * Author: Salim KAYABAŞI <salim.kayabasi@gmail.com>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Sonuç bulunamadı"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "En az " + n + " karakter daha girmelisiniz"; },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return n + " karakter azaltmalısınız"; },
-        formatSelectionTooBig: function (limit) { return "Sadece " + limit + " seçim yapabilirsiniz"; },
-        formatLoadMore: function (pageNumber) { return "Daha fazla..."; },
-        formatSearching: function () { return "Aranıyor..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_ua.js b/circle/network/static/js/select2-3.4.0/select2_locale_ua.js
deleted file mode 100644
index 58d31e7..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_ua.js
+++ /dev/null
@@ -1,17 +0,0 @@
-/**
- * Select2 <Language> translation.
- * 
- * Author: bigmihail <bigmihail@bigmir.net>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Нічого не знайдено"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length, s = ["", "и", "ів"], p = [2,0,1,1,1,2]; return "Введіть буль ласка ще " + n + " символ" + s[ (n%100>4 && n%100<=20)? 2 : p[Math.min(n%10, 5)] ]; },
-        formatInputTooLong: function (input, max) { var n = input.length - max, s = ["", "и", "ів"], p = [2,0,1,1,1,2]; return "Введіть буль ласка на " + n + " символ" + s[ (n%100>4 && n%100<=20)? 2 : p[Math.min(n%10, 5)] ] + " менше"; },
-        formatSelectionTooBig: function (limit) {var s = ["", "и", "ів"], p = [2,0,1,1,1,2];  return "Ви можете вибрати лише " + limit + " елемент" + s[ (limit%100>4 && limit%100<=20)? 2 : p[Math.min(limit%10, 5)] ]; },
-        formatLoadMore: function (pageNumber) { return "Завантаження даних..."; },
-        formatSearching: function () { return "Пошук..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_vi.js b/circle/network/static/js/select2-3.4.0/select2_locale_vi.js
deleted file mode 100644
index 0a45dfc..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_vi.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/**
- * Select2 Vietnamese translation.
- * 
- * Author: Long Nguyen <olragon@gmail.com>
- */
-(function ($) {
-    "use strict";
-
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "Không tìm thấy kết quả"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "Vui lòng nhập nhiều hơn " + n + " ký tự" + (n == 1 ? "" : "s"); },
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "Vui lòng nhập ít hơn " + n + " ký tự" + (n == 1? "" : "s"); },
-        formatSelectionTooBig: function (limit) { return "Chỉ có thể chọn được " + limit + " tùy chọn" + (limit == 1 ? "" : "s"); },
-        formatLoadMore: function (pageNumber) { return "Đang lấy thêm kết quả..."; },
-        formatSearching: function () { return "Đang tìm..."; }
-    });
-})(jQuery);
-
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_zh-CN.js b/circle/network/static/js/select2-3.4.0/select2_locale_zh-CN.js
deleted file mode 100644
index 49d8e59..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_zh-CN.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Select2 Chinese translation
- */
-(function ($) {
-    "use strict";
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "没有找到匹配项"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "请再输入" + n + "个字符";},
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "请删掉" + n + "个字符";},
-        formatSelectionTooBig: function (limit) { return "你只能选择最多" + limit + "项"; },
-        formatLoadMore: function (pageNumber) { return "加载结果中..."; },
-        formatSearching: function () { return "搜索中..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2_locale_zh-TW.js b/circle/network/static/js/select2-3.4.0/select2_locale_zh-TW.js
deleted file mode 100755
index 3d447d6..0000000
--- a/circle/network/static/js/select2-3.4.0/select2_locale_zh-TW.js
+++ /dev/null
@@ -1,14 +0,0 @@
-/**
- * Select2 Traditional Chinese translation
- */
-(function ($) {
-    "use strict";
-    $.extend($.fn.select2.defaults, {
-        formatNoMatches: function () { return "沒有找到相符的項目"; },
-        formatInputTooShort: function (input, min) { var n = min - input.length; return "請再輸入" + n + "個字元";},
-        formatInputTooLong: function (input, max) { var n = input.length - max; return "請刪掉" + n + "個字元";},
-        formatSelectionTooBig: function (limit) { return "你只能選擇最多" + limit + "項"; },
-        formatLoadMore: function (pageNumber) { return "載入中..."; },
-        formatSearching: function () { return "搜尋中..."; }
-    });
-})(jQuery);
diff --git a/circle/network/static/js/select2-3.4.0/select2x2.png b/circle/network/static/js/select2-3.4.0/select2x2.png
deleted file mode 100644
index 4bdd5c9..0000000
Binary files a/circle/network/static/js/select2-3.4.0/select2x2.png and /dev/null differ
diff --git a/circle/network/static/js/switch-port.js b/circle/network/static/js/switch-port.js
index f6991f6..6962f57 100644
--- a/circle/network/static/js/switch-port.js
+++ b/circle/network/static/js/switch-port.js
@@ -1,4 +1,4 @@
-$('i[class="fa fa-times"]').click(function() {
+$('.ethernet-devices-mini-table i[class="fa fa-times"]').click(function() {
     href = $(this).parent('a').attr('href');
     csrf = getCookie('csrftoken');
     var click_this = this;
diff --git a/circle/network/static/network/network.css b/circle/network/static/network/network.less
similarity index 100%
rename from circle/network/static/network/network.css
rename to circle/network/static/network/network.less
diff --git a/circle/network/tables.py b/circle/network/tables.py
index 5cf40f1..a1261d2 100644
--- a/circle/network/tables.py
+++ b/circle/network/tables.py
@@ -97,7 +97,8 @@ class SmallRuleTable(Table):
 
     class Meta:
         model = Rule
-        attrs = {'class': 'table table-striped table-bordered table-condensed'}
+        attrs = {'class': 'table table-striped table-bordered table-condensed',
+                 'id': "small_rule_table"}
         fields = ('rule', 'action', )
 
 
diff --git a/circle/network/templates/network/base.html b/circle/network/templates/network/base.html
index 077e9d5..3cdba7d 100644
--- a/circle/network/templates/network/base.html
+++ b/circle/network/templates/network/base.html
@@ -46,8 +46,3 @@
     {% trans "dashboard" %}
   </a>
 {% endblock %}
-
-{% block extra_script %}
-  <script src="{% static "js/bootbox.min.js" %}"></script>
-  <script src="{% static "js/network.js" %}"></script>
-{% endblock %}
diff --git a/circle/network/templates/network/host-edit.html b/circle/network/templates/network/host-edit.html
index 8f8f879..e426288 100644
--- a/circle/network/templates/network/host-edit.html
+++ b/circle/network/templates/network/host-edit.html
@@ -79,7 +79,3 @@
 </div><!-- row -->
 
 {% endblock %}
-
-{% block extra_etc %}
-  <script src="{% static "js/host.js" %}"></script>
-{% endblock %}
diff --git a/circle/network/templates/network/switch-port-edit.html b/circle/network/templates/network/switch-port-edit.html
index 9ea4a37..1b19bb8 100644
--- a/circle/network/templates/network/switch-port-edit.html
+++ b/circle/network/templates/network/switch-port-edit.html
@@ -51,7 +51,3 @@
   </div>
 </div>
 {% endblock %}
-
-{% block extra_etc %}
-  <script src="{% static "js/switch-port.js" %}"></script>
-{% endblock %}
diff --git a/circle/templates/registration/base.html b/circle/templates/registration/base.html
index a98c4cd..a626320 100644
--- a/circle/templates/registration/base.html
+++ b/circle/templates/registration/base.html
@@ -76,7 +76,7 @@
 
 {% block navbar-brand %}
   <a class="navbar-brand" href="{% url "dashboard.index" %}" style="padding: 10px 15px;">
-    <img src="{{ STATIC_URL}}dashboard/img/logo.png" style="height: 25px;"/>
+    <img src="{% static "dashboard/img/logo.png" %}" style="height: 25px;"/>
   </a>
 {% endblock %}
 
diff --git a/circle/templates/registration/login.html b/circle/templates/registration/login.html
index f2e27d1..f6a09da 100644
--- a/circle/templates/registration/login.html
+++ b/circle/templates/registration/login.html
@@ -1,4 +1,5 @@
 {% extends "registration/base.html" %}
+{% load staticfiles %}
 {% load i18n %}
 {% load crispy_forms_tags %}
 {% get_current_language as LANGUAGE_CODE %}
@@ -7,7 +8,7 @@
 
 {% block navbar-brand %}
   <a class="navbar-brand" href="{% url "dashboard.index" %}" style="padding: 10px 15px;">
-    <img src="{{ STATIC_URL}}dashboard/img/logo.png" style="height: 25px;"/>
+    <img src="{% static "dashboard/img/logo.png" %}" style="height: 25px;"/>
   </a>
 {% endblock %}
 
diff --git a/docs/install.rst b/docs/install.rst
index 5d94228..cdb2c06 100644
--- a/docs/install.rst
+++ b/docs/install.rst
@@ -61,7 +61,8 @@ Update the package lists, and install the required system software::
   sudo apt-get update
   sudo apt-get install --yes virtualenvwrapper postgresql git \
     python-pip rabbitmq-server libpq-dev python-dev ntp memcached \
-    libmemcached-dev
+    libmemcached-dev npm
+  sudo npm -g install bower less
 
 Set up *PostgreSQL* to listen on localhost and restart it::
 
diff --git a/requirements/base.txt b/requirements/base.txt
index 7a91456..4f9f98c 100644
--- a/requirements/base.txt
+++ b/requirements/base.txt
@@ -35,3 +35,6 @@ sqlparse==0.1.11
 pika==0.9.13
 Fabric==1.9.0
 lxml==3.3.5
+pyinotify==0.9.4
+git+https://github.com/BME-IK/django-pipeline.git
+slimit==0.8.1