From b8f12ab58160a9de1cbd6c4a332f5182b7bcf361 Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Mon, 29 Apr 2024 10:46:47 -0700 Subject: [PATCH 1/4] Add contents --- 06-panel-intro.ipynb | 937 +++++++++++++++++++++++++++++++++++++++++++ images/recap.png | Bin 0 -> 194983 bytes 2 files changed, 937 insertions(+) create mode 100644 06-panel-intro.ipynb create mode 100644 images/recap.png diff --git a/06-panel-intro.ipynb b/06-panel-intro.ipynb new file mode 100644 index 0000000..7498efe --- /dev/null +++ b/06-panel-intro.ipynb @@ -0,0 +1,937 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Intro to HoloViz" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "HoloViz is a suite of high-level Python tools that are designed to work together to make visualizing data a breeze, from conducting exploratory data analysis to deploying complex dashboards.\n", + "\n", + "The core HoloViz projects are as follow,\n", + "\n", + "- [Panel](https://panel.holoviz.org): Create interactive dashboards in Jupyter notebooks or standalone apps\n", + "- [hvPlot](https://hvplot.holoviz.org): Quickly and interactively explore data with a familiar API\n", + "- [HoloViews](https://holoviews.org): Interactive plotting experience\n", + "- [GeoViews](http://geoviews.org): Geographic extension of HoloViews\n", + "- [Datashader](https://datashader.org): Render big data images in a browser\n", + "- [Lumen](https://lumen.holoviz.org/): Construct no-code dashboards from simple YAML specifications\n", + "- [Colorcet](https://colorcet.holoviz.org/): Plot with perceptually based colormaps\n", + "- [Param](https://param.holoviz.org): Declaratively code in Python" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What is Panel\n", + "\n", + "Today, the focus is on Panel.\n", + "\n", + "Panel packs many pre-built frontend components that are **usable with Python**.\n", + "\n", + "That means you can convert your static Python scripts into interactive ones--**no Javascript necessary**!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import panel as pn\n", + "pn.extension()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic Panel Tutorial\n", + "\n", + "Let's start out building an interactive app that allows the user to print a custom message.\n", + "\n", + "Currently it's hard coded to `\"Hello World\"`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Hello World!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can give the user more control by introducing a `TextInput` widget." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "message_input = pn.widgets.TextInput(value=\"Hello World!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Then, we can `pn.bind` the widget's `param.value` to the callback, `echo_message`, which simply echos the input value on change.\n", + "\n", + "Note: it's important to prefix `value` with `param`--without it, there will be no updates!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def echo_message(message):\n", + " return f\"{message}\"\n", + "\n", + "message_ref = pn.bind(echo_message, message=message_input.param.value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, create a simple layout to see the results.\n", + "\n", + "Try typing unique in the widget to see the message update!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pn.Column(message_input, message_ref)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To recap, we:\n", + "\n", + "1. instantiated a widget (`TextInput`).\n", + "2. defined a function `echo_message`\n", + "3. bounded the function to the widget's *param* value\n", + "4. laid out the the widget and the bound reference\n", + "\n", + "![recap](images/.png)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Here's all the code cells collected into one!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import panel as pn\n", + "pn.extension()\n", + "\n", + "message_input = pn.widgets.TextInput(value=\"Hello World!\")\n", + "\n", + "def echo_message(message):\n", + " return f\"{message}\"\n", + "\n", + "message_ref = pn.bind(echo_message, message=message_input.param.value)\n", + "\n", + "pn.Column(message_input, message_ref)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Doing this repeatedly is key to creating more complex apps with Panel, so let's do a quick exercise.\n", + "\n", + "Your goal is to create a widget that will toggle the message to upper case if activated by filling out the ellipses (`...`)!\n", + "\n", + "Hint: check out the [Component gallery](https://panel.holoviz.org/reference/index.html) to see what widgets are available to accomplish this goal (one of them starts with a T, but there are multiple solutions!)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import panel as pn\n", + "pn.extension()\n", + "\n", + "message_input = pn.widgets.TextInput(value=\"Hello World!\")\n", + "toggle_upper = ...\n", + "\n", + "def echo_message(message, toggle_upper):\n", + " ...\n", + " return f\"{message}\"\n", + "\n", + "message_ref = pn.bind(echo_message, message=message_input.param.value, toggle_upper=...)\n", + "\n", + "pn.Column(message_input, message_ref)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Congrats on building an interactive Panel app! 🎉" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic Panel ChatInterface" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, introducing `pn.chat.ChatInterface`, which is a component that packages all the steps you just learned to provide convenient features for developing a Chat UI with LLMs!\n", + "\n", + "Try typing a message and pressing enter to send!" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "6e1b47eef7ef45388b045f69d4d507b0", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "BokehModel(combine_events=True, render_bundle={'docs_json': {'8a999aa4-7efd-4bfb-925e-69148192146e': {'version…" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "chat = pn.chat.ChatInterface()\n", + "chat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You might have noticed that it echoes the message you entered, but it doesn't reply... not fun (yet).\n", + "\n", + "To make it reply, all we have to do is set a `callback`, like `pn.bind`, but with a caveat: it needs these three arguments: `contents`, `user`, and `instance`.\n", + "\n", + "Now when you try sending a message in the chat interface, it will be echoed back in italics!" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "def echo_message(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " return f\"{contents}\"\n", + "\n", + "chat.callback = echo_message" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You might have seen services, like OpenAI and Mistral, stream tokens as they arrive.\n", + "\n", + "We can simulate streaming tokens by looping through the contents of the user's input, concatenating the characters to the final message, and `yield`ing it.\n", + "\n", + "Since there's no serious computation, it'll run too fast for us to perceive streaming--thus `time.sleep`.\n", + "\n", + "Here's the latest code collected into one (and also `callback` within instantation)." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.0/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "52657123-eb28-4912-a84b-6adbb91b24d2" + } + }, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "fd1ebc0fa8ff41789afc3fbdedeaa1a3", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "BokehModel(combine_events=True, render_bundle={'docs_json': {'c6988535-b97b-4698-9edd-81a411a34f2e': {'version…" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import time\n", + "import panel as pn\n", + "pn.extension()\n", + "\n", + "def stream_echo_message(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " message = \"\"\n", + " for char in contents:\n", + " time.sleep(0.1) # to simulate a serious computation\n", + " message += char\n", + " yield f\"{message}\"\n", + "\n", + "chat = pn.chat.ChatInterface(callback=stream_echo_message)\n", + "chat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Awesome! Now let's make it much more interesting by connecting an LLM, like the quantized Mistral Instruct 7B model through llama-cpp-python (so no API key necessary)!\n", + "\n", + "Here, we:\n", + "1. download the quantized model (if it doesn't exist already)\n", + "2. instantiate the model with `Llama`\n", + "3. serialize all messages into `transformers` format\n", + "4. calls the chat completion Openai-like API on the messages\n", + "5. stream the chunks" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.0/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "1dbadddd-9c72-4048-9b25-f0243041326f" + } + }, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "b1a5aa7dfd4f4b1aa8b363a40bbc0f6f", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "BokehModel(combine_events=True, render_bundle={'docs_json': {'5c3303d1-50ef-4d08-80ca-f5f3daab1588': {'version…" + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import llama_cpp\n", + "import panel as pn\n", + "from pydantic import BaseModel\n", + "from huggingface_hub import hf_hub_download\n", + "pn.extension()\n", + "\n", + "model_path = hf_hub_download(\n", + " \"TheBloke/Mistral-7B-Instruct-v0.2-GGUF\",\n", + " \"mistral-7b-instruct-v0.2.Q5_K_M.gguf\",\n", + ") # 1.\n", + "\n", + "llama = llama_cpp.Llama(\n", + " model_path=model_path,\n", + " n_gpu_layers=-1,\n", + " chat_format=\"mistral-instruct\",\n", + " n_ctx=2048,\n", + " logits_all=True,\n", + " verbose=False,\n", + ") # 2.\n", + "\n", + "def stream_response(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " messages = instance.serialize() # 3.\n", + " response = llama.create_chat_completion_openai_v1(messages=messages, stream=True) # 4.\n", + "\n", + " message = \"\"\n", + " for chunk in response:\n", + " part = chunk.choices[0].delta.content or \"\"\n", + " message += part\n", + " yield message # 5.\n", + "\n", + "chat = pn.chat.ChatInterface(callback=stream_response)\n", + "chat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can even give the model a personality by setting a system message!\n", + "\n", + "Note, Mistral Instruct does NOT support the `system` role." + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.0/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "a3664db1-6e55-4f4a-b2c1-5ff889950e27" + } + }, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4e2c5ccdc0cb410e88f0f1e8f9e8180d", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "BokehModel(combine_events=True, render_bundle={'docs_json': {'f2849008-b11d-47e6-a0b5-f45b0673da05': {'version…" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import llama_cpp\n", + "import panel as pn\n", + "from pydantic import BaseModel\n", + "from huggingface_hub import hf_hub_download\n", + "\n", + "pn.extension()\n", + "\n", + "system_message = \"You are an excessively passionate Pythonista.\"\n", + "\n", + "model_path = hf_hub_download(\n", + " \"TheBloke/Mistral-7B-Instruct-v0.2-GGUF\",\n", + " \"mistral-7b-instruct-v0.2.Q5_K_M.gguf\",\n", + ") # 1.\n", + "\n", + "llama = llama_cpp.Llama(\n", + " model_path=model_path,\n", + " n_gpu_layers=-1,\n", + " chat_format=\"mistral-instruct\",\n", + " n_ctx=2048,\n", + " logits_all=True,\n", + " verbose=False,\n", + ") # 2.\n", + "\n", + "\n", + "def stream_response(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " messages = [\n", + " {\"role\": \"user\", \"content\": system_message}\n", + " ] + instance.serialize() # 3.\n", + " response = llama.create_chat_completion_openai_v1(\n", + " messages=messages, stream=True\n", + " ) # 4.\n", + "\n", + " message = \"\"\n", + " for chunk in response:\n", + " part = chunk.choices[0].delta.content or \"\"\n", + " message += part\n", + " yield message # 5.\n", + "\n", + "\n", + "chat = pn.chat.ChatInterface(callback=stream_response)\n", + "chat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can make this Chat UI improved by using templates." + ] + }, + { + "cell_type": "code", + "execution_count": 57, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Launching server at http://localhost:57205\n" + ] + }, + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 57, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "template = pn.template.FastListTemplate(main=[chat], title=\"Chatbot\", accent=\"#A01346\")\n", + "template.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Your turn! Try aggregating all you've learned to customize the personality of the chatbot on the go!\n", + "\n", + "Again, replace the ellipses with the appropriate code snippets!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import llama_cpp\n", + "import panel as pn\n", + "from pydantic import BaseModel\n", + "from huggingface_hub import hf_hub_download\n", + "\n", + "pn.extension()\n", + "\n", + "system_message = \"You are an excessively passionate Pythonista.\"\n", + "\n", + "model_path = hf_hub_download(\n", + " \"TheBloke/Mistral-7B-Instruct-v0.2-GGUF\",\n", + " \"mistral-7b-instruct-v0.2.Q5_K_M.gguf\",\n", + ") # 1.\n", + "\n", + "llama = llama_cpp.Llama(\n", + " model_path=model_path,\n", + " n_gpu_layers=-1,\n", + " chat_format=\"mistral-instruct\",\n", + " n_ctx=2048,\n", + " logits_all=True,\n", + " verbose=False,\n", + ") # 2.\n", + "\n", + "\n", + "def stream_response(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " messages = [\n", + " {\"role\": \"user\", \"content\": ...}\n", + " ] + instance.serialize() # 3.\n", + " response = llama.create_chat_completion_openai_v1(\n", + " messages=messages, stream=True\n", + " ) # 4.\n", + "\n", + " message = \"\"\n", + " for chunk in response:\n", + " part = chunk.choices[0].delta.content or \"\"\n", + " message += part\n", + " yield message # 5.\n", + "\n", + "\n", + "system_input = ...\n", + "chat = pn.chat.ChatInterface(callback=stream_response)\n", + "template = pn.template.FastListTemplate(\n", + " main=[chat], sidebar=[...], title=\"Chatbot\", accent=\"#A01346\"\n", + ")\n", + "template.show()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "holonote", + "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.11.8" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/images/recap.png b/images/recap.png new file mode 100644 index 0000000000000000000000000000000000000000..01eb77ae3afaccfb2d9826428ec711e07540b0cc GIT binary patch literal 194983 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 Ue6=M6ujfpeB23;9NdzS^<7Qg?+s zOw9=@B29{-HKvx3G5p{J`g40W1b8eGeM8xw(8}Lzte!BqRN4xO)dRIvjCKYP z3~hc?GIVW6EZ_((o0%Sz;bCx<(f8Mq8=NNomUVmVk+|ybMPr|8&--%G>!}quodf>> z`8g~`Z`{%D`rM0W1H&FikKD6WnD)i++=jXUnEZC1A2ep)VV|BL^U$N_RpdzF{a+S< zD9pK?H~1Y!2jMeh6TMf}vRu5_ObG+;FV>hv>@e$A=d*oo)%fwTivGJ=ZW0l@L4L<; zDFwbFjEj^E_kyC-EginI6RjO_z3G83_|IUcV2~4Uw8IR>u%HP=k$KhOIr^5&<9lnb zjWgfPt?S?bQgkg=pb0GhTvW~1+Eh#bK}F_={mx_iSdi%Dsght#5wGKdbOEbqJ3`mSH= zF~F>Mc}JrcJ<)-%Uod1gLvC)b?8r*lsrT-y>~B>_sYzy zNQU?QKP@NcV;U~pZDV@Q#8|{n(|fcE*J1y)Xgp+tt_aN--b>42H()*7Y{uZ9MhwhXv~Cf z`YGiEJ;Hr9<889t*E149T4SG)798HMc{hzGkl37=MAdxj*6a8Hu+$cT>`^s^@GzBS zP{bs@IozVJgWL`F%d&OQn4K9qYT-evWc{0!-^Lk-?MxgG#>$RE59pvWqejulQ`+9Z^9a{hexC0=~ zmD}R_Z>P3G`x4XHGaT+sP=cQ+nrvKM;E_07b?Km7-!qL;V&4grq8po9+_sxY~MW# z%H=q;1?Rf{o4!~lo>r?+7r5q4#Rmqk%sO6xhrc08F?TI}ce$OlR zy~`}V!I&5!cj{n{CFT?$W0>2RygyBLQkIm=SNSTcnZar7h?>+snRSRcy_@@ZH=K1R z4+Glz!F?ZYk-`R|4<+UWJa-R@d9Lc}{r=KGBjo4jmyf26=YurZ#A{V*)0vc$5A$WL z|9unZw-Z`(J|c0vpbUT1FPaV8y{4g;jCo}6eY03LN*OFjwMTeM^)9I=63$(NeSS)t zew`iuQl&eo1wF{2gO6gW2&FJj<^|(b2O)=+toZ$gzqUH|h5PDin-_JG%!9@0GCx$* z`Qqw|H#88|l>oU4An~*gT_5HRrId_dO7(qdbeJJpR>G0iwkcG}=HXXm9f0J8VR^+J z{drP7yf*!m{kRFt7P*n3!`ap?jyDU$VD5U=0W@@mXHn)YuFuzXzSMkbl(Fl-52!&` z8jBUTiNI-|u>N*)QYZQPaJSgkCIi<7xYe}YB1DHnTdnJ$Niy=YNoa98K_egj)UHcq zGhLSUp-Nv@DFc(Qc=GnM)y_G8YaAj`k$hiyDV zDC8h**+-NGTrXU%p7F|bxoBrTjOE_u38hgH*duT9zD|!eg{g>j>RI-ktKHC~ znnq>Pw)mMVt@YQ^owZ|P89O|0>V{!n(fM5YXb_;G2tzYmMEs;iBA{FsV4G!M9R)i3 z(gDW-AJ&M$qKN8pWQb*EdmtW2TLC#V2pZx!*=Dsc!ik2$Q;EZGudsL>9x>)Qxcc(U zlT#zi&X9fe<*aQ7t+N)YctDi>wh6pdvSk`zd5A-t%waBiaX8)awch{Ck(A3cnoYNP z1Xoy~y)Mn7b#PRK>MIJBZvLkhy1Xg-GK03Pu$`;!5CLR!2=@a5gD%hp0?~AP7sx*v zwc94GOcS`a%Jcd=a;)$=Tn$K=(o&R4uLaao97FjUaMcH z{i5tx1|lvz@$<+eu*`fYg~xr+#F}C*BbhFeWGgJd_9Xhv*Ee%?psR;{=tCSSkK?M4 z46WbI+^0z*7Wl$a@Jau;*4-a3>cKc1%;2ltOk>D3bK>>k4EZw8#Be0FYDP2xW3W)G zMnH?}E^c6D&O5L7x&CK*Y~x~a(KV=3Y=z}A{$>g&)NP)bnU&r zMCLybSkWlOwnm4YxlhKK7J+OjM!#RJp!t|nNj2(u9n(Jzy!3AFlzh%w_Ax;{cA+RZ z@W>MgE9$#1IQ@m9;C^z8w(W#>JE3<2A%3o@jCo(kbaRyH%qk!8{vzM4VLV%P5!zR^ zKdrs1wSCKHobQo_(aU;la_sbLQ4H+`YgzBcwxBb(o@S}Zu}4$yb^&e)Ed@BM7+7~< z@?zaFdwzplYxxK7P|&=ld!aS=jNFB^6A`s%iVht7JVZ}flS&$`<_qapLLiYO^HFG- z?smm#-2G+zy?F=gHiOry(1KE-fIjdnHQqoih_5J-7MziruG0y--2<%XlJIO~ItA7v zK>!PDvA z;9?1+$~Wj(;cn#0k<5a)~Mh=<>UUm zrS@6K$Fud$m)xYwz;g7{h|G5j@E`(HKTrF0k7Xf#Bg~&cW&?B^O~`5v+Cu~*qs;8u z&-rLN9UH4W*kM@w{v7g)8rULfCA^D%fG=cH$9vK8EDCe)Wa5@Eh6-$q9fK?# z^zfDG#~<<7K+LUc{Seuc%KK$)A@|W*Wg1a@@Yy|lK!fJVeL>2r1ZqJkm^q(WUGxF* zd6_~`PCM2Do6j?W76y}j9Ey3%szN4m-#~G#zk{_)$Gwf?kb!ieO#nCZLvYRe^J_2z zZYT=HV+yKi^>h}(bIo*Z09NX+9<9On|)NYX~`uF*2G6kBRl!W_$tDDBGtwt62tf_}GMm--& zav{T>qb~lcaJ1kAbXXSWw41NwUY2gRL>gAi{&I7|%o(I$+R^5D8itdz&4Um&{k7pQ zNqiR7=gD;z;C4HwX62(fo0s%J$ymPROxDv4%FM+U?&O9Bdv}? zFkR7TvPxwnib4QP57O8jnnP;^(;KLvU3ej4FDx)wqL=E=aFm2$$J4Ad>lD4%aqf=i zaq#5%b|;VyBY&!TPnsI5~2-fS#={3AEgvSWQM~SQk}-vGUz3eLx5;tmnc*fy3JuX00w~gG8?SHfoCR zh!NsQcI*<|+m2%=$EbhJ2P+2rcfk)uQR`QN#+9hRHA{x;@QXDzI@*QBX+F_CP-VZWZ;T=Npd7SVgp6OlW0))^|Tr#SaqL#C1oH@Yxt)D5T0x~t3!M^S1o_!`+xjMB>W`C-^zuz z63S|G9>O@c&&D0@(1omgGTOSXxcP2t!Ru-0obmp{G0<@BOJY9V?GHwB-^BD!U-;87 znm<=XnE|r2yvQZ|L)jW?kX{@xMu+zgMoiP_w{rT)#>2shi=LaB_^PxN?zX)920+K_ z4|%;3%%)c5t*ot8db=ewL51cKR)5oay^$(0ID$`IxS;U*;}ur}EgAs-+6mHXC&eT$i(h?R};nNOyAYEoP>QG;o#7F7asw;NE24ss1>6vCxu6&D?rc&jO;?0Ojm;9 zY$lz72vXT5n|X{}Y9!5}I$_^ZuEPm=^=?iU&1>WfSjDS03u!Xr7ite>LNKVZa@G3# zt5F?=GFg|Cg?TXuu52&I#8I=DzAC0fM?>a;pWxmN&Kh{f)HP!a<@U-=!jZ&7K*8c4 zB{ILT4@aSRuVOK3d;;KYIwYKDrYAUL7Sn2h6t8JN>T%~$VYuL-mt4ys7O@|Q??vVm zVxAss15vzBK9%ackBp#6PEX>pU$NqF)bimwMz6_20>jF-mgqIIea=WM0T|PIubX|2 zH6MMUAgPg*TI&cB!uxsvulC>>nqC0hY4NtK*LwWBfu@A!S=D&!Tdu-o zjm#EvQ;DaYu0w%y5xtcCyhd@5eVzIj>aBS!nTQE7>o0!EM(>~T)|Kb{Yk0pR8#Oh5{ac>r+GjSJ$1fyYiLz6p=np0?;2;I-xuwCt2na%7ht*V~ zEV%@D4k3R0<$z=Gy5`Q(9qxSKap#MkyUI-0w?2^bc<&wkQ}i5MSVdzRDgl#UVPP~) zRQ^;$aWqGPrdW}v+VB4c`Fz+qkNPiZWKx#rEJJmf_?g;ydA{zAiQczyYMH%2=XV9b z5@1ruW4|-h6q^et5FUwsk4d8-);J!t#`0`U2qW@*6!&p_Jcy@qaGQH5Z~hZ0I6=-3 zu1LBfRecgJRjhg|t;T8^5ueh0B1V3H!mou^y{Tp%;_$immLMYA^;nmHk(duVFEhn5 zQ!&6yQ5}!Xg{9^bHs~T5u6)_|<>`X8?!#`~Vqy@=w(o8Fw_L}~-ih;`$X7eKJdi{T zOR@eRK5zlGShl%tiY(S}Gj+QHc(xByhr6^gU`m#!6js(e3W`;x2Xt&iQn24eRHJ`< zj_9@fh|2%f8+ms)PLUvH%#aV(#}ST=FRL}*&aoOwyW_hLhKJCMjq=NG5ma8=$Dtt@ z?}&H7r7l;#;=gyhDx(H`7nJ}aAvswh`>Qdz=^0H#MPoQB!Oh1+QQMT}qCgpO8wCA7 zI%L@&#oeFvon;cAYe`aMcgIjgq!*3jMCUzTF=!_)$oDKO?|@6bn%E-SO)PA|!q>xp z;DF=@yn|5btM+%&k&vE~X<|j?=-y>JwN${b)5iBs)IU5v>?08D46#!>mC(=drbs9T zPpC!LHxQr9xIU8b1e8Y2^;_FA1?j25vj|nDW2$TF)F<<0$Sr^AogpQ8uKWit&&SEY#ZSt~EbpoL+XhqT)Ho^3V`EQUfaT~e;{-eqjU>HlIewjEZW22)FU4Iy`aUo0Qu)8S5|(Gn6b)> zYA`4{V;7JC^{d9I(WjOJ*!f?ylhS4#S7CXI;gg)qX&6j_N`W5ZGVE zxL@uJ>OR3GKPH>o+ju^AUfQm^xz{N8VVYWvvs9GiXZq+!A(MpI_RZqwceP-LFINaX z?}=NiEchA>sE9f5ho%&#l18r-u{G$0E7>7x0fq@I~Xic!&+^A zmHZGzj36GL;=wu@^JbFa;Q1-lIwRA`!|~NB=y||Lu5Yg7cqTo6o91e~XO8T6tI(p~ z{Q9Glw#LCw=r432H-t2pB08oH&=c{~Bpx0?^*;5p`g*@m(6lR~xp2^oC5o?{5c zWEM054ZT=aN(0!AOt5j3pdE)^gCx&r%$$+XR2tcQr!nkIl>4}WavU{k$JL?l82SAG z8dvz`5Odovl4hAGO#^>~ai6%L?eYAPBm=Jy#-_^w65mIox~U!4P0EB6h+H-Vk9pm8hg#1RzDUXln4YseE z-gUMfr44UKx!lk|rWRKTS6C#$_ZvnX_}LX~BliEAC5D>__!CzJKhRZ z@f`em#QO%0X3sc7P=%j8xd1bx4cI=R)-EcB&lCHfbhL$#$_e25^MKTNRwr0ZwZhYOLnv0DY5I@cpxA zHRm@n3z%A~yYQ{iOp-h;2&c0(GWXJ1YYYT)@RVOxW*XTX=YeRl+0)%FiG$o@Y7D@9 zodi#A(~%ZJt}mK}u|iN7iN^+~NG+iNGJC2&+x|;YK#H)8r#X-y5v#SDfsIl91ZZo) z+LmZdo?t&)1`dy9o$XJOs|7|R%v83$M?C-0s7KbHN_y$D8nK*HfkbdWU%YI!NnAj8 zs;oz4FuGvVFIG&VePks#@U} zRRRlg-qH%BUEP5PQDkCpDpgL$0dsCNklUz`<8pZF!m{uGzw3zir0u-bR&xbG!&J@h zk{Bs%QW|h#MCV{Vsr#cUlg{os!O1~cdS(B)kC(?z4G@u=SMqFetupPov@(^&LI-yV zclv^pDi^ z-q~(1`oN9jnkR>$b<{sIr&dMvT+*^;@IG*y$({Rt)rI;a$`ay0^jZ@ew^wEhLG?+M zkWI$T2Z}!dR(=(Cnyo)qAxMO{^1E1nMWg`7K*aqe>1^+zv9@cUy?KHRf@&*5{1(8WLw2RrX5I z5r!Etd4XmoEGjPQ2Aih1SxI>>MdGM0#-%4s=Bs{8AT5w4%3{@u;|2?T2Jjx{Oyx{6 zfbZ_ETh7E6+j2(ZmJG#8NHTCAun7LtRi+Y0qYRUE32J$Hevs-4qJ(>Dcr2eiRIN5c z0rJ&2?_w;@udn@&LN2a0q~4@mM<>ntqOHumwTlXAn%Tnb z!BL~70dg)Oftv%=5tY0Qi%O8pG^Lqp_6LM$=@b584(gj{ zJrF|yw>?ze+RdcIEZPe-(WGdd&D;IA+t2jRU2m#t`HEmPqYw%diD5LoW+;Ph6E3wb zl%iho@J~Smf(_w=u}H0?X{LT(lh0YZ zPU*_rbBlEK5nRsWd2G)AaI-4ZQKlzg(vJ7{nN_VP!ws2yNEuT8{<%eD%)y`#D_Qzu z7xhRqd&|gF<%fNxq!y=gX);IY{AcFpv=SLUrbf}Cc!vRs-K-dA4k|W9vz<7aTA`^K z-tX3ScvHa_lcP#33MHX_5?_{;A)sb5{bwPa+#v~s{~m;}e%)|Sy?Xrm17aQr@jMRl z49a;;r6BD`8;(`JA&N&AB-~GVOT1`~b+IHfdNLRhBcs$EH;efa?Qd96@~Q_L_!b8K zV20E!1r(m4r<+C49G@q>SCr67zQN)~E$Z(t(ton1jmbV## z)Ff6@@r=4NdcsayGWc0yjB$Sh-3mV!*OA#GV!^XYjF+YJn?40ye>jaEZ>W@^>CLB> z=R6AkRH-V7fQXn_JytYd>lsx7v5x^!O@qM`KHBcVq6o-<&g-;%=|N;+9fW(~$QP+O z;@Wzrn7h~9E7#>xf-}l#;lRw{QiOY9)7AEZs95?FsW!j@yY}0uzPL&yp-(cL_sWuc zAJLp*QSv;ibypCIne|zrnovASf!Z!pI*J+geh)`?c(dSinY!9fQHK7)Kkarzb)>5S z_EzYuzOX)Ouz6&bmy<^%qWAH!{sAkox$;SQJ?t^nXMKsjR^}a=z@>b z)YiTAJ3V{gaAha0*>RF4S7toc%^&fWB-!_}vgYZ+ZhX5Wvj^6wN_4=4x`^Kow!3E(kdcz6p?0MJGSjXj~`3QyJ z>Kgm|(fr;@wm@f*kJX7uK=#$mr zO`AtQ^ghV<&PG4}Hk{7fUW`*`NZr<%Gm#Ma9B)LeL@D+_M$0O>v?sp_8^;Mk8Ll9IDHQwsx@~T38%$MdN1@ZUTR9J0|WhK&;{8b7+NUTkX(v3PD!uqRYa@b(TX2t``5%WX1bJn@?E zmmH3i@eU4dhHvQZ;?Y#Qvz}~!w_P4ul0^m*0Ee4T8qT)Azvw{k$V2*5OET)##BWf^ zg=Us#rlAVb|M9qHo7IZ+zSEeW;XRxa0v;%@MBn<=#@n2VX_6;w^iq2u^SpE|d1P>v z&z?y4e19}pV#F?4R5ean<7;H))=bs*)u$K?(X zT?GH~Ph{5y!i#RJGM0)`H0 zmacwH8e4Fel|u2~O$|^G;#;Xb-mqPf5m6uxEc8`1pnxx50Ko%5Ozn6%6H554t265s5Y+DrfWM=i-c zshhqg(GHQei>CW8FeUbe!WDpED0i^JS@onj^(kiF?xWp9ig7WNoy+)j^J51L=3 z&*mO&@*6;3mZZ-DYW>~oIb}gz1eA)$zZ$ju=VQ1Ow5(tJ>S#8L=ufS$fAK{nL&21r zok46zO46L}r2Usjesf^~bE-l|e#~pE#})?~SGT0&lit6^Mf=yd0Zl2`*}zkHQT#9L zPS_}YRhq1blx1SCSy`QsS0$I1x5#`mU1kmV9d(q9iqD5&rmGqW#XMeJ)11g5M}87; zA`FKxmVW(5COQ90Y~S$+{YMtHLqKQ}wx#tM9NfF5(yNXB7;s7!oDZ&=JGRt1uu~Rz zq1|9`{Ao3uKRI}?Hu<^MiNfOomNjDvf0O4XZ@>KmLJt5Dc2(BT3F$x#4*Ao5P4eIB_5VzQ9GPB3^IE@|K2O12f>T5|n5 zd~AM-STbNq&G8ZuyB?I-C@X-ga#peF96sWEH+!K|dWgN2j|CF@TyQ!xld&N1@2{h#VgFzMRXh!(d$q&dQh?TT-i{>`^;hkkT>ccT>(l1GQ$m@WW760; zvcgoHsF-Lp1r5AqG!$C@f!p359ANTDIEGMz2z=(SNc!gQSFdP38w$L6dxYe#%KRjk zcO!8cdkyTnrixx(3yvDTJWPDa`n5Jyp}%`yHKEe{{MaXguAQWMc`jjg81$9eB@f@0 z$RbMOZ;p0OI+-)~uU!Mcrt(yvE@1NS%H~OuNTEj4+sKdci}^;diHb~(v$9`@xkEEB zN);$!NBVK8TI}mrvaVl))BmsLzKghXf5VFv{-Bsr9Rg@)=c!~33|Q`#T}hi^6KN1m zw>GNAbEX3|vLpx3Gg;>-wJ`TkW%Lw()|#NB{TA;4sOZ)HukrIk>x?c?(PdDO>ViwT z_A5vxiVREB$UN>kk@`?oK^uIY**0x^6$TA+nQiaXry1S=gMKdfxhU@&v3bndkzQr< z?nrNsr~iwvIsXq~TZF20d5vc1@NRNUmg}jy#Mifq#mZW$RpCOO`ZxL=Wh#~+o;xGU zu{nb(Y=At*rm{IgpLnf>=t=Ynl9!`HE9F5wtH&DU?AP)4I_g7|>uX~96Gr*5 ztM+Epe4H#GT!pFm{`z$R|2+K&r_yWbUK=4B-Qr}Eg7HFctjOrjxs!Z5xZs0qQ)DL( z20KHj4p)MJU~X=@K;q8uS1ifuH@z3qMWEfnYku0A=hR0g%$FgklfD%g`K`R!_21uy zqGq_rYP*2y^dkLdkNeWbPk*Tx#LT3n4d~?Z%6L72^hvisVD?B$)W;zM(uGl9d-yP# zgVX{Vq}Afm`aW4gi@*e0Wq(=?=Dqmq%K%Yb_g|--|4mVZ_F8mn^0n}aMm@!yAn8GH zf5DKXeDg?s2jkO|iM3t}IA|yGeHx=w16t*5#kl0pABjEyH6@}X*}eiDYE0ZGNACcx zX|n@VF6iC$5$uqNp8mbu!~eb{pSy_i^-G4x&ddz`K3(2`W0yEU_al*Rje1`mdV(k* zjC~{S&YD^|TM2*vi^YhLBj8lR!yO(bomrw${>X9-fqxGL-tGT0`+R@|iL}SW8(|Fj zo0(zLAGq;gl3HWERst3J8t&d+^Pv^pZyhepfQ*04>)OIUL&e!vP0L82SimaB7@A3P zfv4HbpoK}~2(Z-yK8?mi{}u8f;E(KH!jxLAO&K(&;_JK;+J60ScmfVa6KQYVt3e95 z)|Ca8tG14g`-CX`*oA=+6yzSSa~Us@e=(VZ3mClrNBr=03a`ibH%-xBYbK}zO<`vY z%|>qfS1P$<8}H1=&O~Z|00GzIF`G})LGXRwe&TTn~1;t8#RHe{CnBAt}IUx{eI%r zUevfy^L2u{kyumRim;+y$?z7legnNw-v;@B&mX`~>8-n9!kd_oZ!;90U~MD67kpcc z_@O{Z1BNUF$9Qjb2;5}9PC?Y3R}u-Y5g5y#UV;<|>qRTRKh~`NWxu}#-`8KI2EB#! zrJ9j^m^c2;p%krw&=RmJt`*a{{C}BSpcOy<3)T?_);dabkS+UvE5)3gs;<@A$}#-) zn8;~q`vWuS;T1+}sH5m*e5qvT-v2cMCDG6J^uRc(f_LQxn=~v-gwlviD$6GU))$Bt zF>lerp_x4Ta|T5{{j<)gb+8{u&LCN7_3Td9%=-7Oo>|O<8{WSe4euI7(3c2p4J9c) zp7I<4AvRWS%FWH~XL0f2*AK@xgKWICk{Fw6-P3|ecP0rnva(7s&`0l3lq8k}j?Dj? z#p%oG#*&ruTe2&3GFKrSh?$$y0^9;IZ}5m$!wm&FHa0hVmY0{k?1BjK5ukPuehg#m-7Zst~PYXkxbx+eas(j?T*+k|0syOB9xo6np20+2P=P zn^{K-`OPo#Lmc~?3%#FuM>)Utesfb~h)sh$hV)v5UBHs<{XLMjW^hT(i?>=hdrmR$ z>PP7{1iqAs;-G%7be6n(2iIm3_QjbvUp1<5eC=eNHkJF4F*UwoVCOT3dC2bWE=>ZR zM)$DBCoiXmU0v%ZKegL$VL-Te5_;YfCmp=9xyt9dj6(lh3PRK#(`woTV3`(a^PC)MX7zrhsvf#_-(tfVv+XY z&&35jZbNET4pvBHWEV7r>{ouM{J_^AR6 za#Hnr{OotS9cJ!f)dYvF4cs@0{ynAU9*S>FXst=gzCEm3Oe^mM=lIG6W}A^s zgh<=GoH~&QZ``X+RjSRpf1;~aOEKQ99{w>I%@Dl#Xg6nHbS)(%C0CrtxSjs37XTW( zDK~qgxVN2EW0$`R0;5sU)tV?l`n4lsLC%=8LH6Hd?v5m6_bClp3wplVd@_6NEPVi# z)e+7V0y)GNe>au;JAbqRyb!@;e`@it?xZUNcB#Fy^4&&E+elvxOPMabwtRPB&2TmA?3MyON{~801kaq*>q}oAo<4u54Hk z=jwVIykq@S_8R!#L!=nv&}%4AE2dGJkEZu|nKT>)xSp2s-TtyX0}hTW(R}m(O={{e zY~~pp1K!$8zQUwnbEbg^9Os&geuF8sg)4fhU{~pZZp~XWg3h2Xm(O(CRXO2LhG|E0 zji2>Bk2wd@`RlC$c`elh6IdaSqyZJe)N*TFcsd-en*)%*PFL(~L&Z94TRNi?;pAm< zhmf$eBZy>kzOT~6K?8P@T}b$5mN_BFk!ZVaVsUp}fh)rpIE4C@hTUbuT;2FnSVMb; zlb-0Z;ghz;J=kk8sY5`U8&;Z^=(0+=&pOd2vE=3)L~|%x8aVqhE3fZWS$)-c`$d7F z<3ASGXh%t%2xq%%(*0ek@ zA*2?vIZjYIpE`I^*f4z<3boIyzh0~q=1DZ_X^ypjXt_(h&ZXGEeijl#Nk!ikSFCH< zQILAL3hy_DHFq3_0n#exjIFO7`#d{XBfMJ`y8hnm5^gRg#c0ptj>dM~+t#u#f?0WH zg8Lp-nCMCRIA$;BJ`xWa8f|NpvELC+n&$~=;6Kz=4Auyn8?+{r|3Mb$Gk$Q^z%NFA zI27oM{)pFNmRr4{!c<4m=02>Q%9eiJQfp$QM~|xCHeonmJRPu#tr6+2W4f66O<~kn zp3D3kG$UusEIi6Om&s0}`eMR~vZ?E?aHw(q*w`qV8fOvit8qG;E^2SB zZ$^cZg7x}_7VPL{7h5S$lAQ7O@rNiX_RIRySq+0c)QoRZ5wX;YDFZ|0F6=3TSH->U zPDGdNI8_&LpApq1^}%Q)gqL?CWoA2AQ)_GP!G@pB`Qor=6;BluPtlfL`vnwpkW7;= zqT!S;@ky0Q97gnoD9A@Z4UyuW2kynhiA(X!rAt#zOq{{8%zl>?Beuyek{5YW=I&-? zfjs+zgL2-{NiqDj`Y=WqtJmpHfUL+8wO(jNB|XLG`NBJGcfM3+{Kl9J9^GTPM@2z* zwt)85QDuOQ$dwFB1o8_@O@@45Xd9Cu^gR}MAqi0vD%Od<0aqX7dg0DSn7FtWLix&> ziGTp5T!w%<;D*!f=kpf;i--2KIP7hDkq{99Y6%>?UzoejaMsbyjpG0FboY>+*v+tK zqx7-Sc{d#S29=NATL-^ix{WSFMmg1NfxTM5+|q*PDD3eGU6>nNw5AIg35nfuE@Tdr z1|uYbg!O^6Ri=wgDMP@r2G+{~>{K9XC^)6)F%=vc_fwSRU`uKK_wOw%mS2|rwTSUU za17s&FHBl(>H)q3VLLP=63FWw!F4AZ8nSsnL#^7&$jE@r_lJTL8`?qNpKU8I(f&iN z_>~*qw9=NnbF}g?)g9baVJ}@7wMLsD?CUeBgb@8g$?@a&m{MeitFT*^fh0(%%ZG@N z&}JbGH#jIL&)&BWnaLS!w;NtTt2Obt;S;zROpmwo zas1<6fYP8TVM7~+vOP{nSWuiX8k3N_UN>|9aCan6(uWwMWOZKb9JJmidALg6?BFm-rp?)Ftt zY{D~w%RE221mLY)IJL4r|0UeO?W#=rx{eFCKKyrwfvA!K_K2Ugl68+iUvbsZRhehzREMPcU3a3@ z_EDyn&jm4$&tn6xS!z>r^T2wSw4vESi*I!+;o{^8jDUPvgnE3s8`^2j4Fs%>bg^Rk zH9@iBypWCB4QFIXmYdK8-aZ4$1LpP@FQ5Ec+7qIc@}sa3$jS3ovs6{45fm-h2bgm7 z{ICVAuNOwC_()meW?rxeEe7|+ zhZqw)fT}%I^m{2rY%-ziP?Y`O#&6Ac6p^u+G-#l z;7=jUodtW>z56_zkIcR2ds~8eG)>y_%ql3zzC^SsbP0idtOO77GL3&5uezA>TKL|W z_C3tv-)coZJq@1w@l-2y1-(lMLOJDTW>0*%%ij-(&wOfU70wuybLcT%MjExUGeg5k z{h|*EG8fF)UN^_2qU#)}CWeU)U#nhO9G%V?g;}L@9GAs#BqmTIC2_9i2cstknZ`)` z43T3Ky7Ge3%c2d(VIKQ05?(PjSti=VH3wzV?H3`5u%SOMf_FoA4`p_mM0{Lp9F-K=UgTLcAH-LrL;CC;`PHoE=% zaLT=lfq}7|YTp)X-*zX35fkLkZKp4Qmg%*Dz;k627@`cZG)9bpO-$YFYA1fr%v{C2 z6HxN0Fm@u#8?I30{2fC3*7rCap@PUv91TV20Q)Vs?9*b{H9;h8-9A;&*!G-L-SXNivu{FIVWdJ{}C! zAf!C~*FB(<%4M5tm+q1L_it+ONpHmAHlSk|^KyNkd9>81CX{*uq7Ark+@)0N&aiu~ zS@KjCuWtY1%_F)B=y`0V0NWCKuImcszE3PjzFPT!=OT#D`)PPq$~tS;T5x-WpFXt* zf(8!Y9-y30(XX zc>06{;yT8p)o9^K!x5soyV&g#=bpJ5wr_pXd49Szh)bCM29(fr!~1#~nZ40&r6m`O zRu32T3TxiiFjL{-NbSzLCzRf2@xOv&_*Ay4z0_={=T9vhUQK>mH_qJKgo`+gzRwP- zuC_mwUi^AffA#SN%QRX&Rg& zhG53z{@W7)#LxLh7K_zf_;|iL-{o{hyf?xV_34~~{UhfO-aB#d{3)^b)kpVV0|8P` z=|~(H(fqDQ(Ih^P`p?e~_Hh$UzFO}{AUUn3qG>X{R8ID_(3fVACwtJ=0|V zj<`8pwZH$+hmaaHj5~>XbFxgYEHu4TLwm{h{l`L*!ALZKFy#K3u9sj0=w*QiaJ6c_ z(&umrcN8Bzc>DP(+1BDW5@q1-h!wl_L-A}$V8G73YMu=*@7IfXFBaGErP)0p z%cX{p{h=`I7pBd=2zDg8L8(Sw*a@3T1PA($zXS24wPyuAU5!hgrDjUBozZV717D4@ z3)Py-@amJLZ5VL6^0(}hg_JUdh8f06?$xB2b^xte8qT6wj!n8r2Y+V_r|0uN)pfV- zn>Dw7R9QbjF-jKT--iEg?!vL5e2%lNHoc?y=wyp82)? z9Yfice;Qs7(IwE!ulhidK2X!*s;U%e{25}XYP&x`5+Few>WUJu!j1tpB(bz=)T!2q zUM)B&T;6D3J?55>N=R_PM?)<*005g|*CF@#^V{JJ^Do82010@mWQX%Un5)qDL)&41 z9YfehB)GhF_9Dg%=i5$n?#y*BUeOki+3~_O8?jFYLpUvg@3*5dh`h+!;UQ$EAYPTg zpp2ySX4ifonVyDV4V;Rk@vwG?WXoz%Un%5;eU8@xce@&huxW^W5$&Gn%W?yC*;2D* zOsq)ar9$lU7oArBcMcibrXR%Q6Nfq1{SryuYVzL#q~H=T^o;+e+WthY>0CvOS>(oP zrZnI+?!W6*15Uf+%*cK2ZG$&BdjvAXSb9K)@So{@nHmVV?HHnjE*h}zfE z!Va5{KWydLTsM1tO|O#2_cyBbZ5^Yg%6-eR{)3SG9qb;xwC;BHgu0p^0XHMq=Op7& z7wB7V*5E565>qkXY|h+!a=Xp?SNr_(I_}(p9s?&n%F=zc%9~j1A^wAYCz>^7+s)B3 zg|klz(9&%Ib>+6r zS@V^4a#mJn81#S{x7D2Yf3*O515Xu&&GSm+6$QlkT#v#VPw99)whC&b+$F=XSgTH# z>ot9#?c~?@k{$1in$=q`mG&oh8No31#%a&({c<4pKMW>&E61ieQAy8Guqjn@=Dm?b zNF}`Qc4Aej!ZtHdLb<1*6w@-n8rgtAZ~{!SG+27=D_bpxs>=$%V6WfJa7h6tE*2izS#-%)-F z{^t<6`Z%h~Y$=CJ%}|*=klUT(hNF9dxKCp-gnlP%Q}#QSbYVh@%Y33Zs70Bb?QWU47pF?MlRVsbJ>6=TC_jx}1na1OXGmMq|Wi5<( z_QYj=41^(>a{WKs?f!xnLoMz>SeA3Y$T-lH3|X5+>+DxU;LNQB z9x2XyA2~Ng;<*`V$Xyh!_b8&)rGyxeD%XJgxbE+5h}Z_Gq{q~F0w%v4{JYyz)3$o~ zvsXF@f`ZJ*>L8I;3-&&=biC^|$<83;aZ?G}K!GN?@p52AA#qd7SBkOvHrt)!kY1u! zi-Fl9qd<5m|KxFN$kwds(Q;ojka~VsQLa&n4`yp^-!cmzQ)(bxPt9MbwK9hEu0L9+ zRcs0vTMtOXB=F(UKACK01}xr(%eXFaz}x|=*~x~03?=BZy+(-^6%_0ZH>UDnAHt~a z(|rf)sj<`1U!&xAjI5~Zh}%O(>*L*q)Aa@h3VZL&eoLlFS1#=P!x2Z{u6U0s@X=|u ziicv+nh7+-9Sx!~gkmv;%695nlpmXIfa^uP@2`5gZ^vDZ)oSI`87@-#gM7IM*E;HM zjGjU+yHJH0sN~}Vd(}!ftfpiJzn|%Z|LBRy?gNXbHD?TGz7%UKTt>_!ATOnzRlb-| zJA5Bi)_`I)wpeW?BBZ$$;Xe|4=?|0r%Qo3pq)~hQ5yQdz{w7A8^aEp>f#a ziIi`u?2K9R6(PS5GSY9pAdbaa>wJOR$4fIv+l09HcO|m_dC#?s<#Vjy_JCwZf^yAS z20~*nNM%l}a2d=ayZgCMiK3s<&T_EZ>ltfPc49hnoe400oJXES#G^KyG|ug_U}!6S z*S%(-dMOnO9tbHWTzOAr9@!%cYJSXJ`s}{7wQhm;aKUtW6J$T5dZu#QOHh#{mDG{b zDP31C$lUyllGFktSV^xQ?e3{jP!sidbGIIr_U;meCgg|5HNMQOUAhSnw38_7=7RN) z$Dxo?xJV7V)_yu>bu{71Y??W^^}$HDJwKUr-J|TF&>5|D{@B`XK5eD&kS+;Nr8UI1d+v%dc)_CLhn~~m zN%W$c5t{s=pr8OJcbvx{%}(SF$>l2%nY{0(XR2%b`C?G6KT&53*CHsy-1c%q03TDW zT4uw$w0LVw7#UFAK08bvfy;i@Y(A=g0eOD{(2{=FDAVJc>!qJm1|u`npZlK^yP5xBR*3`jVg5_~QN&&9aj`Tvw=)^&Onfj=K56#~{Wv z5Q3R(7|>siI9%NH_0Wicj~wti=CW@A2@ieoSQz-Wzw};W3;~2hlkJEbfX`t=D(Ww4 z*6DV!h3CG%ebRp#h*!SM66A6)g>XCrVJz_-{BW)5Tq+T=ae)ip4y4EqE!s!11_a{HI0_|4P{`hFt<98LJy{`#fIp$bj0*;lq2~G zFL}+>h*#ua*7UP)5IAv8x;JV?13ZV9)_luvIkxJjSG6>nU2TUUxtN%wd>$R^#useI zenA}QLsKU*wNt7#eLJXZ z2x`Bt$W({T;yP^B{=l!`lP*l+O*62Bnbv$XUybS`i7mJJa1sab+e7{J!RtT9nDg2y zkugG-n_T;r`Y?BQ2Rg)qb5%ONn}z=j35jDhUWvPFzzHE3+RUfl(WI=1BI0Lg0~T@m z3Pjw_G#Kub)bm0|lP$hK@phRh`+$RBUmjnuVSAFckHuv3Nz)>l5~FS{2XmvAFRT#7 z?g%LCib<;ad~98O1Gd&LbZ-5;^#PyEuBBzVEy^KS`Y^+I;l?7f?6ZLwX#8UHDAU0{ z^Zm$^%qM3d2V(D&ZB2c)OUhzz;CwgR#iNp-KV6H0V3*5=WP}LUd~8kBjGHFU{HYqh zL}-w;4q-=SO5f)qq>q)lH~DTC5cfn@(r67=J}O%F=Kh&?p4@lBowLDoq|o2saxrwb z*XW#;e2UDHL&L^W#n}OH_TtiO3wUYCRB zFZh?U+h!{RcQ~eopLu)#2%8a}g~wx)cFrXpWdcpre%YO8>P)huP9>kn;qC98dfbj0 zQtO`VTg{}2q2-gS(>md!f*1Y4aRZVqV2A6WPC`Zn0`)I=C5m`)cfKDnUmgL3O*B-*G zlE6&)XrjZ;Eq@%up%dROk&5mP<*-yN+D!_1(XtY4G&6AFpRAsXjSAI`<3l=6ZgEU( zXS5BCg82GRwrI$TtI&5oM-X6cKbi|vx;46V>BOG;{F2Y`wu==Kg%2_i*#qLXtF>+E zy^#s6PUg!ZcdlR|ZPwiuGN-DEZIu=>6a771tpfo)5wnP8X5SY?vEHTjI*qmD$?f!5 zQenugq59kYyzQ7gp((x-o*d{MJL1A?|44jozSs141+P>_M@x1<94e78IRNESxas5-7z*C{HcCqUt1RNylF%BPxnB{98ScZ6$4@dJ&7p33#XT}sQd zhy5Mmf&dgO3de$k<^@aLLP+3n^JzHSwaH@5=@>Dl6dKANQul8_cQ4scBDLNq?L$p3 zK~qOSaR2@FVJ^{z)Nk*fP=|ab{b&k^2JrxL&2F!zt-RCW@~HUr_&oWM!+u4K@0-uZ zXT4Sd6oYpgGdTjq%hA`TD5@puL*|O^I~~p;3V##5mj2$(dslJ9R9(FI^! z=t?aT6A4Xm6%Qz+jf4b4MGToafz{@kkB3hlQ~KIL!8Fsc}0)^0;lv*b^C*%gA>}4gRjy)y<6aQOadsEx&fM~uZ(saCan*K!Yhw~pnCC7z9%d- zJk$cB$O}9t;On3IO%{1v+X^Wm5h%Kk9DLMR?OwQ}2 z&&S%@6(K+8-A2qy+lvrzwJ>#L`Tzb|ZIuwxN@r&a{_wyMm)Q z0+Dfc5)%pA3PW~JNj|9MDa8)N7n5h(bMTEY%kELq721 zaXLc8e;6c$sCi1D?~a8KX&6z_%0f@zG;?86N4EPv;|=+@vd%fXPhCDe7loEutzJ|- zEW}~lTa%O2N80;vCBmosM&i=n3H1VcZ28$^GKFmMvGKOog^T`>jTr#gARe0=GHj@5huF}P9;!LAQBBS0pa`fNR znLnNjmsuXy2Mr`NqAR$TlXa!qX_d%>$~2RwZNk{l$C+cU`^Hn6WrwcIdaz*fx>{7G;^ zDqf;Zf+2wE7%{rR?a^k$0X;u^m-cYhg<9FpfEe+A04_n%zKrM1!qRFV;#ZuAsVs3R1gB%)R{5Op%>uYaZz0CQO`YB<^%c z?J{3@X`@mlOKPkcVPxgwS~DTNEL~->W=Gy2!2iC8?@`~oHtU7RMoH2ngR#!5>H2E9j8wJGB|g zFg`TXfgEZL&6_tjEb&jm8;-4b;)!e-E* zff_RkYArilQdC{ExsMY`vDXchB+OlR-K%kDf}~;wSiTq!AZ(apvS&ZTO`J5*!jNBx z8s?m*J9N~c*j!gr2R{(otn29CQzlQ7lKgY#zd!7NW$&(o?uu&J zZN0Jdr>$-vw-SkPfUwCR)ub{PW^(gB-(f0D@mvR?eX%@oPp{30J#F5GRZS)>Ct ztY@yiKd02JOS*4A*x;V)wL*9(ei1_0c-gaCHiqlh5jG+>N}ij+H6C2fegDx0_k8aaCKV%SOx-+x@pP`$nDTD@ zs$FhO+r=WJG%o633$^rurPApDOy!YUxi8NimFJ2(v%BhTOS_-v{^_Q4|4n^IaYau* z!XqVwP1}j*h_Kn=Mz@I}Y_tY^vS%4vL-u)0gpJglz%;e6Z8QFCBW9-dS}N(KE%GA? zL*=8?`59cpfoI!#a7??!Zq2eo5=F6Xk2c$~MGN(Xx^C2{q1JbfHO|Jy5q_V(2w4Bt z_!}f_PCy&*V6ymVCBo*JXP(xiHOUrQY=~B`US}toER?HPuP*76r?klK>}G56$pUJs zHVkESqT8r(LzDFI6EqVci;mf|X6rObS25~6nUMLJhHR;^bYcmMygLZ>&??*A%wBO}>;7iI>YRtE|Ok zWbuN;4Pi)=%^(ZB4C&K}oVwj6y5p%f@=h7AlT=La-n}gzR0KE;fWcbVDKX&2@e53z6P7qwME302QzyH(+51mF{nQptg!g~P zQx+zG`XWQFzwQQ$=U8#fnKN4(;;~j{!Y0>&2aXfo#*Lbqgb^D~Frti<0rBNwLr18r zf0{}g3q#sp<3Z79?fk}7ISY+Ug=&PzD9YFq?Oi;Ek~a%TQ_NS z`_vL$I~h6gq7ty5Q@cwEclISY+*{ACJWRp{9N0wn>pMWD*ypO=%BkpfYn!q7PzT`M zzFk{at=c`VM~`l9^q4V5hEUJEV>8rWo9=VZE$?pEX(yW$-XSg1qepLT9=~)=nl>@w zf%v?m?Nk56!6$h@?4Nvn@WFc;Lz-KEA}-p)lTSSETC`~ErcRycx_0Yk?SG3@0Q#!0 zRjYQFqy#%kE$2D2g+&=zd?O(^X7m{M@h2aPfNW*)(0@|mh>Jdrdd7^IFKV;c&Bk8T zFfP2Xg1b$p%3NW~$@Q?IqeM;(lF0lJ!(ily5mM8t?E3WSDfOr4t*pdHnZS)}a8svF zC&@`&gR4_!@QK{EGE8~hrOm`WmQ}*=E_(d%eTR3P&<`3oRO5MSle(Y|yniBKT=L_! zFFSeQIpbrrU(`o0zv2qly<0C4P4l%$tYLWt&$=Q&TZ;I8cJd^ZsgK18p41Nq18k~( z`Q;~*iX;!zY4>j3Weo8?5n0`2OnQusx1>$}slVqmKb4TgRXvT(sMDNmN4m5ME!_&6O!w7e&Qe_jQo=R%-|I*AE?)hmVq;;Ud9E0DQnwxs}=`Gcdp{9ODdBBiO z_{0elO$C@BaIYJiJwe zP0gCMleN)ZED46EpKj-h3$s^We#In5TdMCe*9{yvKq`q>*nt#kXQ&6gE}|ZZzi!>T zTYGC{^FkvdV8{n{t-upJAT&@Ns8Z!BNnJEBVhfBQt>~+?L-I^tL^2G=``G%SzF9-C z{!%q)Txw!uEPj0$F!yy}599wytbT|eqUqIFU$fg@>eX-HHmLt#cjvBZ)r4_(Qx$3| zX*~`kz#0OAHatN@G!kL;CDq2k8naw8)gw}U`?3CK!%?a%o(uX$s{PWXHBIv2MPuUuXxgM4O zuFrJWSQTf4G;3Yo###Rj9yCM;cEvRo-)=-PV-kmsDJ5)ZyST`jv6mSgu2=5~lUR(# z2rQ4+fin^|54S62#6`clzevJHYeEqVG&$_pJ^D;Zkqnt#pU3A(Wl8;9@2DQ6Xz+(k z8Ea~4ZajxnfHcAON#Dm8NaaR^fc#J#2%E>cm6o(`X5DnTLh3|o?ZAhYN{yq=!&BY-q~;}} zvE_WJaqn`km!gF5Tfqw$vCO-%osc$@-+M%2(5oXS%G})4Gvu7E8K0qSi=$ zuhJTcgSEG(u5>R+^^3w$K3sHptdzd+de`pRaQuqd$Ip2;S#|acy`II&;zXtxyx_Qufw=s-4}0dvAMzu6!i~%k1^#@ z5zTF%>L_*87ZdhAQQpGWfIyN6(1w_U0%4ORM9F{Q!SsYpyY{VZlg~-)EG@EF7}u#= z&qVXt@NjC|t5-L(7lR*8f!0g>ngz4haVB*pCl+iyy7zEdHR&Nz`@3|!nNSc<6GeIQz<|-iG@P+LXrG2sj|_SIb((<*@LVTzbUS>PVkaj z4&wEWCIVq|(e>F}%?@SUr?0PZ&vspzaIH6F%3kSXHyc^nJY-SfR94Z|sz#B5uSEpNKc zW7;is>sKB+fdPYR4GX#(9xm)&AN~7b*Lw2~DK$3an>MYtMLXkw$Iqw9r^kQLz`^Qs zWpxVNL@EP+MEZx`(+2VL_+yV-yRY>~EhB{?9XqsdCl#uiBJxIQbKB>L_C&N>xKI?jkh@s!`o&^bGThAVSq!RFgHgp~B9sL8fiK0b|+4zM$D&pmjuxwOj zNg@O>d(?E0GKubs(Pd5QJL!AEX7ZGYQm5!=QZPdX4>G$N*!5YsXpu=4j2S&atiaAzRY~m|J#WOLt>zVHmDzb@PXk?)jh-UU*{oaWw=8WjeR2?MU+>(ln-Bph{z#7Nn)Wo@j_faOCu z#{H|Vx>k~bl9IURUP}Y4hYuTOcD8!qFzRpp#t8&%VCh3UHspA=YeVobp1PAhUnKpFKKKs0z_QGTlOC#65t5zlAc(Qj_d9InAi20{ z(-wt!(%K&zS0vhyR$)_(og%qCC_OWDaUVkWZd$@Oi2(DX-gauOl=h;3_%JT0`BuKzOua0 zPiYSk!lsAX#Y%UtY?a{`2bQEu+vU&-6;8%co>#0`F~x+9MXG;j4-nGVUUQ>V0UtYp zu<`zm=aaIUN>s?+=r*NuC6k^A<&t!8%xQiZSuOQm;3 zN@sA{rGf;xgUclKrSq=HW$IPkYy516i=zpfCwi0?ag#ynI6q63N{6j+5dtV7|15_+ zyP>aw&mpl=xJ*WuJ+JKL=zvH~)Y|FA*X52JP(8K8ZI{7f2%$Q?%bHr(@D|IYdX!pH zzj@rX4;FSqo6UENzS-#tl}_jC_v6rNw;SAKNy4F4Li)-00yevKX~Qj#=W#b`UGw6= zWm2!&EYd5L;ZWo0V(#3_a=PIyA|w&Smf$i+*nCCPx*}(0lB7{u`G?Go6#3%o^4LWU zqn}#rHmyH&;1&sZk_a0~*dRsoSl8lGeah+HnX=M-_u&>xQuLXPlY4g^a2H;k-Q8TP zhm%=@>WK&RY1VHXiuCB-M-t_4*x?lOb#MWJ)pWh93{6 zCv4h0)k1{GizbHtx~^w7ECf=LI*C-!wZYV*ZHHdAI9HI{xl#x==j#*7(6XcW-mc9z8D z+a{d0%$Po1qW^g`IX`9#SmGglCU+J=Y~bFL4Tts}+S{!aqekPX`q{QEvS7yU4PhxW^>i``8}OtPE4hS;&*wk(lSLDlrPNUtoF{B1 zP89i~g){AfGO}r50SWX+nHjZEQ1OyW*j)Ee9BGV^_9-F7EkC!8=guNW5hSq$m8yj zO`KOp9&U6PT(7E9MH}dzA~05K0eoM=0@&l{Kf#$z>(C)X+uiwhFL2 z;3Xnh$TQ}=q0MiaG;y}cfux8Y9bm-7goAiPvjezYBY?dLl z$EKSNx{n|K^s81aTe>P$uF+;Xlk&M!8`{WCK-5(}*}M4l*QIu%4c6F5nJjgLGeu}T zEgKVWOYM~S_+y+v8if<~Wy_YUF6tVwM?dBnT}+hZE9fM zbg%)z|B`HopklUe-G;-fu*{4ku_sZ(cHym$%K&sLEin{^1X z%G3)fHzWml!|_QN<})Np%a%P${ z?%bx^xOQ7Vfw*9<|Ml19CM`pIfB@_xA`1VIE3aw8O}n5E`8?3SXv3bcfyjrzJ?EVA zlA7COY5IIeGA~1I>_W|*`XL%dMkIkX#ARpI54N4K0|?e@*RGNj&NtRKF?#OH>9HvxDWGnWFoG!Ewrz)nS+i!P zsW;D%EuaK)JHCFv0M+*U?te&!Q@K?)TJP-KW%WaU&YdT>`(xEwNt-?CR*A4-e(&F} zzYb(>lhju$8&A0XjlPH@AK1h}BDsG3dgh-SJ%W3x<2H8|UJ$pT4 z^#hsqclsP*88cEs*nIKDXBsE!SzZWF+eOj|!seTAzSDTn+$4;so2w-a)J+oKzs&#H zJ@UvS);=gdnDN)9b!#0CR98D`t3#TIB;%=0*gVp?v|A~u-9e3(M71l`sn(;nKAz8A zeP2O0eb6%Z!L*ICdndIh9fV#Z)u(?~E1)%q)R83>61go2X&9*h%ZM;**=MT%EcGTy z?CF`HF&j2@dX=#?L(fO%YYnckLjKehk8rdN!d-rQ4yBV{p#RU1 z!D9^Kj@Fukn~XeR!#ZSStK~-6T=!5Ocin@9+>oXVq^7mgRFWWUw#e}Dphk-imtr|0 z7e{%Zc2cZdM)yRwGVa%T+uVp2zZy2h&dMP2qqNkA_PPG`7n-^_eS`8q)?8LKhm0Q= zkos48+2GkHf^7ex^5oX-Wb1dk(QTKQ8dZGPiey6JPl|+%B(cG{@z64^*jZVWU*$)H zoDGiT+rCO-Ft3)65Jjo%E`FGfmW}c{X{OlslLG0$8$JU9 zi6KB6V*Cw+O=9Sz@R#PhNfPbvuPWo>N|5PoA)OQK#eNfd#zBC_dGM{9<$&!e;5xUyoWpyW;DIMYea~ zeXma4Um$BADH1hVKaXGXpxP5k05ON^zN$@ z!%Ake$e(I^!e;Q0ej;s#9d>Kz3q{yO zpI%YCloB>Zu#Az-85ULXE=j^>cscj`f(T)=O^X1-Q^61c#wN}^lGu4I5yHmXIM}~` zk4Y_Y^6cxvr^zR6EJD}}Gh?^hyyczsA*Dqw2^$xe*1ad=#gG^Danu5@zwTz83_oo* zou!1Z88c>t?9L4FN!bQFny_iFn?2}Lj0cd%X;R18hLSNby8V$a2%AiqGXK{J8&1(@ zY4gD?Gc#w-P+#4eP#yyf-1G;I7%66q_KqZ`7nM8Oqi#58~YLK>^%WQ_9z zlipyn?H%Q0%w(f{{q;BKrkl$}2LDSNprWe7R2mQ8Flh+Hp$3|I z2xBDgF%}Iuh6ENi9>5t~Q5h;%?mV4nKW)Z?NtZt+d!%&OJT6|m$TnhZR%r)3V?3QP z<3%GyY_rMuYlWwc(TGy1T%TCmNo?%(>5#X->xk=k2^&ZcjPkOrWdL45|>UXVTH9|=y> zwA!|BYjZ0ko5z{{k4i2!*P;mZ(wBv+!t^8oX8nTev{V-yE`)zmF zMw`4I&8=9uQbfuKv&;1AE3X@2!%aR&k9fkSl?ajy&U^Dn+kus=k8z$k6nI8)`Kez=vYc=0mUKEM3xbCGyWP2$F5Lpi9c zv|3M8xw49@QsqiBj$WcfDTRrXJ(eexcs`oY!`^>aK2RMBXr~Tel7u5 z{#r|A?!gBiHX@mIFMZ-@gbnM`{{03C`@?P6_%i)BBy1pTxL9DY2n;{hQ%`)a`j}LT z?l0(O3|{8me}1E_DgJd$HeD|*wIUfPeskhVsZMX#ZA{$wr&~q~rM0W4A#J+VoOc9a zQ@3{+wZnt1=OYV@DDdTs{v>VI4QE}FSw@G;hz!~<)uQEYv2MU59qNd@wH{m6+Rw<= zixVYmxRnYC8wi`hO%}K%-=8?bM#G*-`_$}M+!fP}N^ZN=9zaXyjRdo>M(lflRHDkBSw`dnx5})wC{6@ngiSj2A1wmfNF{2+A2PDneyQ}i4_Ar0vq1rOQ;i}rI2@xArMfMvQ{*9o zhsm&M7D>h3W|&6zeUAh9(|$QoFIKFmyY{+kZPUVYj~#wJevBdXN8WXm0q^_ouOS1$ zBaGaQ4dc_`leD8HY?4dZK>DJFQ&=iD4W!cfvm^v@Q zmXu1^U{51gu3T>R>#xgB%U{}GY+bNvX(n~gJUY2Y+K&w)@90w_h7Xfuz`rz}KOq&Ww{0Uxe3Tbs zyPZ3AH3 zDk2?3nP^K$^;)NhcZyj{)_@U$r~$lGI3pcqz=I z&n5F0{Gz#_fk`o?gs|z{xs%%>QfKVA@pgkIM)dl)aUoYpw;_%1q)P_g+3GUrl7RAH;zR1B zc9+t2yJWW-$4A%*N;`mhpjAP4#T^A?)OV@-XyzuniITD)ji339G_LI=-Bh&+8#WP} zeX$ZY$4l6F+`uR)?34|2SKpV*-TFi^lOFzP=0@54Deg+1lg;(3^NU;e`yQ7%t%yAN z-6^8!u0{nS(n?aHdiS}Fx*02?9!z=|bZ+}>dD#oxFB^mrL&bW0$SIBjQVqifAy=9Y zZn(tk{~RXeB0msa1+*S}N=AoQ$xaXU3^_nkL8x$7zWgEO)6 z$7IN)h(G=y2+$F)Sg}%qkzBv%!9N2BVVE#|7~W%Ng{yHN*2bJ$D0t6_EVn>#{W2MP#DQB|K5YRb(cmW@uOn;dBg~*43t!S=LDW}^nrhYVmipB! zGrUE9IHBYe(H2q?)yK{Y@e>Ber^mpT^?0hy*Hdx`8{)@5>0*eX(U$U9{+0ayR-XrI2#d85NCR{pN5btAVn zpniZVSy|a*7%CC(En7C5gbn2ex4%Q!Q0L&xCWiLLEoHQ=Xs4naZgf~8zkQ!vWCj4i zgGoAD&NMoqkO{OEV{m6#e^{fo1v+ z;rNRU!!zt@u+fAt=Nex~eA;~h5&7I&RIFHWcgLM~81YWtaOAE@qsEeYtEtoel~O~z z%QmEpuh@oqrb}0m=&vfij+Q3rP~Qz3)Yok+O(az^&&G4eG4kBAM-QtXY^ZVi?Khm3 zR(!sRgEo+ugV=vin>0u#ZVkh>Of-&(g*n7cZ6sl)`fbHH$QE4eHesXq@y_R&{F<@h_ zK5FzRvz11C)DI5)qU(p}#E((xX3bhjm1?>q+uB+E&_Ab2!nbJAl2Y+*Wj1(x{m>pC zd+brED7F@1^PB8()pg57ZW8}ZH{GN@)Jto(FDx(7^@Aj7550rr;+81-y9%SUo4JP{ zt|>{Ifkwg|tA4C7fAb$OoHF@YlNxK)s+nCY@5|?-2A|_1Y@}|A(c!e(h~InPy^=|*Z5)y=IJzbJheI%aTTu4BbBFxvZo^nXxX;0^6brQVN;oQ}sGU*0e3Vz~;$xz^*(5m6&DOX^kY6&K-ocmBV# znsH%n((1#t-kTyuhyPtIr@OCtN%zSstKBQZS6jk9PJU3gNCBA?s=ZD8pF{2SHjOPU zZSNOL(k31kB6|~zNg&JDiwQ2K|`%0uiJ4xhVi^w~$D5t!EJ8Ba+%7X*jlS$Z+ zhR2BS$8wZErOt=pTJMH3KAJ9FCXoUirMfnSf?7Rv?$pVyV#fd{k_&A3Xp@Z^H8dMG z$DdKr2P|_R&-~LCR-A6#)1-ju zl+TqxVswm|oa397#l?ip72ws|7IkGSy30z z)hF_~n`D%ZTLxwfT4g6n?#BkZBIA4U{AiLI^9-opn zP5JPjQo;rUrsNH2h|!})o2pM28QuL-W%X^I8(Rv?J`hqCbLY;r4KislE|w@!LPpDf zwEpe$z}U(yOQlPdm66mrT(qYjyV)zJCNr4c4S0}}ccWgR` zOTy-Y^DDScog*r1G-_GQM+_Fp_Z85mG*!_-~dS9s8bA({gJxvaEmO$7*FfrGYuim}-sVzB^WPMjQ<47MzoEVQq!U4%G)*#?QnUmx2 zOB!I962b+Y10^~_<__ky$w0yM#U4-;0w*Sj7NmYDFXX!wL#h@q>sm% zJag03{W5e*dmlG`ytRGuM<4pP2>*|CTNN8~ABOpZ=qu7>sD+^|aGmwF z*W4hobf_C9+df=njiXILniVZt#I2L+^Nf6B2~vgS>IOSFc`uoiw~mogABfJjbP0{V-NA{vtWz>&IRm=Re@eny=&2 zPn#{7aZ+tYO&Nk*6>nn>WdWn(A#4u6)_anv#(^hNWsizbYt^ca`rBvjQITGdmz0(M zgN?@n2U43v;+wK{M12-lyYA7wr>;J~NVl~uH!}jnMH#%qABPkVRj;M1?M3Kn-9hcSFm^{lfvlz#5~!? z5dn0Zgw4Ip3%aXh@8ym0D5NkzPoNzf0JF2P)d_+jY>m zQBbO}AF1DVvT@Q1n8-gINY(BXk*b;Z#h>o1i*tzZ_)TlGO@|RSNZ8z2KcBm6=(ip5jC0`k%OPXXGY2hqpU&EB?d^;_aqhvEMcvt#=5RZ=?RCAl*4yk2 zM&fQdqO8lJn?7F|@tga6HsicSX?31i(m-V|%A$Pja_dFHMYqw2ugLm@wGQ(<#^$Tt zRn2aGqm6=XZ~=j1Awatdgbls@1UL^SConCVKcxv+H!sMJ3yZ*4UwPTY{1HLNegit} zY^=COmJ?kz{B+zdojXf4>2_@ZHn^9hf`eafjX+QPBK^Jh-ut%rW1`~^!lX@`_GaIJ z4HegZ=gFPRPD+awEuoX6nOf*~Hor_pOnB9G`hHcAs{jB%07*naRNCd4p6;7(Kevs^ zsy|k1AtdHsDi>wSoF&oi8AiM?f#H|{TeN7dO>-j|$CRPfS+gu(mtJ~_RB>*!>pamV z|Lymc67{QVh?S{Ge(u{KQ?X@m5GNpOHGi@20JUr!J=y?ga>(`Rs9Y~nU- zeB6|W%_{YC^Ub$uVZL5CseYu#PyJ9g)X_WdyldrQ0QPzFgbf>s+k`RKen(&H?bA4w zKm7y*VZ-VCAAhV;yDs47y!pD?-U8XssVph0t0jfCSXa^3HzSUehrtC2oB9#~9Xf1) zPE&_lTlW(b?YBjXHtGY@tevum^X~{xzd$nMYKdC2(0cFv4@`ZHw(Rj`k>m-R`&*RM zB)doY%$aS0h3@&8|H>wD)?6~Ax7&?vzgRa!MK&hHAMHr@lIywUsf6M_=$8DrRTK9< zUA?)_y*gsGq*Ef&I@dm!+uhepHfLmXc=k9MAmw;0-d!RB=Khu?jhMmcuo)rL#LnWQ z=wr94heXxKjT>nv!#*SA7aKOcd-a!! zr}~vnys0Pp0R4xnqi?+N7WJFus`Ke4@pJPnw@8)YJonSjKiKVXUX{+rncPpx!iJ$! zr>`{L5}=TP*uCv?Xqdnml>D-6%xgX7dLbTSq7UJ9ca}^(?Ng z&YUTu)RE4YdPHU2%(qGe#}hWbktY`YqehMv;ju=NL7!;+`&|ZHvznUHx#w2U^}*j- zdARWkN1KHhVgtQl!)k3@z7R3J%w^7!+1(`RiSy38Q1(>jsy{SKAceq_Yq+~~>Fzem zP7Ma(x!$*=q#*9s3HHxF&ogxxBWff91|Cp+BQk38eCN2Vv$k{ zjg-d_E%r`OiSpw$)*gdzK$ z-Fs;Rg38xE`@LMG5PdkhPg|g5{Nvj{B*w&vQ$U|9tg> z0RskG8~9Ab`%<-+3>h=14_+hk<5EcteP`o05)zb&@r}jz>{)MVo?56m?o-Eg*AQ^m zTywR%5|lf|~#+!x;uc4`i;ED~yxREFtGbLPx;Km7QU5k=gf^UE*uM51Oln{usM zH8)8mKPKEFRpR#TJBkd-CerUqwWEzval2e;EL7h-Lu12Ut5XOY`Wxw*4{_^F^OJe91VgHKOCQln_1)+51 zmDlJ1s+AGFjO%mMcISTjnfhns<~Z`lAytzm%{A_1l#Q!dhA(Rb4DnuiX(el8HEY$h zK4(~qR{wkw`idxDb>EJRH>rARat#wq2{LsCY9vph=K(Rx(`3lO_(c1 z;(zk7g&~bAMR;Cz+2y+Vag9lQFa{78ZJBY8OA#=>{np!a+&5o;V}vE-+ixNdQl;Vw z_%d4KwXt=Lub-+_tGae=pH}^3J*<9y{dJMbm{rDk_lmI5wcct!zJBUT?X7X+mR3LS zzyG$iXX@eH^Uk&UiA$5(T`9Xel%I5xTR(|)F~ZYtSv$>oeU=D|%vw)ok#o z{*Vm91{LQozW7{odV>TBHS%F9;xbzQ?Kj^^s=B4M9pd%3L~Y-`$qow{^A_g>N%Mmz8hT$uiIhcpw@Ze6(>SgaUm*#X zQLUHTwcZ#VzV-oKR?sZohE2(IQVTERwu%_xmZ)ecWH3Z>6UjK*E;pW`-pnm+zWsZg z`J_zXaqWY-T(t%zOr42*A=MHqA%p)yrP8@4dX$l*b2|6!ha23|AGW#dxzoCTt32Cf zPoov!40XSnelkF-H(tc);NZh~~>*#J?|Yy-*Pc@k-C(4dhkq(y!tOj?`xwr}66h5e^?I{c>=e1!3X z2@_qz1`XZS+7PiYB(^{Q+^F)+GVymd)u~d&nau=Fk^BIT6wE#M-eV_|nKDY^V()HU z?>XBRPA|SN-3%yqkPQtc0Kb4CPlzf*0OZV>#}>a}v*WMrMijjK@=JCb1mq6SeOkw= zLSGjAg9Ek^nl)=-s$7Ex53&VG^n@K7AK{Tkpnk5s=DI}dXQo8mIVHodPtPwB5P!a^ z%2hhy)-|S*h+>oE{lunqs{QsD*QgP>)_a6b9$DbsRqbADLu}A~{dI|mg^?ybK$$5U zb^7qb4{P&ypNO$(rfR`E?{1bDd5s#i-23mp;|A%3llBsg3E|lYHfh{UZD)_#<|x}t z6W;q%b;eJqnWZmX#Jx574_mlgd3OPqF>@M`IS1UjRXg2V6IYudyJ&*N=fi)hyV<0F z(e-&;R!O}et+QDK(9p(<+@4)*0(FzYtvTE+wF|rVrv2eQcu_a{L=iUUU6I9AeYA+K ze%#<*AGOw@5{2V-u_9+?a5q0v&`yB3u5zaqbYHx=UZ*mDxx4BYbMFw}^g}lU5sorK zbUgq3bHaw(of_Jv#McLYq8W=$=w&k|9A!STpx?6PG`UB7;POiGW9D5u@n$ZD)QdF9oaB0i=hWPt_rbu!l4 zxKUG)4`}QW3XV{2gW~3aIK^*x* zs^iHg>L|>)cA^VO&sfB!<)@#&H%W;lOO_rsrcpl+KV025Jlq(AAzMf{KfXUwtCmha zE4lsy`nV52{Lu12dW3@rqD;AR=QAk*#`m}1dD~4={X_25sT(2KJEenME~YZ~HJd|hKu7E5sCRXsF;)_OY}m*jdAe1bXw=2>MlK!DH zVB2lOhP5W)iF6r@AlfO!&y!Eqk#xbotbV|Qac<|Xoo=DpD3UCGeghZMU`}YOYnjWG z(FtspY-%^@71uuNZ?x-?$`>RXc_9qtq7AW5xbNQkb>mQ8Nm#_$Ni{}u`}glJNyUeB zo7k0-z8PoI6&^prB1LxJ{r9PU@@YfG#`H(2Y4tXnam@YLtV5zRy5B)0+^u#{pioiA zmGFutzE0O^F8)yCsxXVsn@{UlpX3GHAgucJ9Uy7G|Cmv1h!1WOLn>_0kOA(8?|-n( zFj6L8iTD^ke3;<|cC=Acy-*p-m#>gXEs-wc(Z-GICAIXv)F+>_-yUn~=i-Ylj$kb^ z5!*r3=Mrs##!IpWH7(+$Jp8eqXw$lt`rLUIhVgK}aHC%@S-Qw>pdt))?J=N!ZqvL| zy?PC`i2_!4kO<#>_l=E(uoR%J0>hC%5W{bm-TNgX71IS2=b| zYN~usH%XZpe{g!v-5^Ojsm_Tep5nHVc1r&q(UfOQ6uM=x@V@4b!`y)n5BqJ77$J z4Cj`pufO@yy(6iu+K)c&vg_7QmD1L|Q>IL^F@!u&pEy2|cIw=zlhkegW%WRPa&W+5 zTJ748=~tmXt36B zIc!}rNQS>@Cq7U3H4J3K=25BiEY{}#%eOYTn`#!e+m|3r)~(v*KAy2gWQmN*3u+HH zeez#dpW&{$FTcxOAcG`tBxSqnfLr*@W*y3`apfyzHCrunCarXzzNU4y)(>i~rjmWX zBs`G*9re^QJ);#Q?kFD)6`m^hE^6l!atYn z_-Oqm=_N>_esvZdhNq@bcXy+Lu3W_&S|i38iMIIr&F=jd*12mR%BQtoI#VS>b)NbG zZ_+yJqD&&h^17ljq?|reWL{%^Ng9j3-6~r`>vb@AB9t}keMlNJq~@IrsT&;7AY5Z+b1w&;`D)fo8}ChNW>i-SYo0S53Np}tIR_Ztm4 zfCTA)6s3i$-eT6&H!ZuCoEaVTbglEs;P3-j3Ax(B97p_#H#<%6^pZ7_OGd1^6ip^# zFc=lKByY}Ur{n%-BJHFoBnfOC&4_cCCJkJx{3;aX{!i9eK#vrYyu$HEj}-kzglVbA zQPE8Q(U7tJ194lT_Tb*cUtBBm35b@@SSv{>t*l$*$294C0OmpQpSr_GmvR4Ma^&Ae z?Tf$bk9iZ$KAyEt{GI*VlN!dtGKH=%DO_RrWs5mSX?ezaEBSj;7vA4?TbK1u(G4KTk;!q>9}i{c zwDP}(0B}aQ27^-)sU!Pm~U~4iN6wXwInv!uij|t#rhjn9~STo0Scxj2wWH{cj$~y#zmuGh$D-xcg2mVv!U)cc2ceClX zkMX1=09OKs$XF;k{IV@Ie0tUB{%H6?Nv%AQjm1JWRIX*j3MV;?l0F`XUCd!j>_~`~ zs~(3r!4C<-4L2!g#*Pu2Nqv1qqK3S?lY6`J+n|bg3v;z5@6Me;MA}&t3f}6P#OV9W z&fg&O%e(|w2hE$DmL()+Ff-lBts#ey?p%7uv^64E&lojYM=bX$*82y)zuK;xWMp}w z5#zr;Jeen>xx#?Hq^GCjZ&Q;M1x@l(`+R+>Q#~BQJm%>b5zijD_t`EH6}c~xXcIBH znN{74s+^WE9ZqZxr55`k>l5WB%HH^(ew{1t7uy_hOL?WS$j?5HN1U_yPpJ$0<5>`Y zIeo3-nA$xyt%A-|e0#J}kk8vLA#&zQdxXu?i=DmP4z2sB#(n2Z`SfX<)19b%om3I3 zAHkcKxH|W;g$Au`cVh`tli8?$5>sHSiD4haBn>d0_i2}u2Cjl9T5r`th*np{Yb;g& zh=DbnvKq9(a96r6L>=nQ#gr`qfiB+vwUhnr=CbdfKr7TJ14kYGR5F>Yp#6({>cz1a z3H?R91hARqN%k$K*x0clhx}(;s&)+?$ciM4>+^1*Wb!XV0j ziYAU?v^kmstdQ2*u`&u*{2JEox`^vw`Vr(8`IEN5AxEtaVx+JOaCjCDtloU z*?qPn3tajwMpTfuph7Dc_J~P%UgKrR&kMVv&?g^?wjZDfm-&!rXb#Lw-5C2?N`#(%eaSj5)t%~sC1#0#8>nH4 zS43^D_?{SjDah1>G{y&8BCaDwW+?6RJ~Dx{Pwd--(AqR;&`0?)%$Ph@m6r|hDRz%Q zd#TpT>`*keXojx4=;cxP@j>)#w}0>TIs!%kQJ>2XMiHaeI!`dFU zJ!5bi@(KTn-db?ukTCeNGrA>KX#8AT_jKuB0KQzu;Vsh@VUkzSbV^X~r^OA6i&D)c z+w20qjlJy~R_>5OJB{C<)+Q|45p($%iU!ERJiFpWB}hvQNtn#Y;?mRHpBAQ&!%xPLebg0E+=xaaCcbTh^HV zmnSRKG8jB78EeW4Bz`0z-&b0bOQb$-z1G^+|2GU~Wfzad`-6CGSn}QJvbC9SeMGdk z**BcRMtWN=-)m=oUrsLjTI8zNztr`t^R&7NoluCv4x^iRml@_fy!_`6F@c^n7bo8eeE@s}3+Y((|dY|5bBZ17TiWoo9d>OV!&{K)Wx zP2Df;aly=qaBJ>C`Rjhq8pArSKRayD-uhl2u*5%LWs1UPLMm*utAy_5k3q+>?iI16 z{$+1MMb%5y>$5}$RO zDB<5#qj*5`XQWK=rL4=riITv<`ESk6=WPd~N8_alf1$iM+A&dz>{okDGr+SwQJ4uY z!f@u!FoNk^crtNRjub*CIJTc0`?n0sgD0M%yp-RH@O`?7L09`9?VbeGxmey52B|CE zB?J#=tam__A5TRNoXgLG0&R?M4`!tX$rw#w(|R7q%5F5WEE?*slMl1&f#g)sr4KgK z1x<4nwL+iOUPt07lQgY)kMA>0>cwu4k*RBJGG8HgDQcU!#ru#>RylC1+nf5VYcLT(##N-B46rr7FjfWO++&UI2m$$vI;TqqkUNlAas5r)HRB#7($erVYJZn(_1l>-lI@HD5hAfsIa>bYC zj&(*}n}2i=FR)V8VQY&Mt2cEl{RR#j|S>zaPs z6`CG_h*3%l2jJ%atq_ai_w1OwBwW`9HbN`XRw++CTW!&ndLkkWeBEG;|%M%fd(V6 z)W=BW`|G1;Qjo*p#jph9BQosbaB!ufaM7<4AUe6FtlLzguD?i8;YsKZ@`}BSW@X?c zM5l0AeEf=a>9-(D1gVzY20n1Lt4R9gc;9&nE@D``$u`MPzy~cnlrIi{jfGu}5H7kZ zuokuf+AN$(I>E!e4-60&r=Y<6uYU#ZfBoucOO1(?nTPFW+cFj3@&ET1|9L}JC=vpQ z4wJXkqya-3{l7l#|MzmeKzua>@NKyb)&hUtw@&D&8_5W^KvzUQz z9w54}_2OmWPJ!PzokK3da5(Noq1jIf#!xYeUvz=-bq_;S0J)ujD8)=ROy1CXsJz7+ zJiYN5*LB>3<4bOWx5(!l#0OR9Zr`^?=hviT23iZ`yWiN2zcvGUH)R9rX7^q7;YlJd ztj%l>OT!#LZT|1w5)<>$in=$$8U~X)KPEnR42ep0e115Cfw@YZg%9>hjBx?yg60Kpkth=5Op5g4G>bfGINZQ}Y{cDH5_qlDY&7;N@c05F|sB zx!UuPH|i@xq&eb+iqH6i3YLL&d@yd zJ0uJ^xHna#yc~lHO-AkK1X%-lKg*GHX_Ux0`xO+8^7=%mUtoQPx$UIezIFG z5ZXq};TUkY{#JS#X8u2JT$U?>&LRwqf<*~0Kn;As$I42OQih2P&VI&RQUYGcKbZDp zGJOZ_JAx1$t`N`>qFzg7<*|7mW9ZEb05DH0)g>BC{&>-PlO*1*)5WYDUVtXP{Y6et z^;ihux=2h^8}?p9d+V*KV=$KeLpA*QtnSaXxpQWN3hrx?H{t91r8m8o4)pd>`_c1> zb{%XKg+JfQmDqrFO6Pl9qw8ynyyQZO8gn1fek&u=gKB#2+cU+0fj$*>#H*MMzmd*? z81Kc9j9l*K?f>=m*+bcH*0MdcTwr7D&FxTQ<^*6J32%nu9M8wn4(bHf3mJO14zOF)mDQsxPw z<01Ck-qJ9M|0fTl#T22SzNb-|BX8<=kRyJMJR_n3+^P!8<4{^tVGHc1@yAjC!f`-! z>+-Y!su0@I-PCK@+gr2T)zLCwXU`!=-DY8D=_9jSKtIfxy(+fY(4d|BytIvY{TF*n zYZsNSGoIYRL{*mLq((>J9lq`WX#&z60VCd>*P&1J5d3pF@d0$jsds&zqo?C3f$DtV zeGgeuEoIzQ?La@lu*zu%%_}*rgA@rV8{~O81B?4205(Lahs3EPJ-@Bcv)dT4JAXCdF`&GK*#+W8S3R?k(=T_W8W7CgW1rFLEy# zk#}Zqwi1(60O^ODzH#n#UJBTyx|3e^5qKe1eezq0ZK%~#>Zb>t9@YX(X|{AA1M9s z{9%2_#eaJe5D>5>duxE`SiI@NQ)FLHsGj2{lQDU(c4MlVSkUF?^8C%z>iOiOVLMVy zNC&j#gR%Ma0dVM#M1s!?O;9aojnS8bHy8_|&{Z60Gh5OWLZeQYg$|Jxz$Wr{QuKe1 z+JsufjkLoY%E8~UtT6dj9n>pG?UD6!swa9hhp)@$=QY#Aup;rgN&-_tRiTTnONo>8 z#MnPP{~P>x^8H#b>h7p}lh_Ay&L$cs(^qUtyNK3{%CyP#Z#zrDXfznSZtA5G{e;>4 zUYkAa*XYDTMMGRS7Xa!nfR^-*Ils~&{eW0OvU+vBN~_-DclS! z&;1(msqKheWijHCX|c?Sx&?+*|5L-@aGxSrs8aqD^aMHJn=Ch5c{gb`U+#GT_Hp9f zG(yTvrjAxc5etq`q2|qU@Cd%KLlf(l$a#cSFO47Rg(t$|>=s2?py4<`-Cyo%(3Nnx>t&L{b&)%H z$T5AS(|w3CqF-4^CO7naATs$#s$VJ!a24DIAE3P5ez3R-zn3L=d4k;aL~t>p`g$`y z?Y=Y5b)+-i4Xb~;hItY3isYv4E?`*Ht`cjN$o^b(SI%s9g*n2w!g_vOnLmnTNw3n< zsU6CmVDQN)L+2~nYLmjyl0*g3Unu|mq;sh%8Nh>nQn`!Go6|Y{OS6M$VWQHdD_Gf_ zRXMBK{fpS?a??bURh|b3iI|nFDIl7~om!m-f~$+fM3_`rw|URKL4I-Pkw^=m_&FhP zK%z|n^nY0Q*la^3{L)Hn-)hu@(h6&}x5bG<`(aAV$($r$uPIg(n;6g-_}TR{VR{DM9;# z8M5?%zhBS4+89E&kJdBxI@VWkeHxv@&7-|Xe~VRV{+a1;V}3Y%C1X9*kf&mpz-7zs zV}0}vyG~h7;ir!}y*PC=o><;iFpi(j_VIErHz##`^Rg&hK9I*rTjBVt&7I9$)|&cO zKYO-R0BL9W!|ZD*^K)+0f8*T$#k@n2)XbA`?TCfv=bYo&s)sYoY}*|+Mj+DJd(~66 z2y=UFbD2kn`L+3Y*bGFT!v^2n#9nWcGG7OYzt`|>I2NM*Ja=U8xsKFtu#B<$=IisL zP^zO`r@TN&)yZ6ly5ptNJ=gEPt%;OZ835?Ku|xWDG^5DoBpr$8v|MlLlGy@qkHTkn zY9yaCHC;tN!rZSPWpnxPX}5(#zs253F%^2;{d%w8w0I{P5j?rp=A!@1rd!ZDn!?;7 z-&Xbb>hbU!pul3>{SqF7XY-ZfhtGD#&zh#$tE!R3jtk&Ff7pgQ9^)-*+RRw)JnJKP_D@I0mw`HS$z&wu2{JqQ{UmuTi#X@1DW~hgN0nv8~JpR+)y4S1UgN z!H2N~u2P{=U$2z>qLFl2Rdj`~KZ_wprFiJ@ZPT%xoS`rS_w^O=2y9xKz{j*qp$D-A zUh61K+_CqVIQ*cg#d3DXj(;yV$@Xk55-!8|#{L#NC?*9%L5JK)&)Lo5BGc8qVNQQM z>rBr#Z8rxZ@lui(WFE#_HrvSORQo=?A>S2t>b_$2M=4UTapIpgb_e1kVJ(`O0) zO#@@XxUm$e!i3{^%d3q7$D1`Z9rr7lYqx}x9VgXY)3C4iD^gwWz>hQD#dbH8hruj? zX2y?FNEw4MnXNKt#BI%IInExNZfPC2Gow|c1pgqsu1oK-zoNHT4Lz%7(a74mG3~QG zde}b<25+vP)+M4}0hF;5)YF#o8MQf+e9GM9v6zYVj?z7IJ`?ShcCu^fFM+nBm!dTqwXomaMUU~7O`V6N0?ojQ_^{JAm`Ce%X`R#*2 zqBd#06zAD67OupD`iiIZoNT~XeoC>!eI=bOBhog#E9se1aR3K}8VpkU4+dG$)2@Ny zl%PxN!?0O%X?6_u<;RGBFFL)%+OGH5r+#W`L7icIXs4#1Vg;LW)gTA?X ztoy}vQL{m;)$Fi4+|DXupv9p$UQ^8LfA7*x<~vF=g}v(U%w`0PhC&@dk4_4OiP92p zuUA73hV%M=h;%=9y{9owE{-UwAmX+z>E`d3zUFMshF>-BrQ?5p<375y$IY$a?x zQ&i`39RVT2D2b42Rr1WLx~0;&fYF-WE~7JVPj`c_ejH3>S3@M{i_fPe6A}Dq0;d+U zodyY0he+E+4(?a&U4lNMc}$9l4Y-}%M~j5X5%D-TUTgmKCl_v&^|XDb5@Sx*#k?)( zW?R!pM`|)P-y@cgo1DAq{~ufepZ%#6meQycFD^E(?%G7Q&>V0d={d6cN8i^4%l(Ph zB_4ZzXG5g;d8v*;uE6sI+>H zZq{pPlB%d9kL^P3^)rWWj^BcAwa0~MMP>tP%OS^TDywtLrc>B}vT1*i9y)IvEF7!& zcB9{gboqEx7`11R;=MpPZqHx>td6UlL1tf9a%cOgfBxqqKx0}EYfwk=F)Q-Udjbw# zj&sd&=cXAM5L@Cxj)>6u;WRaDrtj5&ZrLDma0pwuPb|1=`+C$cj?8bZWz%mj6rHq! z)4B{|f*cj%T&drp$K_aevrHW}JsiNk$WolqRB^4Y;Nly$h--4m< zv<2QlAiR&(kk4FP0|}n{*b-LBF#-%I4P!?A6El63iy_Ti&z`Ty#)Mn^f(!k>E7AW? z2JZNYvX|&|DOfo;KCnOno4SuK#vezN%B1k?vd5c}|5McvV?2!GC#|TapZt80kYuZ0 za`Hr(!f<2l|GKZ~fU|M3lxrMDV~6x}>q*#)7Z6>W(CY4C$9>WD@ZL_LSy6pUh*fXs z=vgKEtIN%mywRxA1M=N&CwBxM%0cbn7vk(^o)!{-_EMv+zR~JaPuz+ zLvF<+seg#L&8t1(uLGR=OezB~w$thS%D&iOx}m=PiWI-CW^?(N!s(Vt-s4*$w_H6p zk#DMEE@jN~f6%~jZ_B3c_H31j>ssx!xz#5d7l=GYhYN~KbQ$jy7)>+4m8+l(@=5_%R!r(B?s!TeBEan5{(#2mA7wXXr?zP{9zuB2Eis+ zi}hMRSKsaA;&>Hl!%$);Oa_{L%D=zp+H_g97&}3Lbvd{UI#YLQP&Kh$HE5J;lKOi4 z-MV(Y0H-Q8wp@Dc@7=l1@8fz4u^GHSO-nC}`a;pmL&`Nu+Oq^)I<$>_mXWeW>gzys zCyP(|+c!~ zRN6>+rmAV`uk~7AX|6aFUY`b~DY#cMri)pc4<9W4RZ!r&IHE5hFn)Ws3 zH^$~DgA^&GEVy~LXUofYM<2!cN$qP@c(%dF#Ea`uvsOz>z;Pb!j%T+M1IX=f8pC?I z-M#fxvEyiOazXQO8e=G}^Mho{9qu17n&$J43;(3>qq(*u*sacJ3f!sE08tvwHOM+N zt-gXo3Y+tVZKd~F(_*E6{NH^4 zNIceaLAP`3$#U{FU8=$B-C;AAyK%lv8u{O=Yd5o0W_bQ(aeK!?(N*#=)iIa<-N~x4 z9TY&U_+6nsqFrp``dRQ(?*FJgsL&$lc)+?|f^w@p>?5Hu8`29UL#j))tD#fVVlR{I zRYSM0wfY78taGLbA*s+fW5=h91m#dh;H43YPBTF>gCY`60^QVV@Wb0COdWi_?)DX0 zt8&ugF>bDuFhKvKp3-5uAO!DL)z<74cxw3ZhnDn$C>&*gf`*{AxVX5%2bAOL54c#k z2~=7iiui1hyFz2tzd9&reU?^RXph>{meBlO#~e-}9dGmj;iczdjgS4It23AefyNQh zsO@25Ec?lF-(tc;^*6g@DEe&oC8Mvblv_m9S$@U8IMI9Sso;>zDP2su>TZZ0VJQ98 zXFVNlJ-(7LV}81hMlvHAHbxTGq#gf&hAl}(Y+e#>+r_yHJx%*R8d4iRPEjvD``_~i zQHGfC8x4+!@X|7EKmXbvt+^iL>T!wY6ej`r4lI?9(0sDcskD7nEc(7WYB4;Ac74Bg zMj5P}LgZECG|9Z1{ULL=$tLGMCXv6c_+OM2PNQve-vc^?4-V?}$vll-A4pFO6sF?I zFlJKrPDvo_0>-OuEENWi8^*9n1Xrrp+nl}sEo7bz(Dl(I#?0o5;y%~%LmBDzic&uDSikxJFu^}4~)#&Xxv5s?S)B8Z4^fF;;1uFvblOF z{hsf%3Vz*bn3>DHV5UoHh9OQddF@UQ-SWDouXbp&Bl*UGHMc(y!lTL?)T6Gd7s{Xs zPm{CfRzB*q54dZ80X4CU<9PJvEU<~^`7zj!oEwQEtO2-fl!`FUt$>R$T0V=}! zAt|3J5MkvDZC`Bc!O_RyU`$XbfznrNGiF2zmWGPtQ1+I71fMKSV8vE$xuzVoy%gC}Gf2s_Ed)=sdOAu4HDgIrIibiY>{ z#C|&waYOI$62Hkypq3d+@C)QSn?$=Lx`fjcw^>%S$8ze5J>f zV=-fw(}cBEd%bwx?0Zg4A@AFeE3#MWLI)X2de7)yzB~K!+O32)oyEj~19Qg~$#!Pn z?+}Y2(3MOjQ|0tOn!6aPblh=OjS2y5g$m%O>HXeq6Crj|UIRJHU;FK+q{qh5& z@%=--beUp$R1kDMEz|qt`$-j4Vijlf#cUrnA}&rlFx7&A+apLuI&ETms}*?h!-NvBq*{};^|%((sv!IQO-BLl&k5Yi_t{XSZ%pCG+Hnne00`-3{BYKp96 zVX<5S==$4PnC4|Zc_=hIF_FVRdQ8fk3L=tjketOb~DZIg+ZhIN2 zUycRo&qepM0uMk3qY2Z<%ZszxO43+xn4Vc1G348QP|fQXUE%7d~HXnI(6PGsf%qe(0 zOW?-hcrGHm_pZ^FbUZ@Ub^~xXC-bgN1|E@7{6#k(Yu6;@|AXWHyLjENK^V^lLhEJJ_!dy2|rq z$Lqr+@Tz_}^a(Nz9f^9)K{y=~b&-uC2ZvY92)3njgi=qLF%&@}GT`fOc- z%av2E*$IHU5s4+&V@K~!%&rF;zC}i>9*R*cby9ebp=9wc$Wa}joMR{kv9Mw-espP&e+JdQtq!3}TOp1a`kOEhM$)Jj+eBke{+kx8WzqxYrUC7M6c% zhkn7lMtOeH`90sJF=BecgxdLc#cpOJFVc$Aihs6>X^jJ|e=ptnq$9m1bcUi0X2yof z|LPy_{50Y9mQ3ikPzE+$cie$EVe--hZd)4A_BaHKg>3vZKX4dwEvQYfimd%D=37jAsNWD1%H5}S2dA^a$RNLGA5HI+qTWg3+%oA~JpuUmOptg~dcBqrK zBGocKOh5iHIb>l%#>)oe5ZUBYNT-l%^lE~AiyR!o%aj)q2Va+uDGS;!r3Kv#JoOjo(DA&4Pg*kF{9G zk1nIB;Jxk|vACrtSZ={WCn>5aAid{2QHLHE|3$IUeAx(vkZYq7JJ{GO)My*%}` zMmtr>QniL(y&`CIvR0VyP-TBYn27Z{*G!~_@z7kqfI{ii>ehWmv)URc)?ztR{^8 zt@x6IuV?Befw%5urRBCU{@f7bD=m8vj6C}$!BrN9o$&(ZcRj>x!$42fZ?b2-03mRG zylx=dFCAQkIhy6KH|U?xaN^+Lz{CAy@>RkOoGg-8_-iXPg|sl_Jh#w6CYlbpjR;aL zOH+-gz2XMseD#U@$5+v8JN8)T>~|ng?N^PTD1?03G9WO-i$!Tp{(IAc!<%zis;S)Tf#%+qBmSA+9fUQR%Lodc zkduuiqGRv6Rd<~7aiYC|o zSPZ3tzcg$TEkl3)6I}5xLCW+3FO1OFB-Kj1g{H_zm0J_Sf%e}aWimbNr8XCij#6Rr zUOXZbTQ9L>!>Xw{pRGHKrIsAg=TWWueNkfKEhz}7khu&PD1*o2^Dnhv4u!mP1dhRI zqlt5b2q4SBF-FI00bS(i>B2$rskqRisrO2YQZ6)$GU1Q_u|KG>JVB&rAgdN^KCb+x;uZeZQZY3-z5#Zc>FA4k zkAz>0uw>wJ)evxc_{b45rh`KR5C+ntOvf5}hGdx2Ht)gR+F^_p=SWHA;6fymJz38- z`SIrX6;MnhuS2AMWx}6oCQE(t#7>$2ZKvx1@Dauq_^+>c044+lXFeIok}D^w%`HDs0xF&Kj!cS zMRu=tINV|Pe-=JxGr=lSXW`b(B;AGE$+eV$oVL3RhCAaKJo9C?H0rwet6%Bc=Ppf2 z-A?A`-TW+;>n}~XKb#H6Jo$e+xpEVEOd(Lp$jSr$d?DiRLoI&cWp=jq=~Wxz(3($QDh&(Yp@DL0c?5MEn?bijfKX#HEpTaxsrNidNu>I{6z@;Os$0W~b#tRZVg}*15Q!R{j zLmv~wr@!ckSxBU=ebzxiJzB4D8_i2{f*Q@fslP(dI1q2WKoixVOdi zSF&%+u~65gv|E~OaggO)S*iI=$sI?MFU_*;Qrb3>kk|*cjDmtZLOgtC`T&7N3(o?& zIl)IqYEhP<-Ia7BQ0U#|e5nUJtUQeD8*sPK)8H=*UNsr|?*YYJ2BFnKA-2}3MA=t- z&@TPF?vmD1RKt4d2hK1p1AiZ_jBh&P)p9ZgK1uwyejFs(8zu9mf<4vnc;RXBM$IN(6&bJVJ ztCXAu=3WE|OkLZmO37Us<-f8?Ws!Ww3}-{hX-$6~MrL0Zh66<+h&{$g(F*=PPFXn%bGuz)ZB}t9d1x*DSLrD&8*_dMdKR^R1I6z!&6HsOzTK4nG=-Lt~%W6gtpvDS@8k%P|jo2TUd2*j&}-~ z6Z~T2EbnheJYK7lQzQ1zx9vSr=;LGl^?AqWTs~9wCyjSxQ4BI3Yield8qXsx92iA1 z5sERyJip4nVel*77f3ll)n@~t+U{p7h5KLnDTJ?bl-irY>?J$tzl4-=83WFP_R(MA zr{_i!C@N=S{%}QPUGKpZJLL^X|hG&S}4yvNwjPvF&NirWF`@)Z1Gbc7fQ1Fi(n4fP)M&}|&(86Zy zQuxhvQ+L{bEV*THcf)$46kDeA^6abARr-ACH#}jy>-@A^S;&|}q2_0;PRPA}*%03? z2Y%$q^2;NQx^14z`57JSl0EJ@9rC1SksmNCZ50 z^n}#@=Jmk3*LvSTt8j7N;lCFewdhG?3wp;Ob7%|qpD zF4YGQN=JCVy*_XwaPjT>Iu&lBCImtr;$#WtTDVO=e+r5FBMT%(?qcN~rsC_35wR1bXM)aBT=dNSFQ7{-f*sk<6 zz8ox%6Uj57kZpVnT^OAlWAN07>HNx?!7jRld~MYQJI0&6o#R~hKdL+PfLwZ@W1F%| zQf$z19xF+SwU5lKUVBnscq2teR|&OMTC zkQP7s6m?uVlOJ>>4kBocQU%V0r z^rk#g0@+wDq?e*fG*ss>TDaqjFsH)j6>b!h@uMK~v2-;G+Wnu#%SLqm^)*TW9~qkF zFoantYyQuzx7g+Gsyt`E6DeINJpNnsT>g%*4|D zOS_S_L!RRqOQag~aUh7{@5ibT(QB$P0WdQ7(wULe#l9%4_BX#x;_iD10+e5c@=3Du zHOj(`8gfMK{r8ZAz>}m*a%fZU6|FmIpqZl74{EPRmW5x`0G-q#>JR?14E1Lu4l?Jq z5FHdR+cBg&9O;692gCN;%|z0Eyz#fPPJn+XeRew05MSur{$bXD` z0;kTGDS0H0IoMBD5z%r?!U>itEEHo{9>1Ll3LY$5CMv-?$MDMnA1&jrRz#a)hD~~X zax2`CPZU^9b{70prOpdnUST>=8!5(66_4Sjm?48wVfW#tH%-_vor5(80ZzbSL%6rT z#B|vE^}*?(LG^#FtN$#oFU)Xjo3Nb!9OJ1sma$CUMUWey^3g;x^`8`s==cyt6VTcg zGeU+|3LaI>oP`-G#pG4M)SYDfQocl#o%lyGiFEX@ko%wvf19IuAra=%M1@MRK5y+PTe ztwDm5A5#=*s6*cz90wFHCfz5*w@hKK>G(FHIYRBS!xs-uFq2i0Ya?b){tg})Ip2(< z@V!SwOH)4k&CG1ffYH>0id9r#F0)C_qvVN~C=lV}QpIPS516r25D;)aM3BoxtG`>M z792(=e^Ep~dq8k{M?+gP!8ragHT5)H>F)He+tj{5(eAgD#OY9qC71VHOv+Use+II6k?*5s zYCabI^CBIK^1eU)P?i2`=H+T=E}wPMC4Uy7@R+nEh~ZHw8#M{(Z=}x)yuWSP2j|C2 zHGZWSw9qO#iO+FU;Q5O6Aa`Z8B!-RLuP`td8qbU-ueEEX;d7EL5{Fog#;DbXL1=3? zK?!vORyTyz+Kn`Y=wUvfc9B3zN<#N_KFw1Bnm&PSDyvKM5UXqtic z%R>}X7KX`4#HM8n0%j2&?+hac=t&4}=;ZuzVMoe?NhBm6kGw9a?>eh>@3%aV<~}1l zb)g~Lo;wN(2NCgN`7Pas&2DK+W}{1j>DZd_|3<;vp7WzX19k9U0~|#SU6d`P+6gNj z+;(-9lu*O7A{26NLytZx&(-gEM12LiJf8ji&82|H>di^8klFK7DNCCs;K}D(sk`Bv zfGkg@O5W=!d`$wwwb|eorMmF;S%T@wdh<5%?!MQRri(mF2X9VNht4o+K+bOwjNql# zJd8}6^ov^)$x?8HD1feaZQ{lRj3j^in;UTGX#M&*FgFnyY5k>{MEuzXTkg8#%RWp` zm`Hgw^fcJ!f=g97U!kSH;r*=4^Zo_iZ?CiDUT>02q^Ww4;`7nBbhC*&$u~|kOqo~7 zN8KkkFrom0dh(7V&%VjUhF_7+)#yKp7FwmO)Dxm&v!}Xne|NDlc&o{rV!!Q-kqYv9E}i9FyxzA-&eSBdVldE^?I5`BNBA|pIADL&1DPb`t?VSM z=K~AaZ6sXpbaQrc47BDgITUXulX#W!vpQkb{xuCcF(uzdJlcqke}D)MjtiBaqf3|K zkqEy^#=bH3Icst(ioRl0*HM1h2o18b4X8sC6n%V+XcI;(=~G3F;8-}?CqvF`wiB{R zE^Xu|-S2uL7N?)j^=rn~Ge6VZ8LA3QUa?#Je+*oP4ZXLAwS8|x zk^656HMnh&@^?#8hEvFI<_N6S=fF$o+ zqVV}|!uskZ!Xv}~Mb%eD#kB?7B8__kK^pfETpD+G4elr_>><_3@$|b~XG>6)S$}I=+sfqw z8vMxOKJDl8(JlU!)mQ>=jm0ktPr)T;ZIU5Vx^PVAlX}_6=3A)n6oqPd9%T!*zni}< zewBj?TWWYqN)r9_+;GjVS5wJ;{m+B#^cTSuDUCZ$DKeX2l*(^?lBTS+HlnP@?Twf= zFA2JzQFqpfc8b>YU>(hnON!u68^IC_ZTUM`Zv>56y*YWQ*P1xT1D}G|X5I(_awA>i z-c_U9Uk44^|7-|GPw(h_M F>Lg?{(o?b1seGawi8J`M;0~YuN*9}y4P!D*>g=Er zglBJ4X@p7>x`PgQN1<$+>toZfV|&lf$h1dqhJ7YD?27H)p7K%)x%;(Orig7CM6?>2%;ACEj}*r@SIu$DnRioAOQnT3xaQOOlCT9nhz zhJtvWaRI2EVct;N>@n>6g1ln;X&e6C^#RdY0Ow?hr{Tpn)RB<6LI1jObM;nljoa~n zbP27muzMyXUMUP@hYyLp`S7~jn{dPkJcL*0_uMW*Ivc(yNsv#HS)!Cqft&m33j=5% zF>?E0_6y3?C-#WYk0%F{v@l|Xn$7ls#Ntj%`r##mkk{|9i8i%UCcUbJ*2k-Zh!k!b zc~LwU2bVg>d6P&Mi$Ny2ZychKo-dWG5<>T#nU^#PgtQkcs(RM?JLWSVMg8s+%aS;6 z9)EoHto^`kJF5Qtk`8XkB^YEHr**y)uk?dUx3tLA0ddkr@g4rb_MO=UHxQi6$harG zWt1ISYSXv(rb$ZZmRvQwl2!vPXrCkjxQQ>ECjy~VF3Zb0YzEM@%wa+11hNtL(MS2vWg>xq4S5|4M~@7K1wVqW8b>u`VL>=#pXb&xm?;MgN<1Ib6f{+8FzV(QH8q z^U^mY?@+HiGK5Y3CmJnlbkGh&Eg&d3dd|xm;n*DYLXN87ObHY+3b72>^{uO<=&f2#l%Oe z{WdsRr$_X4%f0i+bX;c@asO_5?{MAdj}{JY!s%HtXm#E;I1}AE#eaR3mC1-(}Mv`s~i5a7zZETbt6mi^*JpE z=X!=<=_5LeUJ@3%NfmsD4aX|KMyD6%a#(B1+?v+C!z$Bip~x+X6Sw;j>;CL_eX#RR z$X7ufV?*Qy%pVrZkBc_&ZaxT}DsYheN)KWLwfa9Fu{Ltlpx=pm7qRoD@(u7ws zv2sye!knQZiK>UrteSCQjpaWYw$I+e6|P;HWLP9CV?7{CEd9N?5@+yj-eJ1&PvHRm z3UTc#jA8;FGv+7mcmkG0{GeXb8mAu0vrD=6!X03WfUO$F+Y#*AFBwq+AFV<$=oxu@ zh;y%ZXHm9(5=MmeE`48op#OGemC8JO{+)1sNA{jQfmMtWP+bcu9!D$lwKdUyUY5{5 z7ZZk;dmlv;H2d1_S$FvQ`wp)hJy8y`?&mB+_aN`Plhh9!$C4>urX~%3->2Sh?N&Y~ zbilpG9O?dU9KhL~MVVmQj&-vofnQqS>GRF*cA(=7Aw2l((H157A~<6#TL@)R16^sp zBI4}w@metKDTbg%adYVT11^|^e7ohiT?_irVOB`uyAj2g)v$)lT!Vs)he0{8OLR5jAlztD1 z4nrJyVjA3G-JA7P&Wfqcl0!7I5sOXs+=~wdvTq94j@2L@B&hAzV(R!-J=PA3b+9=v z8Aq*O*MGe{NoO^bHSxRTopsJPJGzr9XhPrNLpplAzoKoPc1JzzTW|Gj@E$Nv}5>j){NF#e4Kn**UlKOBQ&7SgL{sj+%*R^-->rLuS5EN*=V>ib z%s&2U(GF_8I=XmO{P!I^f`>;KJJeM~txM-dZns|OcN60IJtb*s z#JM{y&ro}puwLk(+MA}~CwE_Y!K8BZ3M9J?^)C_FpLKm}BHRzbIpVYA|Zi*cBW6*(XH{;G*kanp3R;apd| zeO<}g$Nnl(#NG-E6fwGl%J3VBJEV%b8Yo%ndcG%8b|p^~Z?>-R`f7Iv2y$1en2%}x z=8>&xG<(-tQ$8%T<1+_+_Wq#X9VRNCE0@A_C+rH+L3i_QK3X+9BSms=XL7yat7z?K zJS-0;MUERp%Y%t1Zg{e9KX|EnQ#^Cl*rzZikv^r+A0PogBufT8m&bM7)fP0wD3#Nq z8*pCOOJQZgxZ)ILT!$~1|Cs)CLv2KE`Xy#P1I6?$$L{w;F)E{K<<4E~BJJwOnUSHW z^O1ALIDN1n5d(`28#!$)S-FDxm?i12_q$AY62R{P0Zz0P0g4c%?rPUn5u7i@&y=~%!{&F zjpdze?IZ`Ze-lppUS*Ob0P*l9X^7sHmuv#puw8{CaNiFLE{i-m(UFLE<;?4+WubcR z&p=D$#q5Y$F||6|-v!-rPg^JM=Uv8@ z+1_!FXN{?wV_xL4rlkejzkhu{O|~3+a$Rxvug2t!0RkBY(J7b_(YNJICH0ll&5zr~A2))DwHzBye0oe?8Rdo48dFmLx{cC(4F%KYrQk z)0N&cX^itsr_&o-QvB!YP;LPSc&-oS5N~5I$X^-?aU1c@qhlDUFS_RsOlVcm{xiSq zjSr|&Iw%xm=dA3L8-j5?oh29V!**gp0m(n5X#M>Fu1e7TJpu&xgySUY;(iS^YuZ{o zh+F=I5ayd$@#)QI>MkQ+o$^y`d#?O%tWk?;prPDFge4ae&6e(9@=)&98$BNv<)p1b zWL^2}C6R@;1TN^^f?cjHdd30Lef~sk@RKmqo!Zmh9tWrG8+*W75^Q=MbTXbT{$-hl zS?N)s$5cA!R7PmLTCs3DbI|55F(P~aljbkOdFiWKSr|j93co4J*)>VhS1-rOTkZ#X zdzre#wTMkD$uHa{J4^#+N%Lt}VP_2a3nzB=t&G`j4?ZOfFB%VL!!L~f!3M15A- z3o_4Hd2%&roHEAq9*CQt?tiYGg_&CZBsZ7B%0|N<=r*#Ai+eT9E%SL`c3}MEsiooM zVd#5Jt0R5~H@$Ayt)0bmy(3=&3SVb{3Mk|5A)o(S!#m#M$L0F20GE08dCIvg%{(Lj z=jF%C+wqqB+ws%)?zcXyBG!6rt;Q8%6{61~w{3Qlg^H!>h)Dy=55<)^%~Twl;k~bh z)PMuV^UB^B9qB^HzlX-pCeA)<-!_Y9IHl8`G169PXkqb9y_a$D*h*3umvsRBq+CG> z7^+)|_r&{iehu0xi12LW=1?>6j)ml(24EnyD;rIxA2wzG$LuO70;0(5o)?-+Is2qO zXQdmZ@_P1s1XV?C%-tWDD>UC+Rc8dUG-pa{xSa3OLVUN|-X-j^P(${5O0J|X&9cR` zU$C2uwdfa(X9KNm1YB? z1zdZVfB-98gn2CRtqs@)3WljDG)2##&Z((H-MJDQel@u4yo*nn78-b9@2Jru{+yGA zW8Y?a#w*v}Eg;cd;&<=G5gGLw3v>sx5L~{FTPhs1jl@vV-@_H*8>wRGDL#YU!Gy)R z8EG^%R)Pfo;M*B&mhfIJ^VjoW%R#Z7YpN+- zn3`Y0BrMBS#$k70SWNR=87KmKa`Bz&wLnAid5TRC9lpJ@_0azo&;O@}4)q{`ZyZpH ztQwL$XN>phVvJ0OgGV$I&Z}#R)1tHVesrORH2vy(4g^cAl~JfZki(kQd()sXJ4$gt z;_2qV_XC$!H@0!=gKX*q7K8_h{2?jWVO>0tPwfP+bfohVwD^}W<(6W+&tZqCXhu$d zTOG)cA~_77cybja9|<5A%-zN-sw{s>3J<|j;fKkT!kDCv%tZN&$)jq?866MGmiWF} z|DbSSo4Cd(Vib6mxBohD_9+H#H1l`cwaF!~4#HRv$?K?qCRjrTk#X@k)Mixjav<5A z^`$9RmOz1tS^%S@e+=L8@Ku6z&EG;xm?L??9O-U|2SS4fW*K0mT$NwjyG}s`&Gu3w z4>>G&tL41x^$v<@{GlD2+1Wqcf^0|*UndpJb>Kf(v(6AhI@qKhzgI3?bM?Ob z9OEfC!dCO)qDOocjzH&86vcaa>RWK<4+ihN*g+tz!;b{@q4xFluaVdsz}>Y|8>iylR{hAAVX9yx4s& zVuUe+>XAibgz=!-owO4~H>xQVpWJf>F~JzB7x=n+^p@{ygueg3h1|h%SlI-o!)|jG zG@=>##UcNK;rH`}VPM87YL;|&SO_-v8fFCOcpFbZIQX2Ya=^fl85KltK_%>+gMpUS z`PP5x8#kt0jVUIIc1$YwT-cw1`uDLX8A?iu# z1nS?|O3^yiDpEZ}tkYJ5&#i@@#%^U}GM5b2-X>)l(XLBdkUOkVwPCWd{zo%IjIc|I zuq4Ewwt$Nx+H@5`v?${C#fLcr>-bZpIwiOX2aP!18ZC*OV%MEHB$hi;5H<~`z*24; z#XQBY{*5!WIyQn8lC;y1okXHz_s4T5r-frE$mgC80al;iJh>FF*;yARI!$VAx)u+s zl=-@_@^^WO12E$F`>y+;x#sAT}nLZXi<#t z!)zdgPw?a4Tx9rFH81!3QghA;#KE0*H|KACUIXQ+4g+y6`$nheMq-5!PO z4g;&)jmvE%d==pB-eJcD|A?&;P-FP!$?b$1f)OpdSd1k$?1Y-bjIi#Qa7kkB@wwE% z=U*p)Rr4tk6i~DA2Rhr-wZgJE4%GnNvVMyv?>3?{FZ0}a;q$->74Hq!41RBsf^(5a z70^J|&hl$bx|&!ZdT;rAI|_#dV)NwNlF#)w%G9_DdSnmxs<-Pbo@wt(T&wSi5o{5l z@(1Jc)7;S3<(|Lsr4|R8f|d=3RwN3^nZuM%hwZR!2bi`^{sbVO9T9?smP%DES>;Ng z&?7sJqFfkLC2(((TF<0Ki>qM9)6JlTQ^qTbPmOE;nCYd$Kq~I|`G1Ad|ErfKi4YIN z1(T{oSt$o5Ky|Qtq^wUDGV>X*)k-p}1iCoXsO+?rkSQ6BdKpEw?MJ=mTaQ(v!-x|P zCr?(XrEwLg?y5MGOEGigbY=xY#Oa`usM#KNfnQ(QvLg6DYg8nb7;h$2{iiE3CI*1v zg-OP5IC!ZfdYCLoqTE>=<=QN4<)E5bB|&JipjE?5=Q5?bkg#M< zu0aK9=lRq_Mxzuaj*1|=5YlOm64pr~MK!g^eU!zG+_60PAG={gFM!~DE8tKDT;itv z%*h*MAb5;UvEB}jvffgBn#o+sDJvfttNj(praajWddt|RbT%sa=mJ8U3i&VFre`nV@7Jw+KUf#pHfIkbGF3=dpBFF<`YNJ{TkYMx9U zGRjN~iKwBM>WmM>1N-wFwotp;;8uCQwQ+4|fyvwdzsfz3Iw2GH1RqQ`1LR;I@b2JD zSDl^}VLox<_^kkj_g~UNxTZtu8lE0eGuCdd{FMol~>RVnml*6!(ltK2}ZpUlKsn#H5Q13{3EliO>$8(gw;QrzK~ zN)aRnCo^F~>7}Ru@c0x`YgLF+Yjw0{i@cx6En1*|Z-q=Cv^ZqcP0dmkji}z`EOeLQ zd4txB2dB;{W&U)KI6fZ@ms`3w@A(1`OlPT@@Bz(DvOEPxrSt;B(^dE=Te{l@DF>UK z?^92v`@TVu8WGGxbJ(oDnn+Q-L}*w^vaqoI+h;fc!T?Fs?BVq{H+ozlu~{M?LaHQk zaalDT*Agu`3=xnU1WsB$}KS|1bgrVz{IUL zdfyLGw-7e<=?ryVCh}$zbnp6)9DNvwAI`E2_|C?QIFdn;1((UmZ@?NR?tsg2lr@uY z<@5Ke@QdNW+?Pjj#*Hb*JBxQBnfhnpK%`YPtr-F-?@ShTW>FST?}Xp(C!s6f6}ma7 zX^)TPT(1V6HBT_7H+K_fdHT;z7ECACnc+)#QL0kkFsOOH+ch!r>I zkKIpTuS|)HQ*0=B{t+Pm;!uoA?puT^Ck$z$;0)ZPs8UfE43y~A(?* z<(VC_OFk)3d`a)4Is5xr=p6vo)uO>p8N`7Ic zloj(pC7DUgJh@av>er-NzxQgH?56$v4QiJ7!m+l)0w97!t&Kr^3U_}C4McByA?QPz zC4P#3d&_PnNf<-09fuf#Jv^n%YXac5zNn#RA9kFqxIkh(5 zt}h_^Tx8RanH;f@A)3~{o5y)@DliVVuf3Js!y~WJ+i8H{&(xc!Ah|WBS4APQ4g(2Y z)Na86568FVXj|Jq0%c=&%-i$Bunh7;#?fZ0B4KTFO7QTu5-sG7>*3L%Og?b1FHfTT zaB~Sq$)_t!mDPyK8*Dz{e7m(bx#sq+9Ts{iX3CXqWT;+|noul4lo?MN_urS-7r#yPU4;TL#K_z>KM0YSZ>FL^SSaZr zWcv72&Pj}rrq{@mK{&hdvXL*G3*62^-a-X3SWk&}FHQN)d(Q7H>K~j#Mg>HQ#%sq2 zzh}wx6DiU`-a&p+gYX3QwUf}2KLzEcih%G2p|XifR)ukksu_LF+Hkv!H}d0h4Ul9l zLy3x=EisiA1|P^_)Ze%jCQgGuBDDbEaUI-ck_fh3p+V~2d4`9BdwvdI#5?)F5srr+ zQ1Xps>aQ88V}Xj2sJwL(?}^qY@e*ig_N1by&=)A8)HEhg3JcYI3B;sj004U$asU7j zGVvZClf0OY8W)u})aA)>G)v@tp5GX3tdhsL$aaUqSgwAp&FJCkiqC4}b48}eR-^6n zE$wxp2c_RufG<2Fv1nHIOq<4{+tqWIJsa8NX3@93e9!aquy5@hw}mcOx`GNF-#m7k z*J)*&QI1=dMZAxXocAUQfXQNX6RLon)8xmwZj5hOJ0SXL|A$AMWwnwHXuyj{!K;h_ z|HgSqj4g}9$1}%og0KGkdjmP|cR%|PNv>@o(VXqL46ul5K+bc=bBBSiQTg#f-lahG z+zrCBA8+nU+9Wu%g#Z1Ce*zM7Sw&>?I;Q<}{v@)*g|FlKXL6m?!}GIe#Pc{->T0QN z=lpGl)Z;3(l=fyImNn11+`*#Se#F-1P5%TkpXt-`4YI6<&||&c`nz5V^!<4Obe)-Pj$3V-Y~4UdHSyYjf|f=tpl8X zOfw56-b=@aw06=4sYv8Yh+B=7suu;tqHz^=-B6-(?Wd!HBWN=P%FHaQyY+?aeJL#$ zA~Zx>Y=GR55QYGQ51sPQICk9ZW97mYA%>n?sC@qXXO0(5);sTiKV)(*#~?@WM#y(D z1a6mEqCOlKS}uj)^=!X;;_wS=S%19VtmoCLGWSyH9YgrP^?FxHJ<>hp70w`;22N11J=OKVhhJ+4h619r}zlb))!EC{*%?B^iY zjhV;I3de27E0^QmwAkn{InE&QS4p#w=f?Aat<|w-WuIjg*aa4|bcRUx|SFcirqoCD+;C+>j)P`*9 z;xoCHMFigK{N_S7`18)#e6RlXGI4}9Dzl)`tGtI8LuAv)v-fF=$XIEjNL@&xr|cHd zW{7wL=~_^RyRMhN@DD9y7-wD~fq0~p@luhpqUYK;Xg^Xl%L^FxR zF!1zja($NA`)xtklo#&X6l#d9FuyAar9f5v3nCX|#J`ypS;U}$lQ5>CU>Sox*w6Q7k`@v`MPLRBJO=RhkjBAu7b>HIq5X*)IvyNUa~h=*#`^_;&s^oxFMb4a!UC8W5*rUt*Zfurh)H% z_2~Z|74TRhd*)!@2_;*YMr1D*%Ya>~`V!~;;#3P4QufMe;oAe?!dvL=@)!mi6@IUK zSFP<9ADL{A-t&*+%6JV8l*_z3Ypvtk=eOJTdCrTgo8gu(+`hz<;`JEuSeCSGeRyl} z0qNf_guz0oOeY{)Ered9_VM0K)KV7d1tG-uTUCGxfhPy5H2J;Z>nb$Sk3m?yM1%ZK za)2D^Dhc1(VSTKX5)k%*=F3&~L(ff+RkFDY>LXp?p;K@@PV=wJp1@l?B}Bh)51kM)qNv6)UwsAMv*3CMyQg+W2af_vE$Pd*+|7N z9FZ&fe-H~E2nS_aIBfj{gX^Eq@lgy5;yD_WEQvuAG~_(fvWpMyOvEb1cqp;<-70gY zM^CzzFoY!_9ZndMCaDIj%l2g#V|h{PBasn8w0mLE3n+pyU-7Fv7u-|V)=bJz;2i&@HP(CTDd)@K%~bWsZcPhlK(4WP1qt>2aQfdsf4zz1>s3&bjcM4 zQQ`jy1yD)==}q@C5uK%+qDAS;1#xvKadHHQ<_HEGVG!0kfEb=Ft`t@?fH}pj8~Ad# z$|sNn+{7*{PbC-lKZJ^0)r<;E&V~+#t?Nm6M7rF+Peqi@*RD!b34iT6`B5d)tjM#n zH-ZY^*NA4J6Wd2_k@HuO8UA88Y~W*YkP6e6?}d_a5nSf+*e<${NZGiyL9r16Qw(E6 zw%xNRM?PIU;NRxl;y6S-4UF*U;3J<^{)2WryE-#10!NN7ZKnQTU6L)?|8jk31w#Tp zBrSVyXDoM{@5L1YrWMhovFjYY3Qc#!GJxb%`vqZFzBCvg zf@h_mGXpR!5ToU`Ks&`T{#YaIQ^fpVYk(;ACm4En*~G2BA%<-@QbH%H?^fM03v>mt zN1sOt0H9MjxC2{jRFOzCL~9wO7aDqnX2AuodxsW_O0@_el9;hb3jG-TNg(mq}NE`pG|&~(GrPGB03L3;#p0Z9_zc!q9Ag_Bd zk)!iRvrUatDrgEEQg#aRFrB&>w9rhdy2Rh>g6=O6D5Xn41HTurT3E1cTaN@kC;K&n zl9X{x3r`RXX%-0h$aKU|d4ae|vAwDE8tOV*VoWT!`VZzo7>85NG#I{X_g{c>A=rsl_pmvt%giAgN;*Iz)4s)aiSJ_bs7&CSEt$2l$O@^)W zHxGTM00T_&x64Xg5U#F%j8~@~D-xxr)!gvN;0I`)%|b*5t!F7We-J+{4bJC{ublqz zB9K;A{}RKQRAoJhw}kp{lFeDajPi*$OVC4@52NkLd9i+vXSrD(MObEIYgNHpQ_v+a zigz)L2lE0;!{KTj_Y0&c|6Y<6Tqbm|9*{7d=OY4!rd7}h@aO9awC*^{*@w1?A`2{K z=0!W>P%^xrGgy+r#ylvl-36bBG@M?{a)%j0tYOhDa2|hE1^BF4B_Vz>KmIQMgamxe z*(1Af77oxvAb@C+vLuW90WyrWC>h@+{*%SQq0Ok}H=E%DNGZQ_IVmD#Qw>sK#}$er z*4Dx9jbs!ZTp9v^G%TcZPQ_??w~#>ic6FoAJATq3Ll)wtljR?9m82wxbj+Xspy+26+@G6wSc_ATLEG(bE-sXgp3VMeIdl`S7|LlZ4a(F_B=o_KmcLFeOlKNoVX6qx;=R$+Ij#MBW zh_-=oLHrO-uVVMwx*r3)LF_c8oAps*LxBv7@iN1lmIm`qN)HVo294FBzoZM6J+BqM zK6bK*c@w^22{xUfio{v069bb|aJr|o9IK*(%|?R%^$I71k&3d>@UMT9P(Q{$IC>ov zJ6<(eDe9xpACeJODPHDEOQVeYh6AxTDa~y9sp<=yl_<^L!_$%yRo;zCsEmO|wT$!& z0_us3&L9tiaWHil0<9@DsIioDkFXux+OIo_`7*WiES2fU8)6dh6FWD=)zLd45SVY) z!w3cJ({>(a-SJOG|C@iy=eq!utA5xwK4ZRL7{PwOAZ`bHL?}rwJ6nLHP{;?CO<9>N zv*@7shTX+NGg^Ii=D`RPL_ArH3B4q)-b|{IPG(~+(;pb0_VVti*`7AU^31u(va#P+ z@0g&2{ocDTe6d7RulluMIE>-Q0dF(UL(J6k_vY9_Ee?u3G>3(Ltl3eAjVZ>PL3AdT zcS-KJW>)qoIJ-_aYGdv}nuw+uK_XYFFZj0JeXSnGym@ZDRjv1iDtuM00nZS@p^<}^*?<45q|F z(tbY`zhBJA(+zx}WQjccpA}jW$}|r)>PNS+4cRMA#{dzOPSI%DpA?=+V z8*{NZ9Db_2x{`tD#9)Hna6)CdAzT_Vi&Q@b8G16Qib!}1cq90xn7d=qcu3_ABiCsC z=ow&OvCT)`-nZ<5f&`k_l0c9R42n%$%LFk00k1z6`KK@h z0O-e?g*0i2n65Q{C3AddX;02X*`HipvX2@>_Ohx8b~C2U`|(l2`e9fAVnQ9NlF~th zRGD&hL+v*j!R*-qds@e`{X4&>R`!?tbI3rk&?AhV5szx)gq$C7uuNdKz1 zb#?;fk+QAZ%(&lQLGZNm=So#AgOt3|KG;pLAz&V66g4POa@rXi^b&JHS}Uy%AJ!j+ zTdxo%WsoxR2X5Xi(D9@5tiMtdO&VmYk!B`zJhLtp0^+$zJ?O~+Rw;u<<@3xvaF9St zlrZ{03!@L=!Gu6uguX*k;%om~-l@N%85ITrSbgt`xa|my&t2wyu-&`UrZyv zOA{yBaA;=wRk< zs&aH*nv;BnN7uO#Qo+jz`UEI${xZ|&`@xL647r%>p zw>gU+ElM{*hVTU&^gE7342FP=6pjd*Q`2sFO zT*w->xlA8n0Q4rfnE)n%P)JkR&%3y`nMv|42sn|ejSXf2DW5&!tawniKesoAw+lkc zozFGGam8*Fm*{LR6r8x21VgHo#!e0TUft5?OrOwEqMeujr zI6ZXm*Zb88s!t0xR~+GMh_(bWg9+S0(Mazi9tbH<#}7B?tJeWyZV|h6IEy?wi(<7y zn8iX6hxsQ`kCofqw>{yp3D^GQ4CmAB1r^EY9uxdON_x%XBG~6YT`sjgx=ux5f_i~? zG5{3QK1zH_&1`VQRYIhI|1a&m$}B)H>4n;%E7OnR{(d|QQaZ5;(SCU}{fsIXEOE-=kTEqeX;Y zkG%FEJXJq^#jh(8ddl4581wlt3hOlj!LptUD)iK)?U(4~!zSn4_He~-6GPW^JzFTC zIkvMaekr$Qt7U*?o5IN9M^5Zt|$a~XYsq;VrCM&=_GKe4D07CQ` ze`P*t$AUh%<0YRKN#TV0J{yeHyw+evX}}`>V?7O;1r{!|O->H9IxeW^^JD8z?>nV$ zFLN8_Z2q)&{sHNUmjG$R(gTYVchhHhm4Y)S(t7811{UqBU{SogFb`6N(1;uvNh{-t zk|T#xhqG z@mVQ{@zCD1><52jWwT6he9^Yu5CY2l0?j3lGfzlRAM;|p2?@$ox9hg?K~35~<(F3< z-pQD8vM(H78Ks$f^tpd&d5NJ}^@~ti@GT~kT}1fhTh{9s<3*9)!z?oVe^bK6%)s`A z>udBN9d%&IJ70X_DOGE5o$i844(bQX_s%p7nx$G7c!^Slk{H#f?y_xrpDtNm^b(RS z>LTH4v!vXFH>b{;`W1KZJ1XDo5sNYude169MT@pmi2~{U`wd&AOg;N5`_FcgxRezR z)%z2w7I_DKm8&F(@em%e+gg)0A=Y}uY??^^k|6Xct%JUr3nE*$SMimcZ_3rv;Jb-M zk&(L;?uuflS%c;J1C_W|gRp*oJWY06(;|~&;nD*)G<9*0$+h;DpHG7?F+TM0Z$!qe zCjj@GqPv_qM?M`IUA&wdzO!n8JdA_^bBoJaGfR}&FI9eO3Ju57!=i{KjIa-XmFQxa zGAqbNEk8frU6QTbt#wp2eShvO+3EOCA#cwN;Z8Hp*zB%7)n&M&)>=ee($FtF5(pc$ zo4q{t&FlT!%iTAp)cBDoZ}d%j757&T9jligwlKv= zWPe%;RNuyJ6g{pn#uA!Bz7O<}`7*@yReQJzV=;JqiNIOqc!6O4LQs}itPV$DGiX=_ ztLsa1>rJ-nn(4~Ny?`xVld*QXfRm!5DdyMDw0@EuM$c=M{pwKai+PEf>ZIm=)lKTS zn55fq&QZ4WZr<;{JpwNe$oeEK7la*ir1$|+lh@O=+L9fuDy@>fnNiJQPe4Yr#4D8% z`+a3NlPSCb2_+h>lNRgpY;dkhGU9e}Q#KJOuz zWA%%)Ubt8P-K2X1g!lV){786NPbtfM1OlMgtCb|5tN2n0MO5Z;Nfb`-p%ZrH_HpA$ z70L%VDQzN~_q6EcEUbdoUV6S{Je_*SL>u@_Yk?-XsJCc(WJe_CUFLDpxZofMG8)w# zb4c+2!B0GBVQXFe%S@k)C)#Xt^SjbFG?3;zy&?@&C!16I3xZHcC2@w?IL51ec4#q< z?_rhc~OS|?U5>|6R&HgCC}l9yc`_4|7SUO8eWx~{Q2 zxoXdEm4A?Gxg9#Bukh}_$t0&g#dgwsbz=>_9NpiD_&lPIuK6PR^(EPkt*o_O{b7#G zMT2DC$d?*zR+Ep6tY5{=mSTQ6r`vLM?R+MrT8Oa^Epx-Bo8UokY(wqZ3FTjDi&k}w zXQ}lqul)zhVSnTUq|Hi+WO2FH*xpGhbQrbvni|*ZI*i>)RYX9iYvM|s%9g*|FO8&K zj~~*!33-)p+D1#GClFKOkqBO8mby6#!{bT$SSq$c*ALOx2I8=if^2_EFp|;WE04qC@oqjX{;IL!uQ4)fbPvn1&FvQ_%XsdP#yt;oG zDw;XE*h5?`a-J$ms%l|xdeK8~5D|~1H;gs-;628Gl zkvBM(by(IUqcPMJ8yPQOSQtVQOUjK8_2oP;c7jYR>iMIKs});&i*#jL(%bf>cbj3! zdKrk2Tqs3cqrA&H_uEPu`Mdg7mj6qMpw6`U>=#(A4yf4la^HA8$_3+%gkzJqZ*gzi z%i@VZ?ufdM+%30;{-89aX)&*Je|lo~vqg!Fthti^fGjf1AMa(Zhw*-qdkkw)cRdWd(xF`hf#~m zY_oJ|5WLb3t*4_@GzF=gBUd`V>fS5ZE$;NSvM3mvWtB03?Lbo7>OleG*%E9Aobyy4 z?UZSO{raJ*DN{?@iZF~#iK;H^4cN)x>U1v1;@&uekvGN@AW?jLkzoZWCm5QcuYYH6 z``{46A=~Hu!c@qmBo7$0Qyq|1L@%U=scW2dbM|U9ZUQt0|6UB9)fX3v22q`G{TQiQJCO_zRTo! zJ5+csm?~+`S`DVLlnQ|-lqn_#0AGE1!js024zCp)B=M*^tulpbZNyfum__jYkVD@h=#>Atl3B<8FHd;KvG$8|dQtagN}?t51~YGDw=A$Hmbj zfSwIFuRslB0}>b~yJyf=7(V4!SQGn}6~@8&bRkc+0Rsp60R&%$1xf)Y>JmugK|E0Z z_M(e^ecxc#m(k(;QMM--Pb+NkDaG_*IjnSintA;Q-(8&7Ud1n)? zOMfWxF6fRRUN*Wxs+RP%)c@&;nJCVY-?Y=O;zSJp*jM7#N5pW^n+Kefm6epcrB&sy zXSqnpPrY1F^Ys%GcoSDp`(X`w@9l!S_RshvC~gLvssZ)k59kyc(ErUHVTvuHc8{2Lfwte45J+y(shyxO}@ z5IJeD9b>UP#>b8_XObz+Zg_vO>~kCw||{ZHaWEdK)IjbCbu z0fYJh?Ng4(cZDvtrI=M)2P=gE(rCCiWhgDZgS{aa+^fW1&NnQ4-y^c)$@|eazu)L! z2P@`55L{2|YpR2>zP6*XKL*!c49kETZyvRq=J1dp;Z+1!t z0s|bTv89%4jow@L1cn+oTI@WR^`_LyR8m`agmb8 zPbv*AML#?~|CPIe5boSf)#CFJXIxq1XFbG1$`7+IryI(hwK%9H?{|OJdS@>G+)^WD zzoGZS6Xz%@r)4$|8_KXqj$2Hd;lyoLVkhaoTZi~@fe_Y|RJ&e#7fWIsE~?QK0xf?E z&zjQEJ=Vujd%$vG4ii$X$A`)on6j-fe;rh0X5Jl|^QhGPbb8c4HUuevuR)ILGHvN8 z@d8XR1jurbtx#nO6tK*#Rf_6UdP*4IE57G4L8a!buO#sBj0yie$42-8+22#=#p)O* z2Rdr_X%E?jl}NC_D#M2@#`^F$AWp2lu~E^ogV)%7=t~1j{#`%xSP`9J%QVk}Reozc z`(e~WkKI*^|Hsx_KtI zz|bX)gmiyre7^U2@caL@TrAh(=Dtttv*X&=-e++##+xMpU`S7HB2JuMPkEGx(eZBi zcO<&T@P2;wmuvK1vRQw_+90ZaWz?l$KwC`KwEJ<>V_ndZ^kXs+l*)MwD1HFaXr0OD)`d3O2g6eb?xUBCTA7@hihhE#wN}m z8NZ71k-E`7P~{*iI!Y-VuIJSumt|?N&MH;V)E>GIZ~Nv|ne<5^wRUMKW2lt6Me+nE zRk7py1y_g4D4EDzvqFuk2(tRDn1lEkiwLZjyk|?NX6FQU&x-cA_iqUd!a^~{e80SO z+}njsG5@nbv0}T`vSNqtJ@VZ3{*|EycIXSq9=luAZ)%<&6m43cS1KsetEw@Ae=S$$PT%OY=% z##gq`{F;7dTHnt@JfD3bgj;*sly%X*1FvwSFkcUuL)^e;Rzf`LGV4lj5WWbdW|=Nc z+gD=-g%)I>do(^N3yVBG9>;h{)Xji!Y{d=cS1yD`A>(KE{4ri$?{mfi(xvygsSQ%= zv22&}8l3UX2%_(tNLd;3JktmahA^F%Ud+EmN?8-q5wx(U>d3ICHn~&Qsk`J4J+tl> zlIkxq#5`y`AE#bFi`k;?0&pDrbHN1hH+h9W zqMbjC?I^#q=r~-0#5Qa_q3E;Jnf_*E>g`=u^0NW{EaJUmkI{93v!baO+eXBka&g*G z*zL8JzVr_z`z>0v7O9kN7L7$e4CXm7Y(tpVS_~dy(;312;B8}P6&y`D3xp5Wvp)SK z62-r{vQAPU)!lEE$*8|(EW9?YdJ$BPOLIqS3h>dKcQg_!4BqaTyt`u-xqNyowP2l^ z&{4SS&+FxY&u26>kI7_7bDm^S@PvJ=m<*l%A$vF1%LNZqqnrX?tl5tS&4o%pvNWL6l8kH@Ur`ai(~q{*r!eP z$^Hj$OU&S{M0i(T0I8{b<@4yUFzM}gkCdKvTnf6Zdm25RhkW}n^*iC3%zFI7AK8MW z(b~MS`K(82%;rO2A!yQsana2B+q-OJ&$87f%c=SE;1LTtg?scokC&hacZ#=yj>g}m zRWj@p5$#l_?NuJTzpe^r?xsml5p2QUe}`*mf5hT^!#1-RJ=FQxnB>Mqu))PFJ1!%0 zai_Xuv*58Ag+sS^G{d}{Zx~f4o-H*d-=3V+GfKMd>pwdCIu${ihY1^E3o3=9f!8OR z8xXzDU8!$|P8!Pg-`~CD+5S!|#q{8&xS@@v^K74dqp5+*fF3a#lq}_uYW_-QpAsq&Vc=cQys7SdscZNak@ zbgnJ!&G(wGvkuhTAnsj?wB7^SgBg-8xEOMIKV+~7Q&aG$D2XI*B4k4RNZ;oub>fOy z2q=>)-Uu6+h3`J&!!F9yAk0VzKgg_Ij&$=h*cp7Bl=%6^ONJS`pUM{HKGhYs7CLBJ zG%(f(rM%^DA+O1?Iow!;>bAoQ*2!-2{?25u3OG7qBV~7>#QB6XAaiC?0maOAiHg8} zQ`j`T_%0&(cqM6EygKMY%d0__fevGZBlM}|P$~QisR;KSt`WKMr=z7(m084|12~Su zJnU}dYi1=by)gyvhXrTiOVlD{J=Y=B3s|YPObxf6taRQJbR7B;83DpF5RDc7-XpX7 z>zS zj{km1CX!vg*B@%?GQ$$3mCCDzgvTCBZuAqEMx*hk9z^YD;xbxEay<1-GUSb3Ux~a`G{$f=3DieA|8hx&^elC&nWl;E6A){X1 zJ6PYK%hzwSaYzSJ^3So{4Z<_Yl=_yQ#eHHTYxxOrN@M!|p%#&q@_0kblD+N6O3?O1 z;c0`(^dmjY#5+kTQX;#hRhnP+J<=`Yv}_%94H5^u0xL~0_nkg1a&VL ze46Pdo0sK=eh&@ymO!PnR{O074oweBVS;EufgcAHG}@%S_GH%?CSbjGniEEZFumdN{F zDzcuG_1{PTiWpmp6ErF=eAw7>Oj=LMsd)y>17?ZbbOLRVnu za}14CiAB7}6bv7e=Ga*t%7g^8vKm;+L> z(Xg8E*^ttWl)L1Z@el=e`V%bP8On2`x)W>pqem(;DMwbuBZ5DMDSSr09JW%|P(PEZ zhN$9?%W)lXB6}~oh9wE`N-o%RZ`iN0C6M<$z3Xptji~uDpWLsO7fVm#v>?VURP@L~ z@XU%Z0&)`3WM7G-6^v#vwz%(h5`PirHX`@1v*w#Tt+FsnEj{%!_RJ4UDLH(5YWB}t z-{pk%4qorG2-4E_a$z$oSdQP9MX& z*HtG+!r)GTs#zMbe~i(Kj=;mKqxCx5o_zNJ`8_ zUl9gK$SmLT{x$VH2zT8iD`0q$UiOLdvnra^2O}!6;bT$}9aSGY4i22x9K{eJpGF)m zG%i+XD9RJlNDYk4eXOqAy9*|ALZ2l0rKwQ$-A@}95Z{7$!37STpTH8TzS+~ujYE+c z8C$0p!=mmxpUd9QnQX0?4V8ahOD}9XN)f&5!5);zalw^yCoQdPr>NMmLyIjeKB{Op z&d-71mv*96a!=O5n zwMG9{MJvgEc$lJ|37&gDn(C+8gC8oYaX)_-%SHyf-ZYC5@s&C`o>V&a$7WYpQ$=k^YGd^}b#U84lr3zALlJEsS1! zH$*Fn9wPj4hHx^szO(kqc)X$j07!_czy-nH|!-;r|YVbKf}XD_|} zxgD(o$#URD)I&kJv)-j_GLhK3F?0t#LNRr|%ERqhr0ec@YK^3H+U(JJ_OH#j7GV>>5!`P?xy z={1!NoYI{Y|Ju&t6ao6v>$ruRb8s(j9ZZ~dsC}kr4K#S{3wh)5}u|_JpAJp zF$MOz`k0C(-;6_51b&~I&9749Jrl!gcoK-Q-AOe$JQwbJj2zFrZkZ6dZc7VmK_c! zPRooL>CWv`iJ&S@39YpJbT%Gyw?LFkw!Z-ykLfE~;M;8%)=IDedFJd!VbU$w{^sLl zocL1ea1ReD^hZ0=QMM5(nXUBrk)GTuh3yBY^GzPVBxm~f$-i$$x>%Fg|DI-iJe>nq zIFaVvVp;sjl@MQxM}@1(HvYAubp_^fu_65NwMR!yXP5NsEDPE8qDqXOfTu&zcAVHe zrO=~xYN3;m{y|!I%o!WTkuh3`D3hS|PL9npqvE-ODGz7F%1dGGkd)<4*-sCi%fWc~ z_bWk}(Bx5cy}JJMLsI1Vs|Y75?=hG3Z-1#57q*O&iKzMjed&#s%B%;W7^dY!Wg)oa zBaEk1Co%^2&7KSv&C+7wIdzX$ei-rAy2yqR*#*49qKeu6kavgf*IL`rLuyR#9(HMh zp>3Dl#D}JOUjpkYnTtn;oDe3XTJ%F}{Alg?7^fawZOfg$ir_piA|VW06I$`2W^h5P|oqJ#LS@GjRsh5-By0I<_+VY?y64Czto`DEHTZZj|=Y zJ4^0T)e+5S-_Hg#4btQ9+^uBxC*>7cPN?6TyuX_$-Vk%@(E2CYRdL%N%dT#W+ryx0 z(taE}wI(^$ez-WX&HW0viUawIiJ_~Q#kA*OJ6^)>i%Y*FA3nf_MJD-sr2qMySI~<$ z!9&k{c(km^pWkA^N?)Nhqg($*&FnV#Ch+FL8D@O%So702c)3PXA|c>v2mf1s1Av^Q z9ooFc`l@b$&4dQDz1dFjJZsb9zAFVvR!(GR%fb|vg*GpKDEyTe|C3eGU(bZMeeuK8 zehv7_BlW!R)Gl$o?B)jSwq&TnC419hZF)yb6MqGasFJ7uF&DK_G-t{NzIWB$YC3Y4QJdqVh zqIqWzCBLzI4YHlY{|58mKYEIQh)*@+rSD;lVmFT;hLo=}_|NZlH&}aoiJ89o=oE^x ze>ml&@0beVXq@G5%T=mO@KzR`2z4C2|e)qkKnK;H~PK6PN(#}V}(Ua>>QiAC@moQum3NuMm^~Y0o%rKn5;4O z3NxIyz8hiLmWu391uKEtRiUeoN&)e)#FfQn_U}aPwOei^k{-RoJaOz^&s^`*f1^(D zAE5{!hrPAw^(ioblZDQ0?vR)-ni+Vl0?S2Aa+_NbND{Y~)BSr_Ch1?r3^vi$j)Hx> z0CQups+!Z9yM@j6L+nt2vaF}R#)-{5ev;l$+F@Kd+m$ec8Z|-eOGXE5Jw^D~T-)Tg zE*?g_Y~IfuR5Q<$_~LLFR6PmX(eVhc`|pi$g~tZoy-BR_*9O}@0+OaP4SQ0nic5}_ z`rNC44f(v>6`xFB?i5H+YQeR!Mvac-|8xdew&q!|Yy$TuAKU^gRZH2{4_iL7KHI;a zTi$Lwd)TdI-T3s+iS>RutKbOgegoy9-U-Qi0-=HdQdi&Oj0rfE432c}q`wqr*%hLl zta}Cd^#e@D-r&K$C{Z(=tNicpGmh$?$hC=&6#I2jq?LEuR-CScYH0m96#R}8c|Bo zP>iQ2WpMEPuCX~_n032)Y~G^|B>S|QzUl<2d^y=2cdm$&vn&D)lONesof|2jxFYZo z)Z6D+mw4&@Eb_0vlt%sKl#;%}#B~m{A!rx2oFm?I5C3i>c}s+dCSWrPX#RY_b5+#x zPy)8~tTWLHQhO~O&@c_rR%M>Q?Yc4C|S?=25K;?<=@O-+}XnXa`o7)ID4*v_T?{TtS-v zVi+in=EPKI6l!O9V0JONNPoxHthg5+?`~?dRs;_uq~3W6XY=tmx8Nc@CWx> ze(iZLJlc~i@TDhBbOPMd)zva`OKt)Ww%a3^u457>GYNXNua0OM6Mde1(NzO(v;7f8 zd+(!K(hKla2s+dI7xAgf!R9wcHi}#wq+G{qm>p??Fi#%BH^H^whJt!jb-$A%ftk3X zY%EmKnS72iQ^mY%Jui-zr$A?1<-@P6G1UdCd9}#`It#vB_H-@S0o_S_#*TQl&mr%?tH5^XU{phkHXffMc8L;~h1$$BVt1311j$vyC`ob*g*!A0j z6E$S(`fl`!o|{sFk5^c3hTkrBc+IBt0^*3hZUK^&Mm;VQw#zP4FEu`Iw-SK+BlJAZ z_eZC6>>C!Ry$|)YoG9u3FX&@I?XPB6J;Ht0`*Eb}q4{A9fNQVt-{mv(@ZjQ;?#u5- zxvOUb%Cc}wg{OTly@T2IQpy=Lz^ zDO*nS?3Fx6S7iK0b41;2=9Rja!2aQC6+{KGKPjths7m=pS=V<))N4OVxgTxM@qcrj zcK@R1d%hoUyStQX5A&YqzKxVv9k(g(ne;jR#h!{ENH`KBdbZt$zOnO#DNlZA?@KTS zsH_BNdltO>RF(H79lAd6)l*Cb@pBV!oR=OGq|zzlLiqVGzwC^p*^F1MKELnR_uFO9Nr)a2+grAud)0+Ye^ zjiMY*a~W6FpoVTPkR8)*L`b`-n%ehf+Y&#!U62RyvypLGr!(Qu1an zmA*sI^YX`G1AmGM^&~PlM!?}FuoL2qyK=ap*Qo`}B86xDFebtJ^T2Ede($DV>K+V6 zJ;Bhmc+|4gWpGiJ%``W@gIBcMCq9GfF>W_fsD%+3IQNfg1}_G6-LLwvu5N-LX>()k zdU0K`@JdGDtHreM=C(P5G0IBN@V z9x-d*18xpbzMsWO>wW(7Ggh9UA59*DOPtoh`4mRm-mKfIZ6gt{w>**V!h_M-ApB2D zE>Cy`J@zb)@qd^m>alr_b|(wu38zE!@1e$aHyIS+g7?0*zZSxJRX5MwAZybx{rb@#Uy*FbN~22MpV`3GRii)7lM+oTh?F*6>t zfL@sVRMI$3PE8+#+8NaRQRDo7=WmCOtXlkJaQ;yToEI$2D%<0M7@r^H9Ng?kufw{T zm#H>oVRWFOis!+Y`Ba=7BWL=)9X=89AJ({@;y>FT!G!&nYv>1|7W1k;?G$VzZK4b= z(eT|(ow31x4`%JN9mpiTxVD;??lN=S>zaZd5Qy?rK`kUGGX#}I2kZf(%2(X6Yv@RG z*H1-N*Qr%=6&*EcenbWaC<$;l5u$d`!V#P!(CC5Nr|rJze_IOm&m{#|k%~ZDu4NxR z4ht$GkpCl2Y*~g^(joF0UBL6fBLQ}f=Q6RmiygdC$UjRH6k6xbpc7xImc7y63LNO5 zRH>HS;B;_#6sCLzD;_x(o!O}KPunG#t2${f4!rJKbbu05I@ARv5B_2hj_`Y6Y8cWk zf4LDBz+$%k0^!C$-vgA9&gcN{CV1ta;OeR_#eNT7=|I4NBs?kqiV`_zynjZ?Q?paA zcy-?TsChepZWO~#Qs$^%tOx*o2IeF7!9?!rgT!p0Xk$_rIGbm0b_c=7w8NWC$r7V? zfqU<$!!RXCA^%|jirDCv)d zfY1~@Q0B@!z(-NO+qKXDB@$))RFvk(U_x0t61R=VSEQ)_E$W*SPg-(sr~B&P1@iV9 z<&r$gctCh%suEv-r$%OX6S&asx$ey1o7}Rfz{ExBKEsud`d2|wi^ql!v)!qG5f2`- zm525ex9qw4uI0e$@t<6cvHdVp6o9uotJIQPL&7Kr1Y(64RY4bh+WqNjd}|>BJb!;q ztkh0%-N--7)m=O%aOLEK&v>IMZ5%$phd$$kHlPF~gBDeK#VRFyWfIr$_D~@>T)HK9 zIVAXx_3WoZeUXU!uhs#v5@}%Nn!#zhXn_NP_QO1p0+T(@{L+Y8?0^5w(qpA=ldB-+ z#Q#K~7WCkgccX8zUX^)gR1y4Kqbg#x*Y{ez6_EK(6pXNt%+GRVWDD&Ym-KOV} zdk6Rg2I`9#ZEv6c<&C3aMTaI~83YZVQ4r8P@?PQMCo8Oippr?@b#u~UUBNKTeaR6h zx~`Yt0*~nSUYb-*8X@QW?r+6Zqe9jrTp><7&6AEqE`$e@wv78}bl;k|D3^9xaF~7w zzhBX)$FXSM#curdVwUz52~%3Coq^_0^dI@N?j21-d-d;o7GXSsep>GWI9V)`g|AUXJYw z3)UqKOPlq(y^TTE^63=nnk_|*Cu>jT12lL0d@qJXL8(&B5vyFZGo5WkoR0H=%m?qK z?&Qr^batWp>b!*w2jj$}sf^w=pz#vC6d3uuOlf${PAA$-?Jd!0e8Ue z>}Y2vIS9V{I{hqrruDnI*e;E0za&maHOHjujQ3`U_?cnvNcVR}&yBgp?O@*a4O|l$ z-51|(ZoYHs{ib9*7fj_M$K+k1WBOJt>-@dzv?I7FNu%(y$DH`(t~knYrl+#$gRL~B zk$LbXJAmr)^%J3QN=bK^ONG8E3IP+kn6^Y~^&EO(^Lff;6VXQ8<=(J2sIb{DMN$M| zdhvw&`SH;g@y+cmanUFD=Yr74_Ml#jzGpkD4x5Kfmko7mA3yyR%O;|;tIj+f`P{fj zsbvyp@e2Ctc*^(kd|>1j7Es6E-_MF%RmVaomE%CgiTvU7ZbA}qyxm4JMWLZP*L!~< zaRU~hje)a6JYTFn6)pK3cNugNvUk%x?4fEplKJNR@ldFFzOcOaqh>sY;nw%t zCC*K!Q(J39iwoZ9y;7V=ObL(}ypr)QiC@^U^#%;&Nc{Z9Sp10pT%3 znb7zzk-Uu($zD}N!MQTnA6qeusqh@Wymv3c=|nx8?eeGb2~zE9EiKi_+nI2=XD%-e zop!9%?y#HiP$XLEIkaGHZj|>G4}&|UIgodkT!3oiqo=u=K==bsrAh<@M2TKsG{=W6 z>ZX|LS!4#Aj1iX!3>pt+KibR_Kex2{s3kTZ$~u{#W2d#Yd$!vbktAR{UNLx(jl8gU$!aI&4dpn)d36D>0m;BMaiOFzXPlZIvzgkK>kfSC-RMx zWda2qyYHq`x)ZXCO;q1&N5=Ilb4Ye>%A)xBsxomZpj;#AuoSWoh7O`%Jl2cYPg!#e z?zBD==q96+_}m5T&82HNP;lm7ajy#W4HZyH%LW16ue|R5eu)orXY47KB=<-7-Behm zN}hIGAUce)_iB^0SzYy03CwwHd09bnaIF?Z940ZTKlF->nJDkr#qpnZO^??XE}zKZ`yuy2yf@) zzg8BjDK4b8AtrRp8~69Nxd2{&9htI7X)&*e;pAI&ZBDAqy&>g9-j|D!-1=bgn&?1@ z(8Z4N)jk@a(GEatm7u^~8E4IM!G~2I-~B+5KHn*h9M&)pB@W4vJEFfUMldzx*vwPWtha!wmPIadIXGDZZDdGXo{sbMq0rz5BtlPR(dIsGwGTeJ~!p@4Sv1 zSQIAlgR2k#)ZYqNSxkO%n~$O_R(WvMRAm9}We_}k-fBFpMFks<_d{=h05DM)9NZ5@ z+Gy#*23|WI#sUW)QA%tQ1f$gARAQ#z$z8`S^J>5aA)+U5DG+ma&IZq|&AOB34rY8W ztHztKM`c@bH;6~gjR8FS?*D;jy#Z>-rt$%K0D3m=(xU;=1TSMQyW6F6*X>&l1>1DZj z-=-3>)|)wc0|XeG8G*##e@O-MF(bR*Jt(&-Tud~WKHo4GCtF%_9?>%YR=H8V5FN+N z@6x;lh9mfSPyii%oS!)ecwQ{a^U1a{$dijyhV@;H$1DWUbk1qTBVUWt)t70;dXIA}K zt+flx(@Nuhk^Ljx-3}ia_IC~eb(a^XJ$Eh4%|;1nJ%|;rxDfqVf1GED9^Q-uJh8CrX+wYTFW%Vl(+6twim_UKIFQfef0B&fhunszVq(zA93fPl}r? z&swYAhw?K^VL!w>sBEbma|C->yW1;V@=yff@~*T`>6Ty1!R5uwr4tClYzz9)4Y3b> ziz-LrA4qJVi_>$;d1C8(tllKO2c6z`_S*8CaRMg#sdJzMCZm1Rd6kI$%-NEl42NR6 zaH!DfM!9kmCS7}=LnXifq|r*MGX>HJL~z^^E`KLBRRaSfd2qgp`KNtfoblBl#19iY z2&e_Ww*gAOmOqIH^dvT&nSP$ItE&M9HtztMNik0p6vT9~9YSot@X>{^0v?$25ETHL zNRu11f9k<=sn2FTom=@3!$ZMqwg0QYc34g0rNQ}{1_QtBhJ+cuG>Zw9nlRML288;2 z1dG65aYdOE&!uGZpCSN@LQ*(g_SpL@Sp70~TFpt6-N9jCuAp~88eZqc#t;5gHSt86 ztt*$aO5+o&)FQw;;;cWtbyS;7#ZhR7axjzOUlx}VcDFOr5d`!s0{~2n0M^A-9;rJ7 z0(H7%?F}n)5h?&N#Yes0vB{RJBupiOAti!%Og51Nw`gD;8!7)lg@&hIy;E+#ugZ-C zdeLK)w;@1oVnDn4c0^l0u48i1k81) z0_GUQS2N2W{zL&gF)m%)pCg%>6C@-!d9VaU zB7s&0e+#xkEwRXU^T)#yuzO&EI3McQ`j_|QqzUk6B5rVre#C=)HA2@2Rd%UAS^LBy zuU03%Bp8c2C^z&v|I(mnAaBJcf(Pb%`Ff=Yj^U5pB?J99t029K=8wiZ<39pfevnu~D(*55EdcK|fs2+JLPDeBl5q|U zdO_Vnv~c$uVPhr+6UH1IOsL5sk{=d&PsgS-c;oZyaH5gCBSJssw7@d+YsoP4<8zlg z%Vnl!pu#o)cM0w3r;W5(Mk5kBE>fu)K~E%ni^U|;d!8&Ep%7;7&?XSo#9?fsOO}wC zb9l=|9v?vZ8-2S?m#0l-axpdH;6(ktS;C&~HK?d0PE~IGzhtLUIu6d&$O&+-{{*vB zz%@dQag{wkagv}1?AxIQpmSfFDijcz*5?<0p7tm+!BmjjXzt=GQ$olQB}@UUEn3!x zo8S$1QZw<3q!D2I+>XiH_%-1^aEx#Bt6>9zN55Z#(!sQ+eX5IyRDR1dmTrd8=qTG# zX-j~LCa%jYJ$mZUJXjpTQ!9VK%SlFOw5?ALO@c>5NH+Ws!8e~Et83iI&r5^wMQn`? zafQC-KO(`sk*MdA97I+wwtfCoA=pKQH z<<0W-NZ6POS;#WHa#;O!PiTZfKNQJKhO6)s!YT>?zIHy`hn!4^FV$`r4osvZmpqV9 zf&oNJp;2!mcBRhp(tWfOgbl~YFj*sGd~uKq*z*Rp$|^#>Z$9C{AfB>^Ya7`)6agg ze-PJ?EN#a-Erf?D@GW5SHoI9~0^@f3v^<*zPZK>rDKxGqzOj%b2>u7IC3qnu#xsv{ z`AI~!C3I!UdAZ1Kk_p>MHiqLFFHc6BZY-%Pi@r@c)dlyx4NrY;I=4NZkHbn9dik-w zohtZ&Lx)DrHm3s_4MMPo*Y{Y#oQ4*Hg!V$|+KEFsA&#+O@r<(pp8n_F8xq)r^OE_^ z{`ZmDGyzdjc*5<1T<-%^f_lORctvL;3aL$;xR(VBo}9LloL_)wL0v>xriCpkjDM3s zI=bonmp$>Qnr@bQ2^@ouxRreKrH2H4YdM-eBsd%=4Tp=UZ8zMP&Qwbrh;RGJ)Rxck zvpKSd>^A#0Uv=Lpu %TVl#|0x0IcfBtDG*eOy-4Y7Jmx>6^X3=d3v>Q!}gI& zsoGvu*ik0*F)Cct7<3rjTH?o_)k)alg9P-D%F)M7Fku_BdZMS!7!g+z+e{K<;w$(+ z+rb!(R`O>KpIvNh!YSj4WeC_{6h;u@(7+%!2QkunJLB2AzY&|Q~x^|ESc_U=B#T*Lr z+^jL*BrsS~RX`l?m-znL)^ZUBsI!^t$!cE2HLEJK_sM!gT!Zu>SHK@X%y%}nrNFns z!#|6ear&s#PsUHRd^cv$Vl!37F{SEMAYF42`(vh9hWD|z7$P*QK!bc*n-!L5YFxRC?an< z$5{gHuO5$SP#|~NvBP(28u26&esu?E7nT#Jk2+}Qb1-2qzSBYi+>KWgWe$aCbn?Ed z3I^Z9h>=a$0fAF=xI9SLoFwMJLRws@efqkMvIrZ^_xemHnd0-=a`#%yK)U7k>Wl7@ zk*6i_Ky&E1*L|aTpNIQZ4W3p}fxdJoG}Hu7Jx+(bSr$_ox@*-CAa^oZeczJR> zEADC|TH;GeKq{g}DZbR1V2ssmwIm@kPM=J_y_AzXAuvY^_VxKO(7oaz4Q8~Ca4B=I z1feN`JVo*V+6e11Q*C5Z$3g0&W&fLkh&*(>vVdM-5q~HZ6B&i;(QR@ctoWDg_-6!q zzGfWecX^gx5xI_jc()w$7s@9UQ7EuahGVqgDWLU%%as{}qdY*vSFE;sJQe*9SNqEp z2_Dj<^?4AB7(@Cud^FRw1Bl982YJ2p+~$H&I05NS&xzmypiG#lEd9xB{EJP+q5vgL z6~s5ja1RC30HQ`jP-5R+Fu8&ulxJ`02*A&CE+CT7rNWi0QpTsHH8Sj*5WH zPnkW@fp@{7pXNRaYp7A?TL@<4od$^`^9Dn!lR2k8P0F`E{sgH|V?we@s0Vy2h1X{% z;%R70+4~ajU)IIdKk!&+4niJb;hBuW!7V(q0gG0t_Kog5(_`l8+@55~OhF0H5rO9) zKNZJs+}tf#jx^QPtbNOvB%VN#gF5pYv>TrSPe+HI#=rxWd_nov8^LxFlPP$lvwe>C z!rTnjk|~Yyl8ypG5;hDHNwywop{~QtEU)mNEl--Qgf};*dz1PAgS<3{x z&NEb+rc|=HCv%)8y_$z7LTIO*Yzjn($k=XNlWMpYAtt{t6go@rP0{!>;kZkS+7nS^BulfJ9yg1C0{IdRrH^%V9PO-a*m2ldmv0D5Jz-JBFo-O}a0>Ff=1+X+9ZaDf+mk+|{7~v^ z^I+k;e~zwZXE4`?y=MNqI^U}RX4jRNK1dX@6XvuLB4FGZi6k1kyUNI&)U_;jSfekF zp{b8^QNR%_3592Su7g}aB+dvVdacHO9~TA*+ZNOdZ~~NJF?w35$|(%B@o#r5ay_X8%yZ$kH$Y25|Z4O@m1S9t`F7`u)<4>Z37UFcPK( zO;+K4UjvAoel`2>er4pedtv>nviI_Q=2CBmW)HZA&&yb?yp{4n5iVUq@-KioJ`m{i z)AYZo`Sn?VX2{|b7ia|bVbO-BZRN1ZBefJ6bpO?gp(kXnlM}pNa|FZ&BCTkKKev1@ z>xAcm$g-oEaBU&ggBYU`?v&z-X(w;qmU`hT)U!Q#mt@Vu6LlLOR_(HJduWL28<&M> z0MWtC*8RM$MO2Lb?ZxAcTM=68kx>zGJ#QH+G3fxuj{@tJX27e{!NNemI%4T@yb9FG zLs4MZEa(<;2`2}z49t|}A)mUz`qw>)&Jczua+}x(XpYbx&6X}c%+&Rgrs-FOr-X(W zT0kBMGf^SHCOAn?dc1i~d5gZuwpd;>Nt@N`oOGRZlp8DQ9A}m=d@>wFW+Ot#jF!Gx zwa`Ij@CGP>^*P&0$65EH*?*=v`>*Gh{~c_l6p!&bN{FhrLGWS zUAlzUb6`v>i!pr6TzdRim#+OK^D3ygsrg|`?%r`|rw10D&3HuOg#Udu<+KfA;SB_J zZCrp7XgQX^BMDsG!HI?0KoS?Qv7W^f_eOPDlbQCt7)3@)A7hO%LWl;5(n|LT6)d2= zUZ)c?3Ci+1t~Ro|y1z|q?;Ed@E;TGB=*S9C!#N?H5(zl%7{UlaQfVHqgGpjs0}Wlr zV70}_b2H-mvwr#nu&+NQW&1%`m>Lmc>bNS(i4RMnDhohi*1AnrZ#^*oWVP*<-@EqW z!44=sPMaw*8|NRn?*faEu*!T&fFs64%!i+>)N>!$M8fa?WJ>?t@$V?FN|yuqMjUEZ zqyf$@Ckg<4`Fgj!Pi!5kzIWKXRJ^L;3j`i+*L2juYeEy(L*}_9fml_5Nu8K7MT97l z<8n3hd_`QCns3Mj<|w+r`zS;Chw_vY&(%7k8LXAcw(t`0K`dP*@#g-|Sg9<6gg=N; znH*8j{Ye912l3dQH)b2qa%@lFYr-_Mg8E|fd?-JR(0EcCelRo1&c->AuLW? zi75+D=jk4Zvt-7>$pRe9k( zByOiL;T#s){$^*hW_|htiXS#v$$=v+78Bi_<2+<&LMf@@alDxLDVV3y*plWVSFXq$qpRDd zk2cfL0-T;;yRFme-74OFna}5>nWn=-2FS$Sip#^a08+C>N+lxfAWqM;_ zp^`ZOz7p23nwu&chcVRto6#%2Ua%`ERxf}s#>fm8lbLJC-)|rvBmL=@G#*QE%@K*% z$~G1&mwg$==@MLvgx}tZ0qIPWd>6^|h1iRY-m?=PrY1yu@a)lH37_wFfI}i}cjKv7!>nyyu*BRsHD2R_Jk`OrbG z14xJPKytO`8PvuvB4mhoBj@+T%*6<^XKS=90qiJ#064&lgC#c_fL{4su#v{EYV+j2 zeR&To9xH&5R2cD@@PN6%H92~JeKpeC97>#HEcwnIke8gg>JV=T4IIQh(rB- zPzl)Cr-*`c@?pTI;Ut1#Pa8#Wzd$Q3%&q>c)SIc&!pL;F!*m%}?z1dB-EdpKtSUGEB3*@ zJIK$xIIyD7rQ(12Y=^KBWSvq?YO~J)SP2*5lF@bD+CWEQd^`>?l-0=w z$>uc7)X5B`e2`edi+zB3B`FHhwGu#AUjymdgV)bMWRQ3kH| z=Bf?vHVs;Ka9*4Ac4nej-529ESw`Dc`QRNWxDdSA~@%lpjQ4c~UMal^8~NY4%)iKQ1Eyg-oV`bCcoqK}Vx>N0d_$L+Z~o zkF|oDMJbCwi+x~SrY5b@P>Lhu+&LWQV6LSsW6vT1Uf#u1_r}MR;NcJN!>Pn41r?En zv|hO)=g##Hs^S6HfVS?o$W=}&;KrhwWFDcCQ_zvyNa%L}sjqCeMp3y6$A<0ve69Tb z1%yi=AXLQ#zKW;sCpd2LL3fu(a1yG83-Q?iP1OUdHLt$}3qKCoiR{teDT`8mp4h{{ zLMGM}N#q!zMGYy4oeQw04#halgx9Fvip^P2d@nR?IP)f}Kkg*k)TTa?S1IQdnf;4{ zRp;aQXgOG@i`C_p0h}(k?FUw&WMAbuyLwyBL#_pvJkFtcxDsQkUyUO(P@)w;bo5YO z@vyX|-hly`z5*gZUOn1i9|#)riDWldoiYgdaUIi-+Sy+u%g*9nfYb)nEBhnhp1)!> zmH6u{uaJQR9U2{0>Uf{BJ&1nZwM|mVussVWr!N49 z+#tV{`bB(UwBmDZc=InRZ z6rfmYw0*i%f?zb$q>fRN*bqmSSOe6`_cm;}Fz}by>Bd5=t*Xej@=S=>mB#)lzmP<#Xl{`06B}@%}`yD?V=aklWnBGa)n_V>}pZ znZ9ePB|pqYKuSVm+(GnKM-oMStE`j#n<_&{jFLXjJY3k(_W_XVWK3tP-!qaLzpzu$ zW5n` z7#fDhGD38th1T*X^Gf2}(OdFH{6*EOrd)K6>yH4ErjcSBe-NS)NcG!1-CLbs8BpYaOc(*%$9 z?qf!m-F#-rBvNi)zw-*@Ex$+?dY>V`T|r^M0d=Gf3rjUBK=I z!m3FlI<@D+TG;L!epWn%}uln9+M z4QYFnlh#Vj=noGasFW-~f|%K#jISI7zC&Brv10D^<@N5Rrw1MB`cj4P$W zNATA_a}u;4UyPTdwGfO3nPZHpBM)&?xmkzs#Ex837$MeBMG8SuS(}Z5=j1lCB$A(a z5AQLIe(x^kyZ*O%lvqbOJ)1H>2#a zXN!{7L5hYa3-_SPUnS^V9y%gnBB2h^?{|OBevKIe+_wamTq0{H2qi@ZQ5!KxQv%$R zc4D=;+@FvI*UYWhQOPaZQ3Ts0$+|L5xv!iFok}=rusj1_X}ZCU>tq1-O(qP=|{RD^*rZJrdMV z^%J9*dBm<^PFK@6E9xlL;QKuIP|+o(+tiKz_n61mqVVjk zE4BDWD3q1oSc0CE8Qtibsb=e1e1;!>HG&!!o9sGiVkk67TIJ0R+N_{BfFc;TALWeGyKqr$XAGM2(4-Fhq`F}-$%$* zGAPioVO_7rnsX_dTzQ}Qs}nef+=EjiD^A$wI&Oo%!skH!_@UX{Y&JGajr?(>VKqvw z0*9hc`S(P{h^0mAxLr#0{(AJ^cfoHFsF#Wm*ojX>EtNVW*_~*wR{y&2pY&J9T8PX3$$9Kki z9(+%I)S3A>@Ba=E_250SI|wZp6dQK$)O4Hyi<~-1LJe;GvZvWiH15h{LoBFu8E!Vy z_Ay9%j)rBXnQ^PIwASnuPDhEx{}vCd3<(-Ws;N9S%==7RL>di?mR*Gcsi`+qZCKIv z-xRpXQQus_hH;yI1fL8gsZGrL-{Nunf5y*6mXB{!SiG~G`R_9s5(1cn zHVIL${gniK5C_lDuui~3)`i8ZeZ3#9EN*_FpMOu;(>sWQw!Q%|j*R9EuxNCjtg&;} z-LE{BV@I$?)Sonqf*DYVogB=Gl0%=odb{! zT~V&)APD7=%Xy-T;6+L9XrHXjdR3zT{?pxGp^&Z2IxOr zBNN;PNuBKAmDTD?fwll9=rAqM=mTXZ3B^qpCwuD#qgFNVE$Jzhi~P`)$Pu-!RTWfrBmx6e9YpUn9yXMm%v!otCiwRNyio;OSUn%!ank@q$E)1} zea<^`mPcrAkAb|r1EU1p>J+bxvOBw3AZ;hIqEGBJTd-kONk%Zu=VWznRoPca4=_ii z*44Q&=!!40Uq5*qXH=Td0|aAi@BNk+yC}$1NVV-m0D<@S!2(A~;@}JiK=rc+RW9!F!@CcKown$Y7$`Y`y67lP&Kp&moYE*Md(1_hdCvpqC?8 zRuo8x6vpp=-i-;~E%(j%uXi^Cu4jV&Q7cuhYyAR4*gY4^|I^-kg*Dkk?ZS$p6cIuv zNLNY#3DSEn(vg4>F%nQLNRuj6kPZPAQ3RAGAw;C82-2kl1Zg5wdO*5J@9mqxgmp4i zHb)=LfY8;j*T&u07bLjf3j){Pq7}AOfH>4mgYmP;AJ|l$wOy%rGj+>f>;FicB>Pzb zbxXQ#>8nn~mPH+|^E3@&X`=b1nSEcjfyO}ZMmTczrPr941DKHOfOGl6cMvw9Y6}0r zEwb`Kz4@cWJnN76zx!&Iu0X*Y{aA(sK)wUQUqf)o z-qLlxeEun5&|${;llDD8L5SILb{G^Aw5kiOPs-jl3#pg2o`Y@Iq z6T^Bg=VAspKf!3)dnKE}ABkBpO5l5v87et(B=9iGUfy84{uBI?u0!fs?Yf6{D0AV0&6qhH`0=Y?3bXq+;VX7Rxt3N}&YfN|2Sc)x&Zic7-H>doB-W!? z6?5Y{tS*32wRbs{3|S$56z_+c3^)QSN2i&gskV6 z4?Hx&9jM^nuQDF@?R=tKpj>JuJKbis>A)Eun_RsC{^~^Vp2NGu(@5`yI71b`POX{L z217;E3O!jA0$k5~@PmZJ6?gChYhZw_l~z%uWCmCZxNQz-@%1+kDYAHNJzIriGkgCU z({%Mc%2W4d)pXa*j#Az|3#={XL|s0ae!y$N@B+%EsALM7Q&zy+eDU>_C7-~wxUFs1 zPl7i|r%!|TE6VR4IyqQ#5ZgfAREmL~#DP7?l6sDcBAcHvaA|jHh5Pk@4Rs?q5Pz!q zzpn8i#XCmuyxY~Uh(;LB0iFwH{klcAhi0}gFu{KfZwC!&{gU5MZ^*_k2EWhkcJ1S! zWX7d{_j__ecC!AyKwSy=-T}!rR5k^T(Iv3Hi?v&l{C z$i`n|1>+t-V1eCBD>ni{N{Q2ZtJ;O8JF=z1Ewet}FOai1Rs z8@HZp`Yn=P^9Rh2<8|=}P^G{A!=9GCFLr@g4%CmIB!1~W6rSv{3>y&7){%Y{a0E%) zU+17j)j1Fdd^X`j3Sz|}LeJ_%|MYuy6OcRSq+Oq`H1p6Vyplg~* z{+_P0wzg8ng|DrEQv&;G9MDL3O}5PR8W*5YyXSy9&5_h;=&|1yvhk%&z$)Cd93ntI z0Hd(#HPUHsKctR@By~KuumOHA4t}580PmwFR~Ha*);OHu9RX78gn(V}Abb}!|GP}v zA7GWb0il(ul+3~)CJ+(vKQw!Cb%+I0eB`z&Mm9ZR_!+SLG5H;FaN6rAEQ4G7W4H~b z#84ONR95E5)Djq*N${rU;8OrVo|3`%!f?YuU`_?RvQcs5S`ix!jxR3uO)tm=R4D(6 z<$dpOg_Hlu4|O1u6OU}!fHB=Zj<1DQwazBbNNs#OG%-&wv0P5y6TpmE)r(ahIU=ui zQCkC1^iM=@j5+x&pL`e8fie>5L3pie1=61}yLb5<{d^m>WD3pB0S0`+VITpb$FhGX zR+hL+7RZDB6}GjtXf!V}1;V&VT4I9rHL07{rhktKC#Z2#mv9Q*Q{ zm_u_{0I&M`c}oP$9n2T0<^3){cPYJJhJ0hE!8kLce}Hpgrwqo|5N4Cj*{>9kCkX2x zvG{l^uksS5HJ=$vkL#FK??=1MN`10XbajDt+z9_p3smCY#A(-w%$cOCcLDWEmbF_4 zUf!1mWSM8~c^aEu82KCCf{jh40g14O?fi3Kk!{jpg&=txj|s+65-u$KGQU@o|bQ;sOB@Skfu2{zdTCJ8ben zM7rlYr;nvf>id(e8|0=SrR{ng{5}QPxU0ZL49ixLd60(`t-x~J`BmEQNXgs;&dgW1 zKc4)=3IJV@Vyv6i0e&ACh5@B@)MqmN%L0W2sphP?Vv!CCk^zM`p)$!HlTzS2W9g*q zH(K4&^Z!-_a5kAFo&LMe;w<0~XKMWVX<|c2ehMCqdPMe^20_ifF;*cduZe*Pa)5W%0t3Qg<)cV!5sb5}vk3)tqrihF`&e|YsxfduN9fC2F72}~e= z&9_)^;J%gayaP&02?oGEoYEsdxakmJ$1&`JO1Tdy_<;S=-#lbS|4IWM0_;=lX!>FM zSeOcizkjw0Xuc=#0@!>3`|7`w11Gox4F8CA%^$qpiDck7-wBbqW1wANeLwE0&jTxg z0B*u!Vf^i18G;`rgWqQ<D{>VK1;pc*rhfv%l@0W|*xP_~z`$!TQvS3TIAWDmm3SE0=8=3suh9=4TYWWzJF zUj|3VhMyj&{7aC7I0*jOGa-MDivbS*nr>|%@BpLftY#qIxYPg8?=y|G1~?0X zu}=dI9jO_huP;rmwS)9Eff0;<>0Y2d`TBJA!TUo`bQzl4GK2a5J5{ptZ;J;TV8ODw z0`|fTEZ{`*%-6rt0fnOs@SKiIzWiN{Fe!_V&YG1Wx4b|qr|$h5B-&b&1jK4(dgwUP zkq*>odjCyIUGwzIo~=dRBPq_l<6q4yZWMq`BYW4h2srl%1UaBpNkElOS^Qiii>%ax z%RuP!BOr7>jY6DZ+VYzFdS=9Tg_su~)oTpNMRJt#@18oS1DSECZ-^c`5Fb@rDJ-~a`^=sKK>v#3s0#VL#e@CDH;s26(a8$8H(r$Q1;w$XK+ulFbUT%4Ym`Pb z@3BK`a$*l^=b(2P0HOk)JQut2-7OiAStUU$of7{AkR@Lv!SexcGtjciDn|(16FFFe z>*kj8#y=7zQJ`Z4Q!m#7Xlr3af=~E@79!)>Zak!m#++L!b62QuK~be+mmAk(Zz*SO zV)RBfx&HV~l&ChXr%ovg0jiY?7V0((Dg@bpkX%X>EliWTWnvBR{w=)<;UiNw_5)U} zZRJh4yJalV#uaRh+lOp3h=EC~C#^CE@B#jEE)Ydp#b>C9a zV&F#k3;-IK0D_rM<6PHT<9z>zE)tL=2XJk3ccTGgPIj;R`kv*MoT<-2pMAXeb)w)t zC}kOvz4b1a6MqX;;}0EB650q&GpE5kc&m^4{_7 zIjU>9wP)#%lmLqM>TmCAC6&bo?V>v??_2`F=i+8_nP^(a>xh)Hm7lg`^Qbj=4xL#i z3JmoMuY=Cur5z{YveXH365Iep6*8w!skVFpKInAo5svM<; z+8t-h@vfY^HWMb{kKVddd)zsCW&QO=g%AX(BY;x?biD5&l(gg7)+(<7xQ2`6jM{c* z{C9IbuI|f)p9b!}%?9jL$;ydy5;LWOgp`h1aGSU2Q`yTCyU4TG$>Vuk4>T;YhdkT` zK>dZaB94GPBF}-(06@95sM~?7LOA@yF<{D!@poM$X3c7%M zO+7_WCySvuhngy-JzvTT`EB&kvp}zF?|~+V^+vvVxXjR{ePG@HdQB(B+uF8u&sd#d z0L?vh-?zm+UgbH7ojv}`{lc+z0Dn-c9A_yIR%@mcVd2=ba(%{=TAKivI9Mu7(kG?` zd!8L6iQqflKE9N;Ka=(y>?yK}uye3oaA0lpLgad0XF_}6`UftHOw!GBrgc`D0S*+C z-{Iagi+YTI#}#gk(Fd^yt^2>ZFy-Xpch$F!bJ%PjwfUP?q5{6xQoU=~-rhRFNva2S zmH-tgm_LD@0I2by%N>@1w^M~Ae7?{sYQ7*b*Oi$pEEjb?U_yZB;^k|e-KCCYyX!6oUUt5n zf+_bHdBpLE{ojlG=OtC%#$nRK3(tqZu<;Om5;LCrwl|4H$%eK{T?H6l7`_;^QTXj6 z0^ycKA^NrL7kD&lTO_KLQL{U46*br$ZL1!Sn9UNh&8GQio(>77lN&YS0>B|mvt${7 zNOb||=hM=$)Z6yvS7DT|x4zwa&hri|b|f`i2oXGA+>2^}%DVaXv}NG=T*N+p`Ys;VRq*)W!`LeHxX%$Dmd-H*Yr*)%J;M z*cgc_pKl_Lp>(9$ZOlqNR32fv*Bi8Vd3*GvntU#$yON@$aS%K#=JDCU1hF4R>a}H( zkM1?{1o;nuR$DC=@12>x2*ptA*_+!D&=Fi-kuRcyZUuo6KzmsiCTehnXK+7_JmOMs zp@c&E;GR)y`lU}|3ESLxTaqs+Lvr)bl9yqMnU+JP1i!AOrZzJ$7}Ac$>?4UsT?v~1 z#j3?Lj_g#9h}ObFsGv&r5JUhVc}wi)6N8YCe%+MtyV5VS?celWMAn{C_V}fL?m&3< z$9SH1xl&o%MF^P?l6Amc%y7~a`j&8Q#$e*(n2~1SE6mq(olQ@xtaglV3*6vWzfqZ_ zVcNM<60}pYdbN7(>g1$U00#Ej{~l5;@{cgR{uN?4tR#>v?tHcFOhVwN)n7h!$u_N1 ze~&N7YP^DVkITCFcBOp3I$K*y)$mwzO9ZZixX@Bq<1y*duW*d+yK($cJDQB@$yEm zj-Wp$gE}BI&s@&?X`X}dX`uErZhuJ@?L;yp-_f)W^AMZxuca1x7BjirPXf=eF9!B> zL@h$si6>S61l!3KCei5XFjTvI8stV0N7_lu*ZaO)W3*q+9XwwqAXH%Y?8+a6NKw?% z2W{4Ep##(wg$gC}W>UJ29WvYJD2nOtl?G?ehI9zx#gRu64QQQJg}RbZ4f%#{?naa+ zEJcUp@)H!itJ5-?BXW(m2BhzG18n}@2v?4+91gJB-}_?>czYtz#!t#*o!4LfX2C3x zE*bnz$i|A&!kJb>8%dRWJO6$zu>q2o{M9DRawsvMW{fU|Fgks)b_*lT+9|%L4E<25x%QO0t55{MiI0P#L%q4={#PQjp$+H#XX6sPC*Hej^)U$U?v zj2Vli`hz|O&mz$E#gkpm&2leP(dKus6$>C}m~1h+Zil`Zo4E&$tuX7aNhlur{rSe%r*>@lq)?|}`+Q$~uY4ouqGEO;c$YO( zGhA}i?^oNatAT9x#_El0)f<(I;=R9LHpN+qSs7VE97pQqSFUE#M1_UsHu1x=7C;lf zF!$qv8ZdJQyX^;v*Acw7fQKp) zk}$IMYUE-lU#LhZubaE6tyVQK!)12cRC2qO(2OHv#}kD+smw`1PMnS#HB(=+;wRr< zx~iXil^|Se>(1S?(h!N%(0j4($ zJ|MLASIao5WKr~L6KPSjY0?vjK1JMl`DvXL^pQxo5?Cd`JF(KSWg5}BP4Hatv!hD^ z7g8mqV)^m2l6Y%h89eyfrk#)&;iWslh0$fZ`Pqe@*Pj74I!45U6c@&fCd}nXt|J_E zaP^LPOgicVD%qHkyMbpK<9bgy5}1|)4n^nbCF%>uII+z@FBU~glzv?b+$HklkQih< zCCzVU-{kSJ*|I)ja1s+~_!es@_@z zeAe?EAssr#8f++?A2n3qODRjb)Q#4OB5nc}i)z5M77r{xc$A-lAw;I_r|2nxNI$?- zgyx9UilnYM3NU8|A?`t(b$rYNadXrGLYt+(k{zQZv!QSCkZ4J+m}1||qDf`P-)G)? ze7RZ6qM2CHDG|~*9g>r9&K{?0tM7OROy7ZUk6}JPyOQ4YK?QB>&Iu^7Q>V zSam*kw|i4B{}myT3H{F+3o` z>G4}A-_bd|8R(h|z>MO~zgJSmODY$fX6Rgev_7Y>baNYR&Ey{+*X79pkmZu3)6ys^ z$jDcLZgvFP?B#b+v#;@sQwqW68^uywIkUTneFkXZG#oRdY*bA`SpIVve4MUGixtgo z5kZw-#`y&*yQDN0(Duc|5b_6}xZqjfcMa0>Em`L6sgSaE%Qd;K7j|^7@Eg?j$VU+m zC872PYo}REA&L!tu~J`{SrD;O_H4u+(Ioy*Vu?PyevPo?)`p7rXA5TH`$j@Hp3!~0 z0@5+J&z|WxMSksQqI^>O@=nt2pZ?vJ-}R>U9c)(Gp*<5&RdQ>4loC$~XbXisy7SY_ zLsP$202W@v%QL!Ha9O{B#=;ASNQZoPB^pp_4ktltS6M?Cu;!B(vtSu>s?$`4rCaf4 zd~pI)d>?VvY!RGJpDx9z{^4MKl|69I1;JYM&U6P# z)sfMeIA!!KtA#rr>snODj5d<4r>cuMKYM6%PTg9+39H})7TNYdEG=o@v2 zXAovZ+@@8!rWK|m?6*SL1LJL6xToPd(Qr`|v82W09boPYo0uzK%3$s`UOI7f;0D_S zwmIAjVY1kpEypKC6 zx8TOq%FOm@bsx}A%>$n?gz^Tb*yEKm-I&_S&d$r%x2j|u(Vz=HZGi>xUy1xjpEs96 zxN@mnmI<{V5q;W3!IVI^M?4r#XZ%HgmE9RXSCt|ndt6pIUYCV|dq{3+Fx_3sM20bg zE{$)KH`cb2nIgABG9YF~H_u6`Tlact75taK5evWBv~%d0ygJRS_)uL0mO&l9pDIMb zs(GR3^33Ub>;jr$gAY3%EwtwvWbzmVkC)lMot-|}+v)=-D(@P~Bw~d!TERX0YXEt# zo($pCl%b#_h`E$9o}Xk<-L(?n9UH(g*omLPvMQ zX`kXgJXPWeI2W%(>+jQg{;*l{gbo9fF(SHbUVZ#JFrZ>f^`;p0k6XN^9u z4>+!zXAU;3%Cg)S%oqh6L!0^c+P8J|wTMr`BID)9BkiUnQCW+Kp+ZjNFjds@j8#Qr zaVJ|ynlsZpb?~2PxUd>e+E__~#OSwM$dQQRXPJ=E$*XT0=Tyl{dLVr?Do}q1JX-?% zop3ceT!5Zeu$c*M;2%fxh?L+@#(cfM($4&P7l~(2(tJ8HN>K2baCjjiIv>Y8SJcrC zNFjOlj(6i0s{`HkfZs0AzYu99hPosLZFuXAfE_I+2rad z{RGNbrFBv5j9w&?tmF*BizDUABP*g zYiSHoHG80Ao3IgKkApRr+z^tt3lJi|a0jNL#`Pb|s}CE~8tkA?4o|UUMVxyR$$7ad zhVwp5EOUrNRhG0Y*Kd$iCP+U64H&u`T2e_pl!U!Po8#@LvMQP*WF8>(B1FVHk)Z4M zZK7@p4Gn8xtG99{G)%`SYbii%v}H9PHy*iB#zSq1^F?b6-WGE(g2TIY&(S7IZVjlh zGcju0!`L)v=Y~3{-nia!N@J&m*>BpQ_`a(YM~f&U_|3<(i66vdzad05>Dq$52Wzm7SpYw|G0MMBvdd!kPSXuIrz<#KJm`a z`1x*S(Q76H2Iu-8OmW$Y!9!1$*EChvi{i6iR7{+k%tfXq+J=gV?@5QSIzJ}*;Y@6! z4MTZToIYJ?40*pATqD@yG^W%y88Hj>ij3Ax(sX6O;7{SDmS+X9`L0YRlsak{%2(9J z{PVm=cq2=tuI`qmt$6TgHGP4qOUlG2pty)=PrmHoKivI~n)cubYb%>Z;zpBc^F|yY%X(bdL?$ z-q@qRA^vVCSSHT4IcLB#h$m5hS9W>i=LUci#=#@qKm+oj7RlOZo%dHvb4LiWqr0y& zgLXOXF2Ap^j&YYfj~J?#R)#$)oE7SuEs@~<3&{QFe!3$~-RT%7>{!z2;<5K@hNWkm ztyb=a?w?^$I`&eq(Gj^;5ZUi+Sd%q8L-fkl;bOZm+~*$^lz#2mb7itk%|=l!c?&b8Esvy+ zph>J42$8vyWXB}eO@i&=m6wYz3odh6HZuMwTt8)T?KVPI`zCdeRApG07qww#(Ro^n zgk{bLSf?TfY7B2kjbJtFa8~p=nBlmMy~_PA6Lv;RMMO_W?^4e!$6RWKp1f|ySrL-;_8HRw>-|FeVz5Z6bQ~BY6TSw6MK&L6^r>~30KRw*>5=4_QkIkEMw2i3Nl>W5 z9?uf$nqxEh~4<>%S!b72nq>iQrcIGJPl+ZK&&`8~bq`(9T#5as$qF`q!YmZkH=L6@} z{+lrDnFcp|mE|ivL44AY1ZmDsHLvdqFx%rVp%QD`j1l35+;kc2!ITT2)NB}W=Dz+? z#g5vUy7N{>oY7vLI&3U+d9KbBrSkOMQvOqbT*(q4`019=%xEU1=SAZ3 z7VB-G1CIQSK|P8KJzvq6^KXk$1$;gCqCRa>pjuK>8QNy^g7)+aWmWPk^rMvFFteXE zzmn|ZX8KS`%_p$Z#ts22Fw4@dn~=T=&{s2UwofF-4}x;G%EdP2h)$+~bT$n`=}gUo zV~r}lnpEo!dM)LE%ZEZ`mWv6klNAQ(IoOu}v|9bCT2lNui}(R@Iyzkk8< z^P*m&i6wxYjA-+GK2aOlTk%U~Qt!$}82+^82k}pRnLe);&#Ff?M7BKoAcV*_`@)EU ziQ?6%zAV$c#^14wm5VdaT_v>yMjqU($Te8H7JAF*9DjX`=QUg?e^cb>V|bWk>>Upq zrZ3}^Y&P&;AJ5?fk)sONb0QhS;OC&-vhyJgs}fL)Y-Dx#$PG2j{>oLp-I(;J`%63g z!gJ1N8u>@^uGGmeD7#hsH@w&+g%?Td5Hy8YD5sHe)Ey0`jB#voinlXrMVE>(=IDxI z&?2b+PqvDWF~~KM(Es~I7u9b0o(9nwoqTU?ve-QiZj1q)CdPk{4g06?i2Fy<9pSWS z7vVM&-90KE{!@`_j<_>?k+$z%=E~;Bd)~z%qrFI2=nO{3MQtDTBf$!Li``WBHjP#j z8eaB)jhwMGr`D-a-|SR*7k&2$XuJGDIc{m-y`l%#mUkf0704ey;n zQfU~WzG&&|oTHKZ*{QnxB;EsIStu;o%}}%hvE(s|nDv&t))SAOwGeY?*b7GO0hKr5O`Ycf*cuX**KL&31?g}+au%?k*pjckI99PRu(Yt#H;kOIhkaEDz= zln&(z<%ak$w3#a`*YWHZ5=-%FNweA=8lz7N{OXe~SW0-AWNwF3J|oK2IbYj#KpOex z5nP@=6bli?HcE0ukJw1p3gW9s=IRZDyyr;^H~$TRM5Eo`b#WV8-t``3c-wQp0fkE=M0j9{ie!3xfL(l(y02W0AutxiU$ouy&@WAYpR3 zx7GUbZRwZn$QRmpsvb*KlOWR=2Ye}q3e8(DF)6~?s0#-XMd0zf; zv=RM+sA7Wf9r>bHb>t7VP%8ZQ`VUe}R}@ZH&ee&#z}FPR5SIRE^wAy5P}c`pnbFO7 zoZVQ7mO68}(`2KU+SIPmoL#ip@MgY$D_;n|*Ix7z{~*yj`Lgq5TKts1V2|v$Oiy`6 zh#37Q@_HmJL&5zQGmij*)DgGiGF)%8v3TkzhY&iM>3|h5y$%8Y)>v^jZ4)E{q5gTE zwbl|uN=7&T{ZbP6Jy8tu><{-(fe+dDhx-Im?uba*ry=Uv)QQTgp zEvV^x^9x+t7&1Qr_B>Ejj-aTv*r|qvNLmU*dpQ$zDs+)L#VyC^l^G%ssuyHVH6jZl z?xrf=wtMT{Q<|Ini6FaRbJ>WCsF-_(uP@U&`*K#=$uq9%dY-2nFR&tV7@(c z5j|H67JY_VxMf_8V2F~c;gQCTiEf!t6wmJH$(9v&aR52Eygh(=)%>pFI-<&KPm9G^ zI)n}Xy6>qfw5ypa6?q+dw*n`adEgSblA=U$LABlG$;cgUtEHW>P5(;axa>=j4e#H^ z`i%THysD%qK6NjNu^!_q?M%qcoW3Rga?@yE-}SM}_14x6KEt<0RQ6?@iPRM@xvOE}km{_4<79}tH>gZHB{qY7Dm{Lo#JG6DvHd7S8X{h~sVy*mhMwmM>iDb>Au zsr!s3lY(xix*~BEnby&gxpzY$Llz^*oQRr7G(s>BJLRp`vHCVMNlMYS2jJp@EyD_R zr@OLJ@uxG>3CKWfZ`JOk#EY&v`RBG#3?lS}h4zYrB$`%!oz`@1-vt6fTW3=<>{M4{ z-|y61TS+>x#ghkdIEt3HLCA^iO=7&nTc2^C5VgSSt)ivZhwGI9Zz^F{UK4&KBxMU( za*Tr2cW**SP2smk8p9}A~cD}|-0YuhH6UXR{~Xco~uNDSKW zey@IkR&1)PdOQg>dcgt<>GVk4T z;*H}Qjn;X-vhpWYCqLJ!xiQ&I5i|v43W(Mf)~5X7b2XuH>Aw}SQ>b*WU^>SNSBsa6 zPqis2fBMIl3}0lSmunz(Id6n=4Nku|yc9@G4)TguSr`74@*CCr$i5UEA01md)}}^k zIL>Bqi^@CGIwV&CAv>YOxd+;fp7-L67O_ZuWE;jS(AI*HFK6x?!RvY+m)jnEbGcaF z+cJ?>Zd(jtZt{oiY95Xc|{CJOVez%)i;M@H+n(Onp zjHVJkl?s7}R&%oQumFA*zP|FRC{2n%ifgvwSpVNl}~EGe!*khvsO&gVt=Tg zEWRLN-5hjD^7#puqC4xw6f#M=cP;YL56tS9V6(WB#yF$XsY zK~=K~a;-*|XoFLU>|3oWa|N#M)c{G8$a53Mj5Zub0UN@qajAlUQO;;YDxEfeP|M8C zy7i96Vccd*pqskhs%^wW z*gQ}dw57bu)@OE69m&`&Zp4OGq)FsWxHCBY;e^33$eMLRS2%lj175q^8%?XTzX$EA ztgPVmw~%_FG8aoZ1Wy4Hc%3vS_EjMff?2!?`%dZ-D6g}m57)3|!N6X{2kjCY6o|#Y z^=hfG9~jn2u$C5MKT>%vMD@}YchD=&Toiis>`#>LL;Xowiyyu+6h>ZI{NHZ)UM+BqYZeKN0qx&(Br&ew z3kPB*U#kW1&A9n!-Gg*(5?y%CFrA2@=4)rQd$%?=^ifFgy9k<3-}5$6l`+b73P z1UKEtS#Zto>ruEzZCNHNI9|E?q$85k9m`GPtImL~DS;2pw*e34{RVuft~iOJ&f^_w z>V^SxFH6^>Qo$aRnJSH`B>y60n_gn84-4n&%ZE`__bZPZg=(=cD>}{;F37N``wNYz zSRoTRjn)A>!Fdb8rAe2cGcpUUO0f-@aclSO`Ouu-;aw}#Ci8^wS)QJN{NO6Zce)BW zRzF^QoJAf}>?zyZppZ%7$RA*rd>N%d@GjzotJ=#{C5&9y%Na4^c{7q4|M<@S?pDL% zlMz9}E=r&;Bgp1DYOBH9t%}NXynIXS;1@mwFHZo}v%k<$kTK7&;I7$9RlZRA{K37; zu&+8zK>p;8Dhz@9%e zv7?j&BqqZ1C+mvjn3jJMk90|Zki~Goln!B?{|OnLAOOJIqVM Date: Mon, 29 Apr 2024 10:47:09 -0700 Subject: [PATCH 2/4] strip --- 06-panel-intro.ipynb | 468 ++----------------------------------------- 1 file changed, 16 insertions(+), 452 deletions(-) diff --git a/06-panel-intro.ipynb b/06-panel-intro.ipynb index 7498efe..130f919 100644 --- a/06-panel-intro.ipynb +++ b/06-panel-intro.ipynb @@ -220,25 +220,9 @@ }, { "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "6e1b47eef7ef45388b045f69d4d507b0", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "BokehModel(combine_events=True, render_bundle={'docs_json': {'8a999aa4-7efd-4bfb-925e-69148192146e': {'version…" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "chat = pn.chat.ChatInterface()\n", "chat" @@ -257,7 +241,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -282,143 +266,9 @@ }, { "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.0/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ] - }, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "52657123-eb28-4912-a84b-6adbb91b24d2" - } - }, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "fd1ebc0fa8ff41789afc3fbdedeaa1a3", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "BokehModel(combine_events=True, render_bundle={'docs_json': {'c6988535-b97b-4698-9edd-81a411a34f2e': {'version…" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "import time\n", "import panel as pn\n", @@ -451,143 +301,9 @@ }, { "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.0/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ] - }, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "1dbadddd-9c72-4048-9b25-f0243041326f" - } - }, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "b1a5aa7dfd4f4b1aa8b363a40bbc0f6f", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "BokehModel(combine_events=True, render_bundle={'docs_json': {'5c3303d1-50ef-4d08-80ca-f5f3daab1588': {'version…" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "import llama_cpp\n", "import panel as pn\n", @@ -634,143 +350,9 @@ }, { "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.4.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {}, 'shim': {}});\n root._bokeh_is_loading = css_urls.length + 0;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.4.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.4.0.min.js\", \"https://cdn.holoviz.org/panel/1.4.0/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ] - }, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "a3664db1-6e55-4f4a-b2c1-5ff889950e27" - } - }, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4e2c5ccdc0cb410e88f0f1e8f9e8180d", - "version_major": 2, - "version_minor": 0 - }, - "text/plain": [ - "BokehModel(combine_events=True, render_bundle={'docs_json': {'f2849008-b11d-47e6-a0b5-f45b0673da05': {'version…" - ] - }, - "execution_count": 53, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "import llama_cpp\n", "import panel as pn\n", @@ -824,27 +406,9 @@ }, { "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Launching server at http://localhost:57205\n" - ] - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], + "execution_count": null, + "metadata": {}, + "outputs": [], "source": [ "template = pn.template.FastListTemplate(main=[chat], title=\"Chatbot\", accent=\"#A01346\")\n", "template.show()" From 49439c4e44713a57851b32eff6aeb3c09b378f76 Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Fri, 10 May 2024 00:25:10 -0700 Subject: [PATCH 3/4] add env and exllama --- 06-panel-intro.ipynb | 374 ++++++++++++++++++++++++++++++++++++++----- environment.yml | 7 + 2 files changed, 342 insertions(+), 39 deletions(-) diff --git a/06-panel-intro.ipynb b/06-panel-intro.ipynb index 130f919..b1261b8 100644 --- a/06-panel-intro.ipynb +++ b/06-panel-intro.ipynb @@ -13,7 +13,7 @@ "source": [ "HoloViz is a suite of high-level Python tools that are designed to work together to make visualizing data a breeze, from conducting exploratory data analysis to deploying complex dashboards.\n", "\n", - "The core HoloViz projects are as follow,\n", + "The core HoloViz projects are as follows:\n", "\n", "- [Panel](https://panel.holoviz.org): Create interactive dashboards in Jupyter notebooks or standalone apps\n", "- [hvPlot](https://hvplot.holoviz.org): Quickly and interactively explore data with a familiar API\n", @@ -289,14 +289,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Awesome! Now let's make it much more interesting by connecting an LLM, like the quantized Mistral Instruct 7B model through llama-cpp-python (so no API key necessary)!\n", + "Awesome! Now let's make it much more interesting by connecting an LLM, like the quantized Mistral Instruct 7B model through ExLlama (so no API key necessary)!\n", "\n", "Here, we:\n", - "1. download the quantized model (if it doesn't exist already)\n", - "2. instantiate the model with `Llama`\n", - "3. serialize all messages into `transformers` format\n", - "4. calls the chat completion Openai-like API on the messages\n", - "5. stream the chunks" + "1. download the quantized model (if it doesn't exist already) in exl2 format\n", + "2. instantiate the model; first checking the cache\n", + "3. calls the chat completion through the streaming generator\n", + "4. stream the chunks" ] }, { @@ -304,10 +303,295 @@ "execution_count": null, "metadata": {}, "outputs": [], + "source": [ + "import panel as pn\n", + "from huggingface_hub import snapshot_download\n", + "from exllamav2 import(\n", + " ExLlamaV2,\n", + " ExLlamaV2Config,\n", + " ExLlamaV2Cache,\n", + " ExLlamaV2Tokenizer,\n", + ")\n", + "\n", + "from exllamav2.generator import (\n", + " ExLlamaV2BaseGenerator,\n", + " ExLlamaV2Sampler\n", + ")\n", + "from exllamav2.generator import ExLlamaV2Sampler, ExLlamaV2StreamingGenerator\n", + "\n", + "model_directory = snapshot_download(\n", + " repo_id=\"turboderp/Mistral-7B-v0.2-exl2\", revision=\"2.5bpw\"\n", + ") # 1.\n", + "\n", + "# 2.\n", + "if model_directory in pn.state.cache:\n", + " generator = pn.state.cache[model_directory]\n", + "else:\n", + " config = ExLlamaV2Config()\n", + " config.model_dir = model_directory\n", + " config.prepare()\n", + " model = ExLlamaV2(config)\n", + " cache = ExLlamaV2Cache(model, lazy=True)\n", + " model.load_autosplit(cache)\n", + " tokenizer = ExLlamaV2Tokenizer(config)\n", + " generator = ExLlamaV2BaseGenerator(model, cache, tokenizer)\n", + " settings = ExLlamaV2Sampler.Settings()\n", + " settings.temperature = 0.85\n", + " settings.top_k = 50\n", + " settings.top_p = 0.8\n", + " settings.token_repetition_penalty = 1.01\n", + " settings.disallow_tokens(tokenizer, [tokenizer.eos_token_id])\n", + " generator = ExLlamaV2StreamingGenerator(model, cache, tokenizer)\n", + " pn.state.cache[model_directory] = generator\n", + "\n", + "\n", + "def stream_response(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " input_ids = tokenizer.encode(contents, add_bos=False)\n", + " generator.begin_stream_ex(input_ids, settings)\n", + "\n", + " message = \"\"\n", + " for _ in range(256):\n", + " result = generator.stream_ex()\n", + " if result[\"eos\"]:\n", + " break\n", + " message += result[\"chunk\"] # 4.\n", + " yield message\n", + "\n", + "\n", + "chat = pn.chat.ChatInterface(callback=stream_response)\n", + "chat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For posterity, we can use `llama-cpp-python` for quantized models too!\n", + "\n", + "`llama-cpp` can run on both CPU and GPU, and has an API that mimics OpenAI's API. Personally, I use it because I don't have any spare GPUs lying around and it runs extremely well on my local Mac M2 Pro! It also handles chat template formats internally so it's just a matter of specifying a the proper `chat_format` key.\n", + "\n", + "Here, we:\n", + "1. download the quantized model (if it doesn't exist already) in GGUF format\n", + "2. instantiate the model; first checking the cache\n", + "3. serialize all messages into `transformers` format (new)\n", + "4. calls the chat completion Openai-like API on the messages\n", + "5. stream the chunks" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.4'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.4.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.4.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.4.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.4.min.js\", \"https://cdn.holoviz.org/panel/1.3.8/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", + "application/vnd.holoviews_load.v0+json": "" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "148e04ca-3d33-4860-bac7-1cd1af00a92d" + } + }, + "output_type": "display_data" + }, + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "ChatInterface(_button_data={'send': _ChatButtonData(i...}, _buttons={'send': Button(align='cen...}, _input_container=Row, _input_layout=Row, _placeholder=ChatMessage, _widgets={'TextInput': TextInput(cs...}, callback==0.4.13 - httpx_sse @@ -18,9 +21,13 @@ dependencies: - python-pptx - tiktoken - torch ==2.2.* + - openai + - llama-cpp-python @ + https://github.com/abetlen/llama-cpp-python/releases/download/v0.2.72-cu121/llama_cpp_python-0.2.72-cp311-cp311-linux_x86_64.whl - exllamav2 @ https://github.com/turboderp/exllamav2/releases/download/v0.0.18/exllamav2-0.0.18+cu121-cp311-cp311-linux_x86_64.whl - jupyterlab_nvdashboard - ipykernel - iprogress - ipywidgets +variables: {} From aff2030cb5f74edc1fab3d969e9ca787f181362d Mon Sep 17 00:00:00 2001 From: Andrew Huang Date: Fri, 10 May 2024 11:43:43 -0700 Subject: [PATCH 4/4] split notebooks --- 04-panel-intro.ipynb | 397 +++++++++++++++++++ 05-panel-local-llm.ipynb | 315 ++++++++++++++++ 06-panel-intro.ipynb | 797 --------------------------------------- 3 files changed, 712 insertions(+), 797 deletions(-) create mode 100644 04-panel-intro.ipynb create mode 100644 05-panel-local-llm.ipynb delete mode 100644 06-panel-intro.ipynb diff --git a/04-panel-intro.ipynb b/04-panel-intro.ipynb new file mode 100644 index 0000000..8c2545c --- /dev/null +++ b/04-panel-intro.ipynb @@ -0,0 +1,397 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Intro to HoloViz" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "HoloViz is a suite of high-level Python tools that are designed to work together to make visualizing data a breeze, from conducting exploratory data analysis to deploying complex dashboards.\n", + "\n", + "The core HoloViz projects are as follows:\n", + "\n", + "- [Panel](https://panel.holoviz.org): Create interactive dashboards in Jupyter notebooks or standalone apps\n", + "- [hvPlot](https://hvplot.holoviz.org): Quickly and interactively explore data with a familiar API\n", + "- [HoloViews](https://holoviews.org): Interactive plotting experience\n", + "- [GeoViews](http://geoviews.org): Geographic extension of HoloViews\n", + "- [Datashader](https://datashader.org): Render big data images in a browser\n", + "- [Lumen](https://lumen.holoviz.org/): Construct no-code dashboards from simple YAML specifications\n", + "- [Colorcet](https://colorcet.holoviz.org/): Plot with perceptually based colormaps\n", + "- [Param](https://param.holoviz.org): Declaratively code in Python" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What is Panel\n", + "\n", + "Today, the focus is on Panel.\n", + "\n", + "Panel packs many pre-built frontend components that are **usable with Python**.\n", + "\n", + "That means you can convert your static Python scripts into interactive ones--**no Javascript necessary**!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import panel as pn\n", + "pn.extension()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Basic Panel Tutorial\n", + "\n", + "Let's start out building an interactive app that allows the user to print a custom message.\n", + "\n", + "Currently it's hard coded to `\"Hello World\"`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(\"Hello World!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Widget\n", + "\n", + "We can give the user more control by introducing a `TextInput` widget." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "message_input = pn.widgets.TextInput(value=\"Hello World!\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Interactivity\n", + "\n", + "Then, we can `pn.bind` the widget's `param.value` to the callback, `echo_message`, which simply echos the input value on change.\n", + "\n", + "Note: it's important to prefix `value` with `param`--without it, there will be no updates!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def echo_message(message):\n", + " return f\"{message}\"\n", + "\n", + "message_ref = pn.bind(echo_message, message=message_input.param.value)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Layout\n", + "\n", + "Next, create a simple layout to see the results.\n", + "\n", + "Try typing unique in the widget to see the message update!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pn.Column(message_input, message_ref)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Recap\n", + "\n", + "To recap, we:\n", + "\n", + "1. instantiated a widget (`TextInput`).\n", + "2. defined a function `echo_message`\n", + "3. bounded the function to the widget's *param* value\n", + "4. laid out the the widget and the bound reference\n", + "\n", + "![recap](images/recap.png)\n", + "\n", + "Here's all the code cells collected into one!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import panel as pn\n", + "pn.extension()\n", + "\n", + "message_input = pn.widgets.TextInput(value=\"Hello World!\")\n", + "\n", + "def echo_message(message):\n", + " return f\"{message}\"\n", + "\n", + "message_ref = pn.bind(echo_message, message=message_input.param.value)\n", + "\n", + "pn.Column(message_input, message_ref)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Challenge\n", + "\n", + "Doing this repeatedly is key to creating more complex apps with Panel, so let's do a quick exercise.\n", + "\n", + "Your goal is to create a widget that will toggle the message to upper case if activated by filling out the ellipses (`...`)!\n", + "\n", + "Hint: check out the [Component gallery](https://panel.holoviz.org/reference/index.html) to see what widgets are available to accomplish this goal (one of them starts with a `T`, but there are multiple solutions!)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import panel as pn\n", + "pn.extension()\n", + "\n", + "message_input = pn.widgets.TextInput(value=\"Hello World!\")\n", + "toggle_upper = ... # Fill this out\n", + "\n", + "def echo_message(message, toggle_upper):\n", + " ... # Fill this out\n", + " return f\"{message}\"\n", + "\n", + "message_ref = pn.bind(echo_message, message=message_input.param.value, toggle_upper=...) # Fill this out\n", + "\n", + "pn.Column(message_input, message_ref)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Congrats on building an interactive Panel app! 🎉" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Introducing Panel ChatInterface" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, introducing `pn.chat.ChatInterface`, which is a component that packages all the steps you just learned to provide convenient features for developing a Chat UI with LLMs!\n", + "\n", + "### Widget\n", + "\n", + "Try typing a message and pressing enter to send!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "chat = pn.chat.ChatInterface()\n", + "chat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You might have noticed that it echoes the message you entered, but it doesn't reply... not fun (yet).\n", + "\n", + "### Interactivity\n", + "\n", + "To make it reply, all we have to do is set a `callback`, like `pn.bind`, but with a caveat: it needs these three arguments: `contents`, `user`, and `instance`.\n", + "\n", + "Now when you try sending a message in the chat interface, it will be echoed back in italics!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def echo_message(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " return f\"{contents}\"\n", + "\n", + "chat.callback = echo_message" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Streaming\n", + "\n", + "You might have seen services, like OpenAI and Mistral, stream tokens as they arrive.\n", + "\n", + "We can simulate streaming tokens by looping through the contents of the user's input, concatenating the characters to the final message, and `yield`ing it in italics.\n", + "\n", + "Since there's no serious computation, it'll run too fast for us to perceive streaming--thus `time.sleep`.\n", + "\n", + "Here's the latest code collected into one (and also `callback` within instantation)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import panel as pn\n", + "pn.extension()\n", + "\n", + "def stream_echo_message(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " message = \"\"\n", + " for char in contents:\n", + " time.sleep(0.1) # to simulate a serious computation\n", + " message += char\n", + " yield f\"{message}\"\n", + "\n", + "chat = pn.chat.ChatInterface(callback=stream_echo_message)\n", + "chat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### More Interactivity\n", + "\n", + "`pn.chat.ChatInterface` can be used with other widgets too!\n", + "\n", + "Here, we include a `pn.widgets.FloatSlider` to control how long to wait between each character streamed." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import panel as pn\n", + "pn.extension()\n", + "\n", + "def stream_echo_message(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " message = \"\"\n", + " for char in contents:\n", + " time.sleep(slider.value) # to simulate a serious computation\n", + " message += char\n", + " yield f\"{message}\"\n", + "\n", + "slider = pn.widgets.FloatSlider(start=0.01, value=0.5, name=\"Sleep (s)\", align=\"center\")\n", + "chat = pn.chat.ChatInterface(callback=stream_echo_message, min_height=350)\n", + "\n", + "pn.Column(slider, chat)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Other Inputs\n", + "\n", + "`pn.chat.ChatInterface` also supports multi-modal inputs, like images, videos, PDFs, and more!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from io import BytesIO\n", + "import panel as pn\n", + "\n", + "pn.extension()\n", + "\n", + "def display_info(contents: BytesIO, user: str, instance: pn.chat.ChatInterface):\n", + " size = len(contents.getvalue())\n", + " return f\"Size of input: {size / (1024 * 1024):.2f} MB\"\n", + "\n", + "file_input = pn.widgets.FileInput(accept=\".jpeg,.png,.gif,.mp4,.pdf\")\n", + "chat = pn.chat.ChatInterface(widgets=[file_input], callback=display_info)\n", + "chat" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That's it for a crash course on Panel! These techniques, used repeatedly, will allow you to build increasingly complex web apps with just Python.\n", + "\n", + "To learn more about `pn.chat.ChatInterface`, click [here](https://panel.holoviz.org/reference/chat/ChatInterface.html). It inherits from `pn.chat.ChatFeed`, so check that out [here](https://panel.holoviz.org/reference/chat/ChatFeed.html) too!\n", + "\n", + "For more tutorials delving into Panel in general, click [here](https://panel.holoviz.org/tutorials/index.html) or check out the app gallery [here](https://panel.holoviz.org/gallery/index.html).\n", + "\n", + "There is also a HoloViz Discourse if you want to ask questions [here](https://discourse.holoviz.org/)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ahuang@anaconda.com-ahuang@anaconda.com-ragna-panel-presentations", + "language": "python", + "name": "conda-env-ahuang_anaconda.com-ahuang_anaconda.com-ragna-panel-presentations-py" + }, + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/05-panel-local-llm.ipynb b/05-panel-local-llm.ipynb new file mode 100644 index 0000000..c4266ca --- /dev/null +++ b/05-panel-local-llm.ipynb @@ -0,0 +1,315 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Local LLMs with Panel" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In the [previous notebook](04-panel-intro.ipynb), `pn.chat.ChatInterface` was introduced with a callback that simply echoed the sent message.\n", + "\n", + "In this section, we will make it much more interesting by connecting a local LLM, specfically Llama-3 from earlier.\n", + "\n", + "## ExLlama2\n", + "\n", + "### Initialize\n", + "\n", + "Let's first initialize the model." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from local_llm import Llama38BInstruct\n", + "from ragna import Rag, source_storages\n", + "import panel as pn\n", + "pn.extension()\n", + "\n", + "documents = [\n", + " \"files/psf-report-2021.pdf\",\n", + " \"files/psf-report-2022.pdf\",\n", + "]\n", + "\n", + "chat = Rag().chat(\n", + " documents=documents,\n", + " source_storage=source_storages.Chroma,\n", + " assistant=Llama38BInstruct,\n", + ")\n", + "\n", + "await chat.prepare();" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Migrate\n", + "\n", + "We can first do a test run to see if it works with the example from before." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "message = await chat.answer(\"Who is the Python Developer in Residence?\", stream=True)\n", + "\n", + "async for chunk in message:\n", + " print(chunk, end=\"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, let's migrate this functionality into `pn.chat.ChatInterface` with a callback.\n", + "\n", + "To do this, we copy paste the prior cell's code into a function, and then:\n", + "\n", + "1. prefix the `def` with `async` to make it async\n", + "2. replace the hard-coded string with `contents`\n", + "3. concatenate the chunks into a `response` string\n", + "4. yield the `response`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "async def reply(contents, user, instance):\n", + " message = await chat.answer(contents, stream=True)\n", + "\n", + " response = \"\"\n", + " async for chunk in message:\n", + " response += chunk\n", + " yield response\n", + "\n", + "chat_interface = pn.chat.ChatInterface(callback=reply)\n", + "chat_interface" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now try entering \"Who is the Python Developer in Residence?\" into the chat. It should give you a similar response as before!" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## LlamaCpp" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For posterity, we can use `llama-cpp-python` for quantized models too!\n", + "\n", + "`llama-cpp` can run on both CPU and GPU, and has an API that mimics OpenAI's API.\n", + "\n", + "Personally, I use it because I don't have any spare GPUs lying around and it runs extremely well on my local Mac M2 Pro! It also handles chat template formats internally so it's just a matter of specifying a the proper `chat_format` key.\n", + "\n", + "Here, we:\n", + "1. download the quantized model (if it doesn't exist already) in GGUF format\n", + "2. instantiate the model; first checking the cache\n", + "3. serialize all messages into `transformers` format (new)\n", + "4. calls the chat completion Openai-like API on the messages\n", + "5. stream the chunks" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "\n", + "import llama_cpp\n", + "import panel as pn\n", + "from huggingface_hub import hf_hub_download\n", + "pn.extension()\n", + "\n", + "model_path = hf_hub_download(\n", + " \"TheBloke/Mistral-7B-Instruct-v0.2-GGUF\",\n", + " \"mistral-7b-instruct-v0.2.Q5_K_M.gguf\",\n", + " local_dir=str(Path.home() / \"shared/analyst/models\")\n", + ") # 1.\n", + "\n", + "# 2.\n", + "if model_path in pn.state.cache:\n", + " llama = pn.state.cache[model_path]\n", + "else:\n", + " llama = llama_cpp.Llama(\n", + " model_path=model_path,\n", + " n_gpu_layers=-1,\n", + " chat_format=\"mistral-instruct\",\n", + " n_ctx=2048,\n", + " logits_all=True,\n", + " verbose=False,\n", + " )\n", + " pn.state.cache[model_path] = llama\n", + "\n", + "def reply(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " messages = instance.serialize() # 3.\n", + " message = llama.create_chat_completion_openai_v1(messages=messages, stream=True) # 4.\n", + "\n", + " response = \"\"\n", + " for chunk in message:\n", + " part = chunk.choices[0].delta.content or \"\"\n", + " response += part\n", + " yield response # 5.\n", + "\n", + "chat_interface = pn.chat.ChatInterface(callback=reply)\n", + "chat_interface" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can even give the model a personality by setting a system message!\n", + "\n", + "Update the callback with the a system message.\n", + "\n", + "Note, Mistral Instruct does NOT support the `system` role so we use `user` instead." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "system_message = \"You are an excessively passionate Pythonista.\"\n", + "\n", + "def reply(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " messages = [\n", + " {\"role\": \"user\", \"content\": system_message} # updated here\n", + " ] + instance.serialize()\n", + " message = llama.create_chat_completion_openai_v1(messages=messages, stream=True)\n", + "\n", + " response = \"\"\n", + " for chunk in message:\n", + " part = chunk.choices[0].delta.content or \"\"\n", + " response += part\n", + " yield response\n", + "\n", + "chat_interface.callback = reply\n", + "chat_interface" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Challenge\n", + "\n", + "Your turn! Try aggregating all you've learned to customize the personality of the chatbot on the go!\n", + "\n", + "Again, replace the ellipses with the appropriate code snippets!" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import llama_cpp\n", + "import panel as pn\n", + "from pydantic import BaseModel\n", + "from huggingface_hub import hf_hub_download\n", + "\n", + "pn.extension()\n", + "\n", + "model_path = hf_hub_download(\n", + " \"TheBloke/Mistral-7B-Instruct-v0.2-GGUF\",\n", + " \"mistral-7b-instruct-v0.2.Q5_K_M.gguf\",\n", + " local_dir=str(Path.home() / \"shared/analyst/models\")\n", + ")\n", + "\n", + "if model_path in pn.state.cache:\n", + " llama = pn.state.cache[model_path]\n", + "else:\n", + " llama = llama_cpp.Llama(\n", + " model_path=model_path,\n", + " n_gpu_layers=-1,\n", + " chat_format=\"mistral-instruct\",\n", + " n_ctx=2048,\n", + " logits_all=True,\n", + " verbose=False,\n", + " )\n", + " pn.state.cache[model_path] = llama\n", + "\n", + "def reply(contents: str, user: str, instance: pn.chat.ChatInterface):\n", + " messages = [\n", + " {\"role\": \"user\", \"content\": ...} # Fill this out\n", + " ] + instance.serialize()\n", + " message = llama.create_chat_completion_openai_v1(\n", + " messages=messages, stream=True\n", + " )\n", + "\n", + " response = \"\"\n", + " for chunk in message:\n", + " part = chunk.choices[0].delta.content or \"\"\n", + " response += part\n", + " yield response\n", + "\n", + "\n", + "system_input = ... # Fill this out\n", + "chat_interface = pn.chat.ChatInterface(callback=reply, min_height=350)\n", + "layout = pn.Column(\n", + " system_input,\n", + " chat_interface,\n", + ")\n", + "layout" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "That's all for now. Click [here](https://holoviz-topics.github.io/panel-chat-examples/) to see more on how you can integrate `pn.chat.ChatInterface` with other services!\n", + "\n", + "Again, there is also a HoloViz Discourse if you want to ask questions [here](https://discourse.holoviz.org/)." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "ahuang@anaconda.com-ahuang@anaconda.com-ragna-panel-presentations", + "language": "python", + "name": "conda-env-ahuang_anaconda.com-ahuang_anaconda.com-ragna-panel-presentations-py" + }, + "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.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/06-panel-intro.ipynb b/06-panel-intro.ipynb deleted file mode 100644 index b1261b8..0000000 --- a/06-panel-intro.ipynb +++ /dev/null @@ -1,797 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Intro to HoloViz" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "HoloViz is a suite of high-level Python tools that are designed to work together to make visualizing data a breeze, from conducting exploratory data analysis to deploying complex dashboards.\n", - "\n", - "The core HoloViz projects are as follows:\n", - "\n", - "- [Panel](https://panel.holoviz.org): Create interactive dashboards in Jupyter notebooks or standalone apps\n", - "- [hvPlot](https://hvplot.holoviz.org): Quickly and interactively explore data with a familiar API\n", - "- [HoloViews](https://holoviews.org): Interactive plotting experience\n", - "- [GeoViews](http://geoviews.org): Geographic extension of HoloViews\n", - "- [Datashader](https://datashader.org): Render big data images in a browser\n", - "- [Lumen](https://lumen.holoviz.org/): Construct no-code dashboards from simple YAML specifications\n", - "- [Colorcet](https://colorcet.holoviz.org/): Plot with perceptually based colormaps\n", - "- [Param](https://param.holoviz.org): Declaratively code in Python" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## What is Panel\n", - "\n", - "Today, the focus is on Panel.\n", - "\n", - "Panel packs many pre-built frontend components that are **usable with Python**.\n", - "\n", - "That means you can convert your static Python scripts into interactive ones--**no Javascript necessary**!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import panel as pn\n", - "pn.extension()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Basic Panel Tutorial\n", - "\n", - "Let's start out building an interactive app that allows the user to print a custom message.\n", - "\n", - "Currently it's hard coded to `\"Hello World\"`." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(\"Hello World!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can give the user more control by introducing a `TextInput` widget." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "message_input = pn.widgets.TextInput(value=\"Hello World!\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Then, we can `pn.bind` the widget's `param.value` to the callback, `echo_message`, which simply echos the input value on change.\n", - "\n", - "Note: it's important to prefix `value` with `param`--without it, there will be no updates!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def echo_message(message):\n", - " return f\"{message}\"\n", - "\n", - "message_ref = pn.bind(echo_message, message=message_input.param.value)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, create a simple layout to see the results.\n", - "\n", - "Try typing unique in the widget to see the message update!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "pn.Column(message_input, message_ref)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To recap, we:\n", - "\n", - "1. instantiated a widget (`TextInput`).\n", - "2. defined a function `echo_message`\n", - "3. bounded the function to the widget's *param* value\n", - "4. laid out the the widget and the bound reference\n", - "\n", - "![recap](images/.png)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Here's all the code cells collected into one!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import panel as pn\n", - "pn.extension()\n", - "\n", - "message_input = pn.widgets.TextInput(value=\"Hello World!\")\n", - "\n", - "def echo_message(message):\n", - " return f\"{message}\"\n", - "\n", - "message_ref = pn.bind(echo_message, message=message_input.param.value)\n", - "\n", - "pn.Column(message_input, message_ref)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Doing this repeatedly is key to creating more complex apps with Panel, so let's do a quick exercise.\n", - "\n", - "Your goal is to create a widget that will toggle the message to upper case if activated by filling out the ellipses (`...`)!\n", - "\n", - "Hint: check out the [Component gallery](https://panel.holoviz.org/reference/index.html) to see what widgets are available to accomplish this goal (one of them starts with a T, but there are multiple solutions!)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import panel as pn\n", - "pn.extension()\n", - "\n", - "message_input = pn.widgets.TextInput(value=\"Hello World!\")\n", - "toggle_upper = ...\n", - "\n", - "def echo_message(message, toggle_upper):\n", - " ...\n", - " return f\"{message}\"\n", - "\n", - "message_ref = pn.bind(echo_message, message=message_input.param.value, toggle_upper=...)\n", - "\n", - "pn.Column(message_input, message_ref)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Congrats on building an interactive Panel app! 🎉" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Basic Panel ChatInterface" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, introducing `pn.chat.ChatInterface`, which is a component that packages all the steps you just learned to provide convenient features for developing a Chat UI with LLMs!\n", - "\n", - "Try typing a message and pressing enter to send!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "chat = pn.chat.ChatInterface()\n", - "chat" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You might have noticed that it echoes the message you entered, but it doesn't reply... not fun (yet).\n", - "\n", - "To make it reply, all we have to do is set a `callback`, like `pn.bind`, but with a caveat: it needs these three arguments: `contents`, `user`, and `instance`.\n", - "\n", - "Now when you try sending a message in the chat interface, it will be echoed back in italics!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def echo_message(contents: str, user: str, instance: pn.chat.ChatInterface):\n", - " return f\"{contents}\"\n", - "\n", - "chat.callback = echo_message" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "You might have seen services, like OpenAI and Mistral, stream tokens as they arrive.\n", - "\n", - "We can simulate streaming tokens by looping through the contents of the user's input, concatenating the characters to the final message, and `yield`ing it.\n", - "\n", - "Since there's no serious computation, it'll run too fast for us to perceive streaming--thus `time.sleep`.\n", - "\n", - "Here's the latest code collected into one (and also `callback` within instantation)." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import time\n", - "import panel as pn\n", - "pn.extension()\n", - "\n", - "def stream_echo_message(contents: str, user: str, instance: pn.chat.ChatInterface):\n", - " message = \"\"\n", - " for char in contents:\n", - " time.sleep(0.1) # to simulate a serious computation\n", - " message += char\n", - " yield f\"{message}\"\n", - "\n", - "chat = pn.chat.ChatInterface(callback=stream_echo_message)\n", - "chat" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Awesome! Now let's make it much more interesting by connecting an LLM, like the quantized Mistral Instruct 7B model through ExLlama (so no API key necessary)!\n", - "\n", - "Here, we:\n", - "1. download the quantized model (if it doesn't exist already) in exl2 format\n", - "2. instantiate the model; first checking the cache\n", - "3. calls the chat completion through the streaming generator\n", - "4. stream the chunks" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import panel as pn\n", - "from huggingface_hub import snapshot_download\n", - "from exllamav2 import(\n", - " ExLlamaV2,\n", - " ExLlamaV2Config,\n", - " ExLlamaV2Cache,\n", - " ExLlamaV2Tokenizer,\n", - ")\n", - "\n", - "from exllamav2.generator import (\n", - " ExLlamaV2BaseGenerator,\n", - " ExLlamaV2Sampler\n", - ")\n", - "from exllamav2.generator import ExLlamaV2Sampler, ExLlamaV2StreamingGenerator\n", - "\n", - "model_directory = snapshot_download(\n", - " repo_id=\"turboderp/Mistral-7B-v0.2-exl2\", revision=\"2.5bpw\"\n", - ") # 1.\n", - "\n", - "# 2.\n", - "if model_directory in pn.state.cache:\n", - " generator = pn.state.cache[model_directory]\n", - "else:\n", - " config = ExLlamaV2Config()\n", - " config.model_dir = model_directory\n", - " config.prepare()\n", - " model = ExLlamaV2(config)\n", - " cache = ExLlamaV2Cache(model, lazy=True)\n", - " model.load_autosplit(cache)\n", - " tokenizer = ExLlamaV2Tokenizer(config)\n", - " generator = ExLlamaV2BaseGenerator(model, cache, tokenizer)\n", - " settings = ExLlamaV2Sampler.Settings()\n", - " settings.temperature = 0.85\n", - " settings.top_k = 50\n", - " settings.top_p = 0.8\n", - " settings.token_repetition_penalty = 1.01\n", - " settings.disallow_tokens(tokenizer, [tokenizer.eos_token_id])\n", - " generator = ExLlamaV2StreamingGenerator(model, cache, tokenizer)\n", - " pn.state.cache[model_directory] = generator\n", - "\n", - "\n", - "def stream_response(contents: str, user: str, instance: pn.chat.ChatInterface):\n", - " input_ids = tokenizer.encode(contents, add_bos=False)\n", - " generator.begin_stream_ex(input_ids, settings)\n", - "\n", - " message = \"\"\n", - " for _ in range(256):\n", - " result = generator.stream_ex()\n", - " if result[\"eos\"]:\n", - " break\n", - " message += result[\"chunk\"] # 4.\n", - " yield message\n", - "\n", - "\n", - "chat = pn.chat.ChatInterface(callback=stream_response)\n", - "chat" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "For posterity, we can use `llama-cpp-python` for quantized models too!\n", - "\n", - "`llama-cpp` can run on both CPU and GPU, and has an API that mimics OpenAI's API. Personally, I use it because I don't have any spare GPUs lying around and it runs extremely well on my local Mac M2 Pro! It also handles chat template formats internally so it's just a matter of specifying a the proper `chat_format` key.\n", - "\n", - "Here, we:\n", - "1. download the quantized model (if it doesn't exist already) in GGUF format\n", - "2. instantiate the model; first checking the cache\n", - "3. serialize all messages into `transformers` format (new)\n", - "4. calls the chat completion Openai-like API on the messages\n", - "5. stream the chunks" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "data": { - "application/javascript": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.3.4'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var reloading = false;\n var Bokeh = root.Bokeh;\n\n if (typeof (root._bokeh_timeout) === \"undefined\" || force) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n }\n if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n run_callbacks();\n return null;\n }\n if (!reloading) {\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error() {\n console.error(\"failed to load \" + url);\n }\n\n var skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock', 'gridstack': 'https://cdn.jsdelivr.net/npm/gridstack@7.2.3/dist/gridstack-all', 'notyf': 'https://cdn.jsdelivr.net/npm/notyf@3/notyf.min'}, 'shim': {'jspanel': {'exports': 'jsPanel'}, 'gridstack': {'exports': 'GridStack'}}});\n require([\"jspanel\"], function(jsPanel) {\n\twindow.jsPanel = jsPanel\n\ton_load()\n })\n require([\"jspanel-modal\"], function() {\n\ton_load()\n })\n require([\"jspanel-tooltip\"], function() {\n\ton_load()\n })\n require([\"jspanel-hint\"], function() {\n\ton_load()\n })\n require([\"jspanel-layout\"], function() {\n\ton_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n\ton_load()\n })\n require([\"jspanel-dock\"], function() {\n\ton_load()\n })\n require([\"gridstack\"], function(GridStack) {\n\twindow.GridStack = GridStack\n\ton_load()\n })\n require([\"notyf\"], function() {\n\ton_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n var existing_stylesheets = []\n var links = document.getElementsByTagName('link')\n for (var i = 0; i < links.length; i++) {\n var link = links[i]\n if (link.href != null) {\n\texisting_stylesheets.push(link.href)\n }\n }\n for (var i = 0; i < css_urls.length; i++) {\n var url = css_urls[i];\n if (existing_stylesheets.indexOf(url) !== -1) {\n\ton_load()\n\tcontinue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window['jsPanel'] !== undefined) && (!(window['jsPanel'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.3.8/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['GridStack'] !== undefined) && (!(window['GridStack'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/gridstack/gridstack@7.2.3/dist/gridstack-all.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } if (((window['Notyf'] !== undefined) && (!(window['Notyf'] instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.3.8/dist/bundled/notificationarea/notyf@3/notyf.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(urls[i])\n }\n } var existing_scripts = []\n var scripts = document.getElementsByTagName('script')\n for (var i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n\texisting_scripts.push(script.src)\n }\n }\n for (var i = 0; i < js_urls.length; i++) {\n var url = js_urls[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (var i = 0; i < js_modules.length; i++) {\n var url = js_modules[i];\n if (skip.indexOf(url) !== -1 || existing_scripts.indexOf(url) !== -1) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n var url = js_exports[name];\n if (skip.indexOf(url) >= 0 || root[name] != null) {\n\tif (!window.requirejs) {\n\t on_load();\n\t}\n\tcontinue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n var js_urls = [\"https://cdn.bokeh.org/bokeh/release/bokeh-3.3.4.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.3.4.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.3.4.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.3.4.min.js\", \"https://cdn.holoviz.org/panel/1.3.8/dist/panel.min.js\"];\n var js_modules = [];\n var js_exports = {};\n var css_urls = [];\n var inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (var i = 0; i < inline_js.length; i++) {\n\ttry {\n inline_js[i].call(root, root.Bokeh);\n\t} catch(e) {\n\t if (!reloading) {\n\t throw e;\n\t }\n\t}\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n\tvar NewBokeh = root.Bokeh;\n\tif (Bokeh.versions === undefined) {\n\t Bokeh.versions = new Map();\n\t}\n\tif (NewBokeh.version !== Bokeh.version) {\n\t Bokeh.versions.set(NewBokeh.version, NewBokeh)\n\t}\n\troot.Bokeh = Bokeh;\n }} else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n\troot.Bokeh = undefined;\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n\tconsole.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n\trun_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/javascript": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n console.log(message)\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n comm.open();\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n }) \n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n", - "application/vnd.holoviews_load.v0+json": "" - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/html": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ] - }, - "metadata": { - "application/vnd.holoviews_exec.v0+json": { - "id": "148e04ca-3d33-4860-bac7-1cd1af00a92d" - } - }, - "output_type": "display_data" - }, - { - "data": {}, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.holoviews_exec.v0+json": "", - "text/html": [ - "
\n", - "
\n", - "
\n", - "" - ], - "text/plain": [ - "ChatInterface(_button_data={'send': _ChatButtonData(i...}, _buttons={'send': Button(align='cen...}, _input_container=Row, _input_layout=Row, _placeholder=ChatMessage, _widgets={'TextInput': TextInput(cs...}, callback=