Skip to content

Instantly share code, notes, and snippets.

@Sinusoidal36
Created December 7, 2020 06:32
Show Gist options
  • Save Sinusoidal36/5094341c5dd4a2ddddedfacd191ec55a to your computer and use it in GitHub Desktop.
Save Sinusoidal36/5094341c5dd4a2ddddedfacd191ec55a to your computer and use it in GitHub Desktop.
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import plotly.express as px\n",
"import pandas as pd\n",
"import timeit\n",
"from IPython.display import Image\n",
"\n",
"DATASKETCH_PKG_PATH = '/home/sinusoidal/projects/datasketch/'"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [],
"source": [
"old_setup = '''\n",
"from datasketch import minhash\n",
"from xxhash import xxh3_64_intdigest as hashfunc\n",
"import random\n",
"\n",
"'''\n",
"\n",
"new_setup = f'''\n",
"import importlib.util\n",
"import random\n",
"from xxhash import xxh3_64_intdigest as hashfunc\n",
"DATASKETCH_PKG_PATH = \"{DATASKETCH_PKG_PATH}\"\n",
"\n",
"spec = importlib.util.spec_from_file_location(\"minhash\", DATASKETCH_PKG_PATH + \"datasketch/minhash.py\")\n",
"minhash = importlib.util.module_from_spec(spec)\n",
"spec.loader.exec_module(minhash)\n",
"\n",
"spec = importlib.util.spec_from_file_location(\"bulk\", DATASKETCH_PKG_PATH + \"datasketch/bulk.py\")\n",
"bulk = importlib.util.module_from_spec(spec)\n",
"spec.loader.exec_module(bulk)\n",
"\n",
"'''"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Updates\n",
"\n",
"Here it is shown that the new update implementation is substantially faster when providing a list of tokens instead of performing updates iteratively. \n",
"\n",
"Comparative performance scales with the number of updates."
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [],
"source": [
"iterations = 100\n",
"repeats = 10\n",
"\n",
"update_setup = '''\n",
"byte_data = [str(random.randint(0, 1000000)).encode(\"utf8\") for n in range({})]\n",
"'''\n",
"iterative_statement = '''\n",
"m = minhash.MinHash(hashfunc=hashfunc)\n",
"for b in byte_data:\n",
" m.update(b)\n",
"'''\n",
"list_statement = '''\n",
"m = minhash.MinHash(hashfunc=hashfunc)\n",
"m.update_batch(byte_data)\n",
"'''\n",
"\n",
"data = []\n",
"for token_count in [10, 100, 1000, 10000]:\n",
" _update_setup = update_setup.format(token_count)\n",
" old = timeit.repeat(iterative_statement, setup=old_setup + _update_setup, number=iterations, repeat=repeats)\n",
" new = timeit.repeat(list_statement, setup=new_setup + _update_setup, number=iterations, repeat=repeats)\n",
" data += [{'version':'old', 'tokens':token_count, 't':t} for t in old]\n",
" data += [{'version':'new', 'tokens':token_count, 't':t} for t in new]"
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pd.DataFrame(data)\n",
"df['millis'] = (df['t'] * 1000) / iterations\n",
"reference = df.groupby(['version','tokens'])['millis'].median().old\n",
"df = df.loc[df['version'] == 'new'].groupby(['version','tokens'])['millis'].median() / reference\n",
"df = df.reset_index()\n",
"df['ratio'] = 1 / df['millis']\n",
"\n",
"fig = px.bar(\n",
" df,\n",
" y='ratio',\n",
" x='tokens'\n",
")\n",
"fig.update_layout(barmode='group')\n",
"fig.update_xaxes(type='category')\n",
"Image(fig.to_image(format=\"png\"))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Bulk\n",
"\n",
"Here it is shown that we can avoid a significant amount of overhead when computing minhashes using the bulk method. \n",
"\n",
"This yields anywhere from 5-25X performance gains when combined with the new update method."
]
},
{
"cell_type": "code",
"execution_count": 19,
"metadata": {},
"outputs": [],
"source": [
"iterations = 3\n",
"repeats = 2\n",
"\n",
"bulk_setup = '''\n",
"minhash_data = [[str(random.randint(0, 1000000)).encode(\"utf8\") for n in range({})] for m in range({})]\n",
"'''\n",
"old_statement = '''\n",
"for byte_data in minhash_data:\n",
" m = minhash.MinHash(hashfunc=hashfunc)\n",
" for b in byte_data:\n",
" m.update(b)\n",
"'''\n",
"new_statement = '''\n",
"m = minhash.MinHash(hashfunc=hashfunc)\n",
"bulk.compute_minhashes(minhash_data, m)\n",
"'''\n",
"\n",
"data = []\n",
"for minhash_count in [10, 100, 1000]:\n",
" for token_count in [10, 50, 100, 1000]:\n",
" _bulk_setup = bulk_setup.format(token_count, minhash_count)\n",
" old = timeit.repeat(old_statement, setup=old_setup + _bulk_setup, number=iterations, repeat=repeats)\n",
" new = timeit.repeat(new_statement, setup=new_setup + _bulk_setup, number=iterations, repeat=repeats)\n",
" data += [{'version':'old', 'tokens':token_count, 'minhashes':minhash_count, 't':t} for t in old]\n",
" data += [{'version':'new', 'tokens':token_count, 'minhashes':minhash_count, 't':t} for t in new]"
]
},
{
"cell_type": "code",
"execution_count": 20,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAArwAAAH0CAYAAADfWf7fAAAgAElEQVR4Xu2dCZzV8/7/XzPTXopsKSEipCQqayJEC9VVVEI7UqSV6saoVCpKqVRIsnfRzZJr3yLJki39XGRJ2oQbLTPzf5wT81dmmvnM53vm8/18v8/zeHg8XOezPt+vOfc5n/mcc9JycnJyxAMCEIAABCAAAQhAAAIRJZCG8Ea0smwLAhCAAAQgAAEIQCBJAOElCBCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4SUDEIAABCAAAQhAAAKRJoDwRrq8bA4CEIAABCAAAQhAAOElAxCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4SUDEIAABCAAAQhAAAKRJoDwRrq8bA4CEIAABCAAAQhAAOElAxCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4SUDEIAABCAAAQhAAAKRJoDwRrq8bA4CEIAABCAAAQhAAOElAxCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4SUDEIAABCAAAQhAAAKRJoDwRrq8bA4CEIAABCAAAQhAAOElAxCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4SUDEIAABCAAAQhAAAKRJoDwRrq8bA4CEIAABCAAAQhAAOElAxCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4SUDEIAABCAAAQhAAAKRJoDwRrq8bA4CEIAABCAAAQhAAOElAxCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4SUDEIAABCAAAQhAAAKRJoDwRrq8bA4CEIAABCAAAQhAAOElAxCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4SUDEIAABCAAAQhAAAKRJoDwRrq8bA4CEIAABCAAAQhAAOElAxCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4SUDEIAABCAAAQhAAAKRJoDwRrq8bA4CEIAABCAAAQhAAOElAxCAAAQgAAEIQAACkSaA8Ea6vGwOAhCAAAQgAAEIQADhJQMQgAAEIAABCEAAApEmgPBGurxsDgIQgAAEIAABCEAA4bXMwPfrf7Mcge4QgAAEIAABCMSBQNW9y8Zhm6HcI8L7l7JMu+9JPfTEi9q2bbtObnCMMgd2UbmyZXTxlZn6bOXXUlpasnXFCuX06uOTk/+O8IYy1ywKAhCAAAQgEDoCCK+7kiC8f7B/7pWlmjx7vu6eOFgVypdRn2GTdXzdWrrqsgvUovMQTcrso5o1qv2tUgivu/AyMwQgAAEIQMAnAgivu2ohvH+w/2jFl8mT3eOOOTz5X+Y8ukiffP6Vxg7tpdPbXqOHZ4xQlX0rI7zussrMEIAABCAAAa8JILzuyofw5sP+isET1fS0+mrXsomOO6eHGjeqq2XLP1flvSrqup7tdfpJxyZ7/rDhd3fVY2YIQCCcBNJypJwdV6B4QAACEPiTQJXKZYDhiADCmwf4O+99Qu9++Llmjh+YfHb4uNk6q/HxOrVhXb2+5EMNunm6Fsy5RQfsV1nZOTmOSse0EIBAWAls356jEiUQ3rDWh3VBwBWB9D/eC+Rq/jjPi/D+pfo5OTm65Y55+vrbNbrtpqtVrmzpPLPRtd9YtW3eWC3PPok3rcX5p4e9QwACEIAABAwIcKXBAFbATRHevwAdN/VBrVm3UWOG9lLJEhnJZzb/tkWf//cb1atdM7flpX1Hq1Pbs9WsSQOEN+BAMhwEIAABCEAgqgSKIryrvlujdRs2qX6dI3aLpc/QSTrn9AZqdc7JUcVntS+E9w9877z/mUZNul+PzbpJJTJ2yG7i8fOvm9W0Xb/kie+pDevo9SXLNTBzmhbOHaO996qI8FrFj84QgAAEIACB+BAoivAm3kS/des29ejUEuG1iArC+we860fP1MLn31TGX2S35iHV9NjMm/Ta28t167SHtGbtBh14wL4a1LuDGh13VLInH0tmkT66QgACEIAABGJEwFR431r2ia4bMVUlSmSozXmn6ZruF+qOu/+lRS8vSVKrc+ShGt7vUlUoX1Z/PeFNeMuoSXM1b+owlSldSjfffp8++PiL5F+vO7U9SxddcGay/4ktr9J1PdvpuVeX6tvv16pt89PU85JW+u6HdRoy6i6t2/CTsrKy1a5VkwKFO+xlRHgtK4TwWgKkOwQgAAEIQCAmBEyFN4Fl5O1ztf++eyWF8+kX3tbsB5/S3DuGqmyZUho8cob237ey+l/RPld4jzmyhnoMHK/pY65Lfn/AmCkPaOOmXzTmhp7a9PP/1K7XjbpjZF8dWfMgnXx+b7VvdYau7XGh1qzdqGYdBmjxwmmaMP1h7VO5kq649Hz98utmDR93t24e1FV7VCjnbaUQXsvSIbyWAOkOAQhAAAIQiAkBW+EdPGqGjjzsIHW5+LwkscQ1y9vuelTzZ2UmhfekE47RQ0++qCFXd9DJJxyTbHPOxQM0/p9Xqu7RhyX/d+Iv1uXLltFVl7dOCu/sCYN01OEHJ587qeVVenTmTXrq+bf05tKPNOCKi1S7Vg2lp/v/qTMIr+UPGcJrCZDuEIAABCAAgZgQsBXeHgPGq3nTRsnrDYnH8s++VN9hk/TSY7cnhfedD1Yo8YlT86YMy/122BPO7Zk8mf3zymbiS7bOPaOhru/TKSm8D037pw6qtn9yvD//d9Uq++ieh55Jiu+Gn35Wt44tdFm7Zl5XCeG1LB/CawmQ7hCAAAQgAIGYELAV3sQJ7xGHVle3Ds2TxF57+0NNmjU/+X6jhPAmrikkrjg8vOAlPThtePJN+Od2HKTbM69OPrfrIz/h/VOAE+0TH9V6+bW3aOroa3X0EYd4WymE17J0CK8lQLpDAAIQgAAEYkKgKMKbuINbqmQJXdervZ59aYlmzluo+6cMU+lSJdX/pqk69OCq6tO17U5vWus5cHzy41QT1xbGTn1Qv/++Rf+87jJtz8rWxBmPqOVZJ6l2rUPyPeGdPPtfuqDZqTqtUR1t2bpNF3b/p24Z2lPH1KrhbaUQXsvSIbyWAOkOAQhAAAIQiAmBoghv4i7tNcOn6IyT6yW/J+DPT2lIfNHrCcfWSl5NSHxR1l8/pWH1jxt0YY9/auatA3TwgVWSb3x776OV2p6VpSYn1dPgqzsmP7EhvxPeTb9sVubEOfrp51+V+Ha48885Wb27tPG6SgivZfkQXkuAdIcABCAAAQjEhEBRhDcmaFK+TYTXEjHCawmQ7hCAAAQcEUgLyRvPEyd1POJBAOF1V2eE15I9wmsJkO4QgAAEHBD45ts0Pf9iuoOZ/z7lWWdmq/qBWG8oipHiRSC8KQa8m+ERXkv2CK8lQLpDAAIQcEDgy6/TdM+c//818g6WkDtll8uyVONghNdlDYprboS3uEj/fR6E15I9wmsJkO4QgAAEHBBAeB1AZ0ohvO5CgPBaskd4LQHSHQIQgIADAgivA+hMifA6zADCawkf4bUESHcIQAACDgggvA6gMyXC6zADCK8lfITXEiDdIQABCDgggPA6gM6UKRfe7OwcZWUX/j54Rnqa0tND8nElKc4HwmsJGOG1BEh3CEAAAg4IILwOoDNlyoV36fIteunVwn/6yJmNc3R8nVKxqAzCa1lmhNcSIN0hAAEIOCCA8DqAzpQpF953PtyqGbMLf2Lbq1uOGtRFeIlmIQggvIWARBMIQAACISOA8IasIDFZTqo/paG4hffTlV+r34ipOrVhHQ27tnNuFVd996NuuGWmEs9Xq7KPMgd1Vb3aNZ1WmRNeS/wIryVAukMAAhBwQADhdQCdKSN1wvveRys18va5qlmjmvYoX24n4e3cZ5ROaVBH3Tq20CuL39foyfdr0YPjVbKEu8++RngtfwARXkuAdIcABCDggADC6wA6U0ZKeFd9t0b7VK6k+x59Tus2bMoV3vUbf9a5HQdq8cI7VSJjh+Be2GOEBvfuoAb1jnSWAoTXEj3CawmQ7hCAAAQcEEB4HUBnykgJ75/lnH7fgp2Ed9nylcqcOEdP3DMyt+IDMqepUf2j1K5lE2cpQHgt0SO8lgDpDgEIQMABAYTXAXSmjIXwvrn0I02aOV8PzxiRW/GhY2bpiMOq67J2zZylAOG1RI/wWgKkOwQgAAEHBBBeB9CZMhbCm7jbO2zsbD01d0xuxfsOn6zTGtXlhNfnnwGE1+fqsXYIQCCuBBDeuFbe7b6j9ikNCZq7XmnYuOkXndW+v95YMEVlSu/4yLMWnYfo5kFdVb/OEc4KwAmvJXqE1xIg3SEAAQg4IIDwOoDOlLE44U2UuVv/cTq+bi316NRSi15eokmz5uuZeWNz38TmIgoIryV1hNcSIN0hAAEIOCCA8DqAzpSREt4xUx7QQ0++qOzsbOXk5CgjI0PtWp6uodd01uo16zV41Ax9vOIrVa+6n0YN6a7atQ5xmgCE1xI/wmsJkO4QgAAEHBBAeB1AZ8qUC++yj7fqiX8XHnTrVlL92nzTWuGJxbglwhvj4rN1CEDAWwIIr7el83rhqb7Duy0rW9nZhUeUni6VzEgvfAePW3LCa1k8hNcSIN0hAAEIOCCA8DqAzpQpP+EFcf4EEF7LdCC8lgDpDgEIQMABAYTXAXSmRHgdZgDhtYSP8FoCpDsEIAABBwQQXgfQmRLhdZgBhNcSPsJrCZDuEIAABBwQQHgdQGdKhNdhBhBeS/gIryVAukMAAhBwQADhdQCdKRFehxlAeC3hI7yWAOkOAQhAwAEBhNcBdKZMufBmZ+coKzun0KQz0tOUnp5W6PY+N0R4LauH8FoCpDsEIAABBwQQXgfQmTLlwrvx3aXKefqhwpNu3kGVjz++8O09bonwWhYP4bUESHcIQAACDgggvA6gM2XqhXfpEqWNu67QpHMGTdReJzQsdHufGyK8ltVDeC0B0h0CEICAAwIIrwPoTBkp4Z044xHd+8izSk98e8Ufj4enj1Ctw6pr1Xc/6oZbZurTlV+rWpV9lDmoq+rVruk0AQivJX6E1xIg3SEAAQg4IIDwOoDOlJES3psm3KvDD62ujm2a/q2ynfuM0ikN6qhbxxZ6ZfH7Gj35fi16cLxKlshwlgKE1xI9wmsJkO4QgAAEHBBAeB1AZ8pICe+AzGk6/cRj1eqck3eq7PqNP+vcjgO1eOGdKpGxQ3Av7DFCg3t3UIN6RzpLAcJriR7htQRIdwhAAAIOCCC8DqAzZaSEt9egCcrJydEXX32vtPQ0tW/VRD0vaaVly1cqc+IcPXHPyNyKJ+S4Uf2j1K5lE2cpQHgt0SO8lgDpDgEIQMABAYTXAXSmjJTw3nX/v1W2TGld2LKJvl+zTj0HjNfgqzuqQvkymjRzvh6eMSK34kPHzNIRh1XXZe2aOUsBwmuJHuG1BEh3CEAAAg4IILwOoDNlpIR313JOu+9JrV6zXm3OO03Dxs7WU3PH5DbpO3yyTmtUlxNen38GEF6fq8faIQCBuBJAeONaebf7rrp32ZQuYGMxfizZsuWfq3atGipdqmRyT1Puflw//fyrendprbPa99cbC6aoTOlSyedadB6imwd1Vf06R6R0/7sbnBNeS/QIryVAukMAAhBwQADhdQCdKSN1wtup90idePzR6n15G327eq26XDtGNw7ootMa1VG3/uN0fN1a6tGppRa9vESTZs3XM/PG5r6JzUUUEF5L6givJUC6QwACEHBAAOF1AJ0pIyW8ic/avXH8Pfpk5dfao0K55P3cS/5xdrLKiasNg0fN0McrvlL1qvtp1JDuql3rEKcJQHgt8SO8lgDpDgEIQMABAYTXAXSmTLnwbnjvPWne5MKT7tRXlY87rvDtPW6J8FoWD+G1BEh3CEAAAg4IILwOoDNlyoV3W1a2srMLDzrxJWklM/7/N6UVvqd/LRFey5ohvJYA6Q4BCEDAAQGE1wF0pky58II4fwIIr2U6EF5LgHSHAAQg4IAAwusAOlMivA4zgPBawkd4LQHSHQIQgIADAgivA+hMifA6zADCawkf4bUESHcIQAACDgggvA6gMyXC6zADCK8lfITXEiDdIQABCDgggPA6gM6UCK/DDCC8lvARXkuAdIcABCDggADC6wA6U6ZceLOzc5SVnVNo0hnpaUpPTyt0e58bIryW1UN4LQHSHQIQgIADAgivA+hMmXLhferHVbp9/YeFJt2vcl013/+gQrf3uSHCa1k9hNcSIN0hAAEIOCCA8DqAzpQpF94FP36tC755utCkn6zeXOfvd3Ch2/vcEOG1rB7CawmQ7hCAAAQcEEB4HUBnysgJ76crv1a/EVN1asM6GnZt59wKJ752+IZbZirxfLUq+yhzUFfVq10z+fzMeQs155FF2p6VpeZNT9TQvpcooxi+/ALhtfwBRHgtAdIdAhCAgAMCCK8D6EwZKeF976OVGnn7XNWsUU17lC+3k/B27jNKpzSoo24dW+iVxe9r9OT7tejB8Xr3gxUaNm625ky6XpX2KK8rh9ym5k0bqUPrpilPB8JriRjhtQRIdwhAAAIOCCC8DqAzZaSEd9V3a7RP5Uq679HntG7DplzhXb/xZ53bcaAWL7xTJTIyklW/sMcIDe7dQc+8tEQH7FdZPTq1TP73l958L3nae+/tQ1KeDoTXEjHCawmQ7hCAAAQcEEB4HUBnykgJ75/lnH7fgp2Ed9nylcqcOEdP3DMyt+IDMqepUf2j9OxLS3TxBWfq7MYnJJ/7ctVqdek3Vi/Pvz3l6UB4LREjvJYA6Q4BCEDAAQGE1wF0poyF8L659CNNmjlfD88YkVvxoWNm6YjDquu5l99Rr86t1PjEY5PPff/DOrXuOkxLnp6e8nQgvJaIEV5LgHSHAAQg4IAAwusAOlPGQngTd3uHjZ2tp+aOya143+GTdVqjulr08jtqe17j5L3dxGPFF9+o16AJnPD68LOB8PpQJdYIAQhAYGcCCC+JcEGg6t5lUzqti48l2/VKw8ZNv+is9v31xoIpKlO6VHK/LToP0c2DuuqZF9/WnhUrqHeXNsn//vQLb2v+U69o9sRBKeWSGJwTXkvECK8lQLpDAAIQcEAA4XUAnSljccKbKHO3/uN0fN1ayTenLXp5iSbNmq9n5o3Vh598oUE3T9d9k29Q+fJl1XPAeLU//wz9o0XjlKcD4f0L4mn3PamHnnhR27Zt18kNjlHmwC4qV7aMdvd5cghvyjPKBCEmkJMmpSkcX0uZoxylFf4bNUNMlaUVBwGEtzgoM8euBKJ0wjtmygN66MkXlZ2drZycHGVkZKhdy9M19JrOWr1mvQaPmqGPV3yl6lX306gh3VW71iFJHHMeXaRZ8xZq2/YstT731OSnN6Slpf7/RxDeP9L43CtLNXn2fN09cbAqlC+jPsMmJ387ueqyC5Tf58mVLJEhhJcXtDgTWPVtmp5ZlB4KBOc1y9ZBB2K8oSiGB4tAeD0oUgSXmGrhffbHbzR4zeJCkxu7/0k6d7/qhW7vc0OE94/qfbTiy+TJ7nHHHJ77G8gnn3+lQVd1yPfz5BrUOxLh9Tn9rN2aANJgjZABHBEgu47Ax3zaVAvvtqxsZWcXHnJ6ulSyGL7lrPArSl1LhDcftlcMnqimp9XXYQdXy/fz5Nq1bKIff9qSuuowMgRCTuD//ivdPSccJ7xdL8tWzUNDAixx0Jz6v9CFZLN+LoPs+lk331e9356lfd+Ct+tHePMo3Z33PqF3P/xcM8cP1FvLPs738+Qua9dM27MMfpXyNiYsHAJ5E1j28XbdNTscZtezW47q1y4RilJtz5JK7PiCIR4hJUB2Q1qYiC+rRExOU8NYRoT3L1VJXLq+5Y55+vrbNbrtpqtVrmxp7e7z5BInvNzhDWOsWVNxEeDPwsVFmnmCJkB2gybKeIUhkOorDYVZQ1zbILx/qfy4qQ9qzbqNGjO0lxJvSEs8dvd5cvXrHIHwxvUnh30nCSANBMFXAmTX18r5vW6E1139EN4/2L/z/mcaNel+PTbrJpXI2Plvkfl9nlyiHSe87sLLzO4JIA3ua8AKikaA7BaNG73sCCC8dvxseiO8f9C7fvRMLXz+zeTnyP35qHlINT0286bdfp4cwmsTP/r6TgBp8L2C8V0/2Y1v7V3uPNXCm52do6zswn88Y0Z6mtLTw/E+jFTXBeG1JIzwWgKku9cEkAavyxfrxZPdWJff2eZTLbz/fX+Lvnqh8J+cc0jTHB1ab8fX/0b9gfBaVhjhtQRId68JIA1ely/Wiye7sS6/s82nXHjf26plUwt/Ylu/d44OPQ7hdRYInyZGeH2qFmsNmgDSEDRRxisuAmS3uEgzz18JRE14P135tfqNmKpTG9bRsGs752511Xc/6oZbZirxfLUq+yhzUFfVq10z+fzMeQs155FF2p6VpeZNT9TQvpcoIyNdv2/ZqhG33qOX3nxPZcuU1tVd2yjxaVhBPTjhtSSJ8FoCpLvXBJAGr8sX68WT3ViX39nmoyS8iY9tHXn7XNWsUU17lC+3k/B27jNKpzSoo24dW+iVxe9r9OT7tejB8Xr3gxUaNm625ky6XpX2KK8rh9ym5k0bqUPrppo8e74+XblKE0ZcqTVrN+qya27R7ImDdHiNAwOpF8JriRHhtQRId68JIA1ely/Wiye7sS6/s81HSXhXfbdG+1SupPsefU7rNmzKFd71G3/WuR0HavHCO3M/9erCHiM0uHcHPfPSEh2wX2X16NQyWYPEaW7itPfe24eo1aXXa+SQ7jr26MOSzyU+KrZC+bK66vLWgdQL4bXEiPBaAqS71wSQBq/LF+vFk91Yl9/Z5qMkvH9CnH7fgp2Ed9nylcqcOEdP3DMyl/OAzGlqVP8oPfvSEl18wZk6u/EJyee+XLVaXfqN1cvzb9exTbvp1ccnq1LF8snnHlnwkpZ+sELjhl8RSL0QXkuMCK8lQLp7TQBp8Lp8sV482Y11+Z1tPg7C++bSjzRp5nw9PGNELuehY2bpiMOq67mX31Gvzq3U+MRjk899/8M6te46TG8smKp6Z3XT0mfvUtkyO95E98Szr+v5V9/VlNHXBFIvhNcSI8JrCZDuXhNAGrwuX6wXT3ZjXX5nm4+D8Cbu9g4bO1tPzR2Ty7nv8Mk6rVFdLXr5HbU9r3Hy3m7iseKLb9Rr0ITcE94XHp2YvCaReNw//z/68JMvOOF1ltZdJkZ4w1IJ1uGCANLggjpzBkGA7AZBkTFMCcRBeDdu+kVnte+vNxZMUZnSO05rW3QeopsHddUzL76tPStWUO8ubZL//ekX3tb8p15Jvjntgi5DNbRvZzU87sjkczdNuFf771tZV1x6vinmPNtzwmuJEeG1BEh3rwkgDV6XL9aLJ7uxLr+zzcdBeBNwu/Ufp+Pr1kq+OW3Ry0s0adZ8PTNvbPLEdtDN03Xf5BtUvnxZ9RwwXu3PP0P/aNFYM+b+W+999Lkm3ni1vl29Vl36jdH9dwxVjYMOCKReCK8lRoTXEiDdvSaANHhdvlgvnuzGuvzONh8l4R0z5QE99OSLys7OVk5OjjIyMtSu5ekaek1nrV6zXoNHzdDHK75S9ar7adSQ7qpd65Ak9zmPLtKseQu1bXuWWp97avLTG9LS0rRt23bdOOFe/efVpSpXtoz69WynC5qdElitEF5LlAivJUC6e00AafC6fLFePNmNdfmdbT7Vwvvlh1u1Yn7ht1frH1KNunzTWuGJxbglwhvj4rN1IQ2EwFcCZNfXyvm97lQL77asbGVnF55RerpUMiO98B08bskJr2XxEF5LgHT3mgDS4HX5Yr14shvr8jvbfKqF19nGPJgY4bUsEsJrCZDuXhNAGrwuX6wXT3ZjXX5nm0d4naEXwmvJHuG1BEh3rwkgDV6XL9aLJ7uxLr+zzSO8ztAjvLboEV5bgvT3mQDS4HP14r12shvv+rvaPcLrirwQXlv0CK8tQfr7TABp8Ll68V472Y13/V3tHuF1RR7htSaP8FojZACPCSANHhcv5ksnuzEPgKPtI7yOwAvhtSaP8FojZACPCSANHhcv5ksnuzEPgKPtI7yOwCO89uARXnuGjOAvAaTB39rFfeVkN+4JcLN/hNcN98SsfEqDJXuE1xIg3b0mgDR4Xb5YL57sxrr8zjaP8DpDj/Daokd4bQnS32cCSIPP1Yv32sluvOvvavcIryvynPBak0d4rREygMcEkAaPixfzpZPdmAfA0fYRXkfgudJgDx7htWfICP4SQBr8rV3cV052454AN/tHeN1wT8zKHV5L9givJUC6e00AafC6fLFePNmNdfmdbR7hdYYe4bVFj/DaEqS/zwSQBp+rF++1k91419/V7hFeV+Q54bUmj/BaI2QAjwkgDR4XL+ZLJ7sxD4Cj7SO8jsBzpcEePMJrz5AR/CWANPhbu7ivnOzGPQFu9o/wuuGemJU7vJbsEV5LgHT3mgDS4HX5Yr14shvr8jvbPMLrDD3Ca4se4bUlSH+fCSANPlcv3msnu/Guv6vdI7yuyHPCa00e4bVGyAAeE0AaPC5ezJdOdmMeAEfbR3gdgedKgz14hNeeISP4SyRcBOwAACAASURBVABp8Ld2cV852Y17AtzsH+F1wz0xK3d4LdkjvJYA6e41AaTB6/LFevFkN9bld7Z5hNcZeoTXFj3Ca0uQ/j4TQBp8rl681052411/V7tHeF2R54TXmjzCa42QATwmgDR4XLyYL53sxjwAjraP8DoCz5UGe/AIrz1DRvCXANLgb+3ivnKyG/cEuNk/wuuGe2JW7vBaskd4LQHS3WsCSIPX5Yv14slurMvvbPMIrzP0CK8teoTXliD9fSaANPhcvXivnezGu/6udo/wuiLPCa81eYTXGiEDeEwAafC4eDFfOtmNeQAcbR/hdQSeKw324BFee4aM4C8BpMHf2sV95WQ37glws3+E1w33xKzc4bVkj/BaAqS71wSQBq/LF+vFk91Yl9/Z5hFeZ+gRXlv0CK8tQfr7TABp8Ll68V472Y13/V3tHuF1RZ4TXmvyCK81QgbwmADS4HHxYr50shvzADjaPsLrCDxXGuzBI7z2DBnBXwJIg7+1i/vKyW7cE+Bm/wivG+6JWbnDa8ke4bUESHevCSANXpcv1osnu7Euv7PNI7zO0CO8tugRXluC9PeZANLgc/XivXayG+/6u9o9wuuKPCe81uQRXmuEDOAxAaTB4+LFfOlkN+YBcLR9hNcReK402INHeO0ZMoK/BJAGf2sX95WT3bgnwM3+EV433BOzcofXkj3CawmQ7l4TQBq8Ll+sF092Y11+Z5tHeJ2hR3ht0SO8tgTp7zMBpMHn6sV77WQ33vV3tXuE1xV5TnitySO81ggZwGMCSIPHxYv50sluzAPgaPsIryPwXGmwB4/w2jNkBH8JIA3+1i7uKye7cU+Am/0jvG64J2blDq8le4TXEiDdvSaANHhdvlgvnuzGuvzONo/wOkOP8NqiR3htCdLfZwJIg8/Vi/fayW686+9q9wivK/Kc8FqTR3itETKAxwSQBo+LF/Olhym7fS5Zq/3L/RKKimSX20OquFco1hLFRSC87qrKlQZL9givJUC6e00gTNLQ5bIs1Tg4x2ueLL74CIQpu8MufF8VHxpffJvfzUxbLxug7MOOCcVaorgIhNddVRFeS/YIryVAuntNIEzSgPB6HaViX3yYsjus9bvac9qAYmeQ14S/9xuv7COODcVaorgIhNddVRFeS/YIryVAuntNIEzSgPB6HaViX3yYsovwFnv5nU2I8DpDz5vWbNEjvLYE6e8zgTBJA8Lrc5KKf+1hyi7CW/z1dzUjwuuKPG9asyaP8FojZACPCYRJGhBej4PkYOlhyi7C6yAAjqZEeB2B53N4dwa/4adfNGTUDP2wdqMW3Dsq98mLr8zUZyu/ltLSkv+tYoVyevXxycl/R3jdhZeZ3RMIkzQgvO7z4NMKwpRdhNen5NitFeG142fTmzu8f9D73+bf1eHKTJ1+Uj298tYHOwlvi85DNCmzj2rWqPY31givTfzo6zuBMEkDwut7mop3/WHKLsJbvLV3ORvC644+wvsH+82//a51GzYl/7lxwpydhPf0ttfo4RkjVGXfygivu6wycwgJhEkaEN4QBiTESwpTdhHeEAcl4KUhvAEDNRgO4d0F1rLln/9NeI87p4caN6qrxHOV96qo63q21+kn7fjYFk54DdJG08gRCJM0ILyRi1dKNxSm7CK8KS11qAZHeN2VA+EtQHizs3M0fNxsndX4eJ3asK5eX/KhBt08XQvm3KID9qus9T9vcVc9ZoaAYwKffyHNvjfd8Sp2TN/t8mwdcVgolqKcnNwr/+FYEKv4G4EwZXd4m2WqdGf/UFRp63UTlHF0vVCsJYqL2Lti6Shuy4s9IbyFOOHdtZJd+41V2+aN1fLsk7RlW7YXhWaREEgFgQ8+2a677t7xZk7Xj55dc3Ts0SVcLyM5f1ZOjjL+eJNrKBbEIv5GIEzZDZPwZg2cqAr1TiAxKSJQumQ4DghStL1QD4vwFiC8m3/bos//+43q1a6Z2/LSvqPVqe3ZatakAVcaQh1vFpdqAmH6szBXGlJd7WiNH6bscqUhWtna3W640uCu1ghvAcL786+b1bRdP91209U6tWEdvb5kuQZmTtPCuWO0914VEV532WXmEBAIkzQgvCEIhEdLCFN2EV6PgmO5VITXEqBFd4T3D3jPv/auBmROU+Ly3bbtWSpZsoRqVK+ix+8eqdfeXq5bpz2kNWs36MAD9tWg3h3U6Lijkj1505pF+ujqPYEwSQPC632cinUDYcouwluspXc6GcLrDj/Ca8ke4bUESHevCYRJGhBer6NU7IsPU3YR3mIvv7MJEV5n6IXwWrJHeC0B0t1rAmGSBoTX6ygV++LDlF2Et9jL72xChNcZeoTXFj3Ca0uQ/j4TCJM0ILw+J6n41x6m7CK8xV9/VzMivK7IC+G1RY/w2hKkv88EwiQNCK/PSSr+tYcpuwhv8dff1YwIryvyCK81eYTXGiEDeEwgTNKA8HocJAdLD1N2EV4HAXA0JcLrCLwQXmvyCK81QgbwmECYpAHh9ThIDpYepuwivA4C4GhKhNcReITXHjzCa8+QEfwlECZpQHj9zZGLlYcpuwiviwS4mRPhdcM9MSuf0mDJHuG1BEh3rwmESRoQXq+jVOyLD1N2Ed5iL7+zCRFeZ+gRXlv0CK8tQfr7TCBM0oDw+pyk4l97mLKL8BZ//V3NiPC6Is8JrzV5hNcaIQN4TCBM0oDwehwkB0sPU3YRXgcBcDQlwusIPFca7MEjvPYMGcFfAmGSBoTX3xy5WHmYsovwukiAmzkRXjfcE7Nyh9eSPcJrCZDuXhMIkzQgvF5HqdgXH6bsIrzFXn5nEyK8ztAjvLboEV5bgvT3mUCYpAHh9TlJxb/2MGUX4S3++ruaEeF1RZ4TXmvyCK81QgbwmECYpAHh9ThIDpYepuwivA4C4GhKhNcReK402INHeO0ZMoK/BMIkDQivvzlysfIwZRfhdZEAN3MivG64J2blDq8le4TXEiDdvSYQJmlAeL2OUrEvPkzZRXiLvfzOJkR4naEPh/BmZWVr7vzn9PQLb+nb1WuTNA6qtr/aNm+s9q2auKNTiJkR3kJAoklkCYRJGrp1ydLBB4UFdY6UE5a1sI68CIQpuwhvfDKK8LqrdShOeKfft0APPvGC2px3mqpX3S9J48tvVuvxZ17TVZe1Vqe2Z7kjVMDMCG9oS8PCioFAmKTh+vafquJ3HxbDrgueIuuIusqufnjBDWnhjECYsovwOotBsU+M8BY78twJQyG8zToM1KSb++jImjsfz3z4yRe6YcwsLbzvFneEEN7Qsmdh7gkgDXnX4Pd+45V9xLHuC8QK8iVAdsmuix8PhNcF9R1zhkJ4G5zXS288OUWlSpXcicTWrdt0YsurtOy5me4IIbyhZc/C3BNAGpAG9yks2grILtktWnLseiG8dvxseodCeC/qdZMubHW62rXc+b7uYwtf0f3z/6Mn7hlps8eU9uVKQ0rxMnjICSANSEPII8oJr2GB+OuEITDD5givIbAAm4dCeJe895l6DhqvGtWrqMZBBygnJ0dfrvpBq75bo0k399VpjeoEuOVgh0J4g+XJaH4RQHgRXr8S+/9XS3bJrovsIrwuqO+YMxTCm1jImrUb9e//vKlvv//jUxoO3E/nn3OK9qlcyR2dQsyM8BYCEk0iSwBpQBp8DTfZJbsusovwuqAeMuF1h8BuZoTXjh+9/SaANCANviaY7JJdF9lFeF1Qdyy8J5/fW1NGXav6dQ5X4t9393hzwVR3hAqYGeENbWlYWDEQQBqQhmKIWUqmILtkNyXBKmBQhNcFdcfC+8Jry1S/7uHaq9IeSvz77h5NT6vvjhDCG1r2LMw9AaQBaXCfwqKtgOyS3aIlx64XwmvHz6Z3KO7wPvLvl/P8RrX/bf5dDy94UV0vbm6zx5T25YQ3pXgZPOQEkAakIeQRzXd5ZJfsusguwuuCuuMT3sT027Zt17bt29W4TV+9+vjkv1H44uvV6nLtLVr67F3uCHHCG1r2LMw9AaQBaXCfwqKtgOyS3aIlx64XwmvHz6a30xPexNcJj7njAW3Pysp3DyefcIxmjh9gs8eU9uWEN6V4GTzkBJAGpCHkEeWE17BAfA6vITDD5givIbAAmzsV3sQ+fvt9q045v7ceuHP437ZVpnQpHVRtf6WnpwW45WCHQniD5clofhFAeBFevxL7/1dLdsmui+wivC6o75jTufAmFpH4CuFdv1b4TyR9h0/W5Jv7uiNUwMwIb2hLw8KKgQDSgDQUQ8xSMgXZJbspCVYBgyK8LqiHSHi3bN2mef/6jz5e8VVSfv98rF3/k75dvU6vP3mHO0IIb2jZszD3BJAGpMF9Cou2ArJLdouWHLteCK8dP5veoTjhHTZ2tt79cIVObVhHTy56Q/9ocbo+XvGlNv+2RSMHd9ORNQ+y2WNK+3LCm1K8DB5yAkgD0hDyiOa7PLJLdl1kF+F1QT1EJ7ynXHC1Hplxo6pV2UdnXdRfzz88Ibm6iTMeUaWKFdStAx9L5i4izAyB/AkgDUiDrz8fZDef7Pa/Tdk1jwlJWRPv38kJyVqCWQbCGwzHoowSihPe45v11BsLpijxJrWE8P7nofFKS0tLXm9o1nGgXnrs9qLsrVj6cMJbLJiZJKQEkAaEN6TRLHBZZDdvRG+NnKE3Sv5WIL/iaHBKmSqqW2rv4piq2OZAeIsN9d8mCoXwduo9UvXrHKE+XduoS7+xuviCM9XqnJO18stvdcnVo/T2U9PcESpgZoQ3tKVhYcVAAGlAeIshZimZguzmjfX50dPUbtPrKWFuOuijVc7VyWWqmHYLdXuE1115QiG8yz/7UtcOv0OPzbpJ7374ua67caoqViivX37drPbnN9HQazq7I4TwhpY9C3NPAGlAeN2nsGgrILsIb9GSY9cL4bXjZ9M7FMKb2EBOTk7yGkPi8eWq1Vr+2X9VZd+91fC4I232l/K+nPCmHDEThJgA0oDwhjieu10a2UV4XWQX4XVBfceczoU38S1ria8WXnDvaO1TuZI7EkWcGeEtIji6RYIA0oDw+hpksovwusguwuuCekiEN7GMPsMm68T6R6tT27PckSjizAhvEcHRLRIEkAaE19cgk12E10V2EV4X1EMkvInP4X19yXKVKllC1avtp1IlS+5EZNqYfu4IFTAzwhva0rCwYiCANCC8xRCzlExBdhHelASrgEERXhfUQyS8Y6c+qBIZGfrjCu/faFzXq707QghvaNmzMPcEkAaE130Ki7YCsovwFi05dr0QXjt+Nr2d3+G1WXwY+nLCG4YqsAZXBJAGhNdV9mznJbsIr22GitIf4S0KtWD6ILyWHBFeS4B095oA0oDw+hpgsovwusguwuuC+o45EV5L9givJUC6e00AaUB4fQ0w2UV4XWQX4XVBHeENhDrCGwhGBvGUANKA8HoaXZFdhNdFdhFeF9QR3kCoI7yBYGQQTwkgDfkIb//blF3zmFBUNU1pylFOKNYSpkWQXYTXRR4RXhfUEd5AqCO8gWBkEE8JIA15F27JqLv0csavoajq6WWrqU6pyqFYS5gWQXYRXhd5RHhdUEd4A6GO8AaCkUE8JYA0IA2eRpcrDfkU7vnR09Ru0+uhKOujVc7VyWWqhGItQS0C4Q2KpPk4vGnNnNlOPRBeS4B095oAwovw+hpgskt2XWQX4XVBnRPeQKgjvIFgZBBPCSANSIOn0eWElxNeJ9FFeJ1gT07KCa8le4TXEiDdvSaA8CK8vgaY7JJdF9lFeF1Q54Q3EOoIbyAYGcRTAkgD0uBpdDnh5YTXSXQRXifYOeENAjvCGwRFxvCVAMKL8JJdewLDWr+rPacNsB8ogBF401oAEHczBMKbWr67G50rDZbsEV5LgHT3mgDCi/D6GmCyS3ZdZBfhdUF9x5wIryV7hNcSIN29JoA0IA2+Bpjskl0X2UV4XVBHeAOhjvAGgpFBPCWANCANnkaXO7z5FI4rDalNNMKbWr5caUghX4Q3hXAZOvQEEF6EN/QhzWeBZJfsusguwuuCOie8gVBHeAPByCCeEkAakAZPo8sJLye8TqKL8DrBnpyUO7yW7BFeS4B095oAwovw+hpgskt2XWQX4XVBnRPeQKgjvIFgZBBPCSANSIOn0eWElxNeJ9FFeJ1g54Q3COwIbxAUGcNXAggvwkt27QnwObx5M3y0yrk6uUwVe8AhGgHhdVcMrjT8hf2Gn37RkFEz9MPajVpw76jcZ1Z996NuuGWmPl35tapV2UeZg7qqXu2ayecRXnfhZWb3BBBehNd9Cou2ArJLdouWHLteCK8dP5veCO8f9P63+Xd1uDJTp59UT6+89cFOwtu5zyid0qCOunVsoVcWv6/Rk+/XogfHq2SJDITXJn309Z4A0oA0+Bpiskt2XWQX4XVBfcecCO8f7Df/9rvWbdiU/OfGCXNyhXf9xp91bseBWrzwTpXIyEi2vrDHCA3u3UEN6h2J8LrLLjOHgADSgDSEIIZFWgLZJbtFCo5lJ4TXEqBFd4R3F3jLln++k/AuW75SmRPn6Il7Rua2HJA5TY3qH6V2LZsgvBbho6v/BJAGpMHXFJNdsusiuwivC+qc8OZJfVfhfXPpR5o0c74enjEit/3QMbN0xGHVdVm7Ztr461Z31WNmCDgm8NnKHM2+N93xKnZMP7zNMlW6s38o1vLC6Om6cNNroVjL/Krn6Yw9qoZiLWFaBNnNuxpkN7Up3atCqdROwOj5EuCEt4AT3vc+WqlhY2frqbljclv2HT5ZpzWqmzzh/W1LFvGCQGwJfPhZlmbenRaK/SO8eZfh8WrN1WyvA0NRozAtguzmXY0XR0/XP0Lyy1oUs1u29I6rkTyKnwDCW4Dwbtz0i85q319vLJiiMqV3/GbWovMQ3Tyoq+rXOYIrDcWfWWYMEQH+LJx3MZ4fPU3tNr0eikpF8aOdggBLdsluEDkyHYMrDabEgmuP8BYgvImnu/Ufp+Pr1lKPTi216OUlmjRrvp6ZNzb5JjY+liy4MDKSfwSQBqTBv9TuWDHZJbsusovwuqC+Y06E9w/2z7/2rhJvRlNOjrZtz1LJkiVUo3oVPX73SK1es16DR83Qxyu+UvWq+2nUkO6qXeuQZE+E1114mdk9AaQBaXCfwqKtgOyS3aIlx64XwmvHz6Y3wmtDD+G1pEd33wkgDUiDrxkmu2TXRXYRXhfUOeENhDonvIFgZBBPCSANSIOn0eVKQz6F4/55ahON8KaW7+5G54TXkj3CawmQ7l4TQHgRXl8DTHbJrovsIrwuqHPCGwh1hDcQjAziKQGkAWnwNLqc8HLC6yS6CK8T7MlJOeG1ZI/wWgKku9cEEF6E19cAk12y6yK7CK8L6pzwBkId4Q0EI4N4SgBpQBo8jS4nvJzwOokuwusEOye8QWBHeIOgyBi+EkB4EV6ya09gWOt3tee0AfYDBTACb1oLAOJuhkB4U8t3d6NzpcGSPcJrCZDuXhNAeBFeXwNMdsmui+wivC6o75gT4bVkj/BaAqS71wSQBqTB1wCTXbLrIrsIrwvqCG8g1BHeQDAyiKcEkAakwdPococ3n8JxpSG1iUZ4U8uXKw0p5IvwphAuQ4eeAMKL8IY+pPkskOySXRfZRXhdUOeENxDqCG8gGBnEUwJIA9LgaXQ54eWE10l0EV4n2JOTcofXkj3CawmQ7l4TQHgRXl8DTHbJrovsIrwuqHPCGwh1hDcQjAziKQGkAWnwNLqc8HLC6yS6CK8T7JzwBoEd4Q2CImP4SgDhRXjJrj0BPoc3b4aPVjlXJ5epYg84RCMgvO6KwZUGS/YIryVAuntNAOFFeH0NMNkluy6yi/C6oM6VhkCoI7yBYGQQTwkgDUiDp9HlSgNXGpxEF+F1gp0rDUFgR3iDoMgYvhJAeBFesmtPgCsNXGmwTxEjFESAKw0FESrgeYTXEiDdvSaA8CK8vgaY7JJdF9nlhNcFda40BEId4Q0EI4N4SgBpQBo8jS5XGrjS4CS6CK8T7FxpCAJ7UMKbFsRiAhgjJ4AxGCI+BBBehNfXtJNdsusiuwivC+qc8AZCPQjh/X51mr78Kj2Q9dgOUuOQbFU9AO215RiX/kgD0uBr1sku2XWRXYTXBXWENxDqQQhvmF54u1yWpRoHI7yBhCMGg4Qpu7zxJ+/ARfGzTIP40SK7CG8QOTIdA+E1JRZce960ZskS4bUESHevCSANSIOvASa7ZNdFdhFeF9Q54Q2EOsIbCEYG8ZQA0oA0eBpd3rSWT+GeHz1N7Ta9HoqyRvGvEwivu2hxwmvJHuG1BEh3rwkgvAivrwEmu2TXRXYRXhfUOeENhDrCGwhGBvGUANIQfml4/IDmalh6v1AkLE1pylE43iNAdsOfXU54Q/FjG5lFcMJrWUqE1xIg3b0mgDSEXxoWZ3RQ+hflQpGzPY/IVoWqCO+uxeANl3nHE+ENxY9tZBaB8FqWEuG1BEh3rwkgvOEX3re2d9I3M8uGIme1e2Wp0qEIL8JbuDg+WbWFTgjJXyeSK86xzy5XGgpX+1S0QngtqSK8lgDp7jUBhBfhNQkwwps3LU548+bydskOyv44HH+d2LtulspXMUl73m0RXnuGRR0B4S0quT/6IbyWAOnuNQGEF+E1CTDCi/Ca5CWKf51AeE0SEGxbhNeSJ8JrCZDuXhNAeBFekwAjvAivSV4QXhNatC2IAMJbEKECnkd4LQHS3WsCCC/CaxJghBfhNckLwmtCi7YFEUB4CyKE8FoSonuUCSC8CK9JvhFehNckLwivCS3aFkQA4S2IUMyEt3uXbB1UPduSSjDdw/SZncHsKHqjILwIr0mqEV6E1yQvCK8JLdoWRADhLYhQzIT3+os+0x5fvWtJJZjuWUcfr5zqNYMZjFFSQgDhRXhNgoXwIrwmeUF4TWjRtiACCG9BhGImvGH6eJzf+41X9hHHWlaI7qkkgPAivCb5QngRXpO8ILwmtGhbEAGEtyBCCK8loaJ3R3iLzq64eiK8CK9J1hBehNckLwivCS3aFkQA4S2IEMJrSajo3RHeorMrrp4IL8JrkjWEF+E1yQvCa0KLtgURQHgLIoTwWhIqeneEt+jsiqsnwovwmmQN4UV4TfKC8JrQom1BBBDeggghvJaEit4d4S06u+LqifAivCZZQ3gRXpO8ILwmtGhbEAGEtyBCCK8loaJ3D5PwbtmQpi0/FX0vQfYsvadUunJOkEMWeSyEF+E1CQ/Ci/Ca5AXhNaFF24IIILwFEUJ4LQkVvfvvgyYr+9Cjij5AgD03fZGmj2dkBDhi0YdCGpAGk/REURpM9p9fW35Z45c1kxwF9bpbde+yJtPSNkACCK8lzKh9tXCYPpbs1VtmadyWzywrFEz3ib801aqZZYIZzHKUoF54LZeR7I40IA0mOSK7/LJmkpco/rKG8JokINi2CK8lT4TXEuBuuj8/eprabXo9dRMYjBzFF16D7efbFOFFeE1yhPAivCZ5ieLrLsJrkoBg2yK8ljwRXkuACK8xQKQBaTAJTRSlwWT/+bXllzV+WTPJUVCvuwivCfVg2yK8ljwRXkuACK8xwKBeeI0nzqMD0oA0mOSI7PLLmkleovjLGsJrkoBg2yK8ljwRXkuACK8xQKQBaTAJTRSlwWT/nPCa0eIqWd68gnrdRXjN8hhka4TXkibCawkQ4TUGGNQLr/HEnPAWGhnSkFppKHQhdtOQv07w1wmTHAX1uovwmlAPti3Ca8kT4bUEiPAaAwzqhdd4YoS30MgQXoS30GGRFKZPxyG7qc0uwmvykxFsW4TXkifCawkQ4TUGiPDmjQxpyJsLVxry5sIJLye8Ji++Qb3uIrwm1INti/Ba8kR4LQEivMYAg3rhNZ6YE95CI+OULLWnZIUuxG4aIrwIr0mOgnrdRXhNqAfbFuG15InwWgJEeI0BBvXCazwxwltoZAgvwlvosHClIV9UUfzrBMJr8pMRbFuE15InwmsJEOE1Bojw5o2MKw15c4miNBj/0PDLWqGR8ctaan9ZQ3gLHcXAGyK8lkgRXkuACK8xQIQX4TUJDcKbNy2uNOTNBeFFeE1eX3xqi/BaVgvhtQSI8BoDRHgRXpPQILwIr0leEF6E1yQvPrVFeC2rhfBaAkR4jQEivAivSWgQXoTXJC8IL8Jrkhef2iK8ltVCeC0BIrzGABFehNckNAgvwmuSF4QX4TXJi09tEV7LaiG8lgARXmOACC/CaxIahBfhNckLwovwmuTFp7YIr2W1EF5LgAivMUCEF+E1CQ3Ci/Ca5AXhRXhN8uJTW4TXsloIryVAhNcYIMKL8JqEBuFFeE3ygvAivCZ58aktwmtZLYTXEiDCawwQ4UV4TUKD8CK8JnlBeBFek7z41BbhLUS1Lr4yU5+t/FpKS0u2rlihnF59fHLy3xHeQgAsYhNeeFP7wlvEsuzUjc8yzZsi2SW7Jj9ffGlK3rSi+MsaXzxh8pMRbFuEtxA8W3QeokmZfVSzRrW/tUZ4CwGwiE2QBqTBJDpIQ3ykwSQX+bXllzV+WTPJUVB/WUN4TagH2xbhLQTP09teo4dnjFCVfSsjvIXgFVQThBfhNckSwovwmuQF4UV4TfKC8JrQCmdbhLcQdTnunB5q3Kiuli3/XJX3qqjrerbX6Scdm+zJCW8hABaxCcKL8JpEB+FFeE3ygvAivCZ5QXhNaIWzLcJbQF2ys3M0fNxsndX4eJ3asK5eX/KhBt08XQvm3KID9qusn/631bqyn67M0ex70q3HCWKA4W2WqdKd/YMYynqMF0ZP14WbXrMeJ4gB3t7eSatmlg1iKOsx6l6Zrf2P3HGf3PUjkd1ZZPdvZSC7eSeT7ObNhdfdvLn4+rqbs5sX5j3Ll3L9sh3b+RHeIpS+a7+xatu8sVqefZL+99v2Ioywc5ePVmRpJtKANBQyScdema0Djs4oZOvUNktkF+H9O2OEN+/ckV2E1+QVKUzCa5Ldf9w+0AAAGdtJREFU3R1HlC9bwgQBbQMkgPAWAHPzb1v0+X+/Ub3aNXNbXtp3tDq1PVvNmjTgSkOAYdx1KK405A03qD+tBVE6/iycN0WyS3ZNfr64jpM3LT6lwSRFtC2IAMJbAKGff92spu366babrtapDevo9SXLNTBzmhbOHaO996qI8BaUMIvnkQakwSQ+SEN8pMEkF/m15Zc1flkzyVFQBw18SoMJ9WDbIryF4Pna28t167SHtGbtBh14wL4a1LuDGh13VLInb1orBMAiNkF4EV6T6CC8CK9JXhBehNckLwivCa1wtkV4LeuC8FoC3E13hBfhNUkXwovwmuQF4UV4TfKC8JrQCmdbhNeyLgivJUCE1xhgUC+8xhPn0QFpQBpMckR286bFL2vx+WWNKw0mrxjBtkV4LXkivJYAEV5jgEgD0mASmii+8cdk//m15Zc1flkzyVFQr7sIrwn1YNsivJY8EV5LgAivMcCgXniNJ+aEt9DIuI6TNyqyyy9rhf4hkhTFX9YQXpMEBNsW4bXkifBaAkR4jQEiDUiDSWiiKA0m++eE14wWv6yl9pc1hNcsj0G2RngtaSK8lgARXmOACC/CaxIahDdvWlxpyJsLwovwmry++NQW4bWsFsJrCRDhNQaI8CK8JqFBeBFek7wgvAivSV58aovwWlYL4bUEiPAaA0R4EV6T0CC8CK9JXhBehNckLz61RXgtq4XwWgJEeI0BIrwIr0loEF6E1yQvCC/Ca5IXn9oivJbVQngtASK8xgARXoTXJDQIL8JrkheEF+E1yYtPbRFey2ohvJYAEV5jgAgvwmsSGoQX4TXJC8KL8Jrkxae2CK9ltRBeS4AIrzFAhBfhNQkNwovwmuQF4UV4TfLiU1uE17JaCK8lQITXGCDCi/CahAbhRXhN8oLwIrwmefGpLcJrWS2E1xIgwmsMEOFFeE1Cg/AivCZ5QXgRXpO8+NQW4bWsFsJrCRDhNQaI8CK8JqFBeBFek7wgvAivSV58aovwWlYL4bUEiPAaA0R4EV6T0CC8CK9JXhBehNckLz61RXgtq4XwWgJEeI0BIrwIr0loEF6E1yQvCC/Ca5IXn9oivJbVQngtASK8xgARXoTXJDQIL8JrkheEF+E1yYtPbRFey2ohvJYAEV5jgAgvwmsSGoQX4TXJC8KL8Jrkxae2CK9ltRBeS4AIrzFAhBfhNQkNwovwmuQF4UV4TfLiU1uE17JaCK8lQITXGCDCi/CahAbhRXhN8oLwIrwmefGpLcJrWS2E1xIgwmsMEOFFeE1Cg/AivCZ5QXgRXpO8+NQW4bWsFsJrCRDhNQaI8CK8JqFBeBFek7wgvAivSV58aovwWlYL4bUEiPAaA0R4EV6T0CC8CK9JXhBehNckLz61RXgtq4XwWgJEeI0BIrwIr0loEF6E1yQvCC/Ca5IXn9oivJbVQngtASK8xgARXoTXJDQIL8JrkheEF+E1yYtPbRFey2ohvJYAEV5jgAgvwmsSGoQX4TXJC8KL8Jrkxae2CK9ltRBeS4AIrzFAhBfhNQkNwovwmuQF4UV4TfLiU1uE17JaCK8lQITXGCDCi/CahAbhRXhN8oLwIrwmefGpLcJrWS2E1xIgwmsMEOFFeE1Cg/AivCZ5QXgRXpO8+NQW4bWsFsJrCRDhNQaI8CK8JqFBeBFek7wgvAivSV58aovwWlYL4bUEiPAaA0R4EV6T0CC8CK9JXhBehNckLz61RXgtq4XwWgJEeI0BIrwIr0loEF6E1yQvCC/Ca5IXn9oivJbVQngtASK8xgARXoTXJDQIL8JrkheEF+E1yYtPbRFey2ohvJYAEV5jgAgvwmsSGoQX4TXJC8KL8Jrkxae2CK9ltRBeS4AIrzFAhBfhNQkNwovwmuQF4UV4TfLiU1uE17JaCK8lQITXGCDCi/CahAbhRXhN8oLwIrwmefGpLcJrWS2E1xIgwmsMEOFFeE1Cg/AivCZ5QXgRXpO8+NQW4bWsFsJrCRDhNQaI8CK8JqFBeBFek7wgvAivSV58aovwWlYL4bUEiPAaA0R4EV6T0CC8CK9JXhBehNckLz61RXgtq4XwWgJEeI0BIrwIr0loEF6E1yQvCC/Ca5IXn9oivJbVQngtASK8xgARXoTXJDQIL8JrkheEF+E1yYtPbRFey2ohvJYAEV5jgAgvwmsSGoQX4TXJC8KL8Jrkxae2CK9ltRBeS4AIrzFAhBfhNQkNwovwmuQF4UV4TfLiU1uE17JaCK8lQITXGCDCi/CahAbhRXhN8oLwIrwmefGpLcJrWS2E1xIgwmsMEOFFeE1Cg/AivCZ5QXgRXpO8+NQW4bWsFsJrCRDhNQaI8CK8JqFBeBFek7wgvAivSV58aovwWlYL4bUEiPAaA0R4EV6T0CC8CK9JXhBehNckLz61RXgtq4XwWgJEeI0BIrwIr0loEF6E1yQvCC/Ca5IXn9oivJbVQngtASK8xgARXoTXJDQIL8JrkheEF+E1yYtPbRFey2ohvJYAEV5jgAgvwmsSGoQX4TXJC8KL8Jrkxae2CK9ltRBeS4AIrzFAhBfhNQkNwovwmuQF4UV4TfLiU1uE17JaCK8lQITXGCDCi/CahAbhRXhN8oLwIrwmefGpLcJrWS2E1xIgwmsMEOFFeE1Cg/AivCZ5QXgRXpO8+NQW4bWsFsJrCRDhNQaI8CK8JqFBeBFek7wgvAivSV58aovwWlYL4bUEiPAaA0R4EV6T0CC8CK9JXhBehNckLz61RXgtq4XwWgJEeI0BIrwIr0loEF6E1yQvCC/Ca5IXn9oivJbVQngtASK8xgARXoTXJDQIL8JrkheEF+E1yYtPbRFey2ohvJYAEV5jgAgvwmsSGoQX4TXJC8KL8Jrkxae2CK9ltRBeS4AIrzFAhBfhNQkNwovwmuQF4UV4TfLiU1uE17JaCK8lQITXGCDCi/CahAbhRXhN8oLwIrwmefGpLcJrWS2E1xIgwmsMEOFFeE1Cg/AivCZ5QXgRXpO8+NQW4S1EtVZ996NuuGWmPl35tapV2UeZg7qqXu2ayZ4IbyEAFrEJL7ypfeEtYll26vbl12m6Z05GEENZjzGs9bvac9oA63GCGIDskl2THJHdvGlF8Ze1qnuXNYkGbQMkgPAWAmbnPqN0SoM66taxhV5Z/L5GT75fix4cr5IlMhDeQvArahOkAWkwyQ7SEB9pMMlFfm35ZS1vMrzupvZ1F+EN4qe3aGMgvAVwW7/xZ53bcaAWL7xTJTJ2nGRd2GOEBvfuoAb1jkR4i5a7QvXihTe1L7yFKkIBjZAGpMEkR1zHyZsWv6zF55c1hNfkFSPYtghvATyXLV+pzIlz9MQ9I3NbDsicpkb1j1K7lk0Q3mDzuNNoCC/CaxIvpCE+0mCSC054zWjxupva112E1yyPQbZGeAug+ebSjzRp5nw9PGNEbsuhY2bpiMOq67J2zQKpxXufbNXTiwIZynqQy078WOWemmk9ThADLO5+jUZt/iSIoazHmLrlbK17tpT1OEEMULOlVKNOONZCdvOuKNnNmwvZzZsLr7t5c+F1N4j/x2CMPwkgvAVk4b2PVmrY2Nl6au6Y3JZ9h0/WaY3qJk94eUAAAhCAAAQgAAEIhJsAwltAfTZu+kVnte+vNxZMUZnSO07VWnQeopsHdVX9OkeEu7qsDgIQgAAEIAABCEBACG8hQtCt/zgdX7eWenRqqUUvL9GkWfP1zLyxuW9iK8QQNIEABCAAAQhAAAIQcEQA4S0E+NVr1mvwqBn6eMVXql51P40a0l21ax1SiJ40gQAEIAABCEAAAhBwTQDhdV0B5k8S2PDTLxoyaoZ+WLtRC+4dlUvl9y1bNeLWe/TSm++pbJnSurprG+5OkxnnBBJfQtNvxFSd2rCOhl3bOXc9u/uSmpnzFmrOI4u0PStLzZueqKF9L1FGRrrzvbCA6BNY+Pxi3TThXo0c3F3NmjTI3XB+mdzd6+7uMh59kuzQZwIIr8/Vi8ja/7f5d3W4MlOnn1RPr7z1wU7CO3n2fH26cpUmjLhSa9Zu1GXX3KLZEwfp8BoHRmT3bMM3Aok3so68fa5q1qimPcqX20l48/uSmnc/WKFh42ZrzqTrVWmP8rpyyG1q3rSROrRu6tv2Wa9nBO595Fkl8rd2/U/qcnHzXOF9691P8s3k7l53d/dFTJ6hYbkxI4DwxqzgYdzu5t9+17oNm5L/3Dhhzk7C2+rS6zVySHcde/RhyaWPm/qgKpQvq6subx3GrbCmGBBY9d0a7VO5ku579LlkZv884d3dl9Q889ISHbBf5eT7ABKPxF8sEqe9994+JAbE2KJLAp/93yrVOqy6uve/Ve3PPyNXeDNvuy/fTOb3unvRBWfu9ouYXO6TuSFQEAGEtyBCPF9sBJYt//xvwnts02569fHJqlSxfHIdjyx4SUs/WKFxw68otnUxEQTyIjD9vgU7Ce/uvqTm2ZeW6OILztTZjU9IDvXlqtXq0m+sXp5/O3AhUCwEul03bifhTbwZO79M5ve6e3Hrprv9IqZi2QiTQKCIBBDeIoKjW/AEdhXebduzVO+sblr67F0qW2bHR8I98ezrev7VdzVl9DXBL4ARIWBAYFfh3d2X1Dz38jvq1bmVGp94bHKG739Yp9Zdh2nJ09MNZqQpBIpOYFfh7dR7ZJ6ZfGPB1Hxfdzu2bZryL2Iq+g7pCYHdE0B4SUhoCOR3wvvCoxOTf0JOPO6f/x99+MkXnPCGpmrxXciuwru7L6lZ9PI7ante4+S93cRjxRffqNegCZzwxjc+xb7zXYW3+4Bb881k4oQ3r9fdDm2a8kVMxV45JgyKAMIbFEnGsSaQl/Be0GWohvbtrIbHHZkcP/FO4/33rawrLj3fej4GgIANgV2Fd3dfUvPMi29rz4oV1LtLm+SUT7/wtuY/9UryDZg8IFAcBHYV3lGT5uabyfxedy+64Ay+iKk4isUcKSGA8KYEK4MWhUBewjtj7r/13kefa+KNV+vb1WvVpd8Y3X/HUNU46ICiTEEfCARGYFfhTQyc35fUJP4qMejm6bpv8g0qX76seg4Yn7xP+Y8WjQNbDwNBYHcEdhXexOttfpnc3esuX8REznwlgPD6WrkIrfv5197VgMxpUk6OEvd2S5YsoRrVq+jxu0dq27btunHCvfrPq0tVrmwZ9evZThc0OyVCu2crvhEYM+UBPfTki8rOzlZOTo4yMjLUruXpGnpNZ+3uS2rmPLpIs+YtTGa89bmnanDvDkpLS/Nt+6zXMwIX9hih//vqO23fnqWM9HSlpadp7NCeatakofLL5O5ed/kiJs8CwHJzCSC8hAECEIAABCAAAQhAINIEEN5Il5fNQQACEIAABCAAAQggvGQAAhCAAAQgAAEIQCDSBBDeSJeXzUEAAhCAAAQgAAEIILxkAAIQgAAEIAABCEAg0gQQ3kiXl81BAAIQgAAEIAABCCC8ZAACEIAABCAAAQhAINIEEN5Il5fNQQACEIAABCAAAQggvGQAAhCAAAQgAAEIQCDSBBDeSJeXzUEAAhCAAAQgAAEIILxkAAIQgAAEIAABCEAg0gQQ3kiXl81BAAIQgAAEIAABCCC8ZAACEIAABCAAAQhAINIEEN5Il5fNQQACEIAABCAAAQggvGQAAhCAAAQgAAEIQCDSBBDeSJeXzUEAAhCAAAQgAAEIILxkAAIQgAAEIAABCEAg0gQQ3kiXl81BAAIFEWjbbbj+0eJ0dWp7VkFNdfGVmWp2egN1ufi8AtuaNHjt7eXqN+IOLX32LpNutIUABCAAgUISQHgLCYpmEIBANAl8tOJL7Vt5T+2/714FbhDhLRARDSAAAQiEkgDCG8qysCgIQCCMBBDeMFaFNUEAAhAomADCWzAjWkAAAh4ReGXxBxo9+X5179RCcx99TmvX/6SLWzfVySfU1q3THtLqNevVoN6RGjf8CpXIyNBfrzQknt/08/9UqWJ5Jcb55dfNanXOyRpwxUVJAgnhPePk4/TZ/32dfL7ynnto4FUd1KxJg+Tzyz/7UmOnPJB8vkzp0mp6Wn0N7XuJSpUqqW3bs5Lrev7Vpfrf5t916MFVNfCqi9XouKOUuNIw8OZpGjW4u8ZMfUAbf/pZJ9avrXHDe6lc2TLJsef963nd8/Az+mnTLzr4wCq6pvs/1PjEY5PPvf3ep7r1zof05arVKlumtM5p0kDXX91RJUuW8KhyLBUCEIBA6gggvKljy8gQgIADAgl57Dt8sq667AL16NRSby79SD0GjFezJg01dmhPbf59i5p1GKjRQ7rrzFPr7yS8E2c8ogefeFEjB3dNtl/xxTf6R/d/6rGZN+nImgclhXf9xp91Y//LdcKxtTRtzpN6ZMFLemPBlOROz2rfX+c1baTel7fR+o2b1GPArWrf6ozknd8Hn3hBDz/5kmZNGKg9K1XQk8++ocmz5+uFRydq8dJPdO0/79C5ZzTUgCsv0i+//qbOfUape8cW6nzhOXr1rQ80fNzduvOWfqpVs7pee/tDXXfjnXrynpE6qNr+Oq11H/Xp2lZtWzTWug2b1HfYZF3Q7NRC3Ut2UCKmhAAEIFDsBBDeYkfOhBCAQCoJJIT3isET9M4z05Ono1u2blP9c3ro9syrdXbjE5JTX3L1KJ112vG6/KJz/ya8r7z1gZ68Z1TuEpu2uy4poeed2SgpvEfVPEgj+l+efH7Vd2t0XqfBeuVfk7RP5Ura8NMvqlCuTPJEN/EYNWlu8r9NGHGVZs5bqOdeWaq5d9ygMqVLJZ/PyspWRkZ68oQ3seY/x0k8N3jkDJUrV0YjrrtMVwyeqDpH1lDvLm1y19Vr0ATVPepQ9br0fJ3Y4kqNHNw9Kcx/HTeVnBkbAhCAgE8EEF6fqsVaIQCBAgkk5LH/TVO15OnpuW1rN7lc86YOU73aNZP/rdt145LXGq649Py/Ce/n//1W08del9v33I6D1KtzK7U577Sk8CakuVuH5snnf1i7QQkhfu6h8apWZR+9+MZ7uuehp7X6xw3J53/+5X/JKwt3jLomeTLcc+B4ff/DOp10wjE685Tj1OyMhipZIiMpvNcMn6xlz83MnTdxopuVlaXR1/dQ80sG6+tv1/xt7xc0OyX5fOK6w613PqjDD62uUxoco/ObnaJDDzqgQFY0gAAEIBAXAghvXCrNPiEQEwIJeRyQeafefmraTsL7wJ3DdezRhxUovCu//E7TxvTLV3j/+rFkfxXerVu3qXWXYcoc1FWtzj5Z6elpGjv1QX37/Y9J4U08cnJy9N5HK/Xym+9r4fOLVXX/fXTvpCHJKw27fizZX4W35aXXq32rJrq0XbN8q5g4SX7pjff04hvL9MY7H2nijb2TUs0DAhCAAAQkhJcUQAACkSLgSnjf/XCFbrvrUb302O25PC/tO1qV9iifFN7Nv/0uKU3lypZOPp94c9wpF1ytR++6Ues2/Lxb4b3q+ttUec+KGjm4W+7YiTff7b9vZaWlKXl6nLhS8edjzJQH9O33azVl9A7R5gEBCEAg7gQQ3rgngP1DIGIEXAnvd6vXJd+k9q/ZmapedT/dOedJvb5kuUpkpOuh6SN03Y1Tk6SHXXtpUoJfffsD9fvnFL342O36eMVXuxXexJvW+o2Yqtsz+yQ/beL9j/9PCQlOnERXrFBeF11xk+4Y1VcNjztKP/+yOfmJD4fXOFBDru4YseqyHQhAAAJFI4DwFo0bvSAAgZAScCW8iTu8mbfdp6eeX5w8xe3U9myd2rCOul43NvmJDjf276Kbb5ujt5d9qt+3bFWNgw7Q1V3bJD/mLK9vWvvrlYYE6vvn/0f3PvJs8lMYqu6/t3pe0kqtzz01WYUFz72hmfcv1Lc/rFP5smXU5OR6ur5PJ5Uvt+MjzXhAAAIQiDsBhDfuCWD/EIAABCAAAQhAIOIEEN6IF5jtQQACEIAABCAAgbgTQHjjngD2DwEIQAACEIAABCJOAOGNeIHZHgQgAAEIQAACEIg7AYQ37glg/xCAAAQgAAEIQCDiBBDeiBeY7UEAAhCAAAQgAIG4E0B4454A9g8BCEAAAhCAAAQiTgDhjXiB2R4EIAABCEAAAhCIOwGEN+4JYP8QgAAEIAABCEAg4gQQ3ogXmO1BAAIQgAAEIACBuBNAeOOeAPYPAQhAAAIQgAAEIk4A4Y14gdkeBCAAAQhAAAIQiDsBhDfuCWD/EIAABCAAAQhAIOIEEN6IF5jtQQACEIAABCAAgbgTQHjjngD2DwEIQAACEIAABCJOAOGNeIHZHgQgAAEIQAACEIg7AYQ37glg/xCAAAQgAAEIQCDiBBDeiBeY7UEAAhCAAAQgAIG4E0B4454A9g8BCEAAAhCAAAQiTgDhjXiB2R4EIAABCEAAAhCIOwGEN+4JYP8QgAAEIAABCEAg4gQQ3ogXmO1BAAIQgAAEIACBuBNAeOOeAPYPAQhAAAIQgAAEIk4A4Y14gdkeBCAAAQhAAAIQiDsBhDfuCWD/EIAABCAAAQhAIOIEEN6IF5jtQQACEIAABCAAgbgTQHjjngD2DwEIQAACEIAABCJOAOGNeIHZHgQgAAEIQAACEIg7AYQ37glg/xCAAAQgAAEIQCDiBBDeiBeY7UEAAhCAAAQgAIG4E0B4454A9g8BCEAAAhCAAAQiTgDhjXiB2R4EIAABCEAAAhCIOwGEN+4JYP8QgAAEIAABCEAg4gQQ3ogXmO1BAAIQgAAEIACBuBNAeOOeAPYPAQhAAAIQgAAEIk4A4Y14gdkeBCAAAQhAAAIQiDsBhDfuCWD/EIAABCAAAQhAIOIEEN6IF5jtQQACEIAABCAAgbgTQHjjngD2DwEIQAACEIAABCJO4P8BmvLjmmfl0AkAAAAASUVORK5CYII=\n",
"text/plain": [
"<IPython.core.display.Image object>"
]
},
"execution_count": 20,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"df = pd.DataFrame(data)\n",
"df['millis'] = (df['t'] * 1000) / iterations\n",
"reference = df.groupby(['version','minhashes','tokens'])['millis'].median().old\n",
"df = df.loc[df['version'] == 'new'].groupby(['version','minhashes','tokens'])['millis'].median() / reference\n",
"df = df.reset_index()\n",
"df['tokens'] = df['tokens'].astype(str)\n",
"df['ratio'] = 1 / df['millis']\n",
"\n",
"fig = px.bar(\n",
" df,\n",
" y='ratio',\n",
" x='minhashes',\n",
" color='tokens'\n",
")\n",
"fig.update_layout(barmode='group')\n",
"fig.update_xaxes(type='category')\n",
"Image(fig.to_image(format=\"png\"))"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.8.6"
}
},
"nbformat": 4,
"nbformat_minor": 4
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment