Files
rasbt--python-machine-learn…/faq/decisiontree-error-vs-entropy/decisiontree-error-vs-entropy.ipynb
T
2026-07-13 13:38:23 +08:00

2489 lines
200 KiB
Plaintext

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Why don't we use the classification error as a metric to grow a decision tree?"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\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",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var 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);\n",
" canvas.attr('height', height);\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'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" 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 + '\">');\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 dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\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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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"%matplotlib notebook\n",
"\n",
"\n",
"def entropy(p):\n",
" return - p*np.log2(p) - (1 - p)*np.log2((1 - p))\n",
"x = np.arange(0.0, 1.0, 0.01)\n",
"ent = [entropy(p) if p != 0 else None for p in x]\n",
"plt.plot(x, ent)\n",
"plt.ylim([0,1.1])\n",
"plt.xlabel('p(i=1)')\n",
"plt.axhline(y=1.0, linewidth=1, color='k', linestyle='--')\n",
"plt.ylabel('Entropy')\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\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",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var 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);\n",
" canvas.attr('height', height);\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'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" 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 + '\">');\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 dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\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,iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAAXNSR0IArs4c6QAAQABJREFUeAHsnQm8jdX6x38IRyTKLU1S3eZB3FJdldyb4TY4TRquBtGfpIkmROOtiJRuk1sZSuXcUuFWjgZUOOiKi2ggJTkpIdNBx/4/z9n2sc+29z5773d+1299Po/9jutdv+/zvO9Z1rvWegEmEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEiABEvANgSq+KUkwC6L89hdbH8zis9QkQAIkQAIkYCyBPUT5j2IREwnsZqJoGzVr5e8HG/NjViRAAiRAAiRAAu4ROFAutcK9y/nnSqwAWvNFWcvf8uXLUbduXWs5+fDstm3borCw0Iclc75IJmtXutTP2Hf+LvPnFRj7ZsT+b7/9hoMOOkiD0Ng3eKwA2vAM0spfGCuARx55ZCh1ZeJyk7UrH+pn7Gdyn4TxGMa+ubEfxnhOp6lqup3cZzaBvfbay1gAJmtXp1M/Y9/Um5+xb27smxbzrACa5vEs9OqrEFOTydrV59TP2Oe9byYB0+99k7zOCqBJ3s5S65577pnlGeE53GTt6kXqZ+yH527OTglj39zYzy5Sgn80K4DB96FjCubNm+dY3n7P2GTt6hvqZ+z7/R51qnyMfXNj36mY8mu+nAfQmmd06O86ScYOlrCGj2eTAAmQAAmQgPsEdBTwjtZebfL8zf0SeH9FtgB67wOWgARIgARIgARIgARcJcAKoKu4eTESIAESIAESIAES8J5A0CuAlwnCj8XWiZWKVaannhzzithasV/FXhZL7PF6iWxbJLZRbKHYhWJGpj59+hipW0WbrJ36zfY/Y9/c5x7vfSVgTgp6H8DW4iqdtGh3sRfEqottF0uV3pEdeoxWHFV7gZhW9C4Q03SK2BSxK8QmiOWLjRY7XWyOWGIKdR/A4uJiNGzYMFGzEesma1cHUz9j34gbPYlIxr4Zsc8+gNFKUJJbIHCbWkqJPxJLVwFsJPuXiZ0gtkBMky7PFdN9+k3f4WLaInixWCy9KQurxf4vtiHuN9QVwDidXCQBEiABEiCB0BBgBbDyV6ahcbYIOVGsRCxW+VNt/xPbKqb7NOnvrLKlnf/MlsWmO1e5RAIkQAIkQAIkQALBJlBZn7lgq6tY+rLWuoqbytbWyr+6T5P+6np8WiMrsf3x20O/XFhYGHqNqQSarF2ZUD9jP9W9EfbtpsZ+qfSi37xZ+j5NKMT27WH3MvUpgd0MwqDz/CQO+FD59cR0EIkmPUbX41N9WdHtKZM2JSdLtWvXRrVq1XbZVSp32saN2vVw11SzZk2oJUsbNmyQG3PXO7Nq1aqoU6dOslOwZcuWMku2s7Ly/fjjj0jU5qfyJdNkV/nWro3+P8AKPyfLF8vbqfLF9Meuo79ux1/8tWPLdvk3ll8qfhr7ep8G+f6NaYz/zYRf4n3v1PMlvlyx5UzKFzs29mt3+X799dddnnuxa/mhfBqXq1dvhBSzzNZIE0Vsef36mjIxbU3ZL/2WxPRP01Z5x6W2efMG+d1evq7btm3TfVXF6sRV+qLPPv3TVb36Fvl7tEV+gRo1oqbL+icqL6+2/FYr215P/mruvbd+QxyoX79U/h5t3LEc3RbdDuyxh3/+viX+bYv5mL/BI6B9ACsbBaz9/PSY4+LkNdmx7cAd27QP4Btx+3XxTbHnE7bFVrVlMJLKFixYENE0ZsyYyMSJE8uW9Z8pU6akPOfee+8tO27RokWRAQMGlC3H/tlnn32SnnfMMcfEDon07t07snLlyvL1jh07Jj1Hy8zyRX1HfjtjmPG3kwXvD94fic92N++Pxx5bEBk0KBJp23ZMpHnziZETT4xEDjwwEqlRY0rKZ/pxx90bufHGSOSGGxZFzj9/QGTEiEjk1VcjkbFjI5E990z+9+OPfzwmsnRpJLJiRSRy8829I/Pnr4z88EMksmRJRPJI/ffj8ccXlOV9/fVjIl27Toz06xeJdO8eiZx1VuryVa9+b+TggyORY49dJDYgcuutkcjjj0cib74Ziey1V/Ly2fl81r/DHTp0SORn5Bs+ie2ykbD6G9Skr7B14EdLsffE9hDTSp7261MnJyYd2avHdxTTUcCviW0Qi031oqOAJ4vpKGAdMZwv9pLYGWJzxBKTBs665cuXJ/0SSGUtbImZ6bpf/ocZhBZK8oOlFl7yI7/4GDCphVd1e/V81ha7L74Ali4FlizZgm+/3QL5E4Lvv5eRiDIUUV7aoEEDoHHj2mLVcPDBKLODDgL+8Ad5RVWvVFrfNsqvttDFe9C/fz9Uk75U2bChJrSV8uefo3q/+w6I2bJlG7BmzXbsLnN6qFa1RtJsc/DBVXHEEXVw6KHAMcdAWhd3ak7Vgp+Jf7UF8CC9SPTNYPLXeDsvFcqloE8Dc414ZYRYZId3VI8utxL7VkxuM7QTmyamSW4ZPCV2npgepxXCG8Xina8jgP8hdrDYMrG+Ym+LJUtlFcCwfgqupKREHjR5yXSHfpvJ2tW51M/YD/1NnkKgXbG/fn20ordwoYw8lKGHarosvQuw//7AYYdFK3axCl7sVys9tWqlKJwLm+3Sn0tRlZlWhGOVQv1dtiy6/s03wC+/aMVYXuMdBxx77M7fo47KnplWAE3/FJxWmJhyJxDqCmCvXr0wZMiQ3OkE+EyTtavbqJ+xH+Db11LRs419+X9yWYterKIX+9XKi7bkaWUlZlppUauvPct9mrLV76aMVat2VqTjK9VacdQKdWLF8Mgjd20ljZWXFcDgvwKO+dKr31BXAL38n6BXDo1d12TtyoD62QIYuxdM+00X+xF5b6QtUkVFwIwZ0d+5c+VLBPLaMr7yEVveZ5/g0Uun349q1CcrVuxaMdTX7LrvpJOA004DTj01avvtF1XBCiArgFbjOdQVQKtweD4JkAAJBJmATLyA2bOjFT2t9KnpiNumTXdWKLRiccgh8seU79N85WqdMGPx4oq+01ZD7fanPjvxxN/Qt++eWmb9J74bmK90OFkYhqw1uqwAWuPHs0mABEjANwS+/RaYOnVnpWH+/Gh/vVjrkbYkaeXPyz56voEVwILotDiffRb178cf/ybznZpdAawaQB+yyC4RKCjQTyWbmUzWrh6nfsa+CXe+tuaNHQtcf320D5n2GXvkkQKZrw7o3z86+EBH6L7+OnDbbcCf/xz+yl+Y7/260mTzl7/IyE4Z2vnvf5sQ4ek1mjQRdHoS3LsLgXo6z4ChyWTt6nLqZ+yH8dbX6UimTwfefx/44APgv/+NTi1y9tnAP/8JnHmmTBkxrR7atg2j+sw0mX7vZ0YpHEfxFbA1P/IVsDV+PJsESIAEHCOg/cD0Na5W9rTS9/HH+p8boHVrQCt9arFBAY4Vghn7kgAHgZj1KThfBiELRQIkQAIkYB8BbeX78EPgrbf0u7Y6+TBw1lnA3/4GmdYKOPpoDtiwjzZzCjIB9gEMsvccLntxcbHDV/Bv9iZrV69QP2Pfv3fnriXTeeC0T9fll0e/ltG9u37pAxgzJjpq9z//AW65Jfq6t7LRuox9c2N/18gK9xZWAMPtX0vqhg4daun8IJ9ssnb1G/Uz9v1+/+rnxF58UT7rdF600nf//cDhhwNTpkTn6nviiWjLX40a2Slh7Jsb+9lFSvCPZh9Aaz5kH0Br/Hg2CZAACWRMQD8Tpq921T79NDrJ74UXysfcxY44IuNseCAJgH0A2QeQtwEJkAAJkICPCWhLn77Kffll4PPPgZYtgQ4dgFdeAQ44wMcFZ9FIwOcEdvN5+Vg8EiABEiABwwjo93W1395LLwETJ0Y/5dW1a7Slb++9DYNBuSTgEAH2AXQIbBiyHTZsWBhk5KTBZO0KjPoZ+zndOBZO0u+26hx9OimzTs3Spw9w8snAl19Gv85x3XWAG5U/xr65sW8hfAN5KlsAA+k2dwrdpEkTdy7kw6uYrF3dQf2Mfbduy6VLgdGjo619q1dHR/K++270e62Vjdh1ooyMfXNj34l48nOeHARizTscBGKNH88mARIwkMC6ddFpW/QV78yZ0Tn6rr46OqK3Zk0DgVCy6wQ4CISDQFwPOl6QBEiABEwl8L//AU8/HW3x0wmZr7kGePPN6DQupjKhbhLwigD7AHpFPgDXXbx4cQBK6UwRTdauRKmfsW/XnbV1K/Daa8Dpp0df65aWAp98Anz2GXDTTf6r/DH2zY19u2I+KPmwAhgUT3lQznHjxnlwVX9c0mTt6gHqZ+xbvROXLwf69wcaNQLuuQe4+GJgxQrghReAZs2s5u7c+Yx9c2PfuajyZ87sA2jNL+wDaI0fzyYBEggRAR3J+9FH0de877wDtGsH3HAD0Lo1UJXNDSHydPClsA8g+wAGP4qpgARIgAQ8JqCDOkaNAp55BtCRvDply5AhQOPGHheMlycBEkhJgNPApETDHSRAAiRAAukIfPcd8NhjwPDhwPHHA/36Rb/SwZG86ahxHwn4gwAb5f3hB1+WYuDAgb4slxuFMlm78qX+8Mf+lT2uxGkdTtvFGh3faJdtepweH0vz5wNXXQUceSSwalV0ouYZM4Ar5ZCgV/4Y++GP/Vgcm/7LFkDTIyCN/vz8/DR7w73LZO3qWeoPf+wvWbUERccV7Xoj7wss/4OM4EhMC4BPPwUGDAA+/BDo1AlYuBA47LDEA4O9ztgPf+wHO0LtKz0HgVhjyUEg1vjxbBIgAY8IaKte0gpgivLUKTgVVVfMQI8ewM03Aw0bpjiQm0kgAAQ4CISDQAIQpiwiCZAACXhPYK/6wHxpMKyr/+1lIgESCDwB9gEMvAudE1BUlOT1kHOX81XOJmtXR1C/ubGPJG9/NSb239+Myh9j3+DY10A3KLECaJCzs5U6b968bE8JzfEma1cnUr+5sY+fQnMb5ySEsW9w7OcUMcE9iX0ArfmOfQCt8ePZJEACHhHItg/gqQtOxYzXZagvEwmEgAD7AMrk7CHwIyWQAAmQAAlkSUC/2sFEAiRgLgFWAM31PZWTAAkYSKC0FHj5ZWDuXAPFUzIJkEA5AVYAy1FwIZFAnz59EjcZs26ydnUy9Ycv9rdvB8aOBU44AbjnHuDAA1Pczh+k2G7IZsZ++GLfkNDNWib7AGaNrMIJoe4DWFxcLHN9mTnZl8naNcKpPzyxr696330X6N8f+EkGeOjn2rp0AVp2TDEP4HoJgD0qPOfKVkzpA8jYD0/s7xrFO7ewDyD7AO6MBi7tQsDUyp+CMFk79YfH/1OmAC1aRL/aoZ9p++YboHt3oEYN9XKKlKTyl+LIUG7mvW/mf/pDGcyViOKn4CoBxN0kQAIkEDQCX38N3H47oBXAO++Mfrljj4SK3WH7yDfc5PNumaay4zM9mMeRAAn4ngArgL53kXcFLCwsRNu2bb0rgIdXNlm7Yqf+YMb+mjXAgw8Czz4bbfXTiuA++yS/kUY/PTrpDvo+mL5P6swcNpru/xyQBfYUDgIJrOucL/jatWudv4hPr2CydnUJ9Qcr9n//HXjmGeDww6VRT1r1Zs2KVgJjlb/iDcUY/vnwjO42+j5Yvs/IqVkcZLr/s0AV+EM5CMSaC0M9CMQaGp5NAiTgBoGJE4HbbgO0EjhkCHDOOUCVuCf70jVL0frl1ji90ekYmT9S9sXtdKOAvAYJ+JAAB4FwEIgPw5JFIgESIIHKCSxaFK3s/f3vQNeu0Za/c8+tWPmb/9N8nD78dLQ/oj1G5I9g5a9yrDyCBIwhwFfAxrg6e6ElJSXZnxSSM0zWri6kfv/G/urVwE03Ac2aAX/8I6D9/G65BaheveLNN2P5DLQc2RI3nHwDhrQdgqpVMnvc0/f+9X1FDzuzZrr/naHqz1wzeyL4s+wslcME+vbt6/AV/Ju9ydrVK9Tvv9jfuhV44olopW/pUmDOHODJJ4G99971PpqybArajG6Dh/7yEPqd2S+rlj/63n++39XDzm0x3f/OkfVfzuwMYs0noe4DqP8TzMvLs0YooGebrF1dRv3+iv2PPwauvz76elf7+VU2OP+H337ArBWzcNHRF2V9B9L3/vJ91g60eIIp/mcfQHmeWIwV008PdQXQdOdSPwl4TeCXX4A77gBefx24777kr3q9LiOvTwJBJMAKIAeBBDFuWWYSIIGQE9DPt40YARx1FPDrr8AXX0Qndk7s5xdyDJRHAiTgIAH2AXQQbtCzLigoCLqEnMtvsnaFRv3exb5W9s46C7jnHuCFF4Bx44BGjXIO5axPpO+9833WznLgBNP97wBS32YZlgrg/UJ4hZh+xnyK2LFiqZL8nxrviv0sJi9Y8KJYHbFYaikL28V+22Ga5/dixqV69eoZpzkm2GTtyoD63Y/9zZuBu+8GTjopajrNywUXxCIy+e+20m14Yc4L2B7RR5Y9ib533/f2eM6eXEz3vz0Ug5FLGPoASg8Z3Cj2N7ElYveKXS12hNgmsfikX8NcKDZKTCuN9cWkdw1kYgVcLKZJK4Afieln8iJi6RL7AKajw30kQAIZEdDJnHv0ABo0AIYNA048sfLTNm/bjMveuAzL1i7D1E5TUb+WPs6YSIAEMiHAPoDh6APYXZw9SExenGCLWH8xnRHrQrHE1EI27CWmx8i8+WWtgPLlTOSLHSAWn8LSOhqvicskQAI+IrByJXDZZcDll0f7+E2fnlnlb13JOvztlb9h9ebVrPz5yJ8sCgkEiUDQKznaAtdYbHYc9FJZnivWNG5bbDHW4hn71e3VxHQ98f/cS2Vbsdj7YmeKGZeKi1W+mclk7epx6nc29kvlKfX009FBHlXlKbx4MdBd/itbTZ9GlaRVG1eh1ahWqFW9FiZdOcn2lj/63lnfV+Jez3eb7n/PHeBiAcJQAVRcaxOYrZF1rRwmJvn/dVk/wYflN09MW/3uFtMUO14exWWVwUPk9zAxeTmDQrETxIxKQ4cONUpvvFiTtSsH6ncu9vXLHWfKfyl1Pj+d3uW114CGDeOjL/Wyzu93xogzcFSDozDu8nGoXaN26oNz3EPfO+f7HF3i6mmm+99V2LyYJQJaadsudkpCLlphG5ywLbbaRBYmif0k9pVYVzHNo7VYqvSR7PhHkp16/UibNm0iPXv2LLPx48eX/W7evDkSS2PGjIlMnDgxthpZuXJlpHfv3uXruvDcc89FZsyYUb5t0aJFkQEDBpSv64Ku6/ZY0uP1vPik+Wr+saTX1evHkpZLy8ryRcp4k180Mhh/UQ5O3h+PPDIg0qfPokjt2pHILbdEIpMnZ3///rzu58iZl50Z2bhpY+yWLru/+XyJ4uDzL8qBfz+S//3V+6Rr166Rk08+OdKjRw/t46+mf8eNTPGvQoMKYKkUXP4vjad2CNCXKNKzBj3FXtmxLd2P9v8bLba/mI74TZY+lI1FYrHWwtgxGjjrJKFuXWNjKMaCvyRAAikILFkCdO4M/PADMHy4jDTToWZMJEACnhHgIJBwDAJ5RiLodrFjxWqJaUudDgZ5SyxZaiYbdxfTiuIZYo+L3SsWq/y1keXGYlo51vxuFfuz2FgxJhIgARLImMB2ebegff10VO/xxwPz5rHylzE8HkgCJOAogaD3AVQ4+qp3pNgHYj+LnSbWTkyngDlITCt2LcRiqYssfC+2Tkwrjw+KaQtiLDWXhaliOg/gd2Lni2l+c8SMSsN0PgpDk8na1eXUbz32ly0Dzj5bpigYFJ3M+Sl5R1EnfsZRn95b9L113/vUtRkVy3T/ZwQpJAeFoQKorrhPbD8xfbyeJaZz/WlaLraH2DRd2ZF6yK/MtlV2rPyfHCN2bI/9aAviwWJ63j5ifxXTCqFxqUkT7S5pZjJZu3qc+nOPff2M27/+JaPGTgAOPxz43/+Av/wl+/to3OJx2LRN/x/rbqLvc/e9u55y5mqm+98Zqv7MVV9zMuVOQDv+sQ9g7vx4JgmEisBy+S9nly6AfsXjxReBNtqhJIf06LRH8dAnD2HKNVPQdL+mOeTAU0iABNIRYB/AcPQBTOdj7iMBEiABxwloq58O7jjuOOl3Ih1PFizIrfInYzhx1/t3YfD0wZh8zWRW/hz3HC9AAuYSCMsrYHM96KDyxTo7raHJZO3qcurPPPZ1vvTzzpPPC/WPzumnLX977pn9jVO6vRRdJ3TFmIVj8GnnT9FsPx2v5n6i7zP3vfvecf6KpvvfecL+uQIrgP7xhe9KMm7cON+Vya0CmaxdGVN/ZrH/3nvRvn5a4dNWv3POyS1Ct5ZuLfuu77Tl0zCt8zQcsfcRuWVkw1n0fWa+twG1L7Mw3f++dIpDhWIfQGtg2QfQGj+eTQKBJLBlC9CnD/DCC8A//wlcfbXMG2Xhaaqtfw9+/CBubH4jGuyuY9SYSIAEnCTAPoDRue6cZBz2vFkBDLuHqY8EEgh8+SVwxRXSgVren+hn3HSkLxMJkECwCLACyEEgwYpYlpYESMAzArGBHiedJHNDyeRQ06ez8ueZM3hhEiABywTYB9AywvBmMHDgwPCKq0SZydoVDfVXjP21a6Otfn37Am+8EZ3cuUaNSoIooLvp+4q+D6gbcy626f7PGVwAT2QFMIBOc6vI+fn5bl3Kd9cxWbs6g/p3xr629Omn3OST32Wfcmvb1lq4ziueh5Xr9XPl/kz0/U7f+9NDzpbKdP87S9dfuVvotuwvIR6Vhn0APQLPy5KA0wRKS4EBA4CHH5bvRT4oHwWXr4Jrvz8r6ePvPkb719rj8baP49qm11rJiueSAAlYIMA+gMBuFvjxVBIgARIIJYEffgCuugpYsQL45BOgmQ1T8k34cgKuGHsFnmj3BCt/oYwaiiKBYBGw+P/ZYIllabMjUFRUlN0JITraZO3qRpP1jx8PHHtsEQ45BJgzx57K38vzXsblYy/HqAtG4bpm1/n6TjHZ96bHPvX7+ta0vXCsANqONDwZzps3LzxislRisnZFZaL+338H7roLuPJKoEOHeWWfdqtTJ8vASXL40KKh6PFuD4y7fBwuPubiJEf4a5OJvo/3APWb+9yPjwMTltkH0JqX2QfQGj+eTQK+IPDTT9FRvvpZtzffBI46yr5iDZo2CC0bt0TzA5rblylzIgESsESAfQA5EbSlAJKTWQG0SpDnk4DHBGbMAC65BDjjjOiXPexo9fNYEi9PAiRQCQFWADkRdCUhwt0kQAJhJaATOz/1FHD22cCdd0a/6sHKX1i9TV0kQAKJBNgHMJEI18sJ9NGPnRqaTNauLg+7/o0bo339dIqXwkLgllsqfss37PrT3dYmazch9tP5nvoroxOu/ewDaM2foX4FXCwdoho2bGiNUEDPNlm7uizM+r/6CrhYxmLstRdQUACJ8V2DNBf9a0vW4sf1P+KYPxyza4YB2pKL9gDJq7So1G/Gc5+vgPkKuNKHgckHmFr5U5+brD3M+t96Czj5ZKBdO+CDD5JX/nLRr1/2aDmyJR6b/pieHujE2E/yP4JAezS7wpvu/+xoBftoTgQdbP+x9CRAAhkQ0Cle+vUDnnkGZdO76KAPu9LSNUvR+uXWaHFQCzx33nN2Zct8SIAESMBRAuwD6CjeYGdeqJ2jDE0ma1eXh0n/qlVAmzaATvA8a1Z0xG9lYZ2p/vk/zUeL4S3Q/oj2GHnBSFSvVr2yrH2/P1PtvheSYwGp39znfo4hE9jTWAEMrOucL/jatWudv4hPr2CydnVJWPTrx2z0M2777BOt/GU6v18m+qcvn1722rfHyT0wpO0QVK0SjsdpJtp9etvaUizqN/e5b0sABSgTDgKx5qxQDwKxhoZnk4C3BEaPBrp1Ax56aNdRvnaUbMyCMVizeQ26n9zdjuyYBwmQgIsEOAgEYB9AFwOOlyIBEnCewPbtwN13A88+C+igD33960S6/LjLnciWeZIACZCAKwTC8c7CFVTmXaSkpMQ80TsUm6xdEQRV/4YNwEUXAW+8Aejr31wrf0HVb8cNa7L2IMe+Hb6nfrsoBiMfVgCD4SdPStm3b19PruuHi5qsXfkHQX9EPuVx3623Qn81ffcd0KIFsH49MHOmte/5BkF/mWgH/jFZu+KkfnOf+w7cTr7Okn0Arbkn1H0AtSUgLy/PGqGAnm2ydnVZEPS//corGC+d/NoPG4Z9DumICy+MTvA8dChQ3eJg3Hj92yPbsXDVQhy/7/EBjebsih2vPbszw3E09Zvx3GcfQPn6UThuWc9UhLoC6BlVXpgEKiGgrX5dZHjvC3Pn4qJGJ2LSz3MwaFAV9OhRyYlZ7t5Wug3XTbgO//3xv5h7/VzsVpXdprNEyMNJwJcEWAHkIBBfBiYLRQIkkJ7AuFdfRXv5ppv2Yenw/Vf4012vSuWvY/qTsty7edtmXPbGZVi2dhnev+p9Vv6y5MfDSYAE/E2AfQD97R9PS1egH0o1NJmsXV3uZ/3a+vfWwMHI37SpLDr/jk34tnBweV9AO0J2xMsj0O6Vdvh186+Y2mkq9ttjPzuyDUQefva9GwCp39znvhvx5adrsALoJ2/4rCz16tXzWYncK47J2pWyn/W/MPRVtFvwVXn/Fe3Hoq2B2ipoR1q1cRUemv0QalevjUlXTUL9WvXtyDYwefjZ925ApH5zn/tuxJefrsE+gNa8wT6A1vjxbBLIisCnn0bQ86xmmFU6t7wCqBnoOOAuJ56IF+fMQZUq1h5rs1bMwrDPhuHZ855FjWo1siofDyYBEggGAfYBRFkXmmB4i6UkARIwmoA28LX/66u4q9rO1r8YEDtbAZsf0Bwv5r/Iyl8MLn9JgARCSYBD2kLpVntEFRcXo2HDhvZkFrBcTNaurvKTfp3m79FHgYcflgEfrT/FtF+Ox/QkrXzaN7Dep5/igo7WB4P4Sb/bt47J2v0W+277nvq9IM5rBpWAvgKOrFu3Tv72hC/17t07fKIyVGSydkXkF/2//x6J3HhjJNKwYSQyZ06GzrPhML/ot0FK1lmYrF1hUb8Zz339u61/v8X077iRyVpnGSORVRDNPoAVcHCFBOwjsHkzoI15ixYB770HNG5sX96xnJb8ugSH7XVYbJW/JEAChhBgH0D2ATQk1CmTBIJFYPVq4OyzgVWrgGnTnKn8vTDnBZw47ESs+G1FsOCwtCRAAiRgAwFOA2MDRGZBAiRgH4Fly6Lf9N13X+D994G99rIv71hOj057FLdNug3v/P0dHFD3gNhm/pIACZCAMQRYATTG1dkLHSbfWDU1maxdfe6V/s8/B047DWjdGnj9daBWLXsjULp44a7378Lg6YMx5ZopOPPgM5NewCv9SQvj8kaTtStq6jf3ue/yreb55VgB9NwF/i1AkyZN/Fs4h0tmsnZF64X+SZOAli2Bnj2BJ58EqlWz18ml20vRdUJXjFk4Bp92/hRN92ua8gJe6E9ZGJd3mKxdUVO/uc99l281zy/HQSDWXMBBINb48WwSKCMwahRwww3Av/4VHfjhBJaV61fimrevwfD84Tiw7oFOXIJ5kgAJBIQAB4GgwmT6AXGbr4rJCqCv3MHCBI2AzvH3yCPAwIHAm28Cf/1r0BSwvCRAAkEkwAogRwEHMW5dK/PixYtdu5bfLmSydvWFG/p//z3a6vf008DHH/ur8ueGfr/FfKw8Jmt3K/ZjrP34a7r//egTp8oUlj6A9wsgncthvdgUsWPFUqWjZMe7Yj+L/SL2olgdsfh0iazI7GPYKLZQ7EIx49K4ceOM0xwTbLJ2ZeC0fp3j7+KLgalTgRkztN9VjLw/fp3W7w+VyUthsnYlQv3mPveT3xHh3RqGPoB3iHtuFPub2BKxe8WuFjtCbJNYfNpDVrRCJz2OoJXG+mIy1hAy6xjkz1FZOkX+nSJ2hdgEsXyx0WKni80Ri098BRxPg8skkAGB336Tb/q2B7ZtA/7zH7kJ9S60OWl/v4Z1GqJKkk/G2XwpZkcCJBBAAnwFHI5XwN0l9gaJfSG2Ray/WHWxC8USUwvZoLOK6THyAqqsFfBB+dVKXmwysG6yrC2Eb4uViknPJEwU0+swkQAJWCAQm+C5Zk1AR/06Ufn7fOXnaPJcE0z8Rm9bJhIgARIggWQEgv4KWFvgGovNjhOnlba5Yk3jtsUWYy2esV/drpNN6PqJuiJJf2eVLe38R/NPlt/OI7hEAiSQlsDKlcBZZwEHygDc8eOB2rXTHp52p87n9+2335aZLsfSx999jFajWuH2P9+Ovx2uLwWYSIAESIAEkhEIQwVQda1NELdG1rVymJimywbtJ/iwWJ6YtvrdLaYpdrz+Zppf2Ylh/WegDs00NJmsXV1ut/5ly4AzzgCaNQP+/W9AWwBzTSMkg6Z//ztOGTq0zHRZt034cgLOeeUcDG4zGHe2uDPX7MvOs1u/pcK4fLLJ2hU19Zv73Hf5VvP8crt5XgJrBZDeRGWpXkI22qvoh4RturpOrJ2YvjL+bsf6YPmVP01lr4PlB5pnsvxi19JjjEj5+fpm3Mxksnb1uJ36dTC5ftnjggsAqbOhqoX/dmpF746ZM7G6W7fywPxZlm5++w1s/c8reLX3KFx8TKw7b/khWS/YqT/ri3t8gsnaFT31m/vc9/jWc/3yFh7Frpc12QW1UrZM7OS4nfpKV1/Xfh63LX5xnqy0EZMvjZYNFPlJfjeKzRTTNFcsPj/dpuup8kOHDh3Qq1evMpswYULZb0lJiZ5XlgoKClBYWBhbRXFxMfr06VO+rgv6+aGioqLybToUP/F/oroeP0Rfj0/8bJHmq/nHkl5Xrx9LWi4tayblO+qoo2Kn+bJ85YWTBbv5xbRb4edk+WJ5O1U+zd+O+Hv66UI0b16Aq2VYln7dY+vWzOMvplF/1b8zZLjwEzJZ4Orzzwe+/x547bXyQzZccAnqzGmIY6ocU77Nyv3RuHHj8nyCev+WC5CFbO6PWOxb4ZfJ8yXX8sXOc6p89erVC8TzOcZBf7Pxb+y8VPxUfyw59Xzx6u+b6ukm/3ls3rw5+vbtG5Np7G98X7igQrhdCq6jgM8VWyp2j9iVYkeKJY4Clk1oJiZtEmUDRv4sv6PEnhIbIqZJRwFPFtNRwO+I6X+HXhLTVsI5YvFJXxevk4S6dXWRiQRIIEZgunS4OFfuSv2/zp3W3siWZal9/vS178/alJgk/eHttzHzlltwyCGHJNnLTSRAAiSwkwBHAYdjFLC+wh0p9oGYvg06TUxf82rl7yAx7fOno39jqYssSPNB2evgZ+RXRwHHKn+yWNYSeJX8DhDTFkbd31EssfInm8Kd9H+IpiaTtavPrep//32gbVvpbCu9be2o/Lkdh1b1u11eO69nsnblSP3mPvftvI+CkFfQXwHHGN8nC/uJ1RE7S2yhmKblYjr33zRd2ZF6yG8DMT32eLERYolprGw4Wmx3MX2n9LaYcWnePH1bbmYyWbt63Ip+aYgr6+/33HMyd1J3++JHX8vu/9NPKTPUffGvblMemMEOK/ozyN7Xh5isXR1D/eY+9319YzpQuDC8AnYAS8ZZ8hVwxqh4oAkERsuU6ddfD7zyinamt1/xc6++jH7/nRvtBxiX/d7S93bQKafg2ksvjdvKRRIgARJIToCvgIGgjwJO7lluJQEScJ3AM9Khondv/ZSWM9/1XbN5DV4ueQ4t9myM76R58ceGDcs07i+Dnm656CJW/lz3OC9IAiQQZAKsAAbZeyw7CfiEgE4ZOUB6zepg99O0F67NST/t1nZ0WxxS/xCM6fMC8nbLw7Jly8quoq99+ck3m4EzOxIggdATCEsfwNA7yguBiVPVeFEGr65psnZlno3+hx4CBstQrMkydt6Jyt/SNUtx+ojT0XS/phh76VjUql6rrMKno33VnKj8ZaPfqxh16roma8829p3ygZf5mu5/L9m7fW32AbRGPNR9AHU+wYY7XrNZwxS8s03Wrt7KVL9W/p54AvjwQ+CEE+z38/yf5qPN6Da4/NjL8Vjbx1C1ijv/Z81Uv/2Kvc/RZO1Kn/rNeO6zDyDKvoHr/RMnuCUIdQUwuG5hyd0g4HTlTzV0HtcZh9U/DH3P6OtIS58bnHgNEiAB/xFgBZAVQKtRyQqgVYI8P5AE3Kj8KZjtke2utfoF0hEsNAmQQE4EWAEMx0TQOTmfJ1VOQD+bY2oyWbv6PJ1+typ/Wg63XvnqteJTOv3xx4Vx2WTt6k/qN/e5H8b7OZ0mdzrUpCsB9/mWwNq1a31bNqcLZrJ2ZZtKv5uVP6d9nC7/VPrTnROWfSZrVx9Sv7nP/bDcw5nq4CCQTEklP46vgJNz4dYQEnCy8heJRLBp2ybUrlE7hOQoiQRIwG8E+AqYr4D9FpMsDwn4koCTlT/t59ezsCcue+MyX2pnoUiABEggjAT4CjiMXrVJU0lJiU05BS8bk7Wrt+L1O1n521a6DZ3e7oQJX03Ak3970jeBEq/fN4VyqSAma1fE1G/uc9+lW8w3l2EF0Deu8F9B+vbt679CuVQik7Ur4ph+Jyt/m7dtxsX/vhhzi+fi02s/xaH1D3XJu5VfJqa/8iPDd4TJ2tWb1G/ucz98d3N6RewDmJ5PZXtD3QdQ/yecl5dXGYNQ7jdZuzpU9T/2WJ5jkzyvK1mH9mPao3R7KSZcMQH1a9X3VRyZ7H+Ttcdi39Tnnkn62QeQfQB99UfHb4Ux+SFosnaNQycrf5r/S/NeQu3qtTHpqkm+q/xp+Uz2v8naTfc99SsBcxJbAK35OtQtgNbQ8OygEnjkEWDIEOc+76ZcdNTv79t/R/Vq1YOKieUmARIIMAG2ALIFMMDh63zRCwoKnL+IT69gqvZ//hMYNAi4444CR77tG3N3lSpVfF35M9X/6h+TtVM//R97Rpnwu5sJIqkxNwL16tXL7cQQnGWi9pEjgbvvBt5/XyfDNdf3Gr4m+j9225qs3XTfU3/sLjDjl6+ArfmZr4Ct8ePZPiHwxhtAp07AhAlAq1b2FmrL71tQc7ea9mbK3EiABEjAAgG+AuYrYAvhw1NJIBwE3nsPuOYaffVjf+Vv7BdjccJzJ6Dkd84tFo5ooQoSIIGwEOA8gGHxpAM6iouLHcg1GFmaon3qVKBDB2DECODcc3f6xg79L8x5Ade8fQ0Gtx6MvN2CNZ2QHfp30gzWksna1VPUb+5zP1h3qvXSsgJonWFocxg6dGhotVUmzATts2cD7dsDT8oHOC69tCIRq/ofnfYobp90O97t+C7OP/L8ipkHYM2q/gBITFlEk7UrFOo397mf8qYI6Q72AbTmWPYBtMaPZ3tEYMECoGVLoH9/4NZb7SuETu9y1wd3YdS8UZjYcSKa7tfUvsyZEwmQAAnYRIB9AAGOArYpmJgNCQSFwDffAK1bRyt+dlb+VP/05dPx+hevl33a7fC9Dw8KEpaTBEiABIwjwBZAay5nC6A1fjzbZQLLlwNnnBHt9/foo4BMx2d72rRtE3avvrvt+TJDEiABErCLAFsAOQrYrlgKZT7Dhg0Lpa5MRIVR+6pVwNlnA23bApVV/qzoD0Plz4r+TOLLz8eYrF39Qv3mPvf9fF86UTYOAnGCakjybNKkSUiUZC8jbNrXrAHatAFOOgl45pnKW/7Cpj/bCDBZv8naNU6o39znfrbPiaAf78ALoKAjyar8fAWcFS4e7AWBDRuiff722QfQCZ+r2/T53dLtpahWtZoXknhNEiABErBEgK+A+QrYUgDxZBLwO4ESmX85Px+oXTs60bNdlb+vVn+F4589Hl+v/trvCFg+EiABEiCBJAT4CjgJFG6KEli8eLGxKMKgvbQU6NgR2LQJePttIC+LuZjT6Z+zcg5OH346zj/ifPxxrz+GMkbS6Q+l4DhRJmtXDNRv7nM/7jYwYpEVQCPcnJvIcePG5XZiCM4KunaZjg833wx88QXwn/8Adepk55RU+qcum4pWo1rh9j/fjoGtB8oo4nD2IkmlPzuKwTzaZO3qMeo397kfzDs291KH8+mdO49sz2QfwGyJ8XhXCDz8MPDUU8CMGcDBB9tzyQlfTsAVY6/A0HZD0aVZF3syZS4kQAIk4AEB9gHkRNAehB0vSQLOEhg5MjrNi37n167K3+pNq9F5fGe8dOFLuOjoi5wVwNxJgARIgAQcJ8AvgTiOmBcgAfcIvPsu0KNH9LWvnbP47L373vj6pq9RL6+ee2J4JRIgARIgAccIsA+gY2iDn/HAgQODLyJHBUHUPmsWcNllwPDhQKtWOQrfcVoy/SZV/pLpt0Y0OGebrF29RP3mPveDc5faU1JWAO3hGMpc8nX+EENT0LR/LbOxnHsu8OCD0UqgVbcFTb9VvYnnm6zfZO0aB9Rv7nM/8TkQ9nUOArHmYQ4CscaPZ9tAoLgY+POfgUsuifb9s5plRIYQh3V0r1U2PJ8ESCAcBDgIhBNBhyOSqcJYAuvXR1v+tAI4YIB1DJu2bcL5r50PHfHLRAIkQAIkEF4CfAUcXt9aVlZUVGQ5j6BmEATtW7cCF18M7L13tN9fVYt385rNa9D65dZYv3U9ahXXCqrrbCl3EPxvi9AkmZisXXFQv7nP/SS3Q6g3WfyTEWo2xoubN2+esQz8rn37dqBzZ2D1amDsWKBGDWuuWrl+JVqObIkGuzfAxI4TsWTxEmsZBvxsv/vfSbwma1eu1G/uc9/J+8qPebMPoDWvsA+gNX48O0cCd94JvPEGMH060LBhjpnsOG3pmqVlLX+nNzodL7Z/EbtV5exQ1ojybBIgAb8TYB9A7/sA8i+N3+8Sls93BJ54AhgxAigstF750wEfl/z7ErQ/oj1G5I9g5c933maBSIAESMAZAl5XwH4QWS+KPS+2TIyJBEggDYGCAqB/f+DDD4HDD09zYIa7dLTvex3fwz619+HI3wyZ8TASIAESCAMBr/sA3igQTxb7Suw9sfZiXpdJisCkBPr06WMsCD9q/+STaL8/rQQ2b26fa/ats+8ulT8/6rdPceU5mazfZO0aGdRv7nO/8idDuI7wSx/AwwRrV7FOYjK2ES+IacugthBmku6Xg64T0z55/xWTj2FhoViydJJsfFTsRLHfxeTPKnqKfS+mqaXYZLENuiJJGa0Ra6QrCSnUfQCLZYK5hlY7mCUAC8qq37R/8w1w6qnAQw8B3bo5T9Fv+p1XXPEKJus3WbtGAfWb8dxnH8Bo5abik8/btUPk8q+LNRMr3bF8u/z+KJYq3SE7tCXxb2JLxO4Vu1rsCLFNYvFJK3MybS5eEZNu9KgpJh/OwoFiLcQ0aQXwIzF9PR4RS5dCXQFMJ5z73COwRv77oZW/884DHnvMvevySiRAAiQQVgKsAPrndatW3t4W+0JspZj8qcPxYloJHCeWLnWXnYPE9NwtYv3FqotdKJaY9pQNDcRGiGnr30axl8S0NTAx8VV0IhGuu04gNtffUUdZ+8qHDvb4x8f/wCOfPOK6Bl6QBEiABEjAfwS8ruRoZW2ZmFbItAInf+Zwvti7YovFuogdLZYqaQtcY7HZcQdopXGuWNO4bbHFtbLwtNj/idUSqyfWSWysWGJaKhu0tfB9sTMTd5qwXqjDTA1NftAudTbccIP0P5AWwFekzbpatdycsT2yHT0Le+KZ2c/gvCP0/1aVJz/or7yUzh1hsn6TtWtEUb+5z33nnij+zFlfc3qZWsvFtcfpG2LbkhRE+wNemmR7bJNWADVpxS4+aZ+92L747bqs13pO7DcxfSWslUVtgYylRbJwopj2IdRK4vViekecIvY/MWPS2rWJWI2RDj9oHyTt2u/J0KiZM4E6dXJjv610G7qM74Lpy6fj086f4tD6h2aUkR/0Z1RQhw4yWb/J2jWcqN/c575DjxNm6xABreRtF9PKWXzSCtvg+A07lv8ov1vEuonpa2Kt4N0vJl3sy5blJ2nSPoH/SLJHrx9p06ZNpGfPnmU2fvz4st/NmzfLW7doGjNmTGTixImx1cjKlSsjvXv3Ll/Xheeeey4yY8aM8m2LFi2KDBgwoHxdF3Rdt8eSHq/nxSfNV/OPJb2uXj+WtFxaVpYvUsbbr/zGjo1EatWaEenTJ3f/btq6KXL+q+dHGnVpFHn1rVdjIcD44/1R9hzh8yV6S/D5XP5oKPu7FOa/H/r3sGvXrpGTTz450qNHD+3jr5aqsSjJn/xwbdIWMK/TFVKAzmIHif0gNlzsVbFM01I5cIjYUztO0Bdl2o9QR/bKi7MK6SJZe1GsftzWPWR5nZhWIuNfJccdgg9lpUjs7viNsqyBs04S6tY1NoYSkHDVKoHPPgPOOgsYPRq44ILcc7v+P9djwaoFmHDFBNSvFR/yuefJM0mABEggDAQ4CMT7QSA6glcrbv8Ve1xMK2BPit0plml6Rg7UkcLHimmLnrbUaSvfW2KJSf60oobYdWJaUcwT6yW2XkznItTURqyxmFaONb9bxf4slqyfoGwObyopKQmvuEqUeaV9+XKZDLM9cN991ip/Ku+BVg9g0lWTcqr8eaW/Ere4tttk/SZr1wCjfnOf+649YHxyIa8HgfQQDueI9RYbJtZnx7puzzTpq96RYh+I/Sx2mlg7sU1i2qqolbvYFC/fy3K+mLY46rErxFqJnSumrYCamotNFftN7Dux88U0vzliRqW+ffsapTderBfaN2yQYJNo0+lebrstvjS5LevXPXavvntOJ3uhP6eCOnSSyfpN1q7hRP3mPvcdepz4Nltt5fIy6WCNBmKlcYXQlrlfxILwzirUr4D1f8J5edpIal5yW3up3AH6unfz5ujAj+raQ9XD5LZ+D6UmvbTJ+k3WrsFA/WY89/kK2PtXwG/I/XZtwhP4Gll/PWEbVz0gYGrlT1G7rf126cSgX/t4XSLf68qfF/o9CO+0l3Tb/2kL4/JOk7Urauo38z/9Lt9mvric16+AtQVN5+WbLfZvsVliz4rp9pfiTBaZSCCcBJ6ViNcBH//5jzR759Du/cHSD3Dd+OsgY/nCCYiqSIAESIAEbCfgdQVQ++npiN8FYhvFdO49XZcXYWWvhfXVcPzrYVllcotAQUGBW5fy3XXc0q5zbWvr31syZOmww7LHMPaLscgfk4+zGp+FKlXs69Hhlv7sFbtzhsn6Tdau0UX95j733Xm6+Ocqu3lclMTXvx4Xh5ePJ1CvXr34VaOW3dC+UP67c+mlwL/+BZx+evZ4X5jzAm6deCsKLinI+AsfmV7FDf2ZlsWL40zWb7J2jTXqN/e578Wzxstr2tdkkLsKLcPJYo3EvhP7TCwo77JCPQhE/MDkEIFfZJjTyRL1V10l07U8kP1FHp32KB7+5GGMv2I8zjz4zOwz4BkkQAIkYDABDgIBvG4B3E/ib7xYMzEdEaw9oOaI6VQtP4oxkUDoCPz+O3DZZRL0EvU631+2adTcUXhsxmOYfM1kNN2vaban83gSIAESIAESgNd9AB8XH+iXPP4g1mDHr4yFLJsUWn6YvCRQXFzs5eU9vbaT2u+4A/jpJ5m8cqQMw8/hDuxwbAfM6DLD0cqfk/o9dWyGFzdZv8naNTyo39znfoaPh9AclsOfH1u1t5Tc/k/s1x256u/1YrqdyWMCQ4cO9bgE3l3eKe0vvQSMGgWMGwfssUdu+nRy50PrH5rbyRme5ZT+DC/v+WEm6zdZuwYe9Zv73Pf8weNyAbzuA6j/1fij2IY43fpnUVsB943b5tdF9gH0q2d8WK5ZMslRq1bA228DrVv7sIAsEgmQAAkYQoB9AL2fCHqqxNpzYlqR0rSn2DNiup2JBEJDQN+mX3RRdMAHK3+hcSuFkAAJkEBgCXj9CrinkDtWTF/9rhLTT8AdJ6bbmUggFAS2bgUuuQQ46yygV6/MJf3w2w+4+q2rsXHrxsxP4pEkQAIkQAIkkAEBryuAOtL3T2I6C1oPsTN2rK+QXyaPCQwbNszjEnh3eTu133RT9Bu/zz8Pmaw5M01f/vIlWgxvgZrVaiJvt7zMTrLxKDv121gs17IyWb/J2jXAqN/c575rDxifXMjLaWBqCIM5YieJFe0w+WHyC4EmTZr4pSiul8Mu7c9JBwf9ysdnMrtlrVqZyZizcg7ajW6Hzk0745G/PmLrFz4yKwFgl/5Mr+e340zWb7J2jUPqN/e577fnkNPlybA9wrFiaEvfIWLykiyQiYNAAuk2dwr9ySdAu3bAe+8BZ2Y4V/PUZVPRfkx79DujH+5oIfPFMJEACZAACdhOgINAvB8E8qJ4lX/lbA9tZug1geXLo/3+Bg3KvPI3/6f5OPfVczGkzRBW/rx2IK9PAiRAAiEn4HUfwFbC914x+XOJT8U+jjNZZPKSwOLFi728vKfXtqJ982bgwguB9u2B7t0zl3HsPsfio2s+QpdmXTI/yaEjreh3qEiuZmuyfpO1a5BRv7nPfVcfMj64mNcVwA+EwUNiL4i9L/ZhnMkik5cExulsxYamXLVH5CvWXbsCNaSH61NPZT7oQzFXrVIVzQ9o7gviuer3ReFtKITJ+k3WrqFD/eY+9214dAQqC6/7AAYKVpLCsg9gEigmb3r8cWDw4Oigj/30S9dMJEACJEACviPAPoDe9wGcnyIq5qbYzs0k4FsCH0h7dr9+wJtvAqz8+dZNLBgJkAAJkIAQ8PoVcOMUXjg4xXZuJgFfEli6FLjsMuDpp4FTTklfxK2lW9FzYk8sX6ddX5lIgARIgARIwH0CXlUAO4tUtWpi1+5Yjm0bKOs/iTF5TGDgQHWFmSkb7TroQz/z1rEj0KlTel6btm1C/ph8fPz9x6i5W830B3u4Nxv9HhbTsUubrN9k7RpQ1G/uc9+xB4pPM/ZqIuj+O3joX8B74thsl2X5aipuidvGRY8I5Ofne3Rl7y+bjfYbbwR23z3a9y9dyddsXoPzXjsP1atWx+RrJqNuTe1C6s+UjX5/KrBWKpP1m6xdo4b6zX3uW3tqBO9srweBvCvIzgketvIScxBIOQozF4YPB+66C/j8c+DAA1MzWLl+JdqObotD6h+CgksKPPm8W+rScQ8JkAAJmEWAg0C87wMY5MqfWXcL1e5CYK4MVdLv/L72WvrK34atG3D6iNPRbL9mGHvpWFb+diHJDSRAAiRAAm4T8KoPYExnHVnQiaDfEfs4wWSVyUsCRUX6iWYzU2Xa166Nfumjd2/g7LPTM7qwW5wAAC+ASURBVKpTow7+dd6/MDx/OHar6lWvi/RlTNxbmf7E48O2brJ+k7VrHFO/uc/9sD3HKtPjdQVQXqBBus5joVj8JNC6zOQxgXnz5nlcAu8un067TvZ8rQxdOuII4O67MyvjXw/9a9lEz5kd7f1R6fR7XzrnS2CyfpO1a2RRv7nPfeefLP66gtd9ANcIjqPEgjrql30A/RXPrpRGv++rX/mYMwfYe29XLsmLkAAJkAAJ2EiAfQABr99HyYs0aCWQiQQCQeBj6ahw333A5Mms/AXCYSwkCZAACZBAUgJevwJ+REql5nU5ksLhRhKIJ1AsExTpZM/aAtg8xSd7h302DLNXzI4/jcskQAIkQAIk4DsCXle8dD7Am8U2iH2fYLLK5CWBPn36eHl5T6+dqP3334HLLwf+8hege/ddixaRjoEPTn0QfT7sg9+3y8EBT4n6Ay4n6+KbrN9k7Roo1G/ucz/rB0XAT/C6D+A1afiNSrPPL7tC3QewWJq8GjZs6BfWrpYjUbuO9h0/Hpg1C6ijY9fj0vbIdvQq7IV/L/w3Cq8sxPH7Hh+3N5iLifqDqSL3Upus32TtGjHUb8Zzn30AAa8qgB3kPns97vF8mCwviVu/XZYHx637dTHUFUC/Qne7XFrxu/JKYOZM4OijK159W+k2dBnfBdOXT8ekqybh0PqHVjyAayRAAiRAAr4jwAqgd33vXkyIhsROU/Gfh0s4lKsk4B6BpUuBa6Sd+vnnd638aSk6vtkR836ah087f8rKn3tu4ZVIgARIgAQsEvCqD2Biy2Nl6xZl8vRcCBQWFuZyWijOUe0lJdHJnq+6Kjr4I5mwbn/qhqmdpqJhnXC9KjfZ9+pnk/WbrN1031O/EjAneTUNjEylWyFVtl7hYK64Q2Ctfu7C0KTab5bhSTVqSF+ENJ0RdILnMCaTfa/+NFm/ydpN9z31KwFzUmLLm1vKf5MLaf+5WPpVFvaKrchv4v64Xb5aZB9AX7nDvsKMGgXcdlt0sudGjezLlzmRAAmQAAl4T4B9AL2bCLqmuP+BuBColbAu7S5MJOANgfnzgR49gLFjAVb+vPEBr0oCJEACJOAsAa9eAc8QWWfESdOvT8ev634mjwmUSCe4vLw8j0vh7uU3boz297vpphK0bbtT+8wfZuLH9T/iwqMvdLdAHl3NRN/HozZZv8naNQao37znfvy9b9KyV4NAzhLIrSoxk/zgS619+/b1ZbmcLNStt0Y/8bZ5807tHyz9AGe/fDZWrF/h5KV9lbeJvo93gMn6TdauMUD9O5998fcEl8NHwKs+gGEhGeo+gKb9T7igIPqVj7lzgX32if4veOwXY3H121dj2HnDcOUJMhmgIck03ye61WT9JmvXOKB+M1oA2QfQuz6Aic9brvuQgEmvf7/9FujaFdDBH9F+f3l4/r/Po2dhTxRcUoDzjjjPhx5yrkgm+T4ZRZP1m6xdY4H6d3Z9SXZvcFt4CHjVBzA8BKkk8AS2bYt+51fn+7vggqicf878J/pP7o93O76LMw8+M/AaKYAESIAESIAE4gl41Qcwvgxc9imBAn0nakDq109f+1Sc72/DnA2YfM1kYyt/pvg+VXibrN9k7RoP1G/Gcz/VvW/S9rBUAO8Xp2kP/fViU8SOFUuVTpIdH4np3IOrxGSyDyTO9HaJbFskJmNCsVDMjKGfIjQ+1atXL341lMuTJgHPPAOMGaOvfnZKbHZoMzTdr+nODYYtmeD7dC41Wb/J2jUmqD/8z/10975J+8IwCOQOcdiNYn8TWyJ2r9jVYkeIbRKLT6q3WOwVsTvFdD7C4WIHirUQ03SK2BSxK8QmiOWLjRY7XWyOWHwK9SCQeKFhXC6WSGjSBHjkEaBz5zAqpCYSIAESIIFkBDgIBAhDBXCpOHeI2FM7nFxNfn8U6yWmFb34pP+1WS12ophM91uWzpV//y1WO7paViHcU5Yv3rGuP2+K6Xn/pytxiRXAOBhBWty+HWjXDmjQQIJEoqRKGO6EIDmAZSUBEiABDwmwAggE/RWwVsAai82Oi6NSWZ4rluz93VrZ/rSYVuRqiWmFsJOYvgaOJa0czoqt7PjV/JPll3BYuFaLtYkspEm/77tE2osfevwXjJo3cheVYda+i9gkG6g/vLGfxN0VNtH35vpeA8F0/1e4GUK+EoYKoLpIK3bxaY2saOUwWXpDNp4tpt8b/kXsELHbxGJJz8smv9h5ofsdOnRo6DSpoJkzgfvuA54Y/gPOfeNMvPP1O9gekSbBuBRW7XES0y5SfzhjP63Td+yk7831vYaA6f7P5B4JyzFBf/EVq6ydJg6RP+vlqVCW9BXv7eVbogt/lB8d1HGzmPb9202st1hHsePFNovNESsQGygWS31kQV8JnxTbsONXr79OEurW1UUmrwlc2eNKLFmlXUGTp9+lffh//5Ovfey7GaurLMJBDQ7Cl29+iWpVtecAEwmQAAmQgAkE+Ao4+K+AtRVvmdjJcQGrf8n1de3ncdtiiyfIgg4MGSYms7+VVfjkZSAOFTtOTNNcsfj8dJuuJ8tP96FDhw7o1atXmU2YMKHsV2eTjyWdVqCwUOuk0aRN7H36aJ1yZxo2bBiKiorKNyxevBgDB8bXQaVGKuu6PZb0eD0vPmm+8U34et34aQ20XFrWsJZPK39FxxWhaF+xtWK6HDNZ/2z/Imy9qggr28zD1qO2onR5aYXKn+n8YrHE+OP9y+dL7G6QPxh8PpfBCPrfD/172K1bNzRv3tz4T/6pQ4PeAqgatJXvRjEdzKEDQu4R0292HSmWOAq4kWzT6V1uERshVl3sLjEdMKL71onpKODJYleIvSOWL/aS2Bli2joYn9gCGE/DB8undTitrMKXaVFOXXAqZrw+I9PDeRwJkAAJkEAICLAFMPgtgBqG2oI3UuwDsZ/FThNrJ6aVv4PE1ovFpnj5Xpa1QtdZTI9dIdZKTCuPWvnTpK+SrxIbIKYtjA+K6SvixMqfbAp3SmxdDLfaiupM1q4kqL9iy3rF6Aj3Gn1vru9574f73k5Up33gwpDuExFqiWm5bNgjYaNWFNXSJR0VHD8yON2xod3XRCfJMzSZrF1dTv2MfUNvfca+wc9902I+DK+AvfQZXwF7ST/JtfkKOAkUbiIBEiABEqhAgK+Aw/EKuIJTuUICJEACJEACJEACJJCeQNX0u7nXZALxI45N42CydvU19e8cbc/YN4sAY9/c2Dcr0tkCaJq/s9I7bty4rI4P08Ema1c/Uj9jP0z3czZaGPvmxn42cRKGY9kH0JoX2QfQGj/bz2YfQNuRMkMSIAESCB0B9gFkC2DogpqCSIAESIAESIAESKAyAuwDWBkh7g8UgUgkUMVlYUmABEiABEjAEwKsAHqCPRgXTfwUXRBKvXnVYch75VQ0/9+p0K98VGaH7XNYUllB1J5USI4bqb/iZxhzxBjI0+h7c32vAWu6/wN50+ZY6LBMBJ2jfJ6WjkB+vn40JThp9mzg689GY/o0+Rh0U2vlDpp2a2p3PZv6gxX7u3ow9y30vbm+16gx3f+53znBO5ODQKz5jINArPGz7eyNG4FmzYBOnYA+fWzLlhmRAAmQAAmEkAAHgXAQSAjD2kxJd94J7LMPoL9MJEACJEACJEAC6QmwD2B6PkbvLSoqCoT+994DXn4ZeOkloFo1e4ocFO32qN01F+oPRuzv6jnrW+h7c32v0WO6/63fQcHJgRXA4PjK9ZLOmzfP9Wtme8FffgE6dwaGDgUOOSTbs1MfHwTtqUtvfQ/1+z/2rXs5eQ70vbm+14gw3f/J74pwbmUfQGt+ZR9Aa/wsna1Tvlx8cTSLsWOBKoxmSzx5MgmQAAmYQoB9AAGOAjYl2kOoc9QoYPp0YMECVv5C6F5KIgESIAEScJAAK4AOwmXWzhH49lvg5puBMWOABg2cuw5zJgESIAESIIEwEmAfwDB61SZNfXw6n0ppKXD11cCVVwLnnGOT2IRs/Ko9oZiOrVK/uXMJ0ffm+l4fKKb737GHqg8zZq8pa04JdR/A4uJiNGzY0BohB84eMAAYMQKYMweoXduBC0iWftXujNpdc6V+f8b+rp6yfwt9b67vNZpM8T/7AErXKfsfH0blGOoKoB89+fnnQIsWwJQpQPPmfiwhy0QCJEACJOB3AqwAciJov8coyxdHYMsW4KqrgN69WfmLw8JFEiABEiABEsiaAPsAZo3MnBMKCwt9Jfb++4G8PKBvX+eL5TftziuueAXq91fsV/SOs2v0vbm+18gy3f/O3l3+yp2jgP3lD1+VZu3atb4pz+zZwBNPADNnytxFLkStn7R74QTq90/su+1/+t5c32usme5/t+83L6/HPoDW6LMPoDV+GZ2tr37/9CfgiiuAu+/O6BQeRAIkQAIkQAIpCbAPIPsApgwO7vAPAX31W7MmcOed/ikTS0ICJEACJEACQSbAPoBB9p7DZS8pKXH4CpVnH3v1O3IkUL165cfbdYQftNulJZd8qN/72M/Fb3acQ9+b63uNH9P9b8c9FJQ8WAEMiqc8KGdfN0ZbpNGlr36vvTY66OP449Mc6MAur7U7ICmrLKnfhZFGWXnEvYPpe3N9r1Fmuv/du9O8vxL7AFrzQaj7AOr/BPN02K1HSfv7TZwIFBW52/qncr3W7hHy8stSv7exX+4IDxboe3N9r+Fmiv/ZB1AGVHrwfOElA0LAy8rfZ58Bjz8eHfXr5qvfmGu81B4rg5e/1O/df3y89Ltem7431/f0v9d3n7vX5ytgd3nzahkQ0Fe/nTp58+o3g+LxEBIgARIgARIIPAFWAAPvQucEFBQUOJd5mpwfeCA66veuu9Ic5PAur7Q7LCvj7Knfm9jP2EEOHkjfm+t7DSvT/e/greW7rPkK2Hcu8U+B6tWr53phYq9+vej3Fy/WC+3x1/d6mfrdj32vfR67Pn1vru81Bkz3f+w+MOGXg0CseTnUg0Csocn+7NiEz5ddBvTvn/35PIMESIAESIAEMiHAQSCcCDqTOOExLhF48EGgRg2gd2+XLsjLkAAJkAAJkIChBNgH0FDHZyK7uLg4k8NsOUZf/Q4ZArg94XOqwrupPVUZvNxO/e7Fvpd+TnZt+t5c32s8mO7/ZPdEWLexAhhWz9qga+jQoTbkUnkWsVG/2vJ3wgmVH+/GEW5pd0NLLtegfndiPxffOH0OfW+u7zW2TPe/0/eXn/JnH0Br3mAfQGv8ys7u1w945x1g1iz3J3y2ofjMggRIgARIIGAE2AeQE0EHLGTDV9zYq98ZM1j5C593qYgESIAESMCvBPgK2K+eMaBcsW/96qvfJk0MEEyJJEACJEACJOATAqwA+sQRfizGsGHDHC3WQw9JE7TMRNmnj6OXySlzp7XnVCgXT6J+Z2PfRVdmfSn63lzfa7CY7v+sb5gAn8CJoAPsPKeL3sTBZrkFC4DBg4Fp0/z56tdJ7U77zY78qd/cJmn63lzf67PDdP/b8fwMSh4cBGLNUxwEkgO/0lLg9NOBM84AHn00hwx4CgmQAAmQAAlYIMBBIJwI2kL48NRcCTz7LLBqFXDffbnmwPNIgARIgARIgASsEGAfQCv0Qn7u4sWLbVe4fDnQty/w3HPA7rvbnr1tGTqh3bbCuZAR9dsf+y64zZZL0Pfm+l4DyHT/23ITBSQTVgAD4igvijlu3DhbLxuJAD16ABdcALRubWvWtmdmt3bbC+hwhtRvb+w77C5bs6fvzfW9BpLp/rf1ZvJ5ZmHpA3i/cL5OTPvk/VdMqhlYKJaYDpINX4hJVaQ8yddnUU1sX7FfxVqKTRbbIKZJGa0Ra6QrCYl9ABOApFt94w2ge3dg0SKgQYN0R3IfCZAACZAACThHgH0AwzER9B0SIp3EtE1pidi9YoViR4htEotP8gISe8RvkOWxYjoaWit/saQVxD3F9JfJBgJrpAp9003A44+z8mcDTmZBAiRAAiRAApYIhOEVsLQpYZCYtuxtEesvVl3sQrHK0gFywPliTyc5MAxsksjyZtNdd0Une+7Y0Zvr86okQAIkQAIkQAI7CQS9kqOvYBuLzd4pCaWyPFesady2VIvdZMd3YpOSHLBUthWLvS92ZpL9od80cOBAWzROnQq8+iqgo3+r6Av1ACS7tAdAatIiUr89sZ8Urs830vfm+l5D03T/+/z2tLV4YagAKpC1CVS0z55WDtMlfe3bRUyqJRWS9FDDiWKHiB0mNlFMXymfIGZUys/Pt6y3pATo2hW4/34BqkQDkuzQHhCpSYtJ/dZjPynYAGyk7831vYan6f4PwC1qWxED0h6TUq9W8rTyd5rYzLijtMI2X+z2uG2Ji5fKhhFiB4pphTFd+kh2Thfrl3CQXn+dJNStW1l9M+FMQ1bvuQd4912gqCj62TdDZFMmCZAACZCAjwlwEEjwJ4L+TeJrmdjJcXFWTZb19e/ncduSLXaXjQVilVX+9FwdDJKystyhQwf06tWrzCZMmFD2W6JNXztSQUEBCgu1ThpNxcXF8v3bPrHVsl/9/mKR1pJ2JJ2LKbEpXtfj52jS4xO/26j5av6xpNfV68eSlkvL6kb5Xn21CAMGDMPzz++s/PmpfH7nx/LFojb6fdKw3R/0L/3r5fPZxPhT3t26dUPz5s1lPlqZkNbwlLJSEyAu2sp3o9i5YtpvT9qccKXYkWKJo4BlU1k6Rv5dINZc7LOyLTv/aSOLX4l9J5Ynpv0EHxFrITZHLD6FugVQHxCnnnpqvN6Ml7dvj37urYVQG6RDdAKWrGgPmNSkxaX+3GM/KdAAbaTvzfW9hqkp/mcLYPBbADVeB4uNFPtA7GcxfR3cTkwrfzrv33oxrbzFp+tlRSt+iZU/PUYrhVPFtHVRK4E6SljzS6z8yaZwp3nz5uUsUAd8aEOk9v0LYrKiPYh6E8tM/bnHfiLLoK3T9+b6XmPVdP8H7X61Ut4qVk7muWUDTdgHMCEQfvgBOEbaWMfKDIt+/+JHQtG5SgIkQAIkYAABtgCGowXQgFANjsQgfe4tOFRZUhIgARIgARKwl4BOhcJEArYRePNNGS4t46X1c29MJEACJEACJEAC/iQQ9HkA/Uk1JKVKHKlcmay1MiHPjTeG43Nv2WqvjE3Q9lN/xVH6QfOflfLS9+b6XuPGdP9buXeCdi77AFrzWKhHAet0Mg0bNsyYkIyux3cybOa994LzxY9U4rLVniqfoG6n/uxiP6h+TlZu+t5c32s8mOJ/9gFMM7ddsgcDt+1CINQVwF3Uptnw6acyVFrGSs+X6beD9MWPNJK4iwRIgARIIKQEWAHkIJCQhra7srZtA7rLtNr9+7Py5y55Xo0ESIAESIAEciPAPoC5cTPirPivl6QT/OSTQGkp0LNnuqOCtS9T7cFSlXlpqb8wc1ghO5K+N9f3Gsqm+z9kt3NaORwFnBaP2TvX6qiOSpLO+XfffYB8AQ81alRycIB2Z6I9QHKyLir1Vx77WUMNyAn0vbm+1xA13f8BuU1tKSYHgVjDaHwfwEsvjVb8Ro+2BpJnkwAJkAAJkIBbBNgHEGALoFvRFsLrTJqkrwuAL78MoThKIgESIAESIIEQE2AfwBA716q0kpKSlFnorh49gIcegkwVk/KwwO5Ipz2worIoOPWnjv0sMAbyUPreXN9rwJru/0DetDkWmhXAHMGZcFrfvn1Tyhw0CNhjj+jo35QHBXhHOu0BlpVx0ak/dexnDDGgB9L35vpeQ9Z0/wf0ts2p2OwDmBO28pNC3QdQ/yeYl5dXLja2sHQpcPzxwEcfAaecEtsart9U2sOlMrUa6k8e+6mJhWcPfW+u7zWKTfE/+wByImirT+1QVwCTwYlEgPPPB/bfH/jXv5IdwW0kQAIkQAIk4G8CrAByEIi/I9SHpRs/Higq4sAPH7qGRSIBEiABEiCBjAmwD2DGqMw7sKCgoILojRuBm28GHn0U2HvvCrtCt5KoPXQCKxFE/RVjvxJcodpN35vrew1k0/0fqpu5EjGsAFYCyOTd9erVqyD/H/8ADjgA6NSpwuZQriRqD6XINKKov2Lsp0EVul30vbm+12A23f+hu6HTCOIgkDRwMthlTB/ARYuAP/0JmDEDaNIkAzI8hARIgARIgAR8SoB9AAG2APo0OP1ULB34oXP+devGyp+f/MKykAAJkAAJkECuBFgBzJWcAecVFxeXqRwzBli8GLj/fgNE75AY026O4opKqT8a+xWpmLFG35vre41w0/1vxl0eVckKoEnezlLr0KFDsW4d0KsXMGQIUFdfeBuSVLvJifrN9T99b67v9Zlnuv9Neu6zD6A1b4e+D+AttwALFgAffCCTRjJarEULzyYBEiABEvAFAfYB5DyAvghEvxZi7lzg+eeBOXNY+fOrj1guEiABEiABEsiFAF8B50LNgHO2b49+57dnT+CoowwQTIkkQAIkQAIkYBABVgANcnY2UkeMAL76ahjuvjubs8Jz7LBhw8IjJgcl1G+u/+l7c32vjwrT/Z/D4zKwp7ACGFjXOVfwX38F7roL6N27CXbf3bnr+DnnJoZPdkj95k52Sd+b63t9Jpvufz//XbK7bOzWb41oKAeB3HgjsHQp8O671uDwbBIgARIgARLwIwEOAuEgED/Gpadlmj8fePFFQAeAMJEACZAACZAACYSTAF8Bh9OvOanSL37ceitwww3AkUfq5M8y+7OhyWTt6nLqZ+wbeusz9g1+7psW86wAmubxNHrfeis6598990QPGjduXJqjw73LZO3qWepn7If7Dk+tjrFvbuynjopw7mEfQGt+DU0fwM2bgWOOAfr1A7p0sQaFZ5MACZAACZCAnwmwDyDAFkA/R6iLZdNPve29N3DttS5elJciARIgARIgARLwhMBunlyVF/UVgR9+AB55BJg0Sf5HwP8S+Mo3LAwJkAAJkAAJOEGAf+6doBqwPHXOv/x84M9/rljwgQMHVtxg0JrJ2tXN1M/YN+h2ryCVsW9u7FcIBANW2AJogJPTSZw2TTv866jPXY/K11qhoclk7epy6mfsG3rrM/YNfu6bFvMcBGLN44EeBKLf+z35ZOCii2DsJ9+suZ9nkwAJkAAJBJEAB4FwEEgQ49a2Muv3fvWzb7fdZluWzIgESIAESIAESCAABNgHMABOcqKI69YBffsCjz0G5OUlv0JRUVHyHQZsNVm7upf6GfsG3OZJJTL2zY39pAER4o2sAIbYuemkPfAAcNxxwIUXpj5q3rx5qXeGfI/J2tW11M/YD/ktnlIeY9/c2E8ZFCHdwT6A1hwbyD6AX34JnHgiMHt2tBJoDQHPJgESIAESIIFgEWAfQPYBDFbE2lTanj2B665j5c8mnMyGBEiABEiABAJHgNPABM5l1gr8zjvAzJnA6NHW8uHZJEACJEACJEACwSXAPoDB9V3WJd+6FdDWvwcfBPbaq/LT+/TpU/lBIT3CZO3qUupn7If01q5UFmPf3NivNDhCdgD7AFpzaKD6AA4eDLz0EjBnDrBbBm2/xcXFaNiwoTVCAT3bZO3qMupn7Af01rVcbMa+GbHPPoBAWCqA98tdL73aoBWy/4r1EFsolpgOkg1fiEXidtSQ5Wpi+4r9umP7JfIr7WRoJLZMrJ/YW2KJKTAVQKnL4YgjgPHjgbPOSpTBdRIgARIgARIwhwArgOEYBHKHhGwnsdZiDcSmixWK7S6WmJbLhj3EtOIWM+kVh3fFYpW/U2T5ZTFtB9dj+ou9ItZMLLBJ5/xr25aVv8A6kAUnARIgARIgARsJhKEPYHfhMUhMW/a2iGmFrbrYhWKVpQPkgPPFno47sJssa4XwbbFSsTfFJorpdQKZdLqXggKBpJSySIWFWo82M5msXT1O/Yx9M+98xr7p975JcR/0CqC20DUWkypOedJK21yxpuVbUi9oZe87sUlxh8gMeZgVt66Lmn8m+SWc5v1qRF5233pr9HNvjRtnV561a9dmd0KIjjZZu7qR+hn7Ibqds5LC2Dc39rMKlBAcXCXgGg6U8n8vdrTYl3Faxsjyb2Jd47YlLuowCK38ycfQMCRu5zeyrG1lw+K2XS/LvcSkF12FpBXQdZJQt64u+i+9/jpwyy3A118DtWv7r3wsEQmQAAmQAAm4TYB9AIPfB1AreZrqRX/K/60vS7F95RsTFi6SdT1vRMJ2PS+r/Dp06IBevXqV2YQJE8p+S0pKyrMtkPev8c3qOsoscaqBYcOGVfj+6uLFizFw4MDyPHRB13V7LOk3K/W8+KT5av6atmwBbr65EO3bF5RX/rRcWlY/lE/LqFyUTyyxfJn7l/ys3R/kR34aA149nxl/7sef/r3p1q0bmjdvjr7aMd7wFPQWQHXfUjFtwXtKVyRVE1sp1lNMB2+kSpNlx7dinRMOGC7r2pynI4Fj6U1ZWC32f7ENO371ON+2AD7+uNRupXr7+ecCRalkmbQylpeXl+VZ4TjcZO3qQepn7IfjTs5eBWPfjNhnC2DwWwD17n5G7HaxY8Vqif1DTNq+kk7bIpvL0jHyb0sxPTcxaZPaOWL5Yvqa+GIxGT+LZ8UCk379NTrhs879l0vlT4Wa/D8kk7Wb7nvT9TP2zW4ZMt3/ev+bksLQAqi+uk9MB3ToFC+fifUQ03kADxLT0cHtxKaJxdKTsnCqWPPYhoRfrfRpRfJgsWVi+kR4Wywx+bYFUN7y4gtRPnFiYpEzXzf5f8Ima9cIoX4zWkGSPQ3oe3N9b9K9zxbA8EwEnew55sY2X1YAlywBjjtOhi7Pjv66AYLXIAESIAESIIGgEGAFMByvgIMSb66VUz/he+WVrPy5BpwXIgESIAESIIGAEQj6PIABw+18cWfMkFms3wUeeMD6teJH51rPLVg5mKxdPUX9BcEKWBtLS9+b63ve+zbeSAHIihXAADgp0yLqpM/a9+8O+Tjefvtlelbq4+rVS5wNJ/WxYdtjsnb1JfUz9sN2T2eqh7FvbuxnGiNhOS4sg0C88oev+gBy0mevwoDXJQESIAESCBIB9gFkH8AgxWvasuqkz717y9BlGbvML36kRcWdJEACJEACJGA8Ab4CDkkIPPNMtOJ3zTX2CYp9UcS+HIOTk8na1UvUH/2aTnAi1r6S0vfm+p73vn33URByYgUwCF6qpIx2TPqc7BJDhw5NttmIbSZrVwdTP2PfiBs9iUjGvrmxnyQcQr2JfQCtudcXfQDtmPTZGgaeTQIkQAIkQALBIcA+gNFPnQXHYyzpLgR00udn5SN1s2btsosbSIAESIAESIAESCApAb4CToolOBtjkz4ff3xwysySkgAJkAAJkAAJeEuAFUBv+Vu6up2TPicryLBhw5JtNmKbydrVwdTP2DfiRk8ikrFvbuwnCYdQb2IFMKDutXvS52QYmjRpkmyzEdtM1q4Opn7GvhE3ehKRjH1zYz9JOIR6EweBWHOvZ4NAOOmzNcfxbBIgARIgAXMJcBAIJ4IOZPRz0udAuo2FJgESIAESIAHfEOArYN+4IvOCODHpc7KrL168ONlmI7aZrF0dTP2MfSNu9CQiGfvmxn6ScAj1JlYAA+ZepyZ9ToZh3LhxyTYbsc1k7epg6mfsG3GjJxHJ2Dc39pOEQ6g3sQ+gNfe63gfwttuABQuAwkJrBefZJEACJEACJGAqAfYB5ETQgYr977+PTvqs078wkQAJkAAJkAAJkECuBPgKOFdyHpx3//3AhRfqFB0eXJyXJAESIAESIAESCA0BVgAD4spFi4BXXwUeeMC9Ag8cONC9i/nsSiZrV1dQP2PfZ7eka8Vh7Jsb+64FmU8uxAqgTxxRWTH69QM6dwYOO6yyI+3bn5+fb19mAcvJZO3qKupn7AfslrWtuIx9c2PftiAKSEYcBGLNUa4MApk1C2jVCvjmG2C//awVmGeTAAmQAAmQgOkEOAiEE0H7/h7QT7717g3ceisrf753FgtIAiRAAiRAAgEhwFfAPnfUBx8Ac+cCd9zhfkGLiorcv6hPrmiydnUB9TP2fXIrul4Mxr65se96sHl8QVYAPXZAustv3w706RO1evXSHenMvnnz5jmTcQByNVm7uof6GfsBuE0dKSJj39zYdySgfJwp+wBac46jfQBffz366lf7/tWqZa2gPJsESIAESIAESCBKgH0A2QfQt/fCtm3A3XcD993Hyp9vncSCkQAJkAAJkEBACfAVsE8dN3IkUEXaZ6+91qcFZLFIgARIgARIgAQCS4AVQB+6bvPmaMvfP/4h3+rbzbsC9tEOiIYmk7Wry6mfsW/orc/YN/i5b1rMsw+gNY870gdw0CCgoADQ+f+qelhFLy4uRsOGDa0RCujZJmtXl1E/Yz+gt67lYjP2zYh99gGUt4yW7xazM7C9Arh2LXDoodEKYOvWZsOlehIgARIgARJwggArgBwE4kRcWcpTW/+aNgXOPttSNjyZBEiABEiABEiABFIS8PAFY8oyGbtj5UrgiSeARx6JDgDxGkRhYaHXRfDs+iZrV+jUz9j37Obz+MKMfXNj3+PQc/3yrAC6jjz1BXXQR7t2QPPmqY9xc89afR9taDJZu7qc+hn7ht76jH2Dn/umxTz7AFrzuG19AJcsAY47DpgzBzj6aGuF4tkkQAIkQAIkQAKpCbAPIPsApo4Ol/fccw/w97+z8ucydl6OBEiABEiABIwk4OEsc0byTip67lzgrbeAxYuT7vZsY0lJCfLy8jy7vpcXNlm7cqd+xr6X95+X12bsmxv7XsadF9dmH0AvqCdcUz/51r070KhRwg6PV/v27etxCby7vMnalTr1M/a9u/u8vTJj39zY9zby3L86WwDdZ17hih9/DHzyCTBqVIXNvlhp1aqVL8rhRSFM1q68qZ+x78V954drMvbNjX0/xJ+bZWALoJu0E64Viegnt4A77gAaNEjY6YPVyZMn+6AU3hTBZO1KnPoZ+97ced5flbFvbux7H33uloAtgO7yrnC1d94Bvv5a51yrsJkrJEACJEACJEACJOAoAVYAbcCrw8mzTdr6168fcOutwPbtQA5ZZHvJrI9fuHChlCt7bVlfyIcnmKxd3UH9jH0f3pauFImxb0bsm/q3Lf4mqhK/wuWsCRwgZ/yQ9Vk8gQRIgARIgARIwA8EDpRCrPBDQdwuAyuA1ogrv/3F1lvLhmeTAAmQAAmQAAm4TGAPud6PYvJOjokESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAESIAEAkHgfimldnbVPotTxI4VS5b+IBtHii0V02HA+vuwWA2x+HSJrCwS2yi2UOxCMb8mO7W3FJEydruMjfJRnt+L+Tllql81jBPTwU3rxDReXhTbSyw+Bcn3Wm479QfN/9loj/lY+0YtEysVS5wvNsy+F7llKZX+oPlexWTj/yly/Bax2HNNf68Xi09B83982blMAkYSuENUfyd2jFhNMa3Q6R/53cUS0yGyobeY/mo6VGye2BBd2ZFOkd/NYheIVRO7SGyTWDMxvyW7tesfAf3DWMVvQlOUJxv9msXxYhojmvYUe03sDV3ZkYLkey2y3fqD5P9stcd8rJX+98QSK4Bh931l+oPke9WSrf8nyzn3xyAk+Q2a/5NI4CYSMI+AtuLdGCdbK20/iXWM25Zu8RbZ+XncAcNleWzcui6+KfZ8wjY/rNqtPfZHQBkGIVnRX18EviL2vzihQfK9Fttu/UHyfy7azxdmM8X+IpZYATTB9+n0B8n34r6sY18rgA/oiSlS0PyfQgY3K4HEpn1SCSeBuiKrsdjsOHn6YJ8r1jRuW7rFNrIzvgJ4oqzPSjhB8880v4RTHVt1QnussPrHtVjsfbEzYxt99purfm0h1tc/q8Xyxe4Ti6Wg+F7L64T+GAe/+z8X7XuLuH+KdRLTZ0RiCrvvK9Mf4+F332s5c/G/ntddTO/7L8QeEastFktB8n+szPxNQYAVwBRgQrZZHwSa1kZ/yv9dI0uxfeUbkyz0l21648u3S8qTnpdrfuWZuLAQ05drWZNpXyTlVh76ivwwsYli+kG/E8T8lnLV31eE6Ll/FBsi9o1YLOn2XHnG8nDr1wn9QfF/LtqfEccME1ONyVLYfV+Z/qD4Xn33/+3dSYgcVQDGcZdoNBKjohHF6BhQA+IloB4iHiI4KmKicbtEULybgxdBZNBD8ODBiIKICIInEQOCy0GjuERxQVxxQSMRAwaioklESeL/c/qF6qZ70t2pme6a/B98U/urer/X01Nd1T09TP/fx3YXkJwI30YmydOklCb1fzlmhz0EPAHsATPPZudKTsop04ODP3N7ryw7OLNj5CGm7ya59fFLZVm2G6a+ShVzMlraN8yx9mr7rxz552Q/2U0eIVvJrWTcyuG0P23JlY6XSE5wjyUpTen7cqwZDtP/2a5b+5vS/4P2/e20dzl5OA2nlPe4lmHmzee+76f9Ten70lcZDvLYf5/1f89GlDzHbSA3kYUkpUn9P33E/uwp4AlgT5p5tSC/tNvIpZVW5Y95btdWb+tWFv8/+jg/8yrwClK9ApSFn5JqfZmX6ZnqyzpzXWaj7d3acICZ1T+U3dYZxbxh21891uOZWEqWtGY2pe9zuLPR/hZD22Ac+3/QtudqzwqS9wbvJJtJHtM7yHqSMp/7vp/2Tyu0/xzHvs8RDtr/7a1qnyrPbU3q//YWOKXAESxwL23fRi4mJ5KNZDtZRDpLTg7zxv+8Ajyzc2Fr+nKGe8gasoCsI7vJSjJupe625/2QEyRPirHcQPaScWw7h3XUIO3P7Z8byeJsSLmIvEu2ZqJVmtT3OeS629+k/h+k7TnBz1dbltzM+D5yDsnjPGU+930/7W9S36e/Bun/vMibJOVvQv5WfEieJ6U0rf/LcTtU4IgXmEJgB/mLvEnyC56yjPxJVmWCciXJE39O8PIqMsnyDKslJ31fk6z3FVlLxrVMcWB1tf1+6vqJxCS3hF4nuUU+zmWKg+un/Rey3ttkF0l/5xboE2QpqZYm9X2Oe4rU1f6m9X+/bYeoreQxneeBzjtF87Xv2xrPRLf2N63v06Yp0s9j/1zW+4D8RvK7/y3ZSE4i1dK0/q8eu+MKKKCAAgoooIACCiiggAIKKKCAAgoooIACCiiggAIKKKCAAgoooIACCiiggAIKKKCAAgoooIACCiiggAIKKKCAAgoooIACCiiggAIKKKCAAgoooIACCiiggAIKKKCAAgoooIACCiiggAIKKKCAAgrMvkC+8suigAIKHEkCr9HYvSTfYpOSb3TJ193l213qLpuo8DLyVt0VW58CCiiggAIKKKBAfwI3sNrH/a3a11pPsdYX5F/ybJctzmBevlrrrC7LnKWAAgqMTMArgCOjd8cKKDACgSfZZ07UPqpp3+dRz3NkMclJ4IukWvYwsZIsJ1uqCxxXQAEFFFBAAQUUqEcgJ1mPkRdI+UL79a2qT2e4j5zfmi6D/YysLhNDDp9hu25XAFPdneTLjFgUUECBcRFYMC4H4nEooIACNQncRT23tDLJcDP5npxM/iY/kl5lGQs+IwfI0ZWVynSG15P3KssONZr6VpBFJFcELQoooMDIBTwBHHkXeAAKKFCzwMvUl6S8QnJbNieFb5A/yExlOwtPnWmFIZaVfZ7Gtp4ADgHoJgooUL/AMfVXaY0KKKDASAU6r/BlOlf2dpElIziyss/s36KAAgqMhYAngGPRDR6EAgrUKDDRUVemfyafkBPIBOlVcqKYfwuT9w92psxf1WvjHvMvYf43xKt/PYCcrYACcy/gLeC5N3ePCigwuwLXUf21JP/v72qyllxFdpJ3SN4XmE8Ddyu5BZxP9PZbjmPF/DeFJC+oF5K8T/AfUso1jHR+Orgsc6iAAgoooIACCihwmAJb2H4TKZ8C/o7xOyp1rmE8VwKrJZ8MXl2dMcB49pdPEaeOJOM/kFLyfwBz6/fsMsOhAgoooIACCiigQL0COSF78BBVvsrydYdYp67Fj1LRA3VVZj0KKKBAXQLeAq5L0noUUKApArklO1flnrnakftRQAEFBhHwQyCDaLmuAgqMu0Def2dRQAEFFFBAAQUUUEABBRRQQAEFFFBAAQUUUEABBRRQQAEFFFBAAQUUUEABBRRQQAEFFFBAAQUUUEABBRRQQAEFFFBAAQUUUEABBRRQQAEFFFBAAQUUUEABBRRQQAEFFFBAAQUUUEABBRRQQAEFFFBAAQUUUEABBRRQQAEFFFBAAQUUUEABBRRQQAEFFFBAAQUUUEABBRRQQAEFDkvgP99bXbLoAMdqAAAAAElFTkSuQmCC\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"\n",
"\n",
"def entropy(p):\n",
" return - p*np.log2(p) - (1 - p)*np.log2((1 - p))\n",
"x = np.arange(0.0, 1.0, 0.01)\n",
"ent = [entropy(p) if p != 0 else None for p in x]\n",
"plt.plot(x, ent)\n",
"plt.ylim([0,1.1])\n",
"plt.xlabel('p(i=1)')\n",
"e0 = entropy(40/120)\n",
"e1 = entropy(28/70)\n",
"e2 = entropy(12/50)\n",
"plt.plot([28/70, 12/50], [e1, e2], marker='s', linestyle='--', markersize=10)\n",
"plt.plot([(40/120)], [e0 ], marker='^', markersize=7)\n",
"plt.plot([(70/120 * 28/70 + 50/120 * 12/50)], [(70/120 * e1 + 50/120 * e2) ], marker='o', markersize=7) \n",
"plt.axhline(y=1.0, linewidth=1, color='k', linestyle='--')\n",
"plt.ylabel('Entropy')\n",
"plt.grid()\n",
"plt.show()"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false
},
"outputs": [
{
"data": {
"application/javascript": [
"/* Put everything inside the global mpl namespace */\n",
"window.mpl = {};\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",
" fig.send_message(\"refresh\", {});\n",
" }\n",
"\n",
" this.imageObj.onload = function() {\n",
" if (fig.image_mode == 'full') {\n",
" // Full images could contain transparency (where diff images\n",
" // almost always do), so we need to clear the canvas so that\n",
" // there is no ghosting.\n",
" fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n",
" }\n",
" fig.context.drawImage(fig.imageObj, 0, 0);\n",
" };\n",
"\n",
" this.imageObj.onunload = function() {\n",
" this.ws.close();\n",
" }\n",
"\n",
" this.ws.onmessage = this._make_on_message_function(this);\n",
"\n",
" this.ondownload = ondownload;\n",
"}\n",
"\n",
"mpl.figure.prototype._init_header = function() {\n",
" var titlebar = $(\n",
" '<div class=\"ui-dialog-titlebar ui-widget-header ui-corner-all ' +\n",
" 'ui-helper-clearfix\"/>');\n",
" var titletext = $(\n",
" '<div class=\"ui-dialog-title\" style=\"width: 100%; ' +\n",
" 'text-align: center; padding: 3px;\"/>');\n",
" titlebar.append(titletext)\n",
" this.root.append(titlebar);\n",
" this.header = titletext[0];\n",
"}\n",
"\n",
"\n",
"\n",
"mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"\n",
"mpl.figure.prototype._root_extra_style = function(canvas_div) {\n",
"\n",
"}\n",
"\n",
"mpl.figure.prototype._init_canvas = function() {\n",
" var fig = this;\n",
"\n",
" var canvas_div = $('<div/>');\n",
"\n",
" canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n",
"\n",
" function canvas_keyboard_event(event) {\n",
" return fig.key_event(event, event['data']);\n",
" }\n",
"\n",
" canvas_div.keydown('key_press', canvas_keyboard_event);\n",
" canvas_div.keyup('key_release', canvas_keyboard_event);\n",
" this.canvas_div = canvas_div\n",
" this._canvas_extra_style(canvas_div)\n",
" this.root.append(canvas_div);\n",
"\n",
" var canvas = $('<canvas/>');\n",
" canvas.addClass('mpl-canvas');\n",
" canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n",
"\n",
" this.canvas = canvas[0];\n",
" this.context = canvas[0].getContext(\"2d\");\n",
"\n",
" var 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);\n",
" canvas.attr('height', height);\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'];\n",
" var y0 = fig.canvas.height - msg['y0'];\n",
" var x1 = msg['x1'];\n",
" var y1 = fig.canvas.height - msg['y1'];\n",
" x0 = Math.floor(x0) + 0.5;\n",
" y0 = Math.floor(y0) + 0.5;\n",
" x1 = Math.floor(x1) + 0.5;\n",
" y1 = Math.floor(y1) + 0.5;\n",
" var min_x = Math.min(x0, x1);\n",
" var min_y = Math.min(y0, y1);\n",
" var width = Math.abs(x1 - x0);\n",
" var height = Math.abs(y1 - y0);\n",
"\n",
" fig.rubberband_context.clearRect(\n",
" 0, 0, fig.canvas.width, fig.canvas.height);\n",
"\n",
" fig.rubberband_context.strokeRect(min_x, min_y, width, height);\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_figure_label = function(fig, msg) {\n",
" // Updates the figure title.\n",
" fig.header.textContent = msg['label'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_cursor = function(fig, msg) {\n",
" var cursor = msg['cursor'];\n",
" switch(cursor)\n",
" {\n",
" case 0:\n",
" cursor = 'pointer';\n",
" break;\n",
" case 1:\n",
" cursor = 'default';\n",
" break;\n",
" case 2:\n",
" cursor = 'crosshair';\n",
" break;\n",
" case 3:\n",
" cursor = 'move';\n",
" break;\n",
" }\n",
" fig.rubberband_canvas.style.cursor = cursor;\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_message = function(fig, msg) {\n",
" fig.message.textContent = msg['message'];\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_draw = function(fig, msg) {\n",
" // Request the server to send over a new figure.\n",
" fig.send_draw_message();\n",
"}\n",
"\n",
"mpl.figure.prototype.handle_image_mode = function(fig, msg) {\n",
" fig.image_mode = msg['mode'];\n",
"}\n",
"\n",
"mpl.figure.prototype.updated_canvas_event = function() {\n",
" // Called whenever the canvas gets updated.\n",
" this.send_message(\"ack\", {});\n",
"}\n",
"\n",
"// A function to construct a web socket function for onmessage handling.\n",
"// Called in the figure constructor.\n",
"mpl.figure.prototype._make_on_message_function = function(fig) {\n",
" return function socket_on_message(evt) {\n",
" if (evt.data instanceof Blob) {\n",
" /* FIXME: We get \"Resource interpreted as Image but\n",
" * transferred with MIME type text/plain:\" errors on\n",
" * Chrome. But how to set the MIME type? It doesn't seem\n",
" * to be part of the websocket stream */\n",
" evt.data.type = \"image/png\";\n",
"\n",
" /* Free the memory for the previous frames */\n",
" if (fig.imageObj.src) {\n",
" (window.URL || window.webkitURL).revokeObjectURL(\n",
" fig.imageObj.src);\n",
" }\n",
"\n",
" fig.imageObj.src = (window.URL || window.webkitURL).createObjectURL(\n",
" evt.data);\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
" else if (typeof evt.data === 'string' && evt.data.slice(0, 21) == \"data:image/png;base64\") {\n",
" fig.imageObj.src = evt.data;\n",
" fig.updated_canvas_event();\n",
" fig.waiting = false;\n",
" return;\n",
" }\n",
"\n",
" var msg = JSON.parse(evt.data);\n",
" var msg_type = msg['type'];\n",
"\n",
" // Call the \"handle_{type}\" callback, which takes\n",
" // the figure and JSON message as its only arguments.\n",
" try {\n",
" var callback = fig[\"handle_\" + msg_type];\n",
" } catch (e) {\n",
" console.log(\"No handler for the '\" + msg_type + \"' message type: \", msg);\n",
" return;\n",
" }\n",
"\n",
" if (callback) {\n",
" try {\n",
" // console.log(\"Handling '\" + msg_type + \"' message: \", msg);\n",
" callback(fig, msg);\n",
" } catch (e) {\n",
" console.log(\"Exception inside the 'handler_\" + msg_type + \"' callback:\", e, e.stack, msg);\n",
" }\n",
" }\n",
" };\n",
"}\n",
"\n",
"// from http://stackoverflow.com/questions/1114465/getting-mouse-location-in-canvas\n",
"mpl.findpos = function(e) {\n",
" //this section is from http://www.quirksmode.org/js/events_properties.html\n",
" var targ;\n",
" if (!e)\n",
" e = window.event;\n",
" if (e.target)\n",
" targ = e.target;\n",
" else if (e.srcElement)\n",
" targ = e.srcElement;\n",
" if (targ.nodeType == 3) // defeat Safari bug\n",
" targ = targ.parentNode;\n",
"\n",
" // jQuery normalizes the pageX and pageY\n",
" // pageX,Y are the mouse positions relative to the document\n",
" // offset() returns the position of the element relative to the document\n",
" var x = e.pageX - $(targ).offset().left;\n",
" var y = e.pageY - $(targ).offset().top;\n",
"\n",
" return {\"x\": x, \"y\": y};\n",
"};\n",
"\n",
"/*\n",
" * return a copy of an object with only non-object keys\n",
" * we need this to avoid circular references\n",
" * http://stackoverflow.com/a/24161582/3208463\n",
" */\n",
"function simpleKeys (original) {\n",
" return Object.keys(original).reduce(function (obj, key) {\n",
" if (typeof original[key] !== 'object')\n",
" obj[key] = original[key]\n",
" return obj;\n",
" }, {});\n",
"}\n",
"\n",
"mpl.figure.prototype.mouse_event = function(event, name) {\n",
" var canvas_pos = mpl.findpos(event)\n",
"\n",
" if (name === 'button_press')\n",
" {\n",
" this.canvas.focus();\n",
" this.canvas_div.focus();\n",
" }\n",
"\n",
" var x = canvas_pos.x;\n",
" var y = canvas_pos.y;\n",
"\n",
" this.send_message(name, {x: x, y: y, button: event.button,\n",
" step: event.step,\n",
" guiEvent: simpleKeys(event)});\n",
"\n",
" /* This prevents the web browser from automatically changing to\n",
" * the text insertion cursor when the button is pressed. We want\n",
" * to control all of the cursor setting manually through the\n",
" * 'cursor' event from matplotlib */\n",
" event.preventDefault();\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype._key_event_extra = function(event, name) {\n",
" // Handle any extra behaviour associated with a key event\n",
"}\n",
"\n",
"mpl.figure.prototype.key_event = function(event, name) {\n",
"\n",
" // Prevent repeat events\n",
" if (name == 'key_press')\n",
" {\n",
" if (event.which === this._key)\n",
" return;\n",
" else\n",
" this._key = event.which;\n",
" }\n",
" if (name == 'key_release')\n",
" this._key = null;\n",
"\n",
" var value = '';\n",
" if (event.ctrlKey && event.which != 17)\n",
" value += \"ctrl+\";\n",
" if (event.altKey && event.which != 18)\n",
" value += \"alt+\";\n",
" if (event.shiftKey && event.which != 16)\n",
" value += \"shift+\";\n",
"\n",
" value += 'k';\n",
" value += event.which.toString();\n",
"\n",
" this._key_event_extra(event, name);\n",
"\n",
" this.send_message(name, {key: value,\n",
" guiEvent: simpleKeys(event)});\n",
" return false;\n",
"}\n",
"\n",
"mpl.figure.prototype.toolbar_button_onclick = function(name) {\n",
" if (name == 'download') {\n",
" this.handle_save(this, null);\n",
" } else {\n",
" this.send_message(\"toolbar_button\", {name: name});\n",
" }\n",
"};\n",
"\n",
"mpl.figure.prototype.toolbar_button_onmouseover = function(tooltip) {\n",
" this.message.textContent = tooltip;\n",
"};\n",
"mpl.toolbar_items = [[\"Home\", \"Reset original view\", \"fa fa-home icon-home\", \"home\"], [\"Back\", \"Back to previous view\", \"fa fa-arrow-left icon-arrow-left\", \"back\"], [\"Forward\", \"Forward to next view\", \"fa fa-arrow-right icon-arrow-right\", \"forward\"], [\"\", \"\", \"\", \"\"], [\"Pan\", \"Pan axes with left mouse, zoom with right\", \"fa fa-arrows icon-move\", \"pan\"], [\"Zoom\", \"Zoom to rectangle\", \"fa fa-square-o icon-check-empty\", \"zoom\"], [\"\", \"\", \"\", \"\"], [\"Download\", \"Download plot\", \"fa fa-floppy-o icon-save\", \"download\"]];\n",
"\n",
"mpl.extensions = [\"eps\", \"pdf\", \"png\", \"ps\", \"raw\", \"svg\"];\n",
"\n",
"mpl.default_extension = \"png\";var comm_websocket_adapter = function(comm) {\n",
" // Create a \"websocket\"-like object which calls the given IPython comm\n",
" // object with the appropriate methods. Currently this is a non binary\n",
" // socket, so there is still some room for performance tuning.\n",
" var ws = {};\n",
"\n",
" ws.close = function() {\n",
" comm.close()\n",
" };\n",
" ws.send = function(m) {\n",
" //console.log('sending', m);\n",
" comm.send(m);\n",
" };\n",
" // Register the callback with on_msg.\n",
" comm.on_msg(function(msg) {\n",
" //console.log('receiving', msg['content']['data'], msg);\n",
" // Pass the mpl event to the overriden (by mpl) onmessage function.\n",
" ws.onmessage(msg['content']['data'])\n",
" });\n",
" return ws;\n",
"}\n",
"\n",
"mpl.mpl_figure_comm = function(comm, msg) {\n",
" // This is the function which gets called when the mpl process\n",
" // starts-up an IPython Comm through the \"matplotlib\" channel.\n",
"\n",
" var id = msg.content.data.id;\n",
" // Get hold of the div created by the display call when the Comm\n",
" // socket was opened in Python.\n",
" var element = $(\"#\" + id);\n",
" var ws_proxy = comm_websocket_adapter(comm)\n",
"\n",
" function ondownload(figure, format) {\n",
" window.open(figure.imageObj.src);\n",
" }\n",
"\n",
" var fig = new mpl.figure(id, ws_proxy,\n",
" ondownload,\n",
" element.get(0));\n",
"\n",
" // Call onopen now - mpl needs it, as it is assuming we've passed it a real\n",
" // web socket which is closed, not our websocket->open comm proxy.\n",
" ws_proxy.onopen();\n",
"\n",
" fig.parent_element = element.get(0);\n",
" fig.cell_info = mpl.find_output_cell(\"<div id='\" + id + \"'></div>\");\n",
" if (!fig.cell_info) {\n",
" console.error(\"Failed to find cell for figure\", id, fig);\n",
" return;\n",
" }\n",
"\n",
" var output_index = fig.cell_info[2]\n",
" var cell = fig.cell_info[0];\n",
"\n",
"};\n",
"\n",
"mpl.figure.prototype.handle_close = function(fig, msg) {\n",
" 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 + '\">');\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 dataURL = this.canvas.toDataURL();\n",
" this.cell_info[1]['text/html'] = '<img src=\"' + dataURL + '\">';\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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\">"
],
"text/plain": [
"<IPython.core.display.HTML object>"
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"def error(p):\n",
" return 1 - np.max([p, 1-p])\n",
"\n",
"x = np.arange(0.0, 1.0, 0.01)\n",
"err = [error(i) for i in x]\n",
"plt.plot(x, err)\n",
"plt.ylim([0,0.55])\n",
"plt.xlabel('p(i=1)')\n",
"plt.axhline(y=0.5, linewidth=1, color='k', linestyle='--')\n",
"plt.ylabel('Classification Error')\n",
"plt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$IG(D_{p}, x_i) = I(D_{p}) - \\frac{N_{left}}{N_p} I(D_{left}) - \\frac{N_{right}}{N_p} I(D_{right})$$"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"- $IG$: Information Gain\n",
"- $x_i$: feature to perform the split\n",
"- $N_p$: number of samples in the parent node\n",
"- $N_{left}$: number of samples in the left child node\n",
"- $N_{right}$: number of samples in the right child node\n",
"- $I$: impurity\n",
"- $D_p$: training subset of the parent node\n",
"- $D_{left}$: training subset of the left child node\n",
"- $D_right$: training subset of the right child node"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$I_H(t) = - \\sum_{i =1}^{C} p(i \\mid t) \\;log_2 \\,p(i \\mid t)$$\n",
"\n",
"for all non-empty classed $p(i \\mid t) \\neq 0$, where $p(i \\mid t)$ is the proportion (or frequency or probability) of the samples that belong to class *i* for a particular node *t*; *C* is the number of unique class labels."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"$$I_E(t) = 1 - max\\{{p_i}\\}$$"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"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.5.0"
}
},
"nbformat": 4,
"nbformat_minor": 0
}