From 964a4eac6399266f19b25c96b4c25c922aa621a5 Mon Sep 17 00:00:00 2001 From: Trevor Bekolay Date: Mon, 18 Jul 2016 14:23:37 -0400 Subject: [PATCH] Modularize JS TODO: commit message --- nengo_gui/components/ace_editor.py | 2 +- nengo_gui/components/editor.py | 2 +- nengo_gui/components/htmlview.py | 2 +- nengo_gui/components/netgraph.py | 2 +- nengo_gui/components/pointer.py | 2 +- nengo_gui/components/raster.py | 2 +- nengo_gui/components/sim_control.py | 7 +- nengo_gui/components/slider.py | 2 +- nengo_gui/components/spa_similarity.py | 2 +- nengo_gui/components/spike_grid.py | 2 +- nengo_gui/components/value.py | 3 +- nengo_gui/components/voltage.py | 2 +- nengo_gui/components/xyvalue.py | 2 +- nengo_gui/guibackend.py | 8 +- nengo_gui/modal_js.py | 18 +- nengo_gui/page.py | 19 +- nengo_gui/static/components/2d_axes.js | 13 +- nengo_gui/static/components/component.js | 88 +++---- nengo_gui/static/components/htmlview.js | 29 ++- nengo_gui/static/components/image.js | 27 ++- nengo_gui/static/components/netgraph.js | 140 ++++++----- nengo_gui/static/components/netgraph_conn.js | 30 +-- nengo_gui/static/components/netgraph_item.js | 163 ++++++------- nengo_gui/static/components/pointer.js | 55 +++-- nengo_gui/static/components/raster.js | 53 +++-- nengo_gui/static/components/slider.js | 77 +++--- nengo_gui/static/components/slidercontrol.js | 38 +-- nengo_gui/static/components/spa_similarity.js | 58 +++-- nengo_gui/static/components/time_axes.js | 20 +- nengo_gui/static/components/value.js | 97 ++++---- nengo_gui/static/components/xy_axes.js | 16 +- nengo_gui/static/components/xyvalue.js | 78 ++++--- nengo_gui/static/config.js | 8 +- nengo_gui/static/data_to_csv.js | 9 +- nengo_gui/static/datastore.js | 50 ++-- nengo_gui/static/dist/nengo.js | 66 +++--- nengo_gui/static/editor.js | 88 +++---- nengo_gui/static/hotkeys.js | 41 ++-- nengo_gui/static/menu.js | 76 +++--- nengo_gui/static/modal.js | 212 +++++++++-------- nengo_gui/static/nengo.js | 221 ++++-------------- nengo_gui/static/side_menu.js | 55 +++-- nengo_gui/static/sim_control.js | 95 ++++---- nengo_gui/static/tooltips.js | 53 +++-- nengo_gui/static/top_toolbar.js | 102 ++++---- nengo_gui/static/utils.js | 140 +++++++++++ nengo_gui/static/viewport.js | 22 +- nengo_gui/templates/page.html | 7 +- 48 files changed, 1248 insertions(+), 1056 deletions(-) create mode 100644 nengo_gui/static/utils.js diff --git a/nengo_gui/components/ace_editor.py b/nengo_gui/components/ace_editor.py index 3c6cab75..77cf7e34 100644 --- a/nengo_gui/components/ace_editor.py +++ b/nengo_gui/components/ace_editor.py @@ -50,7 +50,7 @@ def update_client(self, client): self.last_stdout = stdout def javascript(self): - return 'Nengo.ace = new Nengo.Ace("%s", {})' % (id(self),) + return 'var editoruid = "%s";' % id(self) def message(self, msg): data = json.loads(msg) diff --git a/nengo_gui/components/editor.py b/nengo_gui/components/editor.py index c90e92fb..a4914319 100644 --- a/nengo_gui/components/editor.py +++ b/nengo_gui/components/editor.py @@ -13,7 +13,7 @@ def update_code(self, msg): pass def javascript(self): - return 'Nengo.disable_editor();' + return 'utils.disable_editor();' class NoEditor(Editor): diff --git a/nengo_gui/components/htmlview.py b/nengo_gui/components/htmlview.py index b7486c79..6c4b3af2 100644 --- a/nengo_gui/components/htmlview.py +++ b/nengo_gui/components/htmlview.py @@ -39,7 +39,7 @@ def update_client(self, client): def javascript(self): info = dict(uid=id(self), label=self.label) json = self.javascript_config(info) - return 'new Nengo.HTMLView(main, sim, %s);' % json + return 'new HTMLView(nengo.main, nengo.viewport, nengo.sim, %s);' % json def code_python_args(self, uids): return [uids[self.obj]] diff --git a/nengo_gui/components/netgraph.py b/nengo_gui/components/netgraph.py index 36500582..5c904133 100644 --- a/nengo_gui/components/netgraph.py +++ b/nengo_gui/components/netgraph.py @@ -393,7 +393,7 @@ def update_client(self, client): self.expand_network(network, client) def javascript(self): - return 'new Nengo.NetGraph(main, {uid:"%s"});' % id(self) + return 'var netgraphargs = {uid:"%s"};' % id(self) def message(self, msg): try: diff --git a/nengo_gui/components/pointer.py b/nengo_gui/components/pointer.py index 44046981..bfe64cc3 100644 --- a/nengo_gui/components/pointer.py +++ b/nengo_gui/components/pointer.py @@ -87,7 +87,7 @@ def update_client(self, client): def javascript(self): info = dict(uid=id(self), label=self.label) json = self.javascript_config(info) - return 'new Nengo.Pointer(main, sim, %s);' % json + return 'new Pointer(nengo.main, nengo.viewport, nengo.sim, %s);' % json def code_python_args(self, uids): return [uids[self.obj], 'target=%r' % self.target] diff --git a/nengo_gui/components/raster.py b/nengo_gui/components/raster.py index 2a2aabaf..8d42e9b6 100644 --- a/nengo_gui/components/raster.py +++ b/nengo_gui/components/raster.py @@ -61,7 +61,7 @@ def javascript(self): info = dict(uid=id(self), label=self.label, max_neurons=self.max_neurons) json = self.javascript_config(info) - return 'new Nengo.Raster(main, sim, %s);' % json + return 'new Raster(nengo.main, nengo.viewport, nengo.sim, %s);' % json def code_python_args(self, uids): return [uids[self.obj.ensemble]] diff --git a/nengo_gui/components/sim_control.py b/nengo_gui/components/sim_control.py index 1df61b3e..a04256d3 100644 --- a/nengo_gui/components/sim_control.py +++ b/nengo_gui/components/sim_control.py @@ -165,8 +165,7 @@ def update_client(self, client): self.last_status = status if self.send_config_options: client.write_text('sims:' + self.backend_options_html()) - client.write_text('config' - 'Nengo.Toolbar.prototype.config_modal_show();') + client.write_text('confignengo.toolbar.config_modal_show();') self.send_config_options = False def get_status(self): @@ -184,9 +183,7 @@ def javascript(self): info = dict(uid=id(self)) fn = json.dumps(self.page.filename) js = self.javascript_config(info) - return ('sim = new Nengo.SimControl(control, %s);\n' - 'toolbar = new Nengo.Toolbar(%s);\n' - 'Nengo.sidemenu = new Nengo.SideMenu();' % (js, fn)) + return ('var simargs = %s;\nvar filename = %s;' % (js, fn)) def message(self, msg): if msg == 'pause': diff --git a/nengo_gui/components/slider.py b/nengo_gui/components/slider.py index 2c507afd..02e4ac20 100644 --- a/nengo_gui/components/slider.py +++ b/nengo_gui/components/slider.py @@ -114,7 +114,7 @@ def javascript(self): label=self.label, start_value=[float(x) for x in self.start_value]) json = self.javascript_config(info) - return 'new Nengo.Slider(main, sim, %s);' % json + return 'new Slider(nengo.main, nengo.viewport, nengo.sim, %s);' % json def update_client(self, client): while len(self.to_client) > 0: diff --git a/nengo_gui/components/spa_similarity.py b/nengo_gui/components/spa_similarity.py index 8433f6dc..a490d636 100644 --- a/nengo_gui/components/spa_similarity.py +++ b/nengo_gui/components/spa_similarity.py @@ -81,7 +81,7 @@ def javascript(self): info = dict(uid=id(self), label=self.label, n_lines=len(self.labels), synapse=0, pointer_labels=self.labels) json = self.javascript_config(info) - return 'new Nengo.SpaSimilarity(main, sim, %s);' % json + return 'new SpaSimilarity(nengo.main, nengo.viewport, nengo.sim, %s);' % json def message(self, msg): """Message receive function for show_pairs toggling and reset""" diff --git a/nengo_gui/components/spike_grid.py b/nengo_gui/components/spike_grid.py index 9c88dce1..142a5ee3 100644 --- a/nengo_gui/components/spike_grid.py +++ b/nengo_gui/components/spike_grid.py @@ -68,7 +68,7 @@ def javascript(self): info = dict(uid=id(self), label=self.label, pixels_x=self.pixels_x, pixels_y=self.pixels_y) json = self.javascript_config(info) - return 'new Nengo.Image(main, sim, %s);' % json + return 'new Image(nengo.main, nengo.viewport, nengo.sim, %s);' % json def code_python_args(self, uids): args = [uids[self.obj]] diff --git a/nengo_gui/components/value.py b/nengo_gui/components/value.py index 90c1311b..364ed95d 100644 --- a/nengo_gui/components/value.py +++ b/nengo_gui/components/value.py @@ -82,9 +82,8 @@ def javascript(self): # generate the javascript that will create the client-side object info = dict(uid=id(self), label=self.label, n_lines=self.n_lines) - json = self.javascript_config(info) - return 'new Nengo.Value(main, sim, %s);' % json + return 'new Value(nengo.main, nengo.viewport, nengo.sim, %s);' % json def code_python_args(self, uids): # generate the list of strings for the .cfg file to save this Component diff --git a/nengo_gui/components/voltage.py b/nengo_gui/components/voltage.py index e9b646af..cf38ecd3 100644 --- a/nengo_gui/components/voltage.py +++ b/nengo_gui/components/voltage.py @@ -56,7 +56,7 @@ def javascript(self): info = dict(uid=id(self), label=self.label, n_lines=self.n_neurons, synapse=0) json = self.javascript_config(info) - return 'new Nengo.Value(main, sim, %s);' % json + return 'new Value(nengo.main, nengo.viewport, nengo.sim, %s);' % json def code_python_args(self, uids): return [uids[self.obj.ensemble]] diff --git a/nengo_gui/components/xyvalue.py b/nengo_gui/components/xyvalue.py index dfdefd4f..89c33a4a 100644 --- a/nengo_gui/components/xyvalue.py +++ b/nengo_gui/components/xyvalue.py @@ -46,7 +46,7 @@ def update_client(self, client): def javascript(self): info = dict(uid=id(self), n_lines=self.n_lines, label=self.label) json = self.javascript_config(info) - return 'new Nengo.XYValue(main, sim, %s);' % json + return 'new XYValue(nengo.main, nengo.viewport, nengo.sim, %s);' % json def code_python_args(self, uids): return [uids[self.obj]] diff --git a/nengo_gui/guibackend.py b/nengo_gui/guibackend.py index 3ed0c1be..a22618a1 100644 --- a/nengo_gui/guibackend.py +++ b/nengo_gui/guibackend.py @@ -197,8 +197,12 @@ def serve_main(self): html = html.decode("utf-8") # fill in the javascript needed and return the complete page - components = page.create_javascript() - data = (html % dict(components=components)).encode('utf-8') + main_components, components = page.create_javascript() + + data = html % dict( + main_components=main_components, components=components) + data = data.encode('utf-8') + return server.HttpResponse(data) def serve_favicon(self): diff --git a/nengo_gui/modal_js.py b/nengo_gui/modal_js.py index d4864438..47d67b51 100644 --- a/nengo_gui/modal_js.py +++ b/nengo_gui/modal_js.py @@ -21,15 +21,15 @@ def infomodal(ng, uid, **args): def add_modal_title_js(title_text): - return 'Nengo.modal.title("%s");' % (title_text) + return 'nengo.modal.title("%s");' % (title_text) def add_modal_footer_js(footer_text): - return 'Nengo.modal.footer("%s");' % (footer_text) + return 'nengo.modal.footer("%s");' % (footer_text) def show_modal_js(): - return 'Nengo.modal.show();' + return 'nengo.modal.show();' def ensemble_infomodal(ng, uid, conn_in_uids, conn_out_uids): @@ -50,11 +50,11 @@ def ensemble_infomodal(ng, uid, conn_in_uids, conn_out_uids): conninfo = conn_infomodal(ng, uid, conn_in_uids, conn_out_uids) - js = ['Nengo.modal.title("Details for \'%s\'");' % ng.page.get_label(ens)] - js.append('Nengo.modal.footer("close");') - js.append('Nengo.modal.ensemble_body("%s", %s, %s, %s);' % ( + js = ['nengo.modal.title("Details for \'%s\'");' % ng.page.get_label(ens)] + js.append('nengo.modal.footer("close");') + js.append('nengo.modal.ensemble_body("%s", %s, %s, %s);' % ( uid, json.dumps(params), json.dumps(plots), json.dumps(conninfo))) - js.append('Nengo.modal.show();') + js.append('nengo.modal.show();') return '\n'.join(js) @@ -71,7 +71,7 @@ def node_infomodal(ng, uid, conn_in_uids, conn_out_uids): js = [add_modal_title_js("Details for \'%s\'" % ( ng.page.get_label(node)))] js.append(add_modal_footer_js('close')) - js.append('Nengo.modal.node_body("%s", %s, %s, %s);' % ( + js.append('nengo.modal.node_body("%s", %s, %s, %s);' % ( uid, json.dumps(params), json.dumps(plots), json.dumps(conninfo))) js.append(show_modal_js()) return '\n'.join(js) @@ -146,7 +146,7 @@ def net_infomodal(ng, uid, conn_in_uids, conn_out_uids): js = [add_modal_title_js("Details for \'%s\'") % ( ng.page.get_label(net))] js.append(add_modal_footer_js('close')) - js.append('Nengo.modal.net_body("%s", %s, %s);' % ( + js.append('nengo.modal.net_body("%s", %s, %s);' % ( uid, json.dumps(stats), json.dumps(conninfo))) js.append(show_modal_js()) return '\n'.join(js) diff --git a/nengo_gui/page.py b/nengo_gui/page.py index 9474164b..5e19a539 100644 --- a/nengo_gui/page.py +++ b/nengo_gui/page.py @@ -323,19 +323,18 @@ def modified_config(self): def create_javascript(self): """Generate the javascript for the current model and layout.""" - if self.filename is not None: - fn = json.dumps(self.filename) - webpage_title_js = ';document.title = %s;' % fn - else: - webpage_title_js = '' - assert isinstance(self.components[0], nengo_gui.components.SimControl) - - component_js = '\n'.join([c.javascript() for c in self.components]) - component_js += webpage_title_js + main = (nengo_gui.components.NetGraph, + nengo_gui.components.SimControl, + nengo_gui.components.AceEditor) + + main_js = '\n'.join([c.javascript() for c in self.components + if isinstance(c, main)]) + component_js = '\n'.join([c.javascript() for c in self.components + if not isinstance(c, main)]) if not self.gui.model_context.writeable: component_js += "$('#Open_file_button').addClass('deactivated');" - return component_js + return main_js, component_js def get_label(self, obj, default_labels=None): """Return a readable label for an object. diff --git a/nengo_gui/static/components/2d_axes.js b/nengo_gui/static/components/2d_axes.js index b63294f7..9f33c0f9 100644 --- a/nengo_gui/static/components/2d_axes.js +++ b/nengo_gui/static/components/2d_axes.js @@ -9,7 +9,10 @@ * @param {float} args.min_value - minimum value on y-axis * @param {float} args.max_value - maximum value on y-axis */ -Nengo.Axes2D = function(parent, args) { + +var d3 = require('d3'); + +var Axes2D = function(parent, args) { var self = this; this.max_y_width = 100; @@ -48,7 +51,7 @@ Nengo.Axes2D = function(parent, args) { .call(this.axis_y); }; -Nengo.Axes2D.prototype.set_axes_geometry = function(width, height) { +Axes2D.prototype.set_axes_geometry = function(width, height) { scale = parseFloat($('#main').css('font-size')); this.width = width; this.height = height; @@ -64,7 +67,7 @@ Nengo.Axes2D.prototype.set_axes_geometry = function(width, height) { /** * Adjust the graph layout due to changed size */ -Nengo.Axes2D.prototype.on_resize = function(width, height) { +Axes2D.prototype.on_resize = function(width, height) { if (width < this.minWidth) { width = this.minWidth; } @@ -90,7 +93,7 @@ Nengo.Axes2D.prototype.on_resize = function(width, height) { this.axis_y_g.call(this.axis_y); }; -Nengo.Axes2D.prototype.fit_ticks = function(parent) { +Axes2D.prototype.fit_ticks = function(parent) { var self = this; setTimeout(function() { var ticks = $(parent.div).find('.tick'); @@ -106,3 +109,5 @@ Nengo.Axes2D.prototype.fit_ticks = function(parent) { self.on_resize(parent.width, parent.height); }, 1); }; + +module.exports = Axes2D; diff --git a/nengo_gui/static/components/component.js b/nengo_gui/static/components/component.js index c8b07e24..4bea95eb 100644 --- a/nengo_gui/static/components/component.js +++ b/nengo_gui/static/components/component.js @@ -17,7 +17,20 @@ * class prototypes (ie. Slider, Value). * */ -Nengo.Component = function(parent, args) { + +var interact = require('interact.js'); +var menu = require('../menu'); +var utils = require('../utils'); + +var all_components = []; + +var save_all_components = function() { + for (var index in all_components) { + all_components[index].save_layout(); + } +}; + +var Component = function(parent, viewport, args) { var self = this; this.viewport = viewport; @@ -59,7 +72,7 @@ Nengo.Component = function(parent, args) { // Move element to be drawn on top when clicked on this.div.onmousedown = function() { - this.style.zIndex = Nengo.next_zindex(); + this.style.zIndex = utils.next_zindex(); }; this.div.ontouchstart = this.div.onmousedown; @@ -69,7 +82,7 @@ Nengo.Component = function(parent, args) { .draggable({ inertia: true, onstart: function() { - self.menu.hide_any(); + menu.hide_any(); }, onmove: function(event) { var target = event.target; @@ -93,7 +106,7 @@ Nengo.Component = function(parent, args) { edges: {left: true, top: true, right: true, bottom: true} }) .on('resizestart', function(event) { - self.menu.hide_any(); + menu.hide_any(); }) .on('resizemove', function(event) { var target = event.target; @@ -121,19 +134,21 @@ Nengo.Component = function(parent, args) { // Open a WebSocket to the server this.uid = args.uid; if (this.uid != undefined) { - this.ws = Nengo.create_websocket(this.uid); - this.ws.onmessage = function(event) {self.on_message(event);}; + this.ws = utils.create_websocket(this.uid); + this.ws.onmessage = function(event) { + self.on_message(event); + }; } // Flag whether there is a scheduled update that hasn't happened yet this.pending_update = false; - this.menu = new Nengo.Menu(self.parent); + this.menu = new menu.Menu(self.parent); interact(this.div) .on('hold', function(event) { // Change to 'tap' for right click if (event.button == 0) { if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } else { self.menu.show(event.clientX, event.clientY, self.generate_menu()); @@ -144,7 +159,7 @@ Nengo.Component = function(parent, args) { .on('tap', function(event) { // Get rid of menus when clicking off if (event.button == 0) { if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } } }); @@ -152,34 +167,26 @@ Nengo.Component = function(parent, args) { event.preventDefault(); event.stopPropagation(); if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } else { - self.menu.show(event.clientX, event.clientY, - self.generate_menu()); + self.menu.show(event.clientX, event.clientY, self.generate_menu()); } }); - Nengo.Component.components.push(this); -}; - -Nengo.Component.components = []; -Nengo.Component.save_components = function() { - for (var index in Nengo.Component.components) { - Nengo.Component.components[index].save_layout(); - } + all_components.push(this); }; /** * Method to be called when Component is resized. */ -Nengo.Component.prototype.on_resize = function(width, height) {}; +Component.prototype.on_resize = function(width, height) {}; /** * Method to be called when Component received a WebSocket message. */ -Nengo.Component.prototype.on_message = function(event) {}; +Component.prototype.on_message = function(event) {}; -Nengo.Component.prototype.generate_menu = function() { +Component.prototype.generate_menu = function() { var self = this; var items = []; if (this.label_visible) { @@ -197,7 +204,7 @@ Nengo.Component.prototype.generate_menu = function() { return items; }; -Nengo.Component.prototype.remove = function(undo_flag, notify_server) { +Component.prototype.remove = function(undo_flag, notify_server) { undo_flag = typeof undo_flag !== 'undefined' ? undo_flag : false; notify_server = typeof notify_server !== 'undefined' ? notify_server : true; @@ -209,8 +216,8 @@ Nengo.Component.prototype.remove = function(undo_flag, notify_server) { } } this.parent.removeChild(this.div); - var index = Nengo.Component.components.indexOf(this); - Nengo.Component.components.splice(index, 1); + var index = all_components.indexOf(this); + all_components.splice(index, 1); }; /** @@ -220,7 +227,7 @@ Nengo.Component.prototype.remove = function(undo_flag, notify_server) { * how fast update() is called in the case that we are changing the data faster * than whatever processing is needed in update(). */ -Nengo.Component.prototype.schedule_update = function(event) { +Component.prototype.schedule_update = function(event) { if (this.pending_update == false) { this.pending_update = true; var self = this; @@ -235,24 +242,24 @@ Nengo.Component.prototype.schedule_update = function(event) { /** * Do any visual updating that is needed due to changes in the underlying data. */ -Nengo.Component.prototype.update = function(event) { +Component.prototype.update = function(event) { }; -Nengo.Component.prototype.hide_label = function(event) { +Component.prototype.hide_label = function(event) { if (this.label_visible) { this.label.style.display = 'none'; this.label_visible = false; } }; -Nengo.Component.prototype.show_label = function(event) { +Component.prototype.show_label = function(event) { if (!this.label_visible) { this.label.style.display = 'inline'; this.label_visible = true; } }; -Nengo.Component.prototype.layout_info = function() { +Component.prototype.layout_info = function() { var info = {}; info.x = this.x; info.y = this.y; @@ -262,12 +269,12 @@ Nengo.Component.prototype.layout_info = function() { return info; }; -Nengo.Component.prototype.save_layout = function() { +Component.prototype.save_layout = function() { var info = this.layout_info(); this.ws.send('config:' + JSON.stringify(info)); }; -Nengo.Component.prototype.update_layout = function(config) { +Component.prototype.update_layout = function(config) { this.w = config.width; this.h = config.height; this.x = config.x; @@ -284,25 +291,28 @@ Nengo.Component.prototype.update_layout = function(config) { } }; -Nengo.Component.prototype.redraw_size = function() { +Component.prototype.redraw_size = function() { this.width = this.viewport.w * this.w * this.viewport.scale * 2; this.height = this.viewport.h * this.h * this.viewport.scale * 2; this.div.style.width = this.width; this.div.style.height = this.height; }; -Nengo.Component.prototype.redraw_pos = function() { +Component.prototype.redraw_pos = function() { var x = (this.x + this.viewport.x - this.w) * this.viewport.w * this.viewport.scale; var y = (this.y + this.viewport.y - this.h) * this.viewport.h * this.viewport.scale; - Nengo.set_transform(this.div, x, y); + utils.set_transform(this.div, x, y); }; -Nengo.Component.prototype.get_screen_width = function() { +Component.prototype.get_screen_width = function() { return this.viewport.w * this.w * this.viewport.scale * 2; }; - -Nengo.Component.prototype.get_screen_height = function() { +Component.prototype.get_screen_height = function() { return this.viewport.h * this.h * this.viewport.scale * 2; }; + +module.exports.Component = Component; +module.exports.all_components = all_components; +module.exports.save_all_components = save_all_components; diff --git a/nengo_gui/static/components/htmlview.js b/nengo_gui/static/components/htmlview.js index c318a396..7906106b 100644 --- a/nengo_gui/static/components/htmlview.js +++ b/nengo_gui/static/components/htmlview.js @@ -4,11 +4,16 @@ * * @constructor * @param {DOMElement} parent - the element to add this component to - * @param {Nengo.SimControl} sim - the simulation controller - * @param {dict} args - A set of constructor arguments (see Nengo.Component) + * @param {SimControl} sim - the simulation controller + * @param {dict} args - A set of constructor arguments (see Component) */ -Nengo.HTMLView = function(parent, sim, args) { - Nengo.Component.call(this, parent, args); + +var Component = require('./component').Component; +var DataStore = require('../datastore').DataStore; +var utils = require('../utils'); + +var HTMLView = function(parent, viewport, sim, args) { + Component.call(this, parent, viewport, args); var self = this; this.sim = sim; @@ -16,13 +21,13 @@ Nengo.HTMLView = function(parent, sim, args) { this.pdiv = document.createElement('div'); this.pdiv.style.width = '100%'; this.pdiv.style.height = '100%'; - Nengo.set_transform(this.pdiv, 0, 0); + utils.set_transform(this.pdiv, 0, 0); this.pdiv.style.position = 'fixed'; this.pdiv.classList.add('htmlview'); this.div.appendChild(this.pdiv); // For storing the accumulated data. - this.data_store = new Nengo.DataStore(1, this.sim, 0); + this.data_store = new DataStore(1, this.sim, 0); // Call schedule_update whenever the time is adjusted in the SimControl this.sim.div.addEventListener('adjust_time', @@ -31,13 +36,13 @@ Nengo.HTMLView = function(parent, sim, args) { this.on_resize(this.get_screen_width(), this.get_screen_height()); }; -Nengo.HTMLView.prototype = Object.create(Nengo.Component.prototype); -Nengo.HTMLView.prototype.constructor = Nengo.HTMLView; +HTMLView.prototype = Object.create(Component.prototype); +HTMLView.prototype.constructor = HTMLView; /** * Receive new line data from the server */ -Nengo.HTMLView.prototype.on_message = function(event) { +HTMLView.prototype.on_message = function(event) { var data = event.data.split(" ", 1); var time = parseFloat(data[0]); @@ -50,7 +55,7 @@ Nengo.HTMLView.prototype.on_message = function(event) { /** * Redraw the lines and axis due to changed data */ -Nengo.HTMLView.prototype.update = function() { +HTMLView.prototype.update = function() { // Let the data store clear out old values this.data_store.update(); @@ -67,7 +72,7 @@ Nengo.HTMLView.prototype.update = function() { /** * Adjust the graph layout due to changed size */ -Nengo.HTMLView.prototype.on_resize = function(width, height) { +HTMLView.prototype.on_resize = function(width, height) { if (width < this.minWidth) { width = this.minWidth; } @@ -81,3 +86,5 @@ Nengo.HTMLView.prototype.on_resize = function(width, height) { this.update(); }; + +module.exports = HTMLView; diff --git a/nengo_gui/static/components/image.js b/nengo_gui/static/components/image.js index 96ab4f61..c2d9487f 100644 --- a/nengo_gui/static/components/image.js +++ b/nengo_gui/static/components/image.js @@ -3,16 +3,21 @@ * * @constructor * @param {DOMElement} parent - the element to add this component to - * @param {Nengo.SimControl} sim - the simulation controller - * @param {dict} args - A set of constructor arguments (see Nengo.Component) + * @param {SimControl} sim - the simulation controller + * @param {dict} args - A set of constructor arguments (see Component) * @param {int} args.n_lines - number of decoded values * @param {float} args.miny - minimum value on y-axis * @param {float} args.maxy - maximum value on y-axis */ -Nengo.Image = function(parent, sim, args) { + +var d3 = require('d3'); +var Component = require('./component').Component; +var DataStore = require('../datastore').DataStore; + +var Image = function(parent, viewport, sim, args) { var self = this; - Nengo.Component.call(self, parent, args); + Component.call(self, parent, viewport, args); self.sim = sim; self.display_time = args.display_time; self.pixels_x = args.pixels_x; @@ -20,7 +25,7 @@ Nengo.Image = function(parent, sim, args) { self.n_pixels = self.pixels_x * self.pixels_y; // For storing the accumulated data - self.data_store = new Nengo.DataStore(self.n_pixels, self.sim, 0); + self.data_store = new DataStore(self.n_pixels, self.sim, 0); // Draw the plot as an SVG self.svg = d3.select(self.div).append('svg') @@ -54,13 +59,13 @@ Nengo.Image = function(parent, sim, args) { }; -Nengo.Image.prototype = Object.create(Nengo.Component.prototype); -Nengo.Image.prototype.constructor = Nengo.Image; +Image.prototype = Object.create(Component.prototype); +Image.prototype.constructor = Image; /** * Receive new line data from the server */ -Nengo.Image.prototype.on_message = function(event) { +Image.prototype.on_message = function(event) { var data = new Uint8Array(event.data); var msg_size = this.n_pixels + 4; @@ -76,7 +81,7 @@ Nengo.Image.prototype.on_message = function(event) { /** * Redraw the lines and axis due to changed data */ -Nengo.Image.prototype.update = function() { +Image.prototype.update = function() { var self = this; // Let the data store clear out old values @@ -100,7 +105,7 @@ Nengo.Image.prototype.update = function() { /** * Adjust the graph layout due to changed size */ -Nengo.Image.prototype.on_resize = function(width, height) { +Image.prototype.on_resize = function(width, height) { var self = this; if (width < self.minWidth) { width = self.minWidth; @@ -122,3 +127,5 @@ Nengo.Image.prototype.on_resize = function(width, height) { self.div.style.width = width; self.div.style.height = height; }; + +module.exports = Image; diff --git a/nengo_gui/static/components/netgraph.js b/nengo_gui/static/components/netgraph.js index ad801416..80e31f18 100644 --- a/nengo_gui/static/components/netgraph.js +++ b/nengo_gui/static/components/netgraph.js @@ -9,7 +9,21 @@ * NetGraph constructor is written into HTML file from the python * server and is run on page load. */ -Nengo.NetGraph = function(parent, args) { + +var interact = require('interact.js'); +require('./netgraph.css'); +var comp = require('./component'); +var menu = require('../menu'); +var NetGraphConnection = require('./netgraph_conn'); +var NetGraphItem = require('./netgraph_item'); +var utils = require('../utils'); +var Viewport = require('../viewport'); + +var NetGraph = function(parent, config, args) { + var self = this; + this.config = config; + this.viewport = new Viewport(this); + if (args.uid[0] === '<') { console.log("invalid uid for NetGraph: " + args.uid); } @@ -30,21 +44,21 @@ Nengo.NetGraph = function(parent, args) { this.update_fonts(); this.redraw(); - viewport.scale = scale; - viewport.redraw_all(); + self.viewport.scale = scale; + self.viewport.redraw_all(); } }); Object.defineProperty(this, 'zoom_fonts', { // Scale fonts when zooming get: function() { - return Nengo.config.zoom_fonts; + return self.config.zoom_fonts; }, set: function(val) { if (val === this.zoom_fonts) { return; } - Nengo.config.zoom_fonts = val; + self.config.zoom_fonts = val; this.update_fonts(); } }); @@ -52,25 +66,26 @@ Nengo.NetGraph = function(parent, args) { Object.defineProperty(this, 'aspect_resize', { // Preserve aspect ratios on window resize get: function() { - return Nengo.config.aspect_resize; + return self.config.aspect_resize; }, set: function(val) { if (val === this.aspect_resize) { return; } - Nengo.config.aspect_resize = val; + self.config.aspect_resize = val; + } }); Object.defineProperty(this, 'font_size', { get: function() { - return Nengo.config.font_size; + return self.config.font_size; }, set: function(val) { if (val === this.font_size) { return; } - Nengo.config.font_size = val; + self.config.font_size = val; this.update_fonts(); } }); @@ -78,13 +93,13 @@ Nengo.NetGraph = function(parent, args) { // Do networks have transparent backgrounds? Object.defineProperty(this, 'transparent_nets', { get: function() { - return Nengo.config.transparent_nets; + return self.config.transparent_nets; }, set: function(val) { if (val === this.transparent_nets) { return; } - Nengo.config.transparent_nets = val; + self.config.transparent_nets = val; for (var key in this.svg_objects) { var ngi = this.svg_objects[key]; ngi.compute_fill(); @@ -96,8 +111,8 @@ Nengo.NetGraph = function(parent, args) { } }); - this.svg_objects = {}; // Dict of all Nengo.NetGraphItems, by uid - this.svg_conns = {}; // Dict of all Nengo.NetGraphConnections, by uid + this.svg_objects = {}; // Dict of all NetGraphItems, by uid + this.svg_conns = {}; // Dict of all NetGraphConnections, by uid this.minimap_objects = {}; this.minimap_conns = {}; @@ -114,7 +129,7 @@ Nengo.NetGraph = function(parent, args) { // are inside a collapsed network), this dictionary keeps a list of // connections to be notified when a particular item appears. The // key in the dictionary is the uid of the nonexistent item, and the - // value is a list of Nengo.NetGraphConnections that should be notified + // value is a list of NetGraphConnections that should be notified // when that item appears. this.collapsed_conns = {}; @@ -128,7 +143,6 @@ Nengo.NetGraph = function(parent, args) { interact(this.svg).styleCursor(false); - Nengo.netgraph = this; parent.appendChild(this.svg); this.parent = parent; @@ -163,7 +177,7 @@ Nengo.NetGraph = function(parent, args) { this.svg.insertBefore(defs, this.svg.firstChild); // Connect to server - this.ws = Nengo.create_websocket(args.uid); + this.ws = utils.create_websocket(args.uid); this.ws.onmessage = function(event) { self.on_message(event); }; @@ -198,7 +212,7 @@ Nengo.NetGraph = function(parent, args) { interact(this.svg) .draggable({ onstart: function() { - self.menu.hide_any(); + menu.hide_any(); }, onmove: function(event) { self.offsetX += event.dx / self.get_scaled_width(); @@ -213,9 +227,9 @@ Nengo.NetGraph = function(parent, args) { self.svg_conns[key].redraw(); } - viewport.x = self.offsetX; - viewport.y = self.offsetY; - viewport.redraw_all(); + self.viewport.x = self.offsetX; + self.viewport.y = self.offsetY; + self.viewport.redraw_all(); self.scaleMiniMapViewBox(); @@ -235,7 +249,7 @@ Nengo.NetGraph = function(parent, args) { .on('wheel', function(event) { event.preventDefault(); - self.menu.hide_any(); + menu.hide_any(); var x = (event.clientX) / self.width; var y = (event.clientY - self.tool_height) / self.height; @@ -263,7 +277,7 @@ Nengo.NetGraph = function(parent, args) { scale = 1. / scale; } - Nengo.Component.save_components(); + comp.save_all_components(); var xx = x / self.scale - self.offsetX; var yy = y / self.scale - self.offsetY; @@ -271,9 +285,9 @@ Nengo.NetGraph = function(parent, args) { self.offsetY = (self.offsetY + yy) / scale - yy; self.scale = scale * self.scale; - viewport.x = self.offsetX; - viewport.y = self.offsetY; - viewport.redraw_all(); + self.viewport.x = self.offsetX; + self.viewport.y = self.offsetY; + self.viewport.redraw_all(); self.scaleMiniMapViewBox(); @@ -285,14 +299,14 @@ Nengo.NetGraph = function(parent, args) { }); }); - this.menu = new Nengo.Menu(self.parent); + this.menu = new menu.Menu(self.parent); // Determine when to pull up the menu interact(this.svg) .on('hold', function(event) { // Change to 'tap' for right click if (event.button == 0) { if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } else { self.menu.show(event.clientX, event.clientY, self.generate_menu()); @@ -303,7 +317,7 @@ Nengo.NetGraph = function(parent, args) { .on('tap', function(event) { // Get rid of menus when clicking off if (event.button == 0) { if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } } }); @@ -311,16 +325,17 @@ Nengo.NetGraph = function(parent, args) { $(this.svg).bind('contextmenu', function(event) { event.preventDefault(); if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } else { self.menu.show(event.clientX, event.clientY, self.generate_menu()); } }); this.create_minimap(); + this.update_fonts(); }; -Nengo.NetGraph.prototype.generate_menu = function() { +NetGraph.prototype.generate_menu = function() { var self = this; var items = []; items.push(['Auto-layout', function() { @@ -332,7 +347,7 @@ Nengo.NetGraph.prototype.generate_menu = function() { /** * Event handler for received WebSocket messages */ -Nengo.NetGraph.prototype.on_message = function(event) { +NetGraph.prototype.on_message = function(event) { data = JSON.parse(event.data); if (data.type === 'net') { this.create_object(data); @@ -366,9 +381,9 @@ Nengo.NetGraph.prototype.on_message = function(event) { } else if (data.type === 'config') { // Anything about the config of a component has changed var uid = data.uid; - for (var i = 0; i < Nengo.Component.components.length; i++) { - if (Nengo.Component.components[i].uid === uid) { - Nengo.Component.components[i].update_layout(data.config); + for (var i = 0; i < comp.all_components.length; i++) { + if (comp.all_components[i].uid === uid) { + comp.all_components[i].update_layout(data.config); break; } } @@ -395,9 +410,9 @@ Nengo.NetGraph.prototype.on_message = function(event) { } else if (data.type === 'delete_graph') { var uid = data.uid; - for (var i = 0; i < Nengo.Component.components.length; i++) { - if (Nengo.Component.components[i].uid === uid) { - Nengo.Component.components[i].remove(true, data.notify_server); + for (var i = 0; i < comp.all_components.length; i++) { + if (comp.all_components[i].uid === uid) { + comp.all_components[i].remove(true, data.notify_server); break; } } @@ -410,24 +425,24 @@ Nengo.NetGraph.prototype.on_message = function(event) { /** * Report an event back to the server */ -Nengo.NetGraph.prototype.notify = function(info) { +NetGraph.prototype.notify = function(info) { this.ws.send(JSON.stringify(info)); }; /** * Pan the screen (and redraw accordingly) */ -Nengo.NetGraph.prototype.set_offset = function(x, y) { +NetGraph.prototype.set_offset = function(x, y) { this.offsetX = x; this.offsetY = y; this.redraw(); - viewport.x = x; - viewport.y = y; - viewport.redraw_all(); + this.viewport.x = x; + this.viewport.y = y; + this.viewport.redraw_all(); }; -Nengo.NetGraph.prototype.update_fonts = function() { +NetGraph.prototype.update_fonts = function() { if (this.zoom_fonts) { $('#main').css('font-size', 3 * this.scale * this.font_size/100 + 'em'); } else { @@ -438,7 +453,7 @@ Nengo.NetGraph.prototype.update_fonts = function() { /** * Redraw all elements */ -Nengo.NetGraph.prototype.redraw = function() { +NetGraph.prototype.redraw = function() { for (var key in this.svg_objects) { this.svg_objects[key].redraw(); } @@ -450,7 +465,7 @@ Nengo.NetGraph.prototype.redraw = function() { /** * Helper function for correctly creating SVG elements. */ -Nengo.NetGraph.prototype.createSVGElement = function(tag) { +NetGraph.prototype.createSVGElement = function(tag) { return document.createElementNS("http://www.w3.org/2000/svg", tag); }; @@ -460,11 +475,11 @@ Nengo.NetGraph.prototype.createSVGElement = function(tag) { * If an existing NetGraphConnection is looking for this item, it will be * notified */ -Nengo.NetGraph.prototype.create_object = function(info) { - var item_mini = new Nengo.NetGraphItem(this, info, true); +NetGraph.prototype.create_object = function(info) { + var item_mini = new NetGraphItem(this, info, true); this.minimap_objects[info.uid] = item_mini; - var item = new Nengo.NetGraphItem(this, info, false, item_mini); + var item = new NetGraphItem(this, info, false, item_mini); this.svg_objects[info.uid] = item; this.detect_collapsed_conns(item.uid); @@ -476,19 +491,18 @@ Nengo.NetGraph.prototype.create_object = function(info) { /** * Create a new NetGraphConnection. */ -Nengo.NetGraph.prototype.create_connection = function(info) { - var conn_mini = new Nengo.NetGraphConnection(this, info, true); +NetGraph.prototype.create_connection = function(info) { + var conn_mini = new NetGraphConnection(this, info, true); this.minimap_conns[info.uid] = conn_mini; - var conn = new Nengo.NetGraphConnection(this, info, false, conn_mini); + var conn = new NetGraphConnection(this, info, false, conn_mini); this.svg_conns[info.uid] = conn; }; /** * Handler for resizing the full SVG. */ -Nengo.NetGraph.prototype.on_resize = function(event) { - +NetGraph.prototype.on_resize = function(event) { var width = $(this.svg).width(); var height = $(this.svg).height(); @@ -515,21 +529,21 @@ Nengo.NetGraph.prototype.on_resize = function(event) { /** * Return the pixel width of the SVG times the current scale factor. */ -Nengo.NetGraph.prototype.get_scaled_width = function() { +NetGraph.prototype.get_scaled_width = function() { return this.width * this.scale; }; /** * Return the pixel height of the SVG times the current scale factor. */ -Nengo.NetGraph.prototype.get_scaled_height = function() { +NetGraph.prototype.get_scaled_height = function() { return this.height * this.scale; }; /** * Expand or collapse a network. */ -Nengo.NetGraph.prototype.toggle_network = function(uid) { +NetGraph.prototype.toggle_network = function(uid) { var item = this.svg_objects[uid]; if (item.expanded) { item.collapse(true); @@ -545,7 +559,7 @@ Nengo.NetGraph.prototype.toggle_network = function(uid) { * collapsed network. When it does appear, NetGraph.detect_collapsed will * handle notifying the NetGraphConnection. */ -Nengo.NetGraph.prototype.register_conn = function(conn, target) { +NetGraph.prototype.register_conn = function(conn, target) { if (this.collapsed_conns[target] === undefined) { this.collapsed_conns[target] = [conn]; } else { @@ -565,7 +579,7 @@ Nengo.NetGraph.prototype.register_conn = function(conn, target) { * an item is created, this function is used to see if any * NetGraphConnections are waiting for it, and notifies them. */ -Nengo.NetGraph.prototype.detect_collapsed_conns = function(uid) { +NetGraph.prototype.detect_collapsed_conns = function(uid) { var conns = this.collapsed_conns[uid]; if (conns !== undefined) { delete this.collapsed_conns[uid]; @@ -585,7 +599,7 @@ Nengo.NetGraph.prototype.detect_collapsed_conns = function(uid) { /** * Create a minimap. */ -Nengo.NetGraph.prototype.create_minimap = function() { +NetGraph.prototype.create_minimap = function() { var self = this; this.minimap_div = document.createElement('div'); @@ -618,7 +632,7 @@ Nengo.NetGraph.prototype.create_minimap = function() { this.toggleMiniMap(); }; -Nengo.NetGraph.prototype.toggleMiniMap = function() { +NetGraph.prototype.toggleMiniMap = function() { if (this.mm_display == true) { $('.minimap')[0].style.visibility = 'hidden'; this.g_conns_mini.style.opacity = 0; @@ -634,7 +648,7 @@ Nengo.NetGraph.prototype.toggleMiniMap = function() { /** * Calculate the minimap position offsets and scaling. */ -Nengo.NetGraph.prototype.scaleMiniMap = function() { +NetGraph.prototype.scaleMiniMap = function() { if (!this.mm_display) { return; } @@ -702,7 +716,7 @@ Nengo.NetGraph.prototype.scaleMiniMap = function() { * Calculate which part of the map is being displayed on the * main viewport and scale the viewbox to reflect that. */ -Nengo.NetGraph.prototype.scaleMiniMapViewBox = function() { +NetGraph.prototype.scaleMiniMapViewBox = function() { if (!this.mm_display) { return; } @@ -726,3 +740,5 @@ Nengo.NetGraph.prototype.scaleMiniMapViewBox = function() { this.view.setAttribute('width', w / this.scale); this.view.setAttribute('height', h / this.scale); }; + +module.exports = NetGraph; diff --git a/nengo_gui/static/components/netgraph_conn.js b/nengo_gui/static/components/netgraph_conn.js index b7fe06ef..f82a12fa 100644 --- a/nengo_gui/static/components/netgraph_conn.js +++ b/nengo_gui/static/components/netgraph_conn.js @@ -2,7 +2,7 @@ * Network diagram connection line. * * @constructor - * @param {Nengo.NetGraph} ng - The containing Nengo.NetGraph + * @param {NetGraph} ng - The containing NetGraph * @param {dict} info - A set of constructor arguments, including: * @param {string} info.uid - A unique identifier * @param {string|null} info.parent - A containing NetGraphItem @@ -10,7 +10,7 @@ * @param {string[]} info.post - uid to connect to and its parents */ -Nengo.NetGraphConnection = function(ng, info, minimap, mini_conn) { +var NetGraphConnection = function(ng, info, minimap, mini_conn) { this.ng = ng; this.uid = info.uid; @@ -67,7 +67,7 @@ Nengo.NetGraphConnection = function(ng, info, minimap, mini_conn) { this.g_conns.appendChild(this.g); }; -Nengo.NetGraphConnection.prototype.set_recurrent = function(recurrent) { +NetGraphConnection.prototype.set_recurrent = function(recurrent) { if (this.recurrent === recurrent) { return; } @@ -76,7 +76,7 @@ Nengo.NetGraphConnection.prototype.set_recurrent = function(recurrent) { this.create_line(); }; -Nengo.NetGraphConnection.prototype.create_line = function() { +NetGraphConnection.prototype.create_line = function() { if (this.recurrent) { this.recurrent_ellipse = this.ng.createSVGElement('path'); this.recurrent_ellipse.setAttribute( @@ -109,7 +109,7 @@ Nengo.NetGraphConnection.prototype.create_line = function() { } }; -Nengo.NetGraphConnection.prototype.remove_line = function() { +NetGraphConnection.prototype.remove_line = function() { if (this.recurrent) { this.g.removeChild(this.recurrent_ellipse); this.g.removeChild(this.marker); @@ -126,7 +126,7 @@ Nengo.NetGraphConnection.prototype.remove_line = function() { /** * Set the item connecting from. */ -Nengo.NetGraphConnection.prototype.set_pre = function(pre) { +NetGraphConnection.prototype.set_pre = function(pre) { if (this.pre !== null) { // If we're currently connected, disconnect var index = this.pre.conn_out.indexOf(this); @@ -145,7 +145,7 @@ Nengo.NetGraphConnection.prototype.set_pre = function(pre) { /** * Set the item connecting to. */ -Nengo.NetGraphConnection.prototype.set_post = function(post) { +NetGraphConnection.prototype.set_post = function(post) { if (this.post !== null) { // If we're currently connected, disconnect var index = this.post.conn_in.indexOf(this); @@ -164,7 +164,7 @@ Nengo.NetGraphConnection.prototype.set_post = function(post) { /** * Determine the best available item to connect from. */ -Nengo.NetGraphConnection.prototype.find_pre = function() { +NetGraphConnection.prototype.find_pre = function() { for (var i in this.pres) { var pre = this.objects[this.pres[i]]; if (pre !== undefined) { @@ -180,7 +180,7 @@ Nengo.NetGraphConnection.prototype.find_pre = function() { /** * Determine the best available item to connect to. */ -Nengo.NetGraphConnection.prototype.find_post = function() { +NetGraphConnection.prototype.find_post = function() { for (var i in this.posts) { var post = this.objects[this.posts[i]]; if (post !== undefined) { @@ -193,7 +193,7 @@ Nengo.NetGraphConnection.prototype.find_post = function() { return null; }; -Nengo.NetGraphConnection.prototype.set_pres = function(pres) { +NetGraphConnection.prototype.set_pres = function(pres) { this.pres = pres; this.set_pre(this.find_pre()); @@ -202,7 +202,7 @@ Nengo.NetGraphConnection.prototype.set_pres = function(pres) { } }; -Nengo.NetGraphConnection.prototype.set_posts = function(posts) { +NetGraphConnection.prototype.set_posts = function(posts) { this.posts = posts; this.set_post(this.find_post()); @@ -214,7 +214,7 @@ Nengo.NetGraphConnection.prototype.set_posts = function(posts) { /** * Remove this connection. */ -Nengo.NetGraphConnection.prototype.remove = function() { +NetGraphConnection.prototype.remove = function() { if (!this.minimap && this.parent !== null) { var index = this.parent.child_connections.indexOf(this); if (index === -1) { @@ -252,7 +252,7 @@ Nengo.NetGraphConnection.prototype.remove = function() { /** * Redraw the connection. */ -Nengo.NetGraphConnection.prototype.redraw = function() { +NetGraphConnection.prototype.redraw = function() { if (this.pre === null || this.post === null) { if (this.line !== undefined) { this.line.setAttribute('visibility', 'hidden'); @@ -366,7 +366,7 @@ Nengo.NetGraphConnection.prototype.redraw = function() { * @param {number} alpha - the angle between zero and the top right corner * of the object **/ -Nengo.NetGraphConnection.prototype.intersect_length = function( +NetGraphConnection.prototype.intersect_length = function( theta, alpha, width, height) { var quad = 0; var beta = 2 * (Math.PI/2 - alpha); // Angle between top corners @@ -393,3 +393,5 @@ Nengo.NetGraphConnection.prototype.intersect_length = function( return [x, y]; }; + +module.exports = NetGraphConnection; diff --git a/nengo_gui/static/components/netgraph_item.js b/nengo_gui/static/components/netgraph_item.js index 2855b2c9..efd89e80 100644 --- a/nengo_gui/static/components/netgraph_item.js +++ b/nengo_gui/static/components/netgraph_item.js @@ -2,7 +2,7 @@ * Network diagram individual item (node). * * @constructor - * @param {Nengo.NetGraph} ng - The Nengo.NetGraph this Item is inside + * @param {NetGraph} ng - The NetGraph this Item is inside * @param {dict} info - A dictionary of settings for the item, including: * @param {float[]} info.pos - x,y position * @param {float[]} info.size - half width, half height of item @@ -11,7 +11,10 @@ * @param {string|null} info.parent - a NetGraphItem with .type=='net' */ -Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { +var interact = require('interact.js'); +var menu = require('../menu'); + +var NetGraphItem = function(ng, info, minimap, mini_item) { var self = this; this.ng = ng; @@ -26,12 +29,12 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { this.minimap = minimap; this.html_node = info.html; if (minimap == false) { - this.g_networks = ng.g_networks; - this.g_items = ng.g_items; + this.g_networks = this.ng.g_networks; + this.g_items = this.ng.g_items; this.mini_item = mini_item; } else { - this.g_networks = ng.g_networks_mini; - this.g_items = ng.g_items_mini; + this.g_networks = this.ng.g_networks_mini; + this.g_items = this.ng.g_items_mini; } var width = info.size[0]; @@ -109,7 +112,7 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { this.parent = null; this.depth = 1; } else { - this.parent = ng.svg_objects[info.parent]; + this.parent = self.ng.svg_objects[info.parent]; this.depth = this.parent.depth + 1; if (!minimap) { this.parent.children.push(this); @@ -125,7 +128,7 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { this.area = this.ng.createSVGElement('rect'); this.area.style.fill = 'transparent'; - this.menu = new Nengo.Menu(this.ng.parent); + this.menu = new menu.Menu(this.ng.parent); // Different types use different SVG elements for display if (info.type === 'node') { @@ -171,39 +174,39 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { if (!this.minimap) { // Dragging an item to change its position var uid = this.uid; - interact(g) - .draggable({ - onstart: function() { - self.menu.hide_any(); - self.move_to_front(); - }, - onmove: function(event) { - var w = self.ng.get_scaled_width(); - var h = self.ng.get_scaled_height(); - var item = self.ng.svg_objects[uid]; - var parent = item.parent; - while (parent !== null) { - w = w * parent.width * 2; - h = h * parent.height * 2; - parent = parent.parent; - } - item.x += event.dx / w; - item.y += event.dy / h; - item.redraw(); + interact(g).draggable({ + onstart: function() { + menu.hide_any(); + self.move_to_front(); + }, + onmove: function(event) { + var w = self.ng.get_scaled_width(); + var h = self.ng.get_scaled_height(); + var item = self.ng.svg_objects[uid]; + var parent = item.parent; + while (parent !== null) { + w = w * parent.width * 2; + h = h * parent.height * 2; + parent = parent.parent; + } + item.x += event.dx / w; + item.y += event.dy / h; + item.redraw(); - if (self.depth === 1) { - self.ng.scaleMiniMap(); - } - }, - onend: function(event) { - var item = self.ng.svg_objects[uid]; - item.constrain_position(); - self.ng.notify({ - act: "pos", uid: uid, x: item.x, y: item.y - }); + if (self.depth === 1) { + self.ng.scaleMiniMap(); + } + }, + onend: function(event) { + var item = self.ng.svg_objects[uid]; + item.constrain_position(); + self.ng.notify({ + act: "pos", uid: uid, x: item.x, y: item.y + }); - item.redraw(); - }}); + item.redraw(); + } + }); if (!this.passthrough) { // Dragging the edge of item to change its size @@ -215,7 +218,7 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { edges: {left: true, right: true, bottom: true, top: true}, invert: this.type == 'ens' ? 'reposition' : 'none' }).on('resizestart', function(event) { - self.menu.hide_any(); + menu.hide_any(); }).on('resizemove', function(event) { var item = self.ng.svg_objects[uid]; var pos = item.get_screen_location(); @@ -305,7 +308,7 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { // Change to 'tap' for right click if (event.button == 0) { if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } else { self.menu.show(event.clientX, event.clientY, @@ -318,7 +321,7 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { // Get rid of menus when clicking off if (event.button == 0) { if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } } }) @@ -326,7 +329,7 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { // Get rid of menus when clicking off if (event.button == 0) { if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } else if (self.type === 'net') { if (self.expanded) { self.collapse(true); @@ -340,10 +343,10 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { event.preventDefault(); event.stopPropagation(); if (self.menu.visible_any()) { - self.menu.hide_any(); + menu.hide_any(); } else { - self.menu.show(event.clientX, event.clientY, - self.generate_menu()); + self.menu.show( + event.clientX, event.clientY, self.generate_menu()); } }); @@ -357,11 +360,11 @@ Nengo.NetGraphItem = function(ng, info, minimap, mini_item) { }; }; -Nengo.NetGraphItem.prototype.set_label = function(label) { +NetGraphItem.prototype.set_label = function(label) { this.label.innerHTML = label; }; -Nengo.NetGraphItem.prototype.move_to_front = function() { +NetGraphItem.prototype.move_to_front = function() { this.g.parentNode.appendChild(this.g); for (var item in this.children) { @@ -369,7 +372,7 @@ Nengo.NetGraphItem.prototype.move_to_front = function() { } }; -Nengo.NetGraphItem.prototype.generate_menu = function() { +NetGraphItem.prototype.generate_menu = function() { var self = this; var items = []; if (this.type === 'net') { @@ -445,7 +448,7 @@ Nengo.NetGraphItem.prototype.generate_menu = function() { return items; }; -Nengo.NetGraphItem.prototype.create_graph = function(type, args) { +NetGraphItem.prototype.create_graph = function(type, args) { var info = {}; info.act = 'create_graph'; info.type = type; @@ -454,11 +457,13 @@ Nengo.NetGraphItem.prototype.create_graph = function(type, args) { var pos = this.get_screen_location(); - info.x = pos[0] / (viewport.w * viewport.scale) - viewport.x + w; - info.y = pos[1] / (viewport.h * viewport.scale) - viewport.y + h; + info.x = pos[0] / (this.ng.viewport.w * this.ng.viewport.scale) - + this.ng.viewport.x + w; + info.y = pos[1] / (this.ng.viewport.h * this.ng.viewport.scale) - + this.ng.viewport.y + h; - info.width = 100 / (viewport.w * viewport.scale); - info.height = 100 / (viewport.h * viewport.scale); + info.width = 100 / (this.ng.viewport.w * this.ng.viewport.scale); + info.height = 100 / (this.ng.viewport.h * this.ng.viewport.scale); if (info.type == 'Slider') { info.width /= 2; @@ -471,7 +476,7 @@ Nengo.NetGraphItem.prototype.create_graph = function(type, args) { this.ng.notify(info); }; -Nengo.NetGraphItem.prototype.create_modal = function() { +NetGraphItem.prototype.create_modal = function() { var info = {}; info.act = 'create_modal'; info.uid = this.uid; @@ -484,14 +489,14 @@ Nengo.NetGraphItem.prototype.create_modal = function() { this.ng.notify(info); }; -Nengo.NetGraphItem.prototype.request_feedforward_layout = function() { +NetGraphItem.prototype.request_feedforward_layout = function() { this.ng.notify({act: "feedforward_layout", uid: this.uid}); }; /** * Expand a collapsed network. */ -Nengo.NetGraphItem.prototype.expand = function(rts, auto) { +NetGraphItem.prototype.expand = function(rts, auto) { // Default to true if no parameter is specified rts = typeof rts !== 'undefined' ? rts : true; auto = typeof auto !== 'undefined' ? auto : false; @@ -523,7 +528,7 @@ Nengo.NetGraphItem.prototype.expand = function(rts, auto) { } }; -Nengo.NetGraphItem.prototype.set_label_below = function(flag) { +NetGraphItem.prototype.set_label_below = function(flag) { if (flag && !this.label_below) { var screen_h = this.get_screen_height(); this.label.setAttribute( @@ -536,7 +541,7 @@ Nengo.NetGraphItem.prototype.set_label_below = function(flag) { /** * Collapse an expanded network. */ -Nengo.NetGraphItem.prototype.collapse = function(report_to_server, auto) { +NetGraphItem.prototype.collapse = function(report_to_server, auto) { auto = typeof auto !== 'undefined' ? auto : false; this.g.classList.remove('expanded'); @@ -576,7 +581,7 @@ Nengo.NetGraphItem.prototype.collapse = function(report_to_server, auto) { /** * Determine the fill color based on the depth. */ -Nengo.NetGraphItem.prototype.compute_fill = function() { +NetGraphItem.prototype.compute_fill = function() { var depth = this.ng.transparent_nets ? 1 : this.depth; if (!this.passthrough) { @@ -591,7 +596,7 @@ Nengo.NetGraphItem.prototype.compute_fill = function() { /** * Remove the item from the graph. */ -Nengo.NetGraphItem.prototype.remove = function() { +NetGraphItem.prototype.remove = function() { if (this.expanded) { // Collapse the item, but don't tell the server since that would // update the server's config @@ -631,11 +636,11 @@ Nengo.NetGraphItem.prototype.remove = function() { } }; -Nengo.NetGraphItem.prototype.constrain_aspect = function() { +NetGraphItem.prototype.constrain_aspect = function() { this.size = this.get_displayed_size(); }; -Nengo.NetGraphItem.prototype.get_displayed_size = function() { +NetGraphItem.prototype.get_displayed_size = function() { if (this.aspect !== null) { var h_scale = this.ng.get_scaled_width(); var v_scale = this.ng.get_scaled_height(); @@ -654,7 +659,7 @@ Nengo.NetGraphItem.prototype.get_displayed_size = function() { } }; -Nengo.NetGraphItem.prototype.constrain_position = function() { +NetGraphItem.prototype.constrain_position = function() { this.constrain_aspect(); if (this.parent !== null) { @@ -669,7 +674,7 @@ Nengo.NetGraphItem.prototype.constrain_position = function() { } }; -Nengo.NetGraphItem.prototype.redraw_position = function() { +NetGraphItem.prototype.redraw_position = function() { var screen = this.get_screen_location(); // Update my position @@ -677,7 +682,7 @@ Nengo.NetGraphItem.prototype.redraw_position = function() { screen[1] + ')'); }; -Nengo.NetGraphItem.prototype.redraw_children = function() { +NetGraphItem.prototype.redraw_children = function() { // Update any children's positions for (var i in this.children) { var item = this.children[i]; @@ -685,7 +690,7 @@ Nengo.NetGraphItem.prototype.redraw_children = function() { } }; -Nengo.NetGraphItem.prototype.redraw_child_connections = function() { +NetGraphItem.prototype.redraw_child_connections = function() { // Update any children's positions for (var i in this.child_connections) { var item = this.child_connections[i]; @@ -693,7 +698,7 @@ Nengo.NetGraphItem.prototype.redraw_child_connections = function() { } }; -Nengo.NetGraphItem.prototype.redraw_connections = function() { +NetGraphItem.prototype.redraw_connections = function() { // Update any connections into and out of this for (var i in this.conn_in) { var item = this.conn_in[i]; @@ -708,7 +713,7 @@ Nengo.NetGraphItem.prototype.redraw_connections = function() { /** * Return the width of the item, taking into account parent widths. */ -Nengo.NetGraphItem.prototype.get_nested_width = function() { +NetGraphItem.prototype.get_nested_width = function() { var w = this.width; var parent = this.parent; while (parent !== null) { @@ -721,7 +726,7 @@ Nengo.NetGraphItem.prototype.get_nested_width = function() { /** * Return the height of the item, taking into account parent heights. */ -Nengo.NetGraphItem.prototype.get_nested_height = function() { +NetGraphItem.prototype.get_nested_height = function() { var h = this.height; var parent = this.parent; while (parent !== null) { @@ -731,7 +736,7 @@ Nengo.NetGraphItem.prototype.get_nested_height = function() { return h; }; -Nengo.NetGraphItem.prototype.redraw_size = function() { +NetGraphItem.prototype.redraw_size = function() { var screen_w = this.get_screen_width(); var screen_h = this.get_screen_height(); @@ -780,7 +785,7 @@ Nengo.NetGraphItem.prototype.redraw_size = function() { }; }; -Nengo.NetGraphItem.prototype.get_screen_width = function() { +NetGraphItem.prototype.get_screen_width = function() { if (this.minimap && !this.ng.mm_display) { return 1; } @@ -804,7 +809,7 @@ Nengo.NetGraphItem.prototype.get_screen_width = function() { return screen_w * 2; }; -Nengo.NetGraphItem.prototype.get_screen_height = function() { +NetGraphItem.prototype.get_screen_height = function() { if (this.minimap && !this.ng.mm_display) { return 1; } @@ -831,7 +836,7 @@ Nengo.NetGraphItem.prototype.get_screen_height = function() { /** * Force a redraw of the item. */ -Nengo.NetGraphItem.prototype.redraw = function() { +NetGraphItem.prototype.redraw = function() { this.redraw_position(); this.redraw_size(); this.redraw_children(); @@ -846,7 +851,7 @@ Nengo.NetGraphItem.prototype.redraw = function() { /** * Determine the pixel location of the centre of the item. */ -Nengo.NetGraphItem.prototype.get_screen_location = function() { +NetGraphItem.prototype.get_screen_location = function() { // FIXME: this should probably use this.ng.get_scaled_width // and this.ng.get_scaled_height if (this.minimap && !this.ng.mm_display) { @@ -901,7 +906,7 @@ Nengo.NetGraphItem.prototype.get_screen_location = function() { /** * Function for drawing ensemble svg. */ -Nengo.NetGraphItem.prototype.ensemble_svg = function() { +NetGraphItem.prototype.ensemble_svg = function() { var shape = this.ng.createSVGElement('g'); shape.setAttribute('class', 'ensemble'); @@ -939,16 +944,18 @@ Nengo.NetGraphItem.prototype.ensemble_svg = function() { /** * Helper function for setting attributes. */ -Nengo.NetGraphItem.prototype.setAttributes = function(el, attrs) { +NetGraphItem.prototype.setAttributes = function(el, attrs) { for (var key in attrs) { el.setAttribute(key, attrs[key]); } }; -Nengo.NetGraphItem.prototype.getMinMaxXY = function() { +NetGraphItem.prototype.getMinMaxXY = function() { min_x = this.x - this.width; max_x = this.x + this.width; min_y = this.y - this.height; max_y = this.y + this.height; return [min_x, max_x, min_y, max_y]; }; + +module.exports = NetGraphItem; diff --git a/nengo_gui/static/components/pointer.js b/nengo_gui/static/components/pointer.js index 3fc2c842..bd9be21d 100644 --- a/nengo_gui/static/components/pointer.js +++ b/nengo_gui/static/components/pointer.js @@ -3,16 +3,21 @@ * * @constructor * @param {DOMElement} parent - the element to add this component to - * @param {Nengo.SimControl} sim - the simulation controller - * @param {dict} args - A set of constructor arguments (see Nengo.Component) + * @param {SimControl} sim - the simulation controller + * @param {dict} args - A set of constructor arguments (see Component) * * Pointer constructor is called by python server when a user requests a plot * or when the config file is making graphs. Server request is handled in * netgraph.js {.on_message} function. */ -Nengo.Pointer = function(parent, sim, args) { - Nengo.Component.call(this, parent, args); +require('./pointer.css'); +var Component = require('./component').Component; +var DataStore = require('../datastore').DataStore; +var utils = require('../utils'); + +var Pointer = function(parent, viewport, sim, args) { + Component.call(this, parent, viewport, args); var self = this; this.sim = sim; @@ -21,7 +26,7 @@ Nengo.Pointer = function(parent, sim, args) { this.pdiv = document.createElement('div'); this.pdiv.style.width = args.width; this.pdiv.style.height = args.height; - Nengo.set_transform(this.pdiv, 0, 25); + utils.set_transform(this.pdiv, 0, 25); this.pdiv.style.position = 'fixed'; this.pdiv.classList.add('pointer'); this.div.appendChild(this.pdiv); @@ -29,7 +34,7 @@ Nengo.Pointer = function(parent, sim, args) { this.show_pairs = args.show_pairs; // For storing the accumulated data - this.data_store = new Nengo.DataStore(1, this.sim, 0); + this.data_store = new DataStore(1, this.sim, 0); // Call schedule_update whenever the time is adjusted in the SimControl this.sim.div.addEventListener('adjust_time', function(e) { @@ -67,10 +72,10 @@ Nengo.Pointer = function(parent, sim, args) { }); }; -Nengo.Pointer.prototype = Object.create(Nengo.Component.prototype); -Nengo.Pointer.prototype.constructor = Nengo.Pointer; +Pointer.prototype = Object.create(Component.prototype); +Pointer.prototype.constructor = Pointer; -Nengo.Pointer.prototype.generate_menu = function() { +Pointer.prototype.generate_menu = function() { var self = this; var items = []; items.push(['Set value...', function() { @@ -88,21 +93,21 @@ Nengo.Pointer.prototype.generate_menu = function() { // Add the parent's menu items to this // TODO: is this really the best way to call the parent's generate_menu()? - return $.merge(items, Nengo.Component.prototype.generate_menu.call(this)); + return $.merge(items, Component.prototype.generate_menu.call(this)); }; -Nengo.Pointer.prototype.set_show_pairs = function(value) { +Pointer.prototype.set_show_pairs = function(value) { if (this.show_pairs !== value) { this.show_pairs = value; this.save_layout(); } }; -Nengo.Pointer.prototype.set_value = function() { +Pointer.prototype.set_value = function() { var self = this; - Nengo.modal.title('Enter a Semantic Pointer value...'); - Nengo.modal.single_input_body('Pointer', 'New value'); - Nengo.modal.footer('ok_cancel', function(e) { + self.sim.modal.title('Enter a Semantic Pointer value...'); + self.sim.modal.single_input_body('Pointer', 'New value'); + self.sim.modal.footer('ok_cancel', function(e) { var value = $('#singleInput').val(); var modal = $('#myModalForm').data('bs.validator'); @@ -136,13 +141,13 @@ Nengo.Pointer.prototype.set_value = function() { 'such as +, * (circular convolution), and ~ (pseudo-inverse). ' + 'E.g., (A+~(B*C)*2)*0.5 would be a valid semantic pointer expression.'); - Nengo.modal.show(); + self.sim.modal.show(); }; /** * Receive new line data from the server. */ -Nengo.Pointer.prototype.on_message = function(event) { +Pointer.prototype.on_message = function(event) { data = event.data.split(" "); if (data[0].substring(0, 11) == "bad_pointer") { @@ -163,7 +168,7 @@ Nengo.Pointer.prototype.on_message = function(event) { /** * Redraw the lines and axis due to changed data. */ -Nengo.Pointer.prototype.update = function() { +Pointer.prototype.update = function() { // Let the data store clear out old values this.data_store.update(); @@ -213,7 +218,7 @@ Nengo.Pointer.prototype.update = function() { /** * Adjust the graph layout due to changed size. */ -Nengo.Pointer.prototype.on_resize = function(width, height) { +Pointer.prototype.on_resize = function(width, height) { if (width < this.minWidth) { width = this.minWidth; } @@ -231,18 +236,20 @@ Nengo.Pointer.prototype.on_resize = function(width, height) { this.update(); }; -Nengo.Pointer.prototype.layout_info = function() { - var info = Nengo.Component.prototype.layout_info.call(this); +Pointer.prototype.layout_info = function() { + var info = Component.prototype.layout_info.call(this); info.show_pairs = this.show_pairs; return info; }; -Nengo.Pointer.prototype.update_layout = function(config) { +Pointer.prototype.update_layout = function(config) { this.show_pairs = config.show_pairs; - Nengo.Component.prototype.update_layout.call(this, config); + Component.prototype.update_layout.call(this, config); }; -Nengo.Pointer.prototype.reset = function(event) { +Pointer.prototype.reset = function(event) { this.data_store.reset(); this.schedule_update(); }; + +module.exports = Pointer; diff --git a/nengo_gui/static/components/raster.js b/nengo_gui/static/components/raster.js index 0c5db58f..8a451c40 100644 --- a/nengo_gui/static/components/raster.js +++ b/nengo_gui/static/components/raster.js @@ -3,8 +3,8 @@ * * @constructor * @param {DOMElement} parent - the element to add this component to - * @param {Nengo.SimControl} sim - the simulation controller - * @param {dict} args - A set of constructor arguments (see Nengo.Component) + * @param {SimControl} sim - the simulation controller + * @param {dict} args - A set of constructor arguments (see Component) * @param {int} args.n_neurons - number of neurons * * Raster constructor is called by python server when a user requests a plot @@ -12,16 +12,23 @@ * netgraph.js {.on_message} function. */ -Nengo.Raster = function(parent, sim, args) { - Nengo.Component.call(this, parent, args); +require('./raster.css'); +var d3 = require('d3'); +var Component = require('./component').Component; +var DataStore = require('../datastore').DataStore; +var TimeAxes = require('./time_axes'); +var utils = require('../utils'); + +var Raster = function(parent, viewport, sim, args) { + Component.call(this, parent, viewport, args); var self = this; this.n_neurons = args.n_neurons || 1; this.sim = sim; // For storing the accumulated data - this.data_store = new Nengo.DataStore(1, this.sim, 0); + this.data_store = new DataStore(1, this.sim, 0); - this.axes2d = new Nengo.TimeAxes(this.div, args); + this.axes2d = new TimeAxes(this.div, args); this.axes2d.scale_y.domain([0, args.n_neurons]); // Call schedule_update whenever the time is adjusted in the SimControl @@ -49,7 +56,7 @@ Nengo.Raster = function(parent, sim, args) { this.path.enter().append('path') .attr('class', 'line') - .style('stroke', Nengo.make_colors(1)); + .style('stroke', utils.make_colors(1)); this.update(); this.on_resize(this.get_screen_width(), this.get_screen_height()); @@ -57,20 +64,20 @@ Nengo.Raster = function(parent, sim, args) { this.axes2d.fit_ticks(this); }; -Nengo.Raster.prototype = Object.create(Nengo.Component.prototype); -Nengo.Raster.prototype.constructor = Nengo.Raster; +Raster.prototype = Object.create(Component.prototype); +Raster.prototype.constructor = Raster; /** * Receive new line data from the server. */ -Nengo.Raster.prototype.on_message = function(event) { +Raster.prototype.on_message = function(event) { var time = new Float32Array(event.data, 0, 1); var data = new Int16Array(event.data, 4); this.data_store.push([time[0], data]); this.schedule_update(); }; -Nengo.Raster.prototype.set_n_neurons = function(n_neurons) { +Raster.prototype.set_n_neurons = function(n_neurons) { this.n_neurons = n_neurons; this.axes2d.scale_y.domain([0, n_neurons]); this.axes2d.axis_y.tickValues([0, n_neurons]); @@ -80,11 +87,11 @@ Nengo.Raster.prototype.set_n_neurons = function(n_neurons) { /** * Redraw the lines and axis due to changed data. */ -Nengo.Raster.prototype.update = function() { +Raster.prototype.update = function() { // Let the data store clear out old values this.data_store.update(); - // Determine visible range from the Nengo.SimControl + // Determine visible range from the SimControl var t1 = this.sim.time_slider.first_shown_time; var t2 = t1 + this.sim.time_slider.shown_time; @@ -111,7 +118,7 @@ Nengo.Raster.prototype.update = function() { /** * Adjust the graph layout due to changed size. */ -Nengo.Raster.prototype.on_resize = function(width, height) { +Raster.prototype.on_resize = function(width, height) { if (width < this.minWidth) { width = this.minWidth; } @@ -131,25 +138,25 @@ Nengo.Raster.prototype.on_resize = function(width, height) { this.div.style.height = height; }; -Nengo.Raster.prototype.reset = function(event) { +Raster.prototype.reset = function(event) { this.data_store.reset(); this.schedule_update(); }; -Nengo.Raster.prototype.generate_menu = function() { +Raster.prototype.generate_menu = function() { var self = this; var items = []; items.push(['Set # neurons...', function() {self.set_neuron_count();}]); - return $.merge(items, Nengo.Component.prototype.generate_menu.call(this)); + return $.merge(items, Component.prototype.generate_menu.call(this)); }; -Nengo.Raster.prototype.set_neuron_count = function() { +Raster.prototype.set_neuron_count = function() { var count = this.n_neurons; var self = this; - Nengo.modal.title('Set number of neurons...'); - Nengo.modal.single_input_body(count, 'Number of neurons'); - Nengo.modal.footer('ok_cancel', function(e) { + self.sim.modal.title('Set number of neurons...'); + self.sim.modal.single_input_body(count, 'Number of neurons'); + self.sim.modal.footer('ok_cancel', function(e) { var new_count = $('#singleInput').val(); var modal = $('#myModalForm').data('bs.validator'); modal.validate(); @@ -181,10 +188,12 @@ Nengo.Raster.prototype.set_neuron_count = function() { $('#singleInput').attr('data-error', 'Input should be a positive integer'); - Nengo.modal.show(); + self.sim.modal.show(); $('#OK').on('click', function() { var w = $(self.div).width(); var h = $(self.div).height(); self.on_resize(w, h); }); }; + +module.exports = Raster; diff --git a/nengo_gui/static/components/slider.js b/nengo_gui/static/components/slider.js index d2f445f7..a40b31cb 100644 --- a/nengo_gui/static/components/slider.js +++ b/nengo_gui/static/components/slider.js @@ -3,8 +3,8 @@ * * @constructor * @param {DOMElement} parent - the element to add this component to - * @param {Nengo.SimControl} sim - the simulation controller - * @param {dict} args - a set of constructor arguments (see Nengo.Component) + * @param {SimControl} sim - the simulation controller + * @param {dict} args - a set of constructor arguments (see Component) * @param {int} args.n_sliders - the number of sliders to show * * Slider constructor is called by python server when a user requests a slider @@ -12,8 +12,14 @@ * netgraph.js {.on_message} function. */ -Nengo.Slider = function(parent, sim, args) { - Nengo.Component.call(this, parent, args); +require('./slider.css'); +var Component = require('./component').Component; +var DataStore = require('../datastore').DataStore; +var menu = require('../menu'); +var SliderControl = require('./slidercontrol'); + +var Slider = function(parent, viewport, sim, args) { + Component.call(this, parent, viewport, args); var self = this; this.sim = sim; @@ -48,7 +54,7 @@ Nengo.Slider = function(parent, sim, args) { this.sliders = []; for (var i = 0; i < args.n_sliders; i++) { // Creating a SliderControl object for every slider handle required - var slider = new Nengo.SliderControl(args.min_value, args.max_value); + var slider = new SliderControl(args.min_value, args.max_value); slider.container.style.width = (100 / args.n_sliders) + '%'; slider.display_value(args.start_value[i]); slider.index = i; @@ -58,7 +64,7 @@ Nengo.Slider = function(parent, sim, args) { event.target.fixed = true; self.send_value(event.target.index, event.value); }).on('changestart', function(event) { - self.menu.hide_any(); + menu.hide_any(); for (var i in this.sliders) { if (this.sliders[i] !== event.target) { this.sliders[i].deactivate_type_mode(); @@ -82,10 +88,10 @@ Nengo.Slider = function(parent, sim, args) { this.on_resize(this.get_screen_width(), this.get_screen_height()); }; -Nengo.Slider.prototype = Object.create(Nengo.Component.prototype); -Nengo.Slider.prototype.constructor = Nengo.Slider; +Slider.prototype = Object.create(Component.prototype); +Slider.prototype.constructor = Slider; -Nengo.Slider.prototype.set_axes_geometry = function(width, height) { +Slider.prototype.set_axes_geometry = function(width, height) { this.width = width; this.height = height; scale = parseFloat($('#main').css('font-size')); @@ -94,7 +100,7 @@ Nengo.Slider.prototype.set_axes_geometry = function(width, height) { this.slider_height = this.height - this.ax_top; }; -Nengo.Slider.prototype.send_value = function(slider_index, value) { +Slider.prototype.send_value = function(slider_index, value) { console.assert(typeof slider_index == 'number'); console.assert(typeof value == 'number'); @@ -106,7 +112,7 @@ Nengo.Slider.prototype.send_value = function(slider_index, value) { this.sim.time_slider.jump_to_end(); }; -Nengo.Slider.prototype.on_sim_reset = function(event) { +Slider.prototype.on_sim_reset = function(event) { // Release slider position and reset it for (var i = 0; i < this.sliders.length; i++) { this.notify('' + i + ',reset'); @@ -118,11 +124,10 @@ Nengo.Slider.prototype.on_sim_reset = function(event) { /** * Receive new line data from the server. */ -Nengo.Slider.prototype.on_message = function(event) { +Slider.prototype.on_message = function(event) { var data = new Float32Array(event.data); if (this.data_store === null) { - this.data_store = - new Nengo.DataStore(this.sliders.length, this.sim, 0); + this.data_store = new DataStore(this.sliders.length, this.sim, 0); } this.reset_value = []; for (var i = 0; i < this.sliders.length; i++) { @@ -140,7 +145,7 @@ Nengo.Slider.prototype.on_message = function(event) { /** * Update visual display based when component is resized. */ -Nengo.Slider.prototype.on_resize = function(width, height) { +Slider.prototype.on_resize = function(width, height) { console.assert(typeof width == 'number'); console.assert(typeof height == 'number'); @@ -166,7 +171,7 @@ Nengo.Slider.prototype.on_resize = function(width, height) { this.div.style.height = this.height; }; -Nengo.Slider.prototype.generate_menu = function() { +Slider.prototype.generate_menu = function() { var self = this; var items = []; items.push(['Set range...', function() { @@ -181,13 +186,13 @@ Nengo.Slider.prototype.generate_menu = function() { // Add the parent's menu items to this // TODO: is this really the best way to call the parent's generate_menu()? - return $.merge(items, Nengo.Component.prototype.generate_menu.call(this)); + return $.merge(items, Component.prototype.generate_menu.call(this)); }; /** * Report an event back to the server. */ -Nengo.Slider.prototype.notify = function(info) { +Slider.prototype.notify = function(info) { this.notify_msgs.push(info); // Only send one message at a time @@ -206,7 +211,7 @@ Nengo.Slider.prototype.notify = function(info) { * * Also schedule the next message to be sent, if any. */ -Nengo.Slider.prototype.send_notify_msg = function() { +Slider.prototype.send_notify_msg = function() { msg = this.notify_msgs[0]; this.ws.send(msg); if (this.notify_msgs.length > 1) { @@ -218,7 +223,7 @@ Nengo.Slider.prototype.send_notify_msg = function() { this.notify_msgs.splice(0, 1); }; -Nengo.Slider.prototype.update = function() { +Slider.prototype.update = function() { // Let the data store clear out old values if (this.data_store !== null) { this.data_store.update(); @@ -233,7 +238,7 @@ Nengo.Slider.prototype.update = function() { } }; -Nengo.Slider.prototype.user_value = function() { +Slider.prototype.user_value = function() { var self = this; // First build the prompt string @@ -244,9 +249,9 @@ Nengo.Slider.prototype.user_value = function() { prompt_string = prompt_string + ", "; } } - Nengo.modal.title('Set slider value(s)...'); - Nengo.modal.single_input_body(prompt_string, 'New value(s)'); - Nengo.modal.footer('ok_cancel', function(e) { + self.sim.modal.title('Set slider value(s)...'); + self.sim.modal.single_input_body(prompt_string, 'New value(s)'); + self.sim.modal.footer('ok_cancel', function(e) { var new_value = $('#singleInput').val(); var modal = $('#myModalForm').data('bs.validator'); @@ -286,10 +291,10 @@ Nengo.Slider.prototype.user_value = function() { $('#singleInput').attr('data-error', 'Input should be one ' + 'comma-separated numerical value for each slider.'); - Nengo.modal.show(); + self.sim.modal.show(); }; -Nengo.Slider.prototype.user_reset_value = function() { +Slider.prototype.user_reset_value = function() { for (var i = 0; i < this.sliders.length; i++) { this.notify('' + i + ',reset'); @@ -298,12 +303,12 @@ Nengo.Slider.prototype.user_reset_value = function() { } }; -Nengo.Slider.prototype.set_range = function() { +Slider.prototype.set_range = function() { var range = this.sliders[0].scale.domain(); var self = this; - Nengo.modal.title('Set slider range...'); - Nengo.modal.single_input_body([range[1], range[0]], 'New range'); - Nengo.modal.footer('ok_cancel', function(e) { + self.sim.modal.title('Set slider range...'); + self.sim.modal.single_input_body([range[1], range[0]], 'New range'); + self.sim.modal.footer('ok_cancel', function(e) { var new_range = $('#singleInput').val(); var modal = $('#myModalForm').data('bs.validator'); @@ -340,21 +345,23 @@ Nengo.Slider.prototype.set_range = function() { $('#singleInput').attr('data-error', 'Input should be in the ' + 'form ",".'); - Nengo.modal.show(); + self.sim.modal.show(); }; -Nengo.Slider.prototype.layout_info = function() { - var info = Nengo.Component.prototype.layout_info.call(this); +Slider.prototype.layout_info = function() { + var info = Component.prototype.layout_info.call(this); info.width = info.width; info.min_value = this.sliders[0].scale.domain()[1]; info.max_value = this.sliders[0].scale.domain()[0]; return info; }; -Nengo.Slider.prototype.update_layout = function(config) { +Slider.prototype.update_layout = function(config) { // FIXME: this has to be backwards to work. Something fishy must be going on for (var i in this.sliders) { this.sliders[i].set_range(config.min_value, config.max_value); } - Nengo.Component.prototype.update_layout.call(this, config); + Component.prototype.update_layout.call(this, config); }; + +module.exports = Slider; diff --git a/nengo_gui/static/components/slidercontrol.js b/nengo_gui/static/components/slidercontrol.js index 7b05b499..ccf07d52 100644 --- a/nengo_gui/static/components/slidercontrol.js +++ b/nengo_gui/static/components/slidercontrol.js @@ -10,7 +10,11 @@ * handle that is needed. */ -Nengo.SliderControl = function(min, max) { +var d3 = require('d3'); +var interact = require('interact.js'); +var utils = require('../utils'); + +var SliderControl = function(min, max) { var self = this; this.min = min; @@ -86,18 +90,18 @@ Nengo.SliderControl = function(min, max) { this.listeners = {}; }; -Nengo.SliderControl.prototype.on = function(type, fn) { +SliderControl.prototype.on = function(type, fn) { this.listeners[type] = fn; return this; }; -Nengo.SliderControl.prototype.dispatch = function(type, ev) { +SliderControl.prototype.dispatch = function(type, ev) { if (type in this.listeners) { this.listeners[type].call(this, ev); } }; -Nengo.SliderControl.prototype.set_range = function(min, max) { +SliderControl.prototype.set_range = function(min, max) { this.min = min; this.max = max; this.scale.domain([max, min]); @@ -105,7 +109,7 @@ Nengo.SliderControl.prototype.set_range = function(min, max) { this.on_resize(); }; -Nengo.SliderControl.prototype.display_value = function(value) { +SliderControl.prototype.display_value = function(value) { if (value < this.min) { value = this.min; } @@ -119,13 +123,13 @@ Nengo.SliderControl.prototype.display_value = function(value) { this.update_value_text(value); }; -Nengo.SliderControl.prototype.set_value = function(value) { +SliderControl.prototype.set_value = function(value) { var old_value = this.value; this.display_value(value); this.dispatch('change', {'target': this, 'value': this.value}); }; -Nengo.SliderControl.prototype.activate_type_mode = function() { +SliderControl.prototype.activate_type_mode = function() { if (this.type_mode) { return; } @@ -146,7 +150,7 @@ Nengo.SliderControl.prototype.activate_type_mode = function() { elem.style.textAlign = 'center'; elem.style.backgroundColor = 'transparent'; $(elem).on('input', function(event) { - if (Nengo.is_num(elem.value)) { + if (utils.is_num(elem.value)) { self.handle.style.backgroundColor = ''; } else { self.handle.style.backgroundColor = 'salmon'; @@ -156,7 +160,7 @@ Nengo.SliderControl.prototype.activate_type_mode = function() { }); }; -Nengo.SliderControl.prototype.deactivate_type_mode = function(event) { +SliderControl.prototype.deactivate_type_mode = function(event) { if (!this.type_mode) { return; } @@ -170,7 +174,7 @@ Nengo.SliderControl.prototype.deactivate_type_mode = function(event) { this.handle.innerHTML = this.format_value(this.value); }; -Nengo.SliderControl.prototype.handle_keypress = function(event) { +SliderControl.prototype.handle_keypress = function(event) { if (!this.type_mode) { return; } @@ -181,7 +185,7 @@ Nengo.SliderControl.prototype.handle_keypress = function(event) { if (key == enter_keycode) { var input = this.handle.querySelector('#value_in_field').value; - if (Nengo.is_num(input)) { + if (utils.is_num(input)) { this.deactivate_type_mode(); this.set_value(parseFloat(input)); } @@ -190,23 +194,25 @@ Nengo.SliderControl.prototype.handle_keypress = function(event) { } }; -Nengo.SliderControl.prototype.update_handle_pos = function(value) { +SliderControl.prototype.update_handle_pos = function(value) { this.handle.style.top = this.scale(value) + this.border_width; }; -Nengo.SliderControl.prototype.get_handle_pos = function() { +SliderControl.prototype.get_handle_pos = function() { return parseFloat(this.handle.style.top) - this.border_width; }; -Nengo.SliderControl.prototype.update_value_text = function(value) { +SliderControl.prototype.update_value_text = function(value) { this.handle.innerHTML = this.format_value(value); }; -Nengo.SliderControl.prototype.format_value = function(value) { +SliderControl.prototype.format_value = function(value) { return value.toFixed(2); }; -Nengo.SliderControl.prototype.on_resize = function() { +SliderControl.prototype.on_resize = function() { this.scale.range([0, this.guideline.clientHeight]); this.update_handle_pos(this.value); }; + +module.exports = SliderControl; diff --git a/nengo_gui/static/components/spa_similarity.js b/nengo_gui/static/components/spa_similarity.js index 9d08c666..363172b9 100644 --- a/nengo_gui/static/components/spa_similarity.js +++ b/nengo_gui/static/components/spa_similarity.js @@ -3,25 +3,33 @@ * * @constructor * @param {DOMElement} parent - the element to add this component to - * @param {Nengo.SimControl} sim - the simulation controller - * @param {dict} args - A set of constructor arguments (see Nengo.Component) + * @param {SimControl} sim - the simulation controller + * @param {dict} args - A set of constructor arguments (see Component) * @param {int} args.n_lines - number of decoded values */ -Nengo.SpaSimilarity = function(parent, sim, args) { - Nengo.Value.call(this, parent, sim, args); +require('./spa_similarity.css'); +var d3 = require('d3'); +var Component = require('./component').Component; +var GrowableDataStore = require('../datastore').GrowableDataStore; +var utils = require('../utils'); +var Value = require('./value'); + +var SpaSimilarity = function(parent, viewport, sim, args) { + Value.call(this, parent, viewport, sim, args); this.synapse = args.synapse; this.data_store = - new Nengo.GrowableDataStore(this.n_lines, this.sim, this.synapse); + new GrowableDataStore(this.n_lines, this.sim, this.synapse); this.show_pairs = false; var self = this; - this.colors = Nengo.make_colors(6); + this.colors = utils.make_colors(6); this.color_func = function(d, i) { return self.colors[i % 6]; }; + this.line.defined(function(d) { return !isNaN(d); }); @@ -31,17 +39,17 @@ Nengo.SpaSimilarity = function(parent, sim, args) { this.legend = document.createElement('div'); this.legend.classList.add('legend', 'unselectable'); this.div.appendChild(this.legend); - this.legend_svg = Nengo.draw_legend( + this.legend_svg = utils.draw_legend( this.legend, args.pointer_labels, this.color_func, this.uid); }; -Nengo.SpaSimilarity.prototype = Object.create(Nengo.Value.prototype); -Nengo.SpaSimilarity.prototype.constructor = Nengo.SpaSimilarity; +SpaSimilarity.prototype = Object.create(Value.prototype); +SpaSimilarity.prototype.constructor = SpaSimilarity; -Nengo.SpaSimilarity.prototype.reset_legend_and_data = function(new_labels) { +SpaSimilarity.prototype.reset_legend_and_data = function(new_labels) { // Clear the database and create a new one since dimensions have changed this.data_store = - new Nengo.GrowableDataStore(new_labels.length, this.sim, this.synapse); + new GrowableDataStore(new_labels.length, this.sim, this.synapse); // Delete the legend's children while (this.legend.lastChild) { @@ -60,7 +68,7 @@ Nengo.SpaSimilarity.prototype.reset_legend_and_data = function(new_labels) { this.update(); }; -Nengo.SpaSimilarity.prototype.data_msg = function(push_data) { +SpaSimilarity.prototype.data_msg = function(push_data) { var data_dims = push_data.length - 1; // TODO: Move this check inside datastore? @@ -73,7 +81,7 @@ Nengo.SpaSimilarity.prototype.data_msg = function(push_data) { this.schedule_update(); }; -Nengo.SpaSimilarity.prototype.update_legend = function(new_labels) { +SpaSimilarity.prototype.update_legend = function(new_labels) { var self = this; this.legend_labels = this.legend_labels.concat(new_labels); @@ -138,7 +146,7 @@ Nengo.SpaSimilarity.prototype.update_legend = function(new_labels) { * - show_pairs has been toggledn * This calls the method associated to handling the type of message. */ -Nengo.SpaSimilarity.prototype.on_message = function(event) { +SpaSimilarity.prototype.on_message = function(event) { var data = JSON.parse(event.data); var func_name = data.shift(); this[func_name](data); @@ -147,11 +155,11 @@ Nengo.SpaSimilarity.prototype.on_message = function(event) { /** * Redraw the lines and axis due to changed data. */ -Nengo.SpaSimilarity.prototype.update = function() { +SpaSimilarity.prototype.update = function() { // Let the data store clear out old values this.data_store.update(); - // Determine visible range from the Nengo.SimControl + // Determine visible range from the SimControl var t1 = this.sim.time_slider.first_shown_time; var t2 = t1 + this.sim.time_slider.shown_time; @@ -194,7 +202,7 @@ Nengo.SpaSimilarity.prototype.update = function() { } }; -Nengo.SpaSimilarity.prototype.generate_menu = function() { +SpaSimilarity.prototype.generate_menu = function() { var self = this; var items = []; items.push(['Set range...', function() { @@ -212,10 +220,10 @@ Nengo.SpaSimilarity.prototype.generate_menu = function() { } // Add the parent's menu items to this - return $.merge(items, Nengo.Component.prototype.generate_menu.call(this)); + return $.merge(items, Component.prototype.generate_menu.call(this)); }; -Nengo.SpaSimilarity.prototype.set_show_pairs = function(value) { +SpaSimilarity.prototype.set_show_pairs = function(value) { if (this.show_pairs !== value) { this.show_pairs = value; this.save_layout(); @@ -223,24 +231,26 @@ Nengo.SpaSimilarity.prototype.set_show_pairs = function(value) { } }; -Nengo.SpaSimilarity.prototype.layout_info = function() { - var info = Nengo.Component.prototype.layout_info.call(this); +SpaSimilarity.prototype.layout_info = function() { + var info = Component.prototype.layout_info.call(this); info.show_pairs = this.show_pairs; info.min_value = this.axes2d.scale_y.domain()[0]; info.max_value = this.axes2d.scale_y.domain()[1]; return info; }; -Nengo.SpaSimilarity.prototype.update_layout = function(config) { +SpaSimilarity.prototype.update_layout = function(config) { this.update_range(config.min_value, config.max_value); this.show_pairs = config.show_pairs; - Nengo.Component.prototype.update_layout.call(this, config); + Component.prototype.update_layout.call(this, config); }; -Nengo.SpaSimilarity.prototype.reset = function() { +SpaSimilarity.prototype.reset = function() { // Ask for a legend update this.ws.send("reset_legend"); }; // TODO: should I remove the ability to set range? // Or limit it to something intuitive + +module.exports = SpaSimilarity; diff --git a/nengo_gui/static/components/time_axes.js b/nengo_gui/static/components/time_axes.js index 22dfc9db..5f5ca50c 100644 --- a/nengo_gui/static/components/time_axes.js +++ b/nengo_gui/static/components/time_axes.js @@ -6,11 +6,13 @@ * * @constructor * @param {DOMElement} parent - the element to add this component to - * @param {dict} args - A set of constructor arguments (see Nengo.Axes2D) + * @param {dict} args - A set of constructor arguments (see Axes2D) */ -Nengo.TimeAxes = function(parent, args) { - Nengo.Axes2D.call(this, parent, args); +var Axes2D = require('./2d_axes'); + +var TimeAxes = function(parent, args) { + Axes2D.call(this, parent, args); var self = this; this.display_time = args.display_time; @@ -29,18 +31,18 @@ Nengo.TimeAxes = function(parent, args) { } }; -Nengo.TimeAxes.prototype = Object.create(Nengo.Axes2D.prototype); -Nengo.TimeAxes.prototype.constructor = Nengo.TimeAxes; +TimeAxes.prototype = Object.create(Axes2D.prototype); +TimeAxes.prototype.constructor = TimeAxes; -Nengo.TimeAxes.prototype.set_time_range = function(start, end) { +TimeAxes.prototype.set_time_range = function(start, end) { this.scale_x.domain([start, end]); this.axis_time_start.textContent = start.toFixed(3); this.axis_time_end.textContent = end.toFixed(3); this.axis_x_g.call(this.axis_x); }; -Nengo.TimeAxes.prototype.on_resize = function(width, height) { - Nengo.Axes2D.prototype.on_resize.call(this, width, height); +TimeAxes.prototype.on_resize = function(width, height) { + Axes2D.prototype.on_resize.call(this, width, height); scale = parseFloat($('#main').css('font-size')); var suppression_width = 6 * scale; @@ -57,3 +59,5 @@ Nengo.TimeAxes.prototype.on_resize = function(width, height) { this.axis_time_end.setAttribute('y', this.ax_bottom + text_offset); this.axis_time_end.setAttribute('x', this.ax_right - text_offset); }; + +module.exports = TimeAxes; diff --git a/nengo_gui/static/components/value.js b/nengo_gui/static/components/value.js index 96a193a3..e7c9586e 100644 --- a/nengo_gui/static/components/value.js +++ b/nengo_gui/static/components/value.js @@ -7,14 +7,22 @@ * * @constructor * @param {DOMElement} parent - the element to add this component to - * @param {Nengo.SimControl} sim - the simulation controller - * @param {dict} args - A set of constructor arguments (see Nengo.Component) + * @param {SimControl} sim - the simulation controller + * @param {dict} args - A set of constructor arguments (see Component) * @param {int} args.n_lines - number of decoded values * @param {float} args.min_value - minimum value on y-axis * @param {float} args.max_value - maximum value on y-axis */ -Nengo.Value = function(parent, sim, args) { - Nengo.Component.call(this, parent, args); + +var d3 = require('d3'); +require('./value.css'); +var Component = require('./component').Component; +var DataStore = require('../datastore').DataStore; +var TimeAxes = require('./time_axes'); +var utils = require('../utils'); + +var Value = function(parent, viewport, sim, args) { + Component.call(this, parent, viewport, args); var self = this; this.n_lines = args.n_lines || 1; this.sim = sim; @@ -22,9 +30,9 @@ Nengo.Value = function(parent, sim, args) { this.synapse = args.synapse; // For storing the accumulated data - this.data_store = new Nengo.DataStore(this.n_lines, this.sim, 0.0); + this.data_store = new DataStore(this.n_lines, this.sim, 0.0); - this.axes2d = new Nengo.TimeAxes(this.div, args); + this.axes2d = new TimeAxes(this.div, args); // Call schedule_update whenever the time is adjusted in the SimControl this.sim.div.addEventListener('adjust_time', function(e) { @@ -48,8 +56,9 @@ Nengo.Value = function(parent, sim, args) { .selectAll('path') .data(this.data_store.data); - this.colors = Nengo.make_colors(this.n_lines); - this.path.enter().append('path') + this.colors = utils.make_colors(this.n_lines); + this.path.enter() + .append('path') .attr('class', 'line') .style('stroke', function(d, i) { return self.colors[i]; @@ -116,7 +125,7 @@ Nengo.Value = function(parent, sim, args) { this.axes2d.axis_y.tickValues([args.min_value, args.max_value]); this.axes2d.fit_ticks(this); - this.colors = Nengo.make_colors(6); + this.colors = utils.make_colors(6); this.color_func = function(d, i) { return self.colors[i % 6]; }; @@ -134,16 +143,16 @@ Nengo.Value = function(parent, sim, args) { this.show_legend = args.show_legend || false; if (this.show_legend === true) { - Nengo.draw_legend(this.legend, + utils.draw_legend(this.legend, this.legend_labels.slice(0, self.n_lines), this.color_func); } }; -Nengo.Value.prototype = Object.create(Nengo.Component.prototype); -Nengo.Value.prototype.constructor = Nengo.Value; +Value.prototype = Object.create(Component.prototype); +Value.prototype.constructor = Value; -Nengo.Value.prototype.update_crosshair = function(mouse) { +Value.prototype.update_crosshair = function(mouse) { var self = this; var x = mouse[0]; var y = mouse[1]; @@ -188,7 +197,7 @@ Nengo.Value.prototype.update_crosshair = function(mouse) { /** * Receive new line data from the server. */ -Nengo.Value.prototype.on_message = function(event) { +Value.prototype.on_message = function(event) { var data = new Float32Array(event.data); data = Array.prototype.slice.call(data); var size = this.n_lines + 1; @@ -207,11 +216,11 @@ Nengo.Value.prototype.on_message = function(event) { /** * Redraw the lines and axis due to changed data. */ -Nengo.Value.prototype.update = function() { +Value.prototype.update = function() { // Let the data store clear out old values this.data_store.update(); - // Determine visible range from the Nengo.SimControl + // Determine visible range from the SimControl var t1 = this.sim.time_slider.first_shown_time; var t2 = t1 + this.sim.time_slider.shown_time; @@ -233,7 +242,7 @@ Nengo.Value.prototype.update = function() { /** * Adjust the graph layout due to changed size. */ -Nengo.Value.prototype.on_resize = function(width, height) { +Value.prototype.on_resize = function(width, height) { if (width < this.minWidth) { width = this.minWidth; } @@ -253,7 +262,7 @@ Nengo.Value.prototype.on_resize = function(width, height) { this.div.style.height = height; }; -Nengo.Value.prototype.generate_menu = function() { +Value.prototype.generate_menu = function() { var self = this; var items = []; items.push(['Set range...', function() { @@ -279,16 +288,16 @@ Nengo.Value.prototype.generate_menu = function() { }]); // Add the parent's menu items to this - return $.merge(items, Nengo.Component.prototype.generate_menu.call(this)); + return $.merge(items, Component.prototype.generate_menu.call(this)); }; -Nengo.Value.prototype.set_show_legend = function(value) { +Value.prototype.set_show_legend = function(value) { if (this.show_legend !== value) { this.show_legend = value; this.save_layout(); if (this.show_legend === true) { - Nengo.draw_legend(this.legend, + utils.draw_legend(this.legend, this.legend_labels.slice(0, this.n_lines), this.color_func); } else { @@ -300,12 +309,12 @@ Nengo.Value.prototype.set_show_legend = function(value) { } }; -Nengo.Value.prototype.set_legend_labels = function() { +Value.prototype.set_legend_labels = function() { var self = this; - Nengo.modal.title('Enter comma seperated legend label values'); - Nengo.modal.single_input_body('Legend label', 'New value'); - Nengo.modal.footer('ok_cancel', function(e) { + self.sim.modal.title('Enter comma seperated legend label values'); + self.sim.modal.single_input_body('Legend label', 'New value'); + self.sim.modal.footer('ok_cancel', function(e) { var label_csv = $('#singleInput').val(); var modal = $('#myModalForm').data('bs.validator'); @@ -328,17 +337,17 @@ Nengo.Value.prototype.set_legend_labels = function() { self.legend.removeChild(self.legend.lastChild); } - Nengo.draw_legend(self.legend, self.legend_labels, self.color_func); + utils.draw_legend(self.legend, self.legend_labels, self.color_func); self.save_layout(); } $('#OK').attr('data-dismiss', 'modal'); }); - Nengo.modal.show(); + self.sim.modal.show(); }; -Nengo.Value.prototype.layout_info = function() { - var info = Nengo.Component.prototype.layout_info.call(this); +Value.prototype.layout_info = function() { + var info = Component.prototype.layout_info.call(this); info.show_legend = this.show_legend; info.legend_labels = this.legend_labels; info.min_value = this.axes2d.scale_y.domain()[0]; @@ -346,17 +355,17 @@ Nengo.Value.prototype.layout_info = function() { return info; }; -Nengo.Value.prototype.update_layout = function(config) { +Value.prototype.update_layout = function(config) { this.update_range(config.min_value, config.max_value); - Nengo.Component.prototype.update_layout.call(this, config); + Component.prototype.update_layout.call(this, config); }; -Nengo.Value.prototype.set_range = function() { +Value.prototype.set_range = function() { var range = this.axes2d.scale_y.domain(); var self = this; - Nengo.modal.title('Set graph range...'); - Nengo.modal.single_input_body(range, 'New range'); - Nengo.modal.footer('ok_cancel', function(e) { + self.sim.modal.title('Set graph range...'); + self.sim.modal.single_input_body(range, 'New range'); + self.sim.modal.footer('ok_cancel', function(e) { var new_range = $('#singleInput').val(); var modal = $('#myModalForm').data('bs.validator'); modal.validate(); @@ -391,7 +400,7 @@ Nengo.Value.prototype.set_range = function() { $('#singleInput').attr('data-error', 'Input should be in the ' + 'form ",".'); - Nengo.modal.show(); + self.sim.modal.show(); $('#OK').on('click', function() { var w = $(self.div).width(); var h = $(self.div).height(); @@ -399,22 +408,22 @@ Nengo.Value.prototype.set_range = function() { }); }; -Nengo.Value.prototype.update_range = function(min, max) { +Value.prototype.update_range = function(min, max) { this.axes2d.scale_y.domain([min, max]); this.axes2d.axis_y_g.call(this.axes2d.axis_y); }; -Nengo.Value.prototype.reset = function(event) { +Value.prototype.reset = function(event) { this.data_store.reset(); this.schedule_update(); }; -Nengo.Value.prototype.set_synapse_dialog = function() { +Value.prototype.set_synapse_dialog = function() { var self = this; - Nengo.modal.title('Set synaptic filter...'); - Nengo.modal.single_input_body(this.synapse, + self.sim.modal.title('Set synaptic filter...'); + self.sim.modal.single_input_body(this.synapse, 'Filter time constant (in seconds)'); - Nengo.modal.footer('ok_cancel', function(e) { + self.sim.modal.footer('ok_cancel', function(e) { var new_synapse = $('#singleInput').val(); var modal = $('#myModalForm').data('bs.validator'); modal.validate(); @@ -446,5 +455,7 @@ Nengo.Value.prototype.set_synapse_dialog = function() { }, }); $('#singleInput').attr('data-error', 'should be a non-negative number'); - Nengo.modal.show(); + self.sim.modal.show(); }; + +module.exports = Value; diff --git a/nengo_gui/static/components/xy_axes.js b/nengo_gui/static/components/xy_axes.js index b08c4440..315167fa 100644 --- a/nengo_gui/static/components/xy_axes.js +++ b/nengo_gui/static/components/xy_axes.js @@ -10,8 +10,10 @@ * @param {float} args.max_value - maximum value on y-axis */ -Nengo.XYAxes = function(parent, args) { - Nengo.Axes2D.call(this, parent, args); +var Axes2D = require('./2d_axes'); + +XYAxes = function(parent, args) { + Axes2D.call(this, parent, args); this.scale_x.domain([args.min_value, args.max_value]); this.axis_x.tickValues([args.min_value, args.max_value]); @@ -21,14 +23,14 @@ Nengo.XYAxes = function(parent, args) { this.max_val = args.max_value; }; -Nengo.XYAxes.prototype = Object.create(Nengo.Axes2D.prototype); -Nengo.XYAxes.prototype.constructor = Nengo.XYAxes; +XYAxes.prototype = Object.create(Axes2D.prototype); +XYAxes.prototype.constructor = XYAxes; /** * Adjust the graph layout due to changed size. */ -Nengo.XYAxes.prototype.on_resize = function(width, height) { - Nengo.Axes2D.prototype.on_resize.call(this, width, height); +XYAxes.prototype.on_resize = function(width, height) { + Axes2D.prototype.on_resize.call(this, width, height); var x_offset = this.ax_bottom - this.min_val / (this.max_val - this.min_val) * (this.ax_top - this.ax_bottom); @@ -40,3 +42,5 @@ Nengo.XYAxes.prototype.on_resize = function(width, height) { this.axis_y_g.attr("transform", "translate(" + y_offset + ", 0)"); this.axis_y_g.call(this.axis_y); }; + +module.exports = XYAxes; diff --git a/nengo_gui/static/components/xyvalue.js b/nengo_gui/static/components/xyvalue.js index 67a98144..9ea74d88 100644 --- a/nengo_gui/static/components/xyvalue.js +++ b/nengo_gui/static/components/xyvalue.js @@ -3,29 +3,36 @@ * * @constructor * @param {DOMElement} parent - the exylement to add this component to - * @param {Nengo.SimControl} sim - the simulation controller - * @param {dict} args - A set of constructor arguments (see Nengo.Component) + * @param {SimControl} sim - the simulation controller + * @param {dict} args - A set of constructor arguments (see Component) * @param {int} args.n_lines - number of decoded values * @param {float} args.min_value - minimum value on x-axis and y-axis * @param {float} args.max_value - maximum value on x-axis and y-axis - * @param {Nengo.SimControl} args.sim - the simulation controller + * @param {SimControl} args.sim - the simulation controller * * XYValue constructor is called by python server when a user requests a plot * or when the config file is making graphs. Server request is handled in * netgraph.js {.on_message} function. */ -Nengo.XYValue = function(parent, sim, args) { - Nengo.Component.call(this, parent, args); +require('./xyvalue.css'); +var d3 = require('d3'); +var Component = require('./component').Component; +var DataStore = require('../datastore').DataStore; +var utils = require('../utils'); +var XYAxes = require('./xy_axes'); + +var XYValue = function(parent, viewport, sim, args) { + Component.call(this, parent, viewport, args); var self = this; this.n_lines = args.n_lines || 1; this.sim = sim; // For storing the accumulated data - this.data_store = new Nengo.DataStore(this.n_lines, this.sim, 0); + this.data_store = new DataStore(this.n_lines, this.sim, 0); - this.axes2d = new Nengo.XYAxes(this.div, args); + this.axes2d = new XYAxes(this.div, args); // The two indices of the multi-dimensional data to display this.index_x = args.index_x; @@ -53,14 +60,14 @@ Nengo.XYValue = function(parent, sim, args) { .data([this.data_store.data[this.index_y]]); this.path.enter().append('path') .attr('class', 'line') - .style('stroke', Nengo.make_colors(1)); + .style('stroke', utils.make_colors(1)); // Create a circle to track the most recent data this.recent_circle = this.axes2d.svg.append("circle") .attr("r", this.get_circle_radius()) .attr('cx', this.axes2d.scale_x(0)) .attr('cy', this.axes2d.scale_y(0)) - .style("fill", Nengo.make_colors(1)[0]) + .style("fill", utils.make_colors(1)[0]) .style('fill-opacity', 0); this.invalid_dims = false; @@ -69,13 +76,13 @@ Nengo.XYValue = function(parent, sim, args) { this.on_resize(this.get_screen_width(), this.get_screen_height()); }; -Nengo.XYValue.prototype = Object.create(Nengo.Component.prototype); -Nengo.XYValue.prototype.constructor = Nengo.XYValue; +XYValue.prototype = Object.create(Component.prototype); +XYValue.prototype.constructor = XYValue; /** * Receive new line data from the server. */ -Nengo.XYValue.prototype.on_message = function(event) { +XYValue.prototype.on_message = function(event) { var data = new Float32Array(event.data); this.data_store.push(data); this.schedule_update(); @@ -84,7 +91,7 @@ Nengo.XYValue.prototype.on_message = function(event) { /** * Redraw the lines and axis due to changed data. */ -Nengo.XYValue.prototype.update = function() { +XYValue.prototype.update = function() { var self = this; // Let the data store clear out old values @@ -138,7 +145,7 @@ Nengo.XYValue.prototype.update = function() { /** * Adjust the graph layout due to changed size */ -Nengo.XYValue.prototype.on_resize = function(width, height) { +XYValue.prototype.on_resize = function(width, height) { this.axes2d.on_resize(width, height); this.update(); @@ -151,11 +158,11 @@ Nengo.XYValue.prototype.on_resize = function(width, height) { this.recent_circle.attr("r", this.get_circle_radius()); }; -Nengo.XYValue.prototype.get_circle_radius = function() { +XYValue.prototype.get_circle_radius = function() { return Math.min(this.width, this.height) / 30; }; -Nengo.XYValue.prototype.generate_menu = function() { +XYValue.prototype.generate_menu = function() { var self = this; var items = []; items.push(['Set range...', function() { @@ -166,11 +173,11 @@ Nengo.XYValue.prototype.generate_menu = function() { }]); // Add the parent's menu items to this - return $.merge(items, Nengo.Component.prototype.generate_menu.call(this)); + return $.merge(items, Component.prototype.generate_menu.call(this)); }; -Nengo.XYValue.prototype.layout_info = function() { - var info = Nengo.Component.prototype.layout_info.call(this); +XYValue.prototype.layout_info = function() { + var info = Component.prototype.layout_info.call(this); info.min_value = this.axes2d.scale_y.domain()[0]; info.max_value = this.axes2d.scale_y.domain()[1]; info.index_x = this.index_x; @@ -178,18 +185,18 @@ Nengo.XYValue.prototype.layout_info = function() { return info; }; -Nengo.XYValue.prototype.update_layout = function(config) { +XYValue.prototype.update_layout = function(config) { this.update_indices(config.index_x, config.index_y); this.update_range(config.min_value, config.max_value); - Nengo.Component.prototype.update_layout.call(this, config); + Component.prototype.update_layout.call(this, config); }; -Nengo.XYValue.prototype.set_range = function() { +XYValue.prototype.set_range = function() { var range = this.axes2d.scale_y.domain(); var self = this; - Nengo.modal.title('Set graph range...'); - Nengo.modal.single_input_body(range, 'New range'); - Nengo.modal.footer('ok_cancel', function(e) { + self.sim.modal.title('Set graph range...'); + self.sim.modal.single_input_body(range, 'New range'); + self.sim.modal.footer('ok_cancel', function(e) { var new_range = $('#singleInput').val(); var modal = $('#myModalForm').data('bs.validator'); @@ -228,10 +235,10 @@ Nengo.XYValue.prototype.set_range = function() { $('#singleInput').attr('data-error', 'Input should be in the form ' + '"," and the axes must cross at zero.'); - Nengo.modal.show(); + self.sim.modal.show(); }; -Nengo.XYValue.prototype.update_range = function(min, max) { +XYValue.prototype.update_range = function(min, max) { this.axes2d.min_val = min; this.axes2d.max_val = max; this.axes2d.scale_x.domain([min, max]); @@ -243,11 +250,12 @@ Nengo.XYValue.prototype.update_range = function(min, max) { this.on_resize(this.get_screen_width(), this.get_screen_height()); }; -Nengo.XYValue.prototype.set_indices = function() { +XYValue.prototype.set_indices = function() { var self = this; - Nengo.modal.title('Set X and Y indices...'); - Nengo.modal.single_input_body([this.index_x, this.index_y], 'New indices'); - Nengo.modal.footer('ok_cancel', function(e) { + self.sim.modal.title('Set X and Y indices...'); + self.sim.modal.single_input_body( + [this.index_x, this.index_y], 'New indices'); + self.sim.modal.footer('ok_cancel', function(e) { var new_indices = $('#singleInput').val(); var modal = $('#myModalForm').data('bs.validator'); @@ -283,16 +291,18 @@ Nengo.XYValue.prototype.set_indices = function() { 'integers in the form ",". ' + 'Dimensions are zero indexed.'); - Nengo.modal.show(); + self.sim.modal.show(); }; -Nengo.XYValue.prototype.update_indices = function(index_x, index_y) { +XYValue.prototype.update_indices = function(index_x, index_y) { this.index_x = index_x; this.index_y = index_y; this.update(); }; -Nengo.XYValue.prototype.reset = function(event) { +XYValue.prototype.reset = function(event) { this.data_store.reset(); this.schedule_update(); }; + +module.exports = XYValue; diff --git a/nengo_gui/static/config.js b/nengo_gui/static/config.js index a8805730..b91d191c 100644 --- a/nengo_gui/static/config.js +++ b/nengo_gui/static/config.js @@ -1,4 +1,4 @@ -Nengo.Config = function(parent, args) { +var Config = function() { var self = this; define_option = function(key, default_val) { @@ -28,7 +28,7 @@ Nengo.Config = function(parent, args) { define_option("font_size", 100); define_option("scriptdir", "."); - // Ace editor options + // Editor options define_option("hide_editor", false); define_option("editor_width", 580); define_option("editor_font_size", 12); @@ -36,7 +36,7 @@ Nengo.Config = function(parent, args) { define_option("console_height", 100); }; -Nengo.Config.prototype.restore_defaults = function() { +Config.prototype.restore_defaults = function() { for (var option in this) { if (this.hasOwnProperty(option)) { localStorage.removeItem("ng." + option); @@ -44,4 +44,4 @@ Nengo.Config.prototype.restore_defaults = function() { } }; -Nengo.config = new Nengo.Config(); +module.exports = Config; diff --git a/nengo_gui/static/data_to_csv.js b/nengo_gui/static/data_to_csv.js index a3a8cc86..bd12a5d7 100644 --- a/nengo_gui/static/data_to_csv.js +++ b/nengo_gui/static/data_to_csv.js @@ -4,10 +4,12 @@ * As well, it only saves the data in the datastore, which is based on the * amount of time kept in the simulation. * - * @param {Nengo.Component[]} data_set - * A list of the graph items in the simulation + * @param {Component[]} data_set - A list of the graph items in the simulation */ +var Value = require('./components/value'); +var XYValue = require('./components/xyvalue'); + var data_to_csv = function(data_set) { var values = []; @@ -17,8 +19,7 @@ var data_to_csv = function(data_set) { var csv_string = ""; var data_set = data_set.filter(function(data) { - return data.constructor === Nengo.Value || - data.constructor === Nengo.XYValue; + return data.constructor === Value || data.constructor === XYValue; }); // Extracts all the values from the data_set variable diff --git a/nengo_gui/static/datastore.js b/nengo_gui/static/datastore.js index 88fa31fd..530f2ae0 100644 --- a/nengo_gui/static/datastore.js +++ b/nengo_gui/static/datastore.js @@ -4,12 +4,12 @@ * * @constructor * @param {int} dims - number of data points per time - * @param {Nengo.SimControl} sim - the simulation controller + * @param {SimControl} sim - the simulation controller * @param {float} synapse - the filter to apply to the data */ -Nengo.DataStore = function(dims, sim, synapse) { - this.synapse = synapse; // TODO: get from Nengo.SimControl +var DataStore = function(dims, sim, synapse) { + this.synapse = synapse; // TODO: get from SimControl this.sim = sim; this.times = []; this.data = []; @@ -23,7 +23,7 @@ Nengo.DataStore = function(dims, sim, synapse) { * * @param {array} row - dims+1 data points, with time as the first one */ -Nengo.DataStore.prototype.push = function(row) { +DataStore.prototype.push = function(row) { // If you get data out of order, wipe out the later data if (row[0] < this.times[this.times.length - 1]) { var index = 0; @@ -64,7 +64,7 @@ Nengo.DataStore.prototype.push = function(row) { * This will clear current data so there is * nothing to display on a reset event. */ -Nengo.DataStore.prototype.reset = function() { +DataStore.prototype.reset = function() { var index = 0; this.times.splice(index, this.times.length); for (var i = 0; i < this.data.length; i++) { @@ -77,9 +77,9 @@ Nengo.DataStore.prototype.reset = function() { * * This should be call periodically (before visual updates, but not necessarily * after every push()). Removes old data outside the storage limit set by - * the Nengo.SimControl. + * the SimControl. */ -Nengo.DataStore.prototype.update = function() { +DataStore.prototype.update = function() { // Figure out how many extra values we have (values whose time stamp is // outside the range to keep) var extra = 0; @@ -102,7 +102,7 @@ Nengo.DataStore.prototype.update = function() { /** * Return just the data that is to be shown. */ -Nengo.DataStore.prototype.get_shown_data = function() { +DataStore.prototype.get_shown_data = function() { // Determine time range var t1 = this.sim.time_slider.first_shown_time; var t2 = t1 + this.sim.time_slider.shown_time; @@ -126,12 +126,12 @@ Nengo.DataStore.prototype.get_shown_data = function() { return shown; }; -Nengo.DataStore.prototype.is_at_end = function() { +DataStore.prototype.is_at_end = function() { var ts = this.sim.time_slider; return (ts.last_time < ts.first_shown_time + ts.shown_time + 1e-9); }; -Nengo.DataStore.prototype.get_last_data = function() { +DataStore.prototype.get_last_data = function() { // Determine time range var t1 = this.sim.time_slider.first_shown_time; var t2 = t1 + this.sim.time_slider.shown_time; @@ -156,11 +156,12 @@ Nengo.DataStore.prototype.get_last_data = function() { * * @constructor * @param {int} dims - number of data points per time - * @param {Nengo.SimControl} sim - the simulation controller + * @param {SimControl} sim - the simulation controller * @param {float} synapse - the filter to apply to the data */ -Nengo.GrowableDataStore = function(dims, sim, synapse) { - Nengo.DataStore.call(this, dims, sim, synapse); +var GrowableDataStore = function(dims, sim, synapse) { + DataStore.call(this, dims, sim, synapse); + this._dims = dims; Object.defineProperty(this, "dims", { @@ -182,10 +183,10 @@ Nengo.GrowableDataStore = function(dims, sim, synapse) { }); }; -Nengo.GrowableDataStore.prototype = Object.create(Nengo.DataStore.prototype); -Nengo.GrowableDataStore.prototype.constructor = Nengo.GrowableDataStore; +GrowableDataStore.prototype = Object.create(DataStore.prototype); +GrowableDataStore.prototype.constructor = GrowableDataStore; -Nengo.GrowableDataStore.prototype.get_offset = function() { +GrowableDataStore.prototype.get_offset = function() { var offset = []; offset.push(0); @@ -205,7 +206,7 @@ Nengo.GrowableDataStore.prototype.get_offset = function() { * * @param {array} row - dims+1 data points, with time as the first one */ -Nengo.GrowableDataStore.prototype.push = function(row) { +GrowableDataStore.prototype.push = function(row) { // Get the offsets var offset = this.get_offset(); @@ -247,10 +248,10 @@ Nengo.GrowableDataStore.prototype.push = function(row) { /** * Reset dimensions before resetting the datastore. */ -Nengo.GrowableDataStore.prototype.reset = function() { +GrowableDataStore.prototype.reset = function() { console.log("resetting growable"); this._dims = 1; - Nengo.DataStore.call(this, this._dims, this.sim, this.synapse); + DataStore.call(this, this._dims, this.sim, this.synapse); }; /** @@ -258,9 +259,9 @@ Nengo.GrowableDataStore.prototype.reset = function() { * * This should be call periodically (before visual updates, but not necessarily * after every push()). Removes old data outside the storage limit set by - * the Nengo.SimControl. + * the SimControl. */ -Nengo.GrowableDataStore.prototype.update = function() { +GrowableDataStore.prototype.update = function() { // Figure out how many extra values we have (values whose time stamp is // outside the range to keep) var offset = this.get_offset(); @@ -285,7 +286,7 @@ Nengo.GrowableDataStore.prototype.update = function() { /** * Return just the data that is to be shown. */ -Nengo.GrowableDataStore.prototype.get_shown_data = function() { +GrowableDataStore.prototype.get_shown_data = function() { var offset = this.get_offset(); // Determine time range var t1 = this.sim.time_slider.first_shown_time; @@ -336,7 +337,7 @@ Nengo.GrowableDataStore.prototype.get_shown_data = function() { return shown; }; -Nengo.GrowableDataStore.prototype.get_last_data = function() { +GrowableDataStore.prototype.get_last_data = function() { var offset = this.get_offset(); // Determine time range var t1 = this.sim.time_slider.first_shown_time; @@ -357,3 +358,6 @@ Nengo.GrowableDataStore.prototype.get_last_data = function() { } return shown; }; + +module.exports.DataStore = DataStore; +module.exports.GrowableDataStore = GrowableDataStore; diff --git a/nengo_gui/static/dist/nengo.js b/nengo_gui/static/dist/nengo.js index e4f89803..d8cceacf 100644 --- a/nengo_gui/static/dist/nengo.js +++ b/nengo_gui/static/dist/nengo.js @@ -1,4 +1,4 @@ -var Nengo=function(t){function e(n){if(i[n])return i[n].exports;var o=i[n]={exports:{},id:n,loaded:!1};return t[n].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var i={};return e.m=t,e.c=i,e.p="/static/dist/",e(0)}([function(t,e,i){t.exports=i(2)},function(t,e,i){var n,o;/*! +var Nengo=function(t){function e(n){if(i[n])return i[n].exports;var o=i[n]={exports:{},id:n,loaded:!1};return t[n].call(o.exports,o,o.exports,e),o.loaded=!0,o.exports}var i={};return e.m=t,e.c=i,e.p="/static/dist/",e(0)}([function(t,e,i){t.exports=i(42)},function(t,e,i){var n,o;/*! * jQuery JavaScript Library v2.1.3 * http://jquery.com/ * @@ -11,7 +11,7 @@ var Nengo=function(t){function e(n){if(i[n])return i[n].exports;var o=i[n]={expo * * Date: 2014-12-18T15:11Z */ -!function(e,i){"object"==typeof t&&"object"==typeof t.exports?t.exports=e.document?i(e,!0):function(t){if(!t.document)throw new Error("jQuery requires a window with a document");return i(t)}:i(e)}("undefined"!=typeof window?window:this,function(i,r){function s(t){var e=t.length,i=nt.type(t);return"function"!==i&&!nt.isWindow(t)&&(!(1!==t.nodeType||!e)||("array"===i||0===e||"number"==typeof e&&e>0&&e-1 in t))}function a(t,e,i){if(nt.isFunction(e))return nt.grep(t,function(t,n){return!!e.call(t,n,t)!==i});if(e.nodeType)return nt.grep(t,function(t){return t===e!==i});if("string"==typeof e){if(ut.test(e))return nt.filter(e,t,i);e=nt.filter(e,t)}return nt.grep(t,function(t){return Q.call(e,t)>=0!==i})}function l(t,e){for(;(t=t[e])&&1!==t.nodeType;);return t}function h(t){var e=bt[t]={};return nt.each(t.match(vt)||[],function(t,i){e[i]=!0}),e}function c(){et.removeEventListener("DOMContentLoaded",c,!1),i.removeEventListener("load",c,!1),nt.ready()}function u(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=nt.expando+u.uid++}function d(t,e,i){var n;if(void 0===i&&1===t.nodeType)if(n="data-"+e.replace(Ct,"-$1").toLowerCase(),i=t.getAttribute(n),"string"==typeof i){try{i="true"===i||"false"!==i&&("null"===i?null:+i+""===i?+i:_t.test(i)?nt.parseJSON(i):i)}catch(o){}At.set(t,e,i)}else i=void 0;return i}function p(){return!0}function f(){return!1}function g(){try{return et.activeElement}catch(t){}}function m(t,e){return nt.nodeName(t,"table")&&nt.nodeName(11!==e.nodeType?e:e.firstChild,"tr")?t.getElementsByTagName("tbody")[0]||t.appendChild(t.ownerDocument.createElement("tbody")):t}function v(t){return t.type=(null!==t.getAttribute("type"))+"/"+t.type,t}function b(t){var e=Pt.exec(t.type);return e?t.type=e[1]:t.removeAttribute("type"),t}function y(t,e){for(var i=0,n=t.length;i")).appendTo(e.documentElement),e=Ut[0].contentDocument,e.write(),e.close(),i=_(t,e),Ut.detach()),jt[t]=i),i}function E(t,e,i){var n,o,r,s,a=t.style;return i=i||Kt(t),i&&(s=i.getPropertyValue(e)||i[e]),i&&(""!==s||nt.contains(t.ownerDocument,t)||(s=nt.style(t,e)),qt.test(s)&&Vt.test(e)&&(n=a.width,o=a.minWidth,r=a.maxWidth,a.minWidth=a.maxWidth=a.width=s,s=i.width,a.width=n,a.minWidth=o,a.maxWidth=r)),void 0!==s?s+"":s}function k(t,e){return{get:function(){return t()?void delete this.get:(this.get=e).apply(this,arguments)}}}function F(t,e){if(e in t)return e;for(var i=e[0].toUpperCase()+e.slice(1),n=e,o=Zt.length;o--;)if(e=Zt[o]+i,e in t)return e;return n}function S(t,e,i){var n=Gt.exec(e);return n?Math.max(0,n[1]-(i||0))+(n[2]||"px"):e}function D(t,e,i,n,o){for(var r=i===(n?"border":"content")?4:"width"===e?1:0,s=0;r<4;r+=2)"margin"===i&&(s+=nt.css(t,i+kt[r],!0,o)),n?("content"===i&&(s-=nt.css(t,"padding"+kt[r],!0,o)),"margin"!==i&&(s-=nt.css(t,"border"+kt[r]+"Width",!0,o))):(s+=nt.css(t,"padding"+kt[r],!0,o),"padding"!==i&&(s+=nt.css(t,"border"+kt[r]+"Width",!0,o)));return s}function M(t,e,i){var n=!0,o="width"===e?t.offsetWidth:t.offsetHeight,r=Kt(t),s="border-box"===nt.css(t,"boxSizing",!1,r);if(o<=0||null==o){if(o=E(t,e,r),(o<0||null==o)&&(o=t.style[e]),qt.test(o))return o;n=s&&(tt.boxSizingReliable()||o===t.style[e]),o=parseFloat(o)||0}return o+D(t,e,i||(s?"border":"content"),n,r)+"px"}function T(t,e){for(var i,n,o,r=[],s=0,a=t.length;s=0&&i=0},isPlainObject:function(t){return"object"===nt.type(t)&&!t.nodeType&&!nt.isWindow(t)&&!(t.constructor&&!Z.call(t.constructor.prototype,"isPrototypeOf"))},isEmptyObject:function(t){var e;for(e in t)return!1;return!0},type:function(t){return null==t?t+"":"object"==typeof t||"function"==typeof t?X[J.call(t)]||"object":typeof t},globalEval:function(t){var e,i=eval;t=nt.trim(t),t&&(1===t.indexOf("use strict")?(e=et.createElement("script"),e.text=t,et.head.appendChild(e).parentNode.removeChild(e)):i(t))},camelCase:function(t){return t.replace(rt,"ms-").replace(st,at)},nodeName:function(t,e){return t.nodeName&&t.nodeName.toLowerCase()===e.toLowerCase()},each:function(t,e,i){var n,o=0,r=t.length,a=s(t);if(i){if(a)for(;o0&&e-1 in t))}function a(t,e,i){if(nt.isFunction(e))return nt.grep(t,function(t,n){return!!e.call(t,n,t)!==i});if(e.nodeType)return nt.grep(t,function(t){return t===e!==i});if("string"==typeof e){if(ut.test(e))return nt.filter(e,t,i);e=nt.filter(e,t)}return nt.grep(t,function(t){return Q.call(e,t)>=0!==i})}function l(t,e){for(;(t=t[e])&&1!==t.nodeType;);return t}function h(t){var e=bt[t]={};return nt.each(t.match(vt)||[],function(t,i){e[i]=!0}),e}function c(){et.removeEventListener("DOMContentLoaded",c,!1),i.removeEventListener("load",c,!1),nt.ready()}function u(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=nt.expando+u.uid++}function d(t,e,i){var n;if(void 0===i&&1===t.nodeType)if(n="data-"+e.replace(Ct,"-$1").toLowerCase(),i=t.getAttribute(n),"string"==typeof i){try{i="true"===i||"false"!==i&&("null"===i?null:+i+""===i?+i:_t.test(i)?nt.parseJSON(i):i)}catch(o){}At.set(t,e,i)}else i=void 0;return i}function p(){return!0}function f(){return!1}function g(){try{return et.activeElement}catch(t){}}function m(t,e){return nt.nodeName(t,"table")&&nt.nodeName(11!==e.nodeType?e:e.firstChild,"tr")?t.getElementsByTagName("tbody")[0]||t.appendChild(t.ownerDocument.createElement("tbody")):t}function v(t){return t.type=(null!==t.getAttribute("type"))+"/"+t.type,t}function b(t){var e=Pt.exec(t.type);return e?t.type=e[1]:t.removeAttribute("type"),t}function y(t,e){for(var i=0,n=t.length;i")).appendTo(e.documentElement),e=Ut[0].contentDocument,e.write(),e.close(),i=_(t,e),Ut.detach()),jt[t]=i),i}function E(t,e,i){var n,o,r,s,a=t.style;return i=i||Kt(t),i&&(s=i.getPropertyValue(e)||i[e]),i&&(""!==s||nt.contains(t.ownerDocument,t)||(s=nt.style(t,e)),qt.test(s)&&Vt.test(e)&&(n=a.width,o=a.minWidth,r=a.maxWidth,a.minWidth=a.maxWidth=a.width=s,s=i.width,a.width=n,a.minWidth=o,a.maxWidth=r)),void 0!==s?s+"":s}function k(t,e){return{get:function(){return t()?void delete this.get:(this.get=e).apply(this,arguments)}}}function F(t,e){if(e in t)return e;for(var i=e[0].toUpperCase()+e.slice(1),n=e,o=Zt.length;o--;)if(e=Zt[o]+i,e in t)return e;return n}function D(t,e,i){var n=Gt.exec(e);return n?Math.max(0,n[1]-(i||0))+(n[2]||"px"):e}function S(t,e,i,n,o){for(var r=i===(n?"border":"content")?4:"width"===e?1:0,s=0;r<4;r+=2)"margin"===i&&(s+=nt.css(t,i+kt[r],!0,o)),n?("content"===i&&(s-=nt.css(t,"padding"+kt[r],!0,o)),"margin"!==i&&(s-=nt.css(t,"border"+kt[r]+"Width",!0,o))):(s+=nt.css(t,"padding"+kt[r],!0,o),"padding"!==i&&(s+=nt.css(t,"border"+kt[r]+"Width",!0,o)));return s}function M(t,e,i){var n=!0,o="width"===e?t.offsetWidth:t.offsetHeight,r=Kt(t),s="border-box"===nt.css(t,"boxSizing",!1,r);if(o<=0||null==o){if(o=E(t,e,r),(o<0||null==o)&&(o=t.style[e]),qt.test(o))return o;n=s&&(tt.boxSizingReliable()||o===t.style[e]),o=parseFloat(o)||0}return o+S(t,e,i||(s?"border":"content"),n,r)+"px"}function T(t,e){for(var i,n,o,r=[],s=0,a=t.length;s=0&&i=0},isPlainObject:function(t){return"object"===nt.type(t)&&!t.nodeType&&!nt.isWindow(t)&&!(t.constructor&&!Z.call(t.constructor.prototype,"isPrototypeOf"))},isEmptyObject:function(t){var e;for(e in t)return!1;return!0},type:function(t){return null==t?t+"":"object"==typeof t||"function"==typeof t?X[J.call(t)]||"object":typeof t},globalEval:function(t){var e,i=eval;t=nt.trim(t),t&&(1===t.indexOf("use strict")?(e=et.createElement("script"),e.text=t,et.head.appendChild(e).parentNode.removeChild(e)):i(t))},camelCase:function(t){return t.replace(rt,"ms-").replace(st,at)},nodeName:function(t,e){return t.nodeName&&t.nodeName.toLowerCase()===e.toLowerCase()},each:function(t,e,i){var n,o=0,r=t.length,a=s(t);if(i){if(a)for(;oA.cacheLength&&delete t[e.shift()],t[i+" "]=n}var e=[];return t}function n(t){return t[O]=!0,t}function o(t){var e=B.createElement("div");try{return!!t(e)}catch(i){return!1}finally{e.parentNode&&e.parentNode.removeChild(e),e=null}}function r(t,e){for(var i=t.split("|"),n=t.length;n--;)A.attrHandle[i[n]]=e}function s(t,e){var i=e&&t,n=i&&1===t.nodeType&&1===e.nodeType&&(~e.sourceIndex||K)-(~t.sourceIndex||K);if(n)return n;if(i)for(;i=i.nextSibling;)if(i===e)return-1;return t?1:-1}function a(t){return function(e){var i=e.nodeName.toLowerCase();return"input"===i&&e.type===t}}function l(t){return function(e){var i=e.nodeName.toLowerCase();return("input"===i||"button"===i)&&e.type===t}}function h(t){return n(function(e){return e=+e,n(function(i,n){for(var o,r=t([],i.length,e),s=r.length;s--;)i[o=r[s]]&&(i[o]=!(n[o]=i[o]))})})}function c(t){return t&&"undefined"!=typeof t.getElementsByTagName&&t}function u(){}function d(t){for(var e=0,i=t.length,n="";e1?function(e,i,n){for(var o=t.length;o--;)if(!t[o](e,i,n))return!1;return!0}:t[0]}function g(t,i,n){for(var o=0,r=i.length;o-1&&(n[h]=!(s[h]=u))}}else y=m(y===s?y.splice(f,y.length):y),r?r(null,s,y,l):J.apply(s,y)})}function b(t){for(var e,i,n,o=t.length,r=A.relative[t[0].type],s=r||A.relative[" "],a=r?1:0,l=p(function(t){return t===e},s,!0),h=p(function(t){return tt(e,t)>-1},s,!0),c=[function(t,i,n){var o=!r&&(n||i!==S)||((e=i).nodeType?l(t,i,n):h(t,i,n));return e=null,o}];a1&&f(c),a>1&&d(t.slice(0,a-1).concat({value:" "===t[a-2].type?"*":""})).replace(lt,"$1"),i,a0,r=t.length>0,s=function(n,s,a,l,h){var c,u,d,p=0,f="0",g=n&&[],v=[],b=S,y=n||r&&A.find.TAG("*",h),w=H+=null==b?1:Math.random()||.1,x=y.length;for(h&&(S=s!==B&&s);f!==x&&null!=(c=y[f]);f++){if(r&&c){for(u=0;d=t[u++];)if(d(c,s,a)){l.push(c);break}h&&(H=w)}o&&((c=!d&&c)&&p--,n&&g.push(c))}if(p+=f,o&&f!==p){for(u=0;d=i[u++];)d(g,v,s,a);if(n){if(p>0)for(;f--;)g[f]||v[f]||(v[f]=Q.call(l));v=m(v)}J.apply(l,v),h&&!n&&v.length>0&&p+i.length>1&&e.uniqueSort(l)}return h&&(H=w,S=b),g};return o?n(s):s}var w,x,A,_,C,E,k,F,S,D,M,T,B,L,$,R,I,z,N,O="sizzle"+1*new Date,P=t.document,H=0,W=0,U=i(),j=i(),V=i(),q=function(t,e){return t===e&&(M=!0),0},K=1<<31,Y={}.hasOwnProperty,G=[],Q=G.pop,X=G.push,J=G.push,Z=G.slice,tt=function(t,e){for(var i=0,n=t.length;i+~]|"+it+")"+it+"*"),ut=new RegExp("="+it+"*([^\\]'\"]*?)"+it+"*\\]","g"),dt=new RegExp(st),pt=new RegExp("^"+ot+"$"),ft={ID:new RegExp("^#("+nt+")"),CLASS:new RegExp("^\\.("+nt+")"),TAG:new RegExp("^("+nt.replace("w","w*")+")"),ATTR:new RegExp("^"+rt),PSEUDO:new RegExp("^"+st),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+it+"*(even|odd|(([+-]|)(\\d*)n|)"+it+"*(?:([+-]|)"+it+"*(\\d+)|))"+it+"*\\)|)","i"),bool:new RegExp("^(?:"+et+")$","i"),needsContext:new RegExp("^"+it+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+it+"*((?:-\\d)?\\d*)"+it+"*\\)|)(?=[^-]|$)","i")},gt=/^(?:input|select|textarea|button)$/i,mt=/^h\d$/i,vt=/^[^{]+\{\s*\[native \w/,bt=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,yt=/[+~]/,wt=/'|\\/g,xt=new RegExp("\\\\([\\da-f]{1,6}"+it+"?|("+it+")|.)","ig"),At=function(t,e,i){var n="0x"+e-65536;return n!==n||i?e:n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320)},_t=function(){T()};try{J.apply(G=Z.call(P.childNodes),P.childNodes),G[P.childNodes.length].nodeType}catch(Ct){J={apply:G.length?function(t,e){X.apply(t,Z.call(e))}:function(t,e){for(var i=t.length,n=0;t[i++]=e[n++];);t.length=i-1}}}x=e.support={},C=e.isXML=function(t){var e=t&&(t.ownerDocument||t).documentElement;return!!e&&"HTML"!==e.nodeName},T=e.setDocument=function(t){var e,i,n=t?t.ownerDocument||t:P;return n!==B&&9===n.nodeType&&n.documentElement?(B=n,L=n.documentElement,i=n.defaultView,i&&i!==i.top&&(i.addEventListener?i.addEventListener("unload",_t,!1):i.attachEvent&&i.attachEvent("onunload",_t)),$=!C(n),x.attributes=o(function(t){return t.className="i",!t.getAttribute("className")}),x.getElementsByTagName=o(function(t){return t.appendChild(n.createComment("")),!t.getElementsByTagName("*").length}),x.getElementsByClassName=vt.test(n.getElementsByClassName),x.getById=o(function(t){return L.appendChild(t).id=O,!n.getElementsByName||!n.getElementsByName(O).length}),x.getById?(A.find.ID=function(t,e){if("undefined"!=typeof e.getElementById&&$){var i=e.getElementById(t);return i&&i.parentNode?[i]:[]}},A.filter.ID=function(t){var e=t.replace(xt,At);return function(t){return t.getAttribute("id")===e}}):(delete A.find.ID,A.filter.ID=function(t){var e=t.replace(xt,At);return function(t){var i="undefined"!=typeof t.getAttributeNode&&t.getAttributeNode("id");return i&&i.value===e}}),A.find.TAG=x.getElementsByTagName?function(t,e){return"undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t):x.qsa?e.querySelectorAll(t):void 0}:function(t,e){var i,n=[],o=0,r=e.getElementsByTagName(t);if("*"===t){for(;i=r[o++];)1===i.nodeType&&n.push(i);return n}return r},A.find.CLASS=x.getElementsByClassName&&function(t,e){if($)return e.getElementsByClassName(t)},I=[],R=[],(x.qsa=vt.test(n.querySelectorAll))&&(o(function(t){L.appendChild(t).innerHTML="",t.querySelectorAll("[msallowcapture^='']").length&&R.push("[*^$]="+it+"*(?:''|\"\")"),t.querySelectorAll("[selected]").length||R.push("\\["+it+"*(?:value|"+et+")"),t.querySelectorAll("[id~="+O+"-]").length||R.push("~="),t.querySelectorAll(":checked").length||R.push(":checked"),t.querySelectorAll("a#"+O+"+*").length||R.push(".#.+[+~]")}),o(function(t){var e=n.createElement("input");e.setAttribute("type","hidden"),t.appendChild(e).setAttribute("name","D"),t.querySelectorAll("[name=d]").length&&R.push("name"+it+"*[*^$|!~]?="),t.querySelectorAll(":enabled").length||R.push(":enabled",":disabled"),t.querySelectorAll("*,:x"),R.push(",.*:")})),(x.matchesSelector=vt.test(z=L.matches||L.webkitMatchesSelector||L.mozMatchesSelector||L.oMatchesSelector||L.msMatchesSelector))&&o(function(t){x.disconnectedMatch=z.call(t,"div"),z.call(t,"[s!='']:x"),I.push("!=",st)}),R=R.length&&new RegExp(R.join("|")),I=I.length&&new RegExp(I.join("|")),e=vt.test(L.compareDocumentPosition),N=e||vt.test(L.contains)?function(t,e){var i=9===t.nodeType?t.documentElement:t,n=e&&e.parentNode;return t===n||!(!n||1!==n.nodeType||!(i.contains?i.contains(n):t.compareDocumentPosition&&16&t.compareDocumentPosition(n)))}:function(t,e){if(e)for(;e=e.parentNode;)if(e===t)return!0;return!1},q=e?function(t,e){if(t===e)return M=!0,0;var i=!t.compareDocumentPosition-!e.compareDocumentPosition;return i?i:(i=(t.ownerDocument||t)===(e.ownerDocument||e)?t.compareDocumentPosition(e):1,1&i||!x.sortDetached&&e.compareDocumentPosition(t)===i?t===n||t.ownerDocument===P&&N(P,t)?-1:e===n||e.ownerDocument===P&&N(P,e)?1:D?tt(D,t)-tt(D,e):0:4&i?-1:1)}:function(t,e){if(t===e)return M=!0,0;var i,o=0,r=t.parentNode,a=e.parentNode,l=[t],h=[e];if(!r||!a)return t===n?-1:e===n?1:r?-1:a?1:D?tt(D,t)-tt(D,e):0;if(r===a)return s(t,e);for(i=t;i=i.parentNode;)l.unshift(i);for(i=e;i=i.parentNode;)h.unshift(i);for(;l[o]===h[o];)o++;return o?s(l[o],h[o]):l[o]===P?-1:h[o]===P?1:0},n):B},e.matches=function(t,i){return e(t,null,null,i)},e.matchesSelector=function(t,i){if((t.ownerDocument||t)!==B&&T(t),i=i.replace(ut,"='$1']"),x.matchesSelector&&$&&(!I||!I.test(i))&&(!R||!R.test(i)))try{var n=z.call(t,i);if(n||x.disconnectedMatch||t.document&&11!==t.document.nodeType)return n}catch(o){}return e(i,B,null,[t]).length>0},e.contains=function(t,e){return(t.ownerDocument||t)!==B&&T(t),N(t,e)},e.attr=function(t,e){(t.ownerDocument||t)!==B&&T(t);var i=A.attrHandle[e.toLowerCase()],n=i&&Y.call(A.attrHandle,e.toLowerCase())?i(t,e,!$):void 0;return void 0!==n?n:x.attributes||!$?t.getAttribute(e):(n=t.getAttributeNode(e))&&n.specified?n.value:null},e.error=function(t){throw new Error("Syntax error, unrecognized expression: "+t)},e.uniqueSort=function(t){var e,i=[],n=0,o=0;if(M=!x.detectDuplicates,D=!x.sortStable&&t.slice(0),t.sort(q),M){for(;e=t[o++];)e===t[o]&&(n=i.push(o));for(;n--;)t.splice(i[n],1)}return D=null,t},_=e.getText=function(t){var e,i="",n=0,o=t.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof t.textContent)return t.textContent;for(t=t.firstChild;t;t=t.nextSibling)i+=_(t)}else if(3===o||4===o)return t.nodeValue}else for(;e=t[n++];)i+=_(e);return i},A=e.selectors={cacheLength:50,createPseudo:n,match:ft,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(t){return t[1]=t[1].replace(xt,At),t[3]=(t[3]||t[4]||t[5]||"").replace(xt,At),"~="===t[2]&&(t[3]=" "+t[3]+" "),t.slice(0,4)},CHILD:function(t){return t[1]=t[1].toLowerCase(),"nth"===t[1].slice(0,3)?(t[3]||e.error(t[0]),t[4]=+(t[4]?t[5]+(t[6]||1):2*("even"===t[3]||"odd"===t[3])),t[5]=+(t[7]+t[8]||"odd"===t[3])):t[3]&&e.error(t[0]),t},PSEUDO:function(t){var e,i=!t[6]&&t[2];return ft.CHILD.test(t[0])?null:(t[3]?t[2]=t[4]||t[5]||"":i&&dt.test(i)&&(e=E(i,!0))&&(e=i.indexOf(")",i.length-e)-i.length)&&(t[0]=t[0].slice(0,e),t[2]=i.slice(0,e)),t.slice(0,3))}},filter:{TAG:function(t){var e=t.replace(xt,At).toLowerCase();return"*"===t?function(){return!0}:function(t){return t.nodeName&&t.nodeName.toLowerCase()===e}},CLASS:function(t){var e=U[t+" "];return e||(e=new RegExp("(^|"+it+")"+t+"("+it+"|$)"))&&U(t,function(t){return e.test("string"==typeof t.className&&t.className||"undefined"!=typeof t.getAttribute&&t.getAttribute("class")||"")})},ATTR:function(t,i,n){return function(o){var r=e.attr(o,t);return null==r?"!="===i:!i||(r+="","="===i?r===n:"!="===i?r!==n:"^="===i?n&&0===r.indexOf(n):"*="===i?n&&r.indexOf(n)>-1:"$="===i?n&&r.slice(-n.length)===n:"~="===i?(" "+r.replace(at," ")+" ").indexOf(n)>-1:"|="===i&&(r===n||r.slice(0,n.length+1)===n+"-"))}},CHILD:function(t,e,i,n,o){var r="nth"!==t.slice(0,3),s="last"!==t.slice(-4),a="of-type"===e;return 1===n&&0===o?function(t){return!!t.parentNode}:function(e,i,l){var h,c,u,d,p,f,g=r!==s?"nextSibling":"previousSibling",m=e.parentNode,v=a&&e.nodeName.toLowerCase(),b=!l&&!a;if(m){if(r){for(;g;){for(u=e;u=u[g];)if(a?u.nodeName.toLowerCase()===v:1===u.nodeType)return!1;f=g="only"===t&&!f&&"nextSibling"}return!0}if(f=[s?m.firstChild:m.lastChild],s&&b){for(c=m[O]||(m[O]={}),h=c[t]||[],p=h[0]===H&&h[1],d=h[0]===H&&h[2],u=p&&m.childNodes[p];u=++p&&u&&u[g]||(d=p=0)||f.pop();)if(1===u.nodeType&&++d&&u===e){c[t]=[H,p,d];break}}else if(b&&(h=(e[O]||(e[O]={}))[t])&&h[0]===H)d=h[1];else for(;(u=++p&&u&&u[g]||(d=p=0)||f.pop())&&((a?u.nodeName.toLowerCase()!==v:1!==u.nodeType)||!++d||(b&&((u[O]||(u[O]={}))[t]=[H,d]),u!==e)););return d-=o,d===n||d%n===0&&d/n>=0}}},PSEUDO:function(t,i){var o,r=A.pseudos[t]||A.setFilters[t.toLowerCase()]||e.error("unsupported pseudo: "+t);return r[O]?r(i):r.length>1?(o=[t,t,"",i],A.setFilters.hasOwnProperty(t.toLowerCase())?n(function(t,e){for(var n,o=r(t,i),s=o.length;s--;)n=tt(t,o[s]),t[n]=!(e[n]=o[s])}):function(t){return r(t,0,o)}):r}},pseudos:{not:n(function(t){var e=[],i=[],o=k(t.replace(lt,"$1"));return o[O]?n(function(t,e,i,n){for(var r,s=o(t,null,n,[]),a=t.length;a--;)(r=s[a])&&(t[a]=!(e[a]=r))}):function(t,n,r){return e[0]=t,o(e,null,r,i),e[0]=null,!i.pop()}}),has:n(function(t){return function(i){return e(t,i).length>0}}),contains:n(function(t){return t=t.replace(xt,At),function(e){return(e.textContent||e.innerText||_(e)).indexOf(t)>-1}}),lang:n(function(t){return pt.test(t||"")||e.error("unsupported lang: "+t),t=t.replace(xt,At).toLowerCase(),function(e){var i;do if(i=$?e.lang:e.getAttribute("xml:lang")||e.getAttribute("lang"))return i=i.toLowerCase(),i===t||0===i.indexOf(t+"-");while((e=e.parentNode)&&1===e.nodeType);return!1}}),target:function(e){var i=t.location&&t.location.hash;return i&&i.slice(1)===e.id},root:function(t){return t===L},focus:function(t){return t===B.activeElement&&(!B.hasFocus||B.hasFocus())&&!!(t.type||t.href||~t.tabIndex)},enabled:function(t){return t.disabled===!1},disabled:function(t){return t.disabled===!0},checked:function(t){var e=t.nodeName.toLowerCase();return"input"===e&&!!t.checked||"option"===e&&!!t.selected},selected:function(t){return t.parentNode&&t.parentNode.selectedIndex,t.selected===!0},empty:function(t){for(t=t.firstChild;t;t=t.nextSibling)if(t.nodeType<6)return!1;return!0},parent:function(t){return!A.pseudos.empty(t)},header:function(t){return mt.test(t.nodeName)},input:function(t){return gt.test(t.nodeName)},button:function(t){var e=t.nodeName.toLowerCase();return"input"===e&&"button"===t.type||"button"===e},text:function(t){var e;return"input"===t.nodeName.toLowerCase()&&"text"===t.type&&(null==(e=t.getAttribute("type"))||"text"===e.toLowerCase())},first:h(function(){return[0]}),last:h(function(t,e){return[e-1]}),eq:h(function(t,e,i){return[i<0?i+e:i]}),even:h(function(t,e){for(var i=0;i=0;)t.push(n);return t}),gt:h(function(t,e,i){for(var n=i<0?i+e:i;++n2&&"ID"===(s=r[0]).type&&x.getById&&9===e.nodeType&&$&&A.relative[r[1].type]){if(e=(A.find.ID(s.matches[0].replace(xt,At),e)||[])[0],!e)return i;h&&(e=e.parentNode),t=t.slice(r.shift().value.length)}for(o=ft.needsContext.test(t)?0:r.length;o--&&(s=r[o],!A.relative[a=s.type]);)if((l=A.find[a])&&(n=l(s.matches[0].replace(xt,At),yt.test(r[0].type)&&c(e.parentNode)||e))){if(r.splice(o,1),t=n.length&&d(r),!t)return J.apply(i,n),i;break}}return(h||k(t,u))(n,e,!$,i,yt.test(t)&&c(e.parentNode)||e),i},x.sortStable=O.split("").sort(q).join("")===O,x.detectDuplicates=!!M,T(),x.sortDetached=o(function(t){return 1&t.compareDocumentPosition(B.createElement("div"))}),o(function(t){return t.innerHTML="","#"===t.firstChild.getAttribute("href")})||r("type|href|height|width",function(t,e,i){if(!i)return t.getAttribute(e,"type"===e.toLowerCase()?1:2)}),x.attributes&&o(function(t){return t.innerHTML="",t.firstChild.setAttribute("value",""),""===t.firstChild.getAttribute("value")})||r("value",function(t,e,i){if(!i&&"input"===t.nodeName.toLowerCase())return t.defaultValue}),o(function(t){return null==t.getAttribute("disabled")})||r(et,function(t,e,i){var n;if(!i)return t[e]===!0?e.toLowerCase():(n=t.getAttributeNode(e))&&n.specified?n.value:null}),e}(i);nt.find=lt,nt.expr=lt.selectors,nt.expr[":"]=nt.expr.pseudos,nt.unique=lt.uniqueSort,nt.text=lt.getText,nt.isXMLDoc=lt.isXML,nt.contains=lt.contains;var ht=nt.expr.match.needsContext,ct=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,ut=/^.[^:#\[\.,]*$/;nt.filter=function(t,e,i){var n=e[0];return i&&(t=":not("+t+")"),1===e.length&&1===n.nodeType?nt.find.matchesSelector(n,t)?[n]:[]:nt.find.matches(t,nt.grep(e,function(t){return 1===t.nodeType}))},nt.fn.extend({find:function(t){var e,i=this.length,n=[],o=this;if("string"!=typeof t)return this.pushStack(nt(t).filter(function(){for(e=0;e1?nt.unique(n):n),n.selector=this.selector?this.selector+" "+t:t,n},filter:function(t){return this.pushStack(a(this,t||[],!1))},not:function(t){return this.pushStack(a(this,t||[],!0))},is:function(t){return!!a(this,"string"==typeof t&&ht.test(t)?nt(t):t||[],!1).length}});var dt,pt=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,ft=nt.fn.init=function(t,e){var i,n;if(!t)return this;if("string"==typeof t){if(i="<"===t[0]&&">"===t[t.length-1]&&t.length>=3?[null,t,null]:pt.exec(t),!i||!i[1]&&e)return!e||e.jquery?(e||dt).find(t):this.constructor(e).find(t);if(i[1]){if(e=e instanceof nt?e[0]:e,nt.merge(this,nt.parseHTML(i[1],e&&e.nodeType?e.ownerDocument||e:et,!0)),ct.test(i[1])&&nt.isPlainObject(e))for(i in e)nt.isFunction(this[i])?this[i](e[i]):this.attr(i,e[i]);return this}return n=et.getElementById(i[2]),n&&n.parentNode&&(this.length=1,this[0]=n),this.context=et,this.selector=t,this}return t.nodeType?(this.context=this[0]=t,this.length=1,this):nt.isFunction(t)?"undefined"!=typeof dt.ready?dt.ready(t):t(nt):(void 0!==t.selector&&(this.selector=t.selector,this.context=t.context),nt.makeArray(t,this))};ft.prototype=nt.fn,dt=nt(et);var gt=/^(?:parents|prev(?:Until|All))/,mt={children:!0,contents:!0,next:!0,prev:!0};nt.extend({dir:function(t,e,i){for(var n=[],o=void 0!==i;(t=t[e])&&9!==t.nodeType;)if(1===t.nodeType){if(o&&nt(t).is(i))break;n.push(t)}return n},sibling:function(t,e){for(var i=[];t;t=t.nextSibling)1===t.nodeType&&t!==e&&i.push(t);return i}}),nt.fn.extend({has:function(t){var e=nt(t,this),i=e.length;return this.filter(function(){for(var t=0;t-1:1===i.nodeType&&nt.find.matchesSelector(i,t))){r.push(i);break}return this.pushStack(r.length>1?nt.unique(r):r)},index:function(t){return t?"string"==typeof t?Q.call(nt(t),this[0]):Q.call(this,t.jquery?t[0]:t):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(t,e){return this.pushStack(nt.unique(nt.merge(this.get(),nt(t,e))))},addBack:function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}}),nt.each({parent:function(t){var e=t.parentNode;return e&&11!==e.nodeType?e:null},parents:function(t){return nt.dir(t,"parentNode")},parentsUntil:function(t,e,i){return nt.dir(t,"parentNode",i)},next:function(t){return l(t,"nextSibling")},prev:function(t){return l(t,"previousSibling")},nextAll:function(t){return nt.dir(t,"nextSibling")},prevAll:function(t){return nt.dir(t,"previousSibling")},nextUntil:function(t,e,i){return nt.dir(t,"nextSibling",i)},prevUntil:function(t,e,i){return nt.dir(t,"previousSibling",i)},siblings:function(t){return nt.sibling((t.parentNode||{}).firstChild,t)},children:function(t){return nt.sibling(t.firstChild)},contents:function(t){return t.contentDocument||nt.merge([],t.childNodes)}},function(t,e){nt.fn[t]=function(i,n){var o=nt.map(this,e,i);return"Until"!==t.slice(-5)&&(n=i),n&&"string"==typeof n&&(o=nt.filter(n,o)),this.length>1&&(mt[t]||nt.unique(o),gt.test(t)&&o.reverse()),this.pushStack(o)}});var vt=/\S+/g,bt={};nt.Callbacks=function(t){t="string"==typeof t?bt[t]||h(t):nt.extend({},t);var e,i,n,o,r,s,a=[],l=!t.once&&[],c=function(h){for(e=t.memory&&h,i=!0,s=o||0,o=0,r=a.length,n=!0;a&&s-1;)a.splice(i,1),n&&(i<=r&&r--,i<=s&&s--)}),this},has:function(t){return t?nt.inArray(t,a)>-1:!(!a||!a.length)},empty:function(){return a=[],r=0,this},disable:function(){return a=l=e=void 0,this},disabled:function(){return!a},lock:function(){return l=void 0,e||u.disable(),this},locked:function(){return!l},fireWith:function(t,e){return!a||i&&!l||(e=e||[],e=[t,e.slice?e.slice():e],n?l.push(e):c(e)),this},fire:function(){return u.fireWith(this,arguments),this},fired:function(){return!!i}};return u},nt.extend({Deferred:function(t){var e=[["resolve","done",nt.Callbacks("once memory"),"resolved"],["reject","fail",nt.Callbacks("once memory"),"rejected"],["notify","progress",nt.Callbacks("memory")]],i="pending",n={state:function(){return i},always:function(){return o.done(arguments).fail(arguments),this},then:function(){var t=arguments;return nt.Deferred(function(i){nt.each(e,function(e,r){var s=nt.isFunction(t[e])&&t[e];o[r[1]](function(){var t=s&&s.apply(this,arguments);t&&nt.isFunction(t.promise)?t.promise().done(i.resolve).fail(i.reject).progress(i.notify):i[r[0]+"With"](this===n?i.promise():this,s?[t]:arguments)})}),t=null}).promise()},promise:function(t){return null!=t?nt.extend(t,n):n}},o={};return n.pipe=n.then,nt.each(e,function(t,r){var s=r[2],a=r[3];n[r[1]]=s.add,a&&s.add(function(){i=a},e[1^t][2].disable,e[2][2].lock),o[r[0]]=function(){return o[r[0]+"With"](this===o?n:this,arguments),this},o[r[0]+"With"]=s.fireWith}),n.promise(o),t&&t.call(o,o),o},when:function(t){var e,i,n,o=0,r=K.call(arguments),s=r.length,a=1!==s||t&&nt.isFunction(t.promise)?s:0,l=1===a?t:nt.Deferred(),h=function(t,i,n){return function(o){i[t]=this,n[t]=arguments.length>1?K.call(arguments):o,n===e?l.notifyWith(i,n):--a||l.resolveWith(i,n)}};if(s>1)for(e=new Array(s),i=new Array(s),n=new Array(s);o0||(yt.resolveWith(et,[nt]),nt.fn.triggerHandler&&(nt(et).triggerHandler("ready"),nt(et).off("ready"))))}}),nt.ready.promise=function(t){return yt||(yt=nt.Deferred(),"complete"===et.readyState?setTimeout(nt.ready):(et.addEventListener("DOMContentLoaded",c,!1),i.addEventListener("load",c,!1))),yt.promise(t)},nt.ready.promise();var wt=nt.access=function(t,e,i,n,o,r,s){var a=0,l=t.length,h=null==i;if("object"===nt.type(i)){o=!0;for(a in i)nt.access(t,e,a,i[a],!0,r,s)}else if(void 0!==n&&(o=!0,nt.isFunction(n)||(s=!0),h&&(s?(e.call(t,n),e=null):(h=e,e=function(t,e,i){return h.call(nt(t),i)})),e))for(;a1,null,!0)},removeData:function(t){return this.each(function(){At.remove(this,t)})}}),nt.extend({queue:function(t,e,i){var n;if(t)return e=(e||"fx")+"queue",n=xt.get(t,e),i&&(!n||nt.isArray(i)?n=xt.access(t,e,nt.makeArray(i)):n.push(i)),n||[]},dequeue:function(t,e){e=e||"fx";var i=nt.queue(t,e),n=i.length,o=i.shift(),r=nt._queueHooks(t,e),s=function(){nt.dequeue(t,e)};"inprogress"===o&&(o=i.shift(),n--),o&&("fx"===e&&i.unshift("inprogress"),delete r.stop,o.call(t,s,r)),!n&&r&&r.empty.fire()},_queueHooks:function(t,e){var i=e+"queueHooks";return xt.get(t,i)||xt.access(t,i,{empty:nt.Callbacks("once memory").add(function(){xt.remove(t,[e+"queue",i])})})}}),nt.fn.extend({queue:function(t,e){var i=2;return"string"!=typeof t&&(e=t,t="fx",i--),arguments.lengthx",tt.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue}();var Dt="undefined";tt.focusinBubbles="onfocusin"in i;var Mt=/^key/,Tt=/^(?:mouse|pointer|contextmenu)|click/,Bt=/^(?:focusinfocus|focusoutblur)$/,Lt=/^([^.]*)(?:\.(.+)|)$/;nt.event={global:{},add:function(t,e,i,n,o){var r,s,a,l,h,c,u,d,p,f,g,m=xt.get(t);if(m)for(i.handler&&(r=i,i=r.handler,o=r.selector),i.guid||(i.guid=nt.guid++),(l=m.events)||(l=m.events={}),(s=m.handle)||(s=m.handle=function(e){return typeof nt!==Dt&&nt.event.triggered!==e.type?nt.event.dispatch.apply(t,arguments):void 0}),e=(e||"").match(vt)||[""],h=e.length;h--;)a=Lt.exec(e[h])||[],p=g=a[1],f=(a[2]||"").split(".").sort(),p&&(u=nt.event.special[p]||{},p=(o?u.delegateType:u.bindType)||p,u=nt.event.special[p]||{},c=nt.extend({type:p,origType:g,data:n,handler:i,guid:i.guid,selector:o,needsContext:o&&nt.expr.match.needsContext.test(o),namespace:f.join(".")},r),(d=l[p])||(d=l[p]=[],d.delegateCount=0,u.setup&&u.setup.call(t,n,f,s)!==!1||t.addEventListener&&t.addEventListener(p,s,!1)),u.add&&(u.add.call(t,c),c.handler.guid||(c.handler.guid=i.guid)),o?d.splice(d.delegateCount++,0,c):d.push(c),nt.event.global[p]=!0)},remove:function(t,e,i,n,o){var r,s,a,l,h,c,u,d,p,f,g,m=xt.hasData(t)&&xt.get(t);if(m&&(l=m.events)){for(e=(e||"").match(vt)||[""],h=e.length;h--;)if(a=Lt.exec(e[h])||[],p=g=a[1],f=(a[2]||"").split(".").sort(),p){for(u=nt.event.special[p]||{},p=(n?u.delegateType:u.bindType)||p,d=l[p]||[],a=a[2]&&new RegExp("(^|\\.)"+f.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=r=d.length;r--;)c=d[r],!o&&g!==c.origType||i&&i.guid!==c.guid||a&&!a.test(c.namespace)||n&&n!==c.selector&&("**"!==n||!c.selector)||(d.splice(r,1),c.selector&&d.delegateCount--,u.remove&&u.remove.call(t,c));s&&!d.length&&(u.teardown&&u.teardown.call(t,f,m.handle)!==!1||nt.removeEvent(t,p,m.handle),delete l[p])}else for(p in l)nt.event.remove(t,p+e[h],i,n,!0);nt.isEmptyObject(l)&&(delete m.handle,xt.remove(t,"events"))}},trigger:function(t,e,n,o){var r,s,a,l,h,c,u,d=[n||et],p=Z.call(t,"type")?t.type:t,f=Z.call(t,"namespace")?t.namespace.split("."):[];if(s=a=n=n||et,3!==n.nodeType&&8!==n.nodeType&&!Bt.test(p+nt.event.triggered)&&(p.indexOf(".")>=0&&(f=p.split("."),p=f.shift(),f.sort()),h=p.indexOf(":")<0&&"on"+p,t=t[nt.expando]?t:new nt.Event(p,"object"==typeof t&&t),t.isTrigger=o?2:3, -t.namespace=f.join("."),t.namespace_re=t.namespace?new RegExp("(^|\\.)"+f.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=n),e=null==e?[t]:nt.makeArray(e,[t]),u=nt.event.special[p]||{},o||!u.trigger||u.trigger.apply(n,e)!==!1)){if(!o&&!u.noBubble&&!nt.isWindow(n)){for(l=u.delegateType||p,Bt.test(l+p)||(s=s.parentNode);s;s=s.parentNode)d.push(s),a=s;a===(n.ownerDocument||et)&&d.push(a.defaultView||a.parentWindow||i)}for(r=0;(s=d[r++])&&!t.isPropagationStopped();)t.type=r>1?l:u.bindType||p,c=(xt.get(s,"events")||{})[t.type]&&xt.get(s,"handle"),c&&c.apply(s,e),c=h&&s[h],c&&c.apply&&nt.acceptData(s)&&(t.result=c.apply(s,e),t.result===!1&&t.preventDefault());return t.type=p,o||t.isDefaultPrevented()||u._default&&u._default.apply(d.pop(),e)!==!1||!nt.acceptData(n)||h&&nt.isFunction(n[p])&&!nt.isWindow(n)&&(a=n[h],a&&(n[h]=null),nt.event.triggered=p,n[p](),nt.event.triggered=void 0,a&&(n[h]=a)),t.result}},dispatch:function(t){t=nt.event.fix(t);var e,i,n,o,r,s=[],a=K.call(arguments),l=(xt.get(this,"events")||{})[t.type]||[],h=nt.event.special[t.type]||{};if(a[0]=t,t.delegateTarget=this,!h.preDispatch||h.preDispatch.call(this,t)!==!1){for(s=nt.event.handlers.call(this,t,l),e=0;(o=s[e++])&&!t.isPropagationStopped();)for(t.currentTarget=o.elem,i=0;(r=o.handlers[i++])&&!t.isImmediatePropagationStopped();)t.namespace_re&&!t.namespace_re.test(r.namespace)||(t.handleObj=r,t.data=r.data,n=((nt.event.special[r.origType]||{}).handle||r.handler).apply(o.elem,a),void 0!==n&&(t.result=n)===!1&&(t.preventDefault(),t.stopPropagation()));return h.postDispatch&&h.postDispatch.call(this,t),t.result}},handlers:function(t,e){var i,n,o,r,s=[],a=e.delegateCount,l=t.target;if(a&&l.nodeType&&(!t.button||"click"!==t.type))for(;l!==this;l=l.parentNode||this)if(l.disabled!==!0||"click"!==t.type){for(n=[],i=0;i=0:nt.find(o,this,null,[l]).length),n[o]&&n.push(r);n.length&&s.push({elem:l,handlers:n})}return a]*)\/>/gi,Rt=/<([\w:]+)/,It=/<|&#?\w+;/,zt=/<(?:script|style|link)/i,Nt=/checked\s*(?:[^=]|=\s*.checked.)/i,Ot=/^$|\/(?:java|ecma)script/i,Pt=/^true\/(.*)/,Ht=/^\s*\s*$/g,Wt={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};Wt.optgroup=Wt.option,Wt.tbody=Wt.tfoot=Wt.colgroup=Wt.caption=Wt.thead,Wt.th=Wt.td,nt.extend({clone:function(t,e,i){var n,o,r,s,a=t.cloneNode(!0),l=nt.contains(t.ownerDocument,t);if(!(tt.noCloneChecked||1!==t.nodeType&&11!==t.nodeType||nt.isXMLDoc(t)))for(s=x(a),r=x(t),n=0,o=r.length;n0&&y(s,!l&&x(t,"script")),a},buildFragment:function(t,e,i,n){for(var o,r,s,a,l,h,c=e.createDocumentFragment(),u=[],d=0,p=t.length;d")+a[2],h=a[0];h--;)r=r.lastChild;nt.merge(u,r.childNodes),r=c.firstChild,r.textContent=""}else u.push(e.createTextNode(o));for(c.textContent="",d=0;o=u[d++];)if((!n||nt.inArray(o,n)===-1)&&(l=nt.contains(o.ownerDocument,o),r=x(c.appendChild(o),"script"),l&&y(r),i))for(h=0;o=r[h++];)Ot.test(o.type||"")&&i.push(o);return c},cleanData:function(t){for(var e,i,n,o,r=nt.event.special,s=0;void 0!==(i=t[s]);s++){if(nt.acceptData(i)&&(o=i[xt.expando],o&&(e=xt.cache[o]))){if(e.events)for(n in e.events)r[n]?nt.event.remove(i,n):nt.removeEvent(i,n,e.handle);xt.cache[o]&&delete xt.cache[o]}delete At.cache[i[At.expando]]}}}),nt.fn.extend({text:function(t){return wt(this,function(t){return void 0===t?nt.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=t)})},null,t,arguments.length)},append:function(){return this.domManip(arguments,function(t){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var e=m(this,t);e.appendChild(t)}})},prepend:function(){return this.domManip(arguments,function(t){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var e=m(this,t);e.insertBefore(t,e.firstChild)}})},before:function(){return this.domManip(arguments,function(t){this.parentNode&&this.parentNode.insertBefore(t,this)})},after:function(){return this.domManip(arguments,function(t){this.parentNode&&this.parentNode.insertBefore(t,this.nextSibling)})},remove:function(t,e){for(var i,n=t?nt.filter(t,this):this,o=0;null!=(i=n[o]);o++)e||1!==i.nodeType||nt.cleanData(x(i)),i.parentNode&&(e&&nt.contains(i.ownerDocument,i)&&y(x(i,"script")),i.parentNode.removeChild(i));return this},empty:function(){for(var t,e=0;null!=(t=this[e]);e++)1===t.nodeType&&(nt.cleanData(x(t,!1)),t.textContent="");return this},clone:function(t,e){return t=null!=t&&t,e=null==e?t:e,this.map(function(){return nt.clone(this,t,e)})},html:function(t){return wt(this,function(t){var e=this[0]||{},i=0,n=this.length;if(void 0===t&&1===e.nodeType)return e.innerHTML;if("string"==typeof t&&!zt.test(t)&&!Wt[(Rt.exec(t)||["",""])[1].toLowerCase()]){t=t.replace($t,"<$1>");try{for(;i1&&"string"==typeof d&&!tt.checkClone&&Nt.test(d))return this.each(function(i){var n=c.eq(i);p&&(t[0]=d.call(this,i,n.html())),n.domManip(t,e)});if(h&&(i=nt.buildFragment(t,this[0].ownerDocument,!1,this),n=i.firstChild,1===i.childNodes.length&&(i=n),n)){for(o=nt.map(x(i,"script"),v),r=o.length;l1)},show:function(){return T(this,!0)},hide:function(){return T(this)},toggle:function(t){return"boolean"==typeof t?t?this.show():this.hide():this.each(function(){Ft(this)?nt(this).show():nt(this).hide()})}}),nt.Tween=B,B.prototype={constructor:B,init:function(t,e,i,n,o,r){this.elem=t,this.prop=i,this.easing=o||"swing",this.options=e,this.start=this.now=this.cur(),this.end=n,this.unit=r||(nt.cssNumber[i]?"":"px")},cur:function(){var t=B.propHooks[this.prop];return t&&t.get?t.get(this):B.propHooks._default.get(this)},run:function(t){var e,i=B.propHooks[this.prop];return this.options.duration?this.pos=e=nt.easing[this.easing](t,this.options.duration*t,0,1,this.options.duration):this.pos=e=t,this.now=(this.end-this.start)*e+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),i&&i.set?i.set(this):B.propHooks._default.set(this),this}},B.prototype.init.prototype=B.prototype,B.propHooks={_default:{get:function(t){var e;return null==t.elem[t.prop]||t.elem.style&&null!=t.elem.style[t.prop]?(e=nt.css(t.elem,t.prop,""),e&&"auto"!==e?e:0):t.elem[t.prop]},set:function(t){nt.fx.step[t.prop]?nt.fx.step[t.prop](t):t.elem.style&&(null!=t.elem.style[nt.cssProps[t.prop]]||nt.cssHooks[t.prop])?nt.style(t.elem,t.prop,t.now+t.unit):t.elem[t.prop]=t.now}}},B.propHooks.scrollTop=B.propHooks.scrollLeft={set:function(t){t.elem.nodeType&&t.elem.parentNode&&(t.elem[t.prop]=t.now)}},nt.easing={linear:function(t){return t},swing:function(t){return.5-Math.cos(t*Math.PI)/2}},nt.fx=B.prototype.init,nt.fx.step={};var te,ee,ie=/^(?:toggle|show|hide)$/,ne=new RegExp("^(?:([+-])=|)("+Et+")([a-z%]*)$","i"),oe=/queueHooks$/,re=[I],se={"*":[function(t,e){var i=this.createTween(t,e),n=i.cur(),o=ne.exec(e),r=o&&o[3]||(nt.cssNumber[t]?"":"px"),s=(nt.cssNumber[t]||"px"!==r&&+n)&&ne.exec(nt.css(i.elem,t)),a=1,l=20;if(s&&s[3]!==r){r=r||s[3],o=o||[],s=+n||1;do a=a||".5",s/=a,nt.style(i.elem,t,s+r);while(a!==(a=i.cur()/n)&&1!==a&&--l)}return o&&(s=i.start=+s||+n||0,i.unit=r,i.end=o[1]?s+(o[1]+1)*o[2]:+o[2]),i}]};nt.Animation=nt.extend(N,{tweener:function(t,e){nt.isFunction(t)?(e=t,t=["*"]):t=t.split(" ");for(var i,n=0,o=t.length;n1)},removeAttr:function(t){return this.each(function(){nt.removeAttr(this,t)})}}),nt.extend({attr:function(t,e,i){var n,o,r=t.nodeType;if(t&&3!==r&&8!==r&&2!==r)return typeof t.getAttribute===Dt?nt.prop(t,e,i):(1===r&&nt.isXMLDoc(t)||(e=e.toLowerCase(),n=nt.attrHooks[e]||(nt.expr.match.bool.test(e)?le:ae)),void 0===i?n&&"get"in n&&null!==(o=n.get(t,e))?o:(o=nt.find.attr(t,e),null==o?void 0:o):null!==i?n&&"set"in n&&void 0!==(o=n.set(t,i,e))?o:(t.setAttribute(e,i+""),i):void nt.removeAttr(t,e))},removeAttr:function(t,e){var i,n,o=0,r=e&&e.match(vt);if(r&&1===t.nodeType)for(;i=r[o++];)n=nt.propFix[i]||i,nt.expr.match.bool.test(i)&&(t[n]=!1),t.removeAttribute(i)},attrHooks:{type:{set:function(t,e){if(!tt.radioValue&&"radio"===e&&nt.nodeName(t,"input")){var i=t.value;return t.setAttribute("type",e),i&&(t.value=i),e}}}}}),le={set:function(t,e,i){return e===!1?nt.removeAttr(t,i):t.setAttribute(i,i),i}},nt.each(nt.expr.match.bool.source.match(/\w+/g),function(t,e){var i=he[e]||nt.find.attr;he[e]=function(t,e,n){var o,r;return n||(r=he[e],he[e]=o,o=null!=i(t,e,n)?e.toLowerCase():null,he[e]=r),o}});var ce=/^(?:input|select|textarea|button)$/i;nt.fn.extend({prop:function(t,e){return wt(this,nt.prop,t,e,arguments.length>1)},removeProp:function(t){return this.each(function(){delete this[nt.propFix[t]||t]})}}),nt.extend({propFix:{"for":"htmlFor","class":"className"},prop:function(t,e,i){var n,o,r,s=t.nodeType;if(t&&3!==s&&8!==s&&2!==s)return r=1!==s||!nt.isXMLDoc(t),r&&(e=nt.propFix[e]||e,o=nt.propHooks[e]),void 0!==i?o&&"set"in o&&void 0!==(n=o.set(t,i,e))?n:t[e]=i:o&&"get"in o&&null!==(n=o.get(t,e))?n:t[e]},propHooks:{tabIndex:{get:function(t){return t.hasAttribute("tabindex")||ce.test(t.nodeName)||t.href?t.tabIndex:-1}}}}),tt.optSelected||(nt.propHooks.selected={get:function(t){var e=t.parentNode;return e&&e.parentNode&&e.parentNode.selectedIndex,null}}),nt.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){nt.propFix[this.toLowerCase()]=this});var ue=/[\t\r\n\f]/g;nt.fn.extend({addClass:function(t){var e,i,n,o,r,s,a="string"==typeof t&&t,l=0,h=this.length;if(nt.isFunction(t))return this.each(function(e){nt(this).addClass(t.call(this,e,this.className))});if(a)for(e=(t||"").match(vt)||[];l=0;)n=n.replace(" "+o+" "," ");s=t?nt.trim(n):"",i.className!==s&&(i.className=s)}return this},toggleClass:function(t,e){var i=typeof t;return"boolean"==typeof e&&"string"===i?e?this.addClass(t):this.removeClass(t):nt.isFunction(t)?this.each(function(i){nt(this).toggleClass(t.call(this,i,this.className,e),e)}):this.each(function(){if("string"===i)for(var e,n=0,o=nt(this),r=t.match(vt)||[];e=r[n++];)o.hasClass(e)?o.removeClass(e):o.addClass(e);else i!==Dt&&"boolean"!==i||(this.className&&xt.set(this,"__className__",this.className),this.className=this.className||t===!1?"":xt.get(this,"__className__")||"")})},hasClass:function(t){for(var e=" "+t+" ",i=0,n=this.length;i=0)return!0;return!1}});var de=/\r/g;nt.fn.extend({val:function(t){var e,i,n,o=this[0];{if(arguments.length)return n=nt.isFunction(t),this.each(function(i){var o;1===this.nodeType&&(o=n?t.call(this,i,nt(this).val()):t,null==o?o="":"number"==typeof o?o+="":nt.isArray(o)&&(o=nt.map(o,function(t){return null==t?"":t+""})),e=nt.valHooks[this.type]||nt.valHooks[this.nodeName.toLowerCase()],e&&"set"in e&&void 0!==e.set(this,o,"value")||(this.value=o))});if(o)return e=nt.valHooks[o.type]||nt.valHooks[o.nodeName.toLowerCase()],e&&"get"in e&&void 0!==(i=e.get(o,"value"))?i:(i=o.value,"string"==typeof i?i.replace(de,""):null==i?"":i)}}}),nt.extend({valHooks:{option:{get:function(t){var e=nt.find.attr(t,"value");return null!=e?e:nt.trim(nt.text(t))}},select:{get:function(t){for(var e,i,n=t.options,o=t.selectedIndex,r="select-one"===t.type||o<0,s=r?null:[],a=r?o+1:n.length,l=o<0?a:r?o:0;l=0)&&(i=!0);return i||(t.selectedIndex=-1),r}}}}),nt.each(["radio","checkbox"],function(){nt.valHooks[this]={set:function(t,e){if(nt.isArray(e))return t.checked=nt.inArray(nt(t).val(),e)>=0}},tt.checkOn||(nt.valHooks[this].get=function(t){return null===t.getAttribute("value")?"on":t.value})}),nt.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(t,e){nt.fn[e]=function(t,i){return arguments.length>0?this.on(e,null,t,i):this.trigger(e)}}),nt.fn.extend({hover:function(t,e){return this.mouseenter(t).mouseleave(e||t)},bind:function(t,e,i){return this.on(t,null,e,i)},unbind:function(t,e){return this.off(t,null,e)},delegate:function(t,e,i,n){return this.on(e,t,i,n)},undelegate:function(t,e,i){return 1===arguments.length?this.off(t,"**"):this.off(e,t||"**",i)}});var pe=nt.now(),fe=/\?/;nt.parseJSON=function(t){return JSON.parse(t+"")},nt.parseXML=function(t){var e,i;if(!t||"string"!=typeof t)return null;try{i=new DOMParser,e=i.parseFromString(t,"text/xml")}catch(n){e=void 0}return e&&!e.getElementsByTagName("parsererror").length||nt.error("Invalid XML: "+t),e};var ge=/#.*$/,me=/([?&])_=[^&]*/,ve=/^(.*?):[ \t]*([^\r\n]*)$/gm,be=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,ye=/^(?:GET|HEAD)$/,we=/^\/\//,xe=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Ae={},_e={},Ce="*/".concat("*"),Ee=i.location.href,ke=xe.exec(Ee.toLowerCase())||[];nt.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:Ee,type:"GET",isLocal:be.test(ke[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Ce,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":nt.parseJSON,"text xml":nt.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(t,e){return e?H(H(t,nt.ajaxSettings),e):H(nt.ajaxSettings,t)},ajaxPrefilter:O(Ae),ajaxTransport:O(_e),ajax:function(t,e){function i(t,e,i,s){var l,c,v,b,w,A=e;2!==y&&(y=2,a&&clearTimeout(a),n=void 0,r=s||"",x.readyState=t>0?4:0,l=t>=200&&t<300||304===t,i&&(b=W(u,x,i)),b=U(u,b,x,l),l?(u.ifModified&&(w=x.getResponseHeader("Last-Modified"),w&&(nt.lastModified[o]=w),w=x.getResponseHeader("etag"),w&&(nt.etag[o]=w)),204===t||"HEAD"===u.type?A="nocontent":304===t?A="notmodified":(A=b.state,c=b.data,v=b.error,l=!v)):(v=A,!t&&A||(A="error",t<0&&(t=0))),x.status=t,x.statusText=(e||A)+"",l?f.resolveWith(d,[c,A,x]):f.rejectWith(d,[x,A,v]),x.statusCode(m),m=void 0,h&&p.trigger(l?"ajaxSuccess":"ajaxError",[x,u,l?c:v]),g.fireWith(d,[x,A]),h&&(p.trigger("ajaxComplete",[x,u]),--nt.active||nt.event.trigger("ajaxStop")))}"object"==typeof t&&(e=t,t=void 0),e=e||{};var n,o,r,s,a,l,h,c,u=nt.ajaxSetup({},e),d=u.context||u,p=u.context&&(d.nodeType||d.jquery)?nt(d):nt.event,f=nt.Deferred(),g=nt.Callbacks("once memory"),m=u.statusCode||{},v={},b={},y=0,w="canceled",x={readyState:0,getResponseHeader:function(t){var e;if(2===y){if(!s)for(s={};e=ve.exec(r);)s[e[1].toLowerCase()]=e[2];e=s[t.toLowerCase()]}return null==e?null:e},getAllResponseHeaders:function(){return 2===y?r:null},setRequestHeader:function(t,e){var i=t.toLowerCase();return y||(t=b[i]=b[i]||t,v[t]=e),this},overrideMimeType:function(t){return y||(u.mimeType=t),this},statusCode:function(t){var e;if(t)if(y<2)for(e in t)m[e]=[m[e],t[e]];else x.always(t[x.status]);return this},abort:function(t){var e=t||w;return n&&n.abort(e),i(0,e),this}};if(f.promise(x).complete=g.add,x.success=x.done,x.error=x.fail,u.url=((t||u.url||Ee)+"").replace(ge,"").replace(we,ke[1]+"//"),u.type=e.method||e.type||u.method||u.type,u.dataTypes=nt.trim(u.dataType||"*").toLowerCase().match(vt)||[""],null==u.crossDomain&&(l=xe.exec(u.url.toLowerCase()),u.crossDomain=!(!l||l[1]===ke[1]&&l[2]===ke[2]&&(l[3]||("http:"===l[1]?"80":"443"))===(ke[3]||("http:"===ke[1]?"80":"443")))),u.data&&u.processData&&"string"!=typeof u.data&&(u.data=nt.param(u.data,u.traditional)),P(Ae,u,e,x),2===y)return x;h=nt.event&&u.global,h&&0===nt.active++&&nt.event.trigger("ajaxStart"),u.type=u.type.toUpperCase(),u.hasContent=!ye.test(u.type),o=u.url,u.hasContent||(u.data&&(o=u.url+=(fe.test(o)?"&":"?")+u.data,delete u.data),u.cache===!1&&(u.url=me.test(o)?o.replace(me,"$1_="+pe++):o+(fe.test(o)?"&":"?")+"_="+pe++)),u.ifModified&&(nt.lastModified[o]&&x.setRequestHeader("If-Modified-Since",nt.lastModified[o]),nt.etag[o]&&x.setRequestHeader("If-None-Match",nt.etag[o])),(u.data&&u.hasContent&&u.contentType!==!1||e.contentType)&&x.setRequestHeader("Content-Type",u.contentType),x.setRequestHeader("Accept",u.dataTypes[0]&&u.accepts[u.dataTypes[0]]?u.accepts[u.dataTypes[0]]+("*"!==u.dataTypes[0]?", "+Ce+"; q=0.01":""):u.accepts["*"]);for(c in u.headers)x.setRequestHeader(c,u.headers[c]);if(u.beforeSend&&(u.beforeSend.call(d,x,u)===!1||2===y))return x.abort();w="abort";for(c in{success:1,error:1,complete:1})x[c](u[c]);if(n=P(_e,u,e,x)){x.readyState=1,h&&p.trigger("ajaxSend",[x,u]),u.async&&u.timeout>0&&(a=setTimeout(function(){x.abort("timeout")},u.timeout));try{y=1,n.send(v,i)}catch(A){if(!(y<2))throw A;i(-1,A)}}else i(-1,"No Transport");return x},getJSON:function(t,e,i){return nt.get(t,e,i,"json")},getScript:function(t,e){return nt.get(t,void 0,e,"script")}}),nt.each(["get","post"],function(t,e){nt[e]=function(t,i,n,o){return nt.isFunction(i)&&(o=o||n,n=i,i=void 0),nt.ajax({url:t,type:e,dataType:o,data:i,success:n})}}),nt._evalUrl=function(t){return nt.ajax({url:t,type:"GET",dataType:"script",async:!1,global:!1,"throws":!0})},nt.fn.extend({wrapAll:function(t){var e;return nt.isFunction(t)?this.each(function(e){nt(this).wrapAll(t.call(this,e))}):(this[0]&&(e=nt(t,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&e.insertBefore(this[0]),e.map(function(){for(var t=this;t.firstElementChild;)t=t.firstElementChild;return t}).append(this)),this)},wrapInner:function(t){return nt.isFunction(t)?this.each(function(e){nt(this).wrapInner(t.call(this,e))}):this.each(function(){var e=nt(this),i=e.contents();i.length?i.wrapAll(t):e.append(t)})},wrap:function(t){var e=nt.isFunction(t);return this.each(function(i){nt(this).wrapAll(e?t.call(this,i):t)})},unwrap:function(){return this.parent().each(function(){ -nt.nodeName(this,"body")||nt(this).replaceWith(this.childNodes)}).end()}}),nt.expr.filters.hidden=function(t){return t.offsetWidth<=0&&t.offsetHeight<=0},nt.expr.filters.visible=function(t){return!nt.expr.filters.hidden(t)};var Fe=/%20/g,Se=/\[\]$/,De=/\r?\n/g,Me=/^(?:submit|button|image|reset|file)$/i,Te=/^(?:input|select|textarea|keygen)/i;nt.param=function(t,e){var i,n=[],o=function(t,e){e=nt.isFunction(e)?e():null==e?"":e,n[n.length]=encodeURIComponent(t)+"="+encodeURIComponent(e)};if(void 0===e&&(e=nt.ajaxSettings&&nt.ajaxSettings.traditional),nt.isArray(t)||t.jquery&&!nt.isPlainObject(t))nt.each(t,function(){o(this.name,this.value)});else for(i in t)j(i,t[i],e,o);return n.join("&").replace(Fe,"+")},nt.fn.extend({serialize:function(){return nt.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var t=nt.prop(this,"elements");return t?nt.makeArray(t):this}).filter(function(){var t=this.type;return this.name&&!nt(this).is(":disabled")&&Te.test(this.nodeName)&&!Me.test(t)&&(this.checked||!St.test(t))}).map(function(t,e){var i=nt(this).val();return null==i?null:nt.isArray(i)?nt.map(i,function(t){return{name:e.name,value:t.replace(De,"\r\n")}}):{name:e.name,value:i.replace(De,"\r\n")}}).get()}}),nt.ajaxSettings.xhr=function(){try{return new XMLHttpRequest}catch(t){}};var Be=0,Le={},$e={0:200,1223:204},Re=nt.ajaxSettings.xhr();i.attachEvent&&i.attachEvent("onunload",function(){for(var t in Le)Le[t]()}),tt.cors=!!Re&&"withCredentials"in Re,tt.ajax=Re=!!Re,nt.ajaxTransport(function(t){var e;if(tt.cors||Re&&!t.crossDomain)return{send:function(i,n){var o,r=t.xhr(),s=++Be;if(r.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)r[o]=t.xhrFields[o];t.mimeType&&r.overrideMimeType&&r.overrideMimeType(t.mimeType),t.crossDomain||i["X-Requested-With"]||(i["X-Requested-With"]="XMLHttpRequest");for(o in i)r.setRequestHeader(o,i[o]);e=function(t){return function(){e&&(delete Le[s],e=r.onload=r.onerror=null,"abort"===t?r.abort():"error"===t?n(r.status,r.statusText):n($e[r.status]||r.status,r.statusText,"string"==typeof r.responseText?{text:r.responseText}:void 0,r.getAllResponseHeaders()))}},r.onload=e(),r.onerror=e("error"),e=Le[s]=e("abort");try{r.send(t.hasContent&&t.data||null)}catch(a){if(e)throw a}},abort:function(){e&&e()}}}),nt.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(t){return nt.globalEval(t),t}}}),nt.ajaxPrefilter("script",function(t){void 0===t.cache&&(t.cache=!1),t.crossDomain&&(t.type="GET")}),nt.ajaxTransport("script",function(t){if(t.crossDomain){var e,i;return{send:function(n,o){e=nt("