Skip to content

Instantly share code, notes, and snippets.

@moorepants
Created March 14, 2018 20:56
Show Gist options
  • Save moorepants/6505bb8645939470c3089a5070f8910d to your computer and use it in GitHub Desktop.
Save moorepants/6505bb8645939470c3089a5070f8910d to your computer and use it in GitHub Desktop.
Shows how one might make a robot pendulum behave like an ideal pendulum.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Setup"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"import numpy as np\n",
"import scipy as sp\n",
"import scipy.integrate\n",
"import sympy as sm\n",
"import sympy.physics.mechanics as me\n",
"import matplotlib.pyplot as plt\n",
"from opty.direct_collocation import Problem"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"%matplotlib notebook"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"me.init_vprinting()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Simulate Simple Pendulum\n",
"\n",
"The first step is to simulate an ideal simple pendulum so that we have some trajectories. Below is a function that evaluates the first order ordinary differential equations that describe the pendulum."
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def simple_pendulum_state_equations(x, t, g, l):\n",
" \"\"\"\n",
" x : array_like, shape(2,)\n",
" [theta, omega]\n",
" \"\"\"\n",
" return x[1], g / l * np.sin(x[0])"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The motion of the pendulum is simulated over some time span and the results are reported at specific time intervals."
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"num_nodes = 500\n",
"times = np.linspace(0, 10, num=num_nodes)\n",
"interval = times[1] - times[0]\n",
"g = 9.8 # m/s\n",
"l = 0.3 # m\n",
"initial_conditions = [np.deg2rad(2), 0.0]\n",
"\n",
"simple_pend_state_traj = sp.integrate.odeint(simple_pendulum_state_equations, initial_conditions, times, args=(g, l))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now plot the two state trajectories to see the ideal motion."
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"jpeg\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\", \"tif\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" var width = fig.canvas.width/mpl.ratio\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" // select the cell after this one\n",
" var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
" IPython.notebook.select(index + 1);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,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AMoAHAfwAYBvBhznDADvADgIoBlAru/YPekqAbwMQCaARgANALYA+GnQY2aDCSARERFRrwah7wlgO4B0AFcAuB5ALYAVUEOvF0Ilh20AHgg4znQAGwD8EsC5AF4E0ApgQA8xdZUA7gTwfwAu8D33fqikMNBsMAEkIiIi6tUg9D0BFKgkzm8qVK9e4JBxmu9+APgxAA+AHwUdOwPA2B5i6ioBbIDqaezJbDABJCIiIurVIPQ9AWwOesxoALuC7psDYKHv9p2+YzQFtQ6oXsPudJUAjvI9LwPAEHRORP1mgwkgERERUa8GIbQ5gIFGAdgWdN9snEzCHoDqATwfQP+g9sMeYupuEch5AAZDDUO3Abinh3MTERERUTcGwb4E8DzfMX4ZYkx9WQX8GYAlPZybiIiIiLoxCPYlgAAwD0ApgHsBnA3gKgBDoYaHuxOcAJ4JYLIvJg3ALwAUA3i7l3MTERERURcGwd4E8FtQcwVLoVYRH4aaI3hJDzEFJ4CnQ/X4VUAN/R4EMAnAt3s5NxERERHFCRaCJiIiIkoyAqAFwIE+Pv6XOLm6mAkgERERURzyrxQ+u4+PPxN9W11MRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERPHg/wNXfVZ9bX0ohgAAAABJRU5ErkJggg==\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(2, 1)\n",
"axes[0].plot(times, np.rad2deg(simple_pend_state_traj[:, 0]))\n",
"axes[0].set_ylabel('Angle [deg]');\n",
"axes[1].plot(times, np.rad2deg(simple_pend_state_traj[:, 1]))\n",
"axes[1].set_xlabel('Time [s]')\n",
"axes[1].set_ylabel('Angular Rate [deg/s]');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"These trajectories can now be used as the target trajectories when we design a controller for the model of the robot."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Robot Model\n",
"\n",
"Now I can create a model that more realistically captures the actual robot. This model will have a motor, gear reduction, friction, and inertia of the various components. The parameters of the model are given below:\n",
"\n",
"## Constants\n",
"\n",
"- $R$: Motor winding resistance\n",
"- $K$: Motor torque/EMF constant\n",
"- $r_f$: Follower gear radius\n",
"- $r_d$: Driver gear radius\n",
"- $L$: Motor inductance\n",
"- $m$: Mass of pendulum bob\n",
"- $l$: Length of pendulum\n",
"- $g$: Acceleration due to gravity\n",
"- $I_f$: Inertia of follower gear\n",
"- $I_d$: Inertia of driver gear\n",
"- $I_m$: Motor rotor inertia\n",
"- $c_f$: Viscious damping coefficient of follower gear bearings\n",
"- $c_d$: Viscous damping coefficient of motor rotor\n",
"\n",
"## Inputs\n",
"\n",
"- $V(t)$: Motor voltage\n",
"\n",
"## States\n",
"\n",
"- $i(t)$: Motor current\n",
"- $\\theta_f(t)$: Pendulum (or follower) angle\n",
"- $\\omega_f(t)$: Pendulum (or follower) angular rate\n",
"\n",
"I define these symbols with SymPy:"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"R, K, L, Im = sm.symbols('R, K, L, I_m', real=True, positive=True)\n",
"m, l, g = sm.symbols('m, l, g', real=True, positive=True)\n",
"rf, rd, If, Id, cf, cd = sm.symbols('r_f, r_d, I_f, I_d, c_f, c_d', real=True, positive=True)\n",
"\n",
"theta, omega, i, V = me.dynamicsymbols('theta, omega, i_c, V')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This robot model has three first order state equations: the dynamics of the pendulum, the kinematic equation, and the motor voltage/current dynamics. Each of these are written as expressions in implicit form that are equated to zero."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\ny/8HoDaO+wBZI9UAAAAASUVORK5CYII=\n",
"text/latex": [
"$$- \\frac{K r_{f}}{r_{d}} i_{c} - g l m \\operatorname{sin}\\left(\\theta\\right) + \\left(c_{d} + c_{f}\\right) \\omega + \\left(I_{f} + l^{2} m + \\frac{r_{f}}{r_{d}} \\left(I_{d} + I_{m}\\right)\\right) \\dot{\\omega}$$"
],
"text/plain": [
" K⋅r_f⋅i_c ⎛ 2 r_f⋅(I_d + Iₘ)⎞ \n",
"- ───────── - g⋅l⋅m⋅sin(θ) + (c_d + c_f)⋅ω + ⎜I_f + l ⋅m + ──────────────⎟⋅ω̇\n",
" r_d ⎝ r_d ⎠ "
]
},
"execution_count": 19,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"dyn_eq = (omega.diff() * (If + m * l**2 + rf / rd * (Im + Id)) + (cf + cd) * \n",
" omega - m * g * l * sm.sin(theta) - rf / rd * K * i)\n",
"dyn_eq"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAEAAAAAWBAMAAACCkIcHAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEM3dMrsi70RmdpmJ\nVKuALsSwAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAA4ElEQVQoFWNgoAgwfiKk3Y6QAorlGWcSMKJV\ndgNeFSyFDB+xKrgFFWWewPAXr4LpDAw/8SqwZmBBmMAKVMpWAVEPtYLjBwPXD7gJM4Asxl8oCvj+\nvXv+Aa4A7J+zKAqYFRj4FRiEjEFAhaOBgYmBYRpQwSElJXMlJT0gi/8Ag/8FmAlcDAzeDAwHIFyo\nG+QvMGyHyTNwMzCsZWA7AOHDFDQwQB0FFGZ1YPnNwJSAooC9gccAIgAkeWq2339TCeVCTeBekJ4A\nV8AYr8JVvgBVAeOujXB5VAbUBFRBZJ4YEgcARqAzGWyDuZEAAAAASUVORK5CYII=\n",
"text/latex": [
"$$- \\omega + \\dot{\\theta}$$"
],
"text/plain": [
"-ω + θ̇"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"kin_eq = theta.diff() - omega\n",
"kin_eq"
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAANEAAAAtBAMAAADCRJO+AAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAdqvNEDJUuyJEiWaZ\n3e/xv6KKAAAACXBIWXMAAA7EAAAOxAGVKw4bAAADfElEQVRYCd1WTUwTQRT+aLel3bZ0wb+EH61g\n9MABApHoAVkVYzwYeuJgouzNIzXGaEIiPXlQI42JB0m0xZMxhlY4GQ8s8WCiHAiePBhRI4keDPKP\nGuub3Xbp/jVRHA6+w+y875v3vp3ZNzMLoCbfJqNlMQ7+tkgS55P8dRD8DoSULRCCuA7h4VYIwTuP\nM1sihGhrSGVKw/uGR/gqpjPZaaaQuagcocfLHDe5bG14hZL7lBncAcTaDDelrlyA1bkgrDMJb4qb\nEFaBQbZt/fNMIyqzlosFvwHpGKUOt1ITGnxVXkVg8/87E5eByBLFVmVYgnHWlLOZcmRZLkKLVkHH\nBIZSbNxU2cGbIY91LUhoyF8B7mlpBjaT7I9iP7uODrUs7ifSk3AYMZZvvMze8YCda8h3AGd/qVZG\nYF/MxaLTjPDknGgq4KEY0GzntBLyE2exoJatFPRLRS+dKfZsTx8VsIdKy8m+EuixE/oRWIpvKGVT\npbipX8EKeM0EGU4X9XYYXrHjHYsXu8XnhhILcbHKWaA/4Uy2JBHI2CixWodY0C19ChtK2p49OmkL\nIiAag/8DhHrJgaSlcFi8wsAQE+nRwwwldjfTiX+/MMb06Nu762ccYnDWhOrOhOSweMVxYdYRFc01\nlOhuBgLKcw21NHtkjMu4ph1oFgppVV+8vIPhLtCKUJLU2ts7P7a3x1g03c1AN6jKdDv+ltlBzblK\nC5iBHC2untDJuNdxRvYk3BcPEnwqRD2hMadogg7gpN9xwy3o26lf1mNMbXT6qck3OSoqFFzXIUMp\nTS8chjcmQ6wuvnshyveDSk8F2gRgpFBURsLIGjFudgl9Kg7prKGUpbWoQ4+SwRvfrDmSbaesJAgr\nIiKpc2YOlauyBSlxRx/PLYzmdMBQekefbQnpQC6cEEi01NgnnJB6g/M38AInShnqh1kludnJxfju\n9wWyoCQ05Rub8jF4nqFKscSFuxZyCF+Q0JzDnIWjbxuzQc6AMSeDjiaNrr3jciTZB9oRIWnF6KdG\ntWKGf5iq5p9ZYPKJ7JrsZt12V+4/JYIPTj2StmRuYmWHd5YqnzYgZ+uNxIK0GQXagJxN7kkxBX8r\nZx1K369JiCp/JXa9CZPbFP5KX0jidLxP5q4UYMftFKznPQdd7X9yDjUcUjukFNYw0O2Ac4A++ZZz\nHNI6pLy9s56n0m/WKtKeGZsEDQAAAABJRU5ErkJggg==\n",
"text/latex": [
"$$\\frac{K r_{f}}{r_{d}} \\omega + L \\dot{i}_{c} - R i_{c} - V$$"
],
"text/plain": [
"K⋅r_f⋅ω \n",
"─────── + L⋅i_̇c - R⋅i_c - V\n",
" r_d "
]
},
"execution_count": 21,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"cur_eq = i.diff() * L - R * i + K * rf / rd * omega - V\n",
"cur_eq"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In matrix form:"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\nQmCC\n",
"text/latex": [
"$$\\left[\\begin{matrix}- \\omega + \\dot{\\theta}\\\\- \\frac{K r_{f}}{r_{d}} i_{c} - g l m \\operatorname{sin}\\left(\\theta\\right) + \\left(c_{d} + c_{f}\\right) \\omega + \\left(I_{f} + l^{2} m + \\frac{r_{f}}{r_{d}} \\left(I_{d} + I_{m}\\right)\\right) \\dot{\\omega}\\\\\\frac{K r_{f}}{r_{d}} \\omega + L \\dot{i}_{c} - R i_{c} - V\\end{matrix}\\right]$$"
],
"text/plain": [
"⎡ -ω + θ̇ \n",
"⎢ \n",
"⎢ K⋅r_f⋅i_c ⎛ 2 r_f⋅(I_d + Iₘ)⎞ \n",
"⎢- ───────── - g⋅l⋅m⋅sin(θ) + (c_d + c_f)⋅ω + ⎜I_f + l ⋅m + ──────────────⎟⋅ω̇\n",
"⎢ r_d ⎝ r_d ⎠ \n",
"⎢ \n",
"⎢ K⋅r_f⋅ω \n",
"⎢ ─────── + L⋅i_̇c - R⋅i_c - V \n",
"⎣ r_d \n",
"\n",
"⎤\n",
"⎥\n",
"⎥\n",
"⎥\n",
"⎥\n",
"⎥\n",
"⎥\n",
"⎥\n",
"⎦"
]
},
"execution_count": 22,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eom = sm.Matrix([kin_eq, dyn_eq, cur_eq])\n",
"eom"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now a controller needs to be specified. We want to control the voltage to the motors in the real robot based on feedback from $\\theta$ and $\\omega$ such that its motion matches the motion of the idealized pendulum. Let's start with a simple PD controller with $\\theta$ as the feedback variable:\n",
"\n",
"$V = -k_\\theta \\theta - k_\\omega \\omega - k_i i$\n",
"\n",
"The goal is now to find the gains $k_\\theta$, $k_\\omega$, and $k_i$, i.e. these are the primary free variables in the optimization."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"k_theta, k_omega, k_i = sm.symbols('k_theta, k_omega, k_i', real=True)"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAKYAAAASBAMAAAAj/bgnAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAEM3dMrvvmVREiXar\nImZtIuRaAAAACXBIWXMAAA7EAAAOxAGVKw4bAAACMklEQVQ4Ea2UT2jTUBzHvy9N1zRpmiCIwsAU\nGewkFDzoYIfcdnRehiDMiSDqQaqHDunBgMcdlovibQEvgpdOEAUnFFEPU7BeBE8GBEHE2YKwFnX4\nkpe8X9Lm6Lv8vr/v5/v+9OVR4D8PtkcLspVm0tSWyU3V4UupKqwZfPdoiyJKqmshmVLNS1UoJFYv\nYkgJyyM9rUbTVtaRuBRCamDLzoYmdDWz+QSKWsJfgQMKPCA5rfTmtJdxCJ+CmjnnPDZeRbHZTiac\nSqWl7biiKfNiXk2BqBJXxzDGkrGR8ekARgvBPemRcLwXW6Fov/HCfhOKlMBHHqH2592bgWTacJuF\nUPumd1N6JDZn7WNJFz+Ph4QiJfBZxS41YDVw6GQ05lDZFzEGeYYUcXA7XilKVH0owA+uJnGlW/as\nAGe8KBaP0tvzQmhFn3jxSTfJGcASECRdUmLs2KXQ8dAm5PiffVR3AKVnQ3+eLiECbGzym78P1HsV\n4BnMgCZyJfBjWL7j088EfvKLDnTHjgoW1LXcpPqAjXT0ALVZdtV9KP0CfHz9vT3j07MCXsNygw93\n+Ns3w8oyc3OT+F/AL90M+Uds6dfam7vXcxQxxhV8QaX7MbPdKoyODX6ntT3MePk5KId4uq31613W\nZRfmjMv5mxEYf7EK1rkxMRVs6EaWldmLIoZb8/VCIjIDc43CpLRGEDWKjxaZqaqee3l6PW0K6omy\nW+CC7cbnMDvf7QK8ErR7BXZqLd1K1D884o/vbK1lMQAAAABJRU5ErkJggg==\n",
"text/latex": [
"$$- k_{i} i_{c} - k_{\\omega} \\omega - k_{\\theta} \\theta$$"
],
"text/plain": [
"-kᵢ⋅i_c - k_ω⋅ω - kₜₕₑₜₐ⋅θ"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"controller = -k_theta * theta - k_omega * omega - k_i * i\n",
"controller"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The free variables in this direct collocation problem will look like:\n",
" \n",
"$ [\\theta_1, \\ldots, \\theta_n, \\omega_1, \\ldots, \\omega_n, i_1, \\ldots, i_n, k_\\theta, k_\\omega, k_i] $\n",
"\n",
"Our objective is to minimize the error in the trajectories of the angle and angular rate of the robot model output with respect to the ideal simple pendulum output. The objective function and its gradient is defined below in the form needed for collocation:"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"def obj(free):\n",
" \"\"\"Minimize the error in the angle theta and angular rate omega.\"\"\"\n",
" return interval * np.sum((simple_pend_state_traj.T.reshape(2 * num_nodes) - free[:2 * num_nodes])**2)\n",
"\n",
"\n",
"def obj_grad(free):\n",
" grad = np.zeros_like(free)\n",
" grad[:2 * num_nodes] = 2.0 * interval * (free[:2 * num_nodes] - simple_pend_state_traj.T.reshape(2 * num_nodes))\n",
" return grad"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Below I've chosen some reasonable parameters to describe the system we have. The motor specs do not provide much and I've put in some arbitrary friction constants."
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"par_map = {R: 0,\n",
" K: 0.08815, # Vs\n",
" L: 0.5, # H, To measure this see: https://electronics.stackexchange.com/questions/182116/whats-the-easy-way-to-measure-a-dc-hobby-motors-inductance\n",
" Im: 0, # Let's say this is neglible\n",
" m: 0.00763, # kg, mass of pendulum bob equivalent to thin aluminum rod inertia\n",
" l: 0.3, # m\n",
" g: 9.81, # m/s^-2\n",
" rf: 25 * 0.015, # m, motor gear ratio is 25\n",
" rd: 0.015, # m\n",
" If: 0,\n",
" Id: 0,\n",
" cf: 0.0001,\n",
" cd: 0.001,\n",
" }\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The equations of motion with all the known constants substituted in look like:"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/latex": [
"$$\\left[\\begin{matrix}- \\omega + \\dot{\\theta}\\\\- 2.20375 i_{c} + 0.0011 \\omega - 0.02245509 \\operatorname{sin}\\left(\\theta\\right) + 0.0006867 \\dot{\\omega}\\\\k_{i} i_{c} + k_{\\omega} \\omega + k_{\\theta} \\theta + 2.20375 \\omega + 0.5 \\dot{i}_{c}\\end{matrix}\\right]$$"
],
"text/plain": [
"⎡ -ω + θ̇ ⎤\n",
"⎢ ⎥\n",
"⎢-2.20375⋅i_c + 0.0011⋅ω - 0.02245509⋅sin(θ) + 0.0006867⋅ω̇⎥\n",
"⎢ ⎥\n",
"⎣ kᵢ⋅i_c + k_ω⋅ω + kₜₕₑₜₐ⋅θ + 2.20375⋅ω + 0.5⋅i_̇c ⎦"
]
},
"execution_count": 27,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"eom.xreplace(par_map).xreplace({V: controller})"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is worth seeing how the robot model behaves when no voltage is applied with the same initial angle condition at the previous simulation of the ideal simple pendulum. We can simulate the model as before."
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\nlYf3noN0vQAAAABJRU5ErkJggg==\n",
"text/latex": [
"$$\\left[\\begin{matrix}\\omega\\\\\\frac{K r_{f} i_{c} - c_{d} r_{d} \\omega - c_{f} r_{d} \\omega + g l m r_{d} \\operatorname{sin}\\left(\\theta\\right)}{I_{d} r_{f} + I_{f} r_{d} + I_{m} r_{f} + l^{2} m r_{d}}\\\\\\frac{1}{L r_{d}} \\left(- K r_{f} \\omega + R r_{d} i_{c} + r_{d} V\\right)\\end{matrix}\\right]$$"
],
"text/plain": [
"⎡ ω ⎤\n",
"⎢ ⎥\n",
"⎢K⋅r_f⋅i_c - c_d⋅r_d⋅ω - c_f⋅r_d⋅ω + g⋅l⋅m⋅r_d⋅sin(θ)⎥\n",
"⎢────────────────────────────────────────────────────⎥\n",
"⎢ 2 ⎥\n",
"⎢ I_d⋅r_f + I_f⋅r_d + Iₘ⋅r_f + l ⋅m⋅r_d ⎥\n",
"⎢ ⎥\n",
"⎢ -K⋅r_f⋅ω + R⋅r_d⋅i_c + r_d⋅V ⎥\n",
"⎢ ──────────────────────────── ⎥\n",
"⎣ L⋅r_d ⎦"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"explicit_sol = sm.solve(eom, [theta.diff(), omega.diff(), i.diff()])\n",
"rhs = sm.Matrix([explicit_sol[var] for var in [theta.diff(), omega.diff(), i.diff()]])\n",
"rhs"
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAnoAAABYCAMAAABVj6oqAAAAPFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo1xBWAAAAE3RSTlMA\nMquZdlQQQO0wRIlmzd0i77tsXjyQfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAACqNJREFUeAHtXdmC\ng6gSJW53Rs3i9f//daoKQVDcoVwaH9JGilpPIyFHIl4tHYmIR8wASwY+EnFCvNo0gyNnsRqNxAyI\nGvGWtAi9V0xHzAB3BuoIPe6UR3syA1zQK9KqruLgegfYcZWKC3pvmEkWn+8dUr/Jx/xXbJK/gTBX\nqZigV/8w59X7Bpnf4GKRpEn7NOixlYoJeg2t3OSPq5PIHhcSW6mYoNcS9Mr2cQs4z4MeW6l4oFe0\nKd7HyjbbcDu7hejjoMdXKh7ofdsKgfSSf26BqZVOPg56fKXigh6NehF6KwF9othX3qAYSsUDPb5R\nnLtojxv1+ErFAz0h5655/JjB/a+x3R5bqZig1zSYg/pxKxFPXFzhKhUT9OQ6ZfqwJWX4b3rcDVew\nlYoJeuKDX6T9nvcl7vOgx1YqLugVFRC0Hoe8NPm176TePqG6cg+uUnFB78q5jr6dkoEIvVPSHo3i\nh87IUo44OCUDEXqnpD0ajaNexMBpGYij3mmp/+uGI/T+OgJOiz9C77TUX8tw2bQNEnnfbcNE+Q8M\nvaJ53te214KMN28yenzmm7A9uhUYeqL8eMtNVBQ0AwnSBnJGGnlo6FXEEQ2as6jcSwZ+gLqs9KJq\nnZLQ0Hvf/wtO+PbZGAvqpK6z6buSLSwWpNfViEWqaMuiUcVicTsU9GqkC0DOWpg61Gn9yrJUdAQC\nlrj8letTihdNg0SKk4e6bEsB1/CgC3SmXrTwN6Vn8OalVa8r/M3bsnoTVQ+8MdzuAgngYiDoIewa\nuNdS0SAQ+Hf6JYUgNBpxOYoXIMZDKlMoRyEpNyUE9C0yVR94wm44m+iFU5o1zUsf8st35wpqVHb7\nPpluy0B8W0N9YaD3xcEOP6tjnSAQHC5gsBApPJhmxjUuXogYt+rMG3XAMsOvf3S4ovtR0t998cKE\n8LtboRhIb3WFT/6N/0YfGqrhpHdbBeLfkzDQqwlrkP2G6oSB0PiHhFEzLiGr6T8sfxrxnwgP2BJO\nbhmj+K76gmynVyVcVG0l+81JGx3PP6XHZnIVgHK7D8S/h2GgV8F/D2Ht98J7FQZC418r1FuMxFU8\n/xEe1PjGaV0qchiv5cIXUH3w0BfkW/naCcPQ3j0K8J2TNnueff6SoPvJKYRyuw8kgH9hoJcD9BIc\nvFsBAx4FgiNf3Qi8496lHJTub5rVWSHeL/GiSV7ZTfX0BbMonXA/C5yVNnuefF592hSG6fzXbROh\n57Oj6aw/R8NAT6RZRcsqaQWDRokgfENk36SCm/BdymEl+VOIytryd3TBEjeXY7BhXtrqeq03w0A8\neofQK/JuTuxRr7zLziq8VTnKqs5SteyFYY0uWLEmcvVFX5uX1mLXOxkG4tHDL0z8ve+l/IVhLl98\n8PG25VhMf/7VN6xF2UsLBA0kyA339YYV5BAj6aXr1Dtn35r767c7CxqIDT35cwb3fJ2s6z3DUb8s\nMRHWA4KyoTcR57mXX1XVdItr5zri03oMavxtRg5cQXM6PZ/vkNJgmeh+MG86Sr0K6eY23TEoDajx\nqJd1y25aZPYkpDQYRszB55XiKOE0pJvbdMegFJ7G0CPKoGp2/8V1uu7wLk16tYGO7pfjF3NHDu9u\nag9h7Xzlx1ndJQZFpRxDDymDC4eRa+/SZFobkHS/AtejDx3e3dQewgLmcsJiUI7qjaAHlEFDzM2t\n6/NuS7uZkZPSaGfBAH2zWADdCkX30/5sNxdswu3dTIHbxRgUlgT4IfKPJGaKTZUaQS+3pnomt04Z\nMewJW9qkGK6QRpF5A0RBKNJvgbuAz9D+emPuM9vNeZuwGm6lwO2iTvlQGh2YNxCDkkUaQa9S0yqk\n4JrcOoOu2uddSctGU7xngY6le3yYPRwGiJaJP54qfUHXnLS/MV24N4Fnyk1yasFmLx2DMrK4kLUd\nlRpBjyiDaFJyFnrOoKSrJm84fvhCMxwlrbisvTj1n5A2IjJIiQ4Dku6nxKdpf0v8CuVmDEpcp1II\nvf/986+qLowqipUrWZyKMwhrHP03Y/04pqRVYy/es0AH0nWa13Va5t3vRPY9lA7wRXWRdD/l3ATt\nD5qXGKfKzU5w1mafAuVQL94bUh520jEoImZuqtT//7HpAx1lULE4FbdOWHRVnfdOWjdqcdUffRlI\n5xks1AHtHLmWPXnPbYDofiiGxwTtbwXjNAYFFBFaJLhSpQY3XKQMApFYU3AVtw4KbzBRFJg66b5R\niev+CJmhNOxrW8CsLaWPkapHr8PsQnQ/vIDHBO3PsiUlB68xKJjsUl37LKu8W9njrdQAel3RHBRc\nczqlXNQlNhvxotV/KA2wy4GH/RHq1i7VmDqGXbQhx4lly9GuLzkEZ22ajajE6j/0MAal8zx5YiUQ\n1gFgrjfm6zlYnCZddZh3eMLWtmf1H0gXsKqPT7knmb1ObOoYdLGVD95ZtgZt1luH4KxNsxEVWf0H\nHsagrFS731gJnIKeg8Vp0lVtzIAdsxHNWv1H0m7HTB0ru5Aiy5ZbtbzqEJy1aTaiBqv/Sg9NHSu7\nkLOWLem++9UhOGvTbESNVv+VHpo6VnYh5y1bU9AbhTlLV51tHKlyX/Chw615+uqszdnGaZ1Wiw8d\nlsIVb2ZtzjauUI4iPnSQKfcNd+TFLF11tnGkyn3Bhw635umrszZnG6XOxS3pVuiY9m5ny6zN2caV\nBn3oIFMrobfSrT8mxr4l3aPyG6F3oJxEl+Lcku6Ar6u7wliepIn9PdLqzlsEI/S2ZGsgi3Qp1i3p\nBvbDvJW/z/ehFf8wFqTWCL392QVyFfOWdPt93dBTUl8T5GoEPSL09qeXf0u6/b5u6PmhRdq1BNgN\nigeiEXqDhGx4y78l3QbndosWuMlegdvRBT64oAex1B1XJXBEfOr5t6TjiK1s4fn935al4p1ecUHv\nDV/YFnKDup2eXq8b/5Z0HDmokCeyxL314QgT9OSnJorKh9eX0NHxkDi3pOOIu6GHEexnBILYZYJe\nQ08C5kcfpw2Sgp1KkYcEtyXWLel2urqpG43lqdy4fFPHrcJM0GsJeqVmC291807yQ8bLnXxHGhOy\n0WFp5RV6uscDvaLbrLIdkKvuVZWV3prEjpVdriMGYzn+KAjuFRbaKR7ofVv6rP6Sf0LHdKp+b8SO\nU6PgMM4FPdoe+i9Azxuxg6P6p9rggd7tb7jF+6MP4HnDsbjB3all3WvcimqvkpX9eKAn5MeM/E98\nzFiZ+T8vxgS9hp5lqJ+0uILQwb31wn/jxAxSrqCYoCeXlFPjgUrmfAYyh+l73MEUFBP0BP5EVWE8\nxv+Qeq3dW+9W4TIFxQW9An+klObnt6rCkrPhqUVLHgRoZwqKC3oBMnQBlXonPveWfRfwcIcLOqgd\nfbd0idDbkq2hrN6Jz72j3lD8Hu91UIHdjdA7kmBFxTE3n2MhHB1xeqmvCmpJ7mh7hN6RDMp9+160\njYfWM9yrRTfc5KQPKqzDEXpH8iuXyJGVY3x4X9rs74hBjr59UGGtRegdyK8ki2YAPefGggc0n9i1\nDyqwExF6+xOMZNE0+eDuzs7t6vZrPrGnEVRgLyL0vCZ4sIWcV91PUyahR4QFIhI/LT7meAZbyDFb\nv405/FEAOOALrowO2mD2Nt5f09HBFnLXdPJ8r2CrbTzEf3d3r27ZE7BHAAAAAElFTkSuQmCC\n",
"text/latex": [
"$$\\left[\\begin{matrix}0 & 1 & 0\\\\\\frac{g l m r_{d}}{I_{d} r_{f} + I_{f} r_{d} + I_{m} r_{f} + l^{2} m r_{d}} & \\frac{- c_{d} r_{d} - c_{f} r_{d}}{I_{d} r_{f} + I_{f} r_{d} + I_{m} r_{f} + l^{2} m r_{d}} & \\frac{K r_{f}}{I_{d} r_{f} + I_{f} r_{d} + I_{m} r_{f} + l^{2} m r_{d}}\\\\0 & - \\frac{K r_{f}}{L r_{d}} & \\frac{R}{L}\\end{matrix}\\right]$$"
],
"text/plain": [
"⎡ 0 1 \n",
"⎢ \n",
"⎢ g⋅l⋅m⋅r_d -c_d⋅r_d - c_f⋅r_d \n",
"⎢───────────────────────────────────── ───────────────────────────────────── \n",
"⎢ 2 2 \n",
"⎢I_d⋅r_f + I_f⋅r_d + Iₘ⋅r_f + l ⋅m⋅r_d I_d⋅r_f + I_f⋅r_d + Iₘ⋅r_f + l ⋅m⋅r_d \n",
"⎢ \n",
"⎢ -K⋅r_f \n",
"⎢ 0 ─────── \n",
"⎣ L⋅r_d \n",
"\n",
" 0 ⎤\n",
" ⎥\n",
" K⋅r_f ⎥\n",
" ─────────────────────────────────────⎥\n",
" 2 ⎥\n",
" I_d⋅r_f + I_f⋅r_d + Iₘ⋅r_f + l ⋅m⋅r_d⎥\n",
" ⎥\n",
" R ⎥\n",
" ─ ⎥\n",
" L ⎦"
]
},
"execution_count": 34,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A = rhs.subs({sm.sin(theta): theta}).jacobian([theta, omega, i])\n",
"A"
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAACAAAABLCAMAAAAml3VfAAAAPFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAo1xBWAAAAE3RSTlMA\nMquZdlQQQOkwRIlmzd0i77ts7uXj/QAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAUxJREFUSA3tlu1i\nhSAIhjE/dpZlNe7/Xic6TCG3C9jxjxWPKG8RgMEyFhAj1ecABq3Lwws7bPR0QQKMtN33mwSCjVvs\nFihgzzuFdDQXEthOMsV9ClwlFo+BCekBC7BiC0kAAS0tXdFNPBwYyWLqRJfCw1E9zIE/t4B6SD89\nJFxX3XgaZhXKzoWCRFKf98sQUWRjzK/4tssw6QDjUB5GsxJKmt8AK6KUfCcOSfOcOB+vT9ZNJ87X\na/xHvROnaTVeqE9uND/mprl/L5lWHoxdUu9FAQD+nwClbLEWSofDJlxavXlQklfyrDywgecRqNWc\na3phRoCXdbMC/I5XqXw/kALKB/CbB1hK1WqI9nB2ImRMAQHXtpouFOBzx9EPBXStQ+EUsJfyb9o+\nCqhF+W6ZJGCQ2hcngdZoxYQ2J0aNpDVagRoq59q2HERptJyDb8MbGlL4XEX0AAAAAElFTkSuQmCC\n",
"text/latex": [
"$$\\left[\\begin{matrix}0\\\\0\\\\\\frac{1}{L}\\end{matrix}\\right]$$"
],
"text/plain": [
"⎡0⎤\n",
"⎢ ⎥\n",
"⎢0⎥\n",
"⎢ ⎥\n",
"⎢1⎥\n",
"⎢─⎥\n",
"⎣L⎦"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"B = rhs.subs({sm.sin(theta): theta}).jacobian([V])\n",
"B"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\nAAAASUVORK5CYII=\n",
"text/latex": [
"$$\\left[\\begin{matrix}0 & 1 & 0\\\\\\frac{g l m r_{d}}{I_{d} r_{f} + I_{f} r_{d} + I_{m} r_{f} + l^{2} m r_{d}} & \\frac{- c_{d} r_{d} - c_{f} r_{d}}{I_{d} r_{f} + I_{f} r_{d} + I_{m} r_{f} + l^{2} m r_{d}} & \\frac{K r_{f}}{I_{d} r_{f} + I_{f} r_{d} + I_{m} r_{f} + l^{2} m r_{d}}\\\\- \\frac{k_{\\theta}}{L} & \\frac{1}{L r_{d}} \\left(- K r_{f} - k_{\\omega} r_{d}\\right) & \\frac{1}{L r_{d}} \\left(R r_{d} - k_{i} r_{d}\\right)\\end{matrix}\\right]$$"
],
"text/plain": [
"⎡ 0 1 \n",
"⎢ \n",
"⎢ g⋅l⋅m⋅r_d -c_d⋅r_d - c_f⋅r_d \n",
"⎢───────────────────────────────────── ───────────────────────────────────── \n",
"⎢ 2 2 \n",
"⎢I_d⋅r_f + I_f⋅r_d + Iₘ⋅r_f + l ⋅m⋅r_d I_d⋅r_f + I_f⋅r_d + Iₘ⋅r_f + l ⋅m⋅r_d \n",
"⎢ \n",
"⎢ -kₜₕₑₜₐ -K⋅r_f - k_ω⋅r_d \n",
"⎢ ──────── ──────────────── \n",
"⎣ L L⋅r_d \n",
"\n",
" 0 ⎤\n",
" ⎥\n",
" K⋅r_f ⎥\n",
" ─────────────────────────────────────⎥\n",
" 2 ⎥\n",
" I_d⋅r_f + I_f⋅r_d + Iₘ⋅r_f + l ⋅m⋅r_d⎥\n",
" ⎥\n",
" R⋅r_d - kᵢ⋅r_d ⎥\n",
" ────────────── ⎥\n",
" L⋅r_d ⎦"
]
},
"execution_count": 36,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"A_closed = rhs.subs({sm.sin(theta): theta, V: controller}).jacobian([theta, omega, i])\n",
"A_closed"
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"rhs_func = sm.lambdify((theta, omega, i, V), rhs.xreplace(par_map))"
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"initial_conditions = [np.deg2rad(2), 0.0, 0.0]\n",
"\n",
"robot_pend_state_traj = sp.integrate.odeint(lambda x, t: rhs_func(x[0], x[1], x[2], 0).squeeze(),\n",
" initial_conditions, times)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This shows that the system has a damped high frequency oscillation about the initial condition, i.e. gravity doesn't cause it to move in any appreciable way."
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" var width = fig.canvas.width/mpl.ratio\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" // select the cell after this one\n",
" var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
" IPython.notebook.select(index + 1);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nOzdeZxU1Z0//I/k+SXxSeLMPDPJ5DdkpuO+kahxS4xR3KMmqEkcs2jEZJJJ1GR0srRsCqIgKIuAuC+gIK6gNmuzNE0D3ezQDfRK7930Xl291F7f549zb9WtqlvVS91b1cvn/Xp9X9S991TV7apWPtxzzzkAEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREYWcAmAsgNNYLBaLxWINqxoL9fc40YCNBSAsFovFYrGGZY0F0SCcBkBqa2uls7OTxWKxWCzWMKja2lo9AJ6W5hxBw9RpAKSzs1OIiIhoeOjs7GQApKQwABIREQ0zDICULAZAIiKiYYYBkJLFAEhERDTMMABSslISAJfvqpQ/v3tAfP6Are9DREQ0GjAAUrJSEgAzMrMkIzNL1hyss/V9iIiIRgMGQEpWSgPgO/lVtr4PERHRaMAASMliACQiIhpmGAApWSkNgCvyq219HyIiotGAAZCSxSuAREREwwwDICWLAZCIiGiYYQCkZDEAEhERDTMMgJQs3gNIREQ0zDAAUrIYAImIiIYZBkBKFgMgERHRMMMASMlKewCs6+iVN/NOSLfbZ+s5EBERjRQMgJSstAfAS57cJBmZWTJ1daGt50BERDRSMACm3yQAewF0AWgGsAbAuf143ngABwB4AJQDmGjS5m4AxQDcAAoB3BZ1/HMAZgKoBOACUAFgGoBTBnD+KQ2AKwtiA6B+bPyz22w9ByIiopGCATD9NkCFtwsBXARgLYBqAF9K8JzTAfQAmAfgfAAPA/ADuMXQ5ipt39+0NjMBeAGMM7SZDKAV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\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(2, 1)\n",
"axes[0].plot(times, np.rad2deg(robot_pend_state_traj[:, 0]))\n",
"axes[0].set_ylabel('Angle [deg]');\n",
"axes[1].plot(times, np.rad2deg(robot_pend_state_traj[:, 1]))\n",
"axes[1].set_xlabel('Time [s]')\n",
"axes[1].set_ylabel('Angular Rate [deg/s]');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If I apply a constant voltage to the motor we see that it overcomes friction and inertia and rotates."
]
},
{
"cell_type": "code",
"execution_count": 21,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"robot_pend_state_traj = sp.integrate.odeint(lambda x, t: rhs_func(x[0], x[1], x[2], 5).squeeze(),\n",
" initial_conditions, times)"
]
},
{
"cell_type": "code",
"execution_count": 22,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" var width = fig.canvas.width/mpl.ratio\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" // select the cell after this one\n",
" var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
" IPython.notebook.select(index + 1);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nOzdeXxU9aH+8Ud7b2t/tba9vV3utbcsgituxaq1rQu1Wm2LWrVal1bbW7daW2pv2RcFRFaVRRBEEAFFBVFDEkggEEJCVvYtG1nIvu/rzPP748wk50wWksxyMsnzfr2+L2fmnMx8neT2fjwz53sAEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREWlzDoALAVygoaGhoaGhEVTjQhj/f1yk1y4EQA0NDQ0NDY2gHBdCpA8uAMDc3FxWVVVpaGhoaGhoBMHIzc11B+AFNneEBKkLALCqqooiIiISHKqqqhSA4hUFoIiISJBRAIq3FIAiIiJBRgEo3lIAioiI+InT6WSrw+nz51UAircUgCIiIj7kdDp5MKeCs0KO8aY5OxlxrNDnr6EAFG8pAEVERLzkdDp55Ewl54Se4E/m7uSQ8SFt48UPD/r89RSA4i0FoIiISB84nU6eKKji/PCTvHV+lCX6Lp0Sxuc2JDPsSD4bmlt9/toKwP7pZgCfA8iH8cu517Tt3wHMBXAEQJ1rn3UA/tvjOXaj42KPKzz2+Q8AGwBUA6gEsBrA+b2cqwJQRESkF9KKqrloxymOWWCNvosnh/LpdUn8/FAe65pa/DoHBWD/dBeAWQDuQ8cA/BqACAC/BXAJgBsBxANI8niO3QBWAviuaXj+ksMAHARwA4CfAEgDsLGXc1UAioiInEVmSS0XR6byjkV7LNE3clIo//fdRG49cIY1jf6NPjMFYP/nGYCd+aFrv++bHtsN4PVufuYy189cZ3rsFwCc6Hg0sTsKQBERkU5kl9ZxWVQa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vu1kpRLMHKgpBe4GcIWhXOpkpbqITLAL2Aq3Qj2TNgpqUNOTAOrBwQmxthDqF3J9GpiHAZQDeN25KiWEy6Ba+PpDBcDh2vZV2vlkqP8PPgTV9b4KnAaGEtRfoLp0XFAtgrc7W52EIxHKMAfr1FVkggHQKg9CDbhpAnAYHAVsha9B/fwWIjAR9ESox3eo/QbC/N/khdp5fSLoUqif73QERmITEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREZGVBkKtIvANBz5bX8GgqpWvH2h4zyqL6kREREQU1yIt46eX8VDLcl0BtXyUE/UbBuBbrXy9XtelYAAkIiIiMnWFoTwPoDrk2GXOVQ2ACoBD2/G+hWAAJCIiImrRMJh3tQ5EcBew/roHAeQDaADwKYD/A+BpAKcAVAKYAeAiw3UuBvAmgGIA9QBytGtHYxYAbwKQAaAWQA2AnQBuCXnNQjAAEhEREbVoGFofAJsBpAH4PoC7AFQAWAfV9doHKhy6ADxuuM58AFsB3AngWgAvAmgC0CtKncwC4AEAHwK4Xnvvo1Ch0GghGACJiIiIWjQMrQ+AAhXidHOhWvWMXcap2nEAuAqAB8B3Q66dDmBSlDqZBcAaqJbGaBaCAZCIiIioRcPQ+gBYH/KaCQAOhhxbBGCltv2Ado26kOKGajWMxCwAjtfelw5gBIKDqG4hGACJiIiIWjQMbXsG0Gg8gD0hxxYiEMIeh2oBvA5Az5ByRZQ6RRoE0hvAcKhuaBeAh6N8NhERERFFMAzWBcDe2jXubGOdWjMKeDGAL6J8NhERERFFMAzWBUAA+AhAAYBHAPQAcBuAkVDdw5GEBsBLAczS6pQE4IcAjgN4vYXPJiIiIiITw2BtAPxXqGcFC6BGEZ+FekawX5Q6hQbAr0C1+J2G6votBjATwCUtfDYRERERxQlOBE1ERETUxQiARgBnWvn6OxEYXcwASERERBSH9JHCPVr5+kvRutHFRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERBQP/j+n6qszGgDg/wAAAABJRU5ErkJggg==\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(2, 1)\n",
"axes[0].plot(times, np.rad2deg(robot_pend_state_traj[:, 0]))\n",
"axes[0].set_ylabel('Angle [deg]');\n",
"axes[1].plot(times, np.rad2deg(robot_pend_state_traj[:, 1]))\n",
"axes[1].set_xlabel('Time [s]')\n",
"axes[1].set_ylabel('Angular Rate [deg/s]');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now I solve for the controller gains that will make the robot behave like the ideal pendulum."
]
},
{
"cell_type": "code",
"execution_count": 23,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"prob = Problem(obj,\n",
" obj_grad,\n",
" eom.xreplace({V: controller}),\n",
" [theta, omega, i],\n",
" num_nodes,\n",
" interval,\n",
" known_parameter_map=par_map,\n",
" integration_method='midpoint')"
]
},
{
"cell_type": "code",
"execution_count": 24,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAIUAAAAUBAMAAABRzuPpAAAAMFBMVEX///8AAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAv3aB7AAAAD3RSTlMAIma7zZnddlTvRIkQ\nqzLsm4+cAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAB8ElEQVQ4EaWUsWvbQBTGP8tK7FhnW1AoJEvk\nv6BJliRLUQdvHbwEE0KJ6FAyNOBSujngQiBjtgyZNKXdog5Nlg6iHdwOrQMpdCvKfxBKCiaYkk86\nSbYka2kOrHv3+773OL07GSgYuM9o+MkPgC9H06vkcUCsW2FKVWfwhL9mCNJTHgfUVugVJqD4i2E6\nOVzncaDei1LOgVnupTKKQHLO43SdupH1G/CQsWZFIDnncbrOYqdq4w0Xaqu858VwHORxOpo4+C2N\nWgsrjAa9V6dGUG2c70eSJ5lciWFp4Q/EVocNNbFDeNh3PwNXUp54Sj4B4rA86goDRfcpULZwTL4d\nHVTskUEeB2b++o421oDadVBj9zX3NGXkcZ7mr1VetBGeBzX4LuK2cAu8u0hXkfw9XzkjDexFGyUT\nzKtYfk+VazHU8ClzSSRnfs1Kl3/Efjtq8xlzFBMfgeoS/mmFrxbETcIrucHmtTAwE9Il6p4z11Ms\ntsbBCVDkuXZRZE9euJPOgJd1pSM6mH05qXD3pbZb1+mA6gV3PZAHP3hOesLpL0pe1daI32YU1DFP\nyIsefHO+vq/x0meNlbWfOxvETlZS9ceE/OawHIrfPwD9rBHrzuYFz66TlWobNgWTAv+D4mHEUTpQ\n0iBaF3VGBYOP/x8N4A6sHG0KCQIPvAAAAABJRU5ErkJggg==\n",
"text/latex": [
"$$\\left ( k_{i}, \\quad k_{\\omega}, \\quad k_{\\theta}\\right )$$"
],
"text/plain": [
"(kᵢ, k_ω, kₜₕₑₜₐ)"
]
},
"execution_count": 24,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prob.collocator.unknown_parameters"
]
},
{
"cell_type": "code",
"execution_count": 25,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"initial_guess = np.hstack((simple_pend_state_traj.T.reshape(2 * num_nodes),\n",
" np.zeros(num_nodes),\n",
" np.zeros(len(controller.args))))"
]
},
{
"cell_type": "code",
"execution_count": 26,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"sol, info = prob.solve(initial_guess)"
]
},
{
"cell_type": "code",
"execution_count": 27,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"theta_sol = sol[0 * num_nodes:1 * num_nodes]\n",
"omega_sol = sol[1 * num_nodes:2 * num_nodes]\n",
"i_sol = sol[2 * num_nodes:3 * num_nodes]\n",
"k_sol = sol[-len(controller.args):]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"These are the identified optimal gains:"
]
},
{
"cell_type": "code",
"execution_count": 28,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"array([ 3.55144670e+02, -2.38102401e+00, -1.69601612e-10])"
]
},
"execution_count": 28,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"k_sol"
]
},
{
"cell_type": "code",
"execution_count": 29,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"compute_voltage = sm.lambdify(prob.collocator.unknown_parameters + (theta, omega, i), controller, 'numpy')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now we can see if the trajectories of the robot model match that of the simple pendulum using the controller and the identified gains."
]
},
{
"cell_type": "code",
"execution_count": 30,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" var width = fig.canvas.width/mpl.ratio\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" // select the cell after this one\n",
" var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
" IPython.notebook.select(index + 1);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,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dixNXnv7NVm4aqEkbk+UT2M/lcqVK8u8eXNFRKSgoED+7//+Tx588EHJzc2V3NxcuXTpUikBePToUalSpYoMHDhQ9u7dK0uWLJHrr7/eRuB16tRJoqKiJCYmRvbv3y9z586VMmXKyMqVKx0+68uXL0v16tXl7bfflgMHDsiePXtkzpw5kgg8Il4AACAASURBVJ2dLSIiP/74o1SoUEGmTp0qf/zxh0yYMEHKlSsna9assXn2rgrAS5cuyaRJkyQqKsryWwsKCkr5VElJidx+++3SsWNH2b59uyQlJUnr1q2lU6dOluuOHj1aqlatKk8++aSkp6fLhg0bpHbt2vLuu++q+jYFIFGjIoBiAI/bHZ8LZaNqV9BdADpdleujxnRgEC8SIKUJaSEYoB0VvQRgbmGuRfyZreXclj6JBBYUFEjFihXlhx9+sBw7deqUVK5c2akAfOONN2yu9dFHH8n9999vcywnJ0cAyB9//CFnz56ViIgImTVrVql8nL9QIBtTVqkOAVvbgGED5Mb6N0rasTSH39esXVOGvjvU5lj0HdHSu39vlwRgj149pP197W3O7z+4v/yz8T8lIy9Dfkn6RQDIrMWzXF7oMWjQIOnVq5fl97744oulhoDtBeC7774rjRs3litXrljSTJ06VapWrSolJSUiogjAjh072lznzjvvlJEjRzp83qdOnRIAsm7dOoffd+jQQV555RWbY08//bQ8/PDDls9wQwCKqA8BW/vUypUrpVy5cnLkyBHL97t37xYAsm3bNhFRBGCVKlVsIn7Dhw+Xu+66y+FvEaEAJOr8A8rDb293/HMokUFHREBxFrPVhc4CMGbucxR+RDdCRgiahnunLR4RsP6qlwBMPpbssAy25W7TKadX2bFjhwCwRIDM3H777U4F4Pz5823Oeeqpp6RChQoSGRlpYwDk119/leTkZAEghw4dcpgXswByJgDv6XqPPPp/jzr8LulQkgCQuKVxNsdf+NcL0rZjW5cEYNMWTWXgiIE250/5doqUr1Bedh7fKeNnjZdy5cqpCtCMvAx579P3JLplM7n++uskMjJSKlSoIHfeeaflt7oiAJ944gnp16+f5vPq1KmTDBw40CbNo48+Kv3791d95v369ZOIiAjp2bOnTJo0SY4dO2b5zhydtWbSpEnSsGFDm2evtwCcPHmyNGjQoFSaa665RubOVSKno0ePlmbNmtl8/8UXX9jkzR4KQKKGJwIwBnbzGRBMEcC45vJ4bLR8PP+lgG5Iif4EpRAMAtFnTTBGAL0RgPYLAR588EF58sknJTMzs5QVFhbKrl27XBKAW5M2y19/56gurujWo5uhAvCr+V+pCsCsv/bI9FlfSaVKlWTq1KmSmpoqmZmZ8uqrr8ptt91m+a16CkD7xTqPPfaYvPjii1qPXVJTU+Xjjz+W9u3bS9WqVWXr1q0i4r4AXL9+vQCQv//+2/L9tm3bfCYArctQRGTixIlSv3591d9JAUjU8GQI2GEEMCcnR/Lz83WzfhPvkqbTmkjT2Kbe2bQm0veLNvL2tEfl3189JIsSp+maT1rw2dbU32T8t8Pkg5l9LNZ34p36+JtO/vrBzD4y4dthsjX1N8PLyx3Ly8uTjIwMKSwslOLiYq9s0b5FNnMAF+1b5PU1HdmZM2ekQoUKsnDhQsuxvLw8qVKligwdOtRyrH79+jJhwgTLZwASHx9vc61Ro0ZJ48aN5eLFiw7vVVhYKJUrV5YZM2Y4/P7IkSMCQJKTky3HCs7lS+7JbDl64qAcPXFQDh3fIwOHD5S6N9WV1KOpkv5XeimrWbumDH1nqM2x6NujpfdLvSX9r3RJTEkUALLot0WS/le6zP5REYCb92+W9L/S5eEnH5b2ndrbnN9/UH+5pfEtlvPLlCkj3/7wtSVfuSezpeBcvhQXF8ugQYOkc+fONr+tS5cuctttt1k+DxgwQHr06GGT5sCBAwJAtm/fblOely9ftqT58ssvpVq1alJUVCTFxcVy77332jyn4uJiefTRR6Vv374u+8Bdd90lgwcPluLiYmnfvr0MGDDA5vunnnpKHn74YYfPPj09XQDIrl27LN9Pnz5dAMiBAwekuLhY5s2bJ1WrVi11X2ufSkhIkHLlyklWVpble3OHISkpSYqLi+U///mPTRkWFxfLhAkTpH79+qq/rbCwUDIyMiQvL6/U36t5egIoAMOWZABfWn0uC+AoXF8EUhcOIoI0Gi38rH79+pKQkCApKSm62IotK2TeunmyYssK3a7pyHr16iV16tSRadOmyYIFC+Tee++VKlWqSO/evS1p6tSpI//+978tnwHIuHHjbK7z66+/So0aNaRr164yZ84cWbJkiUyZMkV69uwpSUlJkpKSIq+++qpl0cKSJUtk9uzZ8v7770tKSops3bpVIiIi5PXXX5fExERZu3atw/yuWrVKqlevLp07d5a5c+dKfHy8jBkzRhYtWiQpKSny73//WyIjI2Xs2LGyaNEi6du3r5QvX17i4+MlJSVFli1bJoAyhJ2SkmIRLGvWrJGUlBSZN2+elC1bVv71r3/J4sWLZfTo0RIRESEffPCBJQ89e/aUWrVqybhx42Tp0qUyffp0+fjjjyUlJUXeeustiYyMlClTpsjixYvlpZdeksjISLn11lst5w8cOFBq164tixYtklWrVsnWrVtL5Wv58uVSqVIlefrpp2XRokUyfvx4ueaaa+SVV16xXKdVq1Y2zyklJUU6deokPXr0cFh2S5culRdffFG++eYb+emnn+TLL7+U6tWry8iRIyUlJUXGjRsn5cuXl5EjR0p8fLy88cYbUq5cOZk+fbrDZ79161apVauWdOvWTeLj4y0ROQCybNkySUlJka+//loAyNSpU2XVqlWycePGUj61bds2adSokdxxxx0yb948mTNnjjRt2lRatWplue8rr7xiU4bmZ12nTh1N/05ISLDkScXqgoQlz0DZ/+9FAE0BzICyDUwtF88vA8V5onxgZnHpq+vTWM4sZx1t1qxZrVNTU4+cPXt2d1FRUaoRdvHixZ0pKSly8eLFna6ek5eXt+ORRx45FRERUXLttddefvfdd4+2adOmoF+/fifMaerUqXNp9OjROebPACQuLu6g/bVSU1N3d+vW7XTVqlWLK1aseKVBgwYX+vXr99elS5fM+Ut96623jtWpU+dSuXLlrtSpU+fS8OHD/zSf//nnn2fXqlWrqGzZstKmTZsCtTxv3rx5T4cOHc5GRESUVKlSpaRVq1YFO3fuzDDf44033jh2ww03FJUrV+5Ko0aNzi9YsOCA+dzdu3dnAJCNGzfuLSoqSl22bNl+AJKbm2sps6+//vrQzTfffMGcx3ffffeo9f3//vvvXc8995xcd911l8uXL3/lpptuujhhwoTDRUVFqfn5+WlPPvnkqcjIyOKqVasWP/vss3mvvfba8UaNGp03n5+dnb2rQ4cOZytXrlwCRSztt89XUVFR6k8//bQ/Ojr6XPny5a9cd911l//1r38dP3funCUf9s+pqKgotWvXrmeeeOKJU47K7dChQ7u6det25rrrrisqX778lTp16lwaMmRI7sWLFy1pxo4de+TG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\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/plain": [
"<matplotlib.text.Text at 0x7f257c75f7f0>"
]
},
"execution_count": 30,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"fig_y1, axes_y1 = plt.subplots(5, 1)\n",
"\n",
"legend = ['measured', 'initial guess', 'direct collocation solution']\n",
"\n",
"axes_y1[0].plot(times, np.rad2deg(simple_pend_state_traj[:, 0]), '.',\n",
" times, np.rad2deg(initial_guess[:num_nodes]), '.',\n",
" times, np.rad2deg(theta_sol), '.')\n",
"axes_y1[0].set_xlabel('Time [s]')\n",
"axes_y1[0].set_ylabel(r'$\\theta$ [deg]')\n",
"axes_y1[0].legend(legend)\n",
"\n",
"axes_y1[1].plot(times, np.rad2deg(simple_pend_state_traj[:, 1]), '.',\n",
" times, np.rad2deg(initial_guess[num_nodes:2 * num_nodes]), '.',\n",
" times, np.rad2deg(sol[num_nodes:2 * num_nodes]), '.')\n",
"axes_y1[1].set_xlabel('Time [s]')\n",
"axes_y1[1].set_ylabel('$\\omega$ [deg/s]')\n",
"\n",
"axes_y1[2].plot(times, np.repeat(np.nan, num_nodes),\n",
" times, initial_guess[2 * num_nodes:3 * num_nodes], '.',\n",
" times, sol[2 * num_nodes:3 * num_nodes], '.')\n",
"axes_y1[2].set_xlabel('Time [s]')\n",
"axes_y1[2].set_ylabel('$i$')\n",
"\n",
"axes_y1[3].plot(times, np.repeat(np.nan, num_nodes),\n",
" times, np.repeat(np.nan, num_nodes),\n",
" times, compute_voltage(*sol[-len(controller.args):],\n",
" sol[:num_nodes],\n",
" sol[1 * num_nodes:2 * num_nodes],\n",
" sol[2 * num_nodes:3 * num_nodes]), '.')\n",
"axes_y1[3].set_xlabel('Time [s]')\n",
"axes_y1[3].set_ylabel('$V$')\n",
"\n",
"axes_y1[4].plot(times, np.repeat(np.nan, num_nodes),\n",
" times, np.repeat(np.nan, num_nodes),\n",
" times, sol[2 * num_nodes:3 * num_nodes] * \n",
" compute_voltage(*sol[-len(controller.args):],\n",
" sol[:num_nodes],\n",
" sol[1 * num_nodes:2 * num_nodes],\n",
" sol[2 * num_nodes:3 * num_nodes]), '.')\n",
"axes_y1[4].set_xlabel('Time [s]')\n",
"axes_y1[4].set_ylabel('$P$')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now that there are gains the system can be simulated to see if it behaves as expected."
]
},
{
"cell_type": "code",
"execution_count": 31,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"rhs_func = sm.lambdify((theta, omega, i) + prob.collocator.unknown_parameters,\n",
" rhs.xreplace(par_map).xreplace({V: controller}))"
]
},
{
"cell_type": "code",
"execution_count": 32,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"initial_conditions = [np.deg2rad(2), 0.0, 0.0]\n",
"\n",
"robot_pend_state_traj = sp.integrate.odeint(lambda x, t: rhs_func(x[0], x[1], x[2], *k_sol).squeeze(), initial_conditions, times)"
]
},
{
"cell_type": "code",
"execution_count": 33,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" var width = fig.canvas.width/mpl.ratio\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" // select the cell after this one\n",
" var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
" IPython.notebook.select(index + 1);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nOzdd3Rc5bk18E3uWkm+dW8OmGYcEwIEMBBq6CSBQCCEFCCBhJYACTekERICCSQ3nqPi3hvuNu7GvXfLRb1akiVLsizZarZkNavXmfN8f7zjsSwL29Jo5p05s39rnYU8M5a2R4O055y3AERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERETkcQmAwQAMHjx48ODBg0dQHYOhfo8T9dpgAMKDBw8ePHjwCMpjMIj6wAAgpaWlUl9fz4MHDx48ePAIgqO0tPR0ATQ09wgKUgYAqa+vFyIiIgoO9fX1LIDkFRZAIiKiIMMCSN5iASQiIgoyLIDkLRZAIiKiIMMCSN5iAQwQjQ2nJC9tv6Rsmi0JS8IlfsYfJXnCS3Jg9A/l4IjvSc6whyU/4luSH3mf5EU+KLnDHpasEY9L2tifStLk1yVh1ruS+NkoObh3lZTmZ0pHe6vufxLZlMvpkrLiQknft1biV02UuPkfS/zU30rK2OckfeTTkjX8u5Ib+aAcibhXDkfeL7nDHpac4Y9K5qinJHXCi5I47W1JnP+hpG34RI4k75T6kyUilqX7n0U21djcInkHkyVpywKJXTpCYmf9VRImviqpo38kmSOelOxhj0p+xH2SH6F+tuYMe0SyR3xX0sc8KymTX5XkmX+QlCWmZO1aJMdzk6SzJTB+X7IAkrdYADUpOpwpCSvGSPK4n8nxsJtETKNfjw7HADkS+S1JmvqWHNgyV5rqanT/kylItbS0Suq+DRI9+++SOfwxqXdc0++v13pzkGSP+r6kfPqhHE3bJZazU/c/m4JU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fug8pjuITf0PgHwATwHYBxZAXxgFIEZ3iBCwGcC8bretgTrzSv2jewG8BOrM34ddbrsU6grZK37MReRTXwTgxLnvfhZCveMh37gJ6ofOHbqD2NRCABPdH+8DC6Av5EA9x6ughjWkA/id1kT29G+oM623uP98N4CTAF7XFciGuhfAG9233dPtcfsBTPZXKCJf+yrUC/2RbrePgTozSP3vC1Dv6mN1B7GpV6DGop2+VLMPLIC+0OY+RgC4F8A7UGOl3tQZyoa+AHW21QLQ6f7vv7Qmsp/uBfBR922Duj1uJYAV/gpF5GssgP43A+odB08DPwAAIABJREFU/bWac9jR16DOjtzV5bZ9YAH0hQ4A8d1umwIgQUMWO3sFQKn7v3cC+DXUpBsW7f7DAkghiZeA/Wsa1A/zG3QHsakXoH5wO7scAnXWxAk1o5L6RzGAud1u+yPU+GHqP6UA3u12238A5GnIYle8BEwhKwnA1C5//gKAMnASSH+6BKr8HQeXEvClr0CNq+x6pABYDI637G/LcO4kkIk496wgeacGwB+63fYvqElO1D8+bxLIB11uM8BJIGRDL0O9sN8EcBuAWVDLwAzUGcpmpkMtKfA4gGu6HP9PZ6gQsQ+8BOwLD0CNSfs31KSm1wA0g5MT+tsCqDfkp5eB+RmAKgCj9UWyhf+BOsN3D1QBfN/98XXu+z+C+j34HNSl9/XgMjBkU+9CXdJphzoj+JDeOLYjn3O8pTFTqNgHFkBf+QnUhJs2ALngLGBf+ArU67cYZxaCHgY1fIf67nvo+WfyAvf9pxeCroB6fe/GmZnYREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREFIAuATAYgMGDBw8ePHjwCKpjMNTvcaJeGwxAePDgwYMHDx5BeQwGUR8YAKS0tFTq6+t58ODBgwcPHkFwlJaWni6AhuYeQUHKACD19fVCREREwaG+vp4FkLzCAkhERBRkWADJWyyAREREQYYFkLzFAkhERBRkWADJWyFfAF1Ol1TXnhLLsnRHIbqgitoGaW1r0x2D6II6nS4pKq8Sy+XSHcWWWADJWyFdAMtKjsnh8HtFTEMODvuu1NfV6I5E1CPLsmTL8ulS77hG2h2XS/rycN2RiD7X0Ypa2TnsBXE5LpWK8Jul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ehHqD/s1ADcAmARVBuY8O4MKMxOgSgo8AOB8n+OHdgYVIeLBIWAz/BRqTtqnUIuafg+gEVycYLQZUDfkHWVgngNQDmCIfSGFhR9D9fDdDpUAfuj5+lLPzz+G+hx8GmrofQlYBobC1F+ghnRaoXoEf2ZvOGFHjnP0szGmSBEPJoBm+Q3UgpsWAPvBVcBm+E+ov988dBaC7g81fYeC9yC6f0+e4fl5RyHoEqi/7w3oXIlNRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERmehBqF4HTbbh2xw4GNT18/oM+5ywxKSYiIiKiPu142/h1HFFQ23KdD7V9lB3x9QNwbg+f3xHrfDABJCIiIurW+T7HBwBq/R77sX2hAVAJ4LNBnDcDTACJiIiITqofuh9qfRBdh4A7nvcbAAcANAFYBOA/ALwG4AiAagBjAHzXp53vAxgOoBBAI4BkT9sn0l0CeBuAOAD1AOoApAG4y+85M8AEkIiIiOik+qHnCWAbgHUA7gBwP4AKAGuhhl5vhEoOWwG86NPOFACJAO4DcBWAvwNoAXDNCWLqLgHMADAbwPWec38HlRT6mgEmgEREREQn1Q89TwAFKonr8AVUr57vkPEaz+MAcCkAF4AL/dreAGDgCWLqLgGsg+ppPJEZYAJIREREdFL90PMEsNHvOdEA9vk9NhPAYs/XT3raaPA72qF6DY+nuwQwynPeBgCfoGsi2mEGmAASERERnVQ/BDYH0FcUgF1+j81AZxL2IlQP4HUArvY7zj9BTMdbBHItgA+hhqFbATx3gmsTERER0XH0g3kJ4LWeNu4LMKaerAL+CsCyE1ybiIiIiI6jH8xLAAFgDoBcAM8DuALA3QD+CTU8fDz+CeAPAYzzxHQZgHsBZAMYcpJrExEREVE3+sHcBPB7UHMFc6FWERdBzRG85QQx+SeAp0L1+B2FGvotBDAWwA9Ocm0iIiIi6iNYCJqIiIgowgiAZgAFPXz+fehcXcwEkIiIiKgP6lgpfEUPn/9D9Gx1MRERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERH1Bf8fr9zZ5BSZY/8AAAAASUVORK5CYII=\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(2, 1)\n",
"axes[0].plot(times, np.rad2deg(simple_pend_state_traj[:, 0]),\n",
" times, np.rad2deg(robot_pend_state_traj[:, 0]))\n",
"axes[0].set_ylabel('Angle [deg]');\n",
"axes[1].plot(times, np.rad2deg(simple_pend_state_traj[:, 1]),\n",
" times, np.rad2deg(robot_pend_state_traj[:, 1]))\n",
"axes[1].set_xlabel('Time [s]')\n",
"axes[1].set_ylabel('Angular Rate [deg/s]');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"An exact match!\n",
"\n",
"Now try some different initial conditions for each system and see if they still output the same behavior."
]
},
{
"cell_type": "code",
"execution_count": 34,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"initial_conditions = [np.deg2rad(30), np.deg2rad(-8), 0.0]\n",
"\n",
"robot_pend_state_traj = sp.integrate.odeint(lambda x, t: rhs_func(x[0], x[1], x[2], *k_sol).squeeze(), initial_conditions, times)"
]
},
{
"cell_type": "code",
"execution_count": 35,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"g = 9.8 # m/s\n",
"l = 0.3 # m\n",
"initial_conditions = [np.deg2rad(30), np.deg2rad(-8)]\n",
"\n",
"simple_pend_state_traj = sp.integrate.odeint(simple_pendulum_state_equations, initial_conditions, times, args=(g, l))"
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\n",
"\n",
"\n",
"mpl.get_websocket_type = function() {\n",
" if (typeof(WebSocket) !== 'undefined') {\n",
" return WebSocket;\n",
" } else if (typeof(MozWebSocket) !== 'undefined') {\n",
" return MozWebSocket;\n",
" } else {\n",
" alert('Your browser does not have WebSocket support.' +\n",
" 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n",
" 'Firefox 4 and 5 are also supported but you ' +\n",
" 'have to enable WebSockets in about:config.');\n",
" };\n",
"}\n",
"\n",
"mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n",
" this.id = figure_id;\n",
"\n",
" this.ws = websocket;\n",
"\n",
" this.supports_binary = (this.ws.binaryType != undefined);\n",
"\n",
" if (!this.supports_binary) {\n",
" var warnings = document.getElementById(\"mpl-warnings\");\n",
" if (warnings) {\n",
" warnings.style.display = 'block';\n",
" warnings.textContent = (\n",
" \"This browser does not support binary websocket messages. \" +\n",
" \"Performance may be slow.\");\n",
" }\n",
" }\n",
"\n",
" this.imageObj = new Image();\n",
"\n",
" this.context = undefined;\n",
" this.message = undefined;\n",
" this.canvas = undefined;\n",
" this.rubberband_canvas = undefined;\n",
" this.rubberband_context = undefined;\n",
" this.format_dropdown = undefined;\n",
"\n",
" this.image_mode = 'full';\n",
"\n",
" this.root = $('<div/>');\n",
" this._root_extra_style(this.root)\n",
" this.root.attr('style', 'display: inline-block');\n",
"\n",
" $(parent_element).append(this.root);\n",
"\n",
" this._init_header(this);\n",
" this._init_canvas(this);\n",
" this._init_toolbar(this);\n",
"\n",
" var fig = this;\n",
"\n",
" this.waiting = false;\n",
"\n",
" this.ws.onopen = function () {\n",
" fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n",
" fig.send_message(\"send_image_mode\", {});\n",
" if (mpl.ratio != 1) {\n",
" fig.send_message(\"set_dpi_ratio\", {'dpi_ratio': mpl.ratio});\n",
" }\n",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var backingStore = this.context.backingStorePixelRatio ||\n",
"\tthis.context.webkitBackingStorePixelRatio ||\n",
"\tthis.context.mozBackingStorePixelRatio ||\n",
"\tthis.context.msBackingStorePixelRatio ||\n",
"\tthis.context.oBackingStorePixelRatio ||\n",
"\tthis.context.backingStorePixelRatio || 1;\n",
"\n",
" mpl.ratio = (window.devicePixelRatio || 1) / backingStore;\n",
"\n",
" var rubberband = $('<canvas/>');\n",
" rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n",
"\n",
" var pass_mouse_events = true;\n",
"\n",
" canvas_div.resizable({\n",
" start: function(event, ui) {\n",
" pass_mouse_events = false;\n",
" },\n",
" resize: function(event, ui) {\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" stop: function(event, ui) {\n",
" pass_mouse_events = true;\n",
" fig.request_resize(ui.size.width, ui.size.height);\n",
" },\n",
" });\n",
"\n",
" function mouse_event_fn(event) {\n",
" if (pass_mouse_events)\n",
" return fig.mouse_event(event, event['data']);\n",
" }\n",
"\n",
" rubberband.mousedown('button_press', mouse_event_fn);\n",
" rubberband.mouseup('button_release', mouse_event_fn);\n",
" // Throttle sequential mouse events to 1 every 20ms.\n",
" rubberband.mousemove('motion_notify', mouse_event_fn);\n",
"\n",
" rubberband.mouseenter('figure_enter', mouse_event_fn);\n",
" rubberband.mouseleave('figure_leave', mouse_event_fn);\n",
"\n",
" canvas_div.on(\"wheel\", function (event) {\n",
" event = event.originalEvent;\n",
" event['data'] = 'scroll'\n",
" if (event.deltaY < 0) {\n",
" event.step = 1;\n",
" } else {\n",
" event.step = -1;\n",
" }\n",
" mouse_event_fn(event);\n",
" });\n",
"\n",
" canvas_div.append(canvas);\n",
" canvas_div.append(rubberband);\n",
"\n",
" this.rubberband = rubberband;\n",
" this.rubberband_canvas = rubberband[0];\n",
" this.rubberband_context = rubberband[0].getContext(\"2d\");\n",
" this.rubberband_context.strokeStyle = \"#000000\";\n",
"\n",
" this._resize_canvas = function(width, height) {\n",
" // Keep the size of the canvas, canvas container, and rubber band\n",
" // canvas in synch.\n",
" canvas_div.css('width', width)\n",
" canvas_div.css('height', height)\n",
"\n",
" canvas.attr('width', width * mpl.ratio);\n",
" canvas.attr('height', height * mpl.ratio);\n",
" canvas.attr('style', 'width: ' + width + 'px; height: ' + height + 'px;');\n",
"\n",
" rubberband.attr('width', width);\n",
" rubberband.attr('height', height);\n",
" }\n",
"\n",
" // Set the figure to an initial 600x600px, this will subsequently be updated\n",
" // upon first draw.\n",
" this._resize_canvas(600, 600);\n",
"\n",
" // Disable right mouse context menu.\n",
" $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n",
" return false;\n",
" });\n",
"\n",
" function set_focus () {\n",
" canvas.focus();\n",
" canvas_div.focus();\n",
" }\n",
"\n",
" window.setTimeout(set_focus, 100);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items) {\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) {\n",
" // put a spacer in here.\n",
" continue;\n",
" }\n",
" var button = $('<button/>');\n",
" button.addClass('ui-button ui-widget ui-state-default ui-corner-all ' +\n",
" 'ui-button-icon-only');\n",
" button.attr('role', 'button');\n",
" button.attr('aria-disabled', 'false');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
"\n",
" var icon_img = $('<span/>');\n",
" icon_img.addClass('ui-button-icon-primary ui-icon');\n",
" icon_img.addClass(image);\n",
" icon_img.addClass('ui-corner-all');\n",
"\n",
" var tooltip_span = $('<span/>');\n",
" tooltip_span.addClass('ui-button-text');\n",
" tooltip_span.html(tooltip);\n",
"\n",
" button.append(icon_img);\n",
" button.append(tooltip_span);\n",
"\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" var fmt_picker_span = $('<span/>');\n",
"\n",
" var fmt_picker = $('<select/>');\n",
" fmt_picker.addClass('mpl-toolbar-option ui-widget ui-widget-content');\n",
" fmt_picker_span.append(fmt_picker);\n",
" nav_element.append(fmt_picker_span);\n",
" this.format_dropdown = fmt_picker[0];\n",
"\n",
" for (var ind in mpl.extensions) {\n",
" var fmt = mpl.extensions[ind];\n",
" var option = $(\n",
" '<option/>', {selected: fmt === mpl.default_extension}).html(fmt);\n",
" fmt_picker.append(option)\n",
" }\n",
"\n",
" // Add hover states to the ui-buttons\n",
" $( \".ui-button\" ).hover(\n",
" function() { $(this).addClass(\"ui-state-hover\");},\n",
" function() { $(this).removeClass(\"ui-state-hover\");}\n",
" );\n",
"\n",
" var status_bar = $('<span class=\"mpl-message\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"}\n",
"\n",
"mpl.figure.prototype.request_resize = function(x_pixels, y_pixels) {\n",
" // Request matplotlib to resize the figure. Matplotlib will then trigger a resize in the client,\n",
" // which will in turn request a refresh of the image.\n",
" this.send_message('resize', {'width': x_pixels, 'height': y_pixels});\n",
"}\n",
"\n",
"mpl.figure.prototype.send_message = function(type, properties) {\n",
" properties['type'] = type;\n",
" properties['figure_id'] = this.id;\n",
" this.ws.send(JSON.stringify(properties));\n",
"}\n",
"\n",
"mpl.figure.prototype.send_draw_message = function() {\n",
" if (!this.waiting) {\n",
" this.waiting = true;\n",
" this.ws.send(JSON.stringify({type: \"draw\", figure_id: this.id}));\n",
" }\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" var format_dropdown = fig.format_dropdown;\n",
" var format = format_dropdown.options[format_dropdown.selectedIndex].value;\n",
" fig.ondownload(fig, format);\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype.handle_resize = function(fig, msg) {\n",
" var size = msg['size'];\n",
" if (size[0] != fig.canvas.width || size[1] != fig.canvas.height) {\n",
" fig._resize_canvas(size[0], size[1]);\n",
" fig.send_message(\"refresh\", {});\n",
" };\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_rubberband = function(fig, msg) {\n",
" var x0 = msg['x0'] / mpl.ratio;\n",
" var y0 = (fig.canvas.height - msg['y0']) / mpl.ratio;\n",
" var x1 = msg['x1'] / mpl.ratio;\n",
" var y1 = (fig.canvas.height - msg['y1']) / mpl.ratio;\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x * mpl.ratio;\n",
" var y = canvas_pos.y * mpl.ratio;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" var width = fig.canvas.width/mpl.ratio\n",
" fig.root.unbind('remove')\n",
"\n",
" // Update the output cell to use the data from the current canvas.\n",
" fig.push_to_output();\n",
" var dataURL = fig.canvas.toDataURL();\n",
" // Re-enable the keyboard manager in IPython - without this line, in FF,\n",
" // the notebook keyboard shortcuts fail.\n",
" IPython.keyboard_manager.enable()\n",
" $(fig.parent_element).html('<img src=\"' + dataURL + '\" width=\"' + width + '\">');\n",
" fig.close_ws(fig, msg);\n",
"}\n",
"\n",
"mpl.figure.prototype.close_ws = function(fig, msg){\n",
" fig.send_message('closing', msg);\n",
" // fig.ws.close()\n",
"}\n",
"\n",
"mpl.figure.prototype.push_to_output = function(remove_interactive) {\n",
" // Turn the data on the canvas into data in the output cell.\n",
" var width = this.canvas.width/mpl.ratio\n",
" var dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\" width=\"' + width + '\">';\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Tell IPython that the notebook contents must change.\n",
" IPython.notebook.set_dirty(true);\n",
" this.send_message(\"ack\", {});\n",
" var fig = this;\n",
" // Wait a second, then push the new image to the DOM so\n",
" // that it is saved nicely (might be nice to debounce this).\n",
" setTimeout(function () { fig.push_to_output() }, 1000);\n",
"}\n",
"\n",
"mpl.figure.prototype._init_toolbar = function() {\n",
" var fig = this;\n",
"\n",
" var nav_element = $('<div/>')\n",
" nav_element.attr('style', 'width: 100%');\n",
" this.root.append(nav_element);\n",
"\n",
" // Define a callback function for later on.\n",
" function toolbar_event(event) {\n",
" return fig.toolbar_button_onclick(event['data']);\n",
" }\n",
" function toolbar_mouse_event(event) {\n",
" return fig.toolbar_button_onmouseover(event['data']);\n",
" }\n",
"\n",
" for(var toolbar_ind in mpl.toolbar_items){\n",
" var name = mpl.toolbar_items[toolbar_ind][0];\n",
" var tooltip = mpl.toolbar_items[toolbar_ind][1];\n",
" var image = mpl.toolbar_items[toolbar_ind][2];\n",
" var method_name = mpl.toolbar_items[toolbar_ind][3];\n",
"\n",
" if (!name) { continue; };\n",
"\n",
" var button = $('<button class=\"btn btn-default\" href=\"#\" title=\"' + name + '\"><i class=\"fa ' + image + ' fa-lg\"></i></button>');\n",
" button.click(method_name, toolbar_event);\n",
" button.mouseover(tooltip, toolbar_mouse_event);\n",
" nav_element.append(button);\n",
" }\n",
"\n",
" // Add the status bar.\n",
" var status_bar = $('<span class=\"mpl-message\" style=\"text-align:right; float: right;\"/>');\n",
" nav_element.append(status_bar);\n",
" this.message = status_bar[0];\n",
"\n",
" // Add the close button to the window.\n",
" var buttongrp = $('<div class=\"btn-group inline pull-right\"></div>');\n",
" var button = $('<button class=\"btn btn-mini btn-primary\" href=\"#\" title=\"Stop Interaction\"><i class=\"fa fa-power-off icon-remove icon-large\"></i></button>');\n",
" button.click(function (evt) { fig.handle_close(fig, {}); } );\n",
" button.mouseover('Stop Interaction', toolbar_mouse_event);\n",
" buttongrp.append(button);\n",
" var titlebar = this.root.find($('.ui-dialog-titlebar'));\n",
" titlebar.prepend(buttongrp);\n",
"}\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(el){\n",
" var fig = this\n",
" el.on(\"remove\", function(){\n",
"\tfig.close_ws(fig, {});\n",
" });\n",
"}\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(el){\n",
" // this is important to make the div 'focusable\n",
" el.attr('tabindex', 0)\n",
" // reach out to IPython and tell the keyboard manager to turn it's self\n",
" // off when our div gets focus\n",
"\n",
" // location in version 3\n",
" if (IPython.notebook.keyboard_manager) {\n",
" IPython.notebook.keyboard_manager.register_events(el);\n",
" }\n",
" else {\n",
" // location in version 2\n",
" IPython.keyboard_manager.register_events(el);\n",
" }\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" var manager = IPython.notebook.keyboard_manager;\n",
" if (!manager)\n",
" manager = IPython.keyboard_manager;\n",
"\n",
" // Check for shift+enter\n",
" if (event.shiftKey && event.which == 13) {\n",
" this.canvas_div.blur();\n",
" // select the cell after this one\n",
" var index = IPython.notebook.find_cell_index(this.cell_info[0]);\n",
" IPython.notebook.select(index + 1);\n",
" }\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_save = function(fig, msg) {\n",
" fig.ondownload(fig, null);\n",
"}\n",
"\n",
"\n",
"mpl.find_output_cell = function(html_output) {\n",
" // Return the cell and output element which can be found *uniquely* in the notebook.\n",
" // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n",
" // IPython event is triggered only after the cells have been serialised, which for\n",
" // our purposes (turning an active figure into a static one), is too late.\n",
" var cells = IPython.notebook.get_cells();\n",
" var ncells = cells.length;\n",
" for (var i=0; i<ncells; i++) {\n",
" var cell = cells[i];\n",
" if (cell.cell_type === 'code'){\n",
" for (var j=0; j<cell.output_area.outputs.length; j++) {\n",
" var data = cell.output_area.outputs[j];\n",
" if (data.data) {\n",
" // IPython >= 3 moved mimebundle to data attribute of output\n",
" data = data.data;\n",
" }\n",
" if (data['text/html'] == html_output) {\n",
" return [cell, data, j];\n",
" }\n",
" }\n",
" }\n",
" }\n",
"}\n",
"\n",
"// Register the function which deals with the matplotlib target/channel.\n",
"// The kernel may be null if the page has been refreshed.\n",
"if (IPython.notebook.kernel != null) {\n",
" IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n",
"}\n"
],
"text/plain": [
"<IPython.core.display.Javascript object>"
]
},
"metadata": {},
"output_type": "display_data"
},
{
"data": {
"text/html": [
"<img src=\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4nOydd3Qc15Huy7vn7O477+0oZ9uSZdmSLcuWsywHSZZlWQ6SbdleR0kOck6yvZYTpweBAMFMMQcx5wgQBIlE5JyJnHPOGYMJXe+P6mmAFEgCmO6+3YP6ndNHFDDo+xEAp+veqvoKgGEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYhmEYlbcBwD0AYOOLL7744osvvix13QP0HGeYBXMPACBffPHFF1988WXJ6x5gmEVgAwBsa2vDkZERvvjiiy+++OLLAldbW5svALQJjiMYi2IDABwZGUGGYRiGYazByMgIB4CMX3AAyDAMwzAWgwNAxl84AGQYhmEYi8EBIOMvHAAyDMMwjMXgAJDxlyUdALpc05h3djsWrHoea0I+hpfCP485+5fhcH+XaGkBQW1FAWZu/gVWhD6OVaGPYd4bP8KGggTRsgKC4ZERTDuyCgtWPIfVIR/HkpVfwuKTK9E1OSpamuWRZRnzM+Ixff1LWBH6Kaxc/mks2P5L7KkrFC0tIGjr7MKLu5dhYdjT9Lu75gWsjnsTZY9LtDRLwQEg4y9LNgCsr8jH+qAPIkq2t1wj0l1YHLNTtETLMuV0YsqmX6LHfsOc39+StV/HqbFB0TItS05KNLZLD8z5ve11vAub8s6JlmhZunv7MWXFN+f83nrtN2DZrl+i7JoSLdOSeL0yxhzbhoP2u+f8/raFfhCHGotEy7QMHAAy/rIkA8CKnAQcsd+JKNlwSLobs3f+EYviDmD24TBsCHpEfUPKO7BMtFTLMTE5gQVhz6jfw9KVX8KCqC2Yd24nZq39LrrtNyJKNmwO+SCOD/aIlms5ks68idP2mxAlG/Y47sf8/f/EorgDmLbnn2pQ6LLfhDUJb4qWajma2zuwwvFhRMmGHvsNWLLh21h8fidmnd6EOWFfUn+n61Y/jfL0uGi5lsLjlfHUln+p38P2kA9g0bHlWHBhHyZt/QMO2u9BlGw4Id2OfRXJouVaAg4AGX9ZcgFgc00JDkm0A61a/ikc7Gm77PNulwsztvxafaMqitosSKn18Hq8mLmSTk8mpVuxImH/W15zKTsRe6V30oN0+SfQM82nKfMlM/kcOu03I0o2rFj3PLomL/93Ozg0hBkrXlCDwNaC84KUWo/BkXEsDHqcNoWOt2PnpYuXfV6WZUw4sxfH7bchSjas2fhNRFkWpNZ6nNy3QX1PrdnzK5Td05d9vq6pGQuU7/+4dAeOd1QIUmodOABk/GVJBYBTU5NYF/QhehMK/ThOTcxdLyXLMqZv/S2iZMMp+y3YWpVvsFJrknQwQg0+ajPPXPV1laV5OKSkgYq3v2qgQuvS0tqKXfb7ECUbVq792lXrpZwuF6aHP48o2XDQ8Q6cGuw0WKn1kGUZz639uXoCNVBfcNXXJpw/qZ7A1p9daaBK65KWk6MGzvX7f3vVwLm9bwCLHI8hSjbsXP5BRE61XxMOABl/WVIBYMaOPylp33uwv6vlmq/1eDxYHPY0nVSFfgy9brdBKq1JY0O1+iZfctRx3ddnnD+kngi0FCUaoNC6yLKs1qW1B78f3ZPX/vc6MDyCtdIHKFjc8A2DVFqXi4nn1XrVtozD13191A4JUbKhU7oVJzpr9BdoYYbHp7FI+gSVfax+EtHruebrS6qqscdOGYLGI38xSKU14QCQ8ZclEwC2NlSi034LnTqdn199VEdrg1orWHhmvc4KrYssy5i94quIkg1rwz6F8nXe5H2krf4ftR5Q9nCAfTXSLp5TmxC6ylLn9TU5mclqvWV7QYzOCq3L6OQ0lkofpazA5u/M62vGp1yYH/QZ2hxu+KrOCq3Nid2rlZKQ23C6r2leX3Py4DbKJEg3o7O7Vl+BFoYDQMZflkwAmLvmW4iSDcvDPoey1zvvr0vfJyFKNuyT7kUnW2zMSVF20kyAUp0376/r6OrAYftddFJ1YbuOCq2Ly+3B4iBKi5Vv+eGCvjZh9csUYId9jOvVrkL04S1KgHI7Tg/NP12elpmuBtiDlSk6KrQuLT1D2Ga/n34HzwTN++smpz2Y5XgCUbJhw+YX9RNocTgAZPxlSQSATdUlaoqnoSRtQV87NTmBHdK7ESUb5h8L10mhtckLe5ZSvxu+veCvvbjzb4iSDTuCH+JTwDlISzxLtajSrTjZf+2yhSupa2xS0/Jt2Sf0EWhhRiansVqirv+aI39b0NfKsozxK75D7ylrntZJobU5uT2ESm6C7kN0TS7oay8kJtCmUroBnZ3cEDIXHAAy/rIkAsDMjT9BlGx4KeKZRX19xuFwRMmGXY53o9fNZqWzqa0uR68SXPc2li746/sG+nFIOQWsTT6kg0LrIssyZix/DlGyYdnWlxZ1j7j11NxQH/FZjdVZnwtnDqhdp97xhftSZhcUoktpCBltvHrjyFJkcMyJtfb3I0o2bD238GYZl8eLKUFkJ1W/Y2En30sFDgAZfwn4AHBsdFit46tIPbWoe0xMjOGARD5VpYkHNVZobZI3/pJSuBGfX/Q9Lm7+HQWA4Z/WUJn1KS69pJ5cDzUWL+oe5VWVapAyUJersULrIssypodQgFG559eLvkdSKNW+Vm/7kcYKrU1U1HHl5Po2lCeHFnWPs+ciESUbTku3oDzep7FC68MBIOMvAR8AZp1YS4XwjvfOuzlhLtK3/obqsMKf0lCdtRkcGlZd/WtTjy76Pg31NWo9VX9jiYYKrU3culep0WCVf79zqWFfow3Qjp9opMz6FJRVqr9z4+1li75P7IWzakewPDWsoULr4vHKGB/8FTq92/XjRd9nZHIay+yP0ilidJiGCgMDDgCty68AoBQARpUrGwCem/X5twFAMAB0AcAUACQCwHuuuMd/AcBmABgAgHEAOAUAdyxQR0AHgLIsY03wRxAlG+YesPt1r+b6SrXRYaCrWSOF1ib56DpEyYbdQQ/4Xb+Xq9QRFu9c3GlMoDE0NoEDynSEtuzFnVz7iD93TPG4uwORJ1ggImLUxj8jSjZsivDv1HnC6cJ6+/vIzihxh0bqrE16caXqlTjV7F9q/MT2UKoRDntUI3WBAweA1uVrAPBloKDuvQCwHABcAPCw8vnXAWAYAF4AgA8CQBQANAIFfT62AkArAHweAD4KFERmLlBHQAeAtSXZlEKw34wjff4b4paHUDdm3pFQDdRZn6LQJ2layoF/+H2vtKjdNN4s6N3csYqIyeeOKFMp3oHoZ3A9ODaFrXYaE9eRznWWQ+NT2KJ8P9ou+h+0RW98jZpBVnMzCCLi6c1/p6xLxCf9vld+ZYMaTLo6yzVQFzhwABhYDALAT4FO/7oA4C+zPncDADgB4Luz/t8FAN+a9ZqHgH4ZHlvAmgEdAGbsJOPn4pXPaXK/9IOhyhSRT2hyPyvT3t6mptAGmv3v0hsYGsYx++0UpJQtrFM7EEmKoA7Tsm2LT6HN5sLaVxVj6G9qcj8rczEhRtMT0fTcfJofLN2InuGlPXnF6fZgof3jdCJ6fq3f9/N4ZUx1fJ5Oa4//XQOFgQMHgIHBvwMFdtMA8H4AuB/oh/roFa9LBYANyp8/r7zmxite0wIAry1g7YAOABuCyOKhMGqTJvfraGtSi/J7W6s1uadVST6yRjFx/pBm98xU5tgu9TRw79Co2hndXRKvyT0zUmLVUWde54Qm97QqMet+QY0bb2gTDDvdHiySKOhpPBuhyT2tSnpRmeoK4B1qu/4XzIMTu+m9pnf5+zg7MAsOAK3NI0C1ex6gdO+XlY8/DvRDveuK1x8HgGPKn78PFDBeSR4ARFxjzf8E+mXxXfdAgAaAzbWXECUbuu034shgj2b3vRT6WUoDH1im2T2tSP5yGpNXfGBh/mnXIlVJA/cu8TRwQhTZkwwE3Xvd0VnzZWrajZ32d1GQkn5Mk3takclpj2pP0pa6V7P7nt7moFOviE9pdk8rcmJbkGbpXx/5Na04ab+V0sAtbLfjgwNAa/MfAPAAUP1eOAD0AZ0A6hkAOpR7X3YFYgCYuW8ZpdDCn9T0vhlHVi75NHBHV5dal9PftHDvv6vRPzikpoG7y5duGjg54tvUcb7zVU3vm7j2FeoG3vw9Te9rJVKzc2hjKN2E8uTCvf+uRnZxqZoGlsf7NbuvlXB5vJgh0Qa5JTJEs/t6vTImOqhJrJHTwCocAAYWiQCwHfRNAS+ZE8CqEBpAnn984Sak16KtuZbe6O034PhQr6b3tgppp7eSNUPIBzS/d1Y4+aoV7Vuag+AnnW7stt+rywzfxAunESUbjjnu9ruxxKpEbv6b0rCxeN/KuZhyebDa/gGl0WZpeoVmVzSonpOenhpN731qF5nxt0Y8pul9rQwHgIFFEgDshZkmkD/P+pwN5m4CeXHWax4EbgJBRMT+3k61DqW/o0nz+zc5KIVUGq9dCslKZKz5LgVpOtTqJR+m4fF1YUszlZaXlznjK7fA8VnXo3NwTK0tHKnN1PTeVsDrlbFA+iQ1FJxbo/n9z63+GWUHtv5A83tbgTMHN9Hp/XLtN4ZJucXqCStODGh+fyvCAaB1CQeAzwHAfUC1gOEAIAPAM8rnXweAIQB4Xvl8JMxtA9MCAE8BpZGzlGshBGQAmH9+DzUoBD2sy/0zNv6UThc3Lj33f4/Hi+3KbOT6DP/86eaiqrJcrd10TyxugoCVid1lJ2PtldqeUPlID6FUWsXRpVfDWtncoXauu/qbNL9/TNRRZfbtvYher+b3Nzsx4bQxrNur/cZweNKFNcvIb3Ewb/Gm84EEB4DW5U0AaAaq4+sFSv8+M+vzPiPobqCTv0Qgv8DZ+IygBwFgAgBOA8CdC9QRkAFg1hs/JvPnTdpYaFxJfvwRZTbwA0uuWaGqooQeoPab0D2p/e+Nxytjs/QgBZhLsFkhJ4QsLypPBOly/9jdwXRKFaFtbawVOK/M/u0Jea8u96/r6MNx+210gtu6uNF9VmV40oV1yx6iAK1A+40hImLUipcofe/HdJFAggNAxl8CMgBsCnoYUbJhSdw+Xe4/PDykNkF0Ny4tc9LkQxEUQOg4tzdlzQ/p57dd2yYIs9M9OKIGECMN+bqsUVSYo6SYb0F5emnZwcSs/TnZv+iUopVlGdOCKIBvPB2syxpmJTmfNoZe6QZEDZtrZnPyCLkEDIS8Z8ltvOeCA0DGXwIuAOzuaFZHto0Oduu2TmnoZ8hj8PgK3dYwI9krqEmjeP/ruq2RcmYX2XTo0GRiZlLizsxM/9AphTg1PdNk0lV0QZc1zIjHK2OJ9FFqJLi4U7d1IreR+0Dd2md1W8OM+Lz62ld8XLc1cmva0Gm/GVGyodyrbZOJFeEAkPGXgAsAc89upzRBiL6zI9N3/S81Qqz5uq7rmImpadfMfNqSi7qt09zWrhpuT/a36raO2Yjf/Eeqz9N5WkdK+NcpzXzgz7quYybKGtvV+j/PQJNu61y8GDvTab2E6gBjQr9FJ58H/6DbGk63B/Ps1MTTmbxdt3WsAgeAjL8EXACYvf4HVP+39Re6rlOUEkkpYMe7dV3HTJQW0WzlSek2lN1O3daRZRmrHR+idN3F/bqtYzbygp+gwCxyta7rRO8lL8vmFUun0/rcqf1kMq5T/Z+P5t5hNY0/3aGdR6aZ6R11YvMymq08Vhqt61pRSqd13c5XdF3HCnAAyPhLwAWAzT6LlsTDuq4zNDSgnlINdTXrupZZSDlCFi3V4Z/Vfa3UtT9UxsL9Rve1zMDwhBNH7HdSEX1drq5rpefkUoAi3YyoYyBvJqLX0vi3mm0/1HUdWZYx1/E4BdixG3VdyyykKvV/HulGxCl9nyWnD++g8oWwD+q6jhXgAJDxl4AKAIcG+xAlG6Jkw+Hedt3Xqw360JLyA0xb8z2qe9z1e93XSj66XvEDfFz3tcxAXl4WomTDKelWRI9L17UGxpw4YL+bmk3qsnVdywzIsoxFEhnDNyds03296HW/JiufrUtj4sqZQ2QM3xH2Yd3XSi2qUN/j9Wo2sQocADL+ElABYEkqpWU7HQ8Ysl7merIlyN/2S0PWE02d4xE6AUw+pPtapSX5akCkZ7rZLMQdWEUBb4T+p6uIiDnBT9HPMlLbSTlmpLVvBCd89iydFbqvd+7UPrKbCX1I97XMQNTqVw1Lyw6MT2PjsvcgSjYcL186TUxzwQEg4y8BFQBm7P47NWasfsGQ9TJPkfN9zXLtBp+bla7ePkMbM6am3erUip7qLN3XE03Syv+h2dV79Suin42v4aTsje8Ysp5IUtKSESUbTjjuMKQxo6C6SZ1EJI/q50RgBrxeGbPtlPLuSNxiyJoXQl6g09wT/zBkPbPCASDjLwEVABZGPEcNIAcdhqxXX32JaqnsN6NnesqQNUWRc5EsSnod9xu2Zn4oeaqVnQ7sUyqvV8ZaO3lXtmQaY36dGnOYHtrB7zNkPZFE71lBzgCrnjBkvSmXB6uW0c+zL++EIWuKorZrGEftd9D0nvYSQ9Y8vtVBAeC6LxiynlnhAJDxl4AJAGWvF3ule+lELjfOkDU9Hi/2299O9gdFSYasKYqknX+jese1zxu2ZuLW12jNDd82bE0R1Da3qydG7uFOQ9asbmxWa6m844E9WzVuBdWuVu/Tv3ZVXTP827Tmof81bE0RnE9KVozFb0P0uA1ZMyoujjIRjjsRvR5D1jQjHAAy/hIwAWBHc506Q3Zq3Li/T2H4M1QHeCzcsDVFkBv2JZrOcVSfEWVzkX6BZqt2Betr3SGa1AsnKNUd/B7D1nR5vNhofy9ZGRXoa90hErfHi2X2R6k2OEP/2lUfZ3cG0TjDADeEPr6LJgO1rjKmdhURsbRlACftty55Q2gOABl/CZgAMC9mD6V5gj9k6Lrp26mWquCN7xu6rpF4vDL2KNMjWosSDFu3qbVNPaVyjwdux1/cjn+QAfQ6Y2pXfSSHPU+nVEf/aei6RlLd3quObfT0Nxq2bnxsFFlEBd1n2JoiiA6j09WGg8adrro8Xixe9hFKsWfra/dlZjgAZPwlYALAzK2/QZRsmPeGPnM+r0auEnjWh3zE0HWNpKm5SR2v55kaNWxdr1fGdvu7afJIkTFpfRGkrqDJHGWHjQ3Ezm6nsWW1679i6LpGEh9/juxugt5u6PzY0saOmUaQEWPS+kYz7fbipWWPCgnEzoVR01TD4b8Yuq6Z4ACQ8ZeACQBLwqhhIP/EKkPXbawtUxtBvK5pQ9c2iuz449QwEGS8rUXu8i9SHeDJwEyxy7KMtZLSAJJ1ytC142NOUmOPgalnozm7w6GkYr9o6LpTLg/W2t+HKNlwoPisoWsbRWX7wMxs3v56Q9c+uY1S7E3rjP25mgkOABl/CZgAsEe6j04z8hMNXdftdqtdcO1V+YaubRTJu/9JQdiarxm+9sUtf6Daw03GnuwaRWvPgDqjdnrA2LnHZXUzjSDy5JChaxtFworvIEo2rDpk/EnRxdCvUfB5UjJ8bSOIT0kmr07H7YbPPT57jlLsw8H3GrqumeAAkPGXgAgA+7o71AfZ5KjxD7KyEPLBKo7eavjaRpC58pvkr3jgb4avnXJmF+30Qz9q+NpGkJmWSClKxz2GpigR6ZSqw/4uSuGVB14XuyzLWCJ9lEoI0g8avn7U5tfJIPmNrxu+thGc3r+B6oIjjJ8pnVPdpvqSYoB7LV4NDgAZfwmIAPBSGu0GOxxiukUz3vhJQE8EqVUmgNSmHjV87dLSYsVm4hbdR6SJIFaZAFK78kkh62eHPI0o2bAycrWQ9fWkfXAcx5UJINNdlYavfy7yCKXYQx40fG0jiFxN85Xrdv3E8LWHJ1xYu4xS7ONl5w1f3wxwAKg/gwu8BgDgXiFKF0dABICZB0PoBG7lc2LWP7GOHqLhnxOyvp4MjY6pXZRj3Q2Grz8+Na2m2Icaiw1fX28S17xMDSBv/kbI+gkbqXmqdMtLQtbXk4y8PAr+pFsM86ibTW5F3ay5tYGXYk910DjBttj1QtaPC/oKnUBGBgtZXzQcAOqPDAC/B4CX53G9AgCTAHC/CKGLJCACwJx136UJIG/+Wcj6FYVpVI8i3W14Gk9vivPo7zYq3Sns71Ya9EmyK4nbJWR9PSl2PEZ1YvE7hKyfeGIrGZmHB944w5jjOyhACRPToT80MY1t9vtp81STKkSDXvSOOtW/m7MuXYiG4+v/Qr+7W74lZH3RcACoPzIA3L6A148BB4CGUxNMdT4lcfuErD82Po4u5ZRssMPYbji9STlGdT414Z8WpiF57Y/o5/vm74Rp0IOhcSeOKKebo81iTjdz87Kpdla6LeCmKkS/QR6d1Vu+J0xDZtCTVMN64Q1hGvQgo6xe+OnmiWP7KMW+/GEh64uGA0DGXywfALpcLpyy30JO/w3lwnQ0OD5AaeA0Y6089CbljZ9RA8i2nwnTkHiApg1Ur/y8MA16UFJGs6Rd0s2IbjEWQp2DY+q/n+meWiEa9CIlhGaD150OFaYhZvVP6Xd39y+EadCDyEiyhhoIEWchdDGX6oM90o2IbqcwHaLgAJDxF8sHgI1V9CYwYb8NZYEnGHkRX6VGkMOBVY9SHPo5qlE7u0GYhty0WOpUdbxLmAY9SIo+SCnK0A8K0yDLMpbZP0w2RhmBM1XB6fZgnf0hClJKzgnTcXbvSjIsXv2UMA16cGKLndKvG8SZiDf0jOKI/U4yqe8sE6ZDFBwAGsvzV7m+BgDPAMC7xElbNJYPAPPOkU1ITejHhepI2/FawI2Ek2UZu5URcG2XkoXpaG7vVNNNnonAKaaP2/kvGgG33tgRcFeSGP4inVId+btQHVpS0dKt+ivKw+3CdMTHxygj4e4VpkEPzoeRv2LDkb8K0+D2eLFwGZX/9OcEzuZlvnAAaCwyAHiV/86+vLP+mwoAN4kSuAgsHwBm7vozjYBbL67OBxEx++xOCkSXB04xfWd3txp4uQTO4vV4ZwLRrnIxBed6kLySHqJlB8Q9RBERz20hv7rqN74pVIeWXEyKp+YLh9jGrOL6mXnWODEgTIeWeL0yFtg/jijZsDvjgFAtMaHfopPIE/8QqkMEHAAay5MAkAMATwPAfyvX0wCQDQBfAYBPA0A5ALwpSN9isHwAmL/qBUTJhjkHJaE6qktyhHfLak1hJj1E+x33ipaCRSGfpRrLmM2ipWhGqYMeog1JYpqXfMSe3kOnvMsfFapDS84dWEuBwUqx1kwjU65ZncApQrVoRevABA7Y70aUbOhuLxGq5cTGv9G/oc2Bs3mZLxwAGksZADw+x8c/DQAVyp+/AACthinyH8sHgPVBHyIfs4tHhOoYGx9XU07D3S1CtWhF6jHyN6xa8YRoKZi87mWlE/i3oqVowujkNA4r9UujTWL9DXML8mf88gKkEzhm3a/od3eH8SbFV5LhoE7g5tjA6AROL6mkujvpBsTpCaFaTh7bSyeRYeLqaEXBAaCxTAHAB+b4+CPK5wDIBHrSMEX+Y+kA0D27A7ixQrQcbHaQM311ZpRoKZqQsumX1AG89aeipWDivuV0Arj6WdFSNKG0qnqmg9E1JVRL1+A4OpV/R86eOqFatCI15EvUARwVIVoKnlM6gWsDpBP4bNQJasoKETN5aTbxWQV0EindFJCTgq4FB4DGkgEAFwDgtlkfu035WJry/18AgBqDdfmDpQPA1gbaiTrtt6DXbbzT/5XkryDbiYJjYaKlaEJ+2DOIkg0vnVopWgpmJp6hGsAg8Q8dLUi+QA/RzpD3iZaCsixjtUTj/lqzrW9j5PZ4scb+fvKIK4oWLQcjd1MncFOAdAKf2kGTlxrXid+MVXYM45j9dmr26akSLcdQOAA0lgcBoBoApgGgXrmmAaAKAN6rvObrAPAjIeoWh6UDwKLEo/RGFGyO4/+0bb+nAHBTYIzVapHeS9/f3BjRUrC2sUFNO8mC005aELs7iFKUa78sWgoiIqaHkY1R+XHr2xg1dA+h034z/b4MNImWg7Fx1Ak8HPRO0VI04WzEyzS9Zr/4cowplweLl5GN0XDBcdFyDIUDQOP5NwD4EtB4uN8DwLPKx6yKpQPAzP0SpShXPy9aCiIiZp3eQg/1MHFTM7Sif2gYPfYbaErEgDgbDR9Ol1stPB+oyxctx28urvoBdQDvfU20FEREjNv0BwoAN/9AtBS/Sc/JpcyAdCui1ytaDhbWts6amiGum14LZFnGdIm8QTsSzdGQdT7k64iSDVtO2UVLMRQOAMXxXwDwNtEiNMDSAWD2uu9TB7CgGcBXUlGYTp5f0j2ipfjNpYIM03U1X1JmAtfEvylait8UBj1ONWrxO0VLQUTEuGObKU254jHRUvwm5sRuZQbwh0VLQUSaCdyl2BhNNuaIluMXfWNObF32bgqw69NEy0HEWTOBt35btBRD4QDQWP4NAJYBQAcAeGBm5m8IAPxUlCg/sXQAWBHyGJ0AntshWgoiIqaHQqwAACAASURBVA4NDao7/cnhPtFy/CL19HYKUEzka5iy+rvUCbzPHAH/YnG6PdhrfweiZMPBWnMEBOnpyYpv3l2mCfgXy1nF17Bm44uipajkSZ+ioDRlt2gpfpFb04ZeJTOA4+Z4jzt5cBtNslkhdhiA0XAAaCx2AGgAgB8Adfr6AsD/AfICtCKWDQBlrxeHJEoJNpVli5aj0i3dR7vRYmt7fiVvo8kmJRvFGmzPJuHNZZQ2Xfd10VL8or6tQ90oyJPmmGxS09arpvzlkU7RcvwiPpzMgWtMNNkkLpxMv2uP/E20FL84F0djGceC7jHNRuFCUjJtuh3myVYYAQeAxlIPZPwMADAGMwHgQwAwJESR/1g2AOztIod9r/0GdE6Oipajcin0M4iSDYujt4qW4hdZEVRXU3TIPHU1qdH7KeAPNUdqb7FkZ1ykUgHHO0RLUZlyebDJ/h4qpq9IFC1n0ciyjIUSGWy3p+8XLUclarNyKrnJPKeSi+HUvvXULb7SPHXOBfWd6uYFR7tFyzEMDgCNZQrI5w/g8gDw/QAwLkSR/1g2ACzLukA2Go53i5ZyGVnrqLg/780/iZbiF5VBNGOz6uJB0VJUSoryECUbTki3W3qnn3icmoXqwz8lWsplZAWRYXFT7EbRUhZNz+iU2izkbBVrsD2b6OM0KrI1/GOipfhF5NrfUGnIjpdFS1HpG3Nii1qXGDijIq8HB4DGUggAP1T+PDsAtANAuhBF/mPZADD7JO1Ey8KfFC3lMtL2UpqyaI1105RujxeH7HchSjbsqSsULUelZ2hE3ek7B9tEy1k0cVtpfnXZJvOk1xERY1e9REH/vt+LlrJoCipqZzpuTWQXlJyRoaQp77D05iUhhOyCmiJDRUtRkWUZM+w0KrIrebtoOYbBAaCxvAAAwwDwOgBMAMBfAGAnkBfgMwJ1+YNlA8DM7b9DlGyYu/Fl0VIuI/fCATrdCfmIaCmLprVtxrbC6xwXLUdFlmVsUdKUbUVxouUsmtSIFykAPPwv0VIuI3qnRGnK9V8VLWXRJMZG0ZSKYHNlBipae2elKbtEy1kUHq+MJYrnXl+euTz3osPJEaLhsLUbxBYCB4DG81kASACAXqBGkAwA+KJQRf5h2QAwf+XXKAA8FCRaymXUltFc1XELpykLM+NpioLjXaKlvIX80KcQJRtWRFt3ruolxyfoYZW8T7SUy4iNPEj+bqGPiJayaM7tX00bsFXmmrox7nRj0zLavIxVJYuWsyhaBybUzIC3s1S0nMs4sfmf1Hy38QXRUgyDA0DGXywbANYFP0pjyi4eFi3lMsbGx9Wd/mifNdOUaSc20kzj8M+KlvIWkte9TN3Jb1ozTTnl8mCf/e1kAVOfJ1rOZWQX0OZlWrrFFAbKiyFmw69pZvSOn4iW8hYyHU+QYXH8FtFSFkVmaY0p0+uIiKeO7aEUcNijoqUYBgeAjL9YMgD0erw4rsx/bKs1T6G3j3bpATqFyIsVLWVRJG/9I9UxbvqhaClvIXEPjVArX/MV0VIWRV1L+4wFzJS5/t219I7gtP0mZYRas2g5iyIl9Ctkt3J6uWgpbyFmJdVY1h74g2gpiyLmPKXXB4PvFy3lLcSlZyqbF3NMfzECDgD1ZwgABud5WRFLBoA9HS2Ikg099hvQ5ZwULectFC+nNGXRmQ2ipSwK1QLmsCRayltIO3+YuilDrJmmzEpPoIeow3xzYT1eGevtD1H6v+SCaDkLRpZlLLNTZqAz54RoOW8hcrtEHbQbrFljeXrPGkTJhs2rnxAt5S0UNfWqmxccahUtxxA4ANSfl2ddfwIK9I7AzCzgI8rHXlvgff8OAPlA3cS9ABAJAA9e8Zq3AUAwAHQBWdAkAsB7rnjNfwHAZgAYALKiOQUAdyxAhyUDwLLM84oFzAOipcxJxoZXECUb5u8QPyx9MagWMEnmsYDxUVpaZKo5rwslQRm5Vr/CPD5qs8kKeZqClHPrREtZMD3DkzhivwNRsqGrs1y0nLdw7gzVWHYut+bmRbWA2fmKaClvYWhiGuuXPYgo2XCqOkG0HEPgANBYTgHAb+f4+G+BAriFEAsArwDAwwDwIQCIAYAWAPi/s17zOlDX8QsA8EEAiAKARqCgz8dWAGgFgM8DwEeBJpJkLkCHJQNAs1rA+Eg7EEp1aqusl6Y0qwWMj/6RcXWnP9VrvTRl/JY/KRYw3xctZU7i1/6Ymmx2/1q0lAVTWDnLAsZlvsxAWl4hBafSzYhej2g5C8aMFjCzSZEo89KZYF0fy4XAAaCxjAPAA3N8/AHw3wj6NqAf5OeU/38b0MnfX2a95gYAcALAd2f9vwsAvjXrNQ8p93lsnutaMgD0WcDkmcwCxkd+wjFKlQRbb6dvVgsYH7IsY6NEacqW/BjRchZM6opvUA3jkWWipczJhd0h1AC05jnRUhZMYtxZU1rA+KjrHkan/Raq/xxoFC1nQbg9XtUCpj/ffOl1RMTIFS9Td/2B34mWYggcABpLCwD8eY6P/1n5nD88APSD/IDy//cr///oFa9LBYANyp8/r7zmxjl0Xi0l/Z9Avyy+6x6wYADos4DJMZkFjI+GmjIlTXkLyhbb6RdmxJrWAsZHbugXKIiKXCNayoIpddCYsvrkA6KlzElSzFE6RQl5WLSUBXNuP9WoNawyZ2bA6fZg9bKHaQzgJWttXlr6Z1vAlImWMyfHt1KDWNOGL4uWYggcABrLKwDgAYBoAPiXckUDgFv53GL5NwA4B+Qp6ONxoB/sXVe89jgAHFP+/H0gE+oryQOAiKus5VDue9lltQBwxgLmiGgpczLldKppysH2OtFyFkSqiS1gfCSt/yml2Hf+SrSUBTE57cF++z00b7ehQLScOSm6dGkmTelxi5azIGI2UI1a5fYfi5ZyVZKDv0jZgZjVoqUsiAwTW8D4OHXyEG1el79ftBRD4ADQeD4JAIcAoEi5Dikf84etANAMAG+f9TG9AkDLnwCSBcxtiJIN201oAeOjyfE+mqqQFSVayoKYsYD5kWgpVyVx33KqU1v9JdFSFkRN80x63WwWMD56RibUNKWzt160nAWRHPpVxQLGnDVqiIhn1/ycNO7+hWgpC+JcjHktYHzEZ1ONpUe6EdHjEi1HdzgAtD6bAKANAN51xcf1SgFfieVqALs7mmcsYKanRMu5KgXhtNMvPLFStJQFkRXxAqJkw2ITWsD4SI87QRuAYGvt9DNT4xAlGw447hUt5arIsox19vfTRJCCaNFy5o0sy1jqs4DJNmeNGiJi5JsrKE299hnRUhbEqT2rFQsYc6bXERHL2gZx0n4rbbL6rbV5WQwcAOrPQr+x/z3P170NKPjrgLdau/g+3wWX1xzaYO4mkBdnveZBCPAmEJ8FTIfjPaKlXJO0TbTTz9/2c9FSFoSZLWB8lFeWI0o2dEs3WSpNmXBsE9lorPiMaCnXJCuUNi/VUatES5k3ZAFzJ6WvO8xZo4aIGBN9ktKUIQ+KlrIgItf+WrGAMW96fczpxsplH0CUbDhRdk60HN3hAFB/vABw+wJePwp0enc9tgBZvDwBAHfOuv7PrNe8DmRE/TwAPAJkNTOXDUwLADwFZAOTpVzzxXIBoNktYHykH44gnRHW2em73B4cVgq9e+vNZwHjY3jciVNKmnKiq1a0nHkTv5nS62WbzTdhZTYJ614lnTutk6YsrKwztQWMj8zi8pk0pXtatJx5o1rARJk3vY6ImOigzUvHBWvVWC4GDgD1RwaAf8CM8fP1rimYXwD4lkYM5Xpl1mt8RtDdQCd/iQDw3ivu4zOCHgSACQA4DRRIzhfLBYA+C5jcjeYzI51NQdJpGlUX9D7RUuZNS2uLqS1gZlMnUTdlc06kaCnzJnUFTVgpP2oXLeWaxO4Lo/rV1V8ULWXe+Cxg+k1co4aI2Nw3hmPKGEtvT41oOfNitgXMQMFJ0XKuyemVP0OUbNi41zqbl8XCAaD+NANA0wKvd4gQukgsFwAWrKSdaO6hYNFSrklTfTWlo+w3oWyRguQC1QLG3A9RRMSc5c/SKdVp69RYljkovd6YYt70OiJi0gVKU3aFPCRayryJNrkFjA+3x4sVyx6hYLXQGpuX5v5x01vA+Di2nRrEmtdZZ/OyWDgAZPzFcgFgXRAVepea1ALGh9PlUrsp+9ussdNPPf6G6S1gfFzcQDWWJTusUWM5Me3GQfvdiJINR5rMm15HRCwu99VYWqeb8tyG31Lt6nZzZwYQEZNDnqONwNkI0VLmRfqlatNbwPg4dfo4veeGWqvGcjFwAMj4i6UCwNkWMG21JaLlXJdGB6UpqzPOiJYyL6xgAeMj8QB1U1auskaNZVVD86yHqLnT670jk2o3pbPHGjWWyaFkDl97KkS0lOsSrVjB1Lz5qmgp8yJasYAZMOmEldkk5JRYssZyMXAAyPiLpQLA2RYwbhNbwPgoCH/WUlYwPguYoiMO0VKuS0YC1Vh2BFujxjIzhdLrA0H3iZZyXWRZxho7bV468szvYynLMl6yf1ixgDkuWs51idytWMGs+YJoKfPi1G7zW8D4KG8fUmsssdcamZfFwgEg4y+WCgCtYgHjI91iVjBVQR+hE8ukQ6KlXJfKqgpLWcHEH92gWMCYP72OiJgZSpuX6jPm37z0jEzisGIBM91RKlrOdbkQc4pmFoe8V7SUeXHGZwGzy7wWMD7GnG4sV2osx0vPipajKxwAMv5iqQAwR7GAKQ1/SrSUeZF+mHb6pSufFS3lurjcHtVHzcwWMD6GJ2asYMYtYAUTv+n31LSyxfzpdUTEuPW0eSnfaf7NS2FlvWVq1BARM0sqZqUpnaLlXJf4YGq8a44KEy1lXsQ7aPPScd78mxd/4ACQ8RdLBYCqBcwm8+9EERELkmin32qBiRXNl1nAmP8hijhjBdOUbf5uyrRwSq+XHzN/eh0RMXZfuGIFY/4ay4T4aKVGzfzd64iILX3js6xgqkXLuSauWRYwgwWnRMuZF6dWko9l4x5r1FguFg4AjeezAHAQALKB5ugCAPwIAD4jTJF/WCoAVC1gDpu/0BsRsam+ktJS9ptRNnma0koWMD6sZAXjs4BpSjssWsq8SFasYLqDzW8FE71/rWIB84RoKfPC7fFiuf2DlrCCaeqbZQHTVS5azrw4up02Ly3rrFFjuVg4ADSWFwFgEgB2Ahkz+wyffwsA50WJ8hNLBYD1QR9ClGx46eJR0VLmxZRzGp32m+l0ot3caUqfBUxV+OdES5k3VrGCGXO61YfoaHOxaDnzorjcV2NpfiuYGNUC5mXRUuaNagUTtUK0lGuSZiELGB8nz9Cs8IFQa9RYLhYOAI2lGABeUv48BjMB4IeBpnVYEcsEgLMtYNrrLomWM28aHe+nVFqmuXf6yVt/bxkLGB8zVjDmNn2tamiy3EN0thXMtMknViQtt44FjI/otb+kJptdPxMt5ZpEn4u0jAWMj/jcUjqxlG5AdJnfLWKxcABoLJMAcJ/y59kB4P1AJ4JWxDIBYFdbI51I2G9E97T5C6d9FITTbMrCk6tES7km2RHPI0o2LLaABYwPq1jBZCRT93pf0LtES5k3ZAXzAcUKxrybl9kWMF3Zx0TLmTeRu1dS2nr106KlXJOTu1dRA8gaazTeISKWtQ3hqP0O2nD1VImWoxscABpLIwB8Qfnz7ADwJQCoFKLIfywTAJZlnKPTP4e1jvXTN72qWMH8UrSUa+KzgKlKskaNGqJ1rGDijygWMBHWSa8jImaEfsn0VjDdwzMWMC4LWMD4mLGCMbel1Zk1v0KUbFj/5k9ES5k3Y043li6jGsvxS+bdvPgLB4DG8ncAqACATwLAKFDjxw8AoBcAfidQlz9YJgDMPkGzPktXmHvHfCXph8IVK5gviZZyVWZbwPTVF4mWM2+sYgUTt5G618u3viRayoKIW/8LxQrGvN2U+RU1M+l116RoOfMm+1KlJdKUicFfphPAs+auVbySOAfVWHbEWEv3QuAA0FjeBgD/BIBxAJCVawoAQkSK8hPLBICZW8mMNGfTT0VLWRD5F6mbsiX4YdFSrkpTy8yYMqtYwPiYsYIx78SK9DCqUas4YZ0aNUTE2H0rFCsY83ZTxsfSmLJ+C9WoISK29o+raUpPtznTlNNur3qSNlRkjXGWPk6spM1LUwBbwXAAKIb/AID3A8AnAOD/CdbiL5YJAAsjaCeae2S5aCkLorG2wvRWMPlpVKPWHWSthyiiNaxgKqVH6RQlw/xjymaTFHvK9FYw0fuoRq1+1edFS1kQHq+sWsH05p8WLWdO6ntG1SBVtlgt3eEdtHlpXWutjNFC4ACQ8RfLBICNQTTepyzlhGgpC2K2Fcxge51oOXOScnQdddOusE6ht4+kN3xWML8QLWVOhsenVdPfiXZr+Kj5KKmoNL0VTMw66qat2mmtzAAiYpJiBdNg0gkbacXllppYMpuTZyjzMhjygGgpusEBoP6cXsBlRSwRAHo8HrXWq6OhQrScBdPkeB+l0rKiRUuZk+TNvyELmC3WKfT2YXYrmLLqGss+RHtHpnBCsV6a7jbnxIrUUAqi6iKtV+s1YwVjzuA1OtpaM4tnE59Xbsna0IXAAaD+7FnAZUUsEQB2NNND1GW/CT1uc55EXIvC8GcUK5jVoqXMSU44pddLjpvzJOJaZCacMrUVTFo8+ah1BT8oWsqCkWUZq+2PKFYw5qsB83plrFT09eSbT9/1iNrjs4IxZ/r61C7aXDWuNW8N6NUoaxtSG9uw23qHBvOBA0DGXywRAF5KpYdoa5A5H/LXI32jYgWz/VeipcxJnYMeonUZ1pj1ORuzW8HE7Y+gU55V1nuIIiJmLCcrmKozEaKlvIX2wQnVHN5t0hPKa3Hh/BmlgcWcacqo1VReUbfb3JN25mLM6caSZVR7O1Fivc3BfOAAkPEXSwSA2cfoIVqywvyD6eci/VAYjbBb9ZxoKW9hwjmtptdH2q33EB2ZNLcVTMIG6kYsNfm4uqsRu/6XprWCybs0u0ZtWrScBZNTWmVqK5ikIGqwajlnbhP7q3HBQZmNzgC1guEA0FiKAaBojqsQADIBYB8APCVM3eKwRACYtZl2ojlbrPkQzU88oVjBfEC0lLdQU0OF/i6TnqDNBzNbwWSF0kO0MtKiD9F9Eaa1gok/R/+uukPM26V8LdoGZqxg3F3mSlM63R6sXEaTYIZLzFm7fD2Or6TNS/Mec9ZY+gsHgMYSBgDDAJAOAGuUK0352HoAiAcALwC8IErgIrBEAFi0gsap5R4zXxpqPjTU0kmFU7oFZa9HtJzLyEmgbrk2E/sUXg+zWsHIsox1dpoF3Z53VrScRZEcd0axgjFfDeO53XSyXrvmWdFSFoXXK2OZ/UNkBZNnrvKLuu4RtQFI7jPfyfp8OLSDaizb1lrP3WA+cABoLNsAYNkcH/8XAOxU/hwEAAWGKfIfSwSAzQ56iJanWXOsz5TTidP2m8hQtbNBtJzLSDmwnIInE6an54tZrWB6hydUCyBnr7l+7vOlpKLKtGnWC2t+Sqeru809ZvFaJIV8hXwMI83VgJWaXzLzczepBdD1OBFJs8KHQqznbzofOAA0lmEAeGCOjz8AACPKnx8CmhNsFUwfALpdLpxWHqI9rTWi5SyaZpNawaRu+Al1KO/8jWgpi8asVjAlpZfIQkW6GdFkJ7/zpW90Sm20cHaZyww4PYS66+uj14qWsmii19Ks3eqd5rJgio48Ru+5odZsvENEjJ1tBTNtrQlH84EDQGPpAYCX5vj4S8rnAGhCSJ9hivzH9AFgWwPVqDntt6DXY82HKCJiQfgXFSsYc6UpC5Z/nhpUIteLlrJozGoFkxJzhFJQIY+IlrJoZFnGKp8VTK55uindHi/W2mlT1VscI1rOoona67OCMVea8tTOUNK1zrwzzK9HWfswDtnvogCwq0y0HM3hANBY/gUAkwCwAQB+qFwbAGACaEYwAMBrAJAgRN3iMH0AWJxMNWrNQdatUUNETNtMO/38rT8TLeUyWqT3UANFfqxoKYumsto3seImU6Wr4nYH08nk2q+IluIX6cvJbLn6jHm6KVt6R9X0ure/UbScRRN7IdKUs4yjV1F6vXbvr0VLWTTjTjcWL/swOQQUm3Pcnj9wAGg8PwCAbAAYVK5sAPj+rM//HwD4LwG6FovpA8CsI1ToXRxh3Ro1RMT0Y2sRJRtWmGjc2tDoGHrsN5BX1kCbaDmLZmzKpY5bG201TzflxbWvkAXM7t+JluIXsRuom7Jih3m6KbMLiyyfXkdEzCurMuXEipSgL5BzwXnrptcRES8EfZVO4c9aa4b8fOAAkPEX8weAG6lGLWebOU2U50txZix1UzruFy1FpeJSHu2OpdsRZVm0HL+ocNBOvz7tiGgpKnkhT5KJcsxG0VL84vyBNfS9XfmkaCkqcVEHKS0daj5rpYXQPjiBIz4rmE5zpCnHnG6sXUbp9fFy62YGEBFPrqExlw27XhEtRXM4ABTDfwDA2wHgnVdcVsT0AWDp8icodXp6g2gpftHZ2a7u9F2To6LlICJiVsw+GvUU+hHRUvwmPeIbVMt4ZJloKYhIFh8t9gdoDNylBNFy/CL54nlEyYaDQfeKlqJydoeDmqrWf1W0FL/wemW8ZKfNS0/2MdFyEBHxUksvuhTXAhxqFS3HL07sps1Ly+onREvRHA4AjeU9QB6A3isuWfmvFTF9ANgt3Udv9PmJoqX4hdcrY7/97TTSriJbtBxEREzZ/S+yT1n3DdFS/CZx218o3brxu6KlICJie/+wml53D3WIluMXFY1tM2nKySHRchARMXblD6kucf8fREvxm/jQr9Mp1QlzbF7iUlIRJRtOOayfGYi5EE1m1sH3ipaiORwAGksmAKQCwHMA8CgAfOiKy4qYOgAcHhpQHzyjQ32i5fhNechjFKRc2CVaCiIipq/9HnUm7/2LaCl+k3J6Jz1Ewz4hWgoiIublZVJtpXSH5R+iE9Nu7LTTRmykJkO0HEREzHN8mk52Lu4ULcVvzmykzUvdlu+IloKIiKcPbSXz8hUfFy3Fb7Irm2Y2LxMDouVoCgeAxjIB5PMXSJg6AKzMT0KUbNgnvVO0FE3IVAKu/D1/Fi0FEREvBX+KDLYv7BAtxW+K8rMQJRuOSXeaIuBKOLGN0usmCUj9JS/osxRgx20TLQWHJ1zYY38nBdiNOaLl+E3U0R0UcIV/VLQUREQ8s+GPFJBu+55oKX7TPTKFbfb7qWGo0RybF63gANBY8gHgM6JFaIypA8DcU29QgBL2WdFSNCF1j506mtd8XbQUdHu8OGC/h2rUqsyRkvaH7oFhdNtvJM/IQfEdzfGb6SFatvn7oqVoQvyqH1En8F7xKdfimoaZUx2nOepp/SEpM0sZFXmrKTqa40Oep83LaYdoKX4jyzKm2T9HDXhJW0XL0RQOAI3l8wCQBQBPAsAtQN/02ZcVMXUAmLXt1zQDeNOPRUvRhNzYQ/TGGvKoaCnY1NxEHmr2G9DrHBctx29kWcYm+4NUY1lwQbQcTA8j+4nyEyGipWhCzJvkaVizVrwdU2Iseef1mcw7b7HUdA6i034Lzd0dEOtp6PJ4sXQZzSceyD8pVItWRIa/RF6nB6xtx3QlHAAaiwwzDR/cBGIARSueJQuYo+YxoPWHuiqarzkl3YKy4J1+7sUzZKMR9KBQHVqSu5xGg5WdWS1UhyzLWCs9TMFojnmmZ/hD4vkTdIoS8pBoKRi9O5xSlGu+IFqKJky7vVi1jH5fBovOCtVS1z2CE8roP7m3WqgWrTi6NYTqRdeba1Skv3AAaCxPXOeyIqYOANscdKJTni72TVErppxOdaff3yp2rmrKfnpTLFsl/kRHK5Le+AV1NW8TO22lZ2gMpxUbDWefdadUzKaoohpRsqFHuhHRNSVUy4XVP6YJK3usO6XiSpJCaNpKQ2SYUB3JOQWmnKrjDyfP0DSpwZDAODH2wQGgefiAaAGLxLQB4NTkuGqj0d/ZIlqOZtQGUXql4uJhoTrS1pKNRuGb4mu6tOLiYfL8qokQa1hcWJCLKNlwUroN0esVqkUrBsecOGK/kxovWi8J1ZIT9AQFSxc2CdWhJWfX/45+d7e/JFbHSfIG7Vr+QaE6tCShsHqmZnTKfM+6xcIBoFj+GwB+DgB5wClgzakvyyHbCelOlAPkIYqImL3qReoE3vc3oTpKA6gD2EdOejzt9B1iu8YvniJLmqYw69tozOaS9DFEyYbNKfuFaZiYdmO7/V3k7VaVIkyH1pw9uJHSlBGfEqrjzOa/U3p9o/hGNa1o7BvHbqVr3NOSJ1qOZnAAKIbPAcA+ABgHgFoAWAEAHxeqaPGYNgDMi6aHaHVoYNho+EhVzJeL17wgTIPb7cFB+92006/OFaZDa9q6+9CrnBq7hruE6Yjf+idKr28yhym1ViSu+A6lXg/+rzANFY0zE3UCydftYmoyjV5z3CXUxuj88m/R6epRsRtULfF4ZcyyP07TVlLN4cGqBRwAGsedAPA3AKgDgB4A2AgAbgB4v0hRGmDaADBzO6VE8jb8QLQUTcmNP0Y7/eCHhWloaiIbDY/9BvQ6J4Tp0JrLOoHzY4TpSA8nG43yY9a30ZhNzE6yMapZ92VhGhITaSzdkInG0mlBRWuPOn5NFjR+bdrtxZJlNJauP0dsiYrWRIf/AFGyYf3B10RL0QwOAI0hGgBGAOAwAHwFAP5d+TgHgDpSHE4dnbkB0gHso6mxhoqs7TeiZ1pMMX1u4imlA1h8R6fWZIVRMX3ZiVAh68uyjDXSI5QqzQwMGw0fCRfo96Y3+D3CNJxVOoAbVj8lTIMeTLk8WO3rBC6OEqKhqmMQJ+23BlQHsI9T24PIgmvds6KlaAYHgMbgAYC1QLOAZ+NPAPg5oMCyE+gH+PUrPv82AAgGgC4AmAKAxDnW/y8A2AwAA0Dp6FMAcMcCdZg2yoa6jAAAIABJREFUAOyWqM6nKjdOtBRN8Xi8OGy/i5z/q8SkX1P2kadb6WpxJzl6kbj1j8pMYDFTDDoHRtBpv5k6gHvqhWjQi9K6ZjX9KguaCazOAN77WyHr60l8KJ0cN5ySxKyfmqYYUt9mCkNqLTl7jrwjh4LfJVqKZnAAaAyPAcBOABgFgFwA+C0A3Ar+BYDPAUAoAHwD5g4AXweAYQB4AQA+CABRANAIFPT52AoArUAG1R8FgGygecULwZQB4EBvl/qgGRsJnDofH2Uh1IBRck7MWK30Nd+lDuDdfxSyvp4kR75JDRjLxYzVyslMVkbSia3l0oPJaQ92KA0Yg5XJhq8vyzIWSp+kFH/Sm4avrzdnNv1VacD4hpD1T++nyUttEZ8Usr6eZFe1qPXBONYjWo4mcABoLP8XAH4CABkA4ALq/P0DUDewP1wZAL4N6OTvL7M+dgMAOAHgu7P+3wUA35r1moeUez22gLVNGQCWpZ+lFKVDXKpJTzLWkzN9/g4xpxhVQVTnU5UorptTL0ovFSmnGLcgetyGrx9/aC09xCM+Z/jaRpAV/DSiZMPa6DWGr901NIGj9jvo59teavj6ehN9+iCZbYe+X8j6UWvIR7Nu5ytC1teTgfFprF9G9cGTlfGi5WgCB4DieBAAVsJMivasH/e6MgC8X/nYo1e8LhUANih//rzymhuveE0LALx2jbX+Ey4fX3cPmDAAzDpIKcrilYFjUjyb9MMrqE4twvhJBiPjE2qKcqSjxvD19WZk0onjyiSDkdYyw9dPXPsK/Wx3/dLwtY3gwoZfkY/lduODhKz8fETJhtPSzQFjUjybrEtVNJ5RugFx2vjxjOmOp+h09cI6w9c2gjgH1Qe3Ry8XLUUTOAAUz78DBW9aBoCPKx+764rXHQeAY8qfvw8A03PcKw8AIq6xlkO592WX2QLAnHX/QyPgdv1ZtBRdKM64QMX0jvsMX/tSfjqiZMNR6c6AS1H6KHeQX13NxX2Gr10cROn92lgx6X29iT26mVLs4canCc8f204BStjHDF/bCHpHndij+NVNNmQZunb/mBM77PfR2nVphq5tFMfWvka/u9v+R7QUTeAAMDAwMgC0xAlgbTClKItjjX+AG0H/QL865WSsz1jLh5SjlKKsDv+soesaSeoqqnEs2Wus5cPIpBNHlBTlSFORoWsbRXZupjLP2vgpJzEbfkM+hNt+ZOi6RpLpeII6yGPfMHTdnPK6WdMyhg1d2yiOHKL64N6wR0RL0QQOAAMDI1PAV2K6GkCXa1qdl9vRUCFajm40OMjyoTLlmKHrpq1/mRpAtv/K0HWNJGHfcgpyVz5t6LrFJYUBnaJEROwcHMUp5d+ns8tYq5BMpf6w7uwqQ9c1knNrXqXf3V0/NXTd6EjyJ+0Lea+h6xpJbM4loSl2reEAMDC4WhPIn2d9zAZzN4G8OOs1D0IANIHUKSPgxux3oBxgVgSzyVr9bWoE2WNsmrs8+BNUo3Y+cEbAXUluRqIyRvBuQ9PcF09RirJZUAeyEciyjJekj5KZefIew9adnPZgu/1+pQM5ybB1jebsgfVCRsKd3PQ3sqB542uGrmskzf3jaord1Wz9CUgcAFqX/wd0wvco0A/wNeXP71Q+/zoADAHA8wDwCABEwtw2MC0A8BSQDUyWci0E0wWA2SdW0xSFsMBNUSIiph0IVRpBnjFszSnntNog0dtQYti6RtM7NKqeIo91GndKlbCRUpSlmwM3RYmIGLuKutgr3zSu0aWwsn4mRSnIg9AIkjIylC72WxHd04atmxD8Zdq8nAkybE2jkWUZ06XPkdVN/EbRcvyGA0Dr8iTM0YwBAHuVz/uMoLuBTv4SAeC9V9zDZwQ9CAATAHAaaGTdQjBdAJiz7nuIkg2zd/xetBRdKclOoNMM6e2GnVJVluYr9Vu3oizAIsVI1EaQBOP84nJDqIuyInK1YWuKIObQBgoWwh8zbs1TexElG3YJskgxiua+MRxSjOKdzfmGrNk35sTWZe+mWcRViYasKQrV6mbHS6Kl+A0HgIy/mC4AbAyiMVol8QdFS9GV4ZERdfbnUGeDIWumn9xEHarLjXtwiyJ57cv0e7TTmFOqkUmn+uAerM02ZE1RZOXnzdQ6GnRKdW79r6k2bmtgzQa/EjqleoLSwOfXGrJmWnH5TG3clHmeBXpw+shO8lpc/gHRUvyGA0DGX0wVAI4MD6hu7f3dLaLl6E5t0IcoDZxgTLdz2jpK3RVt/7kh64kk6SjVUtWFP27Ienl5WerpaqA2gPgYHHPigP1ushOqzzFkzVzHp2mW6wVju2NFcGbd72ijtuW7xqx3ZAeiZMPOsA8Zsp5IUooqZ0oJJqw9ZYoDQMZfTBUAlqZF0RuR492ipRhC5trvUyPITmPS3bWOD1LtVgBOALmSkqLcWQGZ/unu+AMrKeBcEdi1qz6ygyndXXtW/3R35+AYjtlvJ4+61mLd1xPN2VP7ECUb9oS+z5D1otb8nH6WO142ZD2R9IxOYcOy99LvUvl53dfrHJ7Exr5xlHUo8+EAkPEXUwWAWXv+ThYlq18QLcUQ0o6sopFsYZ/Rfa3unh7Ve3C8v0339UQzPjWtjg3rry/Qfb2UldTVXbo38OYrz8WFjX+gzcQm/U1109KTESUbTkh3IAawM4CPvMqGmVOq8X5d15JlGXOkx6kxImGLrmuZhXNBL9Df9+Q/dF9r09kM/NjrB3FZpPZTiTgAZPzFVAFg0YpnaQLIwcDtRJtNdZmvKeMW9ExP6rpWTjz5fHUGBa7P15UUhXyWOsp1bsrwemVskN5HjRGZJ3RdyywkRB2g36cQ/ZsyYnaTr2P9qqd0X8sMTEy7sc7+EG1eiqJ0XauxZ0Q9XXV1BN585bk4tFmiiTLr9B/FeXwljU6s3vs7ze/NASDjL6YJAGWvF/uld9CJWG6CaDmG4HZ7sM9Of+eG/Dhd10rZSic2xeu/o+s6ZiJh658oAFz/dV3XqWtuUU9s3KO9uq5lFsrrmtS/s3ekW9e1Loa/SKeNB/+i6zpmIj7sm5SWPfy/uq4Tm0iemZOOpXG6iogYFRtnyN/Z6fZgvv3jZLuVrP1oSA4AGX8xTQDYUEGdhZP2W9E5ZX2X9vmSG/FVqgPc97qu65Qop2ElZwJz0PtcZF6Mpi5rxzt0tdpJiabTsI5gY2q2zIDL48UqO3Xst6bpV1M6Oe3BBvuDZAGTd0a3dcxG5C469Wxa9Tld1zm1+Z90cr1W/9Mws1DdMaSWh7ja9fNDLahtw2nF6UHu197pgQNAxl9MEwBmHSJj5NLwJ0VLMZS0g/RGX7FCv7/3+MQkTigG0D31gTmjdi76h0Zw0n4rBYGN+jUPJGz4JXVzb/qebmuYkdg1P6GTue0v67ZGdjGN7/JIN6I8MajbOmYjMZMmIrmkmxGdY7qsIcsypjhovF5zZKgua5gRWZYxS6INccs5/cYKRp3cT2n8kAd02YByAMj4i2kCQF/9X/a+f4mWYiiVJfRGPyndil6XU5c1CjPjZ0ajeb26rGFWCkPI+b/8dIQu9/d6ZayUHqUO4PjAHa83F7GnyZy5O+Qh3daI3kvd1c0rAt+7cjYD49PYYidz5qGSc7qsUdc1hCPKSZizRf9GKTNxauP/0gnr+ud0W+PMyp/R+8L2H+pyfw4AGX8xRQDocs10bNYVpwrVYjQutwcH7PeQx1nhRV3WSN72R0TJhpfWPK/L/c1M4nZ6oy9fq8+M06r6mRFl00OduqxhVqqb29Ftv5H+7n1NuqyRvPxrVER/6K+63N/MXAijzvLafdo3ECAinj9PtltjjruXTP2fj7NxVAc45bgN0a39xnvM6caSZR9GlGzYl75H8/sjcgDI+I8pAsCqvETlhOou9LoDe0TZXOStoDmcBfv+rsv9K4M+Sun1s9aff7lQslPPK79b9+hy+pl49A1KJYV+WPN7mx2vV8YSiUbu1cdt1fz+A2NT2Gd/O52CVaZofn+zE3lwI9WWhunzuxW1gRrD6jbq2yRlRmq7RrBXacCbrkvW/P5JxXWq7RYO62O7xQEg4y+mCAAzd79OEypWfkWoDlGkHVZMhJd/QvN7t7e1qNNVRnsDf7rKlQyPTqg2F33VWZrfPy3iGxRc7wns2dVX48KGXyt+gNp3l6emJsz4/wX4dJW5yC2vUU+X5VFtO629XhnzpE9Rej12g6b3tgKyLGOMgxrwWo9pf7p8cO8Wes8Je1jze/vgAJDxF1MEgBWhZESac2yFUB2iaGmeMX4d6dV2t5h+ajPVuoQ8qul9rURm2HMUpO37s6b3nXBOq6cIHUUXNL23Vbh4/iSiZMNhx9s1n7gSs/WviJINa9bqV6dlZpxuD1bYaXpPR+peTe9dWNuKTvvN1GjSU6Ppva3CkR0R9L1d8XHN7x0dQjY+rfv1m0XOASDjL8IDwN7OmROqrpal+UaEiFgZRKm0Yo1tWrJX0glVwa6leUKFiJh4dAO9GYc8oul9c7OSlBOq21F2TWl6b6vQPTSmzgUeKNPOv9PjlbFAeoxOxs/q16lpds4qY9rqN31T0/ue2kezsntD36erRZKZSSssnXXC2qXZfZt7R7BfqeuerE7U7L5XwgEg4y/CA8DsY7QLqwn5mDANZiB1F512lK58VrN7Tk451QYTvY2mzUxzWzu6FD+ukbZKze4bt+n3ZFy+ZmmeUPlIDP8WpYF3varZPfNKy9WNoWtg6ZUu+IiJO69MC7oNcVobf1RZljEpiFwX6nU2mjYzUy4PXrJ/BFGyYXucdmnwqDM0dWnUcY+upQscADL+IjwALF1ONh3Z+5cJ02AGKoqz6I3efgtOT4xqcs/sOHojGpLuQa9rWpN7WhWfHUzpUW3GDE5Nu7HZTkPl6xN3a3JPqxJ3huxgBoLepVmjTfSOZVS6EPG4JvezKgNjTmy2P0AenlmHNblneVOn6o851VKoyT2tyvGNVH/etvqzmt0zMuwH9L6w40ea3XMuOABk/EVoANjfM2Mj0dGo3cmMFfF6vNgm0Rt9WdweTe6ZtZLqUAq3/EST+1mZxL0h9KYcpo2fXFZavHIycyt6p7QJ2K1KR9/MZIWB6jS/7+fxylgi0Qit2ih9/ButRPSaV5Vu3W9ocr+zhzZR+jfkwSWb/vVxPjNfTQNr0a1b1z2KHfb7yF6n5KwGCq8OB4CMvwgNAHNOrKE3tuClZ6ExF6lbfkuedRFP+32vwcEBdfpHa0my/+IsTnVttZpS1CINnLj+p/Sz2vCiBuqsT2oY+fVV7v613/cquES1WV7pBnQNtWugztrEJ1xQNxv+poFlWcbkEGqKqj34mkYKrcvwhAvzln0CUbJh53n/a00Pnzyh+AvejqhzXTAHgIy/CA0AK0OpyDt77z+FrG826qpo7JXXfgMOdNT7dS9f929HEO/yEenBlxfyFBli7/bPWHd80ond9nvJvDv9uDYCLU7s6T1K3dPdKE9P+HWvc1soLVcfoV1azsoMj09ji5IG7kze6de9iqob0Gm/hZqXmvI0Umhtjm22UxrYz25gWZYxOuRF8gXdqc/0j9lwAMj4i7AAsKmyAFGyodt+I/Z1NBu+vlkpCaUZlQV7/fOmKlr+JN1nz9It8r6S5Mg9VBPpeLtfXbtJ0QfV0XpLtfv3SgZHJ7HNfj8FxQmLH4k3MulUaysb4zZpqNDanNrwZ2pWCP+YXxu6M1v/NWMuzRtDRETMK69RLXEmGhbvFVpQ26p6jk7W6m9czgEg4y/CAsDsjS+T7UnElwxf28xkniYD0W7Hu1FepK9adVm+epLY31qlsULrMjY5hV1KfU5N4uJ81WafJJa+6X+6M5CI2fIXatwI/+Si7xEXRcH1uHQnys4xDdVZm4KKOpxSTu5GFlln2Tc6ifX2h+iE6vxajRVaF1mW8ULI18kUe+u3F32fY5souO5d/rAhwTUHgIy/CAkAh/q61C60svQoQ9c2O2PjYzik+KqVxy8uSElfS11oZauWtj3JXCRuUcZfhT++qDfpwrzMGdPudg6uZ1NZ16CepAzULvwkxe3xYl4QnYBXvqmfga4VkWUZY8PIbqd207cWdY+oY29Sc4LjLpSnxJr/m41TMVRn6ZFuRO/gwm2HWvtGsUk5ue6Mf0MHhW+FA0DGX4QEgFk7/qA2f8g6zGe1OqnbXiPvvpBHUV7gkPam+mr1IdyQH6uTQutSV1+j1kC1FS5seocsy5ge/gKiZMOKdc/rpNDaJIeT8XjNuq8u+GuTEmOoLES6Eaf6mjTXZnUSkxPU74+zu3ZBXzsyOY2XJJoJXnvgj/oItDDDEy7Msn+aTrAPLtw0/9ibq6gGNugeRINOrjkAZPzF8ACwr6sFx5Xu1KK4A4atayV6ujtwTLHVKL2wa0Ffm7Hmu2ROHM4F9Fcjec2PKEAO++SCTgHzspLUTuKemlwdFVqX7Nws9Cjfo/6q9Hl/ndPlxsIgGglZteX7Oiq0LtNuL2Y5nqAgbvPCZi9HHt5GtWnSbegZ0XaucKBw/MhuRMmG09It6B6Yf116Q1c/NtvfQ44LUSE6KrwcDgAZfzE8AMxfQ11S1SEf59O/a5Cy869KLeD9ODU2NK+vuZRzUQ1Qmoou6qzQutQ31KmbkOrY7fP6GqfLhZeCH2Prl+sgyzJeDKd/481hH0ec5wl2zBGqfXVKt+BULzeFXY2Ei/FqCcJARdK8vqatuw9blS7iuiU8+eN6DI07MV8ZP9i0ZX5pdlmW8cS6P1JzWfB9iE7jPEE5AGT8xdAAsDjhiNqcUFukf5eUlRkZHcZ2xRi6cNPL13392PgYNjoepsaa9YsvZF4qJGz/q9rJO9p7/ZqfhD1B6gnKSGeDAQqtS2VtnWoMXX3i+pNXahsbsNf+Dnr94dcNUGhdPF4ZL4R/B1GyYVfI+1C+TsDh8coYE/ESncgG33/d1y91ouMuqMMJenOOXff1cUlJaklJd9oe/QXOggNAxl8MCwBba0twSKLmhuwtv9B9vUCgIOm0utu/FL35qq/zeryYtYpOXfqld+LYQKeBKq3J2MQkVgV9mE5Fwh5Dz/TkVV+bkxKj1lVWnFlpoErrcm4vzfh2STdh+zVqLQeHR7EomGqv2kMfYVudeVDT3IKdSjd73aZvXnP8XuSBN9T3kJ78SANVWhOvV8bTK19VO9En2suv+trKxmZsULqqmzY8Z7itDgeAjL8YEgA2Vxdjl/RuKg4P+Rg6p/wzil1KpG79veqXWBLz1nTl9PQ0Zqz/kfqamix9xw8FEhVlRThsv4vqzlY+jc7xwbe8Ji/lHI7Y76TU79qvaTbrNtCZdnkwJewF5UF6B7YWnH/La/oGBjBn+TPkvybdjkPNpQKUWpPY86fRZb+J3lO3/RBl9+WzvmVZxnNHtqgbl9r9C29sWKp09I9gkUTTQQaC3oUjTUVveU1lXT2WSR9BlGzYF/xuIXWVHAAy/qJLADgxNoR9nc3YXFWAWbv/OjOSzPEQ9ne3arpWoON2uzF79bfUXXzh2hexJi8eu1rrMD/2AFYHf1RNqxdHGmM/EEjkXIxUfz87He/B4rObsLu5GquL0jFt46vqQ7Y2/HF0TbJ1xkIYGB7BwuDPkL2G/QYs3vZTbCnLwPaGSkw/uRGbpQeVovubsa0gRrRcSyHLMkbuX6823LQs/zBWJ+7H7pYaLMqMw9QV31TfM2o3vTjvWkyGKK1twFqJSmqmpFuxbP9fsKu2EOurS/4/e+8d3sZ1pf+/8f52k/w2C9uxHRfZcY9b7HSnbeI4m8SJs3Gc7k2zk12nrFM3xWnCgEWURHWrWl2yei+UKIm9i1XspCj23nsBQWDO948zBCmKpAhMw4D38zzzCARm7n0FUcCZe895D13YEepNWeh13E39tfmmaBQBoEAtugSA6Vv/z/vhM34UL/oMdbc3aTrPfMHlclHyhte8BR5Tj37pdiq6sMtsmZYlNy2GmqUHpn1vSbJR4apv0OiQCP78obu3j5KWfmvG97bTcR81FsytmEFwNbIs07ljO6hHWcWe7ijd8ZoI/vykvKqWMkM/O+N72xj+FPU3lJimTwSAArXoEwBu+xO57TfSkP02Kl70aco+tYk8bvEhpJbSnATKWvZ16pTuIZf9Zmp0vI8yN/6CulpE1aRaOrs6KWnr61QZ8iQ57bdQn3QnFS79Il1OOSpaZqlElmVKu3CEshd/iXrtd9Ko/d1UG/ok5e16fdptd4FvVNfUUPzaX1Ct9CiN2m+mLuluKlj5IjUXJZktzfIMO8fowuGNlBf2GRqw307D9lupctHHqPR4JMmumfOGjUAEgAK16BIACnsXgUAgEAj0QwSAArWY1gtYIBAIBAKBf4gAUKAWEQAKBAKBQGAxRAAoUIsIAAUCgUAgsBgiABSoRQSAAoFAIBBYDBEACtQiAkCBQCAQCCyGCAAFarEBoIaGBurr6xOHOMQhDnGIQxwWOBoaGkQAKFDFAvAvkDjEIQ5xiEMc4rDesQACgR+8DfzLY9PhGA8u9RpfHOJ9Fu9z8B3ifRbvczAder/PC8Df4wJBQGED/+LbzBYS5Ij32RjE+2wM4n02BvE+G4N4nwXzEvGLbwzifTYG8T4bg3ifjUG8z8Yg3mfBvET84huDeJ+NQbzPxiDeZ2MQ77MxiPdZMC95OwCH8qdAP8T7bAzifTYG8T4bg3ifjUG8zwKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAkvwGoBaAE4AmQCeNlVN8PFXANkABgC0AzgB4BFTFc0P/gKu6FtttpAgZQGAPQC6AIwAKALwUVMVBR//BCAMQA34Pa4CsBDCTFgtnwVwGkAz+DPixSmvvw1AKIAW8PseC+BhIwUKBEbwPQCjAH4C4HEAmwH0AHiPmaKCjHMAXgHwBIAPADgDoA7Av5qoKdj5GPhLswAiANSDm8E3jTvAN4z3A/gSgAdN1BSM/A1AJ4CvArgPwLfBN5K/MVFTMPAVAOEAvoHpA8DXAfQC+DqApwCcBFAN4B0GahQIdCcTwLpJP98AoAm8eiLQh9vAHzqfNVtIkPIuABUAvgAgESIA1IMlAFLMFjEPiAKwbcpzR8ErrwJtmBoAvg288vfHSc/dCN4he8lAXQKBrvwLADeuvfvZBb7jEejDQ+APnfebLSRI2QVglfI4ESIA1INS8Ht8GJzWcAnAq6YqCk7+Bl5pfZ/y8wcAtAH4gVmCgpCpAeADynMfnHJeEoA1RokSCPTmLvAv+ienPB8JXhkUaM8N4Lv6VLOFBCkvgXPRxrdqEiECQD1wKkcEgA8B+Bk4V+plM0UFITeAV1tlAGPKn381VVHwMTUA/JTy3J1TzjsE4KBRogQCvREBoPFsBN/R322yjmDkHvDqyFOTnkuECAD1wAUgfcpzbwDIMEFLMPMSgAblzycB/AhcdCMCbe0QAaBgXiK2gI1lHfjD/H6zhQQpL4I/uN2TDgKvmrjBFZUCbagDsHXKc78E5w8LtKMBwK+mPPcPAOUmaAlWxBawYN6SCWDtpJ9vANAIUQSiJW8DB39NEFYCevJv4LzKyUc2gLcg8i21Zh+uLQJZhWtXBQXq6ALwiynP/RVc5CTQhpmKQP4w6TkbRBGIIAj5HvgX+2UAjwF4E2wDc7uZooKMDWBLgWcA3DHpeKeZouYJiRBbwHrwMXBO2t/ARU3fBzAEUZygNTvBN+TjNjDfANABYKl5koKCd4FX+D4IDgB/rzx+r/L66+DvwRfAW+8nIGxgBEHKr8BbOqPgFcGPmysn6KAZjldM1DRfSIQIAPXiP8EFN04AZRBVwHrwb+Df3zpMGEGHg9N3BP7zOUz/mbxTeX3cCLoV/Psdi4lKbIFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAoFAIBAIBAKBQCAQCAQCgUAgEAgEAkEA8jYACwDYxCEOcYhDHOIQh6WOBeDvcYHAZxYAIHGIQxziEIc4xGHJYwEEAj+wAaCGhgbq6+sThzjEIQ5xiEMcFjgaGhrGA0CbyXGEwKLYAFBfXx8JBAKBQCCwBn19fSIAFKhCBIACgUAgEFgMEQAK1CICQIFAIBAILIYIAAVqEQGgQCAQCAQWQwSAArVYLgDs7R+g0VGX2TKCkt6BEeobGDBbRlAiyzLV1tWS2+0xW0pQMjg0RN2dbWbLCErG3B7q7rXOd8R8QQSAArVYJgD0uD2UvOYVcttvpDbpXirKOG+2pKAiK+U8tdjvI4/9Rrr4xo9J9ohARSvaOrsoJeJrRJKNakOeoMaybLMlBRVRe9dSp30BjdpvpsL9diJZNltS0FBWXUeXHB8nkmx0JeIT5OxpNluSQEEEgAK1WCYATN4lEUk279Fvv506WhvMlhUUNDbWU6/9zqve35y9DrNlBQ3nV/70qve2PvQJ8jiHzJYVFCSlp9GI/Zar3t/atMNmywoKBkdclOx49qr3tibyMyLADhBEAChQiyUCwP6+Huqx30Uk2Shv9+tUGfpBIslG6Rt/aba0oCBu7f8SSTaqC3uKMna8TiTZqE+6k5xDvWZLszx5+Xk0ar+ZSLJR8YmV1GG/h0iyUeGRxWZLszyyLFNy2Jc4MFn+OYpf9QqRZKOWsEeJPG6z5VmeEyePEEk2GpXeTbkn13kD7c6Cs2ZLE5AIAAXqsUQAmLp/CZFkoybH+8gzNkYFcQeIJBsN2W+joQERpKihu6eXBuy3E0k2qkw+QC6Xi+qlRzjYPrzEbHmW5/yaXxJJNqpY9nkiIordFU4k2agx7AmxkqKSi/lFNGa/iUiy0WB9IdU1t1K3cqPYkhNltjxL4/bIFOt4jkiyUdXWV4iI6HTky0SSjapXfMFccQIiEgGgQD2WCABLwzgHJXt/GBERyR4PNToe5udjlA55AAAgAElEQVSitpqsztokndhCJNmoLeRBIiXvL+mtMA5awp82WZ216R0YoWb7fbwtmbyHiIiaWtto0H4bBymFCeYKtDin1v4fv7eR/+59LmbZD4kkG5Wt+46JyqxPVlm1d+Xa1VhARERJGRlEko3c0k0k97earFAgAkCBWgI+AGxqqPbmn3Q113ifT3/z17xKFfm8eeKCgPTFXyWSbHRp66+8z9XXVZPHfiORZKPe1hrzxFmc5JgTnK8q3Umya3ji+SXfIJJslL/tV7NcLZiN0TEPFdo/xNu/F9Z7n4+PPUsk2WhEupXINWKiQmtzaNtyIslGrRFPep8bcbmpQHnPG86tNlGdgEgEgAL1BHwAmKZs/16eshpVWZBGJNlo2H4rOUdEQr0/9A0O0oD9PbwaVZp21WvFobzqeklsA/vN+PZvyRtXr0bFHtmkbAM/bpIy65NRUOy9MXT3tXif7x8epRZl1bU1V2wD+4MsyxTnUHIrD75+1WtH1/6Z00VWPmeSOsE4IgD0nW4fjy4A95qi1BgCPgDMXfJlIslGmbv+etXzssdDHdJ7Obk+9bRJ6qxNZsIpIslG3Y57vNu/4yRt/xuRZKOiSPFB7w9uj0xl0lOcQxV7dZpCTVOLd3utv7ncJIXW5tT2xVxRveTj17wWu+S7RJKNSreLIjF/uNLSTX1KXrCzJvOq12ITE5QV1tvECqvJiADQd2QAvwHw8hyOVwAMA3jADKEGEdABoMvloj77HXzHmZd4zetZK75FJNkoY/OvTVBnfeI38DZ6wepvXfNaQWYikWSjAel2kt3CeNtXii9XeFeoxvquzZfKD/kEByln1pmgzvrEL2Jfxcv7Xr/mtTMHeYW1Ofz9JiizPqfOnOTCGsed11RTt/UOU6udb7wHSmNMUiggEgGgP8gA3uPD+QMQAaBplGTHKzlUd5Bn7NogJPP4Ov4SCPuoCeqsT3Ho07yCGrX+mtdGnKPUo3gD1hckGC/O4lw4vJHfu/APTvt67NrX2A5m3X8ZrMz6dA84qcV+L5Fko57i2GteL6yYyBv2DHQYL9DiHFnNxTXVb7ww7evnw7/ON+X7/miwMsFkRAAoUEtAB4BpuxbyCtXS6bchm2rKuUrNfjONDIkWZr7QPzjk9fXqqi+d9pzMxV8hkmyUu+cfBquzPrErfsxb6Ftenfb1xKg9vEoV+qjByqxPUnq615+OJhXXjONye6jS/ihbR2UeNUGhdfF4ZEqVPsOFHmdXTHvO8a2LOEBc9jmD1QkmIwJAgVoCOgDMjuRtnou7/j7t65PzAMsuRhusztrkZyV6DZ9n8qNL3GHnAHyZqLT2BY9HpjLpSU6iT9oz7TnVDY3eSmtnT5PBCq1N1M6lHIBEfmbGc2KXfIe32Hf/3kBl1udKa5/XS9FVlzPtOXFJCRN5gO4xYwUKvIgAUB0vA/jqpJ8jAfQCSIf+hR8O8D/c5KN80utvAxAKoAXACIBYAA9PGeMdANaDC1UGARwFcLuPOgI6AGySHuIqytSTM56Tu/R5DhJ3i1UqX0jcy9XVpUs/P+M5OSnR7PzvuFeYFvtAZUOzN7hzzRDcybJM5UqRSGXi9EGiYHouLH2Jf3d3/XbGc87s4iCxaunMQaLgWk7Fp/LvrXQL0djotOfUdw54c7NH63MNVigYRwSA6rgM4PPK408CGALwMwCnABzTeW4HgGIAd0w6bp30+uvgYPTrAJ4CcBJANTjoG2cjgHrw3+EjADIApPmoI2ADwPaWBm8ez0Bv54znpe+2K36AXzFQnfVJXcFfornbfzfjOd09vd5q1d6mSgPVWZuk89xCqz3koVnPi1vxI84D3PJzg5RZH49HpmL7B3iLMnXfjOelZvA2sVO6dcZARnAtb21h/7/mZZ+c8RxZlinN8VluHxkt/ADNQgSA6hgG8F7l8VIAu5XHTwDo0HluB4D8GV57G3jl74+TnrsRgBPAS5N+dgH49qRzHgX/MnzCBx0BGwDmxh7kJPqQx2Y9r+TieV6lku4heYqViWBmrjh4i7I8Yf+s55WFfIQLRc5tM0iZ9bnw5l945XrV9En048QcXM/bxItEEdNcqWxqJ5dyUzLWWTPjeZ39I9RpX8A3kFfSjRNocY4s4puS+rdmt9A5sYodBK5sfMkgZYKpiABQHe0APqQ8vgTgR8rjB8FbqnriAK84NoNX9vZiIhh9APyP+sEp1yQBWKM8/rxyzk1TzqkD8HsfdARsAJi29Q9Eko1yVn571vNGhge9q1RN1dMXMwiupq2rk9zKFuVgZ8Os5yaveYVXCjf9zCB11ic1gtMSig5Ks55XUFIy0VrLKYqY5kJczBlekXbcfd20hJTQL3CQcmKxQeqszaBzjLIWfoxzg9N3znruiSNvEUk26gh/xCB1gqmIAFAdewHkAtgKDsZuUZ5/Abw9qydfAfAd8Pbuc+C8wzoA/wbgU+B/1DunXHMIwEHl8fcBjE4zbhZ4NXMm3g7+ZRk/FiBAA8BLi79IJNkoa3/4dc8tD/soB4unNhqgzPpkJ57mLUrH/dc9N/kIr1JdWST6As8Fl9tDDfYH+YYk9+ys5zrH3BNdK4riDVJobaK2OLhP9YrrG5SfXv8ntola86IByqxPZmUbDSl9qql9doPyi6UT7SJpoM0ghYLJiABQHTcBWAfOr/vypOdDAPzdBC19AP4b+gaADlxbfBJwAaDs8VCndA9/0Gdf6/M1lfT1r3K3kHU/MUCd9UnYzvY6hcu/et1zy0sLvJYbnlHh/H89yqomedANdV/3/PRFz/EW+5FFBqizPnER3+Sq/2kMoKdyIeowr1KFzp6LKWCOnD3H7TUdd1zTGWgqA84xKl/4BHsx5gqrHTMQAaB//BRXF1wECtkAFkPfLWBLrAA21lz2+vs5h6+/NZZ16k1hCO0DGUtf4MKZOfj7ucbc1Gm/WxhCz5GEqL28+jfHPr/nN/EqVcmab+qszPqMjnmowv44kWSjlqzj1z2/uGrCakcWq1TXZe+GMC6uWfnsnM6PXsSdmCr3/0lnZYLpEAGgf8SDCyrSwdW2j5orBwDwLgA94DZ140Ugf5j0ug3TF4F8a9I5jyBIikCyzmznD5bQD83p/LqKQq74s99CLrFKNSuyLFODYq9TdTFqTtfkRHAu1aXDS3RWZ30ubOAuCsVvzJ67Ok5C9CHeAg59n87KrE9J9aSArv/a9npTGR3z0BX7YxwwZp8wQKG1ORnG3on1B/4wp/OPvhnKfowrv6CzMsF0iADQf24G8EPwtmo/gCsAVgD4LIAbDJh/OYBnANwH3vKNAVce36a8/jo4IHwBwJMATmB6G5g6AM+CbWDSlcMXAjIATNv4v5z/98aP5nS+x+2hPqVtWVVBqs7qrE19Q513i3J04PpblERECZs4qLm0+rs6q7M+GeGcu1pydG6FBxW1jd5/D3d/u87qrM2FM0eULd0H53xNXMQ3lC3jv+iozPr0DruocCH7Ug7kHp7TNWfOn1V6Bt8lfEJNQASA2vAv4BzADQAaAHSCLWG+DeBfdZrzALgCeBRAo/Lzg5NeHzeCbgWv/MUCeN+UMcaNoLvBRSzHwH6CvhCQAWDRIm5FlH105ZyvKYx4hoPGw8v1ExYEpJ/bx9s8oXPboiQiSo/mbc360Cd0VGZ9RlxuarVzZ5q2ORZ1uD2yt21ZY6ZYpZqNqI1/UYo6ZrfXueqaLdKci0bmM2nljV57Heqpm9M1RfUd5FTaScodV3RWKJiKCAD14aPg4KsAwEKTtehNwAWAbrebBuy3E0k2qi25OOfr0jb9igPANT/QUZ31GV/Ny1/znTlfU1tXy0UN9hvJNdSrozprU1Ra6petS+JiLmwo3vtXHdVZn8Rwtte5fNgx52t8sY2Zzxw5cYxIslF/6Hvn/D6NjnkobyH7hLan7tZZoWAqIgDUn382W4DOBFwAWF2ay5Vo9lvJPeaa83U5Z3cqeYMf1FGd9clZ5Hs+n8cjU5P0AOf7ZImeyzMRd5xzV+vDP+DTddHb2NrkslilmpGh0TGqtXPualfBuTlfN1fj6PnOgbV/45vuNb71/T695If8ubv7NZ2UCWZCBIDqWDnDsQLAIgCvAHi3WeIMIuACwIvH1nLOTvgnfLquqZYrh8fsN9HIkDDVnY7JFb0NhUk+XZu5hFdf8vbPffVlvnFh7WtsAL3et1XopPhosUp1HXLLKr25kjTcM+frrmodl7JXR4XW5mwIOwPUH13o03WHt3PruPrIT+ukTDATIgBURwK43+4g2BA6F8CA8txFcBFGN4DHzRJoAAEXAKa/8RMiyUYXN/jWeWKyd+DlnDid1Fmby+VFXnsdz+iwT9cmbOX8q4KVwlR3JrJCn+Gbl1Nzz10lIqpt6/J2sxltr9ZHnMU5e5w7T7SEzd4acjouLP0vIslGpbt+q4My69Mx4KQrCzkPdaj4jE/Xnk1IUnou30bkHtNJoWA6RACojl8DOIqr37wbARwG8FsA/z+4+va88dIMI+ACwLIwbkWUF7XZ52svLebtzcz9wlR3OlJObOZK6fCP+HxtZuxRIslGzSEP66DM+gyMuKjbfhdvUVZk+HStLMtUJH2ISLJRXdJbOim0NqfX/o57V6/zvRI9audS3qaMfEZ7YUFAUsGk1dXBDp+uvdzSS31Kzra7qUAnhYLpEAGgOhow/ereEwCalMcfBlcFBysBFQA6ncM0an83BxpVxT5fn7aFCxyyV869wGE+kbj2Zxxcr3/F52ubWlq8XxIjvcJUdyqX8vN4dVV6N9GY0+frLyzjXKqSHb/SQZ318fb1Pem7F2VySgKvbkm3X7fDxXzk8OE9fOMS7rsXpdsjU7r9U+xlGS9acRqJCADVMQjgc9M8/znwVjDAXTn6DdJjBgEVAJbnJXMulHQXyX58UOfF7OdE5hBhVzIdBaH8QV14ep3P18qyTLUSbxNVpF2/C8N8I/bQRiLJRjURH/Pr+jO7OZeqaum/a6zM+vQOubz2Ov2XfctdJSJq6Ozz9rh1NpfooNDaHFrNN87VG77l1/XHIv+Hf3e3/VRjZdand8hFg059tsZFAKiOvWBz5W8AuFs5vgGgCsBbyjkvAcgxRZ0xBFQAmH6At2oKF8+tFdFU2pvrvHYlQ/1zMzmeLwyNOGlQ+RLsqMzza4z0yBeJJBvl7hZ2JVOJWc39qAvf9O9LMCU9lVdXRS7VNVzML/Ta69DooM/Xy7JMedLTHKDHbtFBoXWRZZliHV/iIpmouZmXT+XQ7vW8a7PE99SSYGfFhct0/1+iaGl0meZjiwBQHe8CsAVsxuxRjlEAmzFhAP1BXNuTN5gIqADw4qrvEUk2ytjyO7/HaFHsSsoyfEtmDnaK8tKVbbD3EHncfo2RsFPiKtdlX9FWXBCQF/JJLkCKXu/X9S09Q9Sv5FINN+RrrM7anDnEuauNi/y3eDq3nIvLSre+qqEy69PYM0wNdv7MHL2S6NcY59JzJgXoQxortDZ7V79ORQufovSDyzQfWwSA2vAuAE8px7tM1mI0ARUAVoc8yZWmMXv8HiN3KduVXNwj7Eomk3hgJSfRL/Z/izEnmU11Oxz3aajM+vQMjtCA/T28RVnrf/CW5fg0r1Kd36ChOusTteqX/Lu7aW6tIafj7L43OD1k8cc1VGZ9YrN4ddUj3Ujk7PdrjJr2AWpTtuhd1ekaK7QusizTBcdzfPNyWvvCRBEAasNDAJ4D8E7l57eZqMVoAiYAHOjvJbfS6L2zZW6tiKYjbcdfeZty+dc1VGd9kldykUHuFv8NW9u7urz/RoMd9RqqszZZWby6Oqxy+/bMyp/z6vXmn2iozvpkOD7LOWrRb/g/RlYWr3JJ7yYaG9VQnbU5tJdXV1sjnvJ7DFmWKUF6lreBz63QUJ21uWp1tSJB8/FFAKiOWwDEAZDB278PKM9vB5tBzwcCJgAsSuPG4m3S/arGyU9gu5JGh+8VbcFMWQjbjJTG7FQ1zhUHr9KWJezXSJn1ubCPV1crl3xK1ThnDmziXKyID2ukzPq09g5Tj/1ODrBrs/0ep7N/xDvOQE2WhgqtzZFlvLpavfmHqsY5vIJbcdZsekkjZdbnqtXVEe2/Y0UAqI7dAM6Biz8GMBEAPgegxCxRBhMwAWDabolblEWqyy/r7mzz2pX0dQm7EiKi7t4+bzusvuZKVWOlLuc8zdztv9dInfWJXfFjLgDZ+ktV46RfKhC5VFNIyUhXVu5uUb1ydzGEVxIrz6zRSJ218XhkSrY/wwbbF9S9Jwf37+CewIse10RbMHBo7xbVq6uzIQJAdbQC+IDyeHIA+ADYImY+EDABYPayr3Pu3q6/qR6rwfE+IslGxcnCroSIKCf1HJFkox5JfauxxD0R7Fe39D80UmdtZFmmYunDbIMRr251tXvA6bU7GahI0UihtTnzFq+u1qhcXSUiOruaV7tKN/qfSxhMXGntpy7FvHysTt2qaGxOyaRWfcKBgYjo8LJf8OrqFn1+30QAqI4BAA9PejweAH4UQJcpiownYALARsfDHLSlnFA9VvYytiu5uFPYlRARxSvVu8XLnlM91qWMOK9Xo+hbS9TQ1uldXXVq0MYtWTE8rjoVqYE66zNukF263f/c1XGiD2/lLXYV1cTBRHRyhirz8sk09QxT7cKHeLW2PEYjhdZlzO2hZPtneAUw1nff1bkgAkB1nAUQpjweAHA/gBsAHAJwxCxRBhMQAeBk/77Bvi7V401sJz+vXlwQkLHka9wBZM/fVY/V2z9ATqVbS2/jZQ3UWZuUuCgiyUbdjvdqEhCffOP3bCezXnSz8Xgmt8jbrXq87MISVX6CwcaRHby62rj0E6rHkmWZzjm+wuOdDNNAnbUpaez15px6GvzzXb0eIgBUx/sBtAGIBvv/HQZQCt4aftBEXUYSEAFgTvRuXioPeVKT8YrS2K6k1aGuoCQY8HhkalK8EasztfFGLAvhLc+SCzs0Gc/KnN/yD16hWqnNzcaZ43u5GCrsUU3GszJXGttpVFldHeusUT3egHOMWuz3csBe6p/nXTARtfgHnBO5S/3qKhHR/tV/ZquddcKB4URcsma5qzMhAkD13Ajg7+BVv7MAwgHcaaoiYwmIADBt4/8SSTbKWvMDTcbr6+0ij2JX0qXCUiYYqK6u4FUP+400NtSryZjJq37EhSCbtfnisDKpEV/l7fUDdk3Gyy6tmsilGlK/Gm5lYs6f5NzVEG1WV4mIUsO+yCusxyM0Gc+qjI55qND+Qb7ZSN+ryZgHDx/gnYGwBzQZz8rs3RxJJNmoaZn63NWZEAGgQC0BEQCWhHOP2uxj/vt8TaVKMZW+dE5dYr7VST21nZPowz6g2ZhamEoHA6NjHmpUfL6aL53XZMxB5xhVLXyEA5/Cs5qMaVVObvwbkWSjK6u/qtmYUeu4723Z2m9rNqYVya9spDH7TUSSjeQebTw9E4qqvT6h1NesyZhW5UT4S5y6sOfXus0hAkDfecqHYz5gegA46nTSsP1WTs6uuKTZuBlvsDVH5oafaTamFUlcx5Voeet/rNmYRflsqjsi3UqyyuRxK1NcVu71+ZI19PmKCX+Bt+YOLdRsTCsSH8arq1cOS5qNeeHUPk4Pmedb7KdPHuQdklDtVuu6B0epdOETbDd1af46MPQOu6hkIS9A9Occ1m0eEQD6zrjp8/ifnkk/T31uPmB6AFiWm+itKpX97FE7HRdPbOStnrCPajamFSkM5R61haf961E7HU7XGHXbF3DQXjh/c6lij3JVaX24dqurRETHNy3kwGfV/C1i6h0cpWb7ffzZUBKr2biFV2q9W+zyYIdm41qNo2t4JbRy3Tc1Hfds+De5in3/nzUd10qkFlV5U5Cov0W3eUQA6Dv3TjpeBFAJ4OeYWPX7OYAK5TU9+SuAbHD1cTuAEwAemXLOTvA/7uTj3JRz3gFgPdi2ZhDAUQC3+6DD9AAwfe8iIslGBUu+oOm4DdW8OuOy30wjQ/71uLQ6fYND3tXVzppCTcfOiuAel5f2z9+eyzErf0ok2ahok7at22IunNY8981qpOfkTFiUaGiK7RxzU4X9cV4FzDyi2bhWQpZlSnR8nm9eopZqOvaxzaFccLbi85qOayUOH9hBJNmoI1zfVWYRAKojC8Dz0zz/PIBcnec+B+AVAE+AzajPAKgD8K+TztkJrlC+Y9Jx85RxNgKoB/B5AB8BkAEgzQcdpgeAXs++HdreMcoeD7VKvIJQlq5N9avVyEnRzgB6Kgnb/87BzzJ1nVusiizLVCJxEn1V3A5Nx65tnfAWHOmo0XRsqxD91nLFAFq9RclUzi/h/KzynfrlZwUy1e0D1GG/m6tUa9I1HTsmIV5JD7mNyO3SdGyrcGTZzzVpr3c9RACojhEAj03z/GPKa0ZyG/gf8rOTntsJXhmciRsBuAB8e9JzjyrjfGKO85oaAMoeD7VL97KNhg5BWvayFxRD6L9oPrYVSNjyOm//rvhPzcfOST2vBJcLiDwezccPdKoam70J784ubSvNZVmmUgf731XE7tB0bKsQt+Q7bDW087eaj316zxpO0F/8Mc3HtgLR8Qn8eyvdptoAeir1nQPe7iLOKm2DSysw4nJT+kJOu2lP2KjrXCIAVEceuB/wv0x67l+U5/IM1vIQ+B/y/ZOe2wmgF7xFfBm82nfLpNc/r1xz05Sx6gD8foZ53g7+ZRk/FsDEALD2cj5/UNhvIeeI9sasaXvDOQBaMj/bluUuepa3aQ8t1nzsvsHBie3l6gLNxw90EqLYr68l9BFdxo9bxdvLhRtf0WX8QGbE5aYqO1dCt2Qd03z8jMk9l53zLz3k2CYHr66u0P5zUZZlinew1U7diflnCJ1V2er9XJRbS3SdSwSA6ngabATdDiBWOdqV5542UMcNAKIApE55/iUALwB4EpyTWAretv4n5fXvgw2sp5IFYOkMczlwbV6haQFgxiHe5ilZpI+dyOW8FK7Ekm4n99j82o4YGhmhAft7ONfpsro+nzORH/Zpzt88sUqX8QOZ2De4r2zRuu/rMn7ciR1sLxP2uC7jBzJZRWUT1dVD2veVHXSOUZ2d25a1X4rSfPxAJyGMO3ZUHtbGu3Iqh9b9lQPM1V/WZfxA5tDxY0SSjQZD9N8ZEQGgev4VwM8ArFSOV3F1Hp4RbARQC+Du65z3APgf+z+Un/0JAANqBTBruZL/t+0Puow/5nJRn9KO50pugi5zBCp56TFsxyDdqdsHUeKGX3MAuPpbuowfyBQ4nuYq8+gNuoxfXlPv3WIe62nUZY5A5dQ+ruBvitCvZ29sBFerlu35o25zBCItPcPe/L+By8m6zHEq+iyRZKNhxx1E7jFd5ghUDq38La9+rte/G4oIAK3POgAN4D7Ec6EDXKkM+LcFPBXTcgD1zv8bJ3fp8+wHOM/yABO9RRr63YVnxh3ntlqOe+ZVtWpjW4e3RdlQS4Uuc3g8MhUrRSY18dt1mSNQiV7KLcoub3tVtzmidi7lRP2ln9ZtjkDkfEKCbvl/41xp6aE++x08T222LnMEImNuD2XYualBy4U1us8nAkDfeQHAP/tw/vMA3qmDjreBg78mAA/P8Zq7wV6FLyg/jxeBfGvSOY/AIkUgeuf/jZO+L4K3mSM+o9scgUhOxBfYAHp/qG5z9PYNePNd2itzdZsn0Eg4s59tHkLu1zXwPb/yf7jN3MYf6TZHoDE8OpH/15qpn4luehabmY9JN8+rPMDDG+y65f+NI8syJTs4/7j65PxpuZdb2UxO+y2cvtBWrvt8IgD0HQ+44nau9IO3XrVmA7jA4xlcbfMyHmy+C8AycCB3H3jbNxfsUfj2SeNsBK/4PQu2gUlXjrliWgCYcXCZrvl/41SVXZoINIcHdJ0rUOgfHPTm/zWXZug6V244f9DnHwzXdZ5AImY1B2ZF67XpXT0Tsafe0rXQJBDJzi9QArObSB7u0W2e/hHXRB5g9vzoWiHLMsU62L+z9pik61wnNvyFA8CVX9R1nkDiyGH+/9oT+oAhOyIiAPQdGey5d2yOhwv6BIDXFGIoxyvK6+8EcB5clOIC5whuxrUmz+NG0N0AhhTNd/igw7QAcHxr9uL2P+k6z2Q/wJKUE7rOFShkxp/gNk+Oe3RPRI7f/g9epYr8kq7zBApuj0yXpfdzEn2cvn2m65pbvf1aB1urdJ0rUDi7S9maXfJJ3ec6t+T7nAe47ee6zxUIXGnpoR4lJ9pZnabrXBe8W823ErmGdZ0rUDiylG8Mazbre2M4jggAfWeHH8etpig1BlMCwFHnCA3Yb+cv0UtJus+XuYI9xS5unh/Gr4nruEI1f/V3dJ/rUlYy58JJ75kXfYFLypX+v/YbydXfrvt8+SEf5yDl1PyotE4M5xvD0n365+xGHdzMK6zh86PS+uwZztkdcNyle3FGa+8wNSmt/AaKzuo6VyDQO+yiSwvZu7M7bYchc4oAUKAWUwLAolRuddUl3U0et3b9f2fi4rF13LEhVL+qwkBBlmW67PgAb1Ge3az7fE6XizqVqsK63Au6z2c2MftW8l1+hDEmwuc3/pG7VqwM/r7ALT1DXhPh3nL9bwyLquq8K6yuzhrd5zOb06v+l83F1xlTtX82/Fu8mvtW8N94x2SXeKv2qdeYqn0RAArUYkoAmL7pNSLJRtkrjfkgamup9zbn7myqMWROs6itqeQPIclGg13NhsyZvvTrXHCyTfuuDYFGymL+uxbu0se6aCqpKXFsqaFj1WagcD6G7UMGHXcY0kbM45EpT2I7n6rotbrPZyYjLjcV2bmqvDF+iyFzHtq1lot5Ip40ZD4zObCVPW1blnzYsDlFAChQiykBYFXIU0SSjXJO6dsqZzJlYfxBn31khWFzmkHyodX8hRb+EcPmTDqygVcAw4L7g753cIS67Au4uCY/1pg5h0ap1f5e/iLNC+6e1qdX/4pXqNa8YNicUWt/x3Ou/nkoQ7kAACAASURBVJphc5pByqUS742h3N9iyJwZxZXeVTFPt7btEgMJWZbpQginLtQcfN2weUUAKFCL4QFga2O1N4eqp73JsHlTt3Ff3Pylzxk2pxlkLPkakWSj3O2/M2zOxuYm71Zab+Nlw+Y1muTYk0pnmTsNbXQft/S7vOq49ZeGzWk0LreHSuyculAb+6Zh88bFcU/rEem2oC5WOLItks21l3zUsDlHxzyUZ/8Y3xye098XzyxKGjq9vocj1fq6LkxGBIACtRgeAI7bv1wOM+6DiIioIj+Dt9LstwatHUxvf7/X/qWhUP8cqsmMt4XLPxy8vl8xq1/l3Mq13zV03tgjXKzQFPpY0Bpu5xSM9+e9kdwDHYbN2zPopCb7/UFtByPLMsWGfFlZofqzoXMfX8s5rDUrv2DovEZy+PA+7roU8l4ij/457eOIAFA73mG2AJMwPAAsiGDfuIxd/zBsTiIij9tDLdID/AUef9DQuY0iI3ovGxQ77tPd/mUq8TvYYLZsyTOGzmsUTtcY1dkf5u31pL2Gzt3Q3EpO+7t5hbW2wNC5jSJqi8Tv7VJ9fUGnIzryR1xo8+aPDZ/bCMrqW2nQfpspnTkuJKdMGG4Pa9/XORA4GvFjDnK3GGvYLgJAddwAYCG4G4cbE35/YQD+2yxRBmNoANjb1UYupYVWQ4XxX2Tpa/g/avYaY3yajCZ1xUu8/bvhp4bPXVrMhtsu+83kHOgyfH69ycpMVXzNbiHPiPGdIy6G/wf7Le77q+Fz643HI1Om4985F+/YIsPnjz51gIPrkHsMXcExitOK3U1n6EOGryB3D47S5YWP8fxpuwyd2wjqOwepZiHfGPbn6te5ZjpEAKgOO4AqAD8AMIyJAPB7ADLMEmUwhgaAmcfZjqU6xJxigUuJ7IPVIy0gt2vUFA16MeIc9dqxVF08bfj8Ho9MVdLjbLh91rjiHqO4sPEP7E+3XL/eyrMR/RZXGdYvCj4ro/yKGu+NobPV+BzSps4+r0FyT1mi4fPrTUw4V65f3vmaKfMfXfYz/txf96Ip8+vJiTNnlBvD24icxqYWiQBQHZXgFmsAMICJAPBRAD2mKDIeQwPAvKWch5Kx1RgLjam4XKPUJXGQVJx8zBQNepGdyN6KfdJdJI+ZE9zGb/o9B4BB1hVkzO2hMokLFMrOmGMXUlZV6w2SBpv17zNqJKd3KgUKi54yTUPcohd5G3jH/5qmQQ8qmjqpVylQGDDAW3E6os6dnSi0GR0yRYNeHI/k7h9V679p+NwiAFTHCIB7lceTA8DHAQyaosh4DAsA+3u7aERplF1dfFH3+WYifc2PlG3g75umQQ+SV/H29qU1L5mmoehSlncbeKTPuER+vcnNuch/L+lmGjXp7yXLMmWHfpZvXg5IpmjQA1mWKTOE/17lh+ym6Yg6tI27OITcF1TbwMcO7VS2t+817e/V0T9C9fYHudAmY78pGvSgqXuI6hby36sr84Dh84sAUB25AH6oPJ4cANoBpJiiyHgMCwDHt3/rHY+SbHCBwmTyk08q28B30dhocBjrDg0Pe/3pKtLMq2T0eGSqcDzJliWn3jBNh9bErPsNr/4tN9dC6MLuxWypEf4hU3VoSdHlK14LoeEW8yyE6tsn+uR2FwVPR5vzyvZv5fZXTdVxcjlX0FetNc7jUW+Onj7FK5uO24hGBw2fXwSA6vg6gF4ArwMYAvBHAFsAjAL4oom6jMSwALBgsVL9u+1Pus81Gy6Xizqle3glJdHYpF29yDi3X2mtdw/JBvrTTUf85j9xrtzSz5uqQyucrjGqkR7hHKoLxnRQmImqujoaVbaB+2ryTNWiFVFbQzioXWxMa73ZOL/4u0o18MtmS9GEy/VtXluogYoUU7WciYlRVtHfHTTVwEcXv8zVvxv177k+HSIAVM9nAMQAaAcXgqQC+JKpiozFkACwo7nO6wjfVFms61xzIW3tT7ladkVwJCWnR36T/z4b/8dsKVRanM9+bvYbabCzwWw5qslIiVXyl24l97CxHXOmIzX8OQ6wd/7GbCmqcbk9lCt9nEiy0ZXji82WQ+dOH+RqTsddRCbl0WrJ0V3cFagj7H2m+0d2D45S2cInuF1a/CZTtWhBVUs3tStFd/155uSTiwBQoBZDAsD0PaF8Zx32tK7zzJXS3GSu3LLfQgO9nWbLUUVPb4/X46s+P8FsOSTLMhWFcNu9/P0Os+WoJnbVT3i1ePU3zJZCRERnD29VctXuJXKPmS1HFRnZnDPqkW4kV3e92XKovXdoou1eprV3B0bHPJQk8a5L9QHj2pPNxtE1/8edXpZ/zmwpqjmx/00lt/K9hnYFmowIANVRDeCWaZ6/SXltPmBIAFgR+mEiyUYX9wdGlwjZ46HKEM5Vyz6y3Gw5qkg+/AaRZKPmEPPv8seJ38tVnQ2hTwSMJn/o7Onz5lbWpR8xWw4RETV39VKX/S5eScmJMluOKs6v+SXnra4InKrxM8v/m1ckV/+n2VJUEZtd7K0aH2spNVsOERElZeZMBPydNWbL8Ru3R6aUkM/z7+5bxrXcnIoIANUhA3jPNM/fDs4DnA/oHgBeKUgjkmw0ar+Zug3s/Xs9UndLnNcVHhirkv4gyzIVhn6St393B45BcFt7Ow3bb+Ut/yJzrCe0IPbwJjawDbk/oFbbYpZzJXvJG982W4rf9A4MU5uy2lZtcGeV2UhISVY6V9xE7r4Ws+X4zb7VnIvbHPlxs6V4cbk9lCl9iotBDv3NbDl+k5ZX6E1pcjabF1yLANA/XlAOGcCPJv38AoBvAFgH4LJp6oxF9wAwYy1voeUu+5puc/hDW1Odt/qwseKS2XL8orwox5tv19daZ7acq0iL/Abb0mx42WwpfsG2K89wRfMuc3wrZyI18fykvMRes+X4RdzxHVyN77iH5LHAqcZ3jrkpX/qokpcYbrYcv2juGaIrCx/l/L+EwDJlP7ZzJd9UhT1kWbudE2/wVnZdpPFtCycjAkD/kJXDM+nx+DEKDv7+0zR1xqJrADgyNEB9ElsrFCYd1WUONeQu+RKRZKPMzb82W4pfJK77BZFko6JIc+1JpiMj5hgnSEt3kNtpPfPXwqIC8ih3+f0tFWbLuQqna4yqpMcUY+p1ZsvxGVmWKT3si/y5sP1XZsu5hpPbI3j1LPz9lkxhOHz00IQ9yYj5hUuTKW9o9RpT9xWdM1uOz3T0D1Ot0hO8KX6zqVpEAKiOGgC3mi3CZHQNALNObuQPUulB8rgD724v68wONieV7iPPmLn2Kb4yODREHXa2sylLCDxzVafLRY0Sm6SWnDPXPsUfxr3/Li8NzIT1mM2v81ba4k+YLcVnisvKvavvffXmuwJMpby2iYaUwqre8mSz5fiExyPT2VD2/qvZ+rLZcqbldMT3eet/g/VSGE6f4ErxIcfthrd+m4oIAAUA8BqAWgBOAJkAnvbhWl0DwOJFnw4I77+ZGBkZpm6Jk/yLEw6ZLccnUk9x54JOx72mtX67HvEbf8cBaoAGUTMxMOykZvv9vA0Yu8NsOdNSfmXCQLmnrshsOT4RvZHz06qWfMpsKTMSE/FNxRPwx2ZL8YmLJdXe/FtnVbrZcqblVPRZryegPGgdFwZZlulC2Av8ubD1J2bLEQGgBvwrgOcB/ALAb6YcVuB74G3rn4Bb2G0G9zGerrhlOnQLAOsrJvzgWuqvaD6+VqStY4f6/MjnzZbiE7mLuAotZ9tvzZYyI+VlRd5t1J7GwNpGnY3EqD28OiXdRbJr2Gw5M5IRzikMhdsCbxt1JgZHRqlO2UK7cj5w/eDOnTnKKz3S7SQ7+82WM2cObpDYxibiqYDdvu4ZGqVi+1O8jRq9wmw5cyavvMbbznSwKsNsOSIAVMmHALQA6APgBptBy+A+wFaxgckEF62McwOAJgB/meP1ugWA6Zt+xYHVki9oPraWXCnK5LtR+83U3Wq+F9lcqL5S5g2sOmsDw+JhJvLCn+EioB2BVUgxG2kRX+HAasvPzZYyK/EndyqFFHcHVCHFbMSfPcJfoNLtJJu8hTYbfcOjVG3nDjC1MYEbqE6md8hFRfYPKIFVYNtbHVq/kK2MFn8oYAPVqRzZ5GDNER8ICM0iAFRHInjF7AZM9AK+B0ASgG+aJ2vO/As4cH1xyvO7AJyc4Zq3g39Zxo8F0CEAdI06qUNii4fcc7s1HVsPSsPYuDjzrYVmS5kTSZt+z1uriz9rtpTrknyMrVTaHfeTHEBWKjNRWV3t9U/rrMoxW86s9A4OU5v9Xt5ODSArldlIjOD8tOJN5m+hXY9T63mrunZp4G5VT2Z8a3XUAlurF4srvatpIzVZZsu5Lv0jLiqyf5AN96MizZZDRCIAVEsvgEcmPX5MefxxAOWmKPKNu8D/+J+c8nwkeGVwOhzKNVcdWgeAued2swWB9F5yjQb+ykTa4VVsXBzyKMkej9lyZsU5OkrN0gNc/Ru91Ww516V/YIB6FOPiipTAMFOejQtb/sYJ6hHW8IeMeYPNlMuWBY6Z8kxU1NaTU/nS76owfwvteuQWl3lvBoYaAj/PMmrR9/hmYMN3zZZyXTwemc6Ffo31bvtvs+VclzMXzk/KW+wwWw4RiQBQLR0AHlYeVwB4Tnn8KIAhUxT5hj8BoCErgFmr+IMofZM1cpN6e7tpUGmafjkz2mw5s5J5nqvQeqW7aMwi9ipJa7j3csHywO6u4HSNUbXE/mmlp9eYLWdO5OfnenNtB9trzZYzK2e28hZa/aIPBsQW2vWQZZmSQjnP8vLO18yWMyvFNc3UZ7+dbYtKYs2WMyeOHtmnVNTeQTQ6aLacWTm9mCuXq9Z/y2wpXkQAqI4LAL6vPN4CDpp+AOAcZg6gAgl/toCnoksOoMftpsKkE9RcW67puHqSvor/g+eu+o7ZUmYla8nzXPyx8VWzpcyZ4rw0b55lf2ej2XJmJC0+ikiy0bB0G40N9ZgtZ07IskyXQri7QuGewOkGM5WR0TEql7j94uVTy8yWM2eijnCeZb9jAVEA51ke3bqEUy3CHyUK8F2McZp7hqhmIRcEtSUF7m5GWX0b9djZz7a38KzZcryIAFAdHwXwrPL4PeDArx9ALoAPmiXKRzIBrJ308w0AGhEARSBWoygzjvNR7LfQYG9g5s80N9V7t6SaygM/b2YcWZapNIS7K+Tsc5gtZ0aSIr/DgdS6/zJbik/EHVjDlZ8hDwfsl39iAm+hOaVbyD3YZbacOdPWO0jN9vvYzzR1j9lypmXE5aYcifOYa46Fmi3HJw6vYquo+mXmdtWYjSNK95KuAOteIgJAwffA/n8vg3MY3wTbwNw+x+tFAKggezxUFcIrFDmHAiPJdypJu3gLrTL8I2ZL8Znk/cuUPMvHA3L7r7mtnQYV89/mgjiz5fhER3cP9SndFeqyz5gtZ1pilv2AcxXXWs/899Sq13j7b/l/mC1lWi4kp3IagHQTeXoDp9/6XIjPyvf6Wbpay8yWcw3OMTddlNjPtjrA+heLAFAf3gHgj2aL8IFfAagD+wFmgotY5ooIACeR+lYof9CHfchsKdfgcXuo0sEBat4R62yhjdPV1entrlCVE2O2nGuI2RPJK6uhjwVkgHo9Elf8kFcvV3/TbCnX0NTR7d1Ca8sLnC20uZKaneO1XRptrzZbzjWcXP4zDlBWf8VsKT7jcnso0cGeptV7f2e2nGuIy8gmkmwcYHfVmC3nKkQA6D+3gfv9fgnAPynP/TOA3wJoBdBpki6jEQHgJNrbmmjU/m5eSSlKM1vOVeRP2qIe7rPOFtpk0ld8l/Ms17xktpSr8HhkKgz5GFdWH5DMluMX2enx3i3Wkb7AqFIc5+yBDewKEPJAQG2hzZUxt4cyHJ/hSvb9r5st5yqauga8W9QdFw+aLccvDu1hq6i+kPcSBVhXo8MruSVk7YpnzZZyDSIA9I9/B9u+yAA84FWzx8GVwKXgriDvNE2dsYgAcAqZkexTlr3uFbOlXEXKqh8RSTa6tCpwqtB8pSD9nNJd4TYa7u82W46XvJwMIslGY/abaLjLWlto47g9Ml12sAlwwZElZsvxIssyZYR+jiur3/qj2XL85uTedZwHFvoAUQD5WZ46sssSRSqzcaWlh1rt7BvbnR04VlFN3UNUtZDNwDuSt5kt5xpEAOgfiQD2AXgCwHJwIHgZwLdN1GQWIgCcQl7CMf5Ale4g53BgtIDq6+/z5nhduXjabDl+43F7qMbxGAeyx1eaLcdL7BpuB1i6wlrtAKcStyuMVyvCAqNTARFRXnEpuZXt06Fm67gCTKWurZs67dw3vDP3hNlyiIiD68Qw7lpTseMXZstRxdFI/j9YuyZwtrEPHuN2gCOO24gCsB2gCAD9owu84gfwSp8HwNfNk2MqIgCcwtjYGDVKbE1w6fRGs+UQEVHqsY3cgsjxEMkW3EKbTOIObgFVuSgwjJYHh53Upqw+VKVYcwttnMbmJq/Rckd5utlyiIgoSummUb3002ZLUc2ZyFfYxmZtYORZFl2pIaeSsjJYE9hda67HmcRJhSw9DWbLIVmW6UQY+9nWbv6B2XKmRQSA/iGDbV/GGQDwoElazEYEgNOQsvWPnA+2JDCq/nIivsDb0tut0093Jmpqa7xWNt01BWbLoZTzhxVj7QWW6ac7G8mLXyCSbFSy+admS6Ehp4sq7WysXX1uvdlyVBMbO25lcyvJI71my6HTW0K4sj7iw2ZLUc3Q6Bhl2z/OAdcp81MYCmtbvYVLw2WBV7RGJAJAf5EBfA7AU8oxCOD5ST+PH/MBEQBOQ1VZvjcnrK+z2VQtrS1N3oCptSrfVC1akRnOAe2lXX8yWwolRXJhSsHGwMr59JeYqAOcUO9YQOR2maolKSkmoAImtfQPj1KVEtA2JJhrXDw65qFciQOmyhMRpmrRisMb2eaqccnHzJZCh3Zzzmd3WOAWLokA0D/Giz/kaQ7PpD/nAyIAnIHLoR9mT8DD5noCJu9ne5LqsA+aqkNLEg6t5Q96ky1XOnt6vbmVTfmBeZfvK139w9Ruv4f/TtknTdUSvYrtScpWf91UHVpyag1XhVatNLf3clJ2vteaxt1db6oWrUjNL/V6Ao61VZimw+2RKcHBN6nV+wN310UEgP5x7xyP+YAIAGcgZZedv7wiPmWqjoLwf+dAdM9CU3VoSUdnJ40ouWot5Zmm6Yg/vpXbZ4U8ELAdNPwhdjlXjBet+75pGgZGXFRvf4gtlZIDs4OGPySlp3OAIt1Enr5W03Qc3/A3fm8jA7eDhq+43B5KlT7L28BH7abpyCir8ebSjjaan6YyEyIAFKhFBIAz0FBb4TUA7WqqMkVDfU2l9y6/q/GKKRr04uJi7mmcv/03pmlIW/w13v7d+pppGvQg+cIJIslGA9KdpvmqJcaf8/ZVlp0DpmjQgxGXmwrtH+IgJXqNKRqcY27Klz7CGs4GTjW9FhzaspQNwyOeNG13YO+2VXxjuCgwuxaNIwJAgVpEADgLxWGf5OKLA+bk2CTvjWCLh0UfN2V+PUk4unmif60JH7Jdvf3Ub7+dNZSkGD6/nvQNO72+ak2Zx0zREL3yf4gkG5W/ERgVs1pyeh1XNleu+KIp86fl5E1UzPa1mKJBLy6WVnsrm10tpYbP7/HIFON4jldXD/7Z8Pl9QQSAArWIAHAWUnZJXFG5+LOmzH9pERvo5uw1bztEL1o6umjYfiv7qlUab2GRdGYvz+24L6i2f8c5t+zH7G24wfht4CHnxPZvY9p+w+fXm8S0NGUb+GaSh403ND+x6R+cn7bsGcPn1hu3R57YBj4RZvj8eVcavS0rXfV5hs/vCyIAFKhFBICzUH250FsNPNhjbHutjo52GvVW/xYaOrdRZC76ElcD7zG+yXri8v9Sqn/Nt0vRg5gzir2N427DqxhT05K8bemCaft3nEHnGF2xs6F5c/IuQ+d2uT2UIX2aSLJRzamlhs5tFEc2KfY2kcbnXx/dw9W/HeGPBPT2L5EIANXwNgDvBfAOs4WYjAgAZ0GWZapyvJ9z1aLeNHTutBPcH7M+9HFD5zWShH3LuaIy/KOGzjs4MuqtlK3LOmXo3EbR3jPgrXDuKE0ydO6zG9hH8/KK5wyd10hOr/wFp2cYbAqdVVbttYVyd5iTm6w38Vn53vxruc84Gy5ZlulcGLcCrXzLvNzkuSICQP+5AYALwMNmCzEZEQBeh5RNbPtwafnXDJ33otKTOGfLrw2d10hq62q8RS6DHXWGzZuecMbb7i8YzJ9nIiWCi1wKd/7OsDk9HpnypY/yl+gZc4okjOD8+TNKkct7iFwjhs17/K01XD2/6CnD5jSaQecY5SuFNq3xGwybt6Kllzrsd3PbwvI4w+b1FxEAqqMEwCfMFmEyIgC8DkWZcRygSO+hMeewIXMODw97CxRqLsUbMqdZFId8jPMsT64ybM7Yda+xTcqabxk2pxnEHGS/xYZw44KFgvIKb1A/2hUc/nTT0d43Qs32+7hCvyDasHnjwjmor9gbuP50WnB41e/488/A3sBHTp3koN5xh2nV874gAkB1fA1ACoD3my3EREQAeB3GxsaoXeKKysvpUYbMmZt8ml3opbst3/v3esRs4orKsuXGbBfKskylDl5dKDtn7La+0ZRV13mNdZ3txmwXntm9jLfWIz5iyHxmcmHxt7nSeZcxq/SNXf3Uq2zr91cEV+X6VKJixrvI3EZk0Cr9keX/y0HnemtUrosAUB09AEbBXT9GAHRPOeYDIgCcAxnL+YM+y6Dt2OSNyrbzquBeoSIiykxP5C0X6T2GbMdW1kxsO490N+k+n5nIskw5DrYyqoxaYcicKYu+wtXHewPbQkMLTu3lFdYmg7Zjo8/yClW/Y0HAtifTiqbuIa+V0UBZrO7zDY2OUcFCvjFsS9yi+3xaIAJAdbx8nWM+IALAOZB+bD1/iYYZ03S9LIRNXvNPrTNkPjMZdrqoQynIaMg7r/t8cQe5yq82PHha681G1HouyChfrX8Oa9fACHXb7+Jt0bJk3eczm5yyKnIrNxOengbd5zu+6tdEko2urLPGCpVaosNe5CKxffpvd6dcKplUeGKNG0MRAArUIgLAOdDUUOv9cOjv0rcqraW1ybtC1dtaq+tcgULaUi54ydvxf7rPlbz0m2z/YmIHEiNJjI+e6AriHtN1ruTEGCVf9nYit0vXuQIBl9tD+Xa+WWuI0zedwOX2ULb9afZWjFmv61yBwqHtK3iFdYn+LgFHdihzLbZO6oIIALXjHeA3cfIxHxAB4By5EvIBXpU7q+/2QNrJLbxCFfqkrvMEEkkHV/LKxqKndZ1n2DlGbcq2UmOucYn7ZtLVP+zNG+ssT9V1rrMbX+dc2ZXGJe6bzalVrymrcvqma+RdqfPav3g6q3WdK1BIyCn23njTQLuuc0WF841h9Z7f6jqPlogAUB3/CmAdgHZwHuDUQw/uA7ANQA0477AKQAiAf5lyHk1zvDTlnKfARSxOAA0A/uyHHhEAzpGU9ez7lbvmJV3nSVvJBsU5m36u6zyBREVFGfua2W8k10CXbvPkXEye6E9roHWH2aQv4tZWxfsX6jpPZgh3cKg4EZwGxdMRfeb4pLw8/TrKnDq4jfvThj2i2xyBRt+Ii4oWPsU3L+lv6TZPY88w1S7kzjVDxWd0m0drRACojvUASgF8C8AwgJ8A+Ac4mPqBTnN+GcAOAF8C8ACAFwC0AVg+5TwC8AqAOyYdk02rbQBaAewB8AQ4OBwG8DMf9YgAcI7kxB/lD2DH/bo5xMuyTE3Sg5yzlXxUlzkCEY9HpmrpUc73Sdqn2zyxOxxc/Rv5Bd3mCETObQ/lVarIz+k2R11bt7e131BDkW7zBBrVbb00qLQOczYU6DbP2Uhu7Ve+JTg718zE0aX/zZ8Lm3+k2xxnkzO9vZXJ2a/bPFojAkB11AP4nPK4H8BDyuMfAThroI4/Aaie8hwBeHGWa34JrlSevHK4BEC5j3OLAHCO9PX3eVuzddSV6TJHTWW5t/Xc6ND8+jeJX8FfcIVv/o9uc6RHcIVqwT59V8ICjfTMDPblk95NNDqkyxwxZ46wdVHIvQHfQktLZFmmDMdnePtQp0pr55ibyu1PcOu5NP1ukAKRowd38I13+KO6zXFw82JOC4n8pG5z6IEIANUxCG4HBwCNAJ5WHt+vvGYU4QBypjxHAJoAdALIAvBTcPu6cXYDODHlmmeV626eZa634+o8xwUQAeCcKQn7ONuznNInCTvtKFcbXzG4NVogEHf0TfaP06k6d9g5Rp2Ky39LYXCba0+lb3iUmhTT4u4ifSqto9/gCtXStd/RZfxA5tTa/+P/t2+8qMv42SVXJipUdc6FCzQySqq9ldZyb6Muc0Qr7d9qDvxJl/H1QgSA6igE8IzyOBYT27C/AQeERvAQgD4Ar055fiGATwP4EIDXwXl+v5n0+gUAb0655nHwL8Njs8znwDT5hSIAnBspG9goNGfN93UZP23VD4gkG2W/+Utdxg9kLlfyl5zHfiO5Brs1Hz8vl1fBRqRbg7r920wkLOIOEqX7/6bL+Nkhn+b8vzNv6DJ+IBN9lvMAe0Pu0WX188SBLUr7t/drPnagMzQ6RkULuQCvI2Ov5uO39g57b44GSy9oPr6eiABQHb/HRFD1BXBRhhNcAPJbH8dagukLNyYfj065ZgGASgBb5zB+CDg3cRx/A0CxAqiCrPP7easgRJ9E7BrHY9wWLW5+bfMQcR5gnfQ+XklJ1T7/MXZXBFeoLn1G87GtwJltnAdYsew/NB+7qbOPhpQ8uKHG+ZP/N05FUweN2G8hkmzkainVfPxTkZwHd2XLK5qPbQVOLuH0kKodr2o+dkxaFqfdSDfrlh6hFyIA1JZ7AXwTXF3rK7eBA7zZjsn5encBqABv5d4wh/G/Cv6Hfrvys79bwFMROYA+0NHe5vXo62vTts9pU2Odd5tnqKdNYubHRwAAIABJREFU07GtQury73Kl9TbtrRhSl7zA+X9vBX+HiulIS03wdlzR2g9w3Guw33GXrpWwgYrHI1OmxB1X6s5ruwLq9siUZ/8oe9QlbtN0bKtw+C1OjWmJ+IDmY+/fvorf26X6WlDpgQgArckCcPC3H8A/zfGav+Pq9nTjRSD/POm5CIgiEN2pUPwAC89t13TcjNPb553/31QS97MfYEXEpzQdd9Tlplb7vbx6m3dO07GtQs/AMPUpfoDdlVmajn3mzb/PO/+/qZxc9StepVuvbQ7klcY2b/GZe574/00lLneiSwcNaWsTdWgRry7W7bKe7ZYIAH3nNz4cerAAwBVwzuECXG3zMs7XAPwPgPeDcwR/CWAIvA08zo1gG5jdYBuY7ynnCBsYnUld8xPOA1yvrR1Dyhv/rYw7P7d5iIiKCnO91aqya1izcUtLi3h7TrqZ5NFBzca1Gplhz7INzvFITcdNDv8yW5QcDtF0XCtx5sQ+zlMLfVjTcROiubq6K0Q/+6lAp2twlCoWcnpM/6Xjmo3bO+yiiwu5u0p/xk7NxjUKEQD6Ts0cj6m2LFrxCmbOERznywAuARgAVyPnA/g5rt0qnmwE3QguFvEVEQD6SPqprZyPEvYhTcctC+VtnoKzmzUd10qMjI5Ru9IXuKVAuwbwicc3c5VfuDG9nAOV6PV/4ABwzTc0G7N3aNT7b9ZdlqTZuFYjv7Lemx4i92nXLjJmI1cYl6yZH/1/ZyIq/NtstbNPu3aRKeUt3txVatPH2ktPRAAoUIsIAH2kpmrCq881MqDJmEPDQ+S0v5v9rmq1TyK3EmmL2Kuv6KBDszHj3/g5t/Hb8LJmY1qR2OijilfffZqtJmVkZ014DM6j7ipTcY65qcz+fiLJRm2ZhzUbNzv88/z/4dj86a4yHYc3cxFX3XLtzMz3nTrLnYFC7iDyuDUb1yhEAChQiwgAfcTj9lCbdC+RZKPKbG1sA4qzE9lGQrpr3m7zjBOz+a/ctmzlC5qNeSmULUpKTs8/i5LJXG5o8/aTdXfXaTLmub2cRF+9xFomunpwfjEXMVXs0WaVamR0wruytSRFkzGtSlRsHNs4ObQrYtq1LoTzgld9XpPxjEYEgOrYfp1jPiACQD/IXsI5Tzl7tVmlStm3hIOexc9qMp6VSY9lT7W2kAc1GW9wZJT67bdzHlVljiZjWhW3R6YSOxcx1afs12TMmOUv8+/u1l9oMp6VObGd/x/XLHtGk/GKSgq9FiVa5sRakZKGbu//Y0+TNi33jod8iwPAQ9YygB5HBIDqOD7liAJQC6AXwDHzZBmKCAD9IHkbr1JdWv41TcZLX/kSkWSjrK3a259Yjea2dm8u1VCXeuf//NyLXgNore1PrEhcJP+uFe/6neqxZFmmAsfHeAUwbn5alEwmLilR+V27TZPftXilO07tovmdu0pENOb2ULqdrXba4jeqHq+tf4SKFz7JW8AFxzRQaDwiANSeG8AGy382W4hBiADQD/IST/G2jOMBTcardPAHUVGs9k73VqTKwX1PyxIOqh4r4cBqtudYrK21jFU5v5tXqa5EPqN6rOauPq8B8khzuXpxFqeuY8BrtTPacEn1eLFK7mrhxpfViwsCjkS+yjcbW9U7JcQV1NCY/SYuAOlt0ECd8YgAUB8eAdBitgiDEAGgH3R1d3n7U/a1qsul6u3p8Y7V01KrkUJrk7b8O7zFvl19LlXCqpd5tXaz2KIkIrqYwatUA9Idqk2bU1MSuIWWBmMFA7IsU7r0Gc0MoXND/51vhM6s1UCd9Tnw1iZeAVz8lOqx9h8+yJ/fYdoVRBmNCAD14XkAHWaLMAgRAPrJ+KpdceweVePkp3IlWofjXm2EBQGJe7jir2Sp+uTs4hC21yk/L7YoiYi6+odo2H4rB4GNJarGit41vpqoXWWm1Tm5kvuFV2z6gapxeoec1KfkvPVW52qkztqcu1jAOYDSjUQj6r6z9qz6M+fCrtOu2MxoRACojpVTjlUADoD999aZqMtIRADoJ2kr/4tIslH2ll+rGidlt4P9/yK/rJEy63PpYjzfnausiu7qG/Da6/Q3iS3KcQpC2Pz28vk3VY0TG8n/B4p3itzVcU4d3EYk2ah5kbpVqpycTCLJRk6Ru+qlrnOI6hc+yFvsFXF+jyPLMp2V2G6q+VSohgqNRQSA6kiYcsSBA8CfAfj/TNRlJCIA9JOUA8t4lWrxM6rGuRj5IgeSO/+ijbAgoG9w0Bu4ddf774uYnR6nSSAZbMSt+infdGx+1e8xZFmmEokrimuTRe7qOGn5pZqsUl3Yv4YN5xcLe51xZFmm89Jz3Lv3dITf49R1DlHNwoc5kLwco6FCYxEBoEAtIgD0k+KcFF5Zku4gWYWJaL30COf5JFuzEk0vSpSt2+LoLX6PEfcWbyWXabCVHEzEHVzHwUXEx/0eo7a109ujdrSjRjtxFqd7cJQa7A/wFnuZ/6tUMSte5sKwLdbrUasnB1ZxZ5TaDf53RonOLJ7oLTzcraE6YxEBoEAtIgD0k+HhEW8FZFtNkV9jtLe1eD+IBrvbNFZobZJWv0Ik2SjvzZ/5PUbyMjbmzd/xew2VWZ/8/Fxle/EWorFRv8ZIio/m/DTH3WJ1dQrxoewTWnMi3O8x8hV7narYrRoqsz6HDu1lT89w/3su79vL7TzbI57QUJnxiABQHZcA5E1z5AJIA7ALwLOmqTMGEQCqoDT0Y6r69+bEcWuuppD3aazM+iQeXssFBhGf8Ot6WZapQuLWXFeStDE9DhaGnC7qsd9JJNmos+KiX2NEb+MuCpeXf0ljddbn2No/caegtf71XG7pHvAW6gw3z+/WkFNJLKz0+oTSQLtfYxxY9hoH6Ju/r7E6YxEBoDoiwKbPKQBWKEey8txqABcAeAB83SyBBiACQBWkrvkJ5+9t8m+VKnnb67zKteJFjZVZn6KCbK+Bs+zHKlVze4fXXmeky5o+X3qSE/YM57CeXOnX9fFLuItCyZ4/ayssCDh1gi1GusIe8ut6Ya8zMx0DTrqy8FE2ii8+4/P1bo9MCfbPsY/rhdU6KDQOEQCqYxOAhdM8/w8AW5THIQByDFNkPCIAVEHaUV6lKl/kX6J29hKuRMvep01LuWBiZNTlNdVtvZzp8/UX408p9jr36aDO+sSu41WQwnW+25W4PTJV2B8nkmzUkHFUB3XW5mJZnffmg/pbfb7+rGKvUynsdablbMgLbOFydKHP115u6aMOpb+yu873z5VAQgSA6ugF8NA0zz8EoE95/CjYFiZYEQGgCi4X5fA2jXQryW6XT9fKskyt0n28RZl5TieF1uZSGBvhFpxc4/O1cdsXchHJiud1UGZ9Ek/uYMPi8A/4fO2VhhZvgOPubdZenMUZcI5R+UIOkPvyT/p8fcxSbtdXskvY60zHwbV/40KQN3z/vx2VlOHtr0yuEe3FGYgIANXRBuDH0zz/Y+U1AHgcwW0KLQJAFYy6xmhAMWttKs/y6dqGumr+ArXfSM6hXp0UWpvEdb8gkmyUu/5ln69NW8KrBPl7/669sCCg7HI5//5JN5I8OujTtQnnT3D+YIg2rRCDkejwb3Ce2UHf7J08HplK7GyvU5+yTyd11ubICc6d7gu91+cCpP3bV7H/39Kn9RFnICIAVMc/AAwDWAPgh8qxBsAQgL8r5/weQIwp6oxBBIAqKQznVaq8E761fsqMfovvYkOf1EmZ9Uk9sZkrIcM/4tN1Ho9MdXb2+arNPK2TOmvjcnuo1X4v37wUxvt0bfTmv3Pqw6r/1EdcEHBoIxu8167yrUimsqmDXIq9zlhnjT7iLE5aaYP3PfK1j++xJS9zYL7Tf3eBQEEEgOr5AYAMAN3KkQHg+5NefyeAd5igyyhEAKiSlPW8SpWz7mXfrtv0G75uzUv6CAsCKsqKiCQbuew3k2d07ts11fX1XnudsYEuHRVam8xFX+I8wCOLfbouKeJrRJKNSg/8Qydl1ufU2Sj2AgxZ4NMqVVzMGV7dEvY6M9I75KLihdyKc/DS3P1TnWNuylzIXXA6U7brqNAYRAAoUIsIAFWSfnILJ2yH+bZKdSniWQ4AD0fqpMz6jI25qdu+gLfDilLnfF3quf28zRP6qI7qrE/cpj9wjuWab8/5mtExD9XY30ck2aglJ0pHddYmr7qVnIpPqNxZOefrTm/hlcOKFc/pqM76nP5/7d15dFRVngfwr3qablstsW2BFqXFjRZtRUe7R21xGXtmHG2XnnZ0xu4x9oyO9jhju0wrTlOVBAi77NgsNkH2RTosQsAghASEQBL2JRJICCGBELKQkKWW23/8XlUqldqSqveer/L9nHNPyHu3Uj9e6lR+dd+9vztMVqGfWBL9KvTdJVWq0X6N/E5OW7+8DhPA+OgB4DoA/QJad8AEMEbFRQd8o1SuKEepXC63qrFfK7ci9uToHKG1FYyQRDl/+bioH+NNbPZO/GcdI7O+3HULlXLY1MnUgVE/5kBxiW901dNwVsforK2p1aUKhv6NbGf41fyoH5eVJnMHDy/i1pDhLJwmifKJiT+P+jGr1m+QRXvJfZSKYfembwomgLG5BVID0B3QPNpXvZRAfmn+7YOAPv0AfA6Zo3gGwFh03J/4Tkj8zQDKAPyhC7EwAYyRy+X2jVKV7smO6jHHiuTWZov9e8rV2qxzhNa25WPtVvnk6Iu2+m5tLhuhY2TWd7y01JfMtTZEtyVW1prFUpondYDO0VlfRtpL8iFv3ptR9W92ulSR/TbZXWhnhs7RWdvyNXKLvTEl+n2+l8wYLu/T4x/VOTpjMAGMzVYA2QCeADAIwF0BTS8lkPqDffzaZX7nLwGwD7L4ZJAWXxWkcLWXDUAlgPkAbgfwIiRZfK2TsTABjIOCtMdklCrK27nbVs6Q8i/D79U5Muvb/nm6Ug6bOpYaXbmSVpdbne7i4obuxu32qDLHTXJ989ZG9Zi102WXi4OTur4Xa3exaNYYGWEd+2BU/fcWn/TtcuGpr9A5Omv7qqjCtxWnivIW+5oRz0tCvuhdnaMzBhPA2DRC6vwZrQTA78OcfwIyAtnb79jrkNqEPbTv34AsWunh12cUgMOdjIUJYBxsmfGWJIBRLujImfpfUgB6apLOkVlf6fEiWcxh76laLpyP2N9b3sTp6Nnp8ibd0fZRT8oq9oWOqPrnDJd9bg8tH6ZvYAlg1cZsGel3fF+pKOqEZq5ZKgsUUm8yIDprq29qVflD71HKYVP1eQsi9m9odvoWjtTuWmZAhPpjAhibnQB+ZsLzlkBG76oh+xH/H9rf3k0FsDvgMf0hv+i7te8/BZAR0OdRrc9VnYiFCWAcbF83v1MlXfYNe0D+6K6cqnNk1udxu1WV43pZaJO/MWL/7Iw/y+9i+CADorO+TbOHyEKQ8c9E7NvY4lSn7FK8vHpflgHRWdu+snOqVtvNxlNeGLH/6mkyunpkctf2EO5uVgz/V5kHuDBywey8I2XKae/ZpdIx31RMAGPzGIBtAB4BcDXkIvo3vbyjPeedkJG9GgAf+Z2fCWB9wGO+C/lFP6F9vwHAjIA+A7U+t4V57m+j/f+xL5gAxqystNhX1LmlMfy1bGlpVQ3aSrTyI/kGRWhtBSN/rpTDpvIWp0XsmzXlDUlopv3agMisL+/LFbKiNyXyvrX5e/f5RlcVR1cjanW5Ve7QB2VLwk0fR+yfM0xe50V/4dzVaMz/00h5Hx0/OGLfv2Qsl9G/1BsSprwOE8DYeNC24CPWRSCj0HFhR2ALdbv5FQBOSHIG6JsAJgeLjQlgbPy3dTu6c33YvgcLt2obvfdSHpfToAitLXfWO3LLfMLzEfvuTr1f5qh9ztHVaFRWVvoWgjTWhN+3NnPJxzKJPu0eg6KzvqWjX5UR6U/CT/eobWxRp+39lHLYVM2hzQZFZ23LMrOUcthUc3IvpSK8ly6Z9AeZ/zflFwZFpz8mgLF5OELrjGsgCV641iPEY2+H/BIHaN/reQuYI4A62TlK5kbtWpgatl/uQvnUemAkN3qP1q4vpK5fWcptYfudq2vwTQyvLd1vUHTWV+L4kZQeyQlfVHfDR6/Ia3fmfxgUmfUtSJ8uq6ZH3R2239b8wrY9alsajQnO4nYeq1Ln7b3kFnvFvpD9PB6P2pj8uLyHrE6c0VUmgPq5w8Dnegky4uhN3LyLQHr59XkNsgjEO0roXQTyLb8+aeAiENNsmf2+Ug6bKvwo/PydHWOlzlfen98zKDLrq6w81TZKVV0esl9ertT5qnX0VcrtNjBCa/tKe03uSg9dVNfj8ag9yffJ1nxZswyMztpW5xYo5bApt6OnUs2hFzGtmj9F5rONZGWAaDW1utT2oT9VymFTZ7Jnh+xXUnVenbFfJ6OFxdEXlP+mYwIYX1dAEq086FcH8H7ICuC7ANwISf7OAJjr18dbBma91u8ftD7+ZWCuhCwk+RQygvgCZFUzy8CYZOdGmWNSnhK6PprH41HlWtmNw1tXGhid9RU57pDSOZtCF9XdOEeKwx4Y+48GRmZ9m+eNkNvmox8L2afszDnVbP+e/BGtLDIwOmsrqqz3LZxxHQtd9H31mCSZ//fJqwZGZ30rR8uo9Ndhrltmdq62GvtqpZyJU3eVCWB8DIYkYA0AiiDz+e7T6bnuAbAdQC2AJgAHAQxB28ie1w8BrIXU9qsCMA7hC0GfBPB+F+JhAhgnlZUVvlGqhnPBa3iVlRT5Fos0na8xOEJr2zju10o5bGrf7NdD9tk26ikZhV0w1MDIrC9/R7Y2L7V3yB0Stnwpe9TWco/aTnG5PeoLu9x+rFg7OmifFqdb5dvvlVvFW+YYG6DFZcyfKrUWR4beinPZ7FEyujr2ZwZGpj8mgF3XB7L7xtcATgOYAlmIMdDMoEzABDCOjibLKNX+rHlBz29fOVPbN5iT6Dsrc9EUbQFC8Dd6p8utTtn7y4T7/EyDo7O22vNNqt7eWymHTdUV7wraJ3PWH2XkevwTBkdnfUsnvC3FtqcH33O5oPhU277BVRxd7Yzcwv3aLfYrlboQfDebdSNk3+CjCxKjALQXE8CuWQ2ZT7cQwJOQW64AE0CKUc7Ef5fVqh//Z9DzWyf/Vub/Teck+s7atVfe6F2OnsrTVNvh/OEjB30Fo13NLFHSWXmpg+UWZEbwUapcrQD0gcUcXe2sjBULpMDzsFuCnl+VIdvr1SRQiRKj1DW1quKhA+T6FXacVlPf1KqOaufPBTlvZUwAu8YFqbt3S8BxJoAUk63aCN/xYcG3LStKuVsph03tXveJwZFZX7PTpU7Yb5bbPXmrOpzftHiiLFAYwUn0XbFmupTJODLhnzqcq66/oGrsP5A/oocTZxK9UQqKSnxFiN3VJR3Or57wO0m+p/2LCdFZ37oRv5IRvvkdC0Ln7D7km5qjGqtNiE4/TAC75m8BzAJQD2AHgDcBfB9MAClGJ8tKfW829VUn2p2rPFXm2+fzXGWpSRFa25bRv5QEOv3tDue2jn5G5v/N6XiOItu8aUPbPMCAbctys9dr5/pErLdGHbU43apAm+N38otp7c45XW5V4JDV1cc3TDcpQmtbNucjmWM5smOpnaVz5INhRVp0e4lbCRPA2FwG4LcAcgG0Qlb+vgVZDdxdMAGMs0Mpsj/l7pVT2h3f9pnMYSsexi3Kuipr0QSZBxiwzVtTS6uqtveVid4FG0yKztrO1jWqc/Zr5QPKwU3tzq2d9q7s//vRk+YElwAyJv6PrFad/Gy74/kHv1Yu7YOh8+xxc4KzuI0Fh3zX0FPT/sP1hmFPy/vugsT7YMgEMH4GABgDoAKyOneVueEYhglgnGXPkAnfu8e1rzifN0beiHbM/r1JkVnf0ZJS36208xVHfce3Z6/1jV55nC0mRmhtX6bJKOrBOb/zHXO63OqgY5AkL2unhHk0hZOZuUbqWCb3Vqr1gu/46rljZWQwLXyhaAqtscWpdtllFPVUVtsOQMdO16lq7UNNw5HE212FCWD8XQLgWTABpC7as2OTUg6banJcrZrqZc5JzbmzqlHb/7e4cJOp8VmZx+NRhSkPyErrZcN9x7MnyOKbPZM4hyoW65bNlsUKKTf6CmnnF+b79v911p8xN0ALq6hpVGX2G6Vo8VeLlFJKud0elZP6d7K6etEQkyO0tmUTZbvIsvEP+459tnSufFhM6ZuQUxeYAFKsmADGmdvlVsXJt8t8tM/GKaWU2rZEPuWXpgxUHu5QEZMN6VK0uDx1oFJut6qtq/fd/i3elmF2eJZ24nS1rxzMmfzVSimlMifJAoUjY0IXiaborBon+wIXT5RSOnmFe3y3LptOht7KjCLL3Jbfdiv9dJFyuz3qy1RZuX40/Q2zw9MFE0CKFRNAHWSnO+R2RMqtqqH2rDqRLHutbp/nMDs0yzt1usqXpBzfslBtmjNUEpbkG5UnYPECdd7asbIjRfGYwaqsvFzV2ftIbcWcxWaHZnlZW3J8C8Hqj+5QmWNl5Pro2EfNDs3ymp0uleN4WF6rs3+jsjZvUq32q5Ry2NSF0kKzw9MFE0CKFRNAHZytPqsqHTe0lR9w2FSVo586X5tYZQjM8sWk19tdW+Wwqb2rOD8tHgr371ct2h9Obysbdgf3Vo6DVpdbfTH86Q6v3YpdHcsaUectWbHCl2B727HJv4j8QItiAkixYgKok21rP/UtWHDZr1QF64PvDkKdV11bpw4lD/K9ye8f/bhyOzn6Fy8Zn6T5ru15R29VcWib2SEljML9B1SpVs9SOWxq/0zu/RsvrS63yhj1su/a1iRfr5qqOtZdTBRMAClWTAB1tH/3DpU98x1VtHe72aEknDNnz6rsxePVruVjlbOVK3/jyePxqK0bM9SWecPVqeL9ZoeTcI6VlqqNs4eofRsXcmQ1zhqaWtXGlZ+qren/ry7UnDY7HF0xAaRYMQEkIiKyGCaAFCsmgERERBbDBJBixQSQiIjIYpgAUqyYABIREVkME0CKFRNAIiIii2ECSLGyAVBlZWWqrq6OjY2NjY2NzQKtrKyMCSDFpC/kBcTGxsbGxsZmvdYXRF1wEeTFY9OheZNLvX4+G68zr3PiNV5nXudEanpf576Qv+NE3yg2yAvfZnYgCY7X2Ri8zsbgdTYGr7MxeJ2pW+IL3xi8zsbgdTYGr7MxeJ2NwetM3RJf+MbgdTYGr7MxeJ2NwetsDF5n6pa+DSBZ+0r64XU2Bq+zMXidjcHrbAxeZyIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiIiL65vlvACUAmgHsAPATU6NJPEMA7ARwHsAZABkABpgaUffwAaSkw0SzA0lQfQHMB1ANoAnAPgD3mhpR4rkEwDAAxyHXuBjAUHA3iVgNBrAawCnIe8SzAecvApAKoAJy3bMA3GJkgERGeAFAC4BXAAwEMBNADYBeZgaVYDIBJAG4HcBdAD4HUArgMhNjSnT3Qf5o7gETQD1cBfnQOAfygbE/gL8HcJOJMSWiDwGcBfAkgBsA/AryQfJ/TYwpETwBYDiA5xA8AXwfQC2AZwDcCWAlgGMAvmNgjES62wFgqt/3FwMoh4yekD6ugbzpDDY7kAR1OYAiAI8D2AwmgHoYBSDH7CC6gTUAPgk49hlk5JXiIzABvAgy8vee37ErIXfIXjQwLiJd9QDgQsdPP3Mhn3hIHzdD3nTuMDuQBDUXwATt35vBBFAPByHXeBlkWkMhgFdNjSgxfQgZab1V+/4uAKcBvGRWQAkoMAG8UTs2KKBfNoBJRgVFpLdrIS/0+wOOj4GMDFL8XQz5VJ9rdiAJ6kXIXDTvrZrNYAKoh2atpQG4G8BrkLlSL5sZVAK6GDLa6gHg1L4OMTWixBOYAD6gHftBQL+lAJYYFRSR3pgAGu9jyCf660yOIxFdDxkdudPv2GYwAdRDK4BtAccmA/jKhFgS2YsAyrSvPwbwG8iiGyba8cMEkLol3gI21lTIm3l/swNJUM9C3rhdfk1BRk1ckBWVFB+lAGYHHHsDMn+Y4qcMwJsBx/4I4LAJsSQq3gKmbmsHgCl+318M4CS4CCSeLoIkf+VgKQE9XQGZV+nfdgKYB863jLeF6LgIZAI6jgpSbKoBvB5wbAhkkRPFR6hFIO/6HbOBi0AoAb0AeWG/DOA2ADMgZWB6mxlUgpkOKSnwMIA+fu1SM4PqJjaDt4D1cB9kTtqHkEVN/wagEVycEG/pkA/k3jIwzwGoAjDavJASwuWQEb5BkATwbe3f/bTz70P+Dj4NufWeAZaBoQT1JuSWTgtkRPCn5oaTcFSIlmRiTN3FZjAB1MtTkAU3zQAOgauA9XAF5PVbirZC0MMh03eo6x5B8PfkdO28txB0JeT1nYW2ldhERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERERKSnRyC7CPQ04bm9OxjURtn/Eb/HZOgUExEREZGlhdrGz9uSIdty9YFsH2VGfEkAekXZ3xvrEjABJCIiIgqqj197C0BdwLHLzQsNgCSAz3bhcelgAkhEREQUURKC32p9BO1vAXv7PQXgCIALAJYD+C6AlwGUAKgBMBnAJX4/59sAxgEoB9AIYIf2s8MJlgDeBWATgPMA6gHkA7g3oE86mAASERERRZSE6BPAVgAbANwNYDCAswDWQ269DoQkhy0AXvD7ObMAbAXwEICbALwHoBnALWFiCpYA7gcwD8CPtMc+D0kK/aWDCSARERFRREmIPgFUkCTO60+QUT3/W8aZ2nEA6AfABeDagJ+dBSAtTEzBEsB6yEhjOOlgAkhEREQUURKiTwAbA/qkADgQcGwugBXav5/UfkZDQHNCRg1DCZYAJmuPywLwAdonol7pYAJIREREFFESOjcH0F8ygN0Bx9LRloS9ABkBHADg5oDWJ0xMoRaB3Argbcht6BYAz4V5biIiIiIKIQn6JYC3aj/joU7GFM0h++s6AAAAyUlEQVQq4EUAVoV5biIiIiIKIQn6JYAAMB/AcQC/BNAfwE8ADIHcHg4lMAG8FMBULaYfAngQwFEAoyM8NxEREREFkQR9E8BvQeYKHoesIj4FmSP44zAxBSaAPSAjficgt37LAUwB8J0Iz01EREREFsFC0ERERETdjALQBOBklP0fQtvqYiaARERERBbkXSncP8r+lyK61cVEREREREREREREREREREREREREREREREREREREREREREREREREREREREREREREZAV/BV2jtJmzuhBPAAAAAElFTkSuQmCC\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"fig, axes = plt.subplots(2, 1)\n",
"axes[0].plot(times, np.rad2deg(simple_pend_state_traj[:, 0]),\n",
" times, np.rad2deg(robot_pend_state_traj[:, 0]))\n",
"axes[0].set_ylabel('Angle [deg]');\n",
"axes[1].plot(times, np.rad2deg(simple_pend_state_traj[:, 1]),\n",
" times, np.rad2deg(robot_pend_state_traj[:, 1]))\n",
"axes[1].set_xlabel('Time [s]')\n",
"axes[1].set_ylabel('Angular Rate [deg/s]');"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Matches again!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Mimic ideal pendulum balancing\n",
"\n",
"The ultimate goal is for the robot controller to behave like a simply controller ideal pendulum. So I can take the above analysis one step further and make the robot behave like that system."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"\n",
"def simple_pendulum_state_equations(x, t, g, l, k_theta, k_omega):\n",
" \"\"\"\n",
" x : array_like, shape(2,)\n",
" [theta, omega]\n",
" \n",
" m * l^2 * theta'' = m * g * l * sin(theta) - k_theta * theta - k_omega * omega \n",
" \n",
" \"\"\"\n",
" return x[1], g / l * np.sin(x[0])"
]
}
],
"metadata": {
"anaconda-cloud": {},
"kernelspec": {
"display_name": "Python [default]",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.5.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment