{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# hvPlot-Beispiele\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Installation\n", "\n", "Um die Beispiele ausführen zu können, muss zusätzlich [Snappy](https://github.com/google/snappy) installiert werden.\n", "\n", "Mit [Spack](https://www.python4data.science/de/latest/productive/envs/spack/index.html) könnt ihr Snappy in eurem Kernel bereitstellen, z.B. mit:\n", "\n", "``` sh\n", "$ spack env activate python-311\n", "$ spack install snappy\n", "```\n", "\n", "Alternativ könnt ihr Snappy auch mit anderen Paketmanagern installieren, z.B.\n", "\n", "* Für Debian/Ubuntu:\n", "\n", " ``` sh\n", " $ sudo apt install libsnappy-dev\n", " ```\n", "\n", "* Für Windows:\n", "\n", " Snappy benötigt Microsoft Visual C++ ≥ 14.0. Dies kann installiert werden mit den [Microsoft C++ Build Tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/).\n", "\n", "* Für Mac OS:\n", "\n", " ``` sh\n", " $ brew install snappy\n", " ```\n", "\n", "Anschließend sollten für euren Kernel noch weitere Pakete installiert werden, z.B. mit:\n", "\n", " ``` sh\n", " $ pipenv install intake intake-parquet s3fs python-snappy pyviz-comms\n", " …\n", " ```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Einführung\n", "\n", "Als erstes importieren wir NumPy und pandas um anschließend einen kleinen Satz zufälliger Daten zu erstellen:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
ABCD
2000-01-011.4319851.3789130.5395670.257977
2000-01-021.2665730.8340501.1767501.458363
2000-01-031.7992830.9454371.792629-0.220764
2000-01-042.1312480.1603771.186063-0.702810
2000-01-053.5749722.2749261.759324-1.297244
\n", "
" ], "text/plain": [ " A B C D\n", "2000-01-01 1.431985 1.378913 0.539567 0.257977\n", "2000-01-02 1.266573 0.834050 1.176750 1.458363\n", "2000-01-03 1.799283 0.945437 1.792629 -0.220764\n", "2000-01-04 2.131248 0.160377 1.186063 -0.702810\n", "2000-01-05 3.574972 2.274926 1.759324 -1.297244" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import numpy as np\n", "import pandas as pd\n", "\n", "\n", "index = pd.date_range(\"1/1/2000\", periods=1000)\n", "df = pd.DataFrame(\n", " np.random.randn(1000, 4), index=index, columns=list(\"ABCD\")\n", ").cumsum()\n", "\n", "df.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### pandas`.plot ()`-API\n", "\n", "pandas bietet standardmäßig Matplotlib-basiertes Plotten mit der `.plot()`-Methode:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAioAAAGyCAYAAADK7e8AAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/bCgiHAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOyddZwUBf/HP7Od1110I42CiAKiYPCgoj52/kzE7u5+bMRCEQtFUUxQEVHpEES6rjv3tmPm98f07Gzd7d4dd/N+ve51u7Ozs7N3uzOf+cbnS1AURUFBQUFBQUFBoQui6uwdUFBQUFBQUFAIhSJUFBQUFBQUFLosilBRUFBQUFBQ6LIoQkVBQUFBQUGhy6IIFQUFBQUFBYUuiyJUFBQUFBQUFLosilBRUFBQUFBQ6LIoQkVBQUFBQUGhy6IIFQUFBQUFBYUuiyJUFBQUFBQUFLosHSZUnn32WRAEgVtvvZVb5na7MXfuXKSnp8NisWDOnDmoqanpqF1SUFBQUFBQ6OJ0iFDZvHkz3n77bYwYMUK0/LbbbsN3332HpUuXYs2aNaisrMQ555zTEbukoKCgoKCgcBSgSfQL2O12XHzxxXj33Xfx5JNPcstbWlqwcOFCfPrpp5g2bRoA4IMPPsCQIUOwYcMGTJgwIartkySJyspKWK1WEASRkPegoKCgoKCgEF8oikJrayvy8vKgUoWOmyRcqMydOxdnnHEGpk+fLhIqW7duhc/nw/Tp07llgwcPRlFREdavXx9SqHg8Hng8Hu5+RUUFhg4dmrg3oKCgoKCgoJAwysrKUFBQEPLxhAqVJUuWYNu2bdi8eXPQY9XV1dDpdEhJSREtz87ORnV1dchtPvPMM3jssceClpeVlSEpKand+6ygoKCgoKCQeGw2GwoLC2G1WsOulzChUlZWhltuuQW//PILDAZD3LZ733334fbbb+fus280KSlJESoKCgoKCgpHGZHKNhJWTLt161bU1tZizJgx0Gg00Gg0WLNmDV577TVoNBpkZ2fD6/WiublZ9Lyamhrk5OSE3K5er+dEiSJOFBQUFBQUujcJi6icfPLJ2Llzp2jZlVdeicGDB+Oee+5BYWEhtFotVq1ahTlz5gAA9u3bh9LSUkycODFRu6WgoKCgoKBwFJEwoWK1WjF8+HDRMrPZjPT0dG751Vdfjdtvvx1paWlISkrCvHnzMHHixKg7fhQUFBQUFBS6Nwnv+gnHyy+/DJVKhTlz5sDj8WDGjBl48803E/JagUAAPp8vIdvuKmi1WqjV6s7eDQUFBQUFhbhBUBRFdfZOtAebzYbk5GS0tLTI1qtQFIXq6uqgWpjuSkpKCnJychRPGQUFBQWFLk2k8zdLp0ZUOgJWpGRlZcFkMnXbEzhFUXA6naitrQUA5ObmdvIeKSgoKCgotJ9uLVQCgQAnUtLT0zt7dxKO0WgEANTW1iIrK0tJAykoKCgoHPV06+nJbE2KyWTq5D3pONj32t3rcRQUFBQUegbdWqiwdNd0jxw96b0qKCgoKHR/eoRQUVBQUFBQUDg6UYSKgoKCgoKCQpdFESoKCgoKCgoKXRZFqHRh1q9fD7VajTPOOKOzd0VBQUFBQaFTUIRKF2bhwoWYN28e/vjjD1RWVnb27igoKHQj/AESa/bXwe7xt+n5uyttuP6jrThQ0xrnPVNQENOtfVSkUBQFly/QKa9t1Kpj6six2+34/PPPsWXLFlRXV2PRokW4//77E7iHCgoKPYUdZc2YPX8tAOCMY3Ix/+IxMT0/QFKYPf8v+AIUml1eLLlWGSSrkDh6lFBx+QIY+vDKTnnt3Y/PgEkX/Z/7iy++wODBgzFo0CBccskluPXWW3Hfffcp7ccKCgrt5vmVe7nbP+yswvwYn//djkr4AvT0lQ2HG7G/phUDs61x3EMFBR4l9dNFWbhwIS655BIAwMyZM9HS0oI1a9Z08l4pKCh0B7Tq9h36t5Q0iu6f+vIfCJBH9dg4hS5Mj4qoGLVq7H58Rqe9drTs27cPmzZtwtdffw0A0Gg0+O9//4uFCxdiypQpCdpDBQWF7kyr24eFfx3BmSPykGzUcsu16tijtI0Ob9Ayty8As75HnVIUOoge9akiCCKm9EtnsXDhQvj9fuTl5XHLKIqCXq/HG2+8geTk5E7cOwUFhaOR51fsw0cbSvD6bwcxqX8GtzwvxRjzthrswULF4ydh1rdrFxUUZFFSP10Mv9+PxYsX43//+x+2b9/O/ezYsQN5eXn47LPPOnsXFRQUjkK2lDQBoAthGx0ebnmrO/auHzai0jfTzC3z+DunUUGh+6MIlS7G999/j6amJlx99dUYPny46GfOnDlYuHBhZ++igoLCUYhGxad4GgUREXs7hMqL543klnn9ZDv2TkEhNIpQ6WIsXLgQ06dPl03vzJkzB1u2bME///zTCXumoKBwNKMWCJUGQY2JN0DGFA0hSQpNTvr5BSlGpJl1AOjUj4JCIuj6BRs9jO+++y7kY8ceeywoSqmsV1BQiB1hREUqKlrdfugt0RX8t7h8YBt8Ukw66DX09a7HpwgVhcSgRFQUFBQUosTu8WPFv1VwM8aRAZICKWjLpSiqy15MCCMqAKDXqGBlunTkunhCwUZjrAYNdBoVL1SUGhWFBKEIFQUFBYUoeX7FXlz/8TY8vPxfuH0BnPLSGlz47gYAdHvuzFf+xKULN8Ef6HrRBalQSTfr0C/LAgDYV03b4C/bVo631xwKux1W1KQzKR+9ho7EKDUqColCESoKCgoKUbJ4fQkA4Ist5dh4pBGH6x3YeKQRXj+Jw3UO7KtpxV8H6/HDzqpO3tNgnF5xxCPNosPQvCQAwK5KGyiKwu1f7MAzP+3F2oP1ISNDbMcQW5ui4yIqilBRSAyKUFFQUFCIkkECm/gHvt7J3W5x+VBn51t+j9Q7OnS/osEhGT6YatKhbwbdXlze5IRDIGQufm8jXv/toOx22NRPGmOaoqR+FBKNIlQUFBQUouClX/Zjn2BScHmTi7vd4vKhrpUXKjZX2yYSJxKpUBmWlwyrga5RcXkDaHH5RI+/9Mt+2e2wrc1c6kcbW0TlSL0Dr/56AC1OX+SVFRSgdP0oKCgoRKSs0YnXVh0I+XiLyysWKu6udxJuZoTI9/NOAElRGJaXjB+ZFJXD649aOHARFYu4RoUVKhXNLny1tRyXTOjFpYeEPPfTXqzYVY2f/q3CiltPbN+bUugRKEJFQUFBIQI1NnfYx1tcPtS2ukX3uxIOj5+rUemTYeZm8pj1tMhwegNodkXX+RNcTCuOqJz/1npUNLtQ0uDE/84fGfT8lburAQB7q1uDHlNQkENJ/SgoKChEoKLZFfbxZqdPNP/G1sWEChvtMenUosGB7Owzh8cf9T43cjUqkmJapmWb/VtJJyyzpAuiLJ9vLuX2T5qaUlBgUYSKgoKCQgSE9Shy7Ktu5VIrAGBrgy19IqlnCn0zLOKpgWZGqDhlalRC0SARKsKIik/Qll2YapJ9vrCN+Z6vdqK21Y0TnvsNE59Zhb3Vtqj2QaFnoQgVBQUFhQhUtYQXKp9vKRMN+uuqEZVMq1iomJjUj8PjR7NMjYpL0tJs9/ixp4oWE+lc1w+9jRdW7sOwh1dy6yYbtUHb8wXIIBH337c3wOOnl/+5vz6m96XQM1CEShfliiuuAEEQ3E96ejpmzpypzPlRUOgg1h2sx9d/l8MXIFHfKl+/cf64AqgIOvXzbwUfDahodmFXZUtH7WpE2HRMljV0RIVtqZ7UPx2sN1yDQHwBwAd/HeFus8W0IwtTuGVeQUTFLpPKaZJxwBW2cldHqAVS6JkoQqULM3PmTFRVVaGqqgqrVq2CRqPBmWee2dm7paDQJiifD5UPPoiW777v7F2JyKE6Oy56byNu+3wHFv51JOiEzZKfYsKYolTRsj6MN8lLP8u393YGOyto0TQ0N0m0nI2o+EkKSzaXAQAuGF+E3GQjAKDGJn7f6w41cLczmTTSuWMLZF9TTqgIvWbkWPjXEQTIrjmCQKHz6FlChaIAr6Nzftow/0Ov1yMnJwc5OTkYNWoU7r33XpSVlaGuri4BfxwFhcRiW7ESLV9+hcq77ursXYnI8r8ruNtljU7U28WRgKI0EwpSjTh3XAGG54snnT911nAAwJ8H6kVzgDoTVqgcUyDeV5M2eBDhkFwrspNoEfL7vlq8+8dhjHh0JX74p4qLmDx4xhCuiFbKXTMGAQBaZVq0G+yRO4tW7qqOuI5Cz6JntSf7nMDTeZ3z2vdXAjpzm59ut9vx8ccfo3///khPT4/jjikodAyk08ndpgIBEOropvV2Bk2Ceo1Wtx/1Ao+UT685DuN6pUGjIqBSEUFCZXRRKgiCToM0OLxBdSEdDUlSKGuk//b9mdk+LBq1CjqNiitw7ZdpRr9MC3KSDQAgcqed++k25CTRy8f3Tgv5epMHZOCFlftglykoDhWZErK5uBGnH5MbcT2FnkPPiqgcZXz//fewWCywWCywWq349ttv8fnnn0OlUv5tCkcfKgsv1P31DWHW7HwcXv4k++2OSrQyaYwdD5+K4/tlQKdRQcUUchwjECpmnRpGnZqrBamM0NbcETQ4vPAFKBAEkM0IDSGZgk6ghZePB0EQyLIGrwfwNSR5KUbR8r6Z9P92aG4SLEz7c6tM6oet9cmw6DB5QAa3PF+wPbNOg/mrD2L1vtqo3p9C96dnRVS0Jjqy0VmvHSNTp07FggULAABNTU148803cdppp2HTpk3o1atXvPdQQaHdeIuL0bzsa5gnHAfz8ceLHqM8fNi/9ddfkHbxxR29e1Hj9ATPrZnQNw1JxuBD5sBsCyb2Tcf6ww247qR+AIDcZCNqbB5UtbhExaadQXULLS4yLXpo1cEXOcKakF7p9HGKjajIQRC00BDyzqVj8e4fR3DTtP68UHH70er2wWrgu38+3kgPdZw9Kh8PnTkUve/9AQCgVRO4aWp/vLH6IJZsLuVSbcXPnhHz+1XofvQsoUIQ7Uq/dDRmsxn9+/fn7r/33ntITk7Gu+++iyeffLIT90xBQZ66116D7cef0PDOOyh89x1YJk/mHiNdfOqn5oknYTlpCnQF+Z2xmxERRlRY3r+CjjZIIQgC710+DusONWDqoEwAQF6KAdvLgMrmzu9iqWRaq3NDiI9e6SYuUsK+P7ZGRQ6KQtDfoX+WFc+dO4K7X5BqRHmTCzvKWnACEzmpZNxqASBdInRUKoKbOyStB1JQUHIIRxEEQUClUsHl6vxwskLn4a+vh+fwYfnH6urgLaGvWgN2e0fuFgDAV13D3W54b6HoMUryuS257NIO2ae2IPUPuWpSH87FVQ6zXoNThmZDw0Qs8piumUj+Kx1BLSNC5NI+APDCuSMxoW8aPvm/47hlodaNltFMJxRbxLt0SxmOf/Y37vHThtM1KFo1LXiO65OGJBnfFQUFQBEqXRqPx4Pq6mpUV1djz549mDdvHux2O2bNmtXZu6bQiZRdex0On34G7H/+FfTYkTnn4tCMmWj86GPsHzcejYsXd+i+BZqauNuuHTtACbrdSKf4pO2vrOqw/YoVh0SojJB0y0Qil6m56AoRFTZCkRGiqLco3YQl107EpP58zUg4ofLeZeMiviZbo9Ps8sLrJ3HXl7z/08S+6VwL9w83T8bcqf1w3+lDkGRQhIqCPD0r9XOUsWLFCuTm0lceVqsVgwcPxtKlSzFlypTO3TGFToOiKLh37wYAVD/6KPqv+pV7jPR64a+lCxBrnnqK/v30M0i77LIO2z+hUKHcbvjr6qDNyqL3j4moECYTKKYDqKt2/zglqZ9heUkh1pQnj0mzVHaBiArbaZMhM8k4FHJC5e1Lx2LGsJyons/OE3J4/DhUJ47sCdNKA7OtuGvGYADgUj9CSJLiipYVei5KRKWLsmjRIlAUxf3YbDZs2rQJc+bM6exdU+hEKEGLr6+iAs6//+buC0VCZ0AFAgi00KF+Qk+fjHzl5dzjpJs+aaddfhldLwYg0NzcsTsZJQ6mmNai1+DYPmnol2mJ8AwxbFdMVReIqLDeJemW6NukLXoNV2/DYpTxXAn9fNaaP8DVpbA0hxgvkGIKjqgInW4Vei6KUFFQOIrwNzWL7lfdex8oH33gDzR0bstvwGbjjA0Nx9CmZ76yMu5xikn9qC0WqJLoCIX99zUdvJfR4WIiKt/POwFfXDcx5qt6dmBfk7PzC0N5oRJ9RAUAPrjyWLx+4WjuvlEXvVAxCzp/WA8XlksnyHcsDs1Nwjmj8zFSkGbz+BShoqAIFQWFowo2aqIymUDo9fCWlHCFtf7GzouoONavR/EFF9D7ZrVC36cPAMBbJoiosKkfoxEkE3mpeuAB0XYoigLpcKAzKW1wcjUq7Ak3VtgWXelE4c6ATf2wQwRjQShuYouo8KmfFYzT7I1T+mHdvdMwbXCW7HM0ahVe+u8ofDN3EjdryOMPbhNX6HkkVKgsWLAAI0aMQFJSEpKSkjBx4kT89NNP3ONutxtz585Feno6LBYL5syZg5qamjBbVFDo2bCpEm1REbR5tMtyoKUFNc8+h7L/+79O26/SK6+Cr6SU3recHGgLCgEAvrJSbh1WqKiMJhhG8K2spId3K6164EHsn3g817nU0bh9AZz4wmruvlzdRDQIBY5Dxviso6AoClWMj0pWmJbjUGQI0kWxRFRYobKrsgVbS2gBfcaIXOSlGGVbvIUQBMFNZPb45UVei8uHv0ubRMXaCt2XhAqVgoICPPvss9i6dSu2bNmCadOmYfbs2di1axcA4LbbbsN3332HpUuXYs2aNaisrMQ555yTyF1SUDiqcW7bCgBQp6ZAlWQFAJRedjkaFy2SXZ8wtK/NNBp8VeLuHV3fvtAV0UJFFFGx0dOF1UlWFLz2Krfcy0SEKIpCy7JloLxeNC9dmujdlmVbiTgqZYghiiBEp1Fxs3DkhvN1FNU2N5zeADQqAkVpsZtOpgsKcHUyZnGhYIWajbHRH5htwbC86Dun9Fr6tUJFVM57ax3OfnMdft+nzD3rCSRUqMyaNQunn346BgwYgIEDB+Kpp56CxWLBhg0b0NLSgoULF+Kll17CtGnTMHbsWHzwwQdYt24dNmzYkMjdUlA46mj57jtUP/U0mr+gT+DGYcOgtlgjP7EDxi14jxwR3df17QNtAT1R11deDipAn2z8zbQIUKekQJuTA9M4us3Vc+AAAHGNDWEUW7R3FFtK4pc+49MfnZe+OFRLp9GK0kyyrrRCSJcLzV8tg7+xkVuWYuKFSiw+JxZJyqwgNTaRpGdEnjtEjcr+GrqTaPn2CtnHFboXHVajEggEsGTJEjgcDkycOBFbt26Fz+fD9OnTuXUGDx6MoqIirF+/PuR2PB4PbDab6EdBobtTedfdaProI/pkThBIv/6GqCZyU04nKDKxNRK+SvFYCsPAgdBk0J4c/tpa7B0xEu69exFgCoHVqbQZmG4A7brsOUAPvmta8jm3DdLWmtB9DkWNje/Seen8ke3aFnuytnvku1w6gpJGWqj0zojsyF370suoeuABlN98M7dMrSLw482T8fWNxyM5BqFikqSJClJjE56RUj8sASXz0yNIuFDZuXMnLBYL9Ho9rr/+enz99dcYOnQoqqurodPpkJKSIlo/Ozsb1dWhx3w/88wzSE5O5n4KCwsT/A4UFDoXaR7eOHo01BYzSLe49TX9mv9Dn2VfBT2fFHiWsB1C8cK57W9UPfiQeP/GjoU6TTBdNxBA7Qsv8qkfRqjoBwwAQEdU/PX1aHj3Xe4p/rrOGUjHduncM3Mwzh7dPnt/MydUOi+iUmOj63/Cze5haf7ySwCAa8tW0fKheUmc02y0SIcWFrYxoiKX+iEFs4lIpUalR5BwoTJo0CBs374dGzduxA033IDLL78cuxnDqrZw3333oaWlhfspE7Q/Kih0RyiJIMm8eZ7scsPwY2AYOjTo+YHmFlAUheL/XoDDZ86Kq1gpu+460X3jqFHQZmVBpddzXikAOH8VEATUTGuyjhms6asoh3PrNlCColpfTecIlUYHLVTyUyMXfUZCw7SuXPPhFrQ4OyeqUtfKFNKGcKUVEafIm6+6Gs7PPsHrs/g5ZQNzokhTCuBrVIL3yebm/5ZC0aLQfUm4UNHpdOjfvz/Gjh2LZ555BiNHjsSrr76KnJwceL1eNEsMn2pqapCTE9r9UK/Xc11E7I+CQncmIEhv6gf0h3nCBAAQCQ6V2QzzcccCAHp98jF0fftyj3kPHUTDO+/C/e+/8JaUwCswYWsvZCufosl//TX0Wvwh/6Dgatf9778AAHVyMudEqzLRV9mk2wM/0+3HdjJ5Szun66fJQf9N00yxeY7Iwc658QZInPxS5/jF1DIRlcwohIowReg5fCTMmmG24ffj4JSpqHn6GfRat5JbPjhGoWJgUz8yNSqsmASAn/6txsn/+z3Iq0Whe9HhPiokScLj8WDs2LHQarVYtWoV99i+fftQWlqKiRMndvRuKSh0WQLNLdztIsHsnpyHHwI0GmTceCP6/foL1Ewa1TR2LPr9+AOSzjgDAGBfuxZ1L7/Mb09iGtceCB1/QrdOmya6L4cmk58no2I6kii3G/5aWqiYGBEWqKsXCbSOopFJ/aSa2z935rTh/AVXvd0TZs3EUdtKv26WNXzqx3PoECAQvrXPPdem1xN2gKU0VCHVpEWfDHN0ER0Bobp+KIrCxiONomWH6hx49qe9bdpfhaODhAqV++67D3/88QeKi4uxc+dO3Hffffj9999x8cUXIzk5GVdffTVuv/12rF69Glu3bsWVV16JiRMnYgJzsOrpVFdXY968eejbty/0ej0KCwsxa9YskbhT6P6QNlqo6Hr1giaVrxUwjR+PQZs3IfPmeaLlLGwaqGnxR6Ll/ob6uO0b2/5cuPC9oJk96ddcA6jVIvGiHzSYf66efi7pdnOpHn2/vtAws4G8ISZEJwqKotDEXK2nxTAXJxSPzR4muh/ohDRFHSdUwguF5mXLRPd9VVVt8igRjnEgbDb8ftdU/Hjz5JjTaKw53S1LtnP/EwB4+sc9uG/ZzqD1/y7t3PERCokloUKltrYWl112GQYNGoSTTz4ZmzdvxsqVK3HKKacAAF5++WWceeaZmDNnDk488UTk5ORgmeQL01MpLi7G2LFj8dtvv+GFF17Azp07sWLFCkydOhVz587t7N1T6CBcO3ei+ulnAACq5GAfClWYNt6k02aK6kRY4mG1T5EkHBs3cQWyxmHDgtbJvPUWDFy3FgVvvsktMwzhhYrKyEdUfFV055AmKxvafLqItaPrVKpa3PCTFDQqok0urlKkUQzpoMNEQ5IUF8mJZPbmPXgIAKDr3w8A4DlyBPvHH4vmZV/H9JpCoeKvq0OyUStrFOdvauIMAOU4cSA/Z+jn3XxzxXc7+IjN2aPzsfR6Ovpe2eLutDoghcST0OnJCxcuDPu4wWDA/PnzMX/+/ETuBgdFUXD5O2eaqVETW3HejTfeCIIgsGnTJpjNfGvhsGHDcNVVVyViFxW6GBRFofymeVz9hjolesMsgK730PXqBW9xMQA6+kG53fDXt1+o1L8xH/WsAFGrudk9Qgi1GurkZJiOHQ/rjBnwHDwI64yZ/ONs6sfng2sbPVzRMHQI1zEUaGoM2mYi2VdD19v0yTBzZm3t5YHTh+CpH/cAoP1UrIb2p5SipdHphZ+kQBBih1k5PIdooWKZdAIaD9JpINLnQ9X99yP5P7NAaOhThbe8HA3vvYf0K6/kiqGF+CVCRQ5vSQkOn30ODAMHoveSz2TXmTk8B3cu3QEAsLl4gadR88fQojQTxvdOQ36KERXNLuyttuG4vulh36dC7Ng9fpEvToCk4AuQbTZDbAsJFSpdDZffheM+Pa5TXnvjRRth0kbXotfY2IgVK1bgqaeeEokUFmlLt0L3xHvwICdSAMB8XOyfXV2/fpxQMR93HOxr1sQl9eP65x/RfSKMsZxKp0PBq68EL9cLTp4kCV3/ftD36wdNGp3G6uhp0PuraaESa4dKOK45sS9e/nU/nN5AhzvUsoW0aSZdWLM3iqLgYz5n+sGDgx7319RwUa7yG26A58BBOP74E/1W/YpAczNsP/yI5DPPgDolRVT/5K+vB0VRQRdoda++BsrphGv7dtnHAdqD5rKJvbB4fYmoy6eZiZqMKkzBtSfSBeOFabRQqWmNXAfU4vTh3mX/4PzxhZg6SH7mkALPN39X4M6lO3DzyQNw88m0ncAF76zHnqpWbLj/5CBjv0ShDCXsghw8eBAURWGwzEFDoWdA+f0ov2ked98y/WSkMkP/YsHIzNQhtFq+UDUOERXSzUcm2e6dWJHa+xsGDgQAqFNoodLRQxYbmFqIvCg8R2IhhTFK6+iZP7VMa3Kkjh/K6+UKabW5uUGPB+x27jZrzuerrETz51+g5JJLUfPkk6h6+BE4t/0tLsL1+0Ut5yzCglu5x1lYg7kWF71vvgDJib0PrhjP+dSkGOl6opYoJlUv2VyKn/6txpUfbO70YZFHA7d+vh1+ksLi9cXcss3FTbB7/Fh/qOOmtfeoiIpRY8TGizZ22mtHizJoS8H20wpuMF/WnXcgvY0DB1MvvggqixnWk0+Ga/t2AIBfUqNCulxha13kIFv4jpy8F55v074RKhUIrZZrs9YWFgGAIPUTm1DxNzWh/vU3YJo4AdapU7l0RbSwJ8G2TkwOhUkwSbgjYQtpIwkVUiBE2EJm0eNMHRI7CoGl+tFHudutP/8M55Ytwc91OECo1aAoCiqmqFr4egGbjev+kpLEpMlsjFBhoykEIbbzTzFpRY9Hy9+lzTi2T1rkFbsRFEXh77Jm9MuwINkUPg0pPA9pmIip0LfG34FCr0dFVAiCgElr6pSfWOpTBgwYAIIgsHev0nLXUxEe9C3TprV5O2qLBWkXXwxtTg406XT+Xpj6afnue+wbOw4t334b03ZZA7eCBW/COmVKm/dPGFVhBxlyqZ/G6GtUKIpCxW23o+nTT1Ex72bUvf5GzPviZIREvMPZrPBxeDvWoZY9cUfqYGKFg8pkgjopOO0VYLxySJc76DHRejL/L39DAw5Mm4Z9I0ZynzFh7YrQh0eKNKLSzERMkgxaqFX88ZQ94TZFIVSEUZTdlS1h1uyerNlfh3PeXIfZ8/+KuK4wVanV0H9vt6Bd3NeBXWw9SqgcLaSlpWHGjBmYP38+HA5H0ONSkzyF7oeXKW5Mv+466AXmbe1BnU57mAhTP5V33QWQJCrvviembbEeJ6wNflsRXk2zaQd2oKF7z56gq/hQONatg1MwzLTh7bdj3hfW6j7eERWLni467OiICnuCT4kwo4dkjjEqiwUqiyX4cUZMUJ4wQoUgoBLW0zEXZp59+xGoo4Vx5d33gHQ4EBAcv8J55SQZxROYWSGSKokEpDLmfM2uyKkfoVjcXdXz5sSt2kN30hU3RDbIY80PAcDnp0WJU/D38/g6TngrQqWLMn/+fAQCARx77LH46quvcODAAezZswevvfaaYojXA/AcpGsBkmacGrdtajLoiArpcATNCYoF0uPh7PvV7XSGFkZUWCFlHDkSquRkBJqaOEfbSHj2HxDd1w8ZEvO+sO3D0oF67cWqp0+sB2o7dtAie+JOjuCyy9agqCwWEPrgNFHAxgqVMMWqKhXUTMROP6A/dEV0Gk86sNKxUZx6F6aBpLDpHTaSEiqVxQqxSO3JFEVh9V6+5f1wXfBFYHdH+LfzRhj42Cio+WllCppdAqHSkcXhilDpovTt2xfbtm3D1KlTcccdd2D48OE45ZRTsGrVKixYsKCzd08hAfgqKnBo5mmoe2M+d9Up1wLaVlRWKwgtfVBnW5TlrqBD4diwEe7duxGoZ1JHBBHT8+UQ1pGwrrWERgPDoEEAAG9pdLO8AowpniY7G4CkoyhKHAlK/UwfSu/Tgt8PYWtJx7Vcs6mfiBEVOx9RIQhC5HsDAIFWOvJAMkJFlZSEjHk3iTcSCMBXWgoAyH/pJRBmusA6SKgIol5A+IhKdhItYqta3KAoiptsnZUkrmlha1TqIrj/frujEnurebFY2gNt94UivKI5vFWH0GjP4Q0gQFJwCaIowrbxRKMIlS5Mbm4u3njjDRQXF8Pj8aC8vBzLly/HlHbUBCh0Xepeew3e4mLUv0HXV2gyM8Xh9HZCEATUGbQYaP3lF9Q886zoitZfH7pt2VdTg9IrrsCRc+ag5bvvAQC63r3DtiVHAzvZGQA3AgDgizpDeXEEbYcp7mWfR4a7+hfwwz9VGPHoSny1tZxLC5h08RUq54zOx6T+6SApYPn2yshPiAOH6uz4/h+6uyYlTNFkwO7gxiuoLfRnzTJ1CnS9e3PrsH9bNqJC6HUwjR0Xcpvq1FSoTfS2pELFs3uP6D4ZRqgUppqgIuh0Q12rBzVMF1O2xEhvWB7tL/RvRUvYUQVLt4hnXNW2evDot7tCrt8dEQ55LG8KL9SaJF1UdrdflPoRto0nGkWoKCh0EXy1YidW4ckiXrAFtbXPPYfGDz8UPebeQ59EKIpCxZ13ofrxJ7jH/IKWUuemTQCA5LPOavf+CO31haKHFRy+8nLO4yMc7JU5+zzpZGk5KIrC3E+3web2446lO7juknhHVFQqApdO6A0AWHswfuMLwvHGbwe528lhIiot33wDzwE6baYy09ExgiDQ99vlyLz9dgCAhxllwAoVlU4PTVamzNZo1CkpnMD2VVSIHvMcEQ87JJ2hr+p1GhXyU+lutMe+242319D7kS1x2S1MM2FAlgUkBfxT3hy0nQ/XFePKDzbhL5m//aJ1xT1qoKEwdSMc7iiH9PGPN5agShCFYb8vHYEiVBQUugiUV/zFN44aFffXYIWKHG7matdfXQ3b99+j6dNPEbDZQHm9cDLOsQC4tml1WvB8oVhJv/YaAMGiTJNJnwibPv0UB0+aAve+/WG3w6V+mBMoGa7wk8EjydGzA/zM+vg7brJtsIfqHFyRayIRzhUKZ/bmPXyIX48xdQNoAWk56UQAgHPrVlBeL0g3E1ExGGTbmLnnajS8UGEiKqzXjnR8g9CPR45+mbR4+mEnL5Szk4LbmVOZziaXN7ju4pFvd2H1PnFkzqDl/ya1URjFdReEqZsGe3ihIo2ovLByH274ZBt3f+nWclyzeIuoZTlRKEJFQaGLID2Im44dH/fXUGeEFiq+croeRFg06S0tQ9Xjj6P2ed4rhb1KVhli816RI/W881DwxusofEtcdyW9Ym/69NOw22HTE1qmRoVyRz75OEO0C8e76wegW4QL0+i/178ViW+LrWqhBYBBq8Kk/vzEan99PVeoDQBgaoS0RUXImHujaBv6AQOgTk2lXWT//ReUl0/9qC0WFC1ahKLF4qgci8pKtzmzka1Q3WGR/k9XTeoTtExubhFr5+6SdKKEiho8/p/hGJBFi6CO7F7pbISf+QYH/7enKAo/76pGrY0X+I2OyIL6l901orqfRKEIFQWFLoLU4EzXJ/gg3V406RlBy0zj6HoDX1U1vKWlqHr4Ee4xX2kJWr78SnZb7FDB9mKdPj04opImNuKK5KnCpX4yo0/9yLULa1RE2JqO9jA0l+6QOlgbutMlXlQ20+//02smiDxHDp12Og6fOYsTm2QrvS8p554LtVXsoUKoVDAxYxscGzZwnWIqZuq1ecJxMB97rOg5uU/S6UJNuvj/Zxg+XHY/I3WfHZMfPN9KLqJiZCIkbono2F8jfxLNTTFwwxKF3iDdHeHfRyjinvh+D679aCue/IGvIWqOwukXAPxk4o3fFKGioNAFoPz+oA4IbZjwelvRyERUjKNGAgB81VUou+FGrgYFCN91Q8QhohIKtWRStD9aoSJTTEtRFA7W2kXpEEA+ojIw2wq9JjHD1tjBgA0RagPiAdtqLay3IV0uzhPFuY0O4ZN2+r7aKt+9ZRxOT8X2lZQgwIw0kGthZkmeM4feXoZYEJsnnyC7PhUh9SNXXyMnVNiIilSoyEWv7jttME7onwGDhn1Oz7HSF9aoCFM/76+la4e+3UGn6h79dhd++peeWh3JMFDYpuz1k7jyg0248J0NQd+39qAIFYV2Y1uxAmU33Mi5lSrETsBmAySjE4SFpvFCLVOjomdm7PgqqzijOW6/WkN3ZcQroiKHVKiEi6hQFBUkVBAIcNb8S7eUY/pLa/D8CrHTs8MbHFEZWRjbhOpYSGcO+I0ODzz+AK78YBPeXnMowrPaBpsCMQom3HrLeNEZYFJlvIeK/CBGtlaoZfm3qH6EjrRJW7/ZQYam447jHLg1EqGi69ULaYKp7+y07UhutyqV/MBCKbzoEAuVzcXiz83fD52C607qB4IgoA8RhenOCFNjNTY33vz9IP7Yz9fv5KcY4fYFsGhdMbeMjQSGwu7mv0dfbi3H6n11WH+4gUs/xoMeNetHITFU3HobAKDhgw+QdeutnbszRykdNSlYLvWjHzgQhF4Pyhnc/SBtLxUiHSoYT9SSCeG+ysqQk3Ypl4sbqiesbSE9Htz+1b9Yvr0So+oOYP8n24DTH+IedzJOtFa9BnqtCh4/KVsTES/YK9OPN5Qi1aTD6n11WL2vDted1C+ur0OSFBclMAiECutzAgC+Mvo2m/pRWeTb4KWRESA4olK44E00L/0SqRfyQzM1GeIaI21ursieX5OVCa/NFrGYFqDTcf4IV+dcGkcSHdlTxad+nj93BFd0C4CLnPXUiMqO8hbsKA++uJQ69s4YniPbMcUiFPy7q/jttbrj57OiCBWFuEHKnOgUooMVKoROB12vIqRedFFCXkcu9aNOS0PaZZei4d33gverIXQkI9ZBhrFASCYyUx4PAvX13BW+EC5lptHQAocgAIoC6XJh+fZKqMkAnllLW+ofmPwL+q/5HYRKxR1gB2Rb8NHVx8EfoCIOamsPwpPk64L24VACrK0Iu5mMAoMvXzXf5s1OQWZ9dKT1KSxSwQEEd+poc3ORefM80TJ1agp32zL9ZKgMBlHURpufD+/BQ6AiRFQAYNrgLPy8m973L6+Xd+VmoyPCiIHQJO6Pu6aiKF38mTJ00YiKxx+AVqWSjSa1F2mxsZRWtw/7JcWx544pwOE6Oz5YWyz7HHb0BABUNPGfjXgKFSX1oxARX1UVNw9EijDdI70K7sm4dv6Lw+ecgzqJy2coWCdaw5Ah6Pvdd0i98MKE7Jc09aMfMgSajAxYZ86U368wkZ5QU2/jgdyJ21teLrMmn8ZQJyWBIAjuit/VSgvnEyr/4db119XBW1wMgK/jMOs1MOs1CRUpQGgjudY4W5ELT0bC1I/Q3M/1zz+gSFJkny8H6xYsxLN3X8R90PXujeRzzkH6ddehkDEwFEZUdEwrdDSjHJ44azheu3A0/n1sBsb1lp92bJSpUbG5/ZxoC9cp5PYHcLDWjnUd5HETjla3D5OeXY1L398YeeU2EGnelM3tx5F68bHeqFPjkVnDcM5ovn395mn9cc6Y/KBtViTIZ0WJqCiExVtejkPTTwEA9Pt5JTfDQ/g4RweO/e7KBFpbUXzeeQAA78FDyLzxxgjP4OepqJLbNzsnEkIxqS0qQp8vl4JQqWBg6gyk+JtDCxUigREVOXzlFcDo0UHLScZDhZ07pDIYEHC7YWtpxci6A7h3yyei9VlR6PCwTrSJKZ6V0ltyRc/S5PAiyRA/kcQKFZ1GJer4EUY8Sbsd9QsWcOMQQs1sUqekAFotl1oDwI1hCAdBEMh7+inRMpVVGFGhB09Srsipn+wkA/4zMi/sOnLtyWyrbZJBI0qB8c+hr9M9PhLTX1oDAPjh5hM4p9vO4M8D9ai3e1B/kK5jindhty2KKMfbfxzmblsF9UAmgb+QUafhaoWEQoXtNgOAVk/8hIoSUemiXHHFFfTVIUFAq9UiOzsbp5xyCt5//32QHdAOxtL68y/c7UOnzoBj4ybR46KR7WEGjPUkKu+8i7tNeb0I2CMPP+NC8O2cnRMJYaSCdDpBqOmDD/tbSqCpOeS2EhlRAYCCtxYg9bJLkXT6aQCCXU5Z2NQPK/LUqbQR3Terd+HUks1B6zd/+RUW/H4ID35DDzw0x9kyPxQDsq24+LiioOWRHEJjha1DMEpOztKoaP3rb3C35VJqAN2i3O+nH5H75BMofPddGI45BnnPPdum/VIZeaHGmsu5d+8GGYVYiQT7Xj2CepP5q+n0lnQ2EAtXgCtoT/7rgDiqQlEUKCrxhmYsQpO1ssb4FaOytIawvb9rxqCgZelmHb6dx3drCb8nRq2K8xtiu368flLUARTPWUCKUOnCzJw5E1VVVSguLsZPP/2EqVOn4pZbbsGZZ54Jv79jBkJJ605KL79cdF84sp109rxppHLY16wR3WdTDeEgHUwI3pxYoSJ+zSj+X2E+Z+HaVOOBdcoU5Nx/P3R9+gIAfBUhUj/NbESFvhJmO042bzuAEfX0yerBKTdicxZ9MG5Ztgzvfc2H1hOd8hFyyYTgIZNSB9D24pbp+AHC/7/DRUl0BQVIOfdcWCafgD5Lv+B8d2KG4kWENjeHu924aFHbtifAIKlRcXkD+JFprw0VyTLIiJuqFnEq6vqPt+LUl/8QFaGGorTBifu/3oni+rYfB4XPLWmI7/HU6yf5VJhgivLrF47G3Kn9g9a/a8Yg9Mngi6yFRogmQUSF7fqRiqBHvt0VtxblHiVUKIoC6XR2yk9bVLler0dOTg7y8/MxZswY3H///Vi+fDl++uknLIrDlzsSFEXJnmSF70UoVAJKREWWlmXyhmlCAmz3RYiixkQQTdidxTxpEvJffom7TxiN7R5IGC3aAjpN0Lz0SzQtWQJfTS2alizh0o5epoNFm5sLgI8OpLpbkeqh/65kXiEMAV4QmH38e++dHr/Bj5FgZ9cIqW9tm1Dx+km8teYQdleKuzQWMC3P0lpMVqikX3NNm16vvRjHjIGuVy9Ypk3jLPUBwB1FzUskpD4qaw/Ww8uclP933qgQz6E/v8LhesIaC5KksHJXDQ7U2rFyV3XEfbjps234dGNpm+tLlm+vwJdbeTFe0hDf5gShkBB+Dk/oH1yHBAApJrE9gjBFatCp+dQPU+tll6l/KY6T2OpRNSqUy4V9Y8Z2ymsP2rY1qJOhLUybNg0jR47EsmXL8H//939x2DN57GvXouxq+e2TLS1crYMoohJFiqMnoE5LQ6CxEbp+/eA9dAj2P/6M+BySK2rsuJOmFHVmBgJ19dD17Yvs++5DmeCEpjIZQej5ELp5onz3RSIQpiWqH30MePQxAHRn0OBtW+E9TJtV6fv1ZdanD7xFrTVQM1fxGZmpSPHwQlpD8lfIvTM67m+eZNDCqteICmj/qWjGO38extRBmXjgjKFRb+vDdcV49qe9ePanvSh+9gxu+Q/M1ORKSXSAFSq6fn2hLSiAL0RxcqJQ6fXo+9OPdFcWAJXZDNLhEI1saCts9Ki00YkASaGKqU85dWh2yIgZW/+xbBufUvy7tJnrwrIL2m6jcRP+h2n1bUvK5mBtK25Zsl20rDTOwxLZLhyzTg29hr/ISGJM9RZePg5Xf7iFW54q+buxhoUAYNKq4eVSPwHR9oWUNDi4eU3toUdFVLoLgwcPRnEU6YT2EEqkAOK6FJFQiSaV0ANgc+45Dz4AgP57RYqodVSNCgBo2MiDxPm26L33YJ0xAwVvvA6VQZzWIYxG0TLrtKkJ308WYaurEMrpxIFp0+DauRMAoOvbF9vLmrHfR+/naSX8lW12Tir2pfL1ITqSv7oMlRpIFHkp4qjKxxtKcbDWjnf/PBLiGfL8I+O6+snGkpDrs99PldksMhfMfujBmF63PRAqFVd7l//aqwAAb3lo9+NoGdsrFSadGuVNLmw83IB6ZtBguiV0elKuVbfe7uEiGc2CWTdlTZFFg7od7cQHa4OPnfGKRrCwkSOrQSsaVMnu98lDsnHe2AJuufRzmpvMX6gYdWpYmOJatpiW3X7vdBNnblhcHx+x1aMiKoTRiEHbtnbaa8eLePsuxIq/rg76AQMQsDvQvORzbjlrz92ToXw+LqXCzuqhPB6Qra0hOyv8TU2w/fgjgI6pUSla+B7qXnsdGTdcL1puGDQIBa++AgBwSUSnymgSGbxpmOF/HYF07o8QfyU/VVdXWIiz5q9Fvj0NUkeYPplWvDZ8FqaX0d9/fYA/CWWEOZklgvxUI/aFmEETIKmoT3hyqz3w9b8h12frzdRmM7T5+VxxctrFF0f1evGG7SD0lZaB8vtBaNp+Okq36DGudxr+2F+HsiYnN3Av0xLa3Xnm8By89EvwVO4GhwcNDi98gi7GaFptTTo1F1WI5Rjt9Ppx/cfB56XSuKd+6H2zGjQhP2PCqEiBJE0pFC4GrQokJe76YX1WUkw6zBieg7fXHI5bVKhHRVQIgoDKZOqUn3gKiz179qBPAgbWhWLAX38iadYs7r6vthYA4Pr7b9F6ioW+OKqkSU/nak6EUSgpLV9/w91WmRLf8qvv2xcFr7wMw6DgSn8WaaGsymgULdNkdZxQUYcSKpIaGSKbLtCssGTi5dHnix47e3Q+NGlp2J9CXzHqBEKlo9qTWfJSQndLxdIBpJIcU6SFi3ecMlB0XxhRyX3icZjGj0fhO29H/XrxRpufD8JoBOX1hp0pFS25THfPPV/txMcb6LqlcBGVgdlWXD4xuLj5041lmLNgHS54ZwO3LBrzMmErsVy9Rij218inlers7U+JCdl4hDZvTDProAkhVISmeNJzVo4gouLyklxx7d7qVhypd+AXxpSvpMHBRVRa4uSl0qOESnfgt99+w86dOzGHGf6VKHS96C+wYcQIaDIykPfM0zAfT9cleEvo8HLAJhYmgaamDm3l64qwBcWEwQBCq+XqK/x1oc2khHUpie6kiRZp67HKJC6eFVrVJ3xfQvxNTGP5ejN1Rgaa/fyB9ede4qm+aWYdfrh5MpKS6b+1LsCfSDo6OikNqQupa+VPTo0Or+iER5KU6MAv3esGyYlt3skDuNsURXEXEiqLBbpevdDro8WwnHhiW95CXCBUKuj7090mpZdfLkojt4Xs5GABGClaJleftGZ/8EWFLURbrxCXoKbF4Yne7bayWb6mxRNna//l2+kI2nnjCnHKUPpCQ1qHcuOUfrhgfCG+uC64Bk2rVqFPhhlqFYERhcmimUtTX/ydu93k9HG+QK1uH93E0s7uH0WodGE8Hg+qq6tRUVGBbdu24emnn8bs2bNx5pln4rLLLkvoa1OMV0v2vfcCAAiNBubJ9EHNe6QYAEAy/hXm44+nn+Pzyc6L6UmQEqdPDeMEG2hsCPkcSmCmZTnppATuXfRI7fH1AwaI3Eu7gguxrj8/I0ebm4t6yYm6VSt+DznJBqSl0hEutkZlcGMxHOvXJ3hPxYQ7eda20kWgpQ1OTHh6FSY/9xuXArjhk60Y+djP2M+kjUSeOCSFGhv//r+6QXyiqbj1Ni6iIh342JnoB9Jiyl9XF7WLcyiyZdxne0WoPzpnTEHQMunnCKCjHgdrQ6e2Pf4AHIIWZrmBl6EIJVS8ATJu7b02t4+rvTl5cBbOG1uI+ReNwY+3TBatl2LS4dk5I3BsH/ko5opbJ2PbQ6cgyaCVHQ4JAMfkJ8PKCJV9Na049eU/cObrf7XrvShCpQuzYsUK5Obmonfv3pg5cyZWr16N1157DcuXL4c6hEFXNFCBAMpvvQ21L74Ych22IFSYitD16Q0A8Bw8AIC3Ltfk5HA+DO29Kjra4Tw9mJQPm/oJ17pNuekDY/Ls/4Q0Xuto1BkZnF+GfuBAWE85BbrCQuQ99ywK33uvw6MQOY8+AsuUKTCfxEcAtIJiYF1hQdAJxq8OPpBqmYnP+oAPFq8TL//xBkqvvAqtv/2GI+edD+eWLUHPiTfpgpk/eZIoQDXTqfNPRTO8ARJNTh+WbKbTGCt30aH1j9bTEU1h9N7lC6Ca6XQZUZCMsb3EJ5rWlSu5211KqPTnoz5spLatSCNV/TLNGJ4f/r0mG6P30Ln8/WDzQJYmhzji4owhosK2RF98XBFykgwY2yuVe8zjD95Oi9OH1XtrY4pS7GWGM+YlG5Bq1kGlInDGiFzkJseWatZr1NzfzBxCqLx24WgkGenHyhpdOFBrx+4qGzd3qS0oQqWLsmjRIs4V0efzoba2Fr/88guuvPJKqNrpX+HcvBmtK1ag4b2FIVM1bEGoMAVgHDECUKngPXgI3vIKzhFUnZTEXWH7e7hQ8VXTxZ2aHDq0yqZ1wrVus0PeCEPHWtKHgyAIFLz1FvJfeRm9Pv2EK3RMnj0blhMmdfj+pF5wAQrfWgBCID6Ek30Nw4YHCZWccaOCtqNjhPfZh/7AZMEMoPIb58K9cycq7rwLvpraOO+9mCmDsnDphF7433kjoVaLBd+9y3Zi5GM/Y49ggu3HG0pEKSEK9HdWeJ5qWr0axLvzoaJI5ElOPn7JvKZoLPA7CqHxm9xk71gYnCP2ILpgfLALsBzRipWKEJEPILi2qC0RlYHZVvx5z1QsuXYC95h0srPT68f4p37FlYs2y6aoQnGknr5Q6p8dP58mc4jarj4ZZtmREHKRqmhRhEoPxFdRyd0Wph24ZczkWQAgBLbXmrQ0GJlZK87Nm7kaFXVykqyvSk/EX0ULFW0uPZuEbTcON16AYgazSVuCOxu1xYykmTM7pGU6WrR5/MwXYX2F4ZjhQcZphU8/ieTZ/0Hvz5dwy/Rm+iRe1FqLi/f+HLR9f3U1Dp50UkLNC9UqAk+cNRxzxhZgkMyJo8Xlw/t/FXP3bW4/1h3ia5xIijY2+2ob74PSeuvNyP9pKSZU7UK/LL7uwrllCw5MPD4xbyQOCFOd7R3BkSOwyjfr1LjqhOgaDlLi4EwsdRd2xiRU6O9/XooRWrWK+aEFrHSy8yu/HoCX6UaKpX2Z9XYplDEcbCsadWj5YDUER1sUoaIQE/56wUFPxvuE8noBpkZF2oXCFtn6a2pAMqkfVVIStIWFAABHFOZmXRHK54Nrx452FwP7KlmhQnuVsO3GAXvo/DbJpH66UkSlq5J501xYT5uJwnfehjY7GwVvvonM22+Hafz4oAOhNisLec89B+PIkdwywsXXUKW7xY6uQlzbd8R/52V44dyRmDIoU2RVDgR7fIgiKhTw6cZS7n6q4H1YvU6RwVbl/Q/Ee5fjispoRP5L/wMABBob27UtgiBw1aQ+yLDo8NudU6Ju835+zggQBO9U2xYaJBEVexuKafOF7b8asdMuy/bSZu62PxD9sYr1gSlMi69n0LIbj8fCy8fhJsaCn52wnCQTpWqrAzOgCJUeidCRUlaoCKzVpd0fmmy6LsBfWwN/E31gUSenIOWcswEA9j+PTqFS+9LLKP7vBSi79jocPuccuPfubdN2fNW01TYb0lZxERX5qx9/UxOaPvqIXteY2CF/3QF1SgoKXn6Zi6ZYp01FxrXXgCCIqNo5g4YshkijsnVYiSbVrMOiK4/F0usnIsOiCypQZLsyWNdTgI54ljfx39Fn1vItxjrShyLByai9J/+OgG0/l6ao2sLDs4Zi8wPTkR1iEKEcx/VNx67HZuDemfITxJ8++xgACFk8CtATsIU4o2xPPlxn50SOUKjouZEA4tRPvYP/jL/y6/4gIRMK9vNSmBpfoTKmKBUnD8nGLdMHYPFVx+LJs4cDgGzqpz3t1opQ6YH4G/gOFDmhwk0z1WqD8tlsAaOvphaefbRZkr5/P+j60h0Y/trE5vcTAeXzofGDDwAAjj//hGf3HlTedVeEZ8nDtoCyB1++RkU+rN3wzrvcbaFFvULs1Nv5k8X1J/WTXSfQ0iy6H8qjhe1s6ygyLHpsefAUfHiVuK36xIF0G/i3OwTpWgpcsSIAmPx8keKwhmKYb7sWLd9+S9e4SVK7aVddlYjdbxfsEEl/dXVc7A3aUuht0mlgkTm5juuVyrXy2j3+kM6/wTUq0QmIt5i5TBoVIfqfstEdt6SYVvg6Dm8AC34/JHo8VIEtK6TSwxjgtQetWoUTB2bCxExY1mlUuG36QFwyoQhXTuoNANhwOHTnYyR6hFAhyfj2o3dlonmvwqssf00NWlevFh3QuI4fGTdd1nbduX49yNZWEDod9P36cb4apN0eNHG5qyNXPOmrijyEDABali/H4bPPga+SPpGwLdts10+kGhVh27ISUWk7AZLCH0xx4asXjMI9M+XN7AISYa7JyEDy2WcHr9dJkQih+VyGRYeTBgb71fhJSmRAZvbxQuWkiu3Anl2ovPsekK2tQXN0su66M/473U60RUWAWg3S4ejUCx1hxOS6k/rivcvGYeEV40U1LKGcf6U+K9FGVJqc9PMuOLZQJLCkQxYBwB8g0ewUv46wdqmu1YPxT/2Kh5cH76NN4ErbUdwyfQCePOsYXD6xNwDgzwP1ohRmLHRrC32dTgeVSoXKykpkZmZCp9N1qvV8IqEoCl6vF3V1dVCpVNDpQitnNmUDAGXXXgeAPoClX301AMlMEAn6fvSVKitGjKNGgdBqodJoaJdJlwv+ujqulqWzce3cCeeWrUg+azY0qamy65By9SMUhaYvvoAmKwvWKVNCbr/yHtpnpn7BAuQ+8QQCzBgBFWOXz7UnO0IUChL8tQKhTczVTk/gZ8F02wFZ1pDf89wnnhDNsdKkpyP7gQdAGPRo/owvuvV3AaGSn2rCiIKUoHXcvgCanPSVs5oMwOSXP/j7a2qClnXF459Kp4OuqAjeI0fgOXgQ2g4czyBEeBJPMeowfWjwfgzPlx+D4ZAIE3uUxbTsROPxvcWRPW6ys4vfTpMzuPFhc3ETmhxepJp1+GxTKRocXixeX4LHZw+XfR25lEyi6Z1hRu90E4obnNhX3YpMa+xNA91aqKhUKvTp0wdVVVWorKyM/IRugMlkQlFRUdgW5kBjcC646fMvOKHCeYHI+C3oeveGZepU2FevBgCkXnQhAPoAqMnKhK+ktMsIFcrrRfF5tJV6oLERWXfcLrueXLSDdDhQ/fAjAIAhe/fIPo+dlQIApMdDd0tJIyrM3zDQEOLEJzTtcsc+dVWBRjg0bkhu6BZMy6RJyLr3HtQ++xwAQJORDrXFjPQrrhAJFdfWrbD/tbbDW7GNAqFi0avRP8uCP++eisnPr+aWN7u8ULnpz820gtBROF91sFDpquj69oX3yBGUX38D+q/5Pex8p0QhjKiwA/dY3r1sHK5ZvCVobAEL60SbZNDA5vbDHWXqh42MSQUEu73rP97KTcZucMgL0nf/PIy7Zw4WFQ+TJAUVc9/rJ+Hx05H2joyoCBmck4TiBif2VttwwoDY29C7tVAB6KhKUVER/H4/AoHoK7GPRtRqNTQaTdirJsrrlR0e6CstRdVjjyH3kUf4OosQxlCGIYM5oWIcNYpbrisohK+kFM4tWzizsA6nqRj49ALAmAr/KQu4xeHMpAJtHKbIFs4CtBChPB4uhcZGVLT5dBW8r6pKNHiN8vsRsNk4LxoAIFsT1xLb3WEP+JdO6BUxaqAr4kU0+/+Rix5W3nUXBq5fF8e9jAyb4wcADXOxIe3UWHuQTheqyABO37kGAODQGPDQxP/DS3++wa3nLaU/85qcHFABPzJvvDGh+94e2NQx5fOh5MKL0G/lig7fB+FJXPh/AIA0My0kpKkXFnbUQYZVTwuVKO3vW0OkZI7U8ylKVnQIvXXkXluv4S9OGxxeLnIhHMMQriA4kQzItmDFLuBwffQt1UK6vVAB6Kt9rVYLbRcyOuoswhmyNX+2hBEq9DqhhIomR2DSJAjTJp1xBhxr16L111XIuP56uacmFpIEXuVbUf1/8jN05cLg3NOYjhxtQYGoI4qF8vlkTbKEkRhvSQkvOlQqqEz0yUWTlQVCqwXl88FXXQNdQT5sP/+MiptvASCeqm0cxe+7QmyEOuDLoc3L5W6zkT85oUJ5295O2VaMWv5KXthdqyLEBm8AMLNkIwbv+A4AYNcasSe9N74YPQvn/00vq3niSQBA6n/PR8YNNyR2x9uJ0OzNW1ICb0lJh0dlLYLPjlkSUWFN4UIN2eOEilmPw3WOoPbyUHApmTCmc41OLzIsemwtoSPhbNSGJc2sw7t/HMZTP/KR35IGB8x6NUgKuPi9jQDotGI475NEwroGV4UxzQtHjyimVeAhbaG9IwCAdLsjRlSSzzoLSf+ZhdwnnxBdveoH0L30Qp+WDsUjfm+BvfzVsDD6IYVk6kcMQwYj/7VXRTNtADqtI0dAEAHxlZdzZm8qq5Ub4EeoVJxJGSuCWJEC8K3gWXfdCdNxx4V5cwrhOMDMYbFGkYNnPW4AQMNMXCYMwSkUjcCiv6MQhu+FaYY3LhoDABiYzX82R9Qf5m7bmblGf46ZEbRN04QJQcu6GpoMcTrAsX5DiDUTh1XPf3akUblkI10/ZnP7ZGfWOLiICr1eNEKFoqiQAvu8sfwMItZ6/nAdfUE1SOLA6/D4RSIFAM59az3GP/krHvx6JxeJ6ay0DyAQKi1ts9FXhEoPg01zhGrLDLS0wP3vLnqdZPnCMZVOh/znn0fKueeKlsfqTksFAiDdbZ//EIRb/Lr+0n387bo6WRdegP+bqMwWJJ16KtIuu1S8nyGEirS2xbGOFkZsfQoLa4bn2b8PZdcFR5rUmRlIu+qqLlnoeDSw7mA9lw6J5mCsSkqiRQhBwDBsKAD5IlN/XfQW5YlAuE+nH5OLVXechGU3TuJ8PYS06ugIntmoD4oOGYYMSeyOxgFC4srcGRc7QsM3aZc0G1GhKD4KIoSLqDADJ6PxN3H5AvAzokcqsJ84iy+GPeO1v/Dot7s4Q8MUk7joXjiMUojDG8A32/nazGhEfKJgZ1qFG0MQDkWo9DDYk6smRGW990gx7L/9BgBQWeWFSijUTFcN5XbzXixhqLjzTuwbNRoN738Q0+uExNUsuhtwC442JImmzz7D/uMmoPX330XrsakfbuJxdo7ocSqEmCIlnTzNS78EAG50PYu2gK6DqHn2OdjXrAnaTtattyoipR288itvzhYuhM5CEAT6/vgDBvz1Z5CoFELa7Qm10o+E1Fi1X6YFFr0GF4wvxOOzh+GkwXzEp8FAf1eTjFpAMthSatrYFZGOafBVVMC9Z09cfFWiRfgdzJJMYtZpVFx9h9SFFmibUGGjKSoieG6OQavGNMH/d9G6YjQwPkHSlvUtxdF1qJlCzObpCHIYodLq9sMVZaGxkIQKlWeeeQbjx4+H1WpFVlYWzjrrLOzbt0+0jtvtxty5c5Geng6LxYI5c+agJkw9gUL7CEi6UgBatOj60HMx3Hv4EKJ+0MCYtq0ymwGmWDSaqErrT3TBXO3zz8O1fXtMryWLIKJCUYCjRnywqXn6GQRaWlB+vThfzxYXq6yMUEkXR5tCpX5sK1aK7rNeKoYR4iteXQETxpXxuBn8zw6kzJkju32F6BBGUaxRFguqLRZo0tNFy0zjx9O/x43j2srD1TYlmlAdJioVgcsm9kaS4L26NfRnvW+GGSo9/7lPv+aaxO5knLBMmYKk00+Hthc9SLDl669x5Oxz0LoyeB5TInnn0rG477TBGFMUbGWQxRSn1spEMBxBQiVyMS0bmbHo5RsgUiSimxVIM4bl4N3LxuGGKbRVRGWU6ZRYJkXHG7OgODmWOUgsCRUqa9aswdy5c7Fhwwb88ssv8Pl8OPXUU+EQmC7ddttt+O6777B06VKsWbMGlZWVOOeccxK5Wz0atrNEJbySJEkQjNlY7XPPcYuFA8OigSCIqNM/UlO42ldfjem15HBs2or932TDVmZAw14LHFWhrySFKSfWqZf1WZHWqMilfjyHDsG9cycAQD9IbC5mGCy24tYWFCAURBi/G4Xo0AtC9tFaisuR/+oryLzlZuT970VomenXVfc/kPBpyqEINySdCgTgLSvj7nvU9EmoT4ZZ9N3OvPWWoOd2RQiNBvkv/Q9Zt90mWt785Zcduh+nDsvBdSFcjdkoS22rWBg0ObzwMXN3spl1oqlR4U3Y5AWEXBpTRdDFs6cMzcaowhTRYxP7pgetLySWsQLxRqUiuK6kaAuNRc+P9w4JWbFiBa644goMGzYMI0eOxKJFi1BaWoqtW7cCAFpaWrBw4UK89NJLmDZtGsaOHYsPPvgA69atw4YNHV9M1RNgzc3UFgsX/TAccww8u8XFWPqhQ9qUjlCnML4hMkKl5bvvUHHX3SC9XvgkV6rO9Rvg2LQp5tcTUvroewi41ahYm4a6HXzaihVPQtiCYYBuHQb4ybymsWNF7dVydTTC7iDD8GGix3RMTQqLNj+0UFFoPw0C6/zj+8fu0cCiSUtDxg03QJudzaX/XDt2oPzmee3ex1hgv3bH9wv9XiruvJMTygDQnF0IgqDfPzuPCwAIdeeF+9uCNMolrV3pTLKszMWcJKKy7hB9odM3w4w0M33hEUvqJ1RdlZyASTXpuIJrqffKBccW4uZp/YOeMzQ3CWadGjdPGxBxnxKJIcT8omjo0BqVFubkkMYUcm7duhU+nw/Tp0/n1hk8eDCKioqwfv162W14PB7YbDbRj0L0BAQRlT5Lv0DKeech59FHOOM2FpWxbcOrwkVUKu+6G7bvvkPLsq9lQ+qtklRKTPhChz/ZtJYQsVChUzaa3Fygdg8IewV6ffwRdP3pKys2ouL65x9UPfQw/I2NosJcld6ArDvv4O5LIyi6QkWoJBJ22NlHVx8bt/C2Joev4XLv+Ccu24yWNXdOxYvnjcSFxxaFXIdNmwJA8uzZuPvl2/HdTSdgYLYVOQ8+CHVaGrLuuacjdjeuqNPF4kyl04P0elH9+ONo+eGHTtorGjZawnbhAHTnzkOMZf2owhTOsC86oRLeLVZOwAgNAY8pSOaEEQD0SjfLiptv5k7C3w+fiqL0+A4kjBVuflFXi6gIIUkSt956KyZNmoThw+mK5urqauh0OqRIrnizs7NRHaKd9JlnnkFycjL3Uyi5elUID1uPoU6ywjBkCHKfeBzarCxk3XuvaL22FuCx6ROpUBGe2P2NDfCW0mPqjaNGQs20JrZ8/73skMRooFyhJ6/K+TGwbdqk14tAHd1hoE01AW9OoL1YAn6omCGBlMeD5q++QvH5/0Xz0qWo/d//ELDxJnHp1/yfqABXOiNJJWjzVmdmYNDWLUg6/TTkv/JK7G9UIQgb423RFmvuUGglBdUdSVG6CeeOLRC1KgsR+rsUvb8Qec89i8xkE4bn058zfb9+GLD2L6RfeUVH7G5c0WRIIyoGNH3yKZo+/QyVd9wJ5+bNnbRngoiKYF6NzeXnBgVeOrEXDBpaSNTbvfAF+MiBxx/Anwfq4PXzy9oSUUkXCBOLXoMZw3hBXZhqFHnBAMAZI3Kh06ig03R+3wwbUfH4u7BQmTt3Lv79918sWbIk8sphuO+++9DS0sL9lAnytAqRYSMJ0o4elU7Hde0AgMoUPJAwGtiIinRkO5teoXeChHvXbgCAyb8VA378EprMTJA2G9x797bpdf0lB0M+pusVfGUasNlgW7EC+0bQJmuETgd1QNASWbUdBFOUSLo9qHrgQe4hz4GDIFtpoZN0xhnQ5uYi6bSZSDnvPOQ992zQawlTaCmzZ0NlNiP/pZeQNDPY80Ihdli7cZM2fj4RwogKAFBdaLCpjxncR+h0ME2cKLvO0dpFppJ0YRFqNdf2DwAll17W0bvEIa1Rsbl9qGds7a16DUYXpYoiHiMf+xmvMh1pl763CZcu3IRblvyN7WXNACKbvckJmKckrenCaEyaWSdynr33tMF4/YLRMb3HRMKaGbq8XTT1c9NNN+H777/H6tWrUSAIi+fk5MDr9aJZcvVdU1ODnBz5Kxq9Xo+kpCTRj0L0cGZuMnUbwmWEoX1CRRpRERb++evq4N5Fh0sNSTYQh1fRaReZ54Xk0G/AP19wd51bQl9p6fr2DVoWaLGh4la+cE+dng7CIfDNKNsIFZMfpzzitJLaauUiKqok+sBKaDTIfeJxJM+eLbsP+a+/hqTTT0O6pONIoX2QJMUV5xnj2H6pzckV3W9Ztixu224vbHeZNjf3qBUkoZC+n0BzU1AUJa7eSzEgrFH5cWcVRjz6M2a/sRYAkGahIx1sRAUAnN4AXv51PyqaXdjEtBD/9G81zpq/FiQZ2uyNRbp82Y3Hc1EzlnPG0OfTkYUpIAhCFFHJSzFy8366AnqZidDRklCrOoqiMG/ePHz99df4/fff0UdSKzB27FhotVqsWrUKc5gWzX379qG0tBQTQ1wpKLQPVgiwRa9ChEKlramfUELFL0jl+Wqq4a9mClgtAUCfFLYINwiKAj46m76dPxa2rYdQ+dy7QatZ8l3IGdsCnyAloMnMhL+uDoHGBtG6mrQ0oFUQ9XE1g2BSP8LhgyyBVrbNOzqhnHTKKUg65ZSo1u2OrN5bi8I0E37dU4NheUmYPID2gli1pwYDsqxtzp+7BWHkePpEaCURFff+/XHbdnthv0ua3NwIax79tP7ya9Ayb0kJDJJOu46Aj6h4cOuS7QB4/xSPL/TQv0oZk7NWjx+r9tSGfA4ACB1ktj44HemW4NTmoBwrfrvjJC7tObowBYOyrShucGBomOGcnYGBST+525D6SahQmTt3Lj799FMsX74cVquVqztJTk6G0WhEcnIyrr76atx+++1IS0tDUlIS5s2bh4kTJ2LCUWD7fDTCC5WUoMdEQqXNqZ/gGpWA3SFJnRzgIhJqHQn43bG52joFBke2ClQ//KDsakm9SGhNJEgDHzjUFhXBX1eH2hdeFO93WhpgFxT4eh1c6qfu1ddE6/obGqDJpE+06qSudTDoiny+uRT3fLVTtOynWybD7vHj6g+3AAA3ITZWnALzKOGcnPYiNUSkojAw7Ch8lYzI76ZCxXLyybCvWiValnnH7bD/ugquHTvgLe4cocK29wqH/LFUMwW2KhWBjfefjOOe5vdfzjZ+X3UrdjPW9rnJ8sfaQdn8sUVOpLD0zeTtFFJMOqy4dTLcPjKuEcZ40GW7fhYsWICWlhZMmTIFubm53M/nn3/OrfPyyy/jzDPPxJw5c3DiiSciJycHy7pQmLW7wQmV5JSgx4wjR3C325z6SaW366/j6z2aBf9vAPBXVoHy0vlZtY4EvPaQRbiytPK20Fj9DNSkvDOjqRcdjlXpBPOIZNJAABNRqRW0aHvt3GBBKf7aWm4/Y3Xv7Yl8sLY4aNnag/XYVcF3XpU0OLCluBEv/bxPVIQYCdbl0qhVxzXMrU5KQs6jj3CF2KSrc9INcvjYaGRu5xX8JpLcxx9DynnniZYZBg/haujYoakAUPfGfBycMQPu/fvh2rkzoU624SYPC6MiWZKi7ps/+zto/c1MKkinVuGC8fINIXkpRqy89URsuv/kmPaTIIguJ1IA/kKiy3X9UBQl+3PFFVdw6xgMBsyfPx+NjY1wOBxYtmxZyPoUhfZB+XychT4rKIQIHVIpd9uuINm5Ip79+zkX3NB2+hRUWgrwOkIW4cpiEwiV0nXQ6PkTW695J6LgrQXo/dWX0KbQM0/UguOG1JyNRZ1kAvYK2h+9jpBDGQONjXAzDsus94pCaLQyE1sP1trhEERDdla04Ny31uO13w5ikYywCQUbUUmEPXjqBRcg7corAQBkG78PiYAtTO+uqR9NejqSTj9NtEydmsoV2rIjL0ivF/VvvAFfSSmO/Gc2is87H/Wvv5HQfXvozKGyy9+8eAx3O5q6oRdW0sePSf3Tw040HpRjRVYnGrXFk6OiPVmh8+GGrBEE1DJFyGw6A0Cb3Ti1ubl08WogAPvq1QAQNCSNRaWjaHMrgVBp+fqbyFEVoVABEPDTBwZLvgumq5+HdcoUGIcNA3T0gU2l8qH30i/Qe+lS2Q4gADD2ywEowRcohFBhXWvZScmhtqfAIzfEbcnmMry95hB3v8XFr7M5ytklAOBg7LgTdQXJpkApZ9cRKn7mu6ntxhd00u+eJjUFambEBWta6dwUXEBf/+abCd2v7CT5FAxbcxUr4VI63Q1DV42oKHQtbMzcDMOIY0I6VmY/8ABUyclIv/qqNr9O8n9mAQCav/kGgHjKsGEEn15Sa5lIiNcO86RJ9MEpEED92++EfwGHeLJqwE2/l4zrrgUMggOcjhFIHjuMxxwD4zHDRbUHyefOQcqFFyDjpptgHStJCXntsgXH+gECd0e1utvWCcQToQgR5t1ZC3EAeODrf7nbzU75KddyuBIYUQFoHw+g8zpN5AjXuddd0A8eLBIr6tRUqCz0Z4c1rWSHp3YkoczZoiE/JTid/n+Tg80ouytdtkZFITKNixej6qGHQQXaPqMkWtjBf0mnhvbvSLv0EgzcsB7GY4JHyYtw24Bti4GqYNdO1n6ebaNkr4DSr7lGZL6mZlM2Hjt0RUXIeeRhAIAjhCsx/9rNorsBD/0x1ky6XLyeniky8/Imctq8fM6jPP3qq5H7yCPIvGkuCKdkrLxMRMV03HGiVI82Lw+EtvMGfR0NUBTFCZKPrz4OK287EctuPD7sczYVN4rETTjY1I9Rl5i+ANahOZpp4B0FJ1RCpCa7A4RKBeMYQTrFaOSGhrKmlbKDTBP8fRQ6H589Oh8WvQavXjAqquf2SjfhiuN7c/fPHJGLwTk9p8aNjXo6utpQQoXwkE4nap5+Bs1Ll8K5cWPCX8/HeJno+vQOu17EHGtzKfBsIfDtPODtyXS7sAD2So9spg+onG2/xSKa2qw1MeKMERLGUaMA0AP/hO6bQbj5IkwyAFAkvb8qaTqLjah4+YiO2mJGr08+Ru/Pl0Dfpw9QswuoPwjYmVSXNY/bJ+GJQGXQoejRa6BO5l9DOtNHIRiHN4AASX8+xvaiiyGPyY98gt1wuCHiOgA/idUUx44fISpmWGdX6fqhvF5QzEBPufRtd8I4mjcrIwiCO3YEmAsfX51MejoQSGhBrdCcbfaoPPzzyKmYPSo/quc2OX24clJv7v6Q3CS0/rYah2ef1Wajy6MJVuRFexEiRBEqnYiTGc4IAL4q+ZEB8cTL+IGEm+YbFRvfFt+v2iG6y57gAy0taFm+nLsCUlktnEEaAKT0ZSYo/7MEIElocnNpseHzwVNcHPr1hULFz4sqqXU9W6MiFCoAYDKUw2ioBGxVwILjgTfG8q3JaUwKyOsQWd9rdA4QH54uWqZV6lMiwh6UdGoVV0wnV1wrxe6O7qqLNc2SWofHC4L5THWViEpAMNtM6uLa3Ui79BJYTjqJm1nEpn7sv66Cr7YWgQa6lkn0PSRJ2H//HXVvvpmQKHWS4HNmNWhDdpp9fu0EDMy24P7T+UnqzU4veqWb8efdU3HvaYNxyXG9UH7jjfDs2yeyb+iupDBCxdYGoZJQHxWF8HgO8Lbv3nAn5jgQaGkByYSMdfnRXQGERFIjgrp9QN4o7q4wElF5z70AUw+jtlrhr+WvgowZgqhJ5TYQBeOgSUuD12bjxI0sQqHio096hF4PQiP5OAtqVPjn2oAvLqVvnySYb8QW6KYUASUAfA5oHHyxp1pHp6mEV7G6QkWoRII9KCUZtTG5qMp5VchR1UILiNzkxHRGsOKXdDjg3LIFxpEjOzXdxwoVVVLSUTcZOVZURiMK336Lvy+YpFz3yqsASQIqFbLuvBMV827mHiu/4UYAgDY3DylnnxXXfRJGVHRhBPdxfdPx820nAQCe/pGOlrAzgQrTTLj+JHrgKdsWQDJRsu4MG1GJpQaNRYmodBKkx4P6BQu4+94EzyxqXUUXnmkLCkJ24USNTeLU6hMPEiR0OvHjzJWNymyBv5a3qVef9QK/DjNUkPUuCfvFlYmoyL4nrkZFIFRcgo6SNYK5PGxExZrD7Y/m+0v5xyn6ddRmPmqjK1JSP5Fo4YSKWER+ef1EXHdSXzw6S77d83CdHSc+vxqvrToQdvuVzXSRayjTrPbCCRW7HSWXXIqmpUsT8jrRwtWndPO0jxyGYcO427affgIAqNPTkHTKKSha/GHQ+lX33ScahhoPtGoVThmajREFyRgSpfPrKUPpAv5w07B7wv9TSf0chTR99JEoahD1jJs2ELDbUXX//QAA0/jx7d+gxya+743uasAwZDA3iE+f4gNM6UDvyaJtckIlzBRlX30zKjekwDXuOVDnfip6ngiZGhW4bcHrAbxQSeajTYTg28EKIrWJv6LSKhGViLAHpWTJ4LVxvdNw32lDcNFxwZOtAeCTjaUobXTipV/2wxEmusLak+elJCaiQkhGSTS+/0FCXida2KnfPeHEJkWbm8tFWNiaIW0uXVNmPvZY2VRsxML8NvDuZeOwfO6ksP4nQl7+7yi8dclY3HvaYNFyoYgKqq/rhiQzx85mRagcPTi3bBXdD9haQqzZftz/8q2fUsfHNuGRpGV8kYVK0qxZ0Obmwjx5MnqfZ0avafWAMQXQW0XbZCMjpCP0Nqt+c6Ol2ITie15HgKCjJvJChd22QKhIRRZLKyNUTOlihzgpAlGmK2xnrU8PgEv9hGjr1GlU2PbQKUgzi6NwfpIviBz2yEo0O+WLq1l78kRFVNQpKaLuE8NQ+QhQR8E65BJtHHFxtKORDIu0Tp/O3VYnBRdpl117HReFiiexpDEteg1mDs/h2nNZ/PV8Cl2Y1uqucBEVpy/mgmdFqHQSUkdTsiXECTQOsELFOnMmTGPiMPabFSp96Bws1/5L8sVrvT9fInKXZDtkiIAXRm0x1DoKSOsnI1QiRFT8HrjZ7FGA5FJEsqkfLqIi2FaoiIqXeU86K2BM5RZnj20GoSGRM46p78nlHwtlsa/AEyqiIiTNrMO2h05B8bNn4MEzhsiu8+G6EtnlrICRCp14QRAEit57F9bTZgIIH+nrCCivBwCgkqZXewjS77lxOJ8O0qSnyz7H/tdfCd2ntiKMorf+8munf7YSTYqJ/sx6A6RoRlc0KEKlk5AO/RNW88cbz0G6KNQwOE6DvNgIBVvP4XMCqx4HnusNNNCvZRw5EnkvCGpQ2CuQml0A6aPFQEpRkFAhItWotJSLporaf2Pcb+VEg1yNSqiICovOTEd6GNIGODHonGqYMukToj7biqJFi9D3px/Db0cBAG/qJq1RCUWoeSqbixvxxeYy+AVzgEiS4opukxLU9QPQn63k2bMBAI61azu1A4ht2yd03f8KXA61RSxUhKZ36gxeqOj69eNX6gCPqrYQkFyc1r32Wog1uwdmnZqb91PX6onpuYpQ6SRI1pJbRf8LyNbWhJm+sbNBtO3t9gGAgA/wM/tuyaJ/e53An/+jRcDPfJsdoVYj5fzzoTKZkDLnHHohI2SQNYwWLxKhomZTPyGECrlzOUgv/7Ft+fprAPx7FCFXoyJNWwU9xwQYUkSLCBWA3JHc880TjqM9WBQiYosioiIkVJvxXwfrcfdX/4gcbB1eP9gMUVKU228rwk62ijvvSuhrhYPkhIoSUQHE/xdNegZ3O+Wcc7hja+Xd9yAQrouwk5CmpBzr1nXSnnQMBEFwIwg2xTAmA1CESqfBnogzb57HLXMkKETJTVuNx2wQ4YnewtjRC7t+msXdSzm3XY2BG9byqS7WVZaNWrBChUnJEMJi2pYKugWRpWIrWhYKojQCZK9y5WpU3BHy1ToLULU9eLmZmeURKSKjICJWoTI0N3xR4ff/8HOeWA8VrZqAXpPYQ5lw2rh91SpQZOw24PGA6uFCRdoarhL8X4SpH3VKClL+ez53v/SKK9tlBOfcsgWtv/7a5ufLIZwCDQDqjAz5FbsRbJ3O3V/+E9PMH0WodBLsiZU1MQKA2pdeDvsc57a/sX/yZNh+/jnq16FIEn7GTE6TG4dJv6xQ0RgBPXNSEXb91OwEPr8E2PklULEVxKvHgPjkHMHzmRM9O5OH3Ya066dqP/DyUOA73h8BB1fB2yp/xZ37xBPBC+VqVKJJ/Yy8kL5tygD+8wZw+fdBkR+FyPgCJP44QBcMphijO7H2zbRg1sjQn1OHN4A5C9ah1uaGzc0X6sZS3NgWpNPGwzonJxDK07OFihS2pg0ANJn8iV6dmiJKB7t37YJ7924A9FgHx/r1UXdaUoEASi67HOU3zYP9jz/is+PgO7hYhBGh7srhev5YXNwQfU2OIlQ6Ca4I1GSCtohuq4v0xam85x4E6upRcfMtUb9OoLGRPqgSBLTZWW3eXw42jaK38EKg+E/xOnu+A766GtjKeBuUrOUfY4tZWYHCChbWR4VN/RzZQi//+yP+uc4Gbq6P6bjjuMW9Pv4IlhMmBe+rXI1KqGJaFp0ZmHo/LVBu3w2MuRToM1kgVJSISrT8U96MersHKgKYNiT6z55FH97IbGtJE+Z+uo2LqFgTWJ/CoklNReat/PeO8sSWY48XXERFrwgVQNx9Y5owAcaRI6EfNAimsWNBtoodqQON9DGm5auvUHrlVTgy51yQLhdavv0WNc8+FzLi4quq5iK7thUr27yvFEWh4u67Uf300/T+SFI/PeF/+h/BRci1i7fivq+CZ8XJoQiVToJ0sULFiPyXXmIWhg8nC9Mb0YSeSacTTV98AQDQZGbGx1GzlbH6N6QAWuaKJVR7cs2u4GVsRMLACBUr027YSqendEW0r4arxiceIeRzAw2H4HfTH9nkWWfCNH48dH37wjB8uPzr6yz8/rEdSZGEhtZE196MuRTQCAoWuciPElF578/DohRMKBoddMTjmPxkZMQwzr4wLXI31ZF6h8j1tiPIuP56vqbM4wHl96P4wotQHsOFQ1shnU7UvvIKHGtp0d9Tu37CoUlNRe/Pl6Dv8m+gTk4OijqRLidIrxdVDz4EAPBVVKDm6adRefc9aFy0KOS8Ne+RI/w22tGZ46+uhu3b79C0+CP4KioQaBYLFcrdOeK3I3noTL69v7TRie/+kaktlEGx0O8kKKaYVmU0cpEOf0MDKL8/2AqeQWUwgM3q+WtqoM3NlV2PpfKBB9D60woAgCY3DvUpAFC2if6dO5KPqITCKRgsx9hdc0KBPfEnMQrbVglQFExjx4BQUfA7NfDZ1dBZA4CjAXhjHOBqRMBNh0fV6ekoWvxh+JC/nk+rwVEPWLODhUb2cKCGKdDUWQFViKv5HipUtpY04pVfD+DW6QOQaTGgxeXDkz/sAQCMLkqVHV3P0sS0DrNtidFy5fF9UFzvwKjCVLzy637UynQIqAiiQyMqLIReD8rlAuX1wnPwIFx//w2A7tpLlAlboLUVh/8zG35BwXhPTv1YTjoJ9jVrInpCpV9zDVzbtvEpH7cbrb/8IlqneemX3G1pAT8VCMC14x949vEDA9kLzLYgFDn2deu4Tk/94MHw7N0L0u1u87aPFpKNWjwxexgeWi5zERsGRah0EsLUjzo9HdBoAL8f/vp62aJXiqLgr6nh7vvrGyIKFVakALyDY7vwOoAt79O3iyYASRG6iAKCPP6ya4BzF/KpF4NEqPicgLsFKr0V+mQf3E06eFq0tFB5eSjgp7/EfjctJDQZGZHrEjR6IHMIULcH+Otl4OAvQAMzX+nst+kW6dQ+wHzGrdeUFnpbrOjZ9Q0w7mogJ0QUp5txwTsb4AtQ+PNAfdBjk579DQsuHoPTjpH/HLYwMz1STbFFPIw6NZ4/l+6yuui4IvS+94egdVQEIapR6ShUOh0CLhcoj0d0RewtKYHxmGMS8prOzVtEIgUACG3PFSrZDz2IpFmzkMR424RCm52FPsu+QtlNN8H+6yqQThf8dXUh15cW5Dcu+hC1L4iL99szk4e086ko1/btXOpHk50Fz969oNohgo4mJvWPvRZHSf10EuwHnjCaQKhUnB9AKBdFyusVWS7760N/4eSIS8dP5XbAUQtoDMCI82kflHAIIyr/fklHY6QRFa2RN1hrKQc8rdAl0VfK5X+lIeAlQHr4K40A05qsTuWN18JSeCz9e+MCXqQAtAfMwBlAusBvIVxXACtUXI3AW5OA0g3Rvf5Rji8QvlPi6Z/2hHysrREVKWePDhbEDQ5PRNfbREDo6RQW5fWKTnreYnlDunggV7vG7kdPRFdQgOQzz4h6KKPKwMxrcrvgKy8HAKRc8F8Yx40VrSc99ja8/37QtthIeFsICCIq7n93cW7k2mz62My6Dnd3+mZaMKm/vDlfKBSh0glQFMUdfFiBwk9pDeEfIlHyQvvlaFCnh4kWRAvb2ps9jC6C1UQ4AfklX7yFp/ADDYVpmYyB9O+aXYC7hZtUDAD7l+Xi4PJs+D0qUAGACjAzdyyW6PY5OcTgQPb1hakef5iDkHB/AeD9GdG9fjfHqg8tEpqYiEpKjBEVKS+cOwIv/3ekaJkvQOHFn/fT+9CRqR8m5UJ5PKJJ4L6KilBPaTdy4zV6cuonVlRGel4T5XLBW0ELFdO48ci44QbReg3vvSd+okwdYLsiKgKh4jl4EP5qOkKuyaFtHnpC6ofl4TOHRV5JgCJUOgHS4eCq9zWMgODaciXhv+rHH0fpNdeKBhgCQCBWoSIzByNmpNEQAMhmwt3//Ti6bTSX0r/NgvBfPnNls+kdYOPbSOkn/hsEvGrYyw0I+PiPqypaoWII8b71Mst9YQ4UUqGiACC0QRvA29untjOiolGrcPbo0HOVOqqYFuAjGaRHHFFpzwksEtI2VgAgdB33no92CPYi0OWGr4IuAtcV5EMnMcD0V1bBtUtQOxFvoWIXFOIGAgg00qZn2mxaqFCd6Hjc0eQkxTZEVBEqnQArMlQmExdJUclYx1MUhaZPP4Pjzz/h2CBONfjrwgsVaaudOjkOhX5uiQcKAFz+Le0zMvhMYOJN0W/LLGhXzWHETsUWYMN8GFL8SB0gbi101OpA+uhoCmEyhSw4DsIQ4n0Ll7PCK3+M/LqAvFAhozcsOlox68KH1z1+/mC+pbgRJQJvhD1V9OelKIounvbQscW0TETF64F7r6DI0p2Yk4ztxx9R/+aCoOWqHpz6iRU29dP0+edcrY82Px+avOC6Pe+hQ/A3NsJbXi7brtye8Qmh0voaJvXjLS5G/Tvvtnn7RxPJJi3eumQs5l8c3ew5Rah0Ah6m3U0tcFJkBQslFCoCrwZpK1skS2hKovzj0pHApn6EJ3lTGu0zQhDAjKfo4tSIEOKIiiUraA2dVSwC/H4zAjPpWRhRp32A0BEV4fKrVgJjLgNmzw+9HbnC4SimRh/tsKPsnz77GPxnZB6uP6mf6PF6piPnYG0rzn1rPU564XcAQI3NjeIGJ1QEMLZ3lPVEEZC+Nou1Q4tpmYiK3Q7X9u3c8kRdDVfcfgd3W1vAR5WU1E/0sHPVSIFQUGdkyLZ4V959D4rPPQ+Hpp8iG8kinc42Odz6GxtR+9xzso8J/a3qWKuKHsDM4Tk4aWB0/kqKUOkEym+4EQDgK+Pt5lmHxcp77uVm/gijK6QkTy1NBUnxNzWJ7qvikvph9kEfRvRctwYYdbF4Wc4x4lSLMRVQC04upuAqcEOO+Co8kDQIpHUAAEBljSENIxQkk+8ATnsBOOstsUdK9lDgP68DKSHqWQAgOR+49BvghnXM8B+IHW+7ERRF4dFvd+F/P+9DK9NZM31oFl67cDTuPW2waN2qFhdsbh82HWkSPX93JX2Q759liVux6z0zB+GDK8cHLVcl1pRWBJv6sf/+OyhBTQHZjiLLaNELBu0pQiV6CENwmoHtGOyz/BsUzH8DxrF8Ya2vMtgjSMXOFAoE2uRK3PjRR7LLdX368NtmSNTMt6MZRah0MEI1bhzDpxoIA+9H4dyyFYBYqEjb6iJFVNj8J0vCUj9SDMnApFvFy066F7j7EH+fknwRTcEV4IZz7hTdD7S0gLQzgwvbGlFJ7w8cdy0w6sLony+k31S6kJg1kvPYw69/FOEPkNhdaQNJUihtdGLRumK8/ttBfuifQGwMzOb//iQFrD/UAAczxRgAVu6qxoFa+n81IDt+tT0EQWDqoOArMLev4+busAKh9ddV9ALGRLEjCiEt00/mbnfFIXtdFZVEqJhPOpG7bRg0CNaTT0b61VeH3YZWkCZqS52Kr7RMdrl15gzRjCKg53T/xIIiVDoYYath3nPPcreFrcdgrhCFHUC+at5DBYgcUQlIIirq5HZGVCgK+Pcr+nY4oQIAmQOB2W8K7g+iIyiZzNV478ni9c3BERXVCdcj+T+zQGjoGgl/ZRVc/9LGbG2OqKTJpw5iRidjzX+U88LP+3D6a39i8fpizkhNCDtMDAAWXj4e98wcjNOPoXPre6psXCsyAFz/8Ta8sHIfAKB/ZgyiMkoWXDwGV07qjTNH5CLNrMNpw+NkZhgFbI0K28FhGDoEABLugaHOyEDK7NnQ9e4NADCNHRv+CQocwuNF7rPPIF8mBWOZOgW6/qGPD2qrlS/KbYNIZI/HhMGAtKuv4pZrs3OC2qxJZ/eM1EohXS7sP15m9IkMiuFbB8O2NKpTU6Er5FMNwg8/5aVFi/AD669mBgtmZ8NfUxP2iooKBGD/UzyJOeoumVDU7uFPzOzU5HCMuoiOlKT3BzL608tmvUrP/Tn2WvG6Wom76Vl08WDe888j+4EHsP+4CQCAhrfeBhDjexEKldRe0T8vHHLDDo9y3l5zGADw9E978cEV4vTK83NGiO4Xpplww5R+mL/6IH7cWY3SRicCpDhvz/qv9M6IfyHtacfk4rRjcmkTRJKCVt1x11tsjQqLNjsHbvyTsNQPodOB8nrR5/MlIHQ69P7ySwQa6qHrFafPcg/ActIUpJx/PqzTT4blxBNl1yEIAtYpU9Bw8JD84wY9NBkZ8JWVwV9fD11RBA8pCWwqvuD110SNEHKRbsrphGPdOpRedTXUaWno/eknnEDtTgRaW6OemaVEVDqQhvc/wJHZZwEANFniEHbAzgsP1sFQGGL0MQKH67kPI1RqX3gRTR/T7cK6/v3Q94fvQaja+a+2CyI6g06PvD5BAINm8iIFoN1sJ98RvtW31wm0yGGQi55Yp02NZo9p9FbglCfoH2ucrrxZofLpfwF7bfh1jwK8gs6d/pkWNDrEOfhQs3fYbp6yRid2VcrPUMqyxtaGGAsEQXSoSAGCjdakHhjxnKpM+f38EEKmK1BtMSsiJUbUFjNyH38spEhh0RaGFh+WEyZDk0FHflmh4a+vh0/iGBwKNhWvTknlBq8CgEqmyYF0OlF61dXc8yoffDCq1zjaEDr1RkIRKh0ERZKoff557r5GOsnYx4fb2bCye+dO/vlMV4E2izkw2u2ioivn5s1wbKCHajUuWsQtNx9/vKgIr82wM24KJ0Q2emsL1/0BDJgBTLpZtFgqsFQWC5JmzYpt25NuDtpuu2CFlrcVWPVY/LbbSdS28jlxq0GDw3XiSFF2knwrLCtUdlXacKhO/qCTZe1ebbTSCbe8q6gTjYsXY+/YcXCsWxeX1xK2wrL2BQqJI3nWmbCeeqpoMjsApJx3HlIvvACazEwAdL0g5fPhyDlzcHDqNOwZPAQNCxeG3C5FUVzqR50qFiqsv1Wvzz7llgWZe0rS/t2FWFJoilDpIKTOlYaBA0X3cx5+iLtNOhygKAp1r7watB1NNp92YRVpoLUVJZdehtIrroC/oUG8PvPlajesUEmU8VnuSODiL2hbewn5r7zM3db16RN5xk+iEQ5j/Ptj4OsbQq/bhfljfx0Wry/G1Yu2cMuqWtx4+df9ovWyQ5gz9cmk/w5ObyDk9IHMbiZUtDniuUZaZtgn5XSh5ulnAJ9P1vekLXDpJLVa6fLpAFQmEwpeexW9PlxEz15jyH3icRBaLR9Rqa+Da+dOkTNx7QsvckMGpYgMPtNSRaKTTf2YRo+GYSg9WVjq1RLPKF2isf/xB1q++z6qdQOtSkSly+HeI56JknTmmaL7xlGjkHzOOQDo2hS5+R4AY7nPFF+RzFhwj8B4SjqqXFcQ2tEzJjihEv/iyEgYhvMDAHV9enf46weRIgm97/hUfr1QBPz0NOdOxO0L4LL3N+Hh5buwr4a/siltFF/NWfUamPXypWxJBi3yknkRQxDA5AHiwujkDnSN7Qj0gweJ7msY4SIcaaHJ48WMr6YGgRhC3ELYGjWV0dj54ryHIWcoqcmkP9uBhgY4N20KejzUWBPXjh3087OzQRiNoqicMLVNmOTHqERbx9HZBOx2lF17HSrvuivoglkO0q5EVLocAeYfZxgxAn2WfQXD4MFB66ittAggHQ7O6lmKymTi5434aKXNjjEHAMfmzaL1tQWFdMfOsuuAlQ+0/Q0kOqISBnYeEoCukZ+XifrI2W2HZOnlwIsDgbp98dunGLnnq38irnP5xF747c4pYdcZlMN/Hq6a1AcfXS0Om3e3E6xhkFio6IqYgnhBSIltn/fV1uLgSVNw6OTpAOiQvuvf6Mfbs+leJe3T8cgNPOTcwx1OePbTUcesO++Athdd2yLttATotE/9fLoD0jxxIgiCEKWzhUac3PYlJ3BS2BHahRFeJMv9LYS49+1Hxa23Rb1tRah0EOxVlb5fPy7EJ0VltnDrhhpypjIZRYPRAnYHap7h25xdf28Xra8tyAdqdwP/LAHWvxHbCVWIlxUqcfBjiRFhTlebL+MQ29H0Pxk45jzxMm+UVwc+N7D3e9pLZm90IdK2QlEU9te0wh8Q/88dHj+Wb5cXwiyTB2TgsdnDI6ZuxvXmh10OzRV/NvSa7nd40UimkGsyMmA+Udxuz9aYOTfRFw2sdXrtSy+j+NxzUff6G1G9FlurwLpWK3QcchEVfmaQC54D9CR2Xf/+0KTS3wG/xLsKAPy1dXBt2wYASL3kEgCAftAgmCdPRvK5c0SCSGWij3O+qmrRNo6WiIp7Dx/ZD5UGY6l+5JGYtt39jiRdFHYgVbjWWvaETDoc8FXRJ5Kk00+DYRg/aVJlMnHWz5TXi6ZPPhFtw1tczN1OOe9caFJTxW20gTbmOzsxokIQBCwnnwxtQQGSTjmlw19flin3ie+7miM/J+AHKrfx93WJTaN9uqkUp778Bx7/frdouZxPipRoh4YJDdhmSPxMMizdqz4FkI8QSS88WIEhrC2gSJLrxKufH2ZUA+hWVsemTZwFQbutBRRiR0aoqIz8PDb2OKvv3x/qVHpERM3jT8BXLRYZgWamiDYtDcbh9HGcUKlQ9O47yHvySdG6rNeV/fffxS8cCIDyR/7OdjbCLp5IQiVW0zxFqHQQ7D+RtcqXgxMqLTa0fEWbq2myskUFtKLUj9cL+59/iLbB2nrnPvUkcp94gl7oFyhyfxtdDztRqABAwRuvo9/PK0XRlU4lvR8wVZBKc0lCnX6JIPzlEeCJdOCD0/hlP90NVGxN2C6+yJiuLV5fIlpuc0cOJecmRydUhuYl4Z1Lx+KbuZNgYWpZRhbQB9yLJ8TmNXG0kHoxPSIi89ZbAQQXrLM1BiKh4nIFWRIAgOuff+CrEXd1lFxwIUovuxwty7+lt58RbIiokFjkUvPszCB/dTVn0KnNyuKEir+uDhW33S56DtftkxZ53hXrUOveFZwejJRK6QqwkURAfuK3EF3fvjFtWxEqHQQrVMLZv7MnYfuaNVxoUZORLmplFgoV0uOBvo/8P1zkROsTVJH72xhGZIVKgqMAoZDmdrsEJ90NZNLOpHA388v//B/wZBbwg2AMwNpX5Lfx3nSEbJlpJ6lm+U6R1iiESt8YHGVPHZaDUYUp3P33Lh+P1y8cjWsnx3YwOlrIuuduFH34IdKv+T8AwZ5I7AGb8ghmAblconRC6VVXw7l5M4rP/y8OTpkKkhE1pNMJbwktLFtXrAAAqDMVodLR5D79FJLOPBO9l3zGLWNnBrH/H3VyMgidDhqBCHH9/bdoO6x/iiYlslBRZwSPEmEJVajblSAdwohKhKG5rN1GlMZ5XezI330JMP/EaFI/QtQZGZxXA8AIFcZ0ivL6OKMpQivurhAJFY9A3bY1ouJk8q+mtPDr9TSMzAFImPr5438AKGBzFCPbKRIo3xx5vTaQauKFisfPe+7YQqR+hOmefu2wvs+06jFrZB43ebm7odLpYD7uWK6+QBrxYMPagRb+e0e6XFy3HgDaefTa6+g7FAX7mjUAwI2JEKJEVDoebXY28l98AcZRo7hlbOqHRc38X/QSqwkhfoF/SiQ06YL/s0aDQdv/hp4p3vbXR+6i6WwCgohKQDJEVwrbgp1+/XVRbbt7Hkm6IFyNijmMULEECxVNeoboi0BIUj+Um/6Hp111lcjlUNgpA7fgQxNLROXIn0ADYyntZBS9zKTjHk0yU9wrFBu+GK31beELW9uKTiAUam38/93mko+o5KfyRZt9M7tIiu0oQJsr9lZhIypCi4HGDxaJpqUD/FUlwJt6yXX7xc0LSaFdsKkfFvb/KxQzUgJN9DrqtMgXeBpBREVXWAiVwSDwbjkaIirC1E/4iAorVFSG6ArFFaGSQFp//x2l112H5mVfcy58cmKERS6iojIZYRjGF+updDoQOjp6Qnk93KRNfU4y0k/iW3dFo8M9gg+NP8qZJDW7gQ/PBF4fA7TWAI30LBi5Scc9mmG09w32/tD2bbjDX320hV9212D9Yf4qrEUgToTFtIuvOhbnjMnHuWML8N9xhSAI4OZp/UN6pygEo83JQcGb85HzOO1SHLDZaDfSFv7/2vRpeK8df20NqEAAda+8Erx9QY2aQuch7b5iLSe0hYWwzpzJLRdOuucdaVMibl9Yi8jeZsVLoEFeqFBdqHWZvRgHxH8D2XWZIZ5S8RcK5WiUQMqvpx1LHWv4gtdwNSpqiVDR5ufDMHw4CJ0OpvHj4a+vhzY/nxuMRnk8IJmICrH5TSRrD6IOOSD0emiEERVR6kcQUdn7I7DyfuDYa4BjrwPUgo9DtcBn47P/8rcVoSImg4l2OUOEZikquAZFpQUu+IR2td3zbdyFytqD9bhm8RbRsmZnsFCZM6YAJw7MxIkD+Sv2047JgdXQvUzaOgLrtGkItLai5smnQNrtcPy1NqRpoxwN776H5qVfBj2H0OthnjxZ/kkKHQohESo5jz5KLycIFLzyMo6cUwr37t2wr12LlLPOAsALFU0UqR+h9QJbjKqWzBcSUvf6G2h4/330XrIEhkGh00/xhvJ60frbamjzcmEYNoxLgQojKr7y8vDbYC6wVYboivYVodLBhMtVCiMq6df8HzJvu40rIC1a/CFAkiAIgLAVAwCog3/w/3B7CbR5JPqe3gjMXSe23HaHqFFZciH9e+X99Mn0+Jv4xwhBsK1SUCBmTInqffYY2L+HxwaQAfHfDaCFISmpCbn7ED3V+eAq+r6wEDcObDwcLJqaXXwHCtv1YzUEf/0VkdJ21FYrrKeeCtv338O18x9RRCUa5ISN+fjjodJ3vzbvoxFhRCX/lZdhnSE2fjQfPxHu3bth+/Y7mMaMga6oiG9PjkKoEAQBTWYm/HV1ME86HgBftyLn9Mq2udc+9yyK3n+/bW8qRmwrVqDizrsAQbt06iWXIOW8c0WpTW8EocKmfoiukPr5448/MGvWLOTl5YEgCHzzzTeixymKwsMPP4zc3FwYjUZMnz4dBw4cSOQuJRx/XR2OnHc+mpYulX1cI5kVIkQ0rCo9XdTlQhAErVy3fwqima4bCWz+jDu4ERr6ql3fOz94CKFDMOE3VI3KHy/Qvze/Bxz4JeQ+QhXs2NijERrgeWzBxco+J+CVWKgbksW/4xxRaZapQRFHVOjbSTJCRaF9aPPyANC1CbEKFTlUxsRNn1aIDaFQ0aSnB3nq6Hr3BkAXSh859zxQXi/8bI1KFEIFAHov/QJZd9+NjJvoi0bWtj9cjQo7SiXRUIEA7SYr8XRp+vhjVN4r9pUKNDSIIixSuBqVKD/fCRUqDocDI0eOxPwQBkfPP/88XnvtNbz11lvYuHEjzGYzZsyYAbe7jZ0pXYDaF/8H986dqH7o4aDHVBYL1GFqVIShRVExrJDiv0CoaVFSuz2Zc7BVqdn0gkyra6vAhChU1w8ZAEo3AD/cAXxyLlAT3H2AXieE3Pcei0YHaJluAFcz4JGIEp9TvOz6tfxtNhoTZ6HS5AwWKnuq+Kgam/pJ6mZzeLoC7Akp0NwcMvWTLRhAKkf6tdcK7nWvEQRHM8L2cl3//kGPawVz1UibDYHWVq49WZ0aXbekNicH6VddyUXRWG+VUDUqQMcNLZQWgwvxCGbZsfWR3nJ5d3WKJPnxEFG6LidUqJx22ml48skncfbZZwc9RlEUXnnlFTz44IOYPXs2RowYgcWLF6OysjIo8nI0wfbYy6HJCV8UJ1ToxhEj5VfSGkGogsWIiomooEXmw9Faxd/e+La8jb63FXhfEMpcGzy5Gectkt+nno4wMvLvV+LHfC4+omLNA3KGyz8vjjQ7+QMXa4H/ycZSOL20QGG7fuRSPwrtgy2a9NfXicbYmyZO4G4nn3EGd5uQSetEOk4odB791/yOfit+kq050UoGwJIOh6BGJaVNr8dG4L1l5SEFSUdY7PubmlBy2eUR18t74XluEK6vXF7YUIJARLQ1Kp3W9XPkyBFUV1dj+vTp3LLk5GQcd9xxWL9+fcjneTwe2Gw20U9XIlwBnTY3L+Lz+3y7HEWLPoC+bx/5FTytIGSyL2yUBQEPsPNL/gGKEkdUiv8EHk8Fvoj8oQvCGF34ssfBCY5mYMU94se8Dl6o6CTRNEMK/TtUIW4bYdM8718xDneeyhfZVTTRVzFsREWpR4k/bCRUeMHS75efUfTee0iaNQvZ998n8jgyjRuH1MsuRcaNNwJMqjfkRYpCp6PNzuZSPEGP5eSIDMx8FRWcuIg29SNF16c31OnpoNxubgqzFM+BAzg8+6wg+/54UvfSy/DX1kZcT5uTA20hPaiz9vkX0PDBoqB1SEFbvrRAORSdJlSqmT9qtqT1Ljs7m3tMjmeeeQbJycncTyHzR+ksKL8ftS+9DOdm8QAyOUINIxStM3AgzBMmhF7BaxekeXi4iAoAlG2iT5D7fqIt2uXm++z+JuK+iHcsWdwVpMDDCo5mmSsIn5MXIlKhl8J8dptL47o7bOFsslGHOWP4q7wfd1aj970/YEsJfZWXpAiVuMNeafsr6SimymKBrrAQhFqN/BeeR9pll4mfQJHIuf9+ZN48D72/+AL9Vq6Acfgw7oSXdPppUDg6IDQa9P3ma65Tp+V7euiofsCANk/AJggCpnHjANDjFliks388+/ah4b2FbXqNaHD+zc8os556asj1NNnZ0BXSxxxvSQlqn3suKAXEF9IaonYbP+p8VO677z60tLRwP2Vh8mZbihtxzeItKG0IHoDU5PBi5a5q+AJtnCbM0Pzll2h45x2UXEofgMKF4YwjR7TrtQAAHrt86kcreB/uFuCPF4HPLgDeOznyNk+6B0jtA1z7O3BPsbiOgiVrWPAyBZrU3vTvbR8CSZLpzj4n7UMDAFZJSD+F8b1x1IkHR7aTZgcdUUk1aaFRqzChL50ff/nX/aL1lNRP/JEae6mS5GdjpV93HaDRIPOWW7hlxuHDoOtFfyZ6f74EvT5aDMvJUXx/FboMKpMJWmakgoPJDFimTGnXNvUDBgAAPIcOc8tkh/rJDMyMF6wlBgCYJ4a+kNZkZAQ5Kbt3i2cXtWUqeKcJlRxmXHqNZCBXTU0N95gcer0eSUlJoh851h2qx7lvrccvu2tw4gurg0bdX/7BJlz30Va8veZQu96Ht5QXSs1fLQMZRqiEs1qOGo8N+hSxmjYPzhE343hswbUSQk64TXx/7BXALduBvNH0Vb+wjoJlzGXByxRojmNsoKt28NETMzP/xesE7EyE0CL5XBtT+GhMU+japljwBUi0eujPRwpjoR9qirEiVOKPRhIhVodwos667VYM2rgBxpHyaR5NaipM48fLTmtW6Nqw3ZtsVE2bHznlHw59P3pmlvcQf66S66hRpyQHLYsXwvZoobmdFJXJFCTWmz79DIfPOhuODRsBIOZCWqAThUqfPn2Qk5ODVatWcctsNhs2btyIiRMntnv7F727UXT/ow3iE8E/5XSK5vMtoSMy0eCv5x34Gt59FwgEQq6rDSPAosZrR1KR2F224GKJADq0GmiWnPjGXU230l76TfBVv7R2AgCukDitSqMBCjy5IwG1jk6xsV1VyUzKxWunBQwAWGX+/8lM+idONvpCB9pkpquHLaiVotSoxB+V0L8Isc/2Ujj6kf7P2zuriY2yeSv4FIr9zz+D1qMS2C3L1l72+/WXiOZ1askARueGDfDs3YvSK64AAM5NnYjSlRZIsFCx2+3Yvn07tm/fDoAuoN2+fTtKS0tBEARuvfVWPPnkk/j222+xc+dOXHbZZcjLy8NZjKtfPHl/7RHZ5a0hBrRFi7BozltcHHZdYXtbm/G0iiJ8hIaEysVEpZKYkyNrky80HzvxLuCeEqDfVL74k0Urc8DsfQJwgmBkuT5xav2oR6UGtJIvXQpTVFexFTj4K31bTqiw/wtPfIrC2Y6fJIMGahX9QclNDq6sz0s2IMMiP11ZIX4QasV3qKchFaDtFSrsDDfSThflB2w2VD/8SNB6Abs9aFk8oLxerqRBbaVTmfmvvIL0a65B2tVXBa2vTgsvZDj7/CjN3oAEC5UtW7Zg9OjRGD16NADg9ttvx+jRo/Hww7THyN1334158+bh2muvxfjx42G327FixQoYomxZioU0s/xVZYvLh9rWtitRduhUKHT9afM1Ns/YbhhPjqLrxkFr8iN/YhPffpwsbo/D+YsBSzaQ1o8+SbKFS0KhojGELpIVricVNwpiCoV5W4KfMn14Db84f2zw8/RMDYNwHlM7YDt+Us28CBmQHVwn8e7l45S0QoJgJ94CXWsWi0LHIBUq6vYKFWZ7lNsNyu+Ha+dO7rGsu+9G1j10p6Fw1k48EQogNlqUNHMGsu64Hdl33RUcQYoQcelyqZ8pU6aAoqign0WLFgGgK5off/xxVFdXw+1249dff8XAeNRxALBIhqqRpIwRGuju3WOfWoV1B9s2nZKM0B6dev5/0evjj9Drk4/btH3xiwW4aIn5mpfQ/3wvrPke3jsltZd4/V6TgHlbgev/EhdaiQRISujX0wtOcAb5WiAFBpHHDMX/XRsYp+VBZwBZQ4KfxwmV+ERUWLM3tj4FAAbJCJU0sxJNSRQFb7zO3VaESs9D2H4O8KZtbd6eQPiQDgf8TFes+YQTaHM4xkSUTFBEhRuoazLJRggtJ9KzqFhX5nCTokmPh+/66Sqpn87EoKX/oJdMoEPw5U0yVdICPtsce60KRVEItIa/ElanpcE0bhzUIYp+Y8InqE3RmYEippbHy+xDikCoTHuQvqrXWwGdpDVOKFRMoT9UUAnEnl4RKmHRmYDx1wAggDP+FxyBygh2sgTAC8C4RVTo1E+KwHVWmvqZMSwbucnRHyQUYkMnsExQhErPQ9jdSeh0MUUO5CB0Os4YkLTbOb8U1hiQHXSbKKESaKW3q7LKd7DlPPwwMubdRM+jA23ilnLeebCeeio0eeKRMb7ycrh30y62KmP0LdvdUqhQFMW5b15xfG8QBH2lWdcauiOnKC32DxPpcMoWzybNmsXdVodoT2wTQqGiMQQXwWYMAJKL6HTPJElnjxDhBGR9lPunVWaOROS054G7DwPj/y94eKO0gJklzqmfJkaopJp4oUIQBL6+8Xju/m2ndNyk1Z6OIlR6HsYxY7jbcalLBJ9yaV6+HPWvvwEA0DKutexjiapRIe1MRMUqXxiuTklB5ty5nCMtAOQ+8TgKXns1aBSMe89eNH3yCX1HOlU+DN1SqLh9JLxMO3JOshF90ukTunDeiTT07fC6caj5EOxeO/zSabcMXj+JR7/dhVV76OJV0saYu2nF3RO6oiLkv/IKUi+9FOZJk+LyngAAvz/NvJ6JrjeRChVzBjB3A3DLjvDmbCZBzjTU7B9AvhtIITQqFR+hkkZUkkK0KMY59VPdQovxrCSxsMxP4YW4UasUeHYUOumAUIVuj/DkHC+hytap1L/GpxW1uTmi1wvITFiOB2zWQG2J/aJbmgZrEYzHcQvmA0WiWwoV1plTrSJg1qkxJI8Or/9T3syt4/aJIyFbWhfjrOVnYeJnE3HzbzfLbvfzzaVYtK4YV3+4BYDgHyhN6xAEkmbOQM4D97ep6v+VX/fj5s/+FtfVOBqALcwobx+TxtJJFK4xlRYX0g4UKUI3QG+YlNiQWUCfE2lDOIXYkLrQZoSIYuhlUj+V2+n/dxuoaqGjbtJ0j9BLJZSvikL86L3kMyT9ZxZyHg4eTqrQvREWqVNh7CpiQSUzzFaTTQsV1vbCX1eXkAgeGSH1Ew51corovuOvv7jb0Ti1s3RLxyd2pklusgEEQeDY3mn44Z8qbDjciJum0akhVqgUphlR1uhCie8X7vl/VgT3qANAebPYv4S1y1cnJYnULBVoe8szSVJ45Ve6APOqE/pgVGEK/cDaV4JXll6lt2UWTzhHVI0euPy72LepAGQfI76f1ld+PTai4mYiKnt/BJZcSEdkbtwIJOXKPy8ElS10hExag6JSEVh/3zT4/BTM+m75te9SGEeNQv6oUZ29GwqdjdwA2DYgZxzIRVTS00FotaB8PvhqaqErCJFmbiP+errRRN2GwYqhhg7qBw1C9n33wiX7qMx2Yn7lo4AypnC2MJUu1jm2Dx2O31HWDADwBSiwwYqrJtHD/7SU+CTvCQTXsxCSketcNbSkDiX1/PPbvO9Ngsm3KvblKArYLDPHYdhZ4vumGKrLBzETXFlXVYX4Yk7noygpvQB1CHM1NkXkoufvcFEzdwtQF31olKWKEdN5KcEHiNxkI4rS2zZzREFBofNQyTRjsBEVQqWCho2qVFfF/bVZR1x9nxCDcsOgLZKZxadWo8+XS6HNjt5EtFteWpU20AfrQqZANpvJ17d6/PAHSLj9fDiODYOTEEdBGp11yNUli4pNpbYTgRb6KlidlIyCN16H/Y8/kXX33VDLhOmipcbGCyRfgFFTfg/gk4l8SH1Toi2MBYA579JmZEXHR15XoW2c/TY9ymD4nNDrWJgvq50x7av5l3/MHXrApRwURaHBQQvdLKtS/Kyg0F2Qi5IIzzPanBz4ysrgq64JWq8tVD32GJwbN6HP0i/gOUKbper6hIgKhyH1wguhMhihTk5G1QMPAKAN8AhtbK7Y3VKoVDTTEZUCJqIinGnS6vbDx4TjCAJIN+sAUAhALAQaFp+J3PpS4JpV9AwcgIun6AI+lN9yC1pX/gyATv1Yp0+Hdfr0du97jcB8jquj8Yap5p72IPDbk8CJd8f2QjozXX+ikDjyx9A/4WDdau21QMBH/2Zxx1Zga/f4EWBChSkmxR5fQaGz0A8cCM/+/TDGKf3HTtNmSZ79H9F9NePVEmhsjMvrNX+2BADQ8u238Bw8CADQ94+9MFyTmor0q66Ee98+flkMkRTuOTE/4yiglmlDzmEiKVq1CiadGk5vADa3DyomNGLQqOl5JyoPQNDipa/Xh8M6LRrsVQAVAP56BTif7g9nIyoTqnahdcvP3OuFmpDaFv6PKdQFohQqJ9xO+6kUHhe3fVDoQMxZAAj6s1a/n/7NEmNEhZ3zo9OoOB8hBQWFjqfwrQVo+uwzpF58cVy2JyxKLXhrAaySicwaxrbe3xjfzh/n5s2gnE6okpOh6xt7RIVFaHqnMseefu6WQoX1SxEOY0syaGmh4vJDq6EVR6GmGUXly6FT0ycHDaFDvt9FCxW2W0dGJKgocYGUOik+9vJuX4C7IgYAFytUPGGEikpNz+VRODpRa+i2ckcdUPWP+LE2CpUkZdiggkKnos3LQ9Ydd8Rte9apU6AfOgSmceOCRAoAqNPYiEpTu1+L8vNlEM6t2wAAxlEjQajaXtIqdKvVpMc+UqDnCBWjBtU2wOb2cQf0RcRjSF5RibN1M/AjAMqrQzrTTlbPCpVavqCRrRkxBPiCVwBQGaOoB6Co4CIXCWWN4lZht48RROEiKgpHP6m9aaGy4zPx8jYKlWRjt/xaKyj0WFRmM/ouWxbycXYQYKCJTv1QFAXK4wnZdRMO1uIeAPw1dM0Lay7XVgiVCr2/+Bz1by5A+jX/F/Pzu13XT4DkCwqlERUAsLl8nPFbHllJ/zbuBgAYPcmcUOEiKrZKwEfXjbi89GNGv7gjiIw0Xrt2L/B8XzqNFIbiBrFQcfkCtMB5f6Z4RY1if96tGH0p/fvIGvHyGEzg/AES3+2gK/6TjUpERUGhJ6FhIhb+BlqoVD/+OPZPmAhvcXHM2yKdwd5abWlNlmIcMQKFby2AQTC0M1q6nVBpcnoRIClBoSxNEnPwtrl9OFAjjlCU6OlISbLHggzG0bZBzf5pKKC5BABfM5LuF59AIprs/Pwg4GoEfg0ezS3ajwZxQa/HFwDq9tL7wHLMecDVP0OhG9F3ivj+yIvo37uXA9/eDFRsi7iJReuK8dmmUgCKUFFQ6GmwqRW2mLb5syWg3G40Lfk85m2RjuAO00gTkRNNtxMqtUx7b7pZB42af3vskLYGh5dz72Rp0tPrpXoNwREVAGik27NcvgB6EdW4mvqRe0idnIy0SAVTUaZujtSLPyAubwD44nLxSnPeA3JHQKEbkSKo6E/rB4z8L33b7wa2fUgL3Qh8ubWcu51qUiYjKyj0JLiISlOT6MJZ3QaBQTrkIiqKUIkrdXYPblYvw2Xa30TL81PpdEl5k4tz72RpZTRJcoAS1aj8GRhOP+CiVarbF8Bgogys5Ur9CaMx4IePoW3cEH7AEino5Fj1BLDkYi6dJKSESf0kMe3UhKseqN8XtJ5CN4Mg6DbzvDHApcuAgmPFj7eUyz9PgNAyf2ieMuk6WvykH9tqtsErqTtLJN6AF1QMA9kUFCLBRlTIlhZ4S0u55XLW+5GQi6hIhwt2NN1OqHgqduJ27Ze42fWmSDwUptEtUYfr7Ki3e6Bl1IadILCPqT2c0z8DRT56eYlWhybQ4ob00P84t4+ElXCC9NNFsUlEI4g3xgJfXgns/SH0TtkFJjx/vgjs/T64HgFAMZP6GZxLn2iSWg6IV8geHs2fQOFo5MS7gGtX04W1OhOQ3p9/LIrJysL5PUNyFaESLW9ufxOXr7gcr257tUNe7+sDX+O4T47DLatv6ZDXU+gZqJOTuRlu7n9500gqUv2kDGyNin7IEG4Zoe9cA8luI1R8ARL/lDfD28CrSQiKXosYobK5uAkUBWSo6X/Gbdl8q9QxSRpkBwLQB1SgCAplOvrPU11P96bbPX5YwQsVa6Caf63S9fI7Vvk3V+MionRD0KJ6O72/vZh9TXXQRjvoNQmYch9wwaeh3r5CN6Ns9muYVdQLn1stdETPH/6K3+Ona6s0KgIT+8YwSqGH8+7OdwEAi3cvjrhugAxge+12+Mi2D377aM9H8FN+rC5bDZKKzxwYBQVCreaiHt4S/hxIutouVNTJych++CEkn3MOTOPGxmU/20q3ESr/+3k//vPGWvyyTZAq8fG5NjaiwvqUDE8j0aJSYYOR76BJ83pAAEjx0OGyCi297vdbD8EXIFFv98AKF3wOOgSTTgnmKoSaWFy1Q375tg9F/ij+AMm1I7PdSs0NdCSmRFUETLkXSO0V7k+g0I14/chyFKspPJnB+A/Yw1tj2z10JPCps4dDpQrfBq8QjDGKTro719yJS3+6FF8f+Dour9Pojo+LqIICwLcoe8vLuGWkK7jeJBKBlmZ6e1YL0i66CHlPPwVC3bkGkt1GqHy8gY5aZBIC7wlBEWtOkgFaNX8APyHdhl9N4oOT7u+PAACaAC0UbEwxLul14tfdNahr9SCnpR6eZrowV2cV1J4QIf6RocL2zgaRR4vDy28rh6k3cDvo7qKfDtiVnHYPwx2QXAk1Hg67PitULHql4ydahHUpOeackOu1elvx4a4P8WvprwCAVaWr2vyaTsHF047aHXD7Y7/iVVCQQ8OYvvnKK7hllCSi4qupQclll6Np6VLRcoqi4Pp3FxoXL0bNE0/S28sO/Z3oaLqNUGHJJQRXKV7+oKBWEdzsHwAYrqvGGoFQmWHnC4gokrHet9DdEyZ4sLm4CR4/iXQbLR70KT4Y0wQh4FCeF3KusplM7s/Diyqnlz7RaNUE0s20UDKD/pA5KD1XaKvQ/dlSvQWry1Zz9ykAOBT65Gj3+GF3M0LF0Elmb3X7AVv8J7cmkgYXbzeuDnGhsb12O47/7Hi8uOVFblmaIQ0UReHVba/iw10fRv16b+94GwebD3L3b/39Vly18qo27LmCQjBsQa2vTBBREdSokC4Xym+cC+emTah+6GHRxW/rihUoPvdc1Dz9DLdMm9s+k7d40m2ECmv6miGKqIirlwtSeWGS5S7Bfh0tRN6tqsELdfxByx+gUz+kjj54mQgPNhymH7d66X+8PkmSp3aFsC6Wi6iYmBoCgfOog7kiNuk03BBFM0G/lhMGHKhV3Gl7CleuvFJ036Yi8PXepahuKQ1ad93Begx/ZCV2MyaGFn0nhGhtVcD88cBLg4Gf7o3ZUbezqHfVc7cdMtPJ3X43rv3l2qDlLZ4WHGk5gvd2vocXt7wIT8ATtI4cb2x/I2jZzvqdMeyxgkJouHk/dXXcMmHqp/K+++HetYu77z3Ii+a6114P2p42V4moxJ00ZlpsKgTCQOJfUpCsw9val/Cn7hYYKn9EhZYWBIO9Pgiz+sf26wMASEmjIytGuLkTgdlLH5S80hB7SKEiE2kxMF0Zgum4dg+d+rHoeaFiYiIqdhjx1dbILaoKRz9yKb77c/LwcJIGN8qcNB/+dpfofqekfqoFJ9uNC2ijuqOABjd/cdLqpY8bDp8DNi/9vax11sLldwU9z+a1ocLOh9er7JEjScL1FRQSATvvR4gw9dO6YoXoMW8Zf07xVVYGPVfTTtv8eNJthIqWqSdJIwRCxSdOl4wid2GGegsKVXX4IImOrhSqzUghxdX3gwtoAy4P89cxwYOTVDtQQNTC5KEjKS1GycRkV7P8jsmZvekZoSIQMU4momLWMxOdwad+nJQeK3ZVo8nRcV4PCp1DkydY8P7BREkOOIJPdmYdH0GxGjQoTOuE8QqOOvH9ozSi4iN9mPbFNJz8xcnwBrz4v5/lZ5K0eFpQ2spHt6IRIXsa9kRcBwBQvBb48e6gaLCCQiTYYloh9t9/h2PjJtn1A83N3G3KExwV1Mhsr7PoNkKllTnR9zG5QJGMhYrky55q5A/qe5i0zwV9zgQu/160nsWUDQBwUPQ2x6r240Pdc/hLfyv0Tlp41DLrcERK/Rx3A6Ax0G3GBmbaMhNR+X1fLe5dRl+VmnQazvCNTf04QEd2alujCzErHL3UOMJ397R4xCLApONrUi48tkh0v8OwSU7UvuAoRFekzsULLAoUiluK4fQ74Q64caD5AKocdKQk05gpep7Na8P6St6OIBqhcqBJ7Ik0KJWfd+IjffSxoHwrsOh0YNPbwPr5bXpPCj0XjWBCsZDSyy+nI7WMz4qud28AQKCFPpaEatRQJSfHfyfbSLcRKg5PAAAFbUsrDv2QhdLf0oOEilXFRyTqNLRoGZpxDNBnMu1VAgAgYGZSM62MX0ISwR94A0yYxdNrLDyUBn6K+RMKhUrZZmDDAtp9tqmYXtbreODeMrrNmEv9tAA/3o3kT05DdSP9oalodnFzidiIiosRKjZ32/0bFI4OapzhhcrDax/G0xuf5jw4zHpemPTNiN2FMi5InXOPEqEiTdkIxUSpjY+YCFNEAN1WvKacN2wsthVHfK1DLYdE99859R3utsfvAT6eA7w3TfAiRyJuU0FBiDqEUAEYt1kmc2AaPw4A0Pz556AoCvbff5ffXlLXMY7sVvPgTfCgYacWPocGPocGgcYGCEsLjQE6ukEBqGX6wrNT+9IPnv028P1tQJ/JsGrptI6DDE61sGZvE6aejHErRiEJDqw13AK4m+kwDkEAC6fTK6+4l3+i3gpomBksbOrH2QDsWobRKmCcah/WkcNR1+qBXqOCCW70V9F5w4z0DKAOaHEqQqW7I4yo3D72dny+73PRFftvZfRoiBPyT8CJBSdCMM4K2cmd4B5JUbzLcmofoOlIlxcqftKPHXU7cLhF3PItLGw90sILhfE547GxamPI7UmjJXI0e5pF91P1qSBAgAIFd8ANS7kkPK/rJNGpcNQSKqICACTTrUrodNBk0dkAb3ExDp54kqj4Vkhne6cI6TYRFQDI1rq4iAcAeCvEV0xFJvpEbycIuJgwWGYKI1RSCoFLvgQm3YIUfQoAYK+jHLPzc7FPq8WcvBzMT0kG6aOfZ8nIBgxJaAJTqxLwAsV/hd45oVmbiflAlazlFrkpWsS8eN5IEASB89W/c48ZzPRrtLgUodLdYSMqFwy6AFcOvxIWrYV7jBBEaNnWWoeH99+Z3K8THGkbDtJRQ40BGDqbXiZTgNpVWHFkBaZ9MQ1XrLgCO+rEZowf7/mYuy0UKo8f/zguGnxRyG1urNooqneRgy3WZSEIAgYNLSxd3mDrgd89tbh7zd2wRznQVEFBGlHp/fkS5gE1l+ZRSaIkoURKV6NbCZVMg18sVMqrUWWvwvzt8+HwOZCmog8IbNrHGiBhkLly6ZfSj7t9WKfFLdmZ2K/X4a3UZC6iojKbkJ9ihBP8jBV8eCYXXhMx7GwgrS9/n53ZI3Ab7Z+mxZFnTse5YwsAAIMJPvTstdDLlNRP94cVKtlm+qrnnmPvAQBc1NKKXDI4l8wavW3svxiatyYgwMylKrGVYO6qudheuz2xO9zMfE7T+vJt9100okJRFO76466ggmVpDQrAC5XJ+ZORZ8nDnePvxJIzlkCv5r/v+ZZ82lMFFL7a/1XY12aFyml9TsO7p9K2/axLrbs1uKNvXuvf+Kn4JyzYsSCGd6jQk1ELakos06ZBP2AAfScQQNUD9AT2QFMT7+VxFNGthEqGzo+Al39LvtoGnL7sdLy14y0s2L6ATs8AaBp9MQAgzZwttxkYNAbkmfO4+zWMsAFFCYSKGUkGLQDJP71EElUh1MCcheJlWUMBtU60KN9KgBB8gMam0fUp7yXfDLOZFlNKRKX7wwkVplh7fM54/HbqYtzT2AS1YAo3O2/G7vFDjQCyy1dga2sJjl96El7a8hKu/fla/FH+B+74/Y7E7rCNaWtMyuPHSHRRoSLXapykSxJdmLDsa6JHcaQa6M4HrUqLYRnDYNXx3X4p+hScP+h8ABAZuUln+ATIAMpaaROu60Zchwm5EwAABjXjQH14NUJRYpOZE6agIIMwVUOo1SCMRkBDV3e4d++ml+t0SL3oQtnnZ95yM5LPPjvxO9oGupVQSdf6EPDyJ/vNrTXwM507B1sOci3Ezcw/L9kauk/8yROeRJqBDqX5GQGh9wGg6NtqsxlGnUwO75DkoJM7AlBJ1tPoQCUXiBb1SxGs03AIA2z00MJzTzkRyUxxrc3lD7m/RwMkSXERAAV56px0KDbLlMUty0wfCBUAtaA6v2X/j/hzfy3qWj3IRDMAYL3RAGfAgw92fYBKBy0gal21id3hHZ/Rv625vFDporbw0o4pABiSPkQkPqSkG8TpNJOGd7c2aU3It+QDAFYUr8DairVYun8pjv/seGyt2cqt99TGp7jbwtdiUz/ug7+GfH05cRUzzWXAB2eEn/Cu0L3QqEEQBNQWi2hxzoMPQpOWhoI33+SW6YcMweDdu5Bxww3IuvMOWE+ZjsJ335FusVPpVkLFrHXAL4io7PHyX/K1FWuxr5W+OmnW0OFbthZFjvE547Fgujjsetlv/JUSYTLBqKXFxY5+1/ErSacom4PDygBA6sS5wr4pajptVLYZeH0Mtzwlrz8TuTn6Iyq3fr4dY574BWWNyjiAULA1CaKTp84MaIxQQ2B5fXg1Xv7gE7S4fEg1HIKHAFpVwV/n/in9E7OjZIA+AbJ1VtYcuk4F6LIRFWlBKwAMTR8Kp5//PM4bPU/0+LG5x4rum7S8UDFrzFzkCwCu//V6PL7+cTh8Djy76VkAtFfL0v38XBXh/5VNI7ltoc0cI80C2l67HWcvPxt3/H6HaHaRiB/uoCO9S0LX2Sh0D4wjRwIAUuacC0DslQIAxtGjAQCWqVOQ+9RTSL/2WuT/70UQzLFDk56Ogtdfh2Xy5A7b52joPl0/hA/fGpZgtp8/WBsk39s7ySp8B6BZQ5/4wwkVgK7MF3LK3/yJgiAImJiIyoai6zBy2HDg23nBQkUnVrQsXm0ShNZc/VPVwN8fAd/dLF4xKR/JxmoAR79Q+XYHfZX/8YYS3Hf6kLhv/6Vf9qPZ6cVj/xkmSqMdTbAnTbNWUjtlzYGa4gWATaVCP1Ul/k2pQHnWSsxvTkGTOlioBG0nHvhcwJsTxG3JvSfzdgBHkVAZkDIAPxziIw25ZnGU9dgciVCRRFSypX5KDGz9iTAlBPDpHuE6bkmhrRChiJLj0p8u5V6HIAj0SuqFuaPmQkUIPgvS9vEeQo2jBnNXzYVVZ8Uzk58JO3iyu/D/7Z13eBTV3se/2zd10xMIEAgdadJBelURBUUpir2j14IF1Iv1ii9y7dhFvIoFRSyoFOkKKr13CAklvbet8/4xe2bOzM5sy24KnM/z5MnszJnZ2WR25nt+tdWiT2DLzoa5s/L9VesOI9BoNIi77tr6PLU6ccFYVGaZP4bWKp19mGXP9SwdYAdQ5v7UFpP3gjZx5jiv24nrp8buBFr0Ux5k8hQqh86XY12W9FyNnA34+33P/fVGxEbwerIpB9PSRYWsDoWA4zricLrw1tpj+N/W08hqog0cOY4THkz0AxEAkNIFZtr1o9PiCf3XMKWsAgB8GheLUgWhEhLXgZwT6/hMH5fbjdd6CJA5DDCYcUavw5dcWaPsClxm83T9dIjvgJmXzgQA3NT5JiEmBQDmDZkHoyyWTGJRMUShjaWNJDOLkBSRhEpbJZYfWy5ZTwtocqzjRgMQI8bE0SHTtbVlKKwpxJXfX8nH2XlhVdYqfLj3Q88Aas6pOP5C5/ODn+NIyRFsz9uu2LPpQkQbFSURKWnPP++xvSlywQiV3oY9HhaUlgUcrtnqQkSt+NWfm5yIUvBfXF8WlQh9BCLkwbL0drfrp8bmBJI7ArEtPAcp+L9/3H0O1Zys5sXKJwEVYSTGqDRdoVJeK8amhEOoVNnEm/FzPx1QrbbYmKl11oqF3OSWkDZD8EyR2Bk8y6BHtFaciVucTpTKY6Gg3GyvzsjbRaS4b4yGSExMb4Z5Jiu+OfJN6N+3DpRZy/DvP/4tWfd0/6fRMaEjJrWbhOVXL8esPrMk94SUiBTIof8vUYYoaDQavD3Ss6FblCEKC3cvxK+nfgUAaDVafDDmA8mYES1HAABWREcByR2E9XQUV2VVLpYeWYqcihy8u+ddyf5q13h+dT5wZrvYud3F4sLodPOLiajLBokvNBpoIxugxUYIuGCEysbISA+h0qIIuHGDC7f9Lj4YV0RHYVveTgCQzJ7UiNV4NnmLHj0KAATXT7XNyad8JbTxPIDJU6gkRBmE8vgSzu2Uvs4cDkAUKk3Z9VNUKZb/L64KfSsAOkh349ECLN2e42V044QWFSTQUqDXzejc936sGvw6ACDLYMAZvei5rdJqUVRfFhV39pyAO/XeoTXA6vZ1Hyr2s7dNPfG/g/9DrZP/zllMFqy/YT2mdpoKgLdytItvB71WLxEqSvcH2tJFgu1TFbIHax21krosj/Z+FIOaD5KMGZLOxwGc0+vhSuBjiY4bDGKWIYBSnU5ihaEzitT+tyWn1gEfjwKWXO/e6eIUKnJr2MUIHUyrMRqFWJSmRtM8awWWWGI8XD2EQQf5mcdl1fwX+0wl77NNj0r3edw8jlc/Oqc4e2n+0ksAgAh3X5W1h/KQV14r1pGgUXD91NpdsEBhpkubywc/Ckz+FACEYNqmbFEprBRV5I7TpXAq1ASpC1WybKInl+1rchlG+wv3A+AfhpIYA4APqB3zAppljoKJM8Kh0WBtlDg7cmg0yNd7hpyFxaJSXSx93ZUP3DvtFC08LaIVrIsNyOYzm4XlXyb9gqSIJMVxtFCJNXqWEG8V20pYHpw+GABfT0Uez1btqBb6+ei1eozPHO9xrKTIJGjB/++K41viwE1fY1KLZrgpI1MyrpYq+lZcK/7tlbKYAKA4ewu/QH7TtZ1cwbmBssqy8MTGJ3C05GhQ+zcE9N9Hr7lwwjEDQUtn/TRBKzPhghEq8eUcTDblf4TRCTxWVIIONumDvnl0c8XxNNfG8EVzIigjAPHzRRj4P9+5slo88d1eIErh5qcQTJtVVIUcTjkbCAAwZQkw+lmhgi2xqFTZnLA7Q+82qQ/OlYqzv8JKK/aeKQ3p8ZVESVZh0+lAu+XsFjy4js84oeMg5Gg0GjTX8jP4hfFxPo9rdVrhCPWMujJX+jqav5ardKL10WpvPHFCDpdDeMCuum6V19i0aGM0pnScgkntJklSxAnTO03H4PTBmJA5Qcio0mq06JrUVTKu2l4tWHA+HvuxojAyaA1Icn+d86Lj8X3BdgBAkUtqccwqFsVBbpX4tycxNxqZe7oIMjFCZwNZ1QN3vfHYxsfwW9ZvuH3V7UHtX5/szNuJD/d+KCns5yH8LxI01OSlKbrDCRfMf+/e35yCRUVr9jT53VJegVSn9IbdLFq9jgrhmcs/xipHCt6IGwYAsBk04PQ6fH7wc5Q5Rb/nxqMFyjEmsofOj7vP4vudZ/GqYwr2J13hsR2Ah2UmxixebBW1TctKQNiVLa0GeiS3Avd9sQPrDntvwucvcosKAGQHkQbtdHEN8oX+6shXwrKvTJ1kTmoJbGUXBbheIabKV+ZIwEgeduL71VIxMtW1Kt3EG4Dcqlw4OSeMWqNfmR/PDHgGL1z2gmLmWKQhEu+Nfg8vD3lZsv3h3g9LqtZWO6pRbuX7qyhZZgAA5eeRauNFSa7RLOnmTHOSiq+ghQo5fqYlE/OHzhcexkVw4rX4OExIb4YTm16RCstaZSuML0gBPDUrDiGnPAfz/p4n1ANqCG5ZeQve3vU21pxeI6yzuWzq6dsXC0yoNDydzojpyLpET2uFw6pFyoCHhNfJEcmSG4sahsgENL9jLWLbXAUAqDFp8NXhrzB/23x8fOohaPT8DVmjL8fSwwc8D+C+mRAe+no3AKAIFqzv/KJYTp8mWjqT0+u0iHZ3yW2qcSq7ckolr59avg+/7c/F7Yu3C+vOlFRje5bMreAnoRAqVocTo1/biBmf/ON7cIihrR4eGT8youxSt8qDJeLDIxMGXJV5FXok9xBm2pW2SuzO340t57aE5mSp9GOXVo+n/3gai/cvRi3VxLPKxwOtPhFcvTHpYZtZd4jvgJXXrRQCa6vt1cKMXlWofHc7Up289SOPc0jcOjSna0QxL3H9uC0qsaZYXNHmCrw+nI9f2oZafBoXiyyjARNPLcEZKuZFfj/yF39dJ1cuvxJfHv4SH+z9wPfgMOAt26zSfnH3TTJ36OB7UCPlghEqdh0wzc7fEMxdOsNyzTXQx4iWFVuFThL05o81hSailrfRVhlcQjEnAIhqNx/6mH2IarsAL0YdwDazTPzEiwG2DpnbxmzQiRkTNAmZHqtCFVBbaXVg+a4zqLXXX8oix3E4VcC7YS5tFQcAUApRGfx/6zH5/a04cC7wh5ySpWn/2cCOs/N0KU4VVuGP44Uhj6FR451d72DC8glCiXXAu+sHALS1UqHS7NaVwnKy3YZ5Q+bhiyu/QHIkL9iLa4sx47cZuGfNPT6b5/kFJVT2ms346cRP+O+O/0oa6FUH+UAMB+RvG+64maSIJOFvnlWeJayPNakIlap8pDrcQqUmX2g0KYe+Ekvy9grLxLphMfKurFYxfPxMhUZ67W6NoAKza4P7v/gTmEp3ow7JdeYHHMdhV/4u4W93ouyE6tiLtcFj3NQp0EZFofn8/2voUwmaC0ao6DUcOtv4mYM2MgrN/+8VtN+2B1Gt+C+YrVyPjNjWwvgofWD55IZq3kRbJUvG0Gg4GCy7oNHaAA3wn+hOmGR9HldZX8JT9juQFTdAGPvBJmlbebNRB4x+DkikqodOeEuxaRRx/9Q1oPb697fikW/24NM/s+p0HH955bfD6PuftaiwOqDRAD1axPncZ8tx/qZjdTjx1tpjuO69Lfj7pPJNnKBkUdl8zH/BwXEcHvxKzLqqstWPi+2DvR8gqzxL0tNFHpgpp9wqvXbpANBmtVWA28VJyr+foZrehcQkbxNjfxxacaZN3AMAUB2OIN4gKKopwgtbXwAAtIt3f88qcoGS8PTQUbKG0UXeJDhsSHPw/6u86jwU1Xq/xgGguDRLWCYF7IgQahmtnBxg4CDWabGW43zlecxcOxN/nf/L5/sRaKGi5kJZcWKFsOyrRlWo2JW/Czf/djOu/YkvXuYtDVnNopJTkYM/z/4Z+liuRkKz555D+61bYGoXpirV9UCjECoLFy5E69atYTab0b9/f/zzT+Cmd42Wg6uKN/VrqFxxUzM+Pbi22AhLpOgSUjOzqmGo4IVKRaSniLDElgrLR40G7OLaYz+XiS+do/DqGjEQ7tVVRyT7mfVaPmD2lp/FlSol94lFZf2R4Hu3WB1OHDrPz6h+PxSa2BBv7MwuwfsbT6DQnZrc3BIBg065Lg1tbSIi4bXVR/HamqPYcboEUz70flOlg2mfvrIzdFoNymrsKKjwLxX6REGlJDOpPmKB1GJhfMWoFNRqoaf2pYVKS7sNKD8LQEyfpUUQCfAMmtNbJWn01VQjtH2F+4TlmkYiVJYdE7sa90ntA2T/Dfy3I19ZN8h4DW+0iG4hESt6rV65SjLHAVUFguvnVNkpv1LJSxz83zWnIgdv7nwTgNu1dPAnmBYqF52s0Gr5FgcAUFuOuVvmYtOZTbhr9V0AgG8Of4P//PUfr/dEOi06v1r5HkQaagJhyjZT4O/zfwPg7+dOlxPnKs95jGlj4a3aSiLdxblw1+q7cO/v92LB9gXhPdkGRGts2qnaDS5UvvnmGzz66KN49tlnsXPnTvTo0QPjxo1Dfn5gD2SdloOrhv+iayPFG0VEW97dU3nehIq/9+KN7+Nwy+9O3Nb1toCOry3nv3gVCvVyajjxC6rVS29+pK+NkstGaGpIN0dMU4hZAYQYlU//zEJptfhA5TgO936+A3cs3uYzCDSbqtjaOjH8FQoPnJOambulW1RThumCcJXu5UBqoZx0u5buHpqJu4ZmIiGK/2K+8bt/6ZRVVqkrrKIeqgCX25TN8L6ESqFVi2gq5ZSujJrkdPEWAygLFV/BkD759HJh0Q5gh0nM9DlcdFhYrvZSFr4+oUvY90ntAyway7+wVwPFoS8CZtAZ0L9Zf+H11+O/Vh5oqwIcNUhxu34OFvHdbUlZfQBob/C0ShS7r5nPD34urLOYLMDSGUBpNr44l4vnCorQt0YUpCU6Ld/dGgC2L8KxkmOSY877Zx6+PvI1Xvn7FSjhcDkk16qaUCmn3H31EQ+SV5UnKYKXVZ7lIVRijDHonMC71+UF8wDgte2v4WwlL+w35GwI27ky6kaDC5XXXnsNd911F2677TZ06dIF77//PiIjI7Fo0aKAjqPRAI5yfvZMlwmO7ManF9ur9DjzxPNofqQQ47dxGHouFmf+9RDsef4JIldZKQCgMkL0BQvbqHRAjc4KaMWbBHHVnC7ynGFoyUxLowEe2gPctQ6Ia+UxDgBKKHFSXCUul1bbsfJALtYezsdti7fhlJeU3DNUinBZjaf5NtTZLvLmg7cMao3bL/Msimd1OCXiK6/CinOlNSip9l8sHMrlH4x9W/MPZ5Oev7S/3pYj+XupUSoTkpVhtKhU2avw2YHPsPnsZsXtnRI6qe7rdHEotunQxSp+Jp1WhxgDbznsX1MrZHkQoXK4RBQQSv1uguXfyYlYFCUKlQq7KE7qa0btC5IlM3/ofETKM6KqwpOZ0i2pm7CcHKlsISXvHa+VznQTzYl4buBz6JbUDR/2fx6fns9Dd+pSLHZncNGJAOR/DwA9rDZcV1mFR4pLxX10OiAijn+R8xdslOXG7rLD6S6xX2xVtqjIxS1tOVl5aiVWZa3CkeIjkmuruh7S0/938H+S11llWYLoICSaE9Exga9nc7DoIG5fdbtQrwgAlh8XWxycrTyrOnlgNCwNKlRsNht27NiB0aNHC+u0Wi1Gjx6NrVu3Ku5jtVpRXl4u+QEAl12Dyjz+Cxs1YKAwXp/aAsYYzwfemTvvRsXq1cj/P/8CjBwlfAR/RYRGPYqffAa9eLGX1thxtrQGV7/Dd5ntkyHGH0hqosS3BtJ7qx4zr1x0YVRT5eJpAbPhSAHuWLxN9Rh0LRO5CFi6LQeXPLsKrWf/gllL96geIxCyZT13OqXFoH1qDI6+dIVkfWWtQ2JxyiurxZQPlf//SnAchxP5/AyuYyp/DdAxK/kVvt0dtFACwuv6eeaPZ7Bg+wLM2TxHsr5LYhfc2e1OXN32atV9q2wOWGHA84XFGFpdgw/TrwQA/DzpZ6wwdeZdCW6LCjF50zPoOllUXNJg8F+i1S0/57UcDhQqZMEFi8MK7PwcKD7pe6wbjuOQVZYFAMiIzfAsVFcZHvdnRmyGsKzapuP8bgBAbJQ0w6+NpQ2u63Advhz/JZLajkKfGb/hf1PW4sN0Puuw2MVfy3TAtV3BetHNZsOsIv6eVazV4v+qT+CWZimo1mhgpWJMaEGh1ypn9sjFLbGolNaW4vFNj+OxjY9h8s+TsbtgtzCmPoSq1Sl165ZaSz3cOwnmBAxNHyq83pa7DdN+mYbPDnyGMmuZIEyI8Msuzw7zWTOCoUGFSmFhIZxOJ1JTpSWoU1NTkZubq7jPvHnzYLFYhJ+WLVsCAFwOLVy1NugSEhBxaU9xh8gERCSqz8zt58/7PM/8N95A2bLvAfCunyijd9O8xiA+DEqr7bjslXXC6wk9xCJzdqf/FoyBbcXaKmpCBQBOyiwqR/MqcLKAv5GdLalR3e+JZXuF4y7beQa2EPTjOVcm9bnHRfKzb6NeixUPDhbWV1qlQuWfrGLkFPtX+p3jOJTXOmBzi76UWP6GQ7tyaJGnRqlMuIWzAeTfuX9LXvdv1h8bp2zEN1d9g4d6PQSdQs8eAm/p0SDN6cTCvAIMjOOtL4kRichwCxNU8Nf01e2uRt+0vpL96yRUygPrwjv1l6nBv5ec5fcAPz0A/PyQ77Fu8qvzUWItgU6jQ6YlE6iR1XYJk1AZ3nI4+qT2wZSOU9TToQ/wM3lLxwmS1R3iZSmk6b2hi05BW/f/tpRzwMW5JPEsZoeyxTDdHUi+02zCF7az2Gk2Y1VUJGycKMLpTB21YNISWU0c0vQwt1r5Hg2EVqjkVeVhZdZKOGVVdZ2yZoul1lIPl1OcKQ7t4tsJfZUIS48sFYLMkyOSBVHvr8Vxf+F+/HO+/ssYXKw0uOsnUObMmYOysjLhJydHGsdg7tJFGrwWlwFDtPrsmJQYdtXUoPaIZzxDwVtvoeh9sSZASbTvjCGNTv1LetOADCGglLau+OLpK8U0ZmIt2H+2DNe9p255KK22YezrmzDyvxvx5/FCScxImQ+3yvi3lN0SgSDPxKH/L13TLUiL5bMhvvjrNDYc8TTDJ0V7r3Nz86J/MOb1Tcgvd88yjTo+5RuATiu+147TvouPyYVKOMvv6zRSIdI+rr3gpvHFoj9kcRVJ7cVlEjBZzgsVg9aAW7rcIhleJ6FSkgUAcAKYmeqlsjJFyNyJ7gc7Tm0CVB7Mcg4X8y6vNpY2fO+kGplFpSI8QsWoM+LTyz/FMwOeUR9UyVslDOm9JKt7pfZSGo14C+8SdgI4VHQIn+7/VNh2TXw3xX0StPz3q4wKeN4uK59w8283C8tq2Tzk4U3iZ9Zmr0VpbSnOV6pP8kIpVG5YcQMe3/g4lh5dKllvd0q/s2XWMg+hQnpm0cHAAP+ZhLT1mBZCpp1clCnh4lyY9ss03LH6Duwr2OdzPKPuNKhQSUpKgk6nQ16e9IaRl5eHtDTlCpImkwmxsbGSHxpzp47SHTIGwdBVNP2lPP64ZDOJZ8l7eR5OXXMNSt2WE0L5qtXC8u6JXbCrrQZ397hbKJ+thEanHEh288AM6LQa/PPUaPz+6DC0TvI/oDU+yoh+bfiHGcmKueMzZTfPqgP8TOdwrhgzcOPHf/PVc92U1ti9PkSO5dc9GK7WLt4cruruWbcmyV3n5qPNp7B4S5bH9k9u6aN67JsX/YNNRwtwPL8Su93F5OIjRX//uzeKN/y31h7zaiHiOA7LdkqtBeEqrOfiXB5+8NRIz6Z2anzsFiq32h4Hxr0MtBYtU0J8k1tQAEDPlJ6S/ascQTxArJXAkZVAPt9ocJvZhE1+dmENWVNEurZM3n71cW6Ka4vxwLoHAFAxI3LXj1y41Cck48gsDZgljQrlGDLE/zNtqXqyqAQRh9xpwS37A5mi5SBeIVX69yj1Gj3yYmnV9mos3r8Yj2x4BADQPak70qPTwYHDsdJjkvgOOaEUKiQbaW32WsX1hKLaIo/3JS6d1lRpCoAPZCeuqlYxrRDnriruj1CpoALFp/86/aKtz1KfNKhQMRqN6N27N9auFS9Al8uFtWvXYuDAgV72VMfQShaMqtFAO1DM8Im77lrF/Uq//RYAcP7pp4V1nN0O22k+Y6Ld+nWYMu9bbLzxT1ySeAm+uPILfDfhOywa5xn0q9Erf0lJc8H4KCPapXj2APIFyfypdrs11Fwa93y+AwBwLM8z88LoDjJ1ujhJpo0S8qJw/5wqxjM/7FOsWeJt/6/vHoC3pl7qsb1NkvrfQKOBkLmjxCZKdJ0v42+wxLUEACM6peCZ8aIVyltA7d4zZUIV20y3eMwtq2MarwoVtgphdkeCsgc0H+BtFwH6/7HBdSkwcKZ0ACkuWCJaXSwmCx7qJbpLqmxBPEDWvQR8NQX47QkAfEdfb9xCdcoOSfCuvZbP0iF4CYIl7ovfTv0mrBuTMYZfkLt+akJwbsGiIFS6JHZRTmUGFJubAoCJcwFHfvM4FgAkUkG2hGov3XPlMR/zt83Hf3f8V3hdbisXXFO783djfc561WPZXfaQl6y3OqTnJy8qd77K08JDhMrdPe7G1W2vxodjPkRyBG8NXHmKL5TYLq6dYNH053qVWyVJ5WNG+Ghw18+jjz6Kjz76CJ999hkOHTqE++67D1VVVbjttsDShwmG5p5FjyJ787NrncUCXVwcokeOFLa5KiqEQFkCx3FwVVWhbMUvgMMBbWQk9Glp0Gq0QiGjKEMUOiZ0lMQAkCBbNYsK3bMnGCLd6cz+uCUO55bjuIJVxKDVCMeRB5DKKaIe7mU1dtzwwVZ88Vc2vt7mX9pwjfvBmh4XAa3W8wYcF2HwWEdvE9K33ZDibfIKv2dK+IcYbVEB+CwjgreYk7XumjJD2ifhjiH8w54OPA4l5CYXoY/AV1d9he8mfOc1y4cm31esTYJbqFTmSYqy3dntTrw67FV+E2Uan79tPl7++2VFyxrHcZi1YRZe+usl4OhKybZqhYepkcpe6c4ZkOouZEY3hgsaueWjpoR/OK99URLge7DoIPot6Yf39rwnCaoc1HyQ9DjkgR6GOip+Q0QSJS66J3X3ust1ek93W4lWB7jc17asAWpMzxnCsl6jR7xG/L4NSR+Cd0a+IxkvFyp0DRoAuL/n/UKq76qsVYrn2DVRLK8Q6oDaWmctvj36rZDKLS+QR1w5Bq34OYnrJ9YYi/8M/g8GNh+IxIhEyf5t49oKQc/+1NeSC5U6p/wzfNLgQmXKlClYsGAB5s6di549e2L37t1YuXKlR4Ctvxiae7oY9ElJaLduLdqu5r9cac/ORfQI3kRa9eefsGVlScY7i4pwasoUnJ/DZ2WYOndWn+kAeHnwyxjVahTu7n43AECj5x8Gi26Vui5ivTyY/UGwqPhRNXX5rrPIdxc7i6Qe+FaHS3ig+0r/vfyNTYLLhBSKA4CdfsR8cBwnCBWTQfkyu3toJtomR6FlguhGiHWLuSu6NZOcNyB+7lqZG2fpdn5GQ1tUAMCg06J1Im/q9ubKyXEHGQ9pn4TmFv5czpWGx6JCZmxxpjjEGmOF1El/yC33cU4R8QCpwVIhDXQkcVXk4VFtr8bnBz/HV4e/wqHiQx6HOl1+GqtPr8Y3R75BDVUNFQAKL53mMb5LYhdhOVUXiXi3mCytLfV+zv6QK4sDqCkFvpoKbF4AHBaLJa44uQJ2lx3v7n4XJ0r5Uur/uvRfYnAycf2QFhWhOLdgcNoB8hA3x2HRuEW4rv11EsuXEs8m9Mf15VIr6bDqGjEo2BQNjH0J0EcAQ5+Atv/dwri2cW1xQ5TYmiM9Ol1wdxDOVp5V7ZUzd+BcDG85HIPSedFHVyGmGdh8oBDLEmqhcrj4MF7Y+gKmrJgCF+dCsVt4EhFOUtGjDdG4ss2V0Gl0mNrJM6BbXjW3V2ovobu1P9YRudWlvtoFXMw0uFABgAceeACnT5+G1WrF33//jf79+/veSQVDM+UePobmzaGz8BeoITUVCbfdKmwr/e47ydjyVatgOy72jIihLDBKTGg7AW+MeEPoJRITacX8yd0xslMq7h4q3hzqblHh939r3XGh2ivNwum9cP/wtgD49FpSlXXB9T1w7zB+/fPXXCI80OWZP3Iqah34cTdfl4AONqVFixpWh0to1hlhUHYVtEyIxNpZw/HejWJa9tvTe2HFg4Mx96ouMOul+9W4s5JqbFKXFKGNQswPEYfeWg8QEWOJMKB5HH+TPVtaE5YuyuQmF0yJcVqofHa7chVSGN0xCLIHTrR7ti0IFaqj8rZcPtYptyoXeVX8Q4+eXRfqpLeJfFkvmV8m/YJ4sxgYnmqIQZw7QyPQCtAeZP8NfHmDdN3KJ8XlQjEAnq4Iu+HMBgCQBikT1w9xkTWURYXut2OKRd+0vnhu0HPC/0gNjSkKD5aUoW9NLWYVleDnnHPoSHXOhjGGLxg5+zQw8mlAq8PLg19GG0sbzOgyA/2jxbRpOoCUZu7afwEOz07DSWb+Qd41saukKF0bSxvRYgUgJTJF+D+EM0X5gz0fwOHOXuqZ3FOyLdoYjVeGvIIt07YgXaGtAP25Z/ebjShDlHCMPfl7vLqs9hXsw/1r75esm715doN0XL+YaBRCJRTET5+GpAcegDbCvyA/fbx4sZb/8qtkW96LL0lex151lX/n4L5ZJ8fZcUMfPm2aWEEAMUYlWKJN/IPb5nDh7bXS6pJ/zh6J8d2bCXEdVVYHCtxiJjnGhMfGdsDKh4dgWt9WgkWFuH68BZpuPVEkGQsAeb5m9gCsVCCtWUWoELqmWzC9fyt0bhaL3hnx6Jpugdmg83AX5bhdPGoNFcnfnMafZo7llFBplRAJrYYfX6AgBusKMU8r3UB9QWKOru/dAsM6qGTdGNzXv136PyLVbonrh66fkVORA5vThut/vh6jvxuNLw99ick/Txa2F8piUkqoAofJEcloFdsKLWLEhn+JRgti3RaVOhfQ+u1x79vXvQR8Oh6wVkqCHIVziRDT+gWhQiwqDRWjQiw5xhhAF8DkxWFFvMuFRbn5uLW8Aq0dMssqiWPRi5k9E9pOwE8Tf8I17a5BmyixNEJyRLKHRQUAfsvdCqycjR9P/ChZT/6OOq071dtNh/gOgiUZ4O+B5FoLp1AhVWbjTHEewehRhihoNBrV5p50bRtiCWwb1xaxxljUOmslDSXlPLz+YcX13vZh1J0LRqikzJqF5Adm+h7oxtiunZCazNWqP3hT58yGITVFdTsNmb3Rs0g6TZbU+AiWsZeImVDrqXTeh0a1R7rbEhDlFkZ55bU47S64lhxtgl6nRae0WGi1GliIRaWKf0B7cyXtyOZv7nTl1iqb02dALXH7GHQaGHS+L7OXJ3XDbw8NkQg7Od+4Y2PUhAqxhtAEYlGJNfNxMSQb6/D50JeBJwWlWsUqVyD2xq7sUgBAj5Zx6oPIbFdWGVT+8KAtKuW2cpRaSwVrz7x/5kn2LdDpgB7TgOaXAp0noILK5NG4q71e0/YaALwAM5hjEeOeYdY5I8Kfbr+n/wD2L1MUKhKLiuD6cVtUnFZJJ+h6gwgVUi3WX/reIX1NZQIB8IhRkZMYKd7HmkU3k1S0lbD9E5w8+otkFd2mgc54TI5IllhYEswJ9SJUCEkRSR5uefp8lKBTlTvG865XjUYjWDm9nbeahVDelqAxcKrsFJYfW+6Rmt0UuWCESqBoNBqkPfec1zFJM2ci4ZZbvI6hSYhwpw/bqwTTuZ4SKqRqarB0Tbdg2X28mZVkqcRHGvDIGLFIFBEqf50Uv1BJMVKBRKwMpPqqPDj3zak9heyXQrf7SO4mUnI90RChInffBMqGx4bjxv78Q518ZjrtmUanELBLrFjP/XxQ1TxLAm2JqOmcxgdF++PiCpTTFXwWWUZMho+RnpB08+4tvLiNiEVF7vpxP2isTivsLrskbbjcVq7YzI1QoNcBSR2AuzcAU76Q1qpw/8k7JnTEdxO+w+LLFwOmGMS4LSp17vlCC52uk9XHHV2paL0hsQcAxGBaS0uAFGJrCKuKSmqyT+JbAz1vEl93uVoqVnwVojTF4I28AjzkikXP5J7QaDQY1mKY0GWbYNUA+ac3Ca9HtxotFEQDpEKlRUwLiTCIN4XWouLLpdI+nq8j9Pyg54V18pR8OXQQLm118ee8OYjnY9KZcFn6ZQCAoyX+9RSrT67+4WrM3TIXPxz/oaFPpc5ctEIF4ONWvKFPCyygN8YQI5ShJvn4Nw3IwLW90rHkzv5eA3L9JVMWhyEv9U7cQ9J1UitFlDtIldRjkcd8XNG1mSCIqmxO2J0ulFZJLRK+uhKTY5qNdRMqrZOihGq+JOulRsWiokQzi1lYXnsoHy6X542PjlEBgM7ujtt0HZpQUVTD3yRTowK7tpwuDsVV/OdPoz6TBwZliwp9Q660VUpcP0U1RZjx2wyocVpvkMz+acvF1I5isGLHhI5Ii0oDzBZEu2dxSlYOv+E40V1z/WdAL+ocJ74HPFcG3OjOTDnyKyoqPMVWsj4a2PQq8M0MMZ4lMpF3uwCS7Civ7F0KHPghuM8hRyHjx2/ofaKSgU5Xiq9NPiZCphiMqq7BnbVi8cW3R76NNdevkQzbZTKh0D3BeHXYq3h9xOuSe1e7eFGoZFoyJX2HQu36cXCeltseyT2EZVIj59r21+LlwS9jbMZY3NP9Hq/HvPWSW6HVaHFT55sk69Via74/9j0W7l4IQCpUHur1EPqn8fGUH+z9AF8e+tLfj1WvbMzZ2NCnUGfqFt3ZxDG1Vy/aBgAGlaJzamg0GiSYEpBfk4+i2iKkRaUhyqTHazf0rMNZSomX1RZxyB68UUbpv/T9mzz7BxGrC3HfWGUxKka9FlqNeJyZS3ZCrrHyZULlWF4FUi1mwYKx50wpAPVA2kBIdVewzSuvxZYThfh+51kfe4jcdllrfLTpJCqsDtz5v+3o0TIOy+8bJMS/WB1OwUJDLCqd3BaVvWdKcTy/MqiaN2oQS0akQjEubxRX2eDi3PVlZGnYEtzpmPIYFYPWgARzAoprizF/23xJaXdSwVWN/Saj5AFJxMes3rNwU5ebPHcwxQjdneskVCpyAVLWvcM4QGfiH85VhUALd1kAixjrU15wAJC1szfs/IyPY6GJTOCtD9YyqcVGjZx/gO/vcp9HHmDwIhQBoPA4sPcbYOD9fCaWnGAtKoDUahKdAiRTqe06HzFwRMhYxf+JRqOBQSPd765moohO1nle+20tbYXlNpY2iDGKAslisgiiOBRCRV47BQAuTbkUw1oMw+rTq3F5a7Gb94S2EzCh7QSP8XJ6pvTEpimbPHq2EYFFi3iO4/DslmcBAKNajZJYeOJMcZIq0/P+mYexrcdKrXiNgFA2Im0oLmqLii5GOgOhuy4DgQsVAEiK5C9SkioXDt6Z7lk8jRAls54ozb6jZUJFKeZDT8WVrD6YJ8S7GN3r6c7IB86VYczrmzBxId94cf/ZMsz5nk8pDYVQSXG7rqpsTkz/6G98t4NPIezhzQXiJsZswGtTegqv9+SUSgJraYtUjPvv0sltUTlRUIXRr23EexvEDDA1CmsKsenMJp+m6hp3TIQvP7ocYsFKiDRK/jceEMuJQvdaEvC64uQK/HTiJ7/f+7DJCBf1MCLiY2zrscqN7EwxiHWFwPXzxXXisiEC0GqB+/8C7t0stA6ojIjDhogIlGq1KFcqZnZinee6iHgx8NQfi8pBKrDUn0yhzyYAm+YDvz2pvF0QKnG+jyXHSAnc2OZAiljUUEhNV0NBqBB6q9RwSXZ4xnalRaVhUrtJmNhuIlIjUxFliMLSq5Zi+dXLodfqBQEQigekvLYLwIv8u7rfhW8nfKvendoHFpPFw8ItCBV3/FZeVZ4kdb+4tlhiUbGYLB6W0cboAtqZv7PJx6lc1EIF4INlASB2/Hgk3HG7ZJs+CKFCOqc+vP5h1SZfdeWq7s2FqqtzrpAWC5O7eZopCBWS5lzlds/QFpU/nhzhMR4Q3SCD2vH+7FNU88M1B/mU1pMFVeA4TlKqX6nQW6BEmfSCiJCvv2Ug//fu30a9V45c0NBCRXBRGbTCuabHRUhSyf9v5WGfmU7P/PEMZq6diU8PfOp1HLGoBCpUCqkMLq+Q2b5CPQx/Mo1MOhN+uOYH3N/zfhjdIsSu0aDMnZ1idVphc/HxSqrptKYYRLstfUFbVJwOIF+h+3JUEuwpnfDZgc/w0l8vYeD3Y/FgWjJeT4hDhVuojG7Fd2NPNyd5ChWdkRc9xDJBC5XacmDXEt7dVHIa+HEmUHwKqKYKi/lTe4W4oPZ+A5zb5bmdHCMYiwp9T4lpzpvYZvwADJsNtBvlfV8iVBSsSJ/0ehKfnPfsfRSv87xONRoNXrjsBbx42YvCw75zYmfBJdQyhs++C0UmjFKqsFo2T12hLUEcx+G2VbdhyoopwvZ71khdSrHGWI+Mo3vW3COxyDQWduUrXIdNiIteqCTccgs6Hz6E9P8ugE5mUZFbXPwhJUKMrA+nb/COwW2w+YkRkjotgNSiotEoN/aLcsexyC0qPVpY0CLe+01gkLuL88kC8QZPi6OCSqvk9ZguwRXuk6OU6RJh0GH2FZ3x+pQeii4uQkqsVKzRgcFWBxEqouVHo9EIAbWEX/d577L95znemvT6jtdVx3AcJ8zWghUqvho1qsWoAECb2DYe6+Q4XA60jWuL+3rch+05+bA43fVQNBzKrGWC8NBAI8kEkUC5foKu2lmknkXx/p73sWD7Anxz5Bth3TGDATVuoTK732zM7jcbi5LcfXNSLhF3Jg8+IrJoIfXLLODH+4FldwHvDwZ2fQGseFgacBto7ZXvbvcovlcn1w/9/kSUth0BjJgDeOm6DUD8zE4bIHOp6GqKkWmXWk90HIdol//xYAQSeLvm9BrVdF5/UbSohEuoUDEq63PWC6UE1DBoDUiJ9MwIVSqgWN/YXdL/5dlK/93ljZGLXqjQRPQSG9mZOvlX1lzOJUniTTGcPSA0Gg1aJkR6mC/p/jjDOyQrZsJEqVhUTD4ydHRaDXq7Oz6fpUrM01lDpwqqJMXhZo4Q/dl1YUCmp8XEbNAhwqjDpEtbeMTueINOtSbxKfLsJBJQS/DWK8hf7C670Jo+whCYUCFVhL31PwJApSd7WlSmdZqGR3o/gpEtpQUMX6CMCuT8AEBjq0SCO3tn/pHPMfjrwRixlLe4RRoiJXEuEkwxSHfX+MiuyPYZA6MIVcgN3fmA3TJrGd7b8x4+3Puhx/CSONFalHTgJ9zY+UY0r3V/MDrglKBkUdnn7s57fA1gdWcQleZIewQFmiVUfBJYNE66joiNQNOTgeDEDYEOtpW7f6oKkShrTRHjckETRG8oOkNobfbaOhVDU3P9hAPi+lm0fxEeWu+9SnBbS1t0SOgAo87z+7i/0HfTzHAjbwbqT7PFxgwTKhQR3bqh1aJPkPHll2j9zddBHWNc63FCPv6pslM+RocenVaDZfcNwoiOyZh9RWfFMfJg2lqVUvdJ0dIvYWqMCYlR/Iyedp/QD/FzZTWCxeL+4W19ih9/yUj09L97q7ki5+1pYlxPWTUtVETXD007WSq5t4Jx/pp66ZtHoBaVMvffVN4mwAMvFpU4cxxu73o7FgxbgAkteTfBK/mFmORSP5dEt0VlS/4OyXpSkl8RkwXNHU4MsvEPqB15O9THqlHlLkue1h24hu9Jc9OvN+Hd3e8qDs+z8Q//aJcLul8f41eS0vLRClY9o58xKgmZUnePN4tKbTlgU7gWSrKk9VqKTqifly/63wt0mchnQQWKVifGsXgIlQJoALxgFNPmLS6X1OLkJ82pwnKA5+w+EJSESriCVf1xUw5vMRw7Z+zE99d8L+kpRNMQ93058nsSEyoXGFGDBiGy16XQmoIrzqbVaPFkXz6IzpfpMFz0zojHp7f1Q8c0ZdeV2IVZmvUjFxXL7huEp64ULUvRZr2QwltpdcDunoEVVYpCpaDCKggXnw/VAEiN9Yy1IfEy/jChR3OMu4R/MJRKXD/Kn12eBq4mVIprizHyW6mFQi2QmggVvVavepNTg1iBvDVyBKBaR0UyRGfAy0jCjlPZGF9VDSS2Q4q7RHo7m40vjGbl4xgSnMqmf68WocS2gFaPlrX8MUhKdkCQmifNegjZLN5iHsjDMJa2ClS6Y6WiU/h4DhrBouIj2NdRK3P9lCqPqy0H3uwOvKzcwgNlbutqbRmQu5dfbhVEh3hTDHDDZ8AlEwPfFxCtOKT4HcEtDNtHiOdvcbqE6yAQdDIXlJLY8Be6MCGhWZTK37iOjM4Y7XPM26PehkFrULcmIryJFP4i/7s19cwfJlTCALGo1Ck1M4xEumNUzpXVYsfpYlWrQkZiFO4e2lbIurmiazNJY0VS7bWoSrwR7couxU97+GDCOG9ptAGSKqvqO7pzCi7vGliwc6I7viOrSPwSq332gZmJmNavFdq7U5PVhMqJ0hMeaZhjvhuD3fm7PcaSm0cwpmvi+rH4+psSAeHLUlBbBuFIjhp81H8urqmoxJt5hUDhMaCaf3ClqAgVUpFWkcgEoM1QwRoTVL8f8iCN9C5G7+1xr+R1jMslWktoi8qUz4GYZsC1H/HryJh/PuJ/1CjLkVlUSpXHnd8jdRHJKc3mA3v/rw3AuXjhFBueB65XYt2CrVwWs1DFi7rIKDGLJsbl8i992wd1ESpK99BAaxD5S9+0vrjtktuE161iWmFESzG5IDnCvwyj81Xe49nqgxpZxeVlx5bVS6XgcMGEShggQYZKs4HGQHpcBIx6/l//7E8HxDgNlVTipfcMxDPjO+OBke2g02qEjBgyy6dTfH/bL84mUnxlqAQAbVHp1zoBH9/SN2C3Uh93fM3S7TmCQCGf3ST77FqtBvOu7YbHxvElttWEilqw6JeHPYs/BZvxA4hWIJ8WFeJOqPBxs6RNw9YKZGoj8FJhMVo5HEDhEcE10EqrfK4+0x2TOwkxD2oWlQNFB/Dh3g+F7LhqezWe3PQkVmetFjNtIvnYJKXsj0d6P4IJmdK6GbHk4VpbLrqPopKBFn2AWYeB7u4Gh8SiUpkH/PoYUKDcDRglWVLrVM425XF5ChlKNAd/BNbPA0gMUHRwabV1RlWo8H+rKEoExLpciqnM/vDpODH7LdRChS4wF2ru6n4XWsXwlbD7pvXFC4NewOQOkzE+czw+u0LZ3fbG8Deg1+qFQnPnq843eJNCpWfPM3880wBnEhqYUAkDQgO4EMxGwoHZoMP6x4YDAPafLcfxfP48TXrly6F1UhTuHJIp9OwhLh0SNKvU9yc11oTB7ULnSzYbdILwUXNp+WJiz3TEmvWotjmx9UQRDueWi6X+VUQacXXtyi7FJ39Ifc9LjyzFIxseUdwvLdLT2hNsDRVAFErxUT6EisXdmLHUh9uRnnFZK6UpuIdWCD12MlSECh10q0hchmBR2XBmA7LKsjyGTF0xFW/vehtLDi0BwIu7X0/9ilkbZ1FChbeoKJXHN+lMHn/LWLj/j6XZYnyFKRYeyK0Zx9d6/zzCuN+Bc7s91yulUtPsXya1cimdU30Q624eWSYL9Hdb0CKjxes2yekMWqj0Sesj1FOpi1Apdwc190/rjyhDFK5soxAYHUJijDFYdvUyzB86H//q9S/EmePw7MBn8cqQV4S0azmjMkbhn+n/4I5ufC+mGkdNg1svSIxKi+gWQmbS+pz1kkmDM4iMroaCCZUwIC8c1BhJj4tA39a8hWH9kXwAvrscEyyyRn/yXkEA8MGMPt4Lkynw1s63MOPXGahVia/49t6BeGf6pZh9RXAZWVqtBpnJvLXrtsXbcPkbmwXxYVYRaRbKgvHiCmm/oNd2vKb6XkqF0IhJOEpWmKvW7vQ5AyOi0BLhw/UT576Zlp0BXF6sHrRQKTgEfD1dfH1sleA2ydQri0KfM8a4VmhGdfddfXq1ZDP98NpTsAdrTq/BmzvfFAdU8tck3P2ziFCh/3YuzgWzXhq71MzkrgR7iioNYFYQBc1lRRNP+BAq0WlAp6t4i8jfH3huL5YFUMpTaG2VigHO9Y5gUaHaDVQXAzl/AwAiY8Xsqa5WW51cP8TyoWQN8xfyf8+My8SGGzbglSGvBH0sfzHrzbiizRXShpY+MOgMMOvM0Lsrete5x1UdIc+e5tHNsfb6tegY3xFOzoltebxF8MWtL2LE0hEorClsyNP0GyZUwgC5mdY4asJW9C0UtHdntpDgVzWLipw498OytIbfT95vCAAyEgKPw/ho30fYXbAbP5/8WXF7RmIUrure3KP6biAM6yA1uZPGg3LXD6FdSrSQkg0ARVSGkzf3h9wCcKDwAJ764ykAkFTTPJ5fiZ4vrMazP3mfkZf4m/UTm8433HNahbgDRXzFsLgfXGmmOAxOH+yx2QUfrp/4DHS22ZHqFivylE2622y5rRwvbn1Rsp3Lc49P68qPcc+s40xx4jkoCJW0OHdq7DF3/xqdEdAruAro2ioAkO+j9kVUEp9xAwBHV/J9iGhKsqSvSfE1k4UXOQBQQomZhprNkpgfOtZmj5jhqItOxYBmA9DGEIeR1TXA+b3A4quAM9sDfisiVNQmHv5AXD+xxliY9eaQ9EsLFxqNBlHG+usc7Q1iUSHxcKRsxtHioyizlmHp0aUosZbgi4NfNNg5BgITKmGAnvU1ZquKRRbvEKhFpazaDrvT5dErCKhbxk+pP9U/g+R+lbouahYVg06LZfcNEoJ5z5aIlgj6/zwmY4xkv2Mlx7Aya6VgXp29ebawja5m+e32HNTaXfjf1tOqVgqH0yWIQZ8xKjoDH5MBAJVesg9kwXYe/P0+/9sci9eHv47Wsa0lXXNd3qw1ABDXChoAr+bzM7Yt57bgTIXobsirEqugHi0+ihKrNBD1qEGHDaltgTg+XoDEAtH9WUw6Ewxag8R61TzJnZJ/dqd7kIqLRW8E7lgDdHdXHiUxGwkqdX8iE8X+QjXF0ge9w+bpSknuDDxyEHhkn/AZJPhynYULUoeFTrOm45kS2+HDMR/ix7YzYOY44NxOIGsz8PEooCqw7K1QWFQq7LxQofsJNWZI2n6DCxVSWNIdXN8hvgMAfjI4fOlwYZySS7UxwoRKGDDqjDBqeatDVRAFk+oLuVDxZVEprCnE2tNrERPBjyutsSvGp+i0mjrNfMJpNjXpdR4ZPoBvkZYex3/hSaE7juMkgbRyQbozfyce3/g4fj31KwDpjYsuEkUXcDtXpjzzLKcsVvL/mSJEqPz8sPoYX0KFYIyBWW/GjxN/xLKrlwmrfVpU3MXFelht6FlrhdVpxYqTK4TNxVYxE0guUgBgcnozPBhpx++nfwcguo5So1Ixs+dM9EjugavbXg0AEqtly2TeAgPyv/HWUbhlP6Dz1dJ1tEsoUhZjZTCLD/rKfD44dtEV/IMcMpEZ25xvmGi2AJYWnu/dUBYVJaFCMqxGzQU0/HdXY4zy3Pf3ZwN6K3KdhyKYtskIFfffrcFdPzKLSs+UnsI2+vvS0OfpL0yohIlQtjoPF6TTMaF1ksLNiWLqiql4eMPDKNZsAcDHTZCZvtmgxT1DMxFr1uOLO/rX6bwW7V8UVqsKyfShURIvNM3dQuW8W0xU2islhaxu6HCD4n478nbAxbkkD2PackJbo04WKN80SMZPjFnvX9wPeRid28l38lWCxEvQFoQnFApVuUvZazVaSe0If/33WgDXVPKfa8u5LcL64ppilT2k/HziZ5yrPCc0UZzeaTru7XEvvrjyC6GUOokLuCz9MnRsNUx6AG9CBfCMX6FFBV0Flrj5SFZVzt/AxleA7C3AXwpF6Jr1EJdjFNLoh6k0LAw3ikJFGrgMQExzp9n1eUBv5cuicqjoEF7++2XJd/1U2Sl8uv9TwV1EfoerGm2oIRaVhur3s+TQEkz6cRJOl58GILYbuCTxEgxrMcxjPLOoXOQImT+NWLHSs/NIow4jO3n2rSDUOmqRV82b6wscfMGq8hq7EEgbbdJjzpWdsfPfYzCwrf+F2Ahyt8eyY8tURtYdeZwK4NuiQnrsFFdZUVpbikFfDRK2Lbt6GUa0HIGFoxZ6tI5PjkxGQXWBMIuJMcbgpi43CdvLFRokyiE1VPx2p9VSNx+1YEhiUZm8CLj6beCahXwq8EhZCmNqV8nLd0e9i66JXf0LahwwEwDQs5Z/UB0vFUUTEW4kFVSNM5VncOOvNwqvL03x7By+cNRCzOo9CwtHLoQmMoGPCyH4KjkvFzKWFsBtv/ExLBPeBG5fzbt8xrzAbydC5fjv4j70MiGVioGJln2vbl8FdBjr/bzCBS1UyHeOiMYISnwqCRVDZECWIJM7NqjWqWwpnPrLVHx1+Cu8+JcYnzT5p8l4bcdr+GgfX9uGiJxACyQ2FA1tUXnln1dwvPS4EOdHC7zXR7yO/s2kk8jGmpkqhwmVMEECJhtD8R81aKESF2EQ0o+VeHaLaPaNN/NCpFQmVAAEnOlDkAcd7y3YG9Rx/OHVyd0lAbIAkOijhw5x0RRV2rDhzAZhvVlnRof4DtBoNBjaYiiWXLlEsp9OoxMagjWPao4/pv4h6WIs6eRsV34IlNWQGip+FtCTdPtVKflOZnyGSKDXzcClbvE0+FHpuFFzJS+HtBiCr676Cu3j2/s+j3H/AfRmIfunwlYh3BhJEbgbOt6AfenXYeepbHx31vO7UlhTKMlMkAfPAsCg9EG4teutYkXUSOqB68uiIo9hiU0HMgYB928B2gwBWvUH7vwdSHf3ASOi47isKzMAJLYHhs8BJr4nDeCVl8pPbIcGgwgVp42vD7PnGyFw2qdFxV7t2WDRC7RFxeFyeExGSDD6tlyxNg3pzE3WkdcGXRMRKn7EqBRUF4TVYkxDN3A0aA1oES11Q8p7AjVWmFAJE61jWwOAYv2IxoLEouIlk6bMWibEWgCAxX3zX3c4H7cu+geAH83yfEBuSIRwdiBNiTVj1pgOknW9M7y7MsjnO1y5Af/+89/CenkQLS1CAN4EvD2Pz5jokNDBo/R2ea1n3yE5pYFaVAZQ1Vo3L1CeBROLivyBJO/AG+mfi0cRjQZIao8ojkOsu94JKS9Oeo8kmBOA0hwYAHS02XF5pfQGT1e1vaXLLf69L21FMcd5HysXKpZ05XEE8jBXqjptiACGzwZ6Tpeul1tUAmxIGVJIRV4AWP8ysPxu8TX9v6bTq3UmsQWBtwBtGUSolNvKcdXyq3D3mrsVx5VYS3C05KhknU7DX4fEvarU/K8xEu3++6oJlSp7FUZ+OxIjvx1ZL0Xh5C4zecfzumRk1SdMqIQJ0kH0ZNnJBj4TdWIjRHESaVR2fThdTtzym/QBodWK1g/SgblZXN1uvnI/9vmq814baRVUFwh+2GCghVmMWe/RLVkOsbicgFhu3awzY3b/2ZJx8plflb0K/+TyYm5wc8803zI/XD9iDRV/hcr9AMmEObUJ+PNN6XaXk09fBjzrfQDA5W63zjXKDQADwv1gb27gBcG5Kr5+Bwk+jjJESTJmYlSyiaIMUXis72P+vScddxLlww0pj1GJy1AeR5D/vdqOUt9GiJbFqARR8C9kaKlb/pa3pNtoyw8tpswWIIZUPM6DvxBxsT1vO85WnsVf5/9STen/ZN8nEqvq6fLTKKopgt3JX/tNxfVDhIGaUCETV7vLXi/9d+T1nOQ9uphF5SKHzKxJXEdjhH7wqbl9NuRswImyE5J1URGeD9TmFk+TfCCQmZNOoxMqKZ6rPKc6fuS3I3HV8quC6yMDINokCrOpfVv6dFmRPkE074x6B6v3lWNXtlRQ9UrpJSxXO6pRUM3XMyHilaasRrw51ygE+QJiq4J4f3sn6QxAem/x9fk90u10xo/S7H7AfcBjx4FLb/TcFiju4NQ08NcasahYHbxQMulMYowE1IUKuSb8grao+OgVBL0JyHT3cxn4gNi0Tw15NkyHceKyQeU7QAsArV4qFhqCG1SCYiMod6heJlSI2Pp6Gl9XxVd6OsTZ+/lK0aVXba9WtCRYTBbJd7mgpgAPr39YmMCQLMrGji+LCp0pSER7OJELQ3mQLxMqFzkkna6xNiYEgBgq68fhUjZDKkWF2121uGdopmRdM0toLCpGndFnZV862ya7PDuo94swijMNf5obJkQZAY00zfLoGR0e+3YPJr27RbL+jRFvCKW+q+xVwswpTsENUVAhHlMtRqXU32JvNHScijzDhhYqCjEfAELXi8adVdQ8l3flEfFJUlZ5oVIqDI9VeQAqtSRQhQ6mlacYK3HT98CDO4GxL/keKxd2zUVRCrWOurRLpTEUgOxytbLliC4poGZRAfh07GrfFU2HtxwOADhSIvZRKqwpxLU/XYsnNj2BGINoxYzQR6CgRlqgcHfBbuG73lRiVIg4UxMq+TX5wnJuAG40f6DviwAwIXOCkMJPkD+PmOvnIocIlcac9aPTijcmh1P5ASFv2Q7wKnz2FZ0wlMqeaR4XGouKXqsX+reoqX1SpRQI3iScFG1EUrQRCVFG9GgR53N8YpQRWrP0xvLv70WXRVm1eJOIN8djaIuhAPj/PxEq8SZpAK/D6ZJ0nvYVo+K36weQxqXIC3WRWZU+Ivyz+0ReqJCAWhJcbnXfIE06o6R4WoyKYFbrs6IIbVGJ8kOoaLX8efpT+0cuVJKooGK7yk1f4TvU4PiKPaI/pzHK031FiUs1eib39Fi3+vRqHC89jt9O/SZZ/93R7ySWFwIRL03FokKCV9Xu+2tOrxGWQ21Roe+Xzw58Fi8Pedkj+Pz6DtcDALondQcAODiH4F5rzDChEiaIsm7MFhUah1P5AaHkU662V0Oj0WBgpmhWD5lFRWsUhIqaRaXMJppP5UG4/mLS67D20eHY9MQIvzKVLBEG6KOOSVdyonA4mi/9PxOrUG5VrvA3pMu/A0BhpU1SiV1NqOSV8w/AOH9dPwBwNRV/UC0XKiqBtOEgvQ8ASqhUngXKz8Nawd+kTRz4DBQ3tEWle3J3YTlSLf5DCdo9449FJRDoPk06o1QU+VM7Q9bnqcGQu8Tk50VfG3qT1KICADXq8WOEKEOUx0Qiv1q0KJCqswBvuV2wfYHqsZqaRUWpjkqFrQKbzmwSXs/fNj9o17US3xz+Rlie3GGy4phuyd2wZvIafDRWjLWrcTZ+9w8TKmGCWFSq7FWSipyNFbuKRUXJhEkEBB3n0SxEFhWDziAEpNWoVE+lLSp18bFaIg1CWrUvtFoNtCZ+xueobo2qUw9Ith/JlQoV8v/PqeC7GEcboj1utkSAEJSCaQ+eK8ffp/ibWXwgrp82Q4GH3f1yqoukvWno1ORwY0kHHjuGNHcn5dzKc8Avj8LqNl6Yjq6SDO9stcEADTrEd8BT/Z4S1idHBOCKoh/CiSol8YNF4hKJk1ph/Kn226puxRBDRoTMonKnrBYMPROPSlawqPh+wGo0GsSbpVZEuo2CHJLGr/SQbSrBtN7qZx0o8uznNffPuR7rguWtXW/5HgQgLSoNEfoIIbNK7T4bTs5UnMH8bfMlrTS8wYRKmKBLPs/ZPMevfXbn70avz3vhy0Nfhuu0VFGLUVESKkQc0FVVk6IUGr8FgJCG6IdFhY6bqU8fq0bLu2nsJf3hqpXWI3jmh/14/mfxRiRPU5ZbUwBpfAqgHKNCOlsDAbp+ANHt4bIDZ3eI6+vTogIA0SlIieVjIgpqirA763dUuV1OpvXzJEMzHA5siumP7yZ8h0uSLsELg17AqFajcH3H6/1/v0smAV0nAzcuq1t6tRK0uJMH3nq74d+0DGg3Brj6ndCeT7DQYm7wI0BqF+l2jQaY9AHQ8ya+to7covLVVOCQcvNQGrm7ky76p4aSm6eppCerVSSvtlfjrtV3eYzffHZzvZyXHI1GI9xn1QryhZMH1z2Izw9+jic2PeHXeCZUwkQwX6w5m+fA7rJj3j/zsK9gH1ycCweKDjSYD5HjOLy9623hNZnVEKFA107Rav3w73uBDqYlZn41awkdOV+/QsXtonAp/28//TNLWJZnqcQqNMeja6gAyq4fFyUge7aM8/NM3RgigBb9+OUvp4gP0voWKgCSYnhh54ALM5qLs3OTJAOEv4ai248TekVNaj8Jb4x4Q7ip+kVMKjD5E6D96DqftwdGSqjIg6O9uX7ajQZu+s53nZb6ghZwUSrWqh5TgYkLgaR2nhYVAPjT9wxeblHxJwuytaW1EONFaCoxKkSonC4/jXd3vysUK1Qr/OmtA3u48RULGGro5xgRrHSgtTeYUGlE0A/ge36/B58f/BxTV0zF81ufD9t7vjSxK6KMOiy4vofHtq3nt0pek9LvuVW5qLZX4+oezXHLwAy8f1Nvj30DRXD9aA2iRcV94990ZhNGLR2F5ceWA5BZVOpxNhBp5uMsOJe69cjq4MWGvLCbvNASAKFPEqFawfVDUpPvGZYZXNXf6d/wZvzqQrGqaH26ftwYIuIQ7/T8fIJQGfQg8K9dfEn/rtfV23kFDC3uiEWl96387+Gz5aMbLzHNxGU1oUIjL1oHANZyoNh7nSi5UPGH69pfh1eHvipZ11RiVOiO6u/teQ/3/34/quxVKKoJrPO0ByfWA0tv8VrHhkwkr21/rV+HJIG29SFUVmWtQr8v++HXk7/6HqwAEyqNBI7jJA/dClsFFu5eCAD48cSPYXvfmwZkYO9z49CvjaeJnNS8APgH74OXPoikCN6dcLz0OPQ6LZ6/pqtf6b2+EHp66ESh8tG+j7D5zGbMXDsT+TX5+PzQ5zhZdhKv/CP2malx1KDaXo3vjn4X0sA0JeKj+YeqN6FCu3OmdZomLCsFg5L2A5nuZpD7zpZ5WFVIQbiA3T7CGyeIAZ+kr0cDWFRgikWSmlDpOJ5PDU5ow4uUOnTeDjv0/5H8Xce/BszcBvS9s2HOKRjoXkT+ZEbpDMD9fwF97hDXFRwG3u4N5GxT3a1HsucEiIakMBOubX+tYFXtlNBJWN/UYlQIh4oP4erlV+OO1Xeo7OHZ50yRzycCB38ANv9XdQiZHN3dXbkCsBzSWJQOcA4Xj218DA6XA09uflLSEsNfmFAJI59d/pmwLO9lI+dM5RmPPHha6b7yzythK7msU3HbkEBQALivx30waA1oa+GDE+tSFVYJoaeH1iC5KX164FNh2eqwYvYm6ay11lGLF/56Ac9vfR5PbX4K4aTWHR1v1JoRpVLJN7/CitJqG6555w+gRCyvr+S6IBaVYR2TkR4XgYpaB1YdkKZA11moAGLZdKs74LfIHScgL14WTsyxSHZ4ChVdfZ9HXTEouH60OiC5Q+MWWHJSOovL/lrWUjoDV8wXKxcDfFfp/eoNRCe0nYDmUc0l657q/xTeHfUu9t68F4/2lvaWoh/0dINPuYWysRJrjPX4rtO1U5Sgu4orQmdYqdRncbgcQm0i0m/IFxnuuLGTpfVbPf2JTU8ELDybxn+/iUKnV/pKUz5SzPvqOid0Fi4gmiWHlmB3we6Qnp8vSDG1aEM0ZnSZAUCMtQh1fRjivzRqjThVdkpYTzcsy67I9ugBVOusxS8nfwEA/Hnuz5CekxwSIPflHcOw5lHPlukAkF9ei/c2nMCeM2X4cONZYb0Gng+xCneMSqzZgMm9+RiO73acQWGlaJUJiVAhjfmslYDTAWyaz792WNX3CTUmCxLUqpk2JaFCl9z3VfW2MWOI4Cvxth0ppJD7hU4PtJFd+16Kv8UaY7HyupXYPWM3Xh32Kj4Z+wmmdZqGIS2GQKPRoI2lDT4dJ05GzDox24hOSGgq6LV6DGuhfG9QY0POBvWNHAd8NkF8bVHuNk5Pav1N5W/hjht7d8+7QVk5gmVb7jbF5qLeYEIljOi1eiHV1pdQIdaLzLhMdIzvqDjGn4j5UEJcKc8OfFaY6fiqvBgsxO1l0pkwON2zJ44av5/+3fegEGB32gWLV9ukBDSnehsN75iMGHeac2GlDQfOuWNoOO+pz8T1E2PWC8XzNh8rxICX1yKnmI8jIYXk/O6crIQgVMqBcio99Nyu4I8ZKGYLEhRcPwDUK7o2RiLigSsXAD2miR2nmyrj/gPMWM6Lj0CQu4qqvD/kNBoNdFodLm99Ofo16+exvU9aH3w45kOMbDlSiIMDmqZQAYCOCcr3b0K/tH4Sl9iegj3qg4tOALn7xNcqlnkSz6fX6P22VnSIFxuzhrNbvRKkYaW/NKE7RNOEWCDGLx8vKcgjh65e2jmxs+KYYyXHFNeHC3JOFqokuVAnwBY6i8rxkuN4YesLAPi/14S2E3BXN89UPppEMz+bpcVbQP1gAoROlZbPWPRaLa7sxgcnllbbqPoo3l0BxPUTY9ajXYoYbOtwcdh0rAAOpwv5Ffyx6tSdmggVWyVQkiWuT1G+zsKCOVZdqDSGsvKB0O8uYNL7QFwA1XIvJCKTgDTRWuxhUTm5Acj+O6BDDmw+EG+OfFOImwCkrp+mBP0ZlJg3ZB6+uPIL/HYtX533WOkx9eyfSlnwrErgK7E0R+gjhIw5XwxvMVxYVstKChanywmny4kH1z2IO1Z5xucEGsbAhEqYoetpvPS3ei8RkvFjMVlULSqlVKnx+oCcE10DhDTdCqXrh65IaTFZoNfqMT5zvNd90qI8A3hpQRVqyIzFqDV6zFiqbQ7ERfHrFqw+imP5nn8bDuIXs9buRH55LSrdQiXaZPBw7Rw6X452T/+GErdFpU1SHdwjQoyKTKhMeFNxeFgwxSJBpaigpNw/o/Gj1QJ3bwTuXMe/pls0lGQB/7sGWDSWdzPWgWAyhhoDZBKlxAdjPhAmVKlRqdBAA4fLodwpnuOA1U9L1ym0aSiuLcaD6x4EIK326wudVie49OnEibrCcRxu/PVGjFg6AhtyNgjd42mKagPLgmJCJczIK2rSSpLjOCw5tARv7HhDbFxnilO1qNRn3yCO4yTnRCCBWkolooOF9q9ajLzYUErnpSH+VZpQnpPHsd0WFbpNOukYPbJTChJ8lbenJhBPLtuLQa+swz9ZvGst2syb3l+4RszE+OIvsdlielwEIlSCd/3CRAXTEqHS7+7QV231hjESiTKLypt57iZ0Tc2iwuDFCmlcWV0oVj7O/kscU1G3XjbXd7gezaOaY2rHqXU6Tn2TGKEsVG7qfBMGNhsovDZoDYL1Rd6QEQCQvdXTPatgUSHxjYByLJw3mkXxluBzledCVq8rpyIHB4oOoMTqu82CvzChEmb6pEoD1br/rztuXXkrah21WJe9Dq/88wo+2f8Jtp7ja5ZYTBYkRSShe1J3D5ET6rgQb9Q4aoSYDInrx6heIjoUEFFELDcAbwK+LP0yxXEAMDZjLIDw9lUiMTR0sN8PD1yGhdN74ZZBrRHvQ6hcmnqpsPzj7nOSSsAkg+jmga1xz7BMj33bpngXbT5Rcv3Et67bMQOl9RAkdBSDAjvGd8TIavdNV1+3qsaMBoKU4XfaxNo8Z3eK20uD62xOsJgsWHndSjw94GnfgxsRSpbdxZcvxpP9nvRwyxDrimKKsFI/JQWLCl308sOxHwZ0ruT9V59ejeFLh4ckqJY8y0IJEyphZnKHyZjdT5pSuyNvB/YV7sP+ov3COjJjJxf5ossXYcWkFfh47MfCmPq0qBBrCl3SHghfMC2BVPQlQcgAn5p4Y6cbJeN6pfQSlol1pdJeiZzynLCkcVvdGTJ0tHpKjBnjuzeDQadFvCyGxKTXopnFjKoTj+K2jrOErqUlVZ5NFGlriZJlpnViHQuzEaFSW9ZwQkWrQ8LoF4SX8eZ4YNw8IKlD0yqUxhAxRkGIw7K57wd0TEUdhQoAv+MtGhOpkWK7gRbRLdA+vr1qPRkiFBQr9ioFxSpU4iaTqH5p/TCg2YCAzpVucVBuK8eqrFVeRvuG4zgs2r9Icduvk4Ir9gYwoRJ2dFodbux8o0fL83+t+xc+3vexx3hiKTDpTIg0RKJ/s/5YcuUSAOERBxW2CticNo+HOzFFxpvjJTcLb023goV2/RArDv2eVqcVQ1oMwZZpW/D75N/x48QfkRknWh6IUHFxLly5/EpJ7ZVQQW4Gaq0RkmOkVoENjw9HXKQRLlsKesVfCb2Wd+8cL/D8u0UaxayLlFhP60KdUpMBsd5HTQlQ7E79rm+hAmnMgUlnAgbeDzywDYht7mUvRqNFo/Gs0UN36pZXrS087rWy6oWCUWfExikbsWnKJqyYtAJfj/9a+P7LIaUotp1XKJqndL9X6CdFLCqBpvwCntaf3fm762SZLrOW4VyVssuvZWxLSXwfPRn1BRMq9YQ8I0XtQa8Ue0GsGGcrzypGhy8/thzfHv02oPPhOA7/WvcvDPpqEHp/0Rv9lvQTapZwHCcUAWptaa14LnS5fzn7C/crB4epQB+rb1pfj+1EyMQYY5AalYpMS6YQywLwflbSCRQAXt/xut/v7S+CRUWnfDPonm6RdDduZomAJYK/OZVTpfLXHPS8UUdSFpVRnVM9tndIrWOaZoRbIBxdBdSW8iX149vU7ZjBnEYg/XoYTQNSA4dkAdJCZefnwPHfgRPr+PYN7/QG/tvB8xgXIAnmBMSb46HT6rz2fbuizRUAgPU56z0KfsKq8IxQsKiQ+6Pavckb8mapK7NW4tktzwZ8HAIpbhdnisMTfcWGg2My+OKXdOxhq1jlmjBKhE2o/Oc//8GgQYMQGRmJuLg4xTHZ2dkYP348IiMjkZKSgscffxwOx4UZWOdP6uzwFsMVU/LoeI3rf74enx0QK97WOGowd8tcvLD1BUlQlS8OFx/G+pz1wutaZy3uWcP3F+r/ZX+hiBqpREsgF9f5qvOKPSIOFR3CtF+mYcx3Y/xOpybWileHvoo2FvEB+tX4r5ASmYLnB3n2OqJnAmadWZIFFGiOvj9YXVavx9ZqNfjq7gGIMuow2i02zAZegNBl8bec8PQB066fWLMBPVqIn+2+4W0xvlszj30CgvSkITfCSyZJm+s1AIEG/TEaKSRQm7h+6JoqlbnAF9cBn08C/ktlMjZQk9XGSJfELogxxqDWWet5v7RRFhVy31FIGBDi54KwqMTJG2sCWHN6TcDHIRS6U9WTI5Mxo8sMbLtxG94Y/gZeuozPeKWfZW3j/A/mD5tQsdlsuP7663Hfffcpbnc6nRg/fjxsNhu2bNmCzz77DIsXL8bcuXPDdUoNijehsvOmnfjP4P/g2UHKSpZWoUdLjmLB9gU4X8nnvdOWC1p4AHyA1qL9izzSmk+UnsC5Sk/znN1lx/xt81HjqMHfuXwdhEyLNLgz0ZyIBHMCXJxL8YLekbcDAO+uufana7E7f7fKpxYhpZ+7JEpbzXdN6oq1169VbLJFz86TIpIkAq9FtKdVqq4Qi4rJS+Bnp7RY/Dl7JN6/iY+fMet5AWKlhEp+uWc12EiDNKPHqBe/lk9e3qnOnakhT/NM9l6Qqj6gb1iMJgyd+s5xUouKGkpBohcpWo0W3ZP4mjT7C/dLN9IumAlv8L/P7QJ2LJYMI66fYCyWahMvXy1f1CAWlZQI/nln1psxKmOUUHuKtnz76gNFEzah8vzzz+ORRx5Bt27dFLevXr0aBw8exBdffIGePXviiiuuwIsvvoiFCxfCZvMMOCRYrVaUl5dLfpoCLWOUi0Nd2eZKGHQGXN32aqHhnxylC/Czg5/h84OfC0GvAHCyTOoTfnLTk3h9x+uY/YcYrFhUU4SJP07Ewxse9uu86VgQgI8daR/XHgDwyb5PPMbLGwP+fOJnn+9BRIA3E6kcjUaDN0a8gX8P+DdaW1pLXGLBzCx8nqPTu+uHEBdpFLocmw3871o7f25OF4cihWBaeVdkWqiEBGJRIcTU0UJTB57q/xTaWNrgwUsfbLBzYIQQIlRslbwA4dyi/OH96vv4I2aCwWkHNvwfcGZ7eI4fJjok8O6wE6UnpBuI62fA/UBiO3H9zw9JhgkxKkG4fiTnQVWqvW3lbUKj2EAgWUNqzzK6hETnBP8LTjZYjMrWrVvRrVs3pKaKPvlx48ahvLwcBw4cUN1v3rx5sFgswk/Llk2jOqRS7AUAvHDZC4rraTQajUcBtCWHlmD+tvkSFS63kmzP47+wf54Ve+AcKw2suq3cogIAd3Xnq8aeqTgjEQj7C/fjo30fScb6aibmcDng4Hj1HugXbVSrUbih4w0AgCf7PSmsD0d2FLkZBCKm5K6fkmobnC7OZ++6u4bwf/PRnUNUaTdCZlGJqXu362CZ1mkafpr4E5pHswDaCwITJVRIanJ8G+9Ve6vD1OX8n4+ADS8DH48Kz/HDRJtY3t1N9zgDILp+jNFe+2EJMSpBTtBm95uNoS2GYsmVSwRX/+6C3X5NMuUQC79adV66IB3t5vdFgwmV3NxciUgBILzOzVWvkjdnzhyUlZUJPzk5OapjGxMWkwXTO01Hp4ROkghwf+Mpnuz7pOL6F/96UVjeU7BHmPmrEUhEd4I5QfGC65XaC1qNFjaXDUU14uzo3d3veoylS88rQZ+vN7eKL/qm9cV3E74DENhn3JG3AwcKeWG85dwWHCjyFMkuzoVXt78KIDAxJQgVd9fgggr+s/qquTK8YwrWPzYc797Y2+/38n4isroOUcnK4xiMQCEP0GOrgSXX8cst+3vfJ1wWlZzAyvY3FkjmT1Z5lriS44Bt7kmfKdpzsuEQrR11iVEBgBs734iFoxbCrDdLXLLB9JYjiRGkdYwcSXFPkwW3XnKrX8cNSKjMnj0bGo3G68/hw4cDOWTAmEwmxMbGSn6aCnP6z8G3E75VNYt5Qx6drcYXB78QlmMMYrYIx3HYnb8bm89s9thn7sC5+Gis1BKi1+rxeN/HFesYGLQGoVbA8dLjOFJ8BIU1hdh81vPYP534SWi4qIREqNQxCJZ8yfxN4y6tLcWtK2/F1F+mYumRpbhnzT24e/XdcMpKupO4m0DP0SRz/ZCuyEnRvq0ybZKiQucC0uqASR+Ir+M8u3MzGEFR6S5UdoiafXe/3vs+f74BHAs+YFMVhYyYpgDJ9MyrzhPvPflUl/jYdLG4HsHKhzwsObQEPxz/AUBosuroVh8eFh4/KLOJrWD84d4e9/o1LqC2mbNmzcKtt97qdUxmpqerQIm0tDT884+0B0BeXp6w7UKGlKEPBH8LH50uP40deTug0+gQoY8QTG151XmY8dsMj/FjMsYIxcgILaJb4MvxX3rttdEsqhnOV53H3WvuBuD9S3Kk+IhqjA6JTzFoDT7dRL4gQcdWpxUbczZiWEvv7dbpIks/nvgRAF/06GzlWUnqHF1a2iOF0AskmPaTP07h/uFtUWXlvsAW+gAAL35JREFUb0LRJj3iIw0oqbbXrYdPIPSYCmQO5/34JhbIyggRbUcAWdQEJaUL0G60933O7gCWTAaeKQD0dWi2KYeuMeKwNpmKxwnmBGiggYtzodRaypfgr6S8Cl2uAXSyWkq1ZUBUEl755xVhVV1jVABgcPPBQiflYKrUlrsFlNrEet6QeXj6j6eFLCB/CejJkJycjE6dOnn9MRr9u/AGDhyIffv2IT9fLB28Zs0axMbGokuXLl72bPqQ/HLSEMpfeqequwKIi+Zc1TncuvJWzPhthhCBDcjMihR00Z1uSXzg89ROU302BEuOlLoP5KnK0ztNF0ya3lwxSqXpg4UUowOA749973M8Xb+FbnMuN3nSVh9v9WPkmKlsnjs+2w6r2wVkNuiw9J6BGNI+CQ+MaKe2e+iJSbt4O/4ywkP/e6WunsQArmd5H5u6YqXuM+FyL4UBvVYvPNgFcUDieFoP8RQpAF8PSYZw/9u+CPh4DFCp0D/IB7d3u12IhwxUqNQ4arAzn49Toutc0VyVeRX+mv4XJrSdoLhdjbDFqGRnZ2P37t3Izs6G0+nE7t27sXv3blRW8oGOY8eORZcuXTBjxgzs2bMHq1atwjPPPIOZM2fCZGoaSjhYBqUPwsYpG/F4n8cD2m/BsAWq20jQq1rtkrwq5YqQJG0MAN4d9S5eG/4apnea7vNclGJXbuwslrlvHt0cXRJ4welNqJDI8kCCVNXQa/Xonsyn+vljgZJnKBFoUXey9CRe+ktU/+U2/7PMSNYPAOzOKRWCas0GHdqnxuDzO/rjut6hT6VmMOoNYxTQ5w7xdQJlUb/mXcAQBQx9wnM/ADj9p/L6YKHFiVyoZP8F/P2B2DyxkUEaGQpdhUk9mkiVTsy1ZZIMmlhjLAalD+JfrHgEOPMPsPXtgM/DpDPhsT6PAQBKrCUebnBv0PW9vLl+gnFRhU2ozJ07F5deeimeffZZVFZW4tJLL8Wll16K7dv5TBSdTocVK1ZAp9Nh4MCBuOmmm3DzzTfjhRd8Z8FcCCSYEwLuY5EUkYRPxymXhycR1GoP38UHFiuupy0qceY4jMkYA4OSgpeh1Mp8Zs+Z+GjsR7ix842Y2mmqEDPy6vZXFVOZgboHgsmZ1mkaAP8yf9RajdN1Z5758xmJZSqQDs1mWX0UEqtCCxgGo8ljocR2s+7i8qU3AnNygG6Tlfc7vSW050HXZ6mSWQMWjQN+ewLYv0xc5/Ks8t1QCEKFJCdU+xYq56vOCy9XT17N15KiP5MtuJYr8aZ4aDVauDhXQHEqG3I2CMv+xqj4S9jumIsXLwbHcR4/w4cPF8ZkZGTg119/RXV1NQoKCrBgwQLo9QGFzVx09Enrg/U3rMeUjlNwaYrYkbd1bGuv+9HujPt6iEX4gg3ASpAHd4EvcT+g2QDM7jcbJp1JEkH+xs43FI8jFFILUTVZUviNtuI8/cfTeGrzUx79jNTK/NNWk32F+yTbnuinMjtUQF6nrbSaj28hsSsMxgUB3aupeS/pNq2OLzB45QJgyGPSbWf+CZ2Fw2kXAkwB8DEcSpCg39x9wP+1Bv4IfbuNYCAJFqJQcf+OohIvrqQs6tXFQjmKDvEdRLcPHdtCrNS2qoD+zjqtTriPvrXrLb/3I5PN9Oh0SaXwUMCmdk2QpIgkPDPgGaGiIaCck65Ujr9DfAc0ixILfhElHyhy149S+jSddaQGif8IlVCJMfLvSYK6yqxl+OnET/j55M8eFhQ16xMtVC5JvERYHpMxRiIOfVFtk5pNz5by1hiTgQkVxgVEXAaQMRhoP1a92WW/u4ARTwFdrwMGzAQ0Wl5MVOYrjw8UebVbOoaDfkgXuYuqbXkHsJYBvz8XmvevI8RC7en6oYRKv7uAXrfwy9VFgkWleRQlFEl3dAD4612g8BjwcnNguX/ZNYQh6UP40wigEe6ZijMAgPlD5wf0Xv7AhEoTpmtSV2FZblGZkDkBf077U2h6RbA6rRKRQQJeA4UUKSJM7+wZ10JEgzdCLVQEi4o724kO8q2RdR4lQkVeTI8OmKVLSVfaAiskJxcqZ0rchZmY64dxIaHVArf9Atz4LbxWM9TqgMmLgMtfFlPkC/3vT+YVeRG5mlJxmQ6yJYHxMVQNLzXrSz1CLCpiMK1bsETKLNekBlJlvmBRaRZNVZqWf5ZF4/jfe78O6Hwub3M5AP9rUrk4F/KredFJT4RDBbtjNmGGthgKgE8FS41KlfgFiRiRW1WsTqtknFrasC8y4zIl+yqlFtMtvWnohz+JUalLsTcaIo4qbBXgOE4yI6CrIgKiUBnVahTeHfUu7urGV9ylLSp0rMv9Pe8P6Fx6tZJmTolChVlUGBc5pN9U4dHQHK9GJlToBzZtXSFl6eleU7vE2lMNhTxGJaemAJ9YYlBtlk32iFCpKsC5Kl6oSCwq8riUILOfyH3U3yrfFbYKoQZLqONTACZUmjSRhkj8Pvl3fDvhWxh1Rug1YnzP6Ay+loGHUHFYJe4ef7o6qzGg2QCv2zsldBKWSTOq57Y8hxFLRwgzh9wq3qeqFJwbDOTzujgXKu2VEqEib5BIhEqCOQFDWgwR6q6UU75usv93E75Dz5SeAZ3LwLaJ+N/t/dAxlf/SZxfzrh8Wo8K46CEuotLs0ByPtqAAUpcSva26iHcF0UHxh39RPmbJaeD8XuVtISbJ7I5Rcbt+7jRX442EeLx9dq10YDQRKoUoqObTjyX3cG9W3wDcXCTmxV8rMpncRegjQpLBKYcJlSZOalSqELhEq1/yUJWr21pnLVrGtMTLg1/GB2M+qFORNVIHZkTLEYrbL0m6BO+O4svqOzkn7E47lh1bhlJrKX45yd8cTpbyjRQDafntDbPeLMwGcqtyJUJl3j/z8NbOt/DBng/w2YHPcLr8NADR+kRy/0l1RUAUKkrxPv4wtEMyureQ/g8ijOxrx7jIsbitsWVnQnM8eTbe7i9EEURbVJxW3hVEu4ELFNxPHAe82R34YAhQoVzaIZSQyWNBdQHgcuGcu1HpmvxtknG/15zFmsgIcFV5gltGco8nFqMWCr3lAggcJvGFFfYKjyQEJYhQ8cfdHwwsxeYCQqnPj/wBS6rQBlpwR4k2ljbYOGWj14tzQHPR6vLH2T+EZbPODI7jsKdgDwDl5ofB0jKmJQ4WHUR2RbbHl0zeNBEQhQrJUqq2V4PjONhddqESLV1vJlCSYqRuLeb6YVz0kJTm0hD1alMqn79yDjB1iae15RWZu7u6kA9epTNsqqhiaWU50piWUHD4V2DNv4FJHwIteqNlTEvoNDqUWEtwrkhsQ+Og7l8nS0/ikYMfAanJuKuyXBAHwj2e4/gAWgBI7gSckYqcQCD3QofLAZvL5jOGUOjxE+SEzhdsaneBQ184d3e/G//q9a+QHj/BnKAaiwJI41T+tV58bwfnwBObnkB2RTYMWoNQqC0UkNiZMxVn/IpaJ38jUh2XAwer0yrZl656GygxZul8wBSqHj4MRlOFVEguC5FQIRaSaEpQHF4BnN8DVKg3uRWQW1Xo1wEUPfObr6cBRcf5VgLgJ0IdE/i4nR+pqto1jhphskX3TPs0yihk/QgNAA//ApSf5ZfljUgDJMoQBQ34wGh/Amo9RFOIYXfMCwgSDHp719uFdXQXy6vbXh2y7Jq6UmYtE5r9Tek4pU6xMnJaxfB9erLKs3wKlaf7Py0U3qNrytQ4agRXmllnlnS8DpRaWfZPYaVNZSSDcZFABEVVYWhqqRChkjlCWsvl3C5pyq4aP9wrpi4D0iDfAFJ0A4YKAu4Q3wEA8N6xpcK6ake1kE1Dl1dwUNlVgkWbbmRojAb63uX5fnb/GjdqNdqA4lRIXF84AmkBJlQuKO7veT++vPJLPHjpg8I60qhPvtzQlFpLBXNhoD2PfEG+8EeLj6La4b2SbOfEzsKyTquDUcsHgtU6aoUvn1rLcn8Z1E7aLTuCuX4YFzsR7ow4lz3oCqoSiFAxRAAT3xXXO2zehQoRTKXZwOeTxPV08bhQnJ8fEGsE3cEYAA4V8wJErfeOIFSMlHtaq+Pr1sjZ8pbfwpCcz+IDi1HrozM1c/0w/Eav1aNbcjfJ7J+OwA5XoFMw5Ffnw+biLQuhVuEdEnihsrdwL97c+SYAYGzGWEkWEiE1Uup7JtUVaxw1KLHyRaTiTd4bNPpiQGYivryzP/4zqSuu790CU/uxxoCMixxDpFg5VV6sLRgclFBJ6Qx0n8q/LssGzvJtW6BQTVvSULH0NF+PpfgU332ZEG6hUsBbb9Qe8g+uexC783crCpVIfaSy691aDpjjPNev/4/fsSskwHfZsWV48a8XvY4lnehDaRmnYULlAqeNpQ36N+uPy1tfHpa0MX+Y02+Ox7qssiwAgF6jl/QbCgUZMRke3Zh7pvRUFGqk0BKBuH9qHDVCif04pS98gAxql4Qb+2fg1et7INLIYtgZFzkajWhVCYVQoS0qAJDgLki55W2gMg+ITgPajvTcr9v10tfv9AHe6smLFUKAhR79gp6cLeQzdOT3p+Ya0U3/wl8viOX1KST71FJWIGsFX4hPiYrzyutl0BZ4YtVRgwgV+cQvVDChcoGj1Wjx8diP8eqwVxvsHKZ3no7hLYZL1p0o4/3BFpMl4OaMvtBpdWgf316yro2ljaLrSx57QguVUmspgLpbVBgMhgLhECokzixKOgHB0McATiEoNioJuGON+JoUSMvaLK4Lh0UlQmZFdtg8hEpLg2hhsTvtQsxcmlHcV9IChXZXKYkygp+VeInFm7y/N/KqeKES6h4/BCZUGPWCmlWCblwYSkgEPSEjNsMv15eiRcUUF/LzYzAuesJpUYmiXBD6CKD7DcqdiE2xQMt+0mwhQMyeAQIXKsfWAP/tBBz7XX1MpExI1ZZ5uMAzzOIYu8suxIkkUGIgNYL6nESAZAwGOl/NLw9+hK9m+8hBoMtE6Tgf2JyiUFGLjyEQiwoTKowmjYWaBbSIFtvCB9L0KhDo3kd6rR7p0ekeKcZXt73aYz8iVGqdtZLKtQwGI8SQmJFQVKd1yIRKPNXDrO1IPl132JNAuzG8OCGQUv7e0nkDFSpLJvPulSXXqY+h2ogAAGpLPSZSqSliLzcn5xTajSRQVpRU+t5EBEjXSWLPpdHPAY8dAyzpQHSKdJwP+qT1EZYr7ZWSvmk0VqdVuFcy1w+jSUMKpwHSTJvRrUaH5f1oZf/BaL4CL2k+aNAa8MqQV/B0/6c99iPBtEsOLcGyY8sABN9hmsFgeKEN36sMuz6v+7HkFpV4qmkqqdkSnQLc9B3QRyzfAJ07ENVbZl8oLD5ynLISBbVlHsG00QnthOXcqlwcLDoIAEig4upSjXHiDsT1I09OIKKFfEY/hcq93e+VZJAWVitbVYjbx6wzs/RkRtOGLu9P13KZ1WdWWN6PbtRFvjw9knvgp4k/4YdrfsD4zPGK1WaJRYXUeAH4+BYGgxFi2o/hf5f7F9zpFVIfhAgVM/XQl3/PL3sI6HkjcMsKcZ3Zi1A5+BNg817mIGDkQqWm1KNB7BVtrlBMNKAtvM04Kr6PdJCOVImpI1YjP4VKpCESd3e/W5j00c1aaYRA2qjUkMcbEphQYdQLpGR/t6RuEusKsWCEGtqiQs9U2ljaoFVsK9X96KJv9D4MBiPEEFGh4lLwyvZFwMdjgEp3qXvS64f+/na7ATBEAX3vkO4bmcDXWmkzRFznzaJiq+BTl0OJQ25RKYVRZ0QLykUeb47HH9P+gBzaatF5DZU2XOW2eMjjXwgBChUCSUKotFfiaMlRTPxhIlZlrRK2k8ayaZHhiU8BmFBh1BP90/rjuwnf4aOxH/mMIA8FiRGJ6JbUDR3jOwaU2z8mY4znsULU2ZnBYFCQSYrLAQR6T1jxCHDmH16wAGLjQTrW5NoPgSdOiH2FvOHNogLw6b6hhPRlS3D3OHOf/+PxvQEAHbV8PJ1SjRR6XWu7O9aF48SMJXnGEyFIoUJi+8qsZbjup+twouwEHtv4GH45+QtyynMkFpVwwQo6MOoFjUYjZOLc0PEGrMtZh/5p/X3sFTxajRZLrlwCF+eCTut/JdiRrUZicPpgoYHiG8PfCJs5k8G4qKFdMvYaMV7EF7Ro0MuKxkVQbg+NRrTa+IIWOFHJ0qaEgLRGiTfkLiKOE2NEaIhFJaYZUHySt4b88xFGHtmINeVnEdnvbmGoTqODk0qtHp0xGns2voA+NbW8pcFhA/IP8lV+AeXsJoC3JAGioPETYlH5eN/HkvWzN88GICYuhDM7kllUGPXOoOaDsPzq5Xhn1DthfR+NRhOQSCF0TRKj7TslelazZTAYIUBvAtyN74RgWH/IOyguu5z8g5p0SI4MMkOPDgJNbO+53eqnUJEH3lorgCO/AW90B7L+FNeTGJVEd8DsoRXAr48BJaeQ5nQiNlqMsfty/JeSQ0YbovFafiGmV7jj/hb2BT4cxi8botTFGXEJBShUiEVFrehbVnkWgPD1+QGYUGE0ABqNBu3i24UtPqWuNItqJizTadUMBiOE0BaPQOJUcveKy+tedHcgdvevCbaKNC1w0sSJimCh8df1Q1xQBFsV8NVUPsZlFVWhm7h+kt0Tobx90v2ikoXFLoldcFXmVeIp6SP4tGMC3csoyoubmlhaakoC6gjtb62rcN4rmVBhMGTQQkVee4XBYIQQMlnx16KyfRFveaA5tZH/bYwWXUGB0m0y0Ps24MoFQCdRFAiF4/yxqHAc8OVU6TraekHuJU4HwLn45eQOyseSxZnQNVYMWgMw4H7l/dp5KfdAxBjnEi1QfuCQ1XyZN2Se4ri6Nm/1BotRYTBk9Evrh3Gtx6FlTEsWn8JghBNDJFBT7L9Q+eN19W1KTQf9xWwBJrzBL9MPcaNbXPhjUakt5Zsg0mxeIC7HNuOr1hYcFtclSStoC3gRKhqNhm/oqNF5tgUY+x/189MZ+M9ZW8YLKG/WFwpSoZvQPk7BNYbwWlSYUGEwZOi0OiwYtsD3QAaDUTcMbouKuzy8V0qzxSq2llaeoiAiLjTnFBEHdJ4A5B8CWg0Azu30L5hWyUpxYLm4XJoDfDlFKi5i0vj4GKssE0eWYuzRWVmj4UUUbemZuQ0w+mjwGpkoChU/KbNJz00ti5LFqDAYDAbjwoPUPbH7KKhWmQ+80Y1fTrkEGPKI55jUS0J3XlO+AB7YLsaK+JPSK49PkVN8UmYB0QBavbTcP0FmURmcPhiAtFgmH4zs5t4/1N1INCRORaXKrBKP9JL+rensnkxLprDMhAqDwWAwLjxIMO36eYC1Urqt7CxfL2X/MmDNXHF9ZAKg1GA0rXtoz02jEWuw+NOPyFfch1wctOjLv0eCQkFJWeZO27i2+G7Cd1h53UpxJV17Jrkz/CKIzJ8+aX3w7wH/BgBc0/YaaDQazOk3Bzd2vhHTOk3jD6uPRHp0ut/HDBTm+mEwGAxGw0AemGe3Awe+B3rdLG5bdieQvQU4+KO0cqzZIrUmdLseqMgFesgCWUMBKchWfFJ5+5kdQMU5oOOVvi0qNJfOAIa6g4KTOwP40ecu8o7wkjL8Oj8f5YJFJbAU5es7XI8+aX2EMv/TO08HwHeZN+lMGN5yeFjj+ZhQYTAYDEbDUHxCXC4/J91Giq5VF/GZMgRDBNCyHy9Y2o/jK9CG6yFJhErFOb6YGx0DUnIaWDSOL7TWdTKw/zt+ffuxwOmtfOl9JVr0A66hakjJXTadPbu6K+LLXaaEUPStOKDdNBqNxM1DiNBHYFL7SYGfR4Aw1w+DwWAwGobLHhKXK/Ol2+iy9nSwKcfxQaiPnwyvSAHcbiZ3HZEKWfPEPV+J1WCJSAH4uBY1kQIAJpnbqkU/cXn4HOCahf6dW5dr+N/dbvBvPCDGvlT5H6PSGGAWFQaDwWA0DMOf4lOT//nQs2y9vHEfgQSk+uvuqCumGMBW6ZmiXHRceXx0Kl/n5K93+dedrgLKcoDze/jX8r5CcS35YFhjtHK8ihrjXuatL10m+r+P3PWjVuK/kcGECoPBYDAaBoMZyBjkFiqyWb5ayjIpllZfmGJ4a4pcqBSf8hwbnQr0uY3/nd6brxrb+zb+98cj+TFGhSKSad0CPy9LC75QXSDQwbQr5wAHfwLu2ajeyLCRwIQKg8FgMBoOkgKcvQXIPwykuMvKO6zK4+tS2C0YiOvH5s5KKjsDbJzPBwDTTP0SaDMMMLnH0yLCRJWhz1fumVMv0OnJxOLz9/vAyGca7pz8gMWoMBgMBqPhSKYaf+79Rlx2yoTK0CeAlgOAEU/Vz3kRSEwJsaj8cB+w8zPPcWndpYKERm8SrSYdLg/9OfqLUjCt3OXWCGEWFQaDwWA0HFFJfJO9358Dcv4R18tdP8OeAEY+XZ9nxiMXKqc2i9v63M6LJ6eVjzXxxm2/8V2SSRBsQ0BcPDaqZo2843MjhAkVBoPBYDQs7UbzQiX/gLhO7vrRGer1lASIUPnlUd7to9HwQagA0LwX0GOK/8fpOS085+gvpli+Gi7daPD8XvXxjQTm+mEwGAxGw0IqwNaU8FlAHCdaVEY/B9y9scFOTZJO/Mdr0mDexLb1fz51QaMR41QIJaeAvAPK4xsJTKgwGAwGo2ExxwF6d4PCilxp1dU+dwDNezbEWfEYVeJOgOCydRqaKIWmguXnPdc1IphQYTAYDEbDotEAMc345Yrz0vgUImAaCnndE4B3ocw66lm8rSmQ0slzna3Sc10jggkVBoPBYDQ8sc3533u/Ab6Z4V6pabjYFIKS1aTD5UBMav2fSyhI7eq5zlYV+vdZ/Qzw80NiPE8dYMG0DAaDwWh4SOzEjsXiOr254Suntuwvfa2PAC77V8OcSyhIUei0HGqLSmUBsOVtfnno42IMUpAwocJgMBiMhsek4GKhuyQ3FKYY4LpPgMo8XrRYWjZdawoAxKZ7rgu1UCHtAgC+ZksdhUrYXD9ZWVm444470KZNG0RERKBt27Z49tlnYbNJ+zfs3bsXQ4YMgdlsRsuWLTF//vxwnRKDwWAwGitKxdIaOj6F0G0yMHAm0KJP0xYpgOhiowm16+fYanG5uu4NEMNmUTl8+DBcLhc++OADtGvXDvv378ddd92FqqoqLFiwAABQXl6OsWPHYvTo0Xj//fexb98+3H777YiLi8Pdd98drlNjMBgMRmNDKTDV0EiEyoVERLznulAKFZdLWrl3+X1A56uA8f8N+pBhEyqXX345Lr9cLBWcmZmJI0eO4L333hOEypIlS2Cz2bBo0SIYjUZccskl2L17N1577TVVoWK1WmG1ioWAysvLw/URGAwGg1FfKKUBG5tgVk1jh475Se4EFBwOrevHVinN2qrMBbZ9zMeqxKQFdch6zfopKytDQoLYUGrr1q0YOnQojEajsG7cuHE4cuQISkqUy/rOmzcPFotF+GnZ0kfZYgaDwWA0fpQsKjoWRhkWbl8NjH0J6H0r/zqUFhW1Y9Whp1C9CZXjx4/j7bffxj333COsy83NRWqq1N9HXufm5ioeZ86cOSgrKxN+cnJywnfSDAaDwagflITK2Jfq/zwuBlr1BwY9SPUxCrFFRYnKvKAPGbBQmT17NjQajdefw4cPS/Y5e/YsLr/8clx//fW46667gj5ZADCZTIiNjZX8MBgMBqOJo9VJXz9yAGg9uGHO5WKBVKktPxu6Y6oKlfygDxmwXW3WrFm49dZbvY7JzMwUls+dO4cRI0Zg0KBB+PDDDyXj0tLSkJcnVVnkdVpacL4sBoPBYDRBHFRG6L921TmlleEHqV3434VH+b+/3uh9vD8Q60xSBz6de9fn/Os6WFQCFirJyclITk72a+zZs2cxYsQI9O7dG59++im0WqkBZ+DAgXj66adht9thMPDVB9esWYOOHTsiPl4hMpnBYDAYFyYJmcrLjPARmw6YLUBtGS9W0hSq1gYKsagYo4Fr3gEiE4A/3wSKTwV9yLDFqJw9exbDhw9Hq1atsGDBAhQUFCA3N1cSezJ9+nQYjUbccccdOHDgAL755hu8+eabePTRR8N1WgwGg8FojLTqD0x8D7jj94Y+k4sHjQaIb80vh8r9Q4JpSV2cjMv438d/D7qcfthCqtesWYPjx4/j+PHjaNFCasLj3CdrsViwevVqzJw5E71790ZSUhLmzp3LaqgwGAzGxUjP6Q19BhcfUW4PSR1iSCRYK/jfJN28zVD+d/lZoKaEt7AESNiEyq233uozlgUAunfvjs2bN4frNBgMBoPBYKhBAmqrQiRUiEWFCBVDBN8fyVHDi5gghArrnsxgMBgMxsVKNLGoBF/nRAKJUaFbIpBlYm0JECZUGAwGg8G4WBEsKiESKoLrJ0pcJ9RrYUKFwWAwGAxGIJAYlWCEyk8PAp+OB1xOcZ3g+qEK+BGhEmSpflafmMFgMBiMixWzhf8dqLWD44Cd/+OXz+4AWvbjl5VcP0S0WIPrzccsKgwGg8FgXKyYghQRtLDRUFKCFHxTcv0UnQj8/MCECoPBYDAYFy9mdxuaQC0qtaXiMucSl+mCbwTSHmH9fwA71VnZT5hQYTAYDAbjYoVYO2oDtKjUlIrLdMdkwfVDxaic2yUuF0h7AfoDEyoMBoPBYFysmNwWFUcNYK/xf7+aEnGZ3k8IpqVcP10mistMqDAYDAaDwfAb2vLxnzRg46v+7Ue7fuzV4rJVwfUzYo74+uCPAZfSZ0KFwWAwGIyLFZ2BrxxL2Pxf//Yro3oDEaHiciq7fkwxwKT3+eUjvwL/fBjQKTKhwmAwGAzGxQxH1UGJTASqioD8Q973+fs9cdleA2xfBLyYLGYP0RYVAGg3Wlw+8ENAp8eECoPBYDAYFzManbis0wPv9AHeHQAUHFEe73IBZWfE17ZKYMUjUsETlSTdxxAB3LOJXz6zDXDa/T49JlQYDAaDwbiYmfG9uFySBdQU88uHf1Eeb6uUpiSXn/Mco9V5rkvtyv922YHaMr9PjwkVBoPBYDAuZjIGAQ/v91xfqdJRWV4cbtvH/r2PVidWqWVChcFgMBgMht9ExHuuq1IRKr5ExiWT1LeRAnMBCBXW64fBYDAYjIsduu4JIXcfn0qs0UjXb3lH+Rgt+gL97wXajVJ/H1MsgLO8VSZGfRgNs6gwGAwGg3GxIxcjAFB4FMjaLF3HccCeL8XX0WniclwroNtkZesMQbCo+F8JlwkVBoPBYDAYypAOyYTqIunrjEHictuRvo9HKuEG0ASRCRUGg8FgMBjAv3Z5rpMH1P78kPR168H876QOQI/pvt8jCIsKi1FhMBgMBoMBJGQChijATjUZpC0f9hrg8Arx9ejngUtnANGpQNsRgNYP24eJBdMyGAwGg8EIFoNZJlQqxGV5tdrBD/O/O1/l//FJ/Ard1NAHzPXDYDAYDAaDh+77A0hdNHkHxOWbfwru+FHJ/O/qQv9PKbh3YjAYDAaDccGhN0lfWyuArD/5irXl7kaEvW4BMocFd3wiVKoK/D+l4N6JwWAwGAzGBYfeLH3tqAEWX8kvt3Jn+Mj7+ARCVCL/u8p/iwpz/TAYDAaDweBJzFTflu92/UTWRagQiwoTKgwGg8FgMALlygVA+7HA9G8BQ6R0G8nUIWIjGOgYleJTfu3CXD8MBoPBYDB4YtKAG7/ll43RgL3acwxx3wRDVDIvgOzVwAdD/NqFWVQYDAaDwWB4ojMorzdbgj+mVgcktgtsl+DfjcFgMBgMxgWLVue5ruN4oFnPuh2XLrvvz2nU7d0YDAaDwWBckGgUhMq0L5UFTCAMfjSg4UyoMBgMBoPB8IQWJIZIYOxLoTluTCrw70Jgype+x4IF0zIYDAaDwVBCS0mE2TmALoSSQWcAMof6dxqhe1cGg8FgMBgXDAPu53+3HxtakRIgzKLCYDAYDAbDk0tnAKmXACldGvQ0mFBhMBgMBoPhiVYLtOjT0GfBXD8MBoPBYDAaL0yoMBgMBoPBaLQwocJgMBgMBqPRwoQKg8FgMBiMRgsTKgwGg8FgMBotTKgwGAwGg8FotIRVqFx99dVo1aoVzGYzmjVrhhkzZuDcuXOSMXv37sWQIUNgNpvRsmVLzJ8/P5ynxGAwGAwGowkRVqEyYsQILF26FEeOHMGyZctw4sQJTJ48WdheXl6OsWPHIiMjAzt27MCrr76K5557Dh9++GE4T4vBYDAYDEYTQcNxHFdfb/bTTz9h4sSJsFqtMBgMeO+99/D0008jNzcXRqMRADB79mz88MMPOHz4sOIxrFYrrFar8Lq8vBwtW7ZEWVkZYmNj6+VzMBgMBoPBqBvl5eWwWCw+n9/1FqNSXFyMJUuWYNCgQTAYDACArVu3YujQoYJIAYBx48bhyJEjKCkpUTzOvHnzYLFYhJ+WLVvWy/kzGAwGg8Gof8IuVJ588klERUUhMTER2dnZ+PHHH4Vtubm5SE1NlYwnr3NzcxWPN2fOHJSVlQk/OTk54Tt5BoPBYDAYDUrAQmX27NnQaDRef2i3zeOPP45du3Zh9erV0Ol0uPnmm1EXb5PJZEJsbKzkh8FgMBgMxoVJwE0JZ82ahVtvvdXrmMzMTGE5KSkJSUlJ6NChAzp37oyWLVvir7/+wsCBA5GWloa8vDzJvuR1WlpaoKfGYDAYDAbjAiNgoZKcnIzk5OSg3szlcgGAEAw7cOBAPP3007Db7ULcypo1a9CxY0fEx8f7dUxinSkvLw/qnBgMBoPBYNQ/5Lnt08vChYm//vqLe/vtt7ldu3ZxWVlZ3Nq1a7lBgwZxbdu25WprazmO47jS0lIuNTWVmzFjBrd//37u66+/5iIjI7kPPvjA7/c5ceIEB4D9sB/2w37YD/thP03w58SJE16f82FLT963bx8eeugh7NmzB1VVVWjWrBkuv/xyPPPMM0hPTxfG7d27FzNnzsS2bduQlJSEBx98EE8++aTf71NaWor4+HhkZ2fDYrEEfJ59+/bFtm3bAt6P7dt03rsp7kvS7nNycoKKwwr2vZvi36oh37sp7ttQ790Ur+mm+L4NuW+g+5eVlaFVq1YoKSlBXFyc6riAXT/+0q1bN6xbt87nuO7du2Pz5s1Bv49Wy8cDWyyWoC5+nU4XdEAu27dpvHdT3JcQbMB4sO/dVP9WTfG8L8a/F9C0rumm+L4NuW+w+5PnuOr2oM/mAmHmzJls33rYtyHfuynuW1eCfe+m+rdqiud9Mf696kJDXNNN8X0bct9Q7K9EvVamDQf+VrZjMJoS7LpmXGiwa5ohp9FVpg0XJpMJzz77LEwmU0OfCoMRMth1zbjQYNc0Q46/10STt6gwGAwGg8G4cGnyFhUGg8FgMBgXLkyoMBgMBoPBaLQwocKoExqNBj/88ENDnwaDEVLYdc240GjK1zQTKgwJt956KyZOnNjQp8FghBR2XTMuNC6ma5oJFQaDwWAwGI2WRi9ULibV2Nho3bo13njjDcm6nj174rnnnmuQ87lQYNd0w8Ku6/DAruuG40K/phu9UGEwGAwGg3Hx0qSEysqVKzF48GDExcUhMTERV111FU6cOCFsz8rKgkajwffff48RI0YgMjISPXr0wNatWxvwrBkMddg1zbgQYdc1I5Q0KaFSVVWFRx99FNu3b8fatWuh1WoxadIkuFwuybinn34ajz32GHbv3o0OHTpg2rRpcDgcDXTWDIY67JpmXIiw65oRSsLWPTkcXHfddZLXixYtQnJyMg4ePIiuXbsK6x977DGMHz8eAPD888/jkksuwfHjx9GpU6d6Pd+mjlarhbxwsd1ub6CzuTBh13T9w67r8MOu6/rlQr+mm5RF5dixY5g2bRoyMzMRGxuL1q1bAwCys7Ml47p37y4sN2vWDACQn59fb+d5oZCcnIzz588Lr8vLy3Hq1KkGPKMLD3ZN1z/sug4/7LquXy70a7pJWVQmTJiAjIwMfPTRR2jevDlcLhe6du0Km80mGWcwGIRljUYDAB4mR4ZvRo4cicWLF2PChAmIi4vD3LlzodPpGvq0LijYNV3/sOs6/LDrun650K/pJiNUioqKcOTIEXz00UcYMmQIAOCPP/5o4LO68HC5XNDr+ctizpw5OHXqFK666ipYLBa8+OKLF5RKb2jYNV1/sOu6/mDXdf1wMV3TTUaoxMfHIzExER9++CGaNWuG7OxszJ49u6FP64IjPz8f7dq1AwDExsbi66+/lmy/5ZZbJK9Z8+3gYdd0/cGu6/qDXdf1w8V0TTf6GBWiGrVaLb7++mvs2LEDXbt2xSOPPIJXX321oU/vgqGkpAQrVqzAhg0bMHr06IY+nQsadk3XH+y6rj/YdV0/XIzXdKO3qNCqcfTo0Th48KBkO60SW7du7aEa4+LimrSSrC9uv/12bNu2DbNmzcI111zT0KdzQcOu6fqDXdf1B7uu64eL8ZputEKlpKQEf/75JzZs2IB77723oU/ngmf58uUNfQoXPOyarn/YdR1+2HVdv1yM13SjFSoXo2pkXNiwa5pxIcKua0a40XDM1sZgMBgMBqOR0uiDaRkMBoPBYFy8MKHCYDAYDAaj0dLgQmXevHno27cvYmJikJKSgokTJ+LIkSOSMbW1tZg5cyYSExMRHR2N6667Dnl5eZIx2dnZGD9+PCIjI5GSkoLHH3/co7nVhg0b0KtXL5hMJrRr1w6LFy8O98djXKTU13V9/vx5TJ8+HR06dIBWq8XDDz9cHx+PcRFSX9f0999/jzFjxiA5ORmxsbEYOHAgVq1aVS+fkdE4aXChsnHjRsycORN//fUX1qxZA7vdjrFjx6KqqkoY88gjj+Dnn3/Gt99+i40bN+LcuXO49tprhe1OpxPjx4+HzWbDli1b8Nlnn2Hx4sWYO3euMObUqVMYP348RowYgd27d+Phhx/GnXfeyb4AjLBQX9e11WpFcnIynnnmGfTo0aNePyPj4qK+rulNmzZhzJgx+PXXX7Fjxw6MGDECEyZMwK5du+r18zIaEVwjIz8/nwPAbdy4keM4jistLeUMBgP37bffCmMOHTrEAeC2bt3KcRzH/frrr5xWq+Vyc3OFMe+99x4XGxvLWa1WjuM47oknnuAuueQSyXtNmTKFGzduXLg/EoMRtuuaZtiwYdxDDz0U3g/CYLipj2ua0KVLF+75558P0ydhNHYa3KIip6ysDACQkJAAANixYwfsdrukAl+nTp3QqlUrbN26FQCwdetWdOvWDampqcKYcePGoby8HAcOHBDGyKv4jRs3TjgGgxFOwnVdMxgNRX1d0y6XCxUVFcL7MC4+GpVQcblcePjhh3HZZZeha9euAIDc3FwYjUbExcVJxqampiI3N1cYQ1/4ZDvZ5m1MeXk5ampqwvFxGAwA4b2uGYyGoD6v6QULFqCyshI33HBDiD8Fo6nQqAq+zZw5E/v372edNhkXFOy6Zlxo1Nc1/eWXX+L555/Hjz/+iJSUlLC+F6Px0mgsKg888ABWrFiB9evXo0WLFsL6tLQ02Gw2lJaWSsbn5eUhLS1NGCOPLCevfY2JjY1FREREqD8OgwEg/Nc1g1Hf1Nc1/fXXX+POO+/E0qVLL5rmewxlGlyocByHBx54AMuXL8e6devQpk0byfbevXvDYDBg7dq1wrojR44gOzsbAwcOBAAMHDgQ+/btQ35+vjBmzZo1iI2NRZcuXYQx9DHIGHIMBiOU1Nd1zWDUF/V5TX/11Ve47bbb8NVXX2H8+PFh/mSMRk8DB/Ny9913H2exWLgNGzZw58+fF36qq6uFMffeey/XqlUrbt26ddz27du5gQMHcgMHDhS2OxwOrmvXrtzYsWO53bt3cytXruSSk5O5OXPmCGNOnjzJRUZGco8//jh36NAhbuHChZxOp+NWrlxZr5+XcXFQX9c1x3Hcrl27uF27dnG9e/fmpk+fzu3atYs7cOBAvX1WxsVBfV3TS5Ys4fR6Pbdw4ULJ+5SWltbr52U0HhpcqABQ/Pn000+FMTU1Ndz999/PxcfHc5GRkdykSZO48+fPS46TlZXFXXHFFVxERASXlJTEzZo1i7Pb7ZIx69ev53r27MkZjUYuMzNT8h4MRiipz+ta6X0yMjLq4VMyLibq65oeNmyY4vvccsst9fRJGY0N1pSQwWAwGAxGo6XBY1QYDAaDwWAw1GBChcFgMBgMRqOFCRUGg8FgMBiNFiZUGAwGg8FgNFqYUGEwGAwGg9FoYUKFwWAwGAxGo4UJFQaDwWAwGI0WJlQYDAaDwWA0WphQYTAYDAaD0WhhQoXBYDAYDEajhQkVBoPBYDAYjZb/B72lQNNlIbKPAAAAAElFTkSuQmCC", "text/plain": [ "
" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "%matplotlib inline\n", "\n", "df.plot();" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Das Ergebnis ist ein PNG-Bild, das leicht angezeigt werden kann, ansonsten aber statisch ist.\n", "\n", "> **Hinweis:** In pandas > 0.25.0 kann das Backend ausgetauscht werden, z.B. mit `pd.options.backend.plotting == 'holoviews',`. Weitere Informationen hierzu findet ihr unter [pandas-API](https://hvplot.holoviz.org/user_guide/Pandas_API.html)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `.hvplot()`\n", "\n", "Wenn wir statt `%matplotlib inline` zu `import hvplot.pandas` und der `df.hvplot`-Methode wechseln, , wird jetzt ein interaktiv erforschbares Bokeh-Diagramm erzeugt mit Verschieben und Vergrößern/Verkleinern sowie anklickbaren Legenden:" ] }, { "cell_type": "code", "execution_count": 3, "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.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", " var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n", " var reloading = false;\n", " var Bokeh = root.Bokeh;\n", " var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\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.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/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.1.1/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.1.1/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.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/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", " },\n", "function(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", " inline_js[i].call(root, root.Bokeh);\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", " Bokeh = root.Bokeh;\n", " bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", " root._bokeh_is_initializing = true\n", " root._bokeh_onload_callbacks = []\n", " if (!reloading && (!bokeh_loaded || is_dev)) {\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": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\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.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/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.1.1/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.1.1/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.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/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 inline_js[i].call(root, root.Bokeh);\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 Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\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));" }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "\n", "if ((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", "\n", "var JS_MIME_TYPE = 'application/javascript';\n", "var HTML_MIME_TYPE = 'text/html';\n", "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", "var CLASS_NAME = 'output';\n", "\n", "/**\n", " * Render data to the DOM node\n", " */\n", "function 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", " */\n", "function 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", " */\n", "function 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", " */\n", "function 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", " */\n", "function handle_update_output(event, handle) {\n", " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", " handle_add_output(event, handle)\n", "}\n", "\n", "function 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", "\n", "if (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": "\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" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":NdOverlay [Variable]\n", " :Curve [index] (value)" ] }, "execution_count": 3, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1002" } }, "output_type": "execute_result" } ], "source": [ "import hvplot.pandas\n", "\n", "df.hvplot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ein solches interaktive Diagramm erleichtert das Erkunden der der Daten erheblich, ohne dass hierfür zusätzlicher Code geschrieben werden müsste." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Native `hvPlot`-API \n", "\n", "Für das obige Diagramm hat hvPlot die pandas-`.hvplot()`-Methode dynamisch hinzugefügt, sodass ihr dieselbe Syntax wie bei pandas-Plots verwenden könnt. Wenn ihr ein expliziteres Vorgehen bevorzugt, könnt ihr stattdessen direkt mit den hvPlot-Objekten arbeiten:" ] }, { "cell_type": "code", "execution_count": 4, "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.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", " var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n", " var reloading = false;\n", " var Bokeh = root.Bokeh;\n", " var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\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.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/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.1.1/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.1.1/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.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/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", " },\n", "function(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", " inline_js[i].call(root, root.Bokeh);\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", " Bokeh = root.Bokeh;\n", " bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n", " root._bokeh_is_initializing = true\n", " root._bokeh_onload_callbacks = []\n", " if (!reloading && (!bokeh_loaded || is_dev)) {\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": "(function(root) {\n function now() {\n return new Date();\n }\n\n var force = true;\n var py_version = '3.1.1'.replace('rc', '-rc.').replace('.dev', '-dev.');\n var is_dev = py_version.indexOf(\"+\") !== -1 || py_version.indexOf(\"-\") !== -1;\n var reloading = false;\n var Bokeh = root.Bokeh;\n var bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\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.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.1.1/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.1.1/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.1.1/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.1.1/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.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.1.1.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.1.1.min.js\", \"https://cdn.holoviz.org/panel/1.1.1/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 inline_js[i].call(root, root.Bokeh);\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 Bokeh = root.Bokeh;\n bokeh_loaded = Bokeh != null && (Bokeh.version === py_version || (Bokeh.versions !== undefined && Bokeh.versions.has(py_version)));\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n if (!reloading && (!bokeh_loaded || is_dev)) {\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));" }, "metadata": {}, "output_type": "display_data" }, { "data": { "application/javascript": [ "\n", "if ((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", "\n", "var JS_MIME_TYPE = 'application/javascript';\n", "var HTML_MIME_TYPE = 'text/html';\n", "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", "var CLASS_NAME = 'output';\n", "\n", "/**\n", " * Render data to the DOM node\n", " */\n", "function 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", " */\n", "function 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", " */\n", "function 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", " */\n", "function 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", " */\n", "function handle_update_output(event, handle) {\n", " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", " handle_add_output(event, handle)\n", "}\n", "\n", "function 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", "\n", "if (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": "\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" }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "" ] }, "metadata": {}, "output_type": "display_data" }, { "data": { "text/html": [ "\n", "
\n", "\n", "\n", "\n", " \n", " \n", "\n", "\n", "\n", "\n", "
\n" ] }, "metadata": {}, "output_type": "display_data" }, { "data": {}, "metadata": {}, "output_type": "display_data" }, { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", "" ], "text/plain": [ ":NdOverlay [Variable]\n", " :Curve [index] (value)" ] }, "execution_count": 4, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "p1449" } }, "output_type": "execute_result" } ], "source": [ "import holoviews as hv\n", "\n", "from hvplot import hvPlot\n", "\n", "\n", "hv.extension(\"bokeh\")\n", "\n", "plot = hvPlot(df)\n", "plot(y=[\"A\", \"B\", \"C\", \"D\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Hilfe\n", "\n", "Wenn ihr in IPython oder Jupyter-Notebooks arbeitet, vervollständigen die `hvplot`-Methoden automatisch gültige Schlüsselwörter. Wenn ihr beispielsweise nach dem Deklarieren des Plottyps die Tabulatortaste drücken, werden alle gültigen Schlüsselwörter und die Dokumentzeichenfolge angezeigt:\n", "\n", "``` Python\n", "df.hvplot.line(TAB\n", "```\n", "\n", "Außerhalb einer interaktiven Umgebung werden mit `hvplot.help` alle Informationen für einen Diagrammtyp angezeigt, z.B.:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "hvplot.help(\"line\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
\n", "\n", "**Siehe auch:**\n", "\n", "Weitere Informationen zu den verfügbaren Optionen erhaltet ihr in [Customization](https://hvplot.holoviz.org/user_guide/Customization.html).\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Plotting\n", "\n", "In den folgenden Beispielen wird neben der pandas- auch die dask-hvPlot-API verwendet:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "import hvplot.dask" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Das `hvplot.sample_data`-Modul erstellt diese Datensätze als Intake-Datenkataloge, die wir mit pandas laden können:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
YearPopulationViolent crime totalMurder and nonnegligent ManslaughterLegacy rape /1Revised rape /2RobberyAggravated assaultProperty crime totalBurglary...Violent Crime rateMurder and nonnegligent manslaughter rateLegacy rape rate /1Revised rape rate /2Robbery rateAggravated assault rateProperty crime rateBurglary rateLarceny-theft rateMotor vehicle theft rate
01960179323175288460911017190NaN1078401543203095700912100...160.95.19.6NaN60.186.11726.3508.61034.7183.0
11961182992000289390874017220NaN1066701567603198600949600...158.14.89.4NaN58.385.71747.9518.91045.4183.6
21962185771000301510853017550NaN1108601645703450700994300...162.34.69.4NaN59.788.61857.5535.21124.8197.4
31963188483000316970864017650NaN11647017421037925001086400...168.24.69.4NaN61.892.42012.1576.41219.1216.6
41964191141000364220936021420NaN13039020305042004001213200...190.64.911.2NaN68.2106.22197.5634.71315.5247.4
\n", "

5 rows × 22 columns

\n", "
" ], "text/plain": [ " Year Population Violent crime total \\\n", "0 1960 179323175 288460 \n", "1 1961 182992000 289390 \n", "2 1962 185771000 301510 \n", "3 1963 188483000 316970 \n", "4 1964 191141000 364220 \n", "\n", " Murder and nonnegligent Manslaughter Legacy rape /1 Revised rape /2 \\\n", "0 9110 17190 NaN \n", "1 8740 17220 NaN \n", "2 8530 17550 NaN \n", "3 8640 17650 NaN \n", "4 9360 21420 NaN \n", "\n", " Robbery Aggravated assault Property crime total Burglary ... \\\n", "0 107840 154320 3095700 912100 ... \n", "1 106670 156760 3198600 949600 ... \n", "2 110860 164570 3450700 994300 ... \n", "3 116470 174210 3792500 1086400 ... \n", "4 130390 203050 4200400 1213200 ... \n", "\n", " Violent Crime rate Murder and nonnegligent manslaughter rate \\\n", "0 160.9 5.1 \n", "1 158.1 4.8 \n", "2 162.3 4.6 \n", "3 168.2 4.6 \n", "4 190.6 4.9 \n", "\n", " Legacy rape rate /1 Revised rape rate /2 Robbery rate \\\n", "0 9.6 NaN 60.1 \n", "1 9.4 NaN 58.3 \n", "2 9.4 NaN 59.7 \n", "3 9.4 NaN 61.8 \n", "4 11.2 NaN 68.2 \n", "\n", " Aggravated assault rate Property crime rate Burglary rate \\\n", "0 86.1 1726.3 508.6 \n", "1 85.7 1747.9 518.9 \n", "2 88.6 1857.5 535.2 \n", "3 92.4 2012.1 576.4 \n", "4 106.2 2197.5 634.7 \n", "\n", " Larceny-theft rate Motor vehicle theft rate \n", "0 1034.7 183.0 \n", "1 1045.4 183.6 \n", "2 1124.8 197.4 \n", "3 1219.1 216.6 \n", "4 1315.5 247.4 \n", "\n", "[5 rows x 22 columns]" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from hvplot.sample_data import airline_flights, us_crime\n", "\n", "\n", "crime = us_crime.read()\n", "print(type(crime))\n", "crime.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternativ können wir `dask.DataFrame` verwenden:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] }, { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
yearmonthdaydayofweekdep_timecrs_dep_timearr_timecrs_arr_timecarrierflight_num...taxi_intaxi_outcancelledcancellation_codedivertedcarrier_delayweather_delaynas_delaysecurity_delaylate_aircraft_delay
02008.011.015.06.01411.01420.01535.01546.0b'OO'4391.0...5.011.00.0None0.0NaNNaNNaNNaNNaN
12008.011.028.05.01222.01230.01345.01356.0b'OO'4391.0...5.015.00.0None0.0NaNNaNNaNNaNNaN
22008.011.022.06.01414.01420.01540.01546.0b'OO'4391.0...5.010.00.0None0.0NaNNaNNaNNaNNaN
32008.011.015.06.01304.01305.01507.01519.0b'OO'4392.0...10.09.00.0None0.0NaNNaNNaNNaNNaN
42008.011.022.06.01323.01305.01536.01519.0b'OO'4392.0...5.021.00.0None0.00.00.00.00.017.0
\n", "

5 rows × 29 columns

\n", "
" ], "text/plain": [ " year month day dayofweek dep_time crs_dep_time arr_time \\\n", "0 2008.0 11.0 15.0 6.0 1411.0 1420.0 1535.0 \n", "1 2008.0 11.0 28.0 5.0 1222.0 1230.0 1345.0 \n", "2 2008.0 11.0 22.0 6.0 1414.0 1420.0 1540.0 \n", "3 2008.0 11.0 15.0 6.0 1304.0 1305.0 1507.0 \n", "4 2008.0 11.0 22.0 6.0 1323.0 1305.0 1536.0 \n", "\n", " crs_arr_time carrier flight_num ... taxi_in taxi_out cancelled \\\n", "0 1546.0 b'OO' 4391.0 ... 5.0 11.0 0.0 \n", "1 1356.0 b'OO' 4391.0 ... 5.0 15.0 0.0 \n", "2 1546.0 b'OO' 4391.0 ... 5.0 10.0 0.0 \n", "3 1519.0 b'OO' 4392.0 ... 10.0 9.0 0.0 \n", "4 1519.0 b'OO' 4392.0 ... 5.0 21.0 0.0 \n", "\n", " cancellation_code diverted carrier_delay weather_delay nas_delay \\\n", "0 None 0.0 NaN NaN NaN \n", "1 None 0.0 NaN NaN NaN \n", "2 None 0.0 NaN NaN NaN \n", "3 None 0.0 NaN NaN NaN \n", "4 None 0.0 0.0 0.0 0.0 \n", "\n", " security_delay late_aircraft_delay \n", "0 NaN NaN \n", "1 NaN NaN \n", "2 NaN NaN \n", "3 NaN NaN \n", "4 0.0 17.0 \n", "\n", "[5 rows x 29 columns]" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "flights = airline_flights.to_dask().persist()\n", "print(type(flights))\n", "flights.head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Die Plot-API\n", "\n", "Die Schnittstellen\n", "\n", "* `dask.dataframe.DataFrame.hvplot`\n", "* `pandas.DataFrame.hvplot`\n", "* `intake.DataSource.plot`\n", "\n", "und ihre `Series`-Äquivalente bieten eine leistungsfähige High-Level-API um auch komplexe Plots erzeugen zu können. Dabei kann die `.hvplot`-API entweder direkt oder als Namespace verwendet werden, um bestimmte Plottypen zu generieren." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die expliziteste Methode zur Verwendung der Plot-API besteht darin, die Namen der Spalten anzugeben, die auf der x- bzw. y-Achse geplottet werden sollen:" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Curve [Year] (Violent Crime rate)" ] }, "execution_count": 9, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "2108" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.line(x=\"Year\", y=\"Violent Crime rate\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Zusätzlich kann auch noch der Diagrammtyp mit `kind` angegeben werden:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Scatter [Year] (Violent Crime rate)" ] }, "execution_count": 10, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "2218" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot(x=\"Year\", y=\"Violent Crime rate\", kind=\"scatter\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Mit der `by`-Variable könnt ihr die Daten in einer oder mehreren zusätzlichen Spalten gruppieren. Als Beispiel wird im Folgenden die Abfahrtsverzögerung (`\"depdelay\"`) als Funktion der `\"distance\"` dargestellt und die Daten nach `\"carrier\"` gruppiert:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":NdOverlay [carrier]\n", " :Scatter [distance] (depdelay)" ] }, "execution_count": 11, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "2329" } }, "output_type": "execute_result" } ], "source": [ "flight_subset = flights[flights.carrier.isin([b\"OH\", b\"F9\"])]\n", "flight_subset.hvplot(\n", " x=\"distance\",\n", " y=\"depdelay\",\n", " by=\"carrier\",\n", " kind=\"scatter\",\n", " alpha=0.2,\n", " persist=True,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Im obigen Beispiel haben wir die x- und y-Achsen explizit angegeben.\n", "\n", "Andernfalls würde für die x-Achse die pandas-Indexspalte verwendet werden und für die y-Achse alle Nicht-Index-Spalten mit der Standardbezeichnung `value`. Wollt ihr nur die y-Achsenbezeichnung explizit angeben, so steht euch die `value_label`-Option zur Verfügung." ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "scrolled": true }, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":NdOverlay [Variable]\n", " :Curve [Year] (Rate (per 100k people))" ] }, "execution_count": 12, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "2552" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot(\n", " x=\"Year\",\n", " y=[\"Violent Crime rate\", \"Robbery rate\", \"Burglary rate\"],\n", " value_label=\"Rate (per 100k people)\",\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Der `hvplot`-Namespace \n", "\n", "Statt des `kind`-Argument können wir auch den `hvplot`-Namespace für den Plotaufruf zu verwenden. Die unterstützten Plottypen lassen sich leicht ermitteln mit der Tab-Vervollständigung, also\n", "``` Python\n", "crime.hvplot.TAB\n", "```\n", "\n", "Verfügbare Diagrammtypen sind:\n", "\n", "* [area()](#area()) zeichnet ein Flächendiagramm ähnlich einem Liniendiagramm, außer dass der Bereich unter der Kurve gefüllt und optional gestapelt wird\n", "* [bar()](#bar()) zeichnet ein Flächendiagramm ähnlich einem Liniendiagramm, außer dass der Bereich unter der Kurve gefüllt und optional gestapelt wird\n", "* [bivariate()](#bivariate()) zeichnet ein Flächendiagramm ähnlich einem Liniendiagramm, außer dass der Bereich unter der Kurve gefüllt und optional gestapelt wird\n", "* [box()](#box()) zeichnet ein [Box-Whisker-Diagramm](https://de.wikipedia.org/wiki/Box-Plot), in dem die Verteilung einer oder mehrerer Variablen verglichen wird\n", "* [heatmap()](#heatmap()) zeichnet Hex-Bins\n", "* [hexbin()](#hexbin()) zeichnet die Verteilung eines oder mehrerer Histogramme als Satz von Containern\n", "* `histogram()` zeichnet die Kernel-Dichteschätzung einer oder mehrerer Variablen\n", "* [kde()](#kde(),-density()) zeichnet die Kernel-Dichteschätzung einer oder mehrerer Variablen\n", "* `line()` zeichnet ein Liniendiagramm (z.B. für eine Zeitreihe)\n", "* [step()](#step()) zeichnet ein Schrittdiagramm, das einem Liniendiagramm ähnelt\n", "* [scatter()](#scatter()) zeichnet ein Streudiagramm, in dem zwei Variablen verglichen werden \n", "* [table()](#table()) erzeugt eine SlickGrid-Datentabelle\n", "* `violin()` zeichnet ein Violinen-Diagramm, in dem die Verteilung einer oder mehrerer Variablen mithilfe der Kernel-Dichteschätzung verglichen wird" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `area()`\n", "\n", "Wie die meisten anderen Diagrammtypen unterstützt das `area`-Diagramm die drei oben beschriebenen Möglichkeiten zum Definieren eines Diagramms. Ein Flächendiagramm ist am nützlichsten, wenn mehrere Variablen in einem gestapelten Diagramm dargestellt werden. Dies kann durch Angabe für die `x`-, `y`- und `by`-Spalten erreicht werden oder mit `columns` und `index`/`use_index` als Optionen für die `x`-Achse." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":NdOverlay [Variable]\n", " :Area [Year] (value,Baseline)" ] }, "execution_count": 13, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "2823" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.area(x=\"Year\", y=[\"Robbery\", \"Aggravated assault\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir können auch explizit `stacked` auf `False` setzen und einen `alpha`-Wert definieren und um die Werte direkt vergleichen zu können:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":NdOverlay [Variable]\n", " :Area [Year] (value)" ] }, "execution_count": 14, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "3045" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.area(\n", " x=\"Year\", y=[\"Aggravated assault\", \"Robbery\"], stacked=False, alpha=0.4\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Eine andere Verwendung für ein Flächendiagramm besteht darin, die Streuung eines Werts zu visualisieren. Wenn wir beispielsweise den Flugdatensatz verwenden, möchten wir möglicherweise die Streuung der mittleren Verspätungswerte zwischen den Fluggesellschaften sehen. Zu diesem Zweck berechnen wir die mittlere Verzögerung nach Tag und Carrier und dann die minimale/maximale mittlere Verzögerung für alle Carrier. Da die Ausgabe von `hvplot` nur ein reguläres Holoviews-Objekt ist, können wir den Overlay-Operator (`*`) verwenden, um die Diagramme übereinander zu platzieren." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Overlay\n", " .Area.I :Area [day] (amin,amax)\n", " .Curve.Carrier_delay :Curve [day] (carrier_delay)" ] }, "execution_count": 15, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "3267" } }, "output_type": "execute_result" } ], "source": [ "delay_min_max = (\n", " flights.groupby([\"day\", \"carrier\"])[\"carrier_delay\"]\n", " .mean()\n", " .groupby(\"day\")\n", " .agg([np.min, np.max])\n", ")\n", "delay_mean = flights.groupby(\"day\")[\"carrier_delay\"].mean()\n", "\n", "delay_min_max.hvplot.area(\n", " x=\"day\", y=\"amin\", y2=\"amax\", alpha=0.2\n", ") * delay_mean.hvplot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `bar()`\n", "\n", "Im einfachsten Fall können wir `.hvplot.bar` verwenden. Um die Beschriftung auf der x-Achse um 90° zu drehen, geben wir noch `rot=90` an." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Bars [Year] (Violent Crime rate)" ] }, "execution_count": 16, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "3482" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.bar(x=\"Year\", y=\"Violent Crime rate\", rot=90)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wenn wir stattdessen mehrere Spalten vergleichen möchten, können wir eine Liste von Spalten festlegen. Mit der `stacked`-Option können wir dann die Spaltenwerte einfacher vergleichen:" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Bars [Year,Variable] (value)" ] }, "execution_count": 17, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "3591" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.bar(\n", " x=\"Year\",\n", " y=[\"Violent crime total\", \"Property crime total\"],\n", " stacked=True,\n", " rot=90,\n", " width=800,\n", " legend=\"top_left\",\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `scatter()`\n", "\n", "Das Streudiagramm unterstützt viele der Funktionen der obigen Diagrammtypen, kann jedoch mit der `c`-Option auch eingefärbt werden." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Scatter [Violent Crime rate] (Burglary rate,Year)" ] }, "execution_count": 18, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "3709" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.scatter(x=\"Violent Crime rate\", y=\"Burglary rate\", c=\"Year\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Um Farbe zur Darstellung einer Dimension zu verwenden, kann die `cmap`-Option genutzt werden werden, um die zu verwendende Farbkarte anzugeben. Zusätzlich kann die Farbleiste deaktiviert werden mit `colorbar=False`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `step()`\n", "\n", "Ein Schrittdiagramm ist einem Liniendiagramm sehr ähnlich, aber anstatt linear zwischen Abtastwerten zu interpolieren, visualisiert das Schrittdiagramm diskrete Schritte. Die Position der Schritte kann mit dem `where`-Schlüsselwort un den Werten `\"pre\"`, `\"mid\"` (Standard) und `\"post\"` gesteuert werden." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":NdOverlay [Variable]\n", " :Curve [Year] (value)" ] }, "execution_count": 19, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "3834" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.step(x=\"Year\", y=[\"Robbery\", \"Aggravated assault\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `hexbin()`\n", "\n", "Mit der `hexbin`-Methode können Sie hexagonale Bin-Diagramme erstellen. Sie können eine nützliche Alternative zu Streudiagrammen sein, wenn die Daten zu dicht sind, um jeden Punkt einzeln zu zeichnen. Da unsere Flugdaten nicht gleichmäßig auf einer linearen Skala verteilt sind, verwenden wir die `logz`-Option für eine logarithmische Skala." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":HexTiles [airtime,arrdelay]" ] }, "execution_count": 20, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "4055" } }, "output_type": "execute_result" } ], "source": [ "flights.hvplot.hexbin(\n", " x=\"airtime\", y=\"arrdelay\", width=600, height=500, logz=True\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `bivariate()`\n", "\n", "Mit der `bivariate`-Methode könnt ihr ein 2D-Dichtediagramm erstellen. Bivariate Diagramme sind neben Hexbin-Diagrammen eine weitere Alternative zu Streudiagrammen, wenn die Daten zu dicht sind, um jeden Punkt einzeln zu zeichnen." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Bivariate [Violent Crime rate,Burglary rate] (Density)" ] }, "execution_count": 21, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "4240" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.bivariate(\n", " x=\"Violent Crime rate\", y=\"Burglary rate\", width=600, height=500\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `heatmap()`\n", "\n", "`heatmap` kann die Beziehung zwischen drei Variablen anzeigen und neben den Variablen `'x'` und `'y'` zusätzlich `'C'` anzeigen. Zusätzlich werden mit der `reduce_function` die Werte für jeden Container aus den Stichproben berechnet." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":HeatMap [day,carrier] (depdelay)" ] }, "execution_count": 22, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "4369" } }, "output_type": "execute_result" } ], "source": [ "flights.compute().hvplot.heatmap(\n", " x=\"day\", y=\"carrier\", C=\"depdelay\", reduce_function=np.mean, colorbar=True\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `table()`\n", "\n", "Im Gegensatz zu allen anderen Plottypen kann für eine Tabelle nur angegeben werden, ob alle Spalten oder mit `columns` nur eine Teilmenge angezeigt werden soll." ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Table [Year,Population,Violent Crime rate]" ] }, "execution_count": 23, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "4502" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.table(\n", " columns=[\"Year\", \"Population\", \"Violent Crime rate\"], width=400\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `hist()`\n", "\n", "Das Zeichnen von Verteilungen unterscheidet sich geringfügig von anderen Plots, da sie im einfachen Fall nur eine Variable darstellen. Daher muss bei diesem Plottyp kein `index` oder `x`-Wert angegeben werden, sondern\n", "\n", "* deklariert eine einzelne `y`-Variable, z.B. `source.plot.hist(variable)` oder\n", "* deklariert eine `y`-Variable und eine `by`-Variable, z.B. `source.plot.hist(variable, by=\"Group\")` oder\n", "* deklariert Spalten oder zeichnet alle Spalten, z.B. `source.plot.hist()` oder `source.plot.hist(columns=[\"A\", \"B\", \"C\"])`" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Histogram [Violent Crime rate] (Violent Crime rate_count)" ] }, "execution_count": 24, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "4521" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.hist(y=\"Violent Crime rate\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternativ önnen wir auch die Verteilung mehrerer Spalten darstellen:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":NdOverlay [Element]\n", " :Histogram [Burglary rate] (Burglary rate_count)" ] }, "execution_count": 25, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "4633" } }, "output_type": "execute_result" } ], "source": [ "columns = [\"Violent Crime rate\", \"Property crime rate\", \"Burglary rate\"]\n", "crime.hvplot.hist(y=columns, bins=50, alpha=0.5, legend=\"top\", height=400)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir können die Daten auch nach anderen Variablen gruppieren und die Carrier in eigene `subplots` aufteilen:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":NdLayout [carrier]\n", " :Histogram [depdelay] (depdelay_count)" ] }, "execution_count": 26, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "5066" } }, "output_type": "execute_result" } ], "source": [ "flight_subset = flights[flights.carrier.isin([b\"AA\", b\"US\", b\"OH\"])]\n", "flight_subset.hvplot.hist(\n", " \"depdelay\",\n", " by=\"carrier\",\n", " bins=20,\n", " bin_range=(-20, 100),\n", " width=300,\n", " subplots=True,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `kde()`, `density()`\n", "\n", "Ihr könnt Dichtediagramme auch mit `hvplot.kde()` oder `hvplot.density()` erstellen:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Distribution [Violent Crime rate] (Density)" ] }, "execution_count": 27, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "5430" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.kde(y=\"Violent Crime rate\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Der Vergleich der Verteilung mehrerer Spalten ist ebenfalls möglich:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":NdOverlay [Variable]\n", " :Distribution [Rate] (Density)" ] }, "execution_count": 28, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "5542" } }, "output_type": "execute_result" } ], "source": [ "columns = [\"Violent Crime rate\", \"Property crime rate\", \"Burglary rate\"]\n", "crime.hvplot.kde(y=columns, alpha=0.5, value_label=\"Rate\", legend=\"top_right\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`hvplot.kde` unterstützt auch das `by`-Schlüsselwort:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":NdLayout [carrier]\n", " :Distribution [depdelay] (Density)" ] }, "execution_count": 29, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "5973" } }, "output_type": "execute_result" } ], "source": [ "flight_subset = flights[flights.carrier.isin([b\"AA\", b\"US\", b\"OH\"])]\n", "flight_subset.hvplot.kde(\n", " \"depdelay\", by=\"carrier\", xlim=(-20, 70), width=300, subplots=True\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `box()`\n", "\n", "Genau wie die anderen verteilungsbasierten Diagrammtypen unterstützt das [Box-Whisker-Diagramm](https://de.wikipedia.org/wiki/Box-Plot) das Zeichnen einer einzelnen Spalte:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "scrolled": true }, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":BoxWhisker (Violent Crime rate)" ] }, "execution_count": 30, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "6336" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot.box(y=\"Violent Crime rate\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Es unterstützt auch mehrere Spalten und die gleichen Optionen wie berits oben genannt:`legend`, `invert` und `value_label`:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "scrolled": true }, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":BoxWhisker [Crime] (Rate (per 100k))" ] }, "execution_count": 31, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "6573" } }, "output_type": "execute_result" } ], "source": [ "columns = [\n", " \"Burglary rate\",\n", " \"Larceny-theft rate\",\n", " \"Motor vehicle theft rate\",\n", " \"Property crime rate\",\n", " \"Violent Crime rate\",\n", "]\n", "crime.hvplot.box(\n", " y=columns,\n", " group_label=\"Crime\",\n", " legend=False,\n", " value_label=\"Rate (per 100k)\",\n", " invert=True,\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Auch die Verwendung des `by`-Schlüsselworts zum Aufteilen der Daten in mehrere Teilmengen wird unterstützt:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":BoxWhisker [carrier] (depdelay)" ] }, "execution_count": 32, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "6810" } }, "output_type": "execute_result" } ], "source": [ "flight_subset = flights[flights.carrier.isin([b\"AA\", b\"US\", b\"OH\"])]\n", "flight_subset.hvplot.box(\"depdelay\", by=\"carrier\", ylim=(-10, 70))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Zusammengesetzte Diagramme\n", "\n", "Eine der Hauptstärken von HoloViews ist die einfache Erstellung verschiedener Diagramme. Einzelne Diagramme können mit den Operatoren `*` und `+` überlagert bzw. zusammengesetzt werden.\n", "\n", "
\n", "\n", "**Siehe auch:**\n", "\n", "* [Composing Elements](https://holoviews.org/user_guide/Composing_Elements.html)\n", "
" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Overlay\n", " .Curve.I :Curve [Year] (Violent Crime rate)\n", " .Scatter.I :Scatter [Year] (Violent Crime rate)" ] }, "execution_count": 33, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "7067" } }, "output_type": "execute_result" } ], "source": [ "crime.hvplot(x=\"Year\", y=\"Violent Crime rate\") * crime.hvplot.scatter(\n", " x=\"Year\", y=\"Violent Crime rate\", c=\"k\"\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Wir können auch verschiedene Diagramme und Tabellen zusammen erstellen:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":Layout\n", " .Bars.I :Bars [Year] (Violent Crime rate)\n", " .Table.I :Table [Year,Population,Violent Crime rate]" ] }, "execution_count": 34, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "7346" } }, "output_type": "execute_result" } ], "source": [ "(\n", " crime.hvplot.bar(x=\"Year\", y=\"Violent Crime rate\", rot=90, width=550)\n", " + crime.hvplot.table(\n", " [\"Year\", \"Population\", \"Violent Crime rate\"], width=420\n", " )\n", ")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Big Data\n", "\n", "In den vorherigen Beispielen fassten wir den relativ große Airline-Datensatz zusammen indem wir Teilmengen für die Darstellung bildeten. Stattdessen können wir die Daten jedoch auch mithilfe von [Datashader](../../datashader.ipynb) aggregieren, wobei der gesamte verfügbare Rohdatensatz gerendert wird (sofern die Auflösung des Bildschirms dies zulässt)." ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", " \n", "\n", "\n", "\n", "\n", "\n", "
\n", "\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap []\n", " :RGB [distance,airtime] (R,G,B,A)" ] }, "execution_count": 35, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "7497" } }, "output_type": "execute_result" } ], "source": [ "flights.hvplot.scatter(x=\"distance\", y=\"airtime\", datashade=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### `groupby`\n", "\n", "Dank der Fähigkeit von HoloViews, einen Parameterraum mit einer Reihe von Widgets zu erkunden, können wir eine Gruppe entlang einer bestimmten Spalte oder Dimension anwenden, z.B. die Verteilung der Abflugverzögerungen nach Carriern und Tag gruppiert anzeigen, wobei Benutzer\\*innen auswählen können, welcher Tag angezeigt werden soll:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "scrolled": true }, "outputs": [ { "data": { "application/vnd.holoviews_exec.v0+json": "", "text/html": [ "
\n", "
\n", "
\n", " \n", "
\n", "\n", "\n", "\n", "\n", "\n", "
\n", "
\n", " \n", "
\n", "
\n", "
\n", "
\n", " \n", " \n", "
\n", " \n", "
\n", "
\n", " \n", "
\n", "
\n", "
\n", "
\n", " \n", " \n", "
\n", "
\n", "
\n", "" ], "text/plain": [ ":DynamicMap [dayofweek]\n", " :Violin [carrier] (depdelay)" ] }, "execution_count": 36, "metadata": { "application/vnd.holoviews_exec.v0+json": { "id": "7607" } }, "output_type": "execute_result" } ], "source": [ "flights.hvplot.violin(\n", " y=\"depdelay\", by=\"carrier\", groupby=\"dayofweek\", ylim=(-20, 60), height=500\n", ")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.11 Kernel", "language": "python", "name": "python311" }, "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.4" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "autocomplete": true, "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 1, "hotkeys": { "equation": "Ctrl-E", "itemize": "Ctrl-I" }, "labels_anchors": false, "latex_user_defs": false, "report_style_numbering": false, "user_envs_cfg": false }, "widgets": { "application/vnd.jupyter.widget-state+json": { "state": {}, "version_major": 2, "version_minor": 0 } } }, "nbformat": 4, "nbformat_minor": 4 }