Adafruit_Learning_System_Gu.../Jupyter_USB/MLX90640 Thermal Camera.ipynb
2019-12-24 16:07:54 -05:00

1765 lines
154 KiB
Text

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# MLX90640 Thermal Camera with CircuitPython\n",
"[Click here to visit the guide for this notebook!](https://learn.adafruit.com/jupyter-on-any-computer-with-circuitpython-and-mcp2221-ft232h/thermal-camera)"
]
},
{
"cell_type": "code",
"execution_count": 48,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Requirement already satisfied: adafruit-circuitpython-mlx90640 in /opt/anaconda3/lib/python3.7/site-packages (1.0.1)\n",
"Requirement already satisfied: hidapi in /opt/anaconda3/lib/python3.7/site-packages (0.7.99.post21)\n",
"Requirement already satisfied: adafruit-circuitpython-register in /opt/anaconda3/lib/python3.7/site-packages (from adafruit-circuitpython-mlx90640) (1.7.1)\n",
"Requirement already satisfied: Adafruit-Blinka in /opt/anaconda3/lib/python3.7/site-packages (from adafruit-circuitpython-mlx90640) (3.2.0)\n",
"Requirement already satisfied: adafruit-circuitpython-busdevice in /opt/anaconda3/lib/python3.7/site-packages (from adafruit-circuitpython-mlx90640) (4.0.1)\n",
"Requirement already satisfied: setuptools>=19.0 in /opt/anaconda3/lib/python3.7/site-packages (from hidapi) (41.4.0)\n",
"Requirement already satisfied: sysv-ipc; platform_system != \"Windows\" in /opt/anaconda3/lib/python3.7/site-packages (from Adafruit-Blinka->adafruit-circuitpython-mlx90640) (1.0.1)\n",
"Requirement already satisfied: Adafruit-PlatformDetect in /opt/anaconda3/lib/python3.7/site-packages (from Adafruit-Blinka->adafruit-circuitpython-mlx90640) (1.3.8)\n",
"Requirement already satisfied: Adafruit-PureIO in /opt/anaconda3/lib/python3.7/site-packages (from Adafruit-Blinka->adafruit-circuitpython-mlx90640) (1.0.4)\n"
]
}
],
"source": [
"# Set an Environment Variable so Adafruit Blinka knows we're using the MCP2221\n",
"import os\n",
"os.environ[\"BLINKA_MCP2221\"] = \"1\"\n",
"\n",
" # Python Software Package Installation\n",
"import sys\n",
"!{sys.executable} -m pip install adafruit-circuitpython-mlx90640 hidapi"
]
},
{
"cell_type": "code",
"execution_count": 49,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Found 0 broken pixels, 0 outliers\n",
"MLX addr detected on I2C!\n",
"MLX refresh rate: 1 Hz\n"
]
}
],
"source": [
"import time\n",
"import board\n",
"import busio\n",
"import adafruit_mlx90640\n",
"\n",
"i2c = busio.I2C(board.SCL, board.SDA, frequency=800000)\n",
"\n",
"mlx = adafruit_mlx90640.MLX90640(i2c)\n",
"print(\"MLX addr detected on I2C!\")\n",
"\n",
"# Set refresh rate\n",
"mlx.refresh_rate = adafruit_mlx90640.RefreshRate.REFRESH_1_HZ\n",
"print(\"MLX refresh rate: \", pow(2, (mlx.refresh_rate-1)), \"Hz\")"
]
},
{
"cell_type": "code",
"execution_count": 53,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"24 x 32\n"
]
}
],
"source": [
"import numpy as np\n",
"\n",
"# read in frame from thermal camera and split into 32 x 24 numpy array of thermal readings\n",
"frame = [0] * 768\n",
"mlx.getFrame(frame)\n",
"pixels = np.split(np.asarray(frame), 24)\n",
"# rotate it around so its right side\n",
"pixels = np.rot90(pixels, 3)\n",
"print(len(pixels[0]), \"x\", len(pixels))"
]
},
{
"cell_type": "code",
"execution_count": 54,
"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",
" fig.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 / mpl.ratio, fig.canvas.height / mpl.ratio);\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 overridden (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",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\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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\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"#%matplotlib notebook\n",
"import math\n",
"import time\n",
"\n",
"from scipy.interpolate import griddata\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib.animation as animation\n",
"\n",
"grid_x, grid_y = np.mgrid[0:31:32j, 0:23:24j]\n",
"\n",
"plt.figure()\n",
"plt.pcolormesh(grid_x, grid_y, pixels)\n",
"plt.colorbar()\n",
"plt.title(\"Original 32x24\")\n",
"\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 43,
"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",
" fig.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 / mpl.ratio, fig.canvas.height / mpl.ratio);\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 overridden (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",
" event.shiftKey = false;\n",
" // Send a \"J\" for go to next cell\n",
" event.which = 74;\n",
" event.keyCode = 74;\n",
" manager.command_mode();\n",
" manager.handle_keydown(event);\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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAgAElEQVR4XuydC5hVZfX/15wZGAaQUVTMEhURMUVNzVQ0ywCvGZal/PprYt4xK/MOKhCIF8xb5i0Lb6F5A+9madw0M/ESSlgoKiUmgpqAwzBnzv9ZG/d4gBnY3/2eOc6Z89nPw9Pv56x13r2/a73v+9nrfffeFblcLmccKIACKIACKIACKIACZaNABQBYNrHmQlEABVAABVAABVAgUgAAJBFQAAVQAAVQAAVQoMwUAADLLOBcLgqgAAqgAAqgAAoAgOQACqAACqAACqAACpSZAgBgmQWcy0UBFEABFEABFEABAJAcQAEUQAEUQAEUQIEyUwAALLOAc7kogAIogAIogAIoAACSAyiAAiiAAiiAAihQZgoAgGUWcC4XBVAABVAABVAABQBAcgAFUAAFUAAFUAAFykwBALDMAs7logAKoAAKoAAKoAAASA6gAAqgAAqgAAqgQJkpAACWWcC5XBRAARRAARRAARQAAMkBFEABFEABFEABFCgzBQDAMgs4l4sCKIACKIACKIACACA5gAIogAIogAIogAJlpgAAWGYB53JRAAVQAAVQAAVQAAAkB1AABVAABVAABVCgzBQAAMss4FwuCqAACqAACqAACgCA5AAKoAAKoAAKoAAKlJkCAGCZBZzLRQEUQAEUQAEUQAEAkBxAARRAARRAARRAgTJTAAAss4BzuSiAAiiAAiiAAigAAJIDKIACKIACKIACKFBmCgCAZRZwLhcFUAAFUAAFUAAFAEByAAVQAAVQAAVQAAXKTAEAsMwCzuWiAAqgAAqgAAqgAABIDqAACqAACqAACqBAmSkAAJZZwLlcFEABFEABFEABFAAAyQEUQAEUQAEUQAEUKDMFAMAyCziXiwIogAIogAIogAIAIDmAAiiAAiiAAiiAAmWmAABYZgHnclEABVAABVAABVAAACQHUAAFUAAFUAAFUKDMFAAAyyzgXC4KoAAKoAAKoAAKAIDkAAqgAAqgAAqgAAqUmQIAYJkFnMtFARRAARRAARRAAQCwneTA1VdfbT/5yU9s++23t5dffjnoqkaNGmWjR4+2XC4X9DtpnGfPnm133XWXDR061Lbccss0P9GiT9Lr8rZvueUW69q1qy1YsCD63/zjzTfftF69ekX6jBw50vx3/ZgyZYrtu+++dvfdd9t3v/vdZs9j6tSpkc0555xj48aNW8Xmtddes5122skOOOAAu+eee5r1r6ioSKTJn//858huXeeT6MfaoJHrkK/92k7xf//7n/3yl7+0SZMm2T//+U9bvny5bbrppvaNb3zDfvSjH9kuu+zSBq+wOKd066232umnn26vv/66rbfeelGjI0aMsEceecQ8z5ctW2af//znbeDAgdF/32KLLZpObObMmfbb3/7Wpk2bZm+88YZ17tzZdthhBxs+fHikrXpks1m76qqr7PHHH4/GsMWLF0ftDR48OOov66+/fos/6ePGzjvvbPX19fa3v/3NvvzlLzfZnn/++fbwww/bc889Z5lMRj0t7FGg3SoAALaT0H7pS1+yl156KbqaZ555xnbffffUV/bvf//b/N8ee+yR+jfSOjr4fO973zMHmK9//etpf6ZZPwUAJ06caJWVlXbNNdfYscceu8rv+e9cccUV5mChAqD/0E9/+tPod59++mn7yle+Ev12Y2Oj7bPPPhGgvPLKK7bxxhs3ew0e2/xjzJgxkVZPPvnkKv99u+22s+eff77sAdCher/99rN3333XTjrppCinHOgdWPxGw0Hngw8+sNra2oLmWin8mMPdNttsE+XjGWec0XTKp5xySgReX/ziFyModLgaO3ZslKOemxtuuGFk6z5+Q/P9738/unFZunSpXX/99ZGmfgP1gx/8QJJhyZIlEWz+3//9nw0aNMg22mijKIe9bQd2B7iampo1ftPBca+99rL58+fb22+/vQYAfvjhh9HN5OWXX27HHHOMdE4Yo0B7VgAAbAfR9YFxt912s4MPPji60z3++OPtxhtvLMkraysA6OdxyCGH2FtvvWVPPfVUk5Ze9fPqn0PFr3/961QA+PHHH5sDu1cjXnjhBevUqZNdeumldvbZZ9u9995r3/nOdxLHzquVfq4+ea5+JKlIJm5oLYYOEl79KeaRpALoYOBVIa9keQz79eu3xik++uij9rWvfa3o5x+iVaH0vu666+xnP/tZVOVeW3XNz9V1Ouigg+w3v/mN/fCHP4xO36G6R48eq1yKa+4VVYfBuXPnSpfpvg7jMWDGzvGYcNttt9mRRx65xm9edtllduWVV9pZZ50VrYKsXgF0h1NPPTWqLM6ZM8eSVtGlk8cYBUpQAQCwBIO2+imffPLJ0Z33rFmz7MQTT4z+95133lllUvOKh4PL+PHjI/DwJbGFCxdGSzZezcqv9jVXKfM7aJ9AvYriSyo+kPp/89/75je/aTfffLNdcsklETD5MvS11167yjKMQ6oP1F7B+u9//2ubbLKJ7bnnnnbxxRc3LSv5bzR3hz5hwoRoSdiPP/3pT3bRRRdFg3xDQ0M0wf/85z+3AQMGrCKLg7AvWf3jH/+Iqgpe1XBISrK0HUOVLxk66Pm19u3bN/r9P/7xj9F/8+pd//79UwGg/85f/vIX23vvvaMJyydUX7LyZePbb79dysgkAOjVTF9Scx1dA686/upXv2q6prjBJNrGueHLf76E/cQTT0QA6xARn4vH2q9rxowZ1q1bt+j/9iU8j71XjRx6v/CFL0TxOfroo5uu1/PRK6oOrp5HDpWecx6zr371q6vokgQAHaZdU88Xb39dhwPLhRdeGJ33f/7zH9tggw0imPHr9H4SHzFY/+53v4uq7r6M+tFHH0XV1ptuuik6b19Wve+++yIXv5Hw/pa/lcBvJBzA/Ebt1VdfjTT0HPYbga222qqpLa9Yvvfee1F/8mt48cUX7Vvf+pbdeeed9vvf/z4CMu/vDk7eH3251Ptnly5d1nW5tuOOO9q2224bVULXdcQ3mUkqe57Pro0vtfvxr3/9y3bddVfbf//9o+0R8eFVa6/0+ZKxV7JbOjwXvCLpcTj33HNXMfPf9uqj6+FLxj5+NAeAzz77bLQq4vmaZnl6XfrwdxQoRQUAwFKMWt45ezXJl0d8KccHOZ8QjjvuuAjI8ifXGAB9kvBB30HOD58sfLl33rx5TctgLQGg36F7pcAnbl8y84nZl2h8UPaB1Sc9n5i9kuXLLv6b8ZKN38X7ROXA1r179wgYfAL05SX/58s9DgA+gfqE4IAS783q3bt3tCTqcOTLSj7J+f926NDBbrjhhqg68Yc//KEJAv1cfLJxwPQKh5+3T6wOnj6ZrGtvYwwyPqk7NB9xxBER3PoxZMiQ6NwdLvyc0iwBx+FznRyKfXLzydIhzaFDOZIAoMfcl8h8qc6Xrb3d6urqCI59mduPpNrGueHn7Fr43jCv9nhM/FzuuOMO83h5fvkytMOng6fniGvmbW+22WYRED300EPRsp7DgR8OQr4HzCtyn/vc5yJYdQh3f49p/paAJADoN0MOWH6dnvPrOnwv2wMPPBDljcfWgcKBx3PLoTW+CYgB0DVw6HMdvH853HolvqqqKoISv1FwP8/nYcOGme/TjY8TTjgh6qM//vGPIwjytvxG5v3334+g0m+Q/PBr9n7jQOcVLgdiv4Hz7QK+NOpQ6X3f/+43Kp6nHu/VtwSsfu3e53v27BmBpd9ANnf4DdaKFSui3/UKmvdPB//V98Tm+7pPvHTsY0N8OKy6Th5fv2a/QfUquMfFYxvnYXPnEd8Y3n///RH8xof3Y9fHtXKIje2aA8B47HLdf/GLX6wrFfg7CpSFAgBgiYfZl0UchrwC6BOeT5oOhA5aPqHFRwyAXsnwSSkecH2w9IqQT9w+QPvREgD6ko/fcXv1xg+fqHwQ9/a8ehIvA/pAfeihh0aTqVc/mjt8QK6rq4sGb7+z90nBj5aWgH3ZyycsBxn/3fjwfUkOig40f/3rX6P/7NVM3w/k+7+8suKHw5xPjD7RJgVA19K1cMj033N48mqi//++3B4KgH79DjoOy37dhx12mJyNSQDQl+68IhofXoU5/PDDoyqka6VoG+fGBRdcEN0A5B/xwzP5y9gOBK6Zw4MDgeelHx4HXz706mBLE7LniMfKH4rxSmJcUXP/JAB44IEH2mOPPRblmeeHenj7nl9e0fYqt+8h8yMGQM/t/Fw87bTToqVIz2UHnfj49re/HfXFRYsWRf/JK6EOmX7dfoMSHw5lDnMOW/ENhwOO77NbV+XKdfLz9cq0A7T3Ta/wtXQ4MPmNTUv7hR3QvF/Hh1fPXH+P5dqO8847L6qiTp48ObopyD8cgv0G1a/HbyL9hscrmvntrP7bXon1GwTv+96/8x/i8H20nocO+D6OrA0A/Xe94u75uPo+WjUvsEeB9qIAAFjikfQJwit/XpWKN7L7EoxXTfyBgj59+kRXGAOgLyP5klh8eOXJIcmXYr0640dLAOiDv08w8eFP3PnE6pu2vdITH96uV0u8yuNPWfrhMOXLPA4Hfi4+WcWHV4u8GuhHSwDoy5NeKfG/rz6x+KTjFT6HPD8cFnyy8fbzjxhQFACMn/h1qPXz9onLJ0eHplAA9Gv28/RJzfdtOsSrRxIAjG8O4t/2SptXXnzZzCEgqbZeZYpzoznA8HPx5VDXJgZvb9OXyl0736Cff3g++d/yn3j2c/WqnVeF4yVE9/Hz9Yk+PloDAB0OPI+8Guo3NF79ig+HUK80+xEDoN8IeEUpPvy8/SbMK4Ze/YsPrwB6n/P89OqZ56vf9HgeeTU8//ClbofO+GbG+/ff//73CJhXP/zJXf8tr/b5zVl+XsexbSmfHFQdWP03vMq9+uFaOJx5DFx318U192tvCdi8eu957CsBXtle/fDfcvD13/Oxw+Hc+3RLh1+zV1hdJ79ZyV8a937p1VC/jvghrXUBoO+t9Rtev5njQAEUMAMASzgLfJLyioFXjvyBhPhwSPMKVT7s5e8BzH/iz31Wn0zXtgfQl+3yD/f1/XV+Nx4fzbXlSzdexfAlZ18mc0hzX69O+T8fvP1oCQB9T1FzG8Dzz8WXd/03vVrgy2MOa/mH6+GVFQUA3d8nqfjJUT93n+h9X1YIAPrE6xUaBwX/X6+m+f5CX1JVjiQAuPpraeL4xHsrk2rrusa54cCx+pPKLZ1LvI9t9dcTxftK45zyCpvDg98QeMXNtwV4pdpzxqHBzzs+kgCgugTslTvfeuA3Ql5F8+V4h3PfUuFbHxx+/Gjp4ZqWACTWzKugfk0OSQ5LLR0OOl699sO1cz9/+jb/8Bsqv8ly0PbldR8HvALvcOOgk79vtrl2HEgdTB3K11aBi329Oumg6Dcs+dXN+O/enuvk/xziW3rQwsHwzDPPjKr2vpzc0uFL4d4XHPQccFevZnp+eEU1hnL/Hb8J9bHIn4r3SvPqT3b7Fgh/EMT7LgcKoAAAWNI5EFcWWroIH9h9QvBJ9LMEQF/i9MnU98v5v/jwioBXlRzs1gWAXlXxKoxX9Vp6PY1PEl618VdX+ERQiAqgn6svj/s5emUmXjYNAcB475JXuXxid20cLH0jv+/3it/HliQ5CwGASbXt2LFjEwDGMJN/jqEA6FDgk3b8DsP4t33pzgFEBUBfsvSbo6QPgXg1zqvLDjP5h+9Z3HrrrQsGgA5sfiMyffr0ZpemvaoeP3TSEjz70rOfq8Oow2p8xNXcdQGg3zB69dKh3Je4kxy+59H3deZDl/vF8Od7jn2JtyX487Z8u4lX7rwSt/oSeHwOMfz5HmK/aYy3DeSfo988OBy2dHgeeX/KP3z88BzyPY0cKIACAGDJ5oAvoW6++ebRQxbNVRO8quID7IMPPhhVUz5LAPS9cz4grz4Re7XFl4h94ogB0M/Xq4X+LjHfwxUfXvHwCpQvN/vG9bUdhdwD6O34HjIHQL8Gn+D8CAHAePktvzLny20+OfryvbIUXAgAVLRdvZpVSAD0vV5eVfSlwfjw5U8HAI+9CoBJXgPj8OvLrl4989eP+Dso8/X3vZPefxyyClUB9FfSONT6gxG+F3NtR0sAGPeT+IYk/g0/f6+irwsAHT79QZLVH6xo6Vx8tcErjqtvrfB+60uw3j+8zZZetOwPCvmT7g6HDn9ejfcldD+P/HeWxvDnFXKviOe/0Dn/3Hwfn/fL/MPzxsHa4+dQ6xrnH14ldfjM30tashMAJ44CBVCAJeACiPhZ/IQDnm9C9wHPnw5c/XBA8cqFQ5Q/SflZAqCfm0+gXgGIn1L0jeAOU/4Us1cyYgD0u35fAvOHSHw50Je4fOnJJ2ffm+Ww6JOcv97DHyLwSpTvR/P/jfcR+sThd/u+v8x/w0HA2/W9RF4RVZeAm4vv2gDQ22yuSuka+ATnD874NXtlMf+I4UpZCi4EAPo5JNW2NQHQq8O+T9SXfF0r36voT8Z6ldj3pKkA6NeV/yJof9rV95T573n1yEHJQcpj4nDvueVQ5vthvZrsS5T+miOvyPmTzYUCQD8vX552zb1S7SDm5+T7eP0VNF79i5/MbQkAffnT9/f6TaDr5k/E+1K+n7M/qLUuAPQ9eL6s7S+Bzv8ijQO37w30/uX90IHOq9L+qiiv2Du8xV8D8RsYf3DM89mr7avDn4N7/PDNUUcdFYGX71d2OPP2vX/6dfhDaX4uPhZ43P3JcL9Jil+SHvcRvznwOLR0rG0PoLfjy+/+JLY/ZMOBAihABbBkc8CfLPQqmS+NtfTVCK+W+STnNj64xu8B/Cz2APrTfP7Ep+/n8cncn+b1/UC+V9EnuRgAPSC+x8j/+Z4+h7f8ycyfpvQN6V758E31DoE+ATkI5X9+zSd23yDvyz3+pK1XLlwD5T2Azb1cOU6YtQFgS0nly1l+Tg65vvS7+gMAvnytLgUXCgD9nJNo25oA6FDg+zYdjH3C9uVGf8rTb2AcvtIAoF+Xb0Fo7lNwDl4OWg4ifviSofcNzx2PvS9Je9XaY+ZHIQHQf8/z2qtgfmPk2wv8oRjvF74XMX41TksA6P7eB/xmw2+AHCD9psLz3M97XQDo/v72AAfG/P2F/qok18B/24HU+6rfSPpeVd9y4pXY+Igfqmop3z3Pfak2fjhk9XNyOPdz9ffy5d+ktvR7+SsFzdmsDQD9k3W+t9RvAONX7JTs4M+Jo0CBFKACWCAh+RkUQAEUKCUF4pc7h346shSu2Zf5vVrqVVIOFECBlQoAgGQCCqAACpSpAv4aIN+ft/rT/e1JDq9sewXTH7rKf5VMe7pGrgUF0igAAKZRDR8UQAEUaAcK+PYQ34vrL6RWnj4vpUv35WXfXrGuB25K6Zo4VxQohAIAYCFU5DdQAAVQAAVQAAVQoIQUAABLKFicKgqgAAqgAAqgAAoUQgEAsBAq8hsogAIogAIogAIoUEIKAIAlFCxOFQVQAAVQAAVQAAUKoQAAGKCiv7vLv6Xpm6db+vxRwM/jigIogAIo0I4U8JfQ+/tL/Z2PLX01pRCX619J8fdqhh7++Ud/GT9H+1QAAAyIqz9Bl/9i1ICfwhUFUAAFUKBMFPAXUvsLtlvjcPjrtUVXe+fdbPDP+0v0/YXeQGCwlG3yBwDAgLD4Fwb8E0Z9TrzAKjsmu0vKZfQGa+fpHTnTkNMbqqiQfSqyWju5Sr2Nhk66T5p2Miu0a4nEEl0aO8gSp3NIEct0DbVNr1ylfl45Pc0s21FzqmhMcV4prsW004pOqrFKPzfVI834l2lQWzH7eCPdp/Jj3ScjDs3Z+jr7540/j746458fbI0j/vb6mzO3tG7rpZhwPjmp/33UaFvs+kb0JZ1u3bq1xqnym5+xAgBgQADijrbtqeOssrr1AHD918RRxszKHQAbq/QZsLJepLk2DIC5jH79FWkuX29G7nFpzisNzACAcmhkhzRgnlkhN2Mfb6z7FAUAl9fZP64Z3qpQFc9Li/7ZKxgAN9xmXqueqx4lPAqpAAAYoCYAaNZWK4AAoE5maUArDTSpXS7NeQGAqspFqgCmqGYCgFos43np3Ve3CAbAHn3fBAA1+UvKGgAMCBcACAC21SVgKoB6x04DsywBazpTASxeBfCdVzcPBsDP9X0LANRSvKSsAcCAcAGAACAAGNCBErpSAUwoVL6ZXgAuzh5AKoBFWwIuNgBed9115v/eeOONKBO33357u+CCC+zAAw+0xYsX28iRI+3xxx83fwBmo402skMPPdTGjBnTanshU/SasnMBAANCDgACgABgQAdK6AoAJhQKAGxSgD2Atfb2q5sFVwA/3/ffiSuADz74oFVWVtrWW28dxeGWW26x8ePH2wsvvGD++hsHwKFDh9p2221nb775pp100km244472j333JMiwXEphAIAYICKACAACAAGdKCErgBgQqEAQADQzOJ5af6cLwQDYM9t/5MYAJvL0u7du0cQeOyxx67x57vvvtuOPPJIW7p0qVVVFeER9BTdqL27AIABEQYAAUAAMKADJXQFABMKBQACgG0EALPZrDngHX300VEF0Kt+qx833XSTnXvuubZw4cIUCY5LIRQAAANUBAABQAAwoAMldAUAEwoFAAKAeQD45pzPB1cAt9j27WjPXv57AKurq83/NXfMmjXL9txzT/OXUXft2tUmTpxoBx100BqmixYtsl122cWOOuooGzt2bIoEx6UQCgCAASoCgAAgABjQgRK6AoAJhQIAAcA8AJw3Z1NbL+BF0B991Gi9tl2wRvL5Xr5Ro0Y1m5T++bm33noretH1vffea17lmzp16ioVQJ8399tvP9tggw3sgQcesA4divV2/BT9qJ27AIABAQYAAUAAMKADJXQFABMKBQACgK0AgEoFcPVMHThwoPXu3dtuuOGG6E/+HeT999/fOnfubA899BCfmEvRtQvpAgAGqAkAAoAAYEAHSugKACYUCgAEAPMA8LU5nwuuAPbe9p2gh0AGDBhgPXv2tJtvvjl6OMXhz5ePH3nkkQgCOT5bBQDAAP0BQAAQAAzoQAldAcCEQgGAAGAeAP7zH5sEA+A2X/xvYgAcPnx49M4/Bz6v9N1555128cUX22OPPWZ77LGHDRo0yJYtW2aTJk2yLl26NMVq4403jl4fw1F8BQDAAM0BQAAQAAzoQAldAcCEQgGAAOBnCID+qpcnnnjCFixYEL3c2d/xd/bZZ0fgN2XKFNt3332bTeR58+bZlltumSLJcQlVAAAMUBAABAABwIAOlNAVAEwoFAAIAOYB4JwCVAC3FSqAKbIUl89YAQAwIAAxAG59zjirrO6U6JeyycxW+a2ubyX66VWMqj9slJ06LNV9sh0zWjspPlGVrU7hpJ1VZN2YYhWicoXWUJrvzTYW6SG5iqx2LZFm4vtbMw16G8X6fmwanSuX56QLSvON5kxWa8NPaEWN3mfSgHaD2E7Vx/q1qG349WfEfuk+DSm2pFUul8Jv2fo6+/tvhydeVtV+faV1PC+98o8ewUvA23/x3VY91zTXh0/hFAAAA7QEAM0AQC2BAEBNL7cGAHVoAgD1PGtvAPj32eEAuON2AKCeSaXjAQAGxAoABACpAGodiAqgXpmjAphCMyqABgBqY1M5WgOAAVEHAAFAAFDrQABgCphhCVhLMpaAo4cwXixABfBLVADl3CslBwAwIFoAIAAIAGodCAAEALWMMWMPoKZYPC89P3sT6xrwJZAlHzXaLtslfw2MdpZYtwUFAMCAKACAACAAqHUgABAA1DIGAFT1AgBVxcrXHgAMiD0ACAACgFoHAgABQC1jAEBVr3heeu6V8Argl7enAqjqX0r2AGBAtABAABAA1DoQAAgAahkDAKp6xfPSX1/5XPAS8O7bh30KTj137IurAAAYoDcACAACgFoHAgABQC1jAEBVLwBQVax87QHAgNgDgAAgAKh1IAAQANQyBgBU9Yrnpadf2TS4Ath/+wW8CFoNQAnZA4ABwQIAAUAAUOtAACAAqGUMAKjqFc9LM17+fDAA7t3vbQBQDUAJ2QOAAcECAAFAAFDrQAAgAKhlDACo6gUAqoqVrz0AGBB7ABAABAC1DgQAAoBaxgCAql7xvDT15S8EVwC/1u8/VADVAJSQPQAYECwAEAAEALUOBAACgFrGAICqXvG89OTLPYMB8Bv95gOAagBKyB4ADAgWAAgAAoBaBwIAAUAtYwBAVa94Xnpi1ubWJeBLIEs/arQBO7wFAKoBKCF7ADAgWAAgAAgAah0IAAQAtYwBAFW9AEBVsfK1BwADYh93tK1GjrNMp04Bv7R215p39Z9e762s7FTRKLtYRU7zqU9xR5rmvLSz+sQ6J16MmeUy2oRe0ai3ke2oteFXk0azXEZXTW2nsYPeRhpozHbQNctk9dio16/aR7FMcV5qXno7xYhNNkX801xLrkrPM0sx/uUqtXay9XU26zfDW7WqFs9Lj8/aIrgCuN8Ob7bquWrqYV1oBQDAAEUBQAMAAUCpBxUDMvyEAEAdgIsRGwCweAD46N97BQPggTvOAwClEa60jAHAgHgBgACgWp2gAqh3OCqAemVSzUsqgF4C1XOzLVcAAUA9nuXmAQAGRBwABADViRYA1DscAAgAqlnDEnCtPfz3razLeuIadZ7QSz/K2sE7vk4FUE2+ErIHAAOCBQACgACg1oGKsczIErC+N5UKYPurAD7w997BAPitHV8DALUhrqSsAcCAcAGAACAAqHUgAFDTy615CETfz0gFsNYAQL2vlZsHABgQcQAQAAQAtQ4EAGp6AYDpqpkAYK1NeqlPcAXw2zv9iwqg3mVLxgMADAgVAAgAAoBaBwIANb0AQABQzZh4Xrr3pW2CAfCwnf4JAKoBKCF7ADAgWAAgAAgAah0IANT0AgABQDVjAEBVsfK1BwADYg8AAoAAoNaBAEBNLwAQAFQzJp6X7n5pW+sc8BTwso+y9r2d5lABVANQQvYAYECwAE/aUpEAACAASURBVEAAEADUOhAAqOkFAAKAasbE89KdL24XDIBDvjQbAFQDUEL27RYAL7roIrvvvvtszpw5VlNTY/3797dLLrnE+vbt2xSe5cuX2xlnnGF33HGHffzxxzZgwAC79tprbbPNNksUQgAQAAQAE3WVJiMAUNMLAAQA1YyJ56WJL/YLBsDvf+llAFANQAnZt1sAPOCAA2zIkCG22267WUNDg40YMcJmzZpls2fPti5dukQhOvnkk+3BBx+0m2++2TbccEM7/fTTbfHixTZz5kyrrFz3CzQBQAAQANRGOwBQ0wsABADVjAEAVcXK177dAuDqIV24cKH16NHDpk6davvss090V7PxxhvbbbfdZkcccURk/vbbb1vPnj3tkUcesf3333+dWQEAAoAA4Dq7ySoGAKCmFwAIAKoZE89Lt72wQ3AF8KidZ1EBVANQQvZlA4Bz5861Pn36RFXAfv362ZNPPhkt+XrFb4MNNmgK2U477WSHHnqojR49ep1hBAABQABwnd0EAMxToCLF92Z5ETQvglZ6WTwv3fzCTsEAOHTnlwBARfwSsy0LAMzlcjZ48GB7//33bfr06VGIJk6caMccc4z5PsD8Y7/99rNevXrZDTfcsEYo3Tbf3juaVwy3GjnOMp06tVroa97Vf3q9t7KyU6rJSfxMaf16maKcl9yIO+TEi3GXjDY58S1gPTJ8C7j189KjUozqbLaDHn+1j0VduUpvx1LAeW7dO4VWOZFsfZ3N+s3wVoUqADBF7MvUpSwA8JRTTrGHH37YZsyY0fSAR0sAOGjQIOvdu7ddf/31a6TEqFGjmq0Mbn7pWMvUJAPAXBcdzCoX6aNZp/c0MPGL3XB2g9wNcpV6O2ojuTRNpPBJ044KzY1V+olV6PN/qsnc0rQjXk8qAK7WNUsDjY3iZO55nBG7c5o21ByLAEi/z7I07ZgYmmLFJU2faUiRZ5X1WqdxAHz+zhFFAcDfPr9zcAXwh7u80Krnqs4F2BdWgXYPgKeeeqpNnjzZpk2bFlX24iPNEnBLFUAAsLBJufqvpQEzdWKKJk1xMnMfddIEALUJ0zXOppiYiwUaAKDW94sVFwCw1n79/K7BAHj8LjMBQC3FS8q63QKgL/s6/E2aNMmmTJkS7f/LP+KHQG6//XY7/PDDoz8tWLAgqhCqD4EAgK2b82nADABMEROdzUwFWiqAelzUmwwqgPreZNesvVUAAUC9r5WbR7sFwGHDhkX7/O6///5V3v1XW1sbvRfQD38NzEMPPRS9BqZ79+7ROwEXLVokvwYGAGzdbgMA6vqm2c/FErCuMxVATTMqgMVbAr7h+V2tpqu+fSiO6MdLGuxEKoBagpeYdbsFwIqK5tfzJkyYYEOHDo3CVFdXZ2eeeWYEivkvgvYHO5Ic8WZbADCJWultAEBdOwAwhWbsAdRFE7dNAIDFA8Drnt8tGABP3uVvLAHrvaJkPNotABYjAgCgGQ+BaJmmLpn6r6fZzwQAanFx6zQPaFAB1HQGAAFALWOwbk0FAMAAdQFAAFDdnwUA6hsNeQhEH6R4CljXrL3tAbxm5u7BFcAf7frXxBXA6667zvzfG2+8EYm//fbb2wUXXGAHHnhg9P+HfnpVjyge61IAAFyXQmv5OwAIAAKA2hogD4HoA46aY94CAKjr3N4A8OqZewQD4I93fSYxAPpnVf0TqltvvXUk/i233GLjx4+3F154IYLB0E+v6hHFY10KAIDrUggAXKtCLAFrCUQFkAqgljH6q4YAwHTbJtobAF7xXP9gADzty08nBsDm8tofrnQI/O53vxv86VW132C/bgUAwHVr1KIFFUAqgGp1BgAEANUhR80xABAA9LddfJYAmM1m7e6777ajjz46qgC+8847wZ9eVfsN9utWAABct0YA4Fo0ogKoJRAACABqGUMFMM3DOWkenGpvFcDLnts7uAJ4xpdn2Pz5861bt25NaVtdXW3+r7lj1qxZtueee0Zv2OjatWv0ho2DDjoo1adX1X6Cva4AAKhr1uRBBZAKoFqdAQABQHXIUXOMCiAVQK8AXvq3rwYD4Fm7TV8jXUeOHGn+WdTmjvr6envrrbfsgw8+sHvvvdduuukmmzp1qr344ot2zDHHRA+C5B9r+/Sq2k+w1xUAAHXNAMA8zagAagkEAAKAWsZQAaQCqGVMXJgoFAAqFcDVz3TgwIHWu3dvO+KII1gC1sJYFGsAMEBmKoBUANXqDAAIAKpDjppjVACpAHoF8OK/fc06BXwJpG5Jg52z29Sgh0AGDBhg/mGFq666KnoIJOTTq2q/wX7dCgCA69aoRQsAEABUJ2cAEABUhxw1xwBAANABcNyz+wYD4PCv/DkxAA4fPjx6558D30cffWR33nmnXXzxxfbYY4+ZL/WGfnpV7TfYr1sBAHDdGgGAa9GIJWAtgQBAAFDLGJaAWQLWMiYuTBQbAI899lh74oknbMGCBeYAuuOOO9rZZ58dwZ8foZ9e1VTAOokCAGASlVqwiTtaz2tHWaamU6JfyjVqL871H61Ynkn02/lGHRfpHzbd+MWs3E6mQZvQiwGMfhGNlbrOmax2LZFYokuaF/Sm0UyNS1rNTJdZzrHGFN+zz3bUT0z9rFua+KfRKw0AySJ7n6nSNatcoXWANPnflj8fp8YmW19nL94+InFVLU0c43lpzLPfCK4Anv+VJ1v1XNNcHz6FUwAADNASADRTQSMNzKQJEQCoTcwAoBkACACqY01bBsDRfx0YDIAjd/8TAKgmRQnZA4ABwQIAAUAqgAEdKKErFcCEQgWaUQHUBQQAdc3waDsKAIABsQAAAUAAMKADJXQFABMKFWgGAOoCtmUAvCCqAHbQL+oTj7olK+znVABT61cKjgBgQJQAQAAQAAzoQAldAcCEQgWaAYC6gG0ZAM97Zr9gABy7x+MsAetpUTIeAGBAqABAABAADOhACV0BwIRCBZoBgLqAbRkAz/3LAcEAeNGejwGAelqUjAcAGBAqABAABAADOlBCVwAwoVCBZgCgLiAAqGuGR9tRAAAMiAUACAACgAEdKKErAJhQqEAzAFAXsC0D4Dl/OdCqA/YALl+ywi7e81EqgHpalIwHABgQKgAQAAQAAzpQQlcAMKFQgWYAoC5gWwbAM58+OBgAx/d/GADU06JkPADAgFABgAAgABjQgRK6AoAJhQo0AwB1AQFAXTM82o4CAGBALABAABAADOhACV0BwIRCBZoBgLqAbRkAT3/qm8EVwF/s9RAVQD0tSsYDAAwIFQAIAAKAAR0ooSsAmFCoQDMAUBewLQPgT5/6VjAAXrnXAwCgnhYl4wEABoQKAAQAAcCADpTQFQBMKFSgGQCoCwgA6prh0XYUAAADYgEAAoAAYEAHSugKACYUKtAMANQFbMsA+OMZg4MrgFfvfT8VQD0tSsYDAAwIFQAIAAKAAR0ooSsAmFCoQDMAUBewLQPgj2Z8OxgAr9l7EgCop0XJeACAAaECAAFAADCgAyV0BQATChVoBgDqAgKAumZ4tB0FAMCAWMQA2HfiOVbZuTrRL1VmGhPZ5RstXdpJ9sl+XCX79Jiq+1Qty0ntVK7Q7P3HU01My3WdGztUSNfixhViM9kUbcgnZWa5St2rcrkem1xGaydXqWucJi6W069Fu5KV1hViM40prj/TIDZiZg2ddJ3TXL/aN6tS5Fiaa6mq0zVTYc71qlyhqdawos5m3jWiVatq8bx08vTvBFcAr/vqfa16rpp6WBdaAQAwQFEA0AwA1BIIANTBBADUYSYNNGmZvNIaANRUKyYAnjjtsGAAvGGfewFALcQlZQ0ABoQLAAQAqQBqHYgKoA7AVAB1zagA1toJU79nHQM+BVe/ZIXd+LW7AUBtiCspawAwIFwAIAAIAGodCADUYQYA1DUDAAFAbWQqT2sAMCDuACAACABqHQgA1GEGANQ1AwBr7diphwdXAH/ztbuoAGpDXElZA4AB4QIAAUAAUOtAAKAOMwCgrhkAWGvHTHEA7Kh10Dzr+iX1NuHrAGBqAUvAEQAMCBIACAACgFoHAgB1mAEAdc0AQABQG5nK0xoADIg7AAgAAoBaBwIAdZgBAHXNAMBaO/rPQ4IrgLfseydLwNoQV1LWAGBAuABAABAA1DoQAKjDDACoawYA1tpRf/6/YAC8bd87AEBtiCspawAwIFwAIAAIAGodCADUYQYA1DUDAAFAbWQqT2sAMCDuACAACABqHQgA1GEGANQ1AwBr7ftPfj+4AjjxGxOpAGpDXElZA4AB4QIAAUAAUOtAAKAOMwCgrhkAWGtDnjgyGADvHHA7AKgNcSVlDQAGhAsABAABQK0DAYA6zACAumYAYK0d/sRR1rFLwGtgltbbXQNuAwC1Ia6krAHAgHABgAAgAKh1IABQhxkAUNcMAAQAtZGpPK0BwIC4A4AAIACodSAAUIcZAFDXDACste898QPrEFABXLG03u4ecCsVQG2IKylrADAgXAAgAAgAah0IANRhBgDUNQMAa+2wPx0dDID3DrwFANSGuJKyBgADwpUGALtU11vdiiqp1aVLO0n2bpz9WGvDfXpM1X2qluWkc6tcodn7jzdW6RNA5fJG6byidjro7agA2Fhplsvo7agXk6tUPcwql+uxyWW0dlxjWbMUcbGcfi3alay0rhCbqciaZTtq8W9PAFiRy1llvaZ0QydNL/91ABAA1LKsPK0BwIC4xwC4491nWGXn6kS/VJXRwWR5gz6bL12W7HzyT3q9qV0SXUO+Uc1C7XrSAGBOH/9NBRO/pkxWvnwdTlOASTGAMYKZRpFmTIfZNGBqaeKfwiezQo9/TrxncgBUDxUYV5Kp2opZtoPuo8JcVh+WLNOgn5fpqWypxibxZq5hRZ3NvGtEq1bV4nnp2388JrgCOGnQhFY91xSRxaWACgCAAWICgGYAoDjTAoB6jxMl9gbS3DQAgHpoAEAtOYsJgIMf/2EwAN6/328BQL1blIwHABgQKgAQAJSXpwFAvcdpc2z0+wCgLjMVQL1sqFbnAUA9L/FoPQUAwABtAUAAEADU6IwlYH3AYQlY14wl4Fo75PFjgyuAD+73GyqAKdKvVFwAwIBIAYAAIAAIACpDCHsAFbVW2rIHUNMsnpcO/sNxwQD48P43AYCa/CVlDQAGhAsABAABQABQGUIAQEUtAFBXywwATKNaefoAgAFxBwABQAAQAFSGEABQUQsA1NX6FAAPfOz44Argowf8mgpgmiCUiA8AGBAoABAABAABQGUIAQAVtQBAXa1PAXD/R08IBsA/HHhjYgC86KKL7L777rM5c+ZYTU2N9e/f3y655BLr27dv02W88847duaZZ9of//hH++ijj6K/DR8+3L773e+muVR8AhUAAAMEBAABQAAQAFSGEABQUQsA1NX6FAAHPXJiMAD+8aAbEgPgAQccYEOGDLHddtvNGhoabMSIETZr1iybPXu2demy8h2zgwYNin7vmmuusY022sgmTpxoI0eOtOeee8523nnnNJeLT4ACAGCAeAAgAAgAAoDKEAIAKmoBgLpanx0Arn6uCxcutB49etjUqVNtn332if7ctWtXu+666+yoo45qMt9www3t0ksvtWOPPTbN5eIToAAAGCAeAAgAAoAAoDKEAICKWgCgrtanADjwkROtqkuKT6980mjD0uX2p4NusPnz51u3bt2aTqW6utr837qOuXPnWp8+faIqYL9+/SJzrxJWVVXZrbfeauuvv77ddddddtxxx9lLL71kvXv3XtdP8vcCKwAABggKAAKAACAAqAwhAKCiFgCoq/UpAH7j4ZOCAfDJg69f4xR8yXbUqFFrPbVcLmeDBw+2999/36ZPn95k68u/RxxxhP3hD3+IQLBz5852zz33REvDHMVXAAAM0BwABAABQABQGUIAQEUtAFBXq/AAmKYCeMopp9jDDz9sM2bMsM0226zpMk499VR79tlnbdy4cdEewMmTJ9sVV1wRQeIOO+yQ5nLxCVAAAAwQDwAEAAFAAFAZQgBARS0AUFfrUwD8+kMnB1cAp3zzusQPgcTn6pDnYDdt2jTr1atX0yW89tprtvXWW9vLL79s22+/fdN/HzhwYPTfr79+zWpjmuvHJ7kCAGByrdawBAABQAAQAFSGEABQUQsA1NX6FAD3eXBYMABOO+TaxADoy74Of5MmTbIpU6ZE+//yD98LuOOOO0ZPBX/xi19s+tP+++9vW2yxhd14441pLhefAAUAwADxAEAAEAAEAJUhBABU1AIAdbU+OwAcNmxY9FqX+++/f5V3/9XW1kbvBVyxYoVtt912tummm9pll11m/vSvVwr9vYAPPfSQHXTQQWkuF58ABQDAAPFiAFTutDbqtExucfHyGtlnRbZS9nljzqayz3rzMpJP7bysZO/GjZUaZLhPRU5uxnJ6M3I7jVX6eaXxqGjUvTIrdNGy1aJoonna+FfW69eS01J5pcDi9RQjx/y0sh3EE9PTJfJQNUvVL1PEJQ1oq9fi11+1XMuzhhV19tw95yWuqqUJSzwv7f3AKcEVwBnf+lXic62oaD7nJkyYYEOHDo0u5V//+pedc8450d7AJUuWREu/Z5xxxiqvhUlzzfikUwAATKdb5AUAmgGAWgIBgJpeAGC6mxkAUM+z9gaAe93/o2AAfGrwNYkBUFccj89aAQAwIAIAIACoVjQAQL3DpakAUwGkAqhmGgC4qmL+HkAAUM2i0rIHAAPiBQACgACgCBqiORVAKoBpwIwl4Frb8/5TgyuAfxn8SyqAAYzQ1l0BwIAIAYAAIAAoEp1oDgACgACgNknF89Luk38cDIB/PfRqAFCTv6SsAcCAcAGAACAAKBKdaA4AAoAAoDZJxfPSVyb9JBgAn/32VQCgJn9JWQOAAeECAAFAAFAkOtEcAAQAAUBtkgIANb3K2RoADIg+AAgAAoAi0YnmACAACABqk1Q8L335vp8GVwCf+86VVAA1+UvKGgAMCBcACAACgCLRieYAIAAIAGqTVDwv7XrvacEAOPOwKwBATf6SsgYAA8IFAAKAAKBIdKI5AAgAAoDaJAUAanqVszUAGBB9ABAABABFohPNAUAAEADUJql4Xtrlnp9ZZZdqzTnPOrt0uT3/3cupAKZWsO07tlsAnDZtmo0fP95mzpxpCxYsiD5QfeihhzZFxD9Nc8stt6wSod13392eeeaZxFEDAAFAAFAkOtEcAAQAAcDEU1JkGM9LOzsAdg4AwGXL7QUAUBO/xKzbLQA++uij9tRTT9kuu+xihx12WLMA+N///tf8O4Xx0bFjR+vevXviEAKAACAAKBKdaA4AAoAAYOIpCQDUpCp763YLgPmR9Y9UN1cB/OCDD2zy5MmpkwAABAABQJHoRHMAEAAEALUpKp6Xdrrn9OAK4Evf/QVLwJr8JWVd1gDo8OdVv/XXX9++9rWv2YUXXmg9evRoMYDLly83/xcf3tF69uxp+zw4LPHTVht1WiYnyOLlNbLPimyl7PPGnE1ln/XmZSSf2nlZyT4tAKhg5u3kUsCJ2g7fApbDb3wLWNcs2yFFMuvNmApnan+J+qU2xERXwafgam3Hu88IBsC/f+8yADBFvygVl7IFwN///vfWtWtX22KLLWzevHl2/vnnW0NDQ7RnsLq6+X0To0aNstGjR68RWwAweboDgMm1CrGsaNS9MytyslO2WgQN0TztDUBlvX4taUDDxOspxk2GawYAyqmcCjSrlmt51rCizp6757xWhaq4AggA6jlQbh5lC4CrB9ofFHEYvPPOO+073/lOs3nQUgVw7wdOSVwB7Fy1Qs6xRnWWMbO6hiq5nTfe3kj2yfxX22S8ybPagLnybl73yWXEmdnb0ZsxtaKXaZAlltvwFtLAXBrN1NTM6YVpa6xKEcsUAFzRqCdAhRjPNNefDkx1zRq0rryy0ibqrNqvbETvM2kqgJk044x4bg6AM+8uDgD2u+vM4Argy4ePb1VY1SOLRyEVAADz1OzTp48dd9xxdvbZZyfSOL7TAgATyRUZAYDJtYotVcgEAHUwWQkzAKCanSrQqfYAoBqRT58C3v734QD4yhEAoB6B0vEAAD+J1aJFi+wLX/iC3XjjjfaDH/wgUQQBQDMqgIlSpcmICqCml1tTAdQ1swqxNGVmVAD1GwB1Sb+YFcDt7jwruAI4e8ilVABTdL9ScWm3ALhkyRKbO3duFIedd97ZLr/8ctt3332j17z4P9/P56+H2XTTTe2NN96w4cOH21tvvWX/+Mc/bL311ksUPwAQAFSrcwBgoq61ihEAqGsGAOqatbclYABQz4Fy82i3ADhlypQI+FY/jj76aLvuuuuil0K/8MIL5q+CcQh02zFjxkRP9SY9AEAAEABM2ltW2qXZAwcAahqvXDalAqiq1t4A8It3nB1cAfzH/11CBVBNpBKyb7cAWIwYAIAAIACo9TQAUNMrguYUr0EBAHWd2xsA9p14TjAAvvr9iwFAPZVKxgMADAgVAAgAAoBaBwIANb0AQJ4CVjMmnpcAQFW58rMHAANiDgACgACg1oEAQE0vABAAVDMmnpe2+V14BfCf/48KoKp/KdkDgAHRAgABQABQ60AAoKYXAAgAqhkTz0t9bncA7KS6N9lnl9XZv44EAFMLWAKOAGBAkABAABAA1DoQAKjpBQACgGrGAICqYuVrDwAGxB4ABAABQK0DAYCaXgAgAKhmTDwvbX3bucEVwLlHXcRDIGoASsgeAAwIFgAIAAKAWgcCADW9AEAAUM2YeF7qXQAAfA0AVOUvKXsAMCBcACAACABqHQgA1PQCAAFANWMAQFWx8rUHAANiDwACgACg1oEAQE0vABAAVDMmnpe2unV48BLw6z8YxxKwGoASsgcAA4IFAAKAAKDWgQBATS8AEABUM6YJAG8pAAAeDQCq+peSPQAYEC0AEAAEALUOBABqegGAAKCaMU0AePMIywS8BqZxWZ29PvRCKoBqAErIHgAMCFbc0Xr+YoxlahK+b6lzVm4x00H3qa5ZIbdTX18l++QatW+OrvdMjdxG53cbZZ/K5TnZJ1epXYs3kFmhnVu2Y4rveumnlerzYRXapUT6qkDXmEJjtY2VcUkR/4wudGW91k6az7qlupY0OqdIzcYOmmZpcizbQe7KltGHzFR9Ro1/w4o6e+6e81oVqgBAPV/K1QMADIg8AGgGAGrUBABqwJAGMgFAB/MUOgOA8mzQlgGw14TwCuC8Y6gAyklRQg4AYECwAEAAkAqg1oGoAGp6pYZZAFAWOk11ti0D4Ja/PS94CfiNH45t1WqlHCQcCqoAABggJwAIAAKAWgcCADW9AEAzloC1nInnJQBQ060crQHAgKgDgAAgAKh1IABQ0wsABADVjGkCwN+cH14BPHYMFUA1ACVkDwAGBAsABAABQK0DAYCaXgAgAKhmTDwvbXFTOAC+eRwAqOpfSvYAYEC0AEAAEADUOhAAqOkFAAKAasYAgKpi5WsPAAbEHgAEAAFArQMBgJpeACAAqGZMEwD+ugAVwOOpAKr6l5I9ABgQLQAQAAQAtQ4EAGp6AYAAoJox8by0+Y0XBO8BfOuEnyfeA3jRRRfZfffdZ3PmzLGamhrr37+/XXLJJda3b99VLuEvf/mLjRgxwv76179ahw4d7Etf+pI9+uijkQ9HcRUAAAP0BgABQABQ60AAoKYXAAgAqhnzWQHgAQccYEOGDLHddtvNGhoaIsibNWuWzZ4927p06RJdhsOf25177rl2yCGHWMeOHe2ll16K/u/q6mr1UrEPVAAADBAQAAQAAUCtAwGAml4AIACoZswqAJj0C1XNNNL4cZ0pFcDVf2LhwoXWo0cPmzp1qu2zzz7Rn/fYYw8bNGiQjRkzRr0s7FtBAQAwQFQAEAAEALUOBABqegGAAKCaMU3z0g0jk3+itAUAnH/i6MRLwKv/xNy5c61Pnz5RFbBfv3727rvv2iabbGJXX3213XHHHfbaa6/ZtttuaxdeeKHtvffe6mViXwAFAMAAEQFAABAA1DoQAKjpBQACgGrGNM1L1xcAAE8abfPnz7du3bo1nYYv1a5ruTaXy9ngwYPt/ffft+nTp0e+zzzzjO25557WvXt3u+yyy6K9f7feeqtde+219vLLL0ewyFFcBQDAAL0BQAAQANQ6EACo6QUAAoBqxhQaAFdvf+TIkTZq1Ki1ntYpp5xiDz/8sM2YMcM222yzyPbpp5+2vfbaK9r/N27cuCb/HXfc0Q4++GDzh0g4iqsAABigNwAIAAKAWgcCADW9AEAAUM2YTwFwVPgS8Emj5ArgqaeeapMnT7Zp06ZZr169mk5/3rx5ttVWW9ltt91mRx55ZNN/P+KII6yqqsp+97vfqZeKfaACAGCAgAAgAAgAah0IANT0AgABQDVjmual6woAgCePSrwH0Jd9Hf4mTZpkU6ZMWWNJ1//u1cAf/vCHqzwEsvPOO9uBBx64SlVQvWbs0ykAAKbTLfJq+ubi2Ast06lTol9qrM4lsss3auzUKPtUdMzqPpX6uZno0vmVZDrln3yXBWIjZlb9oa5ZrkKWTHcoRhtmVizQqhDTrKGmOAJU6OG3XCZFOMV2Mg16Lmca9POynN5OYwc9NqrO2Y56G7lK/frVvNRbWOmRyWo6N6yos+fuOS8xVKU5r88KAIcNG2YTJ060+++/f5V3/9XW1ja94+/KK680X0L+zW9+E+0BvOWWW6L9gL4HsHfv3mkuF58ABQDAAPEAQDMAUEwgff4TG1hpDgDqsgGAenICgG0YAK8tQAVwWPIKYEVF8/kzYcIEGzp0aFOHvPjii+1Xv/qVLV682HbaaSe79NJLeQpYH64K4gEABsgIAAKAcvroc6zcBABopoKJawYA6smp6kwFsIgVwF+NDt8DeMrIVq1WphrccCqYAgBggJQAIAAop48+x8pNAIAAIEvAqbqN7NSml4ABQDme5eYAAAZEH80BdAAAIABJREFUHAAEAOX0AQBlydI4qJUpKoBm7AHUM60tA+Bm14RXAP/9IyqAelaUjgcAGBArABAAlNMHAJQlS+MAAGp706KqMQ+ByKnWpgHwlwUAwFMBQDkpSsgBAAwIFgAIAMrpAwDKkqVxAAABwDR5o/oAgKpi2LclBQDAgGgAgACgnD4AoCxZGgcAEABMkzeqT5sGwKt/HvwQyL9/fAEPgahJUUL2AGBAsABAAFBOHwBQliyNAwAIAKbJG9WnLQNgz6vCAXD+TwBANSdKyR4ADIgWAAgAyukDAMqSpXEAAAHANHmj+rRpALyyAAD4UwBQzYlSsgcAA6IFAAKAcvoAgLJkaRwAQAAwTd6oPgCgqhj2bUkBADAgGgAgACinDwAoS5bGAQAEANPkjerTpgHwijHBewDnn3Y+ewDVpCghewAwIFgAIAAopw8AKEuWxgEABADT5I3q06YB8PICAODPAEA1J0rJHgAMiBYACADK6QMAypKlcQAAAcA0eaP6AICqYti3JQUAwIBoAIAAoJw+AKAsWRoHABAATJM3qk+bBsBfFKACeDoVQDUnSskeAAyIFgAIAMrpAwDKkqVxAAABwDR5o/q0aQC8rAAAeAYAqOZEKdkDgAHRigFwqxHjrLJTp0S/lO2sD8y5Kt2nsaYx0fnkG+UyejsVHbR2Or1eLZ9X7ev6edX+c4ncTkOXjrJPtjoj+eRSfG4rlykSNUpXstI4K15PtjrFtaRw6bBEy0u/ljSfQlMla6xSPcwyK3SfXKXuk2nQfRo7aD4VKdpIlTPaaUXWaWLTYak2NjWsqLO/TT6vVR+siOelngBgiiwoLxcAMCDeAKAZAAgAKl0o1WQOACoSR7YAoCxZ+wPA8WPDnwI+s3VhVY8SHoVUAAAMUBMABACpAGp0BgDqAw4VQC3HdIVXerS3CuDml4YD4FtnAYBp86kU/ADAgCgBgAAgAKhNzgCgPuAAgFqO6QoDgM1p1vhxnQGAabOpNPwAwIA4AYAAIACoTc4AoD7gAIBajukKt1MAvKQAFcCzqQCmzadS8AMAA6IEAAKAAKA2OQOA+oADAGo5pisMALZYAQQA06ZTSfgBgAFhAgABQABQm5wBQH3AAQC1HNMVbp8AuIVXABO+naJZAKyrszcBwLTpVBJ+AGBAmABAABAA1CZnAFAfcABALcd0hQFAADBt1pS2HwAYED8AEAAEALXJGQDUBxwAUMsxXeF2CoAXXxheATxnRKu+szBtrPArjAIAYICOACAACABqkzMAqA84AKCWY7rC7RQALyoAAJ4LAKbNp1LwAwADogQAAoAAoDY5A4D6gAMAajmmKwwAtrgEDACmTaeS8AMAA8IEAAKAAKA2OQOA+oADAGo5pivcTgFwXAEqgMOpAKbNp1LwAwADogQAAoAAoDY5A4D6gAMAajmmK9w+AXDLC8MB8I0RAGDafCoFPwAwIEoAIAAIAGqTMwCoDzgAoJZjusIAYEtLwABg2mwqDT8AMCBOACAACABqkzMAqA84AKCWY7rC7RQAxxagAngeFcC0+VQKfgBgQJQAQAAQANQmZwBQH3AAQC3HdIXbKQCOKQAAng8Aps2nUvADAAOi1ASA54+zyoA3rq/rFBpqcusyWePvjdWNsk+uo96OZTSfmjc7yOe14Wz9Wjrf+4zcTqZzZ9nHvriV5NNYXSXZu3HdRh1lH6vQJ83GyhTNaOG35d0yciNVdWIjZpZpkJuxnC6Z5UTNKrIpzktsw1tIc/2NempaZoUWm8aOKUTWJbNsinZSxUZM52x9nT1/Z+tCVTwvbQkApsic8nIBAAPiDQD6TKNNAACgPssCgFqOpQUgAFAfDAFATbNiAmCvn4dXAOdd0LqwqqmHdaEVAAADFAUAAUAqgFoHogKo6eXWapUxLQBTAUwRmzZcAew1elzwl0DmjRzOl0D0tCgZDwAwIFQAIAAIAGodCADU9AIAdb3cgyXgWus1qgAAOAoATJeBpeEFAAbECQAEAAFArQMBgJpeAKCuFwD4P6utBQDTZU55eQGAAfEGAAFAAFDrQACgphcAqOsFAK4EwK1GhlcAXx9NBTBdBpaGFwAYECcAEAAEALUOBABqegGAul4A4CcAeEEBAPDnAGC6DCwNLwAwIE4AIAAIAGodCADU9AIAdb0AQAAwXdaUnxcAGBBzABAABAC1DgQAanoBgLpeAOAnABj4ftpsXZ29PoYKYLoMLA0vADAgTgAgAAgAah0IANT0AgB1vQDATwDwvLAPFEQAODY5AF500UV233332Zw5c6ympsb69+9vl1xyifXt23eNIOZyOTvooIPsscces0mTJtmhhx6aLtB4BSkAAAbIBwACgACg1oEAQE0vAFDXCwD8bADwgAMOsCFDhthuu+1mDQ0NNmLECJs1a5bNnj3bunTpskogr7jiCvvjH/9ojz76KACYLsUL4tVuAXDatGk2fvx4mzlzpi1YsGCNJPM7kNGjR9uNN95o77//vu2+++72q1/9yrbffvvEwgKAACAAmLi7RIYAoKYXAKjrBQB+AoAjClABvDB5BXD1SC1cuNB69OhhU6dOtX322afpzy+99JJ985vftL/97W+26aabAoDpUrwgXu0WAP3O4qmnnrJddtnFDjvssDWSzEvTF154od188822zTbb2NixY82h8dVXX7X11lsvkbgAIAAIACbqKk1GAKCmFwCo6wUArgTA3sPDAfC1cekBcO7cudanT5+oCtivX78okMuWLbMvf/nL5svFgwcPtoqKCgAwXYoXxKvdAmC+OqsnmVf/Pv/5z9tPf/pTO/vss1dWJpYvt0022STas3DiiScmEhcABAABwERdBQD8RIGKrKYXAKjrBQAWFgDnz59v3bp1awpEdXW1+b+1HT7HOuD56tr06dObTH1uzWazdtNNN0X/DQBMl9+F8ipLAHz99detd+/e9vzzz9vOO+/cpKUn7Prrr2+33HJLIn0BQAAQAEzUVQBAADBSoLFjhZYwKa35FFzhKoCrh2DkyJE2atSotUbmlFNOsYcffthmzJhhm222WWT7wAMP2Omnn24vvPCCde3aFQBMmduFdCtLAHz66adtr732sv/85z9RJTA+TjjhBHvzzTftD3/4Q7Mae5XQ/8WHA2DPnj1tq8DH7dcV0Iaa3LpM1vh7Y3Wj7JPrqLdjGc2n5s0O8nltOFu/ls73PiO3k+ncWfYBADXJWALW9HLrXKXuk2nQfRqrdJ/MCq3/A4B19vydI+zDDz9cpaqmK9+yR1yY6H1uAZaA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56V7t5N8KrTuEv129Qd6v8ylyOWqOr0d6eLNrNOiBtXFKpfrojV2zMjtNHTWfVaIPr6sOvOuEfbhhx9at27d5HNM4hDPS/2OLwAA/hoATKJ5qdoAgAGRAwAdGrXBGQAEANUuBwDqYAYA6jAHAK7aMx1WXwYA1eGqpOwBwIBwAYAAIBVAKoDKEEIFkApgsSqAOxwXXgGcdRMVQKV/l5otABgQMQAQAAQAAUBlCAEAAcCiAeCxBQDA3wCASv8uNVsAMCBiACAACAACgMoQAgACgACg0mOwbU0FAMAAdQFAABAABACVIQQABACLBYA7/jC8Avj331IBVPp3qdkCgAERAwABQAAQAFSGEAAQACwaAB5TAACcAAAq/bvUbAHAgIgBgAAgAAgAKkMIAAgAFg0AhxYAAG8GAJX+XWq2AGBAxABAABAABACVIQQABAABQKXHYNuaCgCAAeoCgAAgAAgAKkMIAAgAFgsAdzo6vAL40i1UAJX+XWq2AGBAxABAABAABACVIQQABACLBoA/KAAA3goAKv271GwBwICIAYAAIAAIACpDCAAIALZXALzooovsvvvuszlz5lhNTY3179/fLrnkEuvbt2/URRYvXmwjR460xx9/3ObPn28bbbSRHXrooTZmzBirra1VuhG2BVIAAAwQEgAEAAFAAFAZQgBAALBYAPiloy60yo7JvlHfXA77p+BevC35d4sPOOAAGzJkiO22227W0NBgI0aMsFmzZtns2bOtS5cu9vLLL0cAOHToUNtuu+3szTfftJNOOsl23HFHu+eee5RuhG2BFAAAA4QEAAFAABAAVIYQABAALBoAHlkAALw9OQCu3g8WLlxoPXr0sKlTp9o+++zTbDe5++677cgjj7SlS5daVVWV0pWwLYACAGCAiAAgAAgAAoDKEAIAAoClBoC+XNutW7emNK+urjb/t65j7ty51qdPn6gK2K9fv2bNb7rpJjv33HPNYZGj+AoAgAGaA4AAIAAIACpDCAAIABYLAHf+f+EVwBd+N2KN9PZl3FGjRq017XO5nA0ePNjef/99mz59erO2ixYtsl122cWOOuooGzt2rNKNsC2QAgBggJAxAG459kLLdEq216IiWyG32NAtK/tYdaPuU6X7VFTkpHYq306mU/6PVi+WmoiMv/DkR7JT5QdLZZ9ctbZsUbF0udxGdqNP776TOtdvqOv8zvF1SX++ye64Lz4l+azIVUr2bvzash6yz0cr9Ot/9vUt5HZy9dr1ZDrpAJRr1MeMxuXaefmFV/5Py2X3qVqmnVvNu7LE1mmRNsZ4C5kG3aexSrsWbyfbUbueaF9dwLJqktbieWnn7xcAACeOiB7YUCuAp5xyij388MM2Y8YM22yzzdY4bT/H/fbbzzbYYAN74IEHrEOHDkkuDZsCKwAABggKAJoBgNqkCQDqYAIA6mACAAKAhQLADz/8cBUAXNeUeeqpp9rkyZNt2rRp1qtXrzXMP/roI9t///2tc+fO9tBDD1mnhMWTdbXL33UFAEBdsyYPABAApAJIBVAZQqgAKmqttKUCqGkWz0u7/F94BfD5O5I/BOLLvg5/kyZNsilTpkT7/1Y//Nwc/nwP4SOPPBJBIMdnpwAAGKA9AAgAAoAAoDKEAICKWgCgrpZZEwAOKQAA3pkcAIcNG2YTJ060+++/v+ndf37+/o4/fy+gV/4GDRpky5YtiyDRXw0THxtvvLFVVuqrA2n0wedTBQDAgGwAAAFAABAAVIYQAFBRCwDU1foUAHc9IhwAZ/4+OQBWVDS/VWHChAnRu/+8Krjvvvs2e0nz5s2zLbfcMs3l4hOgAAAYIB4ACAACgACgMoQAgIpaAKCu1mcHgGnOFZ/PVgEAMEB/ABAABAABQGUIAQAVtQBAXa08ADy8ABXAu5JXANOcKz6frQIAYID+ACAACAACgMoQAgAqagGAulqrAmBVB/11SHGbDSvqrLXfWZjm+vApnAIAYICWACAACAACgMoQAgAqagGAuloAYBrNytUHAAyIPAAIAAKAAKAyhACAiloAoK5WHgB+b6wFVwDvPs/U9wCmOWd8PhsFAMAA3QFAABAABACVIQQAVNQCAHW1PgXAL383HACfuwcATBODUvEBAAMiBQACgAAgAKgMIQCgohYAqKsFAKbRrFx9AMCAyAOAACAACAAqQwgAqKgFAOpq5QHgYQWoAN5LBTBNDErFBwAMiBQACAACgACgMoQAgIpaAKCu1qcAuNu3wwHwb5MAwDQxKBUfADAgUgAgAAgAAoDKEAIAKmoBgLpaAGAazcrVBwAMiDwACAACgACgMoQAgIpaAKCuVh4AHlqACuBkKoBpYlAqPgBgQKRiANz80rGWqUn2ws1cdaPeYkfdp2OXermdbIP+Me7Ghua//9hS45X/SaZTvn9FTr4UW/9V3amyXvep/p8Wm1xGv5Y0HtkOWly8jYNGT5Gb6lfzb8ln707vSfZu3Gh6XMb+dx+5nZmLeso+H/xhU8knTfwrtBSLzqexg3RakXGHpbpPZoXm0/EjPZZaCyutKxr1drId9T6jjhnRy5Vb+dUq8bz0lcHhAPjs/QBgmvwrFR8AMCBSAKAZAKjNzmkAIE2KAoAAoJo3AGA7A8BvjQl+D+CzD5zPewDVjlRC9gBgQLAAQACQCiAVQGUISXMDQAVQUZgKYFMFEADUE6fMPADAgIADgAAgAAgAKkMIAKgvzSr6xrYsAdfa7oeEVwD/+iAVwDT5Vyo+AGBApABAABAABACVIQQABACLtQdw928WAAAfAgCV/l1qtgBgQMQAQAAQAAQAlSEEAAQAAUClx2DbmgoAgAHqAoAAIAAIACpDCAAIABYLAPc4OLwC+MzDVACV/l1qtgBgQMQAQAAQAAQAlSEEAAQAiwaAB/08+CngZx65gKeAlQ5eYrYAYEDAAEAAEAAEAJUhBAAEAAFApcdg25oKAIAB6gKAACAACAAqQwgACAAWCwD3PDC8AviXR6kAKv271GwBwICIAYAAIAAIACpDCAAIABYNAA8oAAA+BgAq/bvUbMsWAEeNGmWjR49eJV6bbLKJvfPOO4ljCAACgAAgAJh4wDAzABAABACVHoNtaypQ1gB4zz332J/+9KcmfSsrK23jjTdOrDcACAACgABg4gEDADS+BVy8bwH33z+8Avj0H6gAKv271GzLGgAnT55sL774YuqYAYAAIAAIACoDCBVAKoDFqgD2HzQ6+Cngp/84kqeAlQ5eYrZlDYDjx4+32tpaq66utt13393GjRtnW221VeIQAoAAIAAIACYeMKgAUgFcUcQK4MACAOCfAEClf5eabdkC4KOPPmrLli2zbbbZxv773//a2LFjbc6cOfbKK6/Yhhtu2Gwcly9fbv4vPhwAe/bsaZtfOtYyNZ0SxT5X3ZjIbhWjjrpPxy71cjvZhkrZp7GhQvKp/E8ynfJ/tCJF0WD9V3WnynrdBwAEAJUOQAVQ72OKvrEt3wKutf4AYJrUKSufsgXA1aO8dOlS6927t5111ln2s5/9rNkkaO7BETfsedXPkwNgpT4AVtY0yEmZqdShsTGbkdtprNegserdDnIbmXoNMr2BLv+Rm7GqOj02OfHUKnUuT/XgwPJa8cTMbPPvvS6LNnaLyZLP1h30HKupqJbacON7l64n+5w5/XDZp/b5jpJP5af3j4n9KlfoeWkpXKqW606VYp/JZPU2Giv1XE6lWeKIfGpYt4E2/mXr62zm70e06rJqvDK1lwNglX7DHV9dQ0OdPUUFMEVWlI4LAJgXq0GDBtnWW29t1113XbMRbKkCCAAmT3gAMLlWsWWaqhEACACqmQYAqoqZtWkAHDAqHACfGNWqsKorjkchFQAAP1HT4c4rgCeccIJdcMEFiTSO77QAwERyRUYAYHKtAMCVClAB1KtmVABTaKZ3TQAwhWa4tB0FyhYAzzjjDDvkkENs8803t3fffTfaAzh16lSbNWuWbbHFFokiBACasQScKFWajFgCZglYyxizVMuZKfiHCqAambZdAdz7G+EVwBlPUgHUs6J0PMoWAIcMGWLTpk2z9957L3r33x577GFjxoyx7bbbLnH0AEAAkD2A7AFMPGCYGXsAdTJlD6CSYWbxvLT3vgUAwD8DgJr6pWVdtgBYiDABgAAgAAgAKmMJAAgAFushEABQ6ZnlaQsABsQdAAQAAUAAUBlCAEAAsFgA+NWvjwx+CGT6lNE8BKJ08BKzBQADAgYAAoAAIACoDCEAIABYNADcpwAAOA0AVPp3qdkCgAERAwABQAAQAFSGEAAQAAQAlR6DbWsqAAAGqAsAAoAAIACoDCEAIABYLADc56sXBC8BT5v+c5aAlQ5eYrYAYEDAAEAAEAAEAJUhBAAEAIsGgHsXAABnAIBK/y41WwAwIGIAIAAIAAKAyhACAAKARQPAvc4PrwA+NYYKoNLBS8wWAAwIGAAIAAKAAKAyhACAAGB7BcCLLrrI7rvvPpszZ47V1NRY//797ZJLLrG+ffs2dRH/4pZ/hOGOO+6wjz/+2AYMGGDXXnutbbbZZko3wrZACgCAAUICgAAgAAgAKkMIAAgAFgsAv9Y/vAI49enkFcADDjjA/AMLu+22mzU0NNiIESOiL2vNnj3bunTpEnWTk08+2R588EG7+eabbcMNN7TTTz/dFi9ebDNnzrTKykqlK2FbAAUAwAARAUAAEAAEAJUhBAAEAIsGgHueF7wEPPUvY1MvAS9cuNB69OgRfWJ1n332iX7Hv7p122232RFHHBF1m7ffftt69uxpjzzyiO2///5KV8K2AAoAgAEiAoAAIAAIACpDCAAIAJYaAM6fP9+6devWlObV1dXm/9Z1zJ071/r06RNVAfv162dPPvlktOTrFb8NNtigyX2nnXayQw891EaPHr2un+TvBVYAAAwQtAkArx9pmZpOiX6pc7e6RHb5Rg0NKUrjFXIzVv9OZ9mpolFzydTrJ9bYUZ80qpZmtBMzs1yl3k5ObEbVyy9CbcN9Gqv1axm1/72yZttVvy359Ougx79DhZ7/fZ44VjqvSOePOsg+3V/Szk29YfATqqrTYylfSPSdYr2dRjGemQb9zBrWzRpr/Ghlvd5OGo9sR80rW19nL94+InVVLUlr8bz09d3DK4BT/jp2jSZHjhxpo0aNWuup5HI5Gzx4sL3//vs2ffr0yHbixIl2zDHHmO8DzD/2228/69Wrl91www1JLg+bAioAAAaICQCaqUADAOoJBwBqkOUKA4B6ngGAumaiPiAVAAAZKUlEQVRtGgC/MiJ4CXjKsxdamgrgKaecYg8//LDNmDGj6QGPlgBw0KBB1rt3b7v++uv1AOARpAAAGCAfAAgAqnCmAnNUmRKrjO5DBZAKoDq0AYCqYmblAIC+dy9/CXhdKp166qk2efJkmzZtWlTZiw+WgNelXPH/DgAGaA4AAoAqnAGALAGrQw5LwKpiZiwB19rXdytABfBvFyZervZlX4e/SZMm2ZQpU6L9f/lH/BDI7bffbocffnj0pwULFkQVQh4C0XO8EB4AYICKACAACACyB1AZQtgDqKi10pY9gJpm8by075eHBy8B//m5cYkBcNiwYdE+v/vvv3+Vd//V1tZG7wX0w18D89BDD0WvgenevXv0TsBFixbxGhgtxAWzBgADpAQAAUAAEABUhhAAUFELANTVMvusALCiovnq/oQJE2zo0KHRpdTV1dmZZ54ZgWL+i6D9VTAcxVcAAAzQHAAEAAFAAFAZQgBARS0AUFcrDwB3PTe8AjjzosQVwDTnis9nqwAAGKA/AAgAAoAAoDKEAICKWgCgrlYeAO5yrlVVJns9WXPtNGTr7M/PA4BpYlAqPgBgQKQAQAAQAAQAlSEEAFTUAgB1tT4FwG/sfE4wAD75wsVUANMEoUR8AMCAQAGAACAACAAqQwgAqKgFAOpqAYBpNCtXHwAwIPIAIAAIAAKAyhACACpqAYC6WnkA+CWvAKb4jMonjTZkl9uTL1IBTBODUvEBAAMiBQACgAAgAKgMIQCgohYAqKuVB4A7nR0OgC9dwhJwmiCUiA8AGBAoABAABAABQGUIAQAVtQBAXS0AMI1m5eoDAAZEHgAEAAFAAFAZQgBARS0AUFcrDwB3KEAFcBYVwDQxKBUfADAgUgAgAAgAAoDKEAIAKmoBgLpanwLggH5nBS8BP/HypSwBpwlCifgAgAGBAgABQAAQAFSGEABQUQsA1NUCANNoVq4+AGBA5GMA3PySsZapSfjCzea/lrPWs2js1CifZUWD3lDlkozcjuqQq1I9imefRmfrlNVOsF7XuKJzg9aGmXXsvEL2GbDlP2Wfb27wouTTv/pDyd6N/5sVNTazb/3tJLmdipfWk306LdZcKpdr9m6dWZGTndQbE2+gsUofM6rq9HOTLyaFQ65Sd0pz/SZefra+zl66dXirVtXieWnA9meGVwBfGd+q56pHCY9CKgAABqgJAOriAYAAoJo1AKBIGWYGAKpZlg6A2zQAbndGOADOvgwA1FOpZDwAwIBQAYC6eAAgAKhmDQAIAKo5QwWw1gZ88fRwAPzHLwBANflKyB4ADAgWAKiLBwACgGrWAIAAoJozACAAqOZMOdoDgAFRBwB18QBAAFDNGgAQAFRzBgCstQF9C1ABfJUKoJp7pWQPAAZECwDUxQMAAUA1awBAAFDNGQCw1gZu87PgJeA//fNyloDV5CshewAwIFgAoC4eAAgAqlkDAAKAas4AgACgmjPlaA8ABkQdANTFAwABQDVrAEAAUM0ZALDWBvY5LbwC+K8rqACqyVdC9gBgQLAAQF08ABAAVLMGAAQA1ZwBAGttYO+fhgPga1cCgGrylZA9ABgQLABQFw8ABADVrAEAAUA1ZwBAAFDNmXK0BwADog4A6uIBgACgmjUAIACo5gwAWGsDt/pJeAXw9auoAKrJV0L2AGBAsABAXTwAEABUswYABADVnAEAHQB/bFWZalW6JvuGxuX2p9evBgBTK9j2HQHAgBgBgLp4ACAAqGYNAAgAqjkDAAKAas6Uoz0AGBB1AFAXDwAEANWsAQABQDVnAMBaG9jr1PAK4LxfUgFUk6+E7AHAgGABgLp4ACAAqGYNAAgAqjkDANbawC1+FA6Ab14DAKrJV0L2AGBAsABAXTwAEABUswYABADVnAEAa23g5sPCAfCtawFANflKyB4ADAgWAKiLBwACgGrWAIAAoJozACAAqOZMOdoDgAFRjwGw9/BxVtmpU6JfaqjRB/NMQ0Wi3843ylbr7VTWpWins9hOo3wp1litO1U06tfSWJOVT67TBnWSTy6nn1fnTvVSG27csVK/lg1qluntZLR29ug+T25jg6qlss8vZ39d9vn4I/2Jya6zNJ/K5fJpWc1isY+ZWWOV3k6FFsqogZx4P9PxI70vN9TofSZbrfuo1+LX31iltZOtr7O/TxjeqlW1eF4a2PPk8Arg/Ota9Vz1LMWjkAoAgAFqAoBmWQBQyiAAEACUEsYMAAQApZRpAsAvnBQOgP+5HgCU1C8tYwAwIF4AIABIBVArG1EB1AccKoBalc0VpgJYawMBQL2zlZkHABgQcAAQAAQAAUBlCGEJmCXgoi0Bf/7E8Arg2zdQAVQ6eInZAoABAQMAAUAAEABUhhAAEAAsGgBu6gDYUUnPVWwbGuvtTwsAwNQCloAjABgQJAAQAAQAAUBlCAEAAUAAUOkx2LamAgBggLoAIAAIAAKAyhACAAKARQPAz50QXgF850aWgJUOXmK2AGBAwABAABAABACVIQQABACLBoA9jgsHwHdvAgCVDl5itgBgQMAAQAAQAAQAlSEEAAQAAUClx2DbmgoAgAHqAoAAIAAIACpDCAAIABYNADc+NrwCuPA3VACVDl5itgBgQMAAQAAQAAQAlSEEAAQAiwaAG/0wHADf+y0AqHTwErMFAAMCBgACgAAgAKgMIQAgAFg0AOx+TDgALp4AACodvMRsAcCAgAGAACAACAAqQwgACAC2VwCcNm2ajR8/3mbOnGkLFiywSZMm2aGHHtrUPZYsWWLnnHOOTZ482RYtWmRbbrml/fjHP7aTTz5Z6ULYFlABADBATAAQAAQAAUBlCAEAAcBiAeCADY4OrgA+8f4tiSuAjz76qD311FO2yy672GGHHbYGAB5//PH25z//2W666aYI/h5//HEbNmyY3XvvvTZ48GClG2FbIAUAwAAhAUAAEAAEAJUhBAAEAIsGgOv/wKoqAr4Ekqu3Jz64NTEA5veDioqKNQCwX79+dsQRR9j555/fZLrrrrvaQQcdZGPGjFG6EbYFUgAADBASAAQAAUAAUBlCAEAAsFwB8KSTToqWh30J+POf/7xNmTLFvvWtb5lXDvfee2+lG2FbIAUAwAAhYwDc+pxxVtmpU6JfymUSma1ilO2U050aK3SfTIp2clo7uSq9jTQ+jdUp2umgT05dui+TdF5ep9+R13bT2vATqqzQr2X9mo+la3Hj5dkqyWeb2oWSvRtnTI/lPz/cWG7nzXc2lH06vJms38c/XL1IbsKqP9Cvv7Jeb6dRC2XUQGW9dm65jDZe6Fex0iOrdzPLaPcyUTvLu2nXk62vs1duGJ6qqpZUi3heGlB7VHgF8MPbbP78+datW7em5qurq83/re1orgJYX19vvgx86623WlVVlWUymWg5+Kijjkp6adgVWAEAMEBQANDMAEApgwBAAFBKGDMAUBUMALTa2lobsN7/CwfAj363hvojR460UaNGyQB42WWX2a9//Wvz/91iiy3MHxo599xzo6XigQMHpogyLqEKAIABCgKAACAVQK1sRAVQH3CoAOqaUQEsHAAWogL48ccfR1DqsHfwwQc3BfS4446zf//73/bYY4/pQcYjWAEAMEBCABAABAABQGUIYQlYWzJVtM23BQBrbUDX74dXAJdMTLVcvfoScDxXPvLII3bggQc2herEE0+0efPmRU8EcxRfAQAwQHMAEAAEAAFAZQgBAAHAYu0B/EbnIcEA+OSyOxMDoL/nb+7cuVF32Hnnne3yyy+3fffd17p3726bb765ff3rX7f33nvPrrnmmmgJeOrUqdE7AN2OdwEqo0jhbAHAAC0BQAAQAAQAlSEEAAQA2ysA+lO9DnyrH0cffbTdfPPN9s4770R7/rzat3jx4ggCTzjhBDvttNPMK4YcxVcAAAzQHAAEAAFAAFAZQgDA4kz0LAHX2jdqjgivAH78+8QVQKUfYNs2FAAAA+IAAAKAACAAqAwhACAAWLQKYPXh4QC4/C4AUOngJWYLAAYEDAAEAAFAAFAZQgBAALBoANjxe1ZV0UFJz1VsG3Ir7Mn6uwHA1Aq2fUcAMCBGACAACAACgMoQAgACgACg0mOwbU0FAMAAdQFAABAABACVIQQABACLBYD7Vn03uAL454Z7qAAqHbzEbMseAK+99lobP368LViwwLbffnu78sor7atf/WqiMAKAACAACAAmGiw+MQIAAcCiAWDld8IBMHsfAKh08BKzLWsA/P3vfx99h9AhcK+99rIbbrgh+jbh7Nmzo/cWresAAAFAABAAXNc4kf93ABAABACVHoNtaypQ1gC4++67///2zjXEqqqN44+jr5qa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\" width=\"640\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"\"\"\"Animated MLX Thermal Camera Demo\n",
"\"\"\"\n",
"%matplotlib notebook\n",
"\n",
"# Set up plot\n",
"fig, ax = plt.subplots()\n",
"grid_x, grid_y = np.mgrid[0:31:32j, 0:23:24j]\n",
"\n",
"def animate(i):\n",
" # read in frame from thermal camera and split into 32 x 24 numpy array of thermal readings\n",
" frame = [0] * 768\n",
" mlx.getFrame(frame)\n",
" pixels = np.split(np.asarray(frame), 24)\n",
" # rotate it around so its right side\n",
" pixels = np.rot90(pixels, 3)\n",
" \n",
" # Clear the current figure\n",
" plt.clf()\n",
" \n",
" # Create a color plot with a rectangular grid\n",
" plt.pcolormesh(grid_x, grid_y, pixels)\n",
" plt.colorbar()\n",
" plt.title(\"Animated MLX Thermal Camera (32x24)\")\n",
" plt.show()\n",
" plt.pause(0.05)\n",
"\n",
"ani = animation.FuncAnimation(fig, animate)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"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.7.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}