{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# Fast TopK elements\n", "\n", "Looking for the top k elements is something needed to implement a simple k nearest neighbors. The implementation *scikit-learn* is using relies on *numpy*: [_kneighbors_reduce_func](https://github.com/scikit-learn/scikit-learn/blob/master/sklearn/neighbors/_base.py#L496). *mlprodict* also contains a C++ implementation of the same function. Let's compare them."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [{"data": {"text/html": ["
\n", ""], "text/plain": [""]}, "execution_count": 2, "metadata": {}, "output_type": "execute_result"}], "source": ["from jyquickhelper import add_notebook_menu\n", "add_notebook_menu()"]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": ["%matplotlib inline"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Two implementations\n", "\n", "We assume we are looking for the `k` nearest elements of every row of matrix `X` which is a dense matrix of doubles."]}, {"cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": ["import numpy.random as rnd\n", "from sklearn.neighbors._base import KNeighborsMixin\n", "\n", "mixin = KNeighborsMixin()"]}, {"cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([[2, 7, 3],\n", " [7, 0, 8],\n", " [1, 5, 6],\n", " [8, 9, 3],\n", " [4, 6, 5]], dtype=int64)"]}, "execution_count": 5, "metadata": {}, "output_type": "execute_result"}], "source": ["def topk_sklearn(X, k):\n", " return mixin._kneighbors_reduce_func(X, 0, k, False)\n", " \n", "X = rnd.randn(5, 10)\n", "ind = topk_sklearn(X, 3)\n", "ind"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Now the implementation with *mlprodict* (C++) available at [topk_element_min](https://github.com/sdpython/mlprodict/blob/master/mlprodict/onnxrt/ops_cpu/_op_onnx_numpy.cpp#L201). It uses [heap](https://en.wikipedia.org/wiki/Heap_(data_structure))."]}, {"cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": ["from mlprodict.onnxrt.ops_cpu._op_onnx_numpy import topk_element_min_double"]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [{"data": {"text/plain": ["array([[2, 7, 3],\n", " [7, 0, 8],\n", " [1, 5, 6],\n", " [8, 9, 3],\n", " [4, 6, 5]], dtype=int64)"]}, "execution_count": 7, "metadata": {}, "output_type": "execute_result"}], "source": ["def topk_cpp(X, k):\n", " return topk_element_min_double(X, k, True, 50)\n", " \n", "ind = topk_cpp(X, 3)\n", "ind"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Speed comparison by size"]}, {"cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["21.7 \u00b5s \u00b1 4.19 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n"]}], "source": ["%timeit topk_sklearn(X, 3)"]}, {"cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["4.1 \u00b5s \u00b1 435 ns per loop (mean \u00b1 std. dev. of 7 runs, 100000 loops each)\n"]}], "source": ["%timeit topk_cpp(X, 3)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Quite a lot faster on this simple example. Let's look for bigger matrices."]}, {"cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": ["X = rnd.randn(1000, 100)"]}, {"cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["1.8 ms \u00b1 102 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 1000 loops each)\n"]}], "source": ["%timeit topk_sklearn(X, 10)"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["786 \u00b5s \u00b1 116 \u00b5s per loop (mean \u00b1 std. dev. of 7 runs, 1000 loops each)\n"]}], "source": ["%timeit topk_cpp(X, 10)"]}, {"cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [{"name": "stderr", "output_type": "stream", "text": ["100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 10/10 [00:08<00:00, 1.16it/s]\n"]}, {"data": {"text/html": ["\n", "\n", "
\n", " \n", " \n", " \n", " average \n", " deviation \n", " min_exec \n", " max_exec \n", " repeat \n", " number \n", " context_size \n", " N \n", " name \n", " \n", " \n", " \n", " \n", " 0 \n", " 0.016310 \n", " 0.000260 \n", " 0.016050 \n", " 0.016571 \n", " 2 \n", " 2 \n", " 240 \n", " 1000 \n", " topk_sklearn \n", " \n", " \n", " 1 \n", " 0.003872 \n", " 0.000501 \n", " 0.003335 \n", " 0.004631 \n", " 4 \n", " 4 \n", " 240 \n", " 1000 \n", " topk_cpp \n", " \n", " \n", " 2 \n", " 0.034684 \n", " 0.001629 \n", " 0.033055 \n", " 0.036313 \n", " 2 \n", " 2 \n", " 240 \n", " 2000 \n", " topk_sklearn \n", " \n", " \n", " 3 \n", " 0.006973 \n", " 0.000558 \n", " 0.006307 \n", " 0.007756 \n", " 4 \n", " 4 \n", " 240 \n", " 2000 \n", " topk_cpp \n", " \n", " \n", " 4 \n", " 0.051934 \n", " 0.000851 \n", " 0.051084 \n", " 0.052785 \n", " 2 \n", " 2 \n", " 240 \n", " 3000 \n", " topk_sklearn \n", " \n", " \n", "
\n", "
"], "text/plain": [" average deviation min_exec max_exec repeat number context_size \\\n", "0 0.016310 0.000260 0.016050 0.016571 2 2 240 \n", "1 0.003872 0.000501 0.003335 0.004631 4 4 240 \n", "2 0.034684 0.001629 0.033055 0.036313 2 2 240 \n", "3 0.006973 0.000558 0.006307 0.007756 4 4 240 \n", "4 0.051934 0.000851 0.051084 0.052785 2 2 240 \n", "\n", " N name \n", "0 1000 topk_sklearn \n", "1 1000 topk_cpp \n", "2 2000 topk_sklearn \n", "3 2000 topk_cpp \n", "4 3000 topk_sklearn "]}, "execution_count": 13, "metadata": {}, "output_type": "execute_result"}], "source": ["from cpyquickhelper.numbers import measure_time\n", "from tqdm import tqdm\n", "from pandas import DataFrame\n", "\n", "rows = []\n", "for n in tqdm(range(1000, 10001, 1000)):\n", " X = rnd.randn(n, 1000)\n", " res = measure_time('topk_sklearn(X, 20)',\n", " {'X': X, 'topk_sklearn': topk_sklearn},\n", " div_by_number=True,\n", " number=2, repeat=2)\n", " res[\"N\"] = n\n", " res[\"name\"] = 'topk_sklearn'\n", " rows.append(res)\n", " res = measure_time('topk_cpp(X, 20)',\n", " {'X': X, 'topk_cpp': topk_cpp},\n", " div_by_number=True,\n", " number=4, repeat=4)\n", " res[\"N\"] = n\n", " res[\"name\"] = 'topk_cpp'\n", " rows.append(res)\n", "\n", "df = DataFrame(rows)\n", "df.head()"]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [{"data": {"image/png": "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", "text/plain": [""]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["import matplotlib.pyplot as plt\n", "\n", "fig, ax = plt.subplots(1, 2, figsize=(10, 4))\n", "piv = df.pivot(\"N\", \"name\", \"average\")\n", "piv.plot(ax=ax[0], logy=True, logx=True)\n", "ax[0].set_title(\"top 20\")\n", "piv[\"ratio\"] = piv[\"topk_cpp\"] / piv[\"topk_sklearn\"]\n", "piv[[\"ratio\"]].plot(ax=ax[1])\n", "ax[1].set_title(\"ratio\");"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Speed comparison by k"]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [{"name": "stderr", "output_type": "stream", "text": ["100%|\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2588| 68/68 [00:34<00:00, 1.95it/s]\n"]}, {"data": {"text/html": ["\n", "\n", "
\n", " \n", " \n", " \n", " average \n", " deviation \n", " min_exec \n", " max_exec \n", " repeat \n", " number \n", " context_size \n", " k \n", " name \n", " \n", " \n", " \n", " \n", " 0 \n", " 0.009558 \n", " 0.001392 \n", " 0.008166 \n", " 0.010949 \n", " 2 \n", " 2 \n", " 240 \n", " 1 \n", " topk_sklearn \n", " \n", " \n", " 1 \n", " 0.002665 \n", " 0.000571 \n", " 0.002094 \n", " 0.003236 \n", " 2 \n", " 2 \n", " 240 \n", " 1 \n", " topk_cpp \n", " \n", " \n", " 2 \n", " 0.021933 \n", " 0.000575 \n", " 0.021358 \n", " 0.022508 \n", " 2 \n", " 2 \n", " 240 \n", " 2 \n", " topk_sklearn \n", " \n", " \n", " 3 \n", " 0.001000 \n", " 0.000084 \n", " 0.000917 \n", " 0.001084 \n", " 2 \n", " 2 \n", " 240 \n", " 2 \n", " topk_cpp \n", " \n", " \n", " 4 \n", " 0.025986 \n", " 0.001411 \n", " 0.024575 \n", " 0.027398 \n", " 2 \n", " 2 \n", " 240 \n", " 3 \n", " topk_sklearn \n", " \n", " \n", "
\n", "
"], "text/plain": [" average deviation min_exec max_exec repeat number context_size k \\\n", "0 0.009558 0.001392 0.008166 0.010949 2 2 240 1 \n", "1 0.002665 0.000571 0.002094 0.003236 2 2 240 1 \n", "2 0.021933 0.000575 0.021358 0.022508 2 2 240 2 \n", "3 0.001000 0.000084 0.000917 0.001084 2 2 240 2 \n", "4 0.025986 0.001411 0.024575 0.027398 2 2 240 3 \n", "\n", " name \n", "0 topk_sklearn \n", "1 topk_cpp \n", "2 topk_sklearn \n", "3 topk_cpp \n", "4 topk_sklearn "]}, "execution_count": 15, "metadata": {}, "output_type": "execute_result"}], "source": ["rows = []\n", "X = rnd.randn(2000, 1000)\n", "for k in tqdm(list(range(1, 20)) + list(range(20, 1000, 20))):\n", " res = measure_time('topk_sklearn(X, k)',\n", " {'X': X, 'topk_sklearn': topk_sklearn, 'k': k},\n", " div_by_number=True,\n", " number=2, repeat=2)\n", " res[\"k\"] = k\n", " res[\"name\"] = 'topk_sklearn'\n", " rows.append(res)\n", " res = measure_time('topk_cpp(X, k)',\n", " {'X': X, 'topk_cpp': topk_cpp, 'k': k},\n", " div_by_number=True,\n", " number=2, repeat=2)\n", " res[\"k\"] = k\n", " res[\"name\"] = 'topk_cpp'\n", " rows.append(res)\n", "\n", "df = DataFrame(rows)\n", "df.head()"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [{"data": {"image/png": "iVBORw0KGgoAAAANSUhEUgAAAmEAAAEaCAYAAABZ+IDUAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4yLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy8GearUAAAgAElEQVR4nOydeXxU5fX/389MJvu+EJYAYd/3EEBkU0ERUcEVrYq41Lr021rb0v6otWrVamvR1qUuuCuouAsuqMimEJawB0JIQjay75kkszy/P+7MZJJMkgkkmUl43q/XvJi593nuPTND7v3MOec5R0gpUSgUCoVCoVB0LTpPG6BQKBQKhUJxLqJEmEKhUCgUCoUHUCJMoVAoFAqFwgMoEaZQKBQKhULhAZQIUygUCoVCofAASoQpFAqFQqFQeAAlwhQOhBDLhRDb3BwrhBCvCSFKhRC7Ots2hUKh6I4IIV4UQvzF03YovBMlwroZQogMIcRFnrYDOB+YD8RJKRPP9mBCiOFCiE+FEIVCiBIhxNdCiBFNxvxWCHFaCFEuhFgjhPBz2hcphPhYCFEthMgUQtzQZO6FQogUIUSNEOIHIcTAs7VZoVAonHH1Q1ZKeZeU8hFP2aTwbpQIU5wpA4EMKWV1eycKIXxcbA4HPgNGALHALuBTpzkXAyuBC4F4YDDwN6f5zwH1trk3Ai8IIcbY5kYDHwF/ASKB3cA6N20VQgj1d6JQKFq6dikUZ4y6uXQjhBBvAQOAz4UQVUKIP9i2Xy6EOCyEKBNCbBZCjHKakyGE+JMQ4ogtdPiaEMLfzfM9JYTYJoQIa7L9NuAVYIbNjr/Ztt8hhDhh82R9JoTo6zRHCiHuEUKkAqlNzyWl3CWlfFVKWSKlNAH/BkYIIaJsQ24BXpVSHpZSlgKPAMttxw4CrgL+IqWsklJuQxN0N9nmLgUOSyk/kFLWAg8BE4QQI1t435uFEH8XQmwHaoDBQojzhBBJNi9ckhDiPNvYeUKIg05zNzmHZ22f35W2538UQuQIISqFEMeEEBe2+SUoFAqPYruG/lEIcQCoFkKsEkKk2f6OjwghltjGjQJepOG6WGbb/roQ4lGn47V4nVSceygR1o2QUt4EnAIWSymDpZRPCiGGA+8BvwFigA1oIs3XaeqNwMXAEGA4sKq18wghdEKIl4HxwAIpZXkTO14F7gJ+stnxVyHEBcDjwLVAHyATWNvk0FcC04DRbrzd2cBpKWWx7fUYYL/T/v1ArE2kDQcsUsrjTfaPcTXX5r1Lc9rvipuAO4EQoBL4EngWiAKeBr60nfsnYKgQItr2K3ksECeECBFCBABTgK220Oq9wFQpZQja95HhxuegUCg8zzJgEZrH/hgwCwhD88a/LYToI6U8SuPrYnjTg7h5nVScQygR1v25DvhSSvmtzYP0TyAAOM9pzH+llFlSyhLg72gXlJYwoIm6SDSxV+OmHTcCa6SUe6WUdcCf0H4RxjuNedzm6TK2diAhRBxaePF+p83BgLMYtD8PcbHPvj+khblN97vidZvXzQwsAFKllG9JKc1SyveAFLTPpxYtvDkbSAAOANuAmcB027xiwAL4AaOFEAYpZYaUMq21z0GhUHgNz9quoUabRz1XSmmVUq5D8+y7mxfrznVScQ6hRFj3py/arykApJRWIAvo5zQmy+l5pm1OSwwFrgD+JqWsPws7qoDiVuxwiRAiBvgGeN4mduxUAaFOr+3PK13ss++vbGFu0/2ucLa10XuzkUnDe/sRmIsmxH4ENgNzbI8fAaSUJ9C8lQ8BBUKItSoMoVB0GxzXAyHEzUKIZFv6Rxma9zvazeO4c51UnEMoEdb9kE1e56IlyQNaIjnQH8hxGtPf6fkA25yWOArcCmxsujqxDZraEYQWunO2o6ntjRBCRKAJsM+klH9vsvswMMHp9QQg3+ZlOg74CCGGNdl/2NVcm21DnPa7wtnWRu/NxgAa3ltTEfYjTUQYgJTyXSnl+bZjSeAfrZxfoVB4DxLAtqr6ZbTUgihbyPEQIJzHtYI710nFOYQSYd2PfLSVgXbeBxbZSjAYgN8BdcAOpzH3CCHihBCRwJ9pY2WgzQP1Z2CTEGKIm3a9C9wqhJgotNIRjwE7pZQZ7kwWQoQCXwPbpZQrXQx5E7hNCDHaJtZWAa/b7K1GW/34sBAiSAgxE82b95Zt7sfAWCHEVbZFCQ8CB6SUKW6+tw3AcCHEDUIIHyHEdWh5bV/Y9u9AW9WZCOySUh5Gu9BOA7bY3t8IIcQFts+mFjCihSgVCkX3IQhNaBUCCCFuRfOE2clHywn1dTEXzvI6qeh5KBHW/XgcWGVzhT8gpTwG/AL4D1AELEbLVXIOJb6L5mE6aXs8ShtIKd8AHga+dydfQUr5HVoJiPVAHpqn6Xr33xZLgKloF6gqp8cA2/G/Ap4EfkBz52cCf3WafzdaLlwBWk7br2xiCCllIdrqyb8DpWjiyG3bbN62y9AEbjHwB+AyKWWRbX81sBdtBab9c/8JyJRSFthe+wFPoH1Hp4FeaEJXoVB0E6SUR4B/of195wPjgO1OQ75H87CfFkIUuZh/ttdJRQ9DSNmW91TRnRFCZAC3Syk3edoWhUKhUCgUDShPmEKhUCgUCoUHUCJMoVAoFAqFwgOocKRCoVAoFAqFB1CeMIVCoVAoFAoPoESYQqFQKBQKhQfw6o7w0dHRMj4+3tNmKBSKLmLPnj1FUsoYT9vREajrl0Jx7tHea5hXi7D4+Hh2797taTMUCkUXIYRo2h6q26KuXwrFuUd7r2EqHKlQKBQKhULhAZQIUygUCoVCofAASoQpFAqFQqFQeACvzglzhclkIjs7m9raWk+bck7j7+9PXFwcBoPB06YoFGeNEOIS4BlAD7wipXzCxZi5wGrAABRJKed0qZEKRTfgXLlHd9Q9sNuJsOzsbEJCQoiPj0cI4WlzzkmklBQXF5Odnc2gQYM8bY5CcVYIIfTAc8B8IBtIEkJ8ZmvWbB8TDjwPXCKlPCWE6OUZaxUK7+ZcuEd35D2w24Uja2triYqK6rFfbndACEFUVFSP/6WjOGdIBE5IKU9KKeuBtcAVTcbcAHwkpTwFIKUs6GIbFYpuwblwj+7Ie2C3E2FAj/5yuwvqO1C0SHUxlOd42or20A/IcnqdbdvmzHAgQgixWQixRwhxs6sDCSHuFELsFkLsLiws7CRzvZtak4UTBVWeNkPhQc6F+0NHvcduKcIUCoUX8/RI+PdoT1vRHlxdTZs21fUBpgCLgIuBvwghhjebJOVLUsoEKWVCTEyPqDnbbtbuOsWiZ7dirLd42hSFwutRIkyhUHQslnpPW9BesoH+Tq/jgFwXY76SUlZLKYuALcCELrKvW5FbXkud2UppTbf7f6BQdDlKhJ0lGRkZjBo1ijvuuIMxY8awYMECjEYjL7/8MlOnTmXChAlcddVV1NTUALB8+XJ+9atfMW/ePAYPHsyPP/7IihUrGDVqFMuXL3cc95tvvmHGjBlMnjyZa665hqoq5d5XKDqJJGCYEGKQEMIXuB74rMmYT4FZQggfIUQgMA042sV2dgtKqjXxVW40edgSRXfkXLunKhHWAaSmpnLPPfdw+PBhwsPDWb9+PUuXLiUpKYn9+/czatQoXn31Vcf40tJSvv/+e/7973+zePFifvvb33L48GEOHjxIcnIyRUVFPProo2zatIm9e/eSkJDA008/7cF3qFCcAebu4QmRUpqBe4Gv0YTV+1LKw0KIu4QQd9nGHAW+Ag4Au9DKWBzylM3eTFlN2yJMSsmz36VystA7boR26swWthw/N3P5vIlz6Z7a7UpUeCODBg1i4sSJAEyZMoWMjAwOHTrEqlWrKCsro6qqiosvvtgxfvHixQghGDduHLGxsYwbNw6AMWPGkJGRQXZ2NkeOHGHmzJkA1NfXM2PGjK5/YwrF2XBgLRzbCNe/C16eqCul3ABsaLLtxSavnwKe6kq7uiPueMLKakw8/e1xAH594bAuscsdPt+fxwMf7Oeze2cyPi7c0+acs5xL91SvFGFCiMXA4qFDh3raFLfw8/NzPNfr9RiNRpYvX84nn3zChAkTeP3119m8eXOz8TqdrtFcnU6H2WxGr9czf/583nvvvS57DwpFh/PZfdq/+Yeh91jP2qLoMkprNPHVqgiz7aus9a6QZZrNM7ftRJESYR7kXLqnemU4Ukr5uZTyzrCwME+bcsZUVlbSp08fTCYT77zzTrvmTp8+ne3bt3PixAkAampqOH78eGeYqVB0LK5CkCd/6Ho7FB7DnpBf0aonTBtTWWvuEpvc5VSxlme040Sxhy1RNKWn3lO9UoT1BB555BGmTZvG/PnzGTlyZLvmxsTE8Prrr7Ns2TLGjx/P9OnTSUlJ6SRLFYoOpK6y+bY0JcLOFSxW6fCAueMJq/AyT1hGcTUASRkl1JlViQ1voqfeU4WUTcvheA8JCQly9+7djbYdPXqUUaNGecgihTPqu1A0oyQdnp3Y8Dp+Flz7JgRGujVdCLFHSpnQSdZ1Ka6uXz2dkup6Jj/yLQA3zxjIw1e4DkN/si+H36xLZtawaN66bVpXmtgiUkrGPfQNEUEGskqMvHfHdGYMifK0Wd2Oc+m+4Oq9tvcapjxhCoWi46iraPx6xEK3BZii+2NPyoe2EvPbDll2NcXV9VTVmblmSn90An5KK/K0SYpzACXCFApFx9E0HBnW3/U4RY+krMZNEeZIzPeenLBMWyhyXL8wxseFsz1N5YUpOh8lwhQKRcdR28QTNmi2Z+xQeAS7Jyw80NBmiQrwrpywTFtS/oCoQM4bEsX+rDKq6rxHJCp6JkqEKRSKs0NKqCkBqxWKjmnbLnkCfr0PAtQy/3MJu7gaGBXUqgiz76sweo/IySiuQScgLiKAmUOjMVslSeklnjZL0cPxyjphCoWim2C1wEd3wKH1EDkEStK07WOvhuBzs4H1uUyJLRw5KCqQbSdazqmyhy3rLVZqTRb8Dfousa81Mour6RsegJ+PnikDI/D10bEjrYh5I3t52jRFD0aJMIVCcWbk7Yf3boCKbBhyIaR9B/5hMOePSoCdo5TW1OPro6N3WADlRhNSSoSLbgllTl6yilqTV4iwjOIa4qOCAPA36JkyIILtql6YopNR4UiFQtF+6qthwx/AUgfXvA43fQQrvoFfJ8OMezxtncJDlFbXExFoICzAgMkiMZpc19oqN5rQ2bSZtyTnZxZXMzAq0PH6vCFRHMmroLS6e/RAVbSf1atXOxqBA1x66aWUlZV1qQ1KhLWTsrIynn/++TOeHxwc3IHWKBQeoCgVnh4FWT/DvD/DmCXa9gHTVDmKc5zSGhMRgb6EBRiAlldIlteY6BMWAHhHmYryGhNlNSaHJwzgvKHRAPx0UnnDujNSSqxWq8t9TUXYhg0bCA/v2jxWJcLaydmKMIWi2+F8AcvdB1//GSxmuOF9mHKr5+xSeB2aJ6x1ESalpMxoon+kTYR5gScss0QrTzHAyRM2Pi6MIF89O1S9sG5HRkYGo0aN4u6772by5MncdtttJCQkMGbMGP76178C8Oyzz5Kbm8u8efOYN28eAPHx8RQVad/3008/zdixYxk7diyrV6/uNFu7dU7Y3z4/zJHcirYHtoPRfUP56+IxLe5fuXIlaWlpTJw4kfnz5wOwceNGhBCsWrWK6667js2bN/Pggw8SFRXFsWPHmD17Ns8//zw6XYPmLSoqYvHixaxatYpFixa5PNeTTz7JW2+9hU6nY+HChTzxxBPMnTuXiRMnsmvXLioqKlizZg2JiYk89NBDpKWlkZOTQ1ZWFn/4wx+44447OvSzUZxjZCXBT/+BlA0QEQ8jF8F228Vozh9h+MUeNU/hfZTW1DOyd2iDCKtpLsKq6sxYrJL+EYH8TIlXNPHOsJWncPaEGfQ6pg2OUn0kzwJP3KPtHDt2jNdee43nn3+ekpISIiMjsVgsXHjhhRw4cIBf//rXPP300/zwww9ER0c3mrtnzx5ee+01du7ciZSSadOmMWfOHCZNmtSh7wW6uQjzBE888QSHDh0iOTmZ9evX8+KLL7J//36KioqYOnUqs2drdZF27drFkSNHGDhwIJdccgkfffQRV199NQD5+flcfvnlPProow4h15SNGzfyySefsHPnTgIDAykpaVgqXV1dzY4dO9iyZQsrVqzg0KFDABw4cICff/6Z6upqJk2axKJFi+jbt28nfyKKHsnBD2H9beAfDpNv0gTZ9tXQazQsfhb6Tmz7GIpzjtIaE+G2nDBw7Qmzl7EYEKl5nbyhTEVmkc0TFhnYaPt5Q6L4PqWAvHKjI3yq6B4MHDiQ6dOnA/D+++/z0ksvYTabycvL48iRI4wfP77Fudu2bWPJkiUEBWmifOnSpWzdulWJsKa4o4Y7k23btrFs2TL0ej2xsbHMmTOHpKQkQkNDSUxMZPDgwQAsW7aMbdu2cfXVV2Mymbjwwgt57rnnmDNnTovH3rRpE7feeiuBgdpFITKyIddm2bJlAMyePZuKigpHIuEVV1xBQEAAAQEBzJs3j127dnHllVd21ttX9FSkhK3/0gTXbd+CXzDU18COZ2HsVRA9zNMWKrwQq1VSVlNPZFDr4Uj7tv42weMtnrDeof4E+DZepXneEM1DsuNEMVdNifOEad0aT96j7QIqPT2df/7znyQlJREREcHy5cupra1tdW5X9tRWOWFnQWtfVNNl2fbXPj4+TJkyha+//rrNY7ta2t3asVvarlC0i7TvoOAIzLhXE2AAvoEwd6USYIoWqag1YZUQ3kZOmN0T1ifMH71OeEXV/KYrI+2M7B1CZJAvO1QLo25LRUUFQUFBhIWFkZ+fz8aNGx37QkJCqKysbDZn9uzZfPLJJ9TU1FBdXc3HH3/MrFmzOsU+JcLaifOXNnv2bNatW4fFYqGwsJAtW7aQmJgIaOHI9PR0rFYr69at4/zzzwc0YbRmzRpSUlJ44oknWjzPggULWLNmjWPlhnM4ct26dYDmiQsLCyMsLAyATz/9lNraWoqLi9m8eTNTp07t+A9A0bM5+SN8uELr+Tjuak9bo+hGlNrEVWSQgRB/H4RwvfKxzKiVfIgI8iXE38crSlRkltS4FGE6nWDG4Ci2nyjqUu+IouOYMGECkyZNYsyYMaxYsYKZM2c69t15550sXLjQkZhvZ/LkySxfvpzExESmTZvG7bff3imhSOjm4UhPEBUVxcyZMxk7diwLFy5k/PjxTJgwASEETz75JL179yYlJYUZM2awcuVKDh48yOzZs1myZInjGHq9nrVr17J48WJCQ0O5++67m53nkksuITk5mYSEBHx9fbn00kt57LHHAIiIiOC8885zJObbSUxMZNGiRZw6dYq//OUvKh9M4T61FZDyJXx2H0QNhRvWgY+fp61SdCMa+kb6otMJQvx8WvWEhQcYCPU3eLxERXWdmcLKOgY6JeU7c/6waL48mMeJgiqGxYZ0sXWKMyE+Pt6RKw3w+uuvuxx33333cd999zleZ2RkOJ7ff//93H///Z1logMlws6Ad999t9Hrp556qtmYwMBAh8fKmaqqKgB8fX3bDEmuXLmSlStXNtt+1VVX8fjjjzfbPnz4cF566aVWj6lQNOLIp7Djv5C9S3vdf7omwFTPR4ULNhzMY0BkIGP7hTXbZ29FFBnoC0BYC0287dtCAwyEBvh4vERFpouVkc7MGqblhW1JLVIiTNHhqHCkQnGusutleP9mqKuAOSvh+nfh5k+VAFO4pN5s5f73k3lhc5rL/XZPWIRdhAW4FmFlNfUEGPT4G/SE+Bm6LDHfbLFisjQv2plZrK2MdBWOBIiLCGRwTBBbUws71T7FuYnyhHUCc+fOZe7cuW6NPXjwIDfddFOjbX5+fuzcudPl+M2bN7vc/tBDD7XDQsU5T24ybHgARlyqtR1SoUdFGxzMKaPWZCWrtMblfnuYMSJIS8pvWYRpZSwAQgN8yChyfbyO5q639wCCV25JaLTdXiOsJREGMHtYDGuTTlFntuDn4/k+l4qeQ5eJMCHEYOD/AWFSSpXxa2PcuHEkJyd72gzFucbuV8EQCEteVAJM4RY707XFQdmlRpf7S2rq8dEJgv2020pYgIHT5c1LAZQZTY7VkyH+XecJO5xbQV55LWmFVQyJaWgfd6qkmuhgX0L8DS3OnTUsmtd3ZLAno9TRzkjRMq2t7u8pdNRCDbfCkUKINUKIAiHEoSbbLxFCHBNCnBBCNE9eckJKeVJKedvZGKtQKDqA2nKtGOu4q8G/eW6PQuGKnSc1EVZSXU91XfM8rrKaeiKCfB03X80T1nxcubMnzN/QJTlhZouV/ApNEL7z86lG+zKKapoVaW3K9MFRGPSCLamqhVFb+Pv7U1xc3KNXk0opKS4uxt/f/6yP5a4n7HXgv8Cb9g1CCD3wHDAfyAaShBCfAXqgadb4CillwVlbq1Ao2o/VCjodWC1w+GNtFaSpBhLUbyKFe5gtVvZklhId7EtRVT3ZpUZG9G6cpF5SXU9EYIM3KTTAQLmxvplXpMxYz+DoYNsYH0cbI72u8zwn+ZV1WCUEGPR8uCeL3188wlGYNbO4mumDo1qdH+Tnw+QBEWxNLWTlwpGdZmdPIC4ujuzsbAoLe3YOnb+/P3FxZ1/A1y0RJqXcIoSIb7I5ETghpTwJIIRYC1whpXwcuOxMDRJC3AncCTBgwIAzPYxCoQDY+Ec4+rnWbPvg+7D9GRB6GH+daj2kcJujeZVU1Zm5NmEQa7ank1VS00yEldaYHEn5oHnCTBaJ0WQh0LfhVuOcE2YPAVbVmgkLbDkceLbklWkh1FtnxvP85jQ+35/LtVP7U2uykFte22J5CmdmD4/hqa+PUVhZR0zImYXwX9ueTlSwH5dP6LnlgwwGA4MGDfK0Gd2Gs1kd2Q/IcnqdbdvmEiFElBDiRWCSEOJPLY2TUr4kpUyQUibExMSchXkKxTnO7jWw80WoKYZXF2gCLGEFrCqApaqUicJ9dqZrFeOvmqJd4rNdJOeXVtc3E2HQuGq+lFLLCXOEIzVx1tlV83NtuWlXTurH8Nhg3vw5AyklWSW28hTRrYcjoaFUxfYTZxaSLK2u5/ENKbyxI+OM5it6Jmcjwlz5jlsMAkspi6WUd0kph9i8Zd2SsrIynn/++TOeHxwc3Pagds7PyMhg7NixZ3VcRQ8jYxts+AMMnQ93/wQhvWHIBbDwSdCrRdFNaSu/VQgxVwhRLoRItj0e9ISdnmJnegnxUYGM7hNKgEFPlovk/NIak2NlJLgWYbUmK/VmK+EBmlize8I6XYTZPGF9wvy5afpADuVUsD+73FEjzB1P2Ni+YUQEGthyhqUqPk3Ood5iJcPWLFyhgLMTYdlAf6fXcUDu2Znj/ZytCPNmpJRYrc3r6Ci6GQUpsPYGiIiHq16ByMFwbxLcuB70nRfy6a445bcuBEYDy4QQo10M3SqlnGh7PNylRnoQq1WSlFFC4qBIhBDERQQ084RJqTXvdukJq2kQWPaWRc4lKgAqXCTwdyR5ZUZC/H0I8Tdw5aR+BPnqeeunTDJsNcLiWylPYUenE5w/LIatqWfWwuj93dkAFFfXe0W/TGfyyo1YrT03kd6bOZufxEnAMCHEICAHuB64oSOMEkIsBhYPHTq09YEbV8Lpgx1xygZ6j4OFLfd0XLlyJWlpaUycOJH58+drZmzciBCCVatWcd1117F582YefPBBoqKiOHbsGLNnz+b5559Hp2vQvEVFRSxevJhVq1axaNGiZufJy8vjuuuuo6KiArPZzAsvvNCogajz/DFjGjrVWywWVq5cyebNm6mrq+Oee+7hl7/8JVVVVVxxxRWUlpZiMpl49NFHueKKK8jIyHD0zvrpp59YvXo1d911F+effz47duygX79+fPrppwQEBHTEp6voCKwW+ORuqC6AWb+D/tMg5Qs49hVIC2RsB70f/GJ9Q+FVnapt1Aou81uBIx61yks4XlBJWY2JxEFa8romwhp7wirrzJitss1wpP15eEDD6kig08tU5JTV0jdMu4aF+BtYMrkf7+/Ops4cS6i/D+FOdrfGrGHRfL4/l2P5lYzsHer2+Q/llHMkr4KZQ6PYfqKYzKIaxsV5x8rk7NIa5j61mdXXT+Sy8T03V81bcbdExXvAT8AIIUS2EOI2KaUZuBf4GjgKvC+lPNwRRkkpP5dS3mlvTO1NPPHEEwwZMoTk5GSmT59OcnIy+/fvZ9OmTfz+978nLy8P0Bp4/+tf/+LgwYOkpaXx0UcfOY6Rn5/PokWLePjhh10KMNBaI1188cWO40+cONGt+a+++iphYWEkJSWRlJTEyy+/THp6Ov7+/nz88cfs3buXH374gd/97neOX3PHjh3j5ptvZt++fQwcOJDU1FTuueceDh8+THh4OOvXr+/oj1FxNnzzFziwFnL2wuuL4B/x8MFySPsOcvZAUBTc+D5EDPS0pd0Fd/NbZwgh9gshNgohxrjYjxDiTiHEbiHE7p6yOmyXrT7YtEGRAPSPDHTkUtkprW5oym3HlQizF3QNC2wswjq7TEVeuZG+4Q3lBH4xfSD1ZitfHswjPrrtUKQde17Y1uPtywv7cE82vj46fn3BMACHB84b2JFWjNkqOX660tOmnJO4uzpyWQvbNwAbOtSi9tCKx6or2LZtG8uWLUOv1xMbG8ucOXNISkoiNDSUxMREBg8eDMCyZcvYtm0bV199NSaTiQsvvJDnnnuOOXPmtHjsqVOnsmLFCkwmE1deeaVDhLU1/5tvvuHAgQN8+OGHAJSXl5OamkpcXBx//vOf2bJlCzqdjpycHPLz8wEYOHAg06dPdxxj0KBBjvNNmTKlUVNThYfZvQZ+fg6m3QUXPQR739TE2NilMPQi5fE6M9zJb90LDJRSVgkhLgU+AYY1myTlS8BLAAkJCT0ivrMzvYS+Yf7ERWiepLiIACpqzZQ7FV0ttVfLD2w9J6yhebcm1hrCkZ3rCcsrr2VC/4Z2XCN7h5IYH8mujBK38sHs9AkLYFivYLakFnLH7MFuzak1Wfh4Xw4Xj+nN+DjNBm/KC7OL7Owy10V4FZ2L6h15FrSWF9C0WrD9tY+PD1OmTGmzeffs2bPZspeQDFYAACAASURBVGUL/fr146abbuLNN990a76Ukv/85z8kJyeTnJxMeno6CxYs4J133qGwsJA9e/aQnJxMbGwstbXaiqGgoMYXIT+/huXXer0es9mzDXYVNjJ3wJcPwLAFcPFjYAiAab+Epf+D4RcrAXbmtJnfKqWskFJW2Z5vAAxCiB5fOl1Kyc6TDflgAP0jtPwp57wwV56wEH8DQjQWWOVNcsLs1fUrO9ETZqy3UFJdT9+wxoU1b5yulUByJx/MmVnDYtiVXkKtyeLW+E1H8yk3mrg2IY4AXz29Q/0drZI6m+9T8vn9B/tbvVftaqMTgqJzUSKsnYSEhFBZqbltZ8+ezbp167BYLBQWFrJlyxYSExMBLRyZnp6O1Wpl3bp1nH/++YAmxtasWUNKSgpPPNGyJy8zM5NevXpxxx13cNttt7F371635l988cW88MILmEzahe/48eNUV1dTXl5Or169MBgM/PDDD2RmZnbo56LoZGpKYP0dWojxqleV4OpYHPmtQghftPzWz5wHCCF6C5sKEUIkol07i7vc0i4mvaiaoqo6pjkVM41ziLCGm3ZpTePm3QB6nSDEz8d1ONLmJfPR6wjy1XdqonpeuWZn3/DGea0Lx/bhqslxXDymd7uON2t4NHVmq0O8tMX7u7PpFx7AeUM0zR4fHdhl4cjP9+fxwZ5s0gqrXO4/XV7LqZIa9DpBjhJhHsEr16q7nZjvAaKiopg5cyZjx45l4cKFjB8/ngkTJiCE4Mknn6R3796kpKQwY8YMVq5cycGDB5k9ezZLlixxHEOv17N27VoWL15MaGgod999d7PzbN68maeeegqDwUBwcLDDE+Zq/qWXXurYd/vtt5ORkcHkyZORUhITE8Mnn3zCjTfeyOLFi0lISGDixImMHKmqPncbpITPfw1V+XD7t+DvfkKwom2klGYhhD2/VQ+skVIeFkLcZdv/InA18CshhBkwAtfLntyXxYZdaCTa8sEA+kdqYsY5L6zE5gmLbJLgHhbYuIl3mdGEQS8I9G34EdHZ/SPzbDXC+oQ1FmG+Pjr+de2Edh9v2qBIfPU6fjxeyOzhrdeyzC0zsjW1kPsuGOboCBAfFcSmo/ntPu+ZcNImvr5PKWBor5Bm+3dlaN/v7GHR/Hi8EJPFikGvfDNdiVeKMCnl58DnCQkJd3jaFle8++67jV4/9dRTzcYEBgaybt26ZturqrQ/Cl9f31ZDkrfccgu33HKL2/MPHdLaeup0Oh577DEee+yxZnN/+uknl+eyzwWIj49v9PqBBx5o0UZFF7F7jVb1fv4j0HeSp63pkbjKb7WJL/vz/6K1bjun2JleQnSwL4OdktfDAgwE+/k08oSV1ZjQCQjxb3xL0fpHNvaEhQX4NkrXCA3w6dQSFTlldk/Y2ff5Awj09WHGkCi+O5rPqkWjWm1UvX5PNlLCNVMa2tvERwdRVFVPZa2p1abhZ4uUkpO23LPvUwq4c/aQZmN2pRcT7OfD/NG9+eFYIafLa+nfRh9NRceiJK9C4a1YLbD5CdjwgFZodca9nraoVUqr67llzS6Hh2RHWhH3r0umpl7lFHZXdqU3zgcDXNYKK7HVCNM16f/YVISVG+sd+WB2QvwNVNZ1oiesTPOE9Q7rGBEGcNHoWDKKa0grbDmsaLVKPtiTzXlDohoJG3sOWmYn54UVV9dTWWsmItDA7oxSlyHfXeklTBkY4bApy0UnBEXnokRYJzB37ly++OILt8YePHiQiRMnNnpMmzatky1UeIy6KsjeDXve0Po6bvwjFBxtPq48G95YDJsfh3HXwrVvak24PUx+RS1mi+uCvh/syeLH44XMevIHHvhgP49+cZSP9uXwx/UdXMtP0SVkl9aQU2Zk2qDmza3jIgKbeMKaiytw7Qmz1wizE+rfuZ6wvHIj0cF++Pl0XB7lRaN6AbQaVtyZXsKpkhquTejfaLt9NWZ6J6+QPGkTiL+YPhCzVTYrq1FSXc/x/CoSB0W6zPNTdA1eGY5sKydMStmqC7g7MW7cOJKTkz1tRrs5B9JhOp69b8Fn9+GofmAIBGnV+jsOuQCm3gGVeXDkU63tkI8/XPkiTHRZIabLKa8xMeepH/jb5WO4buqAZvtT8xuSfz/ck41eJ/D10bF0UostZRVezM6TzfPB7MRFBPBTWpHjWlxSXU9kUPOCp5oIaxBYZTWmZmHB0ACDI2zWGeSUGTssFGmnT1gAY/uFsulIPnfNaR7mA1iXdIoQP59mif8DHZ6wzhVh6UXa3+PSyXG8+VMm36cUsGh8H8f+pIyG+m+9w/zRCSXCPIFXirDWcsL8/f0pLi4mKiqqxwix7oaUkuLiYvz9O/bC1qMx18H3j2o5XbMfgF6jIDwejKWwZw3segXW2sRW1FA4/zcw6SaIHORRswFq6s1c/t/tXDKmN7UmayOxZcdssbIjrfFiQYtV8s7t05g+uLknReH97MsqJcTfhxGxzRO6+0cGUl1voazGRESQL2U1Jpe5RKEBBiqMJodYKzeaGNWn8cKSEH+fTi1RkVdey9CYs+vZ64qLRsXyzHepFFXVER3s12hfaXU9Gw6d5vqp/QnwbeyBC/T1ITbUr9PLVJwsrMbXR8eAyEDmDI/hx+MFWK3SETLelV6Cn4+OcXFh+Pro6B3q77Ixu6Jz8UoR1hpxcXFkZ2fTU6pRd1f8/f2Ji4tre6BC48A6qDoNS17QvF52gqJg9u/hvP+DtO8hfIAm0LzoB8ax05WcKKjildKTQMNqs4LKWmKC/RBC8NiGFEcCtDMJAyO61FZFx3GqxMig6KBmeV6Ao3BrVmkNEUG+lFTXMyEuvNm4sAAD9RYrtSYrAb56l2HLUP/GQq0jkVKSW2Z0VLrvSC4aFcvqTal8n1LQLOT40b4c6s1WbpjW3GMM2grJzi7YerKomvioQPQ6wQUje/HZ/lwO5JQz0Va0dld6CZMGhDvCtE1DzIquoduJMIPBwKBBnvcOKBRuY7XA9meh93gYPM/1GB9fGHFJ19rlJvbk41qTlguWW25k76lSlj6/g8RBkbx8cwLv7TrFVZPjWLVoFFtSC/m/tcnERwXio5a7d1uyS2tcesHAuWCrkXH9wrRcryDXOWGgVc3X6wTV9ZZmOWEh/gbMVukQah1JhdFMTb2FfuEd3/t2TN9Q+oT5s+lIfiMRJqXk3Z2ZTBoQ3mJ/yfioIL5LKehwm5w5WVjF0F6aB3DO8Bh0QlslObF/OJW1Jg7nlnPvBQ1NH+IiAtjpZu0zRcehrpAKRWeT8iUUp2ohRi/ycLnLySaFHk+X1/LVodOA9mv6398ex2iycNXkfkQE+XLFxH58cd/5fHz3TE+Yq+gApJTklBodHq+mxNlqhWWX1lBdb6HeYm1WIwwaizBH8+6mnjB766JOqBWWayvU2rRGWEcghOCiUbFsTS1qVD0/KaOUtMJqbkh07QUDe5mKuk6rj2a2WDlVUsNgWxg2IsiXSQMi+MEm/PZklmKVDf1AAfpFBJBXbsTUwsIbReegRJhC0ZlICdtXQ0Q8jLrC09a0SJ3Zwq/e3uNI1rVv++rQaY7nVzoKTYK2QvLbI/mM7K15SV7fkUFEoKFRAvfYfmGNWtgouhdFVfXUma2OVXNNCfU3EBZgIKvE2NCyqE0Rpo0LazLOXivLVf/I6jozBZW1Z/w+cm0h8j4dnJhv56LRsRhNFnakNaw8fHdnJiH+Plw2vm+L8zq7TEVOmRGTRTLIqb7bBSN7cTCnnIKKWnall+CjE0wa0BBCjosIwCq1H1mKrsMrRZgQYrEQ4qXy8nJPm6JQnB0Z2yBnD5x3H+g9G/0vrKzjktVb2J9V1mzfh3uy2XjoNJ/sy3Fse2ZTKne9vYdNRws4f2g00wdHctn4Pliltrz+2oT+xIRoCcmzhsWo0GMPwp6g3VoYz14rzNGyqIXVkaCJsIbm3c1LVABUuEjOf3zjUS7/z/YWy6K0Ra5NUHRGOBJg+uBIgnz1fHtE8zDZE/KXTOrXamg13iaOOqt9kb08xZCYBhE2b4RWVmPzsUJ2pZcwLi6MQN+Ga1J3KFPx9y+P8LfPD3vajA7FK6+aUsrPpZR3hoWFedoUheLs2L4agmJg4o2etoSfTxaTcrqSf3yV0mi72WLlxR/TANifrQm0QznlvLTlJHYH2Kg+oay9cwZXTW5YjHHpuD4YbAPOH9rje1mfU9gXWdjDjq7oHxFIVqmRUpu4imihThg0EWHNwpE2T5iL0NyR3ApOV9Ty88kzy1XKKzPioxPNVi92FH4+euaMiOG7o/lYrZL1e7NbTci3M7CTPWH2kh+DohtWhY7qE0KfMH82HMpjf3ZZs9Ij9tCzt66QPHa6kle2pfPOzlNU1/WcAtBeKcIUim6B1Qonf4RP7oanhsLrl8HPL0LZKW3/6YNwYhNM+yUYOueXeHs4lKt5lnekFbPzZLEj9+PLg3lklRgZ1SeUlLxKjuRWcMuaXcSE+PGPq8YDMDxWu5g7Vx3vHebPSFu5gZmdsPpM4Tns3hB3PGEl1XWAG54we05YQONxdk+YqzIV9oKmn+/Pbe9bALRwZGyof6Nwekczf3QsBZV1HMgp571dp1pNyLdjL1PRWQVbTxZWERZgaCSMhRDMHdGLzccKMVlko3ww0PLmhBfXClu96TgCqDdb2Zrac6ojdLvVkQqFxylIgQNr4cD7UJEDviEw7CKt8v1Xf9QeseO0Cve+wTD1dk9bDMDhnAqGxwZTWmPipld3UW+x8tTV43l9RwZDYoL49QVD+dU7e7n9jSSsUqvxNSg6iN5h/o5fzfFRQQyPDeaBBSMA+Nc1E9ifXdZp4R6FZ8gurSEswNBqb8P+kYHUmqycKNAWbrjKCbPPL7eVoACtqbczoS3khJXV1FNaY8JXr2PjoTweuXIsvj7t8xvkltd2+v/NeSN6odcJnth4lLTCap66erxb8wZGBXVawdb0omoGxwQ1K/lxwchevLfrFELAlIGNRVhDrTDvE2GHc8vZeOg0d88dwjs7T/HNkXwuGdun7YndACXCFIq2MBkhayekb4HUb+H0ARB6GHohzH8YRlwKvrYE5uI0bTXksQ1w6mc4/7cQ4LlaWVklNRzJq2DB6FgO5pRz6bjeLBjdm68Onebo6Qr+/PFBTBbJ40vHMdGWpJtbXsvvLx7hWFk1a1iM43gBvnq++e0cx+uIIF/m2nJNFD2H1lZG2rHvP5BdjhANXi9n9DpBiL+PJrCk1Jp8+zW+7diFWlNPmN1LdE1CHO/sPMXW1EIuHBXbrveRW2ZkSifXqgsP9CVhYAQ/nyxpMyHfmUGdWKbiZGE15w1tXiR55tAofH10DI0Jdvl9Ne0J6i38+9tUQv19+OWcIeSV1/J9SgFmi7VH5KEqEaZQNMVigpy9muhK/xGydoGlThNe/abAJU/A2Ksg2IX4iBoCM3+tPeqqtNZEHuTFH9N4d9cp3lyRSLnRxJi+Ycwb2Yt5I3uRV27kktVb8dEJlkzqh5+Pjl4hflTVmbmxjZwWRc8mu9TIYKekblfYK+QfzCknLMDQYsjP3j/SKiVhAYZmxV/9DToMetEsJ8wuwm6aMZAvD+bx+f7cdokwq1WSX1HbKeUpmjJ/dCw700vaTMh3ZmB0IEVVdVTVmQn267hbcXWdmdMVtQxx0SUg0NeHBxYMb/EziYsIZJeX1Qrbn1XGpqP5/G7+cMICDMwfHcvH+3LYk1nKtB7QjUOJMIXCTvZu+PkFOP4V1FcBAnqPg8Q7YNAcGDgD/FwXr3SJX8e3SmkvqQVVSAmrPjkEaKUj7PQJC+CDu2ZgsljxN2g3jvsuGIpBryPcRWhJcW4gpSS71NjIA+oKe5ivrMbE4OiWBZtdhFms0uX/KyGEo2q+M+lF1egEDI4OZuHY3nyWnIux3uK2yCmqqsNkkfTrpPIUziye0JdvjuSzYqb7hcTjbY28M4qqG/1dni3pjqR819/JnbNd97oEzRP22f5ar/IyPf3tcSICDdx6vvbZzh4eg69ex7dH8nuECPOOT7kJqkSFosuwmOHwx/DKfHjlQkj9BsZdA9e+CX84CXdthYv/DsMXtE+AdQL1Ziuvbkunzmxpe7ANe75OZnENep1w1PayMzw2hDF9G24AN82I5/pWikwqej6lNSaMJkub4cggPx+ibMn4TVc8OmMXYWVGk8sQGLjuH3myqJr+kYH4+uhYPL4v1fUWfjjmfvjOvsKzKzxhsaH+vP/LGY7SE+5gF2FNV0hmldTw9LfHGxWAbQ92EdaWJ9MVcREBWKzS0ZqsLV7ecpIjuRXtPo+77Mks4cfjhfxyzhCHtzDYz4cZQ6L49mi+I8+wO+OVIkyVqFB0OrXlsOM/8Owk+GA5VBfCwifh/iOweDWMvgICI9s8TFey5Xghj3xxxFH1ui1Kquspqa5n6aR+AAzrFezweCkULeGoEdaGCIOGvLDIVgrz2kVYuYu+kXZCAwzNwpEZRdUOb860wVFEB/u1a5WkXUj09dJFI/YyFc61wswWK/e+u5dnv0vl/318qEWRkV9Ry6XPbOXtnzOb7bOLMLvIaw/tqRV2OLecv284ysqPDnSaGPrXN8eJDvbl5hkDG22fPzqWzOIaUguqWpjZffBKEaZQdBolJ2HjH+Hp0fDNKq1h9vXvwn17tFISHvZ2tUaarX3Q0bxKt8bbvWCXT+zLNVPiuNImxhSK1six3YDb8oQBxNnywloLXzt7wpoWarXT1BMmpSS9qNohJPQ6wWXj+/B9SoHbrX7s1fL7dkE48kwI8vOhV4hfo0beL/6Yxv7scmYNi2b93mze3nmq2bzKWhPLX0viSF4F//3+RLNCticLq+gXHnBGP7jaUyvsg93ZgLYw45sj+e0+V1vsSCtiR1oxd80Z0qioLGgiDODbTjhvV6NEmKJnIyUUpcLet2DtjfDsZEh6FUZeBnf+CLd+CSMXgc77PUT2X7gpp91z/6cWaGJtaK9gnrpmAnfNaTkXRKGwk+0QYW0vKmmPJ6ysxtSiWGuaE1ZQWUdNvaVRSG3xhD7Uma1sOurejTe3rJYAg77FEKg3EB8V5PCEHcmt4JnvUlk0vg9v3JrIvBExPPz5YfZkljrGmyxW7n5nL6n5lSw/L57TFdpKQWfs5SnOBHdrhdWaLHy8L4dLx/VmcHQQT39zHKu147xhFqvkkS+O0jfMn19MH9hsf2yoPxPiwpQIUyi8DnMdnNoJ21bDe8vgqSHw3wT47F6tZMSs++E3B2Hp/6DvRE9b2y7srUhSTrvvCQv01dO3C3JiFD2H7NIaQvx83BIv/SPsnrCWx4YGGKg3WylvR06Yq+TySf0j6BcewOf789x6H3nlRvqG+zerleVNxEcHklFcQ73Zyu8+2E9YgC+PXDEWnU6w+rpJ9AkL4O539lBYWYeUkpXrD7I1tYjHl45j1aJR9A71b+Qtk1JysrC6xaT8tvD10REb4u/Ip2uJTUfzKTeaWJY4gN/MH86x/Eo+P3BmBXVd8e7OTI7mVfD/Fo1u0aN30ahYkrPKKKjo3r0u1epIRfemulir4ZX1sya+cvdp5SQAIofA8Eug/zQYMB2ihmkFVLsBaYVVBPv5EBvaEEo5WdSQZF9dZyaojWXtJwqqGBIT3KwkgELRGjllRrfywcDJE9ZGONLVc2dC/RvnhLnKa9LZQpKvbkunrKa+zRW8ueW1XpsPZmdgVBCFldn846sUjuZV8PLNCQ6vYliggRd/MYWlL2zn3nf3MjU+kvV7s/nNRcO4JqE/ANcn9mf1plQyi6sZGBVEUVU9lXXmVlertoU7tcLWJWXRLzyA84ZEI4Dnvj/B6k2pLBrX56xXVRZX1fHU18c4b0gUl47r3eK4+WNi+de3x9l0tKDNNlHejBJhio6nuhheuQCMZaD3Bb3B9vAFnaHxa73Btq3pOB/bNl+t8bX9uc5HexQd00RXcap2Tp0B+k6CaXdC/+ma8ApufYm9tyKl5OZXdzGqTyiv3JIAaBXHi6rqmRofQVJGKcfyK5k8oPUilCcKqpjeA5ZwK7qW7FKjW6FIgNF9Q4kINDCqT8ttepyFV2uJ+TX1FkwWKwa9jvSianx9dM1E1OIJffnflpN8vj+Xm2bEt2pbbpmRESO8+xpg91i9ui2dpZP7OXKd7IzuG8rjS8fx23X72ZlewrUJcfzfhcMc+6+fOoD/fH+Cd3ed4k8LR3HSljc6yEWNMHeJiwhgt1MItCk5ZUa2nSjivguGOWrD3b9gOL98aw8f7cvhWptAPFP++c0xauot/O3yMa16MUfEhtA/MoBvj5xWIkyhaMT+d6E0A6YsB4RW/NRSD1aT7bnttcWkVaO3lGulIiz1tnHmhv0WkzbPXAc45RwERGhCa+INMGCGJsAM3pmA216yS43klBmprDVhtUp0OuHwDFw6rg9JGaWk5GkirLS6ni2phSwe37eRx6uqzkxeeS1De3m+Vpmi+yClJKfU6LZ47xXiz74HF7Q6xh0RFmLrH1lVayYiyNeWlB/YrADsmL6hjI8L45EvjhIR5Ntidfo6s4XCyrpu4AnTxG7vUH/+uniMyzFLJsWRWVxDVomRvy8Z10iY9A7z56JRvfhgdzb3zx/eUJ7irDxhgXx+IK/FWmHr92QjJVwzJc6xbcHoWMbHhfHMplSumNgXP58zy7E9kF3G2qQsVswcxLDY1hdJCSGYP6o3b+/MdCsy4K14pdVCiMXA4qFDh3raFEV7kRL2vK4JpMXPdOyxrZYGAecb3G1Ci+0lKUOrWF1Raya1oIoRvUMcv3BnDYsm2M/HkZz/r2+P8fbPp0jOKuPBy0Y7LtBptpWRSoQp2kOF0UxlndmtlZHu0jgc2XJiPkBFrckhwlwJCSEEb65I5PY3dnPvu/s4XV7L7bMGNxuXX66lJHh7PuTQXsFcMLIXd8wa3GoO3m8uGt7ivhunDeTrw/l8deh0ix7E9mCvFXa6oraZR9Rqlby/O4uZQ6McHRNA+15+t2AEt6zZxftJWW16KV1htUoe/PQwUUF+/N9Fw9qeAFw0uhdrtqezNbWw2/aS9Mq7mKoT1kHUV4PpDJIWa0ogfSvs/B98+1fY9BD88BiUZzeMMdVqie7pWzWvl53M7VB8wuYF62B0es3b5R/aIwRYUVUdB7ObFyROyijBoNfE1O5MTZCdLKxGrxMMiAxiZO8QUvIqMVusbDh4mrAAA69tz+Bf3xxHSonVKlmzPR2AUb1bDhMpFE3JstcI60APUns8YZW1ZixWyaniGga1sMIvPNCXt2+fxsKxvXn0y6P87fPDWJqszMsttxVq9dLyFHb8fPSsWT6VGUPOPG3g/KHRDIwK5O2fM0krdO1BbA+t1Qr7+WQx2aVGlyHH2cOimRofwX++P3FGhWY/3JtNclYZf1o40iHK2yIxPhJfvY59p8rafT5vwSs9YYoO4NhX8OndEBQDt3zhXn6UuQ42PwHbnwFp+yPSGUDYQoqHP4bbvtVys95YDDm7tTF6X63C/NCLYMd/wS8MRl/Zee+tB1BaXc81L/5ETqmRnX++kAinJf5JGaXMHBrN4dwKdmeUcuO0gZwsqmKArXr4yD4hfJqcy/a0Ykqq63nxF1P4IaWA//5wgu1pRcRHBfFpci4PLBjOgCjP9q5UdC/sq+LczQlzh0YirKXEfNv2CqOJ3DIj9RZrqyE1f4Oe526YzKNfHmXN9nRyy4xcObEfYYEGwgIMHLZVcff2cGRHoNMJbpw2gMc2pBDi78PMIdFndbyGWmHNRdi63VmE+vtw8ZjmCfNCCO69YBi3rNnFj8cLXY5picpaE//YmMLkAeEsaUc9Qx+9jn4RAWS3sZrTm1EirKdRXwPf/gWSXoGYkVCaCW9eAcu/aLkCvJSQuxc+uQcKj8LEG2HsUug1BkJ6ayIsY7t2nA9vBZ8AyNkDl/4ToodpnrJ1N2nPC47AvP8Hvurm3xJ1Zgu/fGsPWSU1mK2Szw/kcrPNfV9SXc+JgiqtEbBB7whNOi87H9k7lLdrT/HSljRC/HyYOyKG+aNjmTggnGe/S2XfqTKWnxfPPfNUOF/RPrLbUajVXULdWB1p94RV1Jo46WbFd51O8ODi0fQN9+fvG47y9eHGNaN0AvqEebcnrKO4ekp//vnNcSprzS16EN2lT7i/rVZY4xWS5TUmNh46zXUJ/VssGzF9cCR+Pjp+Situlwh786dMiqvreXX51Hav5o6LCCC7pO3ist6KEmE9idMH4cPbtJWDM+6FCx+EzB3w7nXw1pVw82cQEK6Nzd0Hhz+B0we0edWFENIHbvwQhs1vfuz4mXDZv7V6W6C1+Em8Q3t+0yfwzjVaGPKaN2CM8oK1hL3Wz66MEp5dNokXNqexfk+2Q4TttomuxEGR+Bv0bDx0mrxyIxnF1Zw/VPuFO6qPlrC6/UQxSyf3c1wQlyUOYMmkfuzPKmNqfKRX10fyNoQQlwDPAHrgFSnlEy2Mmwr8DFwnpfywC03sUPZkljA8NoSQJmGfnFIjgb76Vut+tRe9ThBiS5puqXxBQ06YmdO2dkPuionbZw3mykn9KKioo8xYT4XRRLnRRHSwX7NK6z2VyCBfFo3rw8f7cs4qKR+0EGlsiH8zT9in+3OoN1u5bmrLqx/9fPRMjY/k55PFbp+vpt7Mq9vSmTsihon9w9ttb1xEIN/knm73PG/h3Pgf6q2YjPDdw1B0XAsFmoxgrtUeplowG22rAy0grVqIUFq110hAaF4q+79WMwTHwi8+gqEXaucYMg+uexvW3gBvX6WtJtz7BuTt10KNvUbBsIuhz3gYf6226rAlJt8E9VXaeab9smF7QDis+EpLmDf0fPf/2fDsdyf4eF8Ov5s/nMsn9KWgopZHvzzKiYJKhvYKISmjBF8fHePjwvDz0W5YnyXnUmuyMti27Hy406qhxRMarw7zN+iZpspStAshhB54DpgPZANJQojPpJRHXIz7B/B111vZcdSaXAEw6gAAIABJREFULFz3v5+5cdoA/nbF2Eb7sktriIsI6HABHxpgoLVDOocjs0pqCPbzISbYz+3jRwf7Ed2O8T2RFTMH8d3RfCa1UbrGHZxrhRnrLTzzXSqvbD3JhLgwxvRtPc90xpAonvr6GMVVdUS58Z28u/MUJdX13HfBmXnu4yICKK6u77YrJLufxT2F+hpYuwxO/qhVbjcEagnnPrHg46eJGR9/W20sPQid9nB+LiUgbQJNasdIWAFBTW7CwxfAtW/A+zdreVy9xmihxHHXNHjG3GX6r1xv1+lBpwRYa3x3NJ9/bzrOVZPjuNd2wbliYj8e35jCh3tyWLlwJLsySpkQF4afj55RfUIJMOh5f3cWgKMVSYi/gf6RAVTWmh3eMcVZkQickFKeBBBCrAWuAI40GXcfsB6Y2rXmdSwFFXW2MHgeqy4bjcHJO9WeGmHtISzA0OpammC/hsT89OIaBkUHKU9uOxkXF8b+vy7okM+tX0QAezJL+SGlgL98eojsUiPXTInjT5eOavP49vImO9NLuHRc6ysWa00W/rflJOcNiWLKwBbSZdrAHjrPKTM2+oHaFkdyK+gV6nnxrkSYJ6irgveuh4xtcOXzmneqsxm5CFbYfsD3m0KrP0sVncInybn0CvHj8aUNtX5iQvyYOzyGj/dlc+8FQzmcU86ds7Ul9wa9jkkDwtmRprn2ncMM98wdik4nGt1AFWdMPyDL6XU2MM15gBCiH7AEuIBWRJgQ4k7gToABA7yzgGR+pRbuK6muZ1tqEfNG9nLsyykzMmXg2XtSmpI4KLLVS449ZFlRayK9qIqJ/TvehnOBjhKucREBfJqcy62vJzG0VzDr7pzutod9fFwYgb56fkorblOEvb87i8LKOp65/sxbyNlLZWSX1rgtwrafKOKWNbuYNSya125NPONzdwRKhHU1dZVa/lTWTlj6Moy/puvOHZfQdedSNEJKSVJ6CYmDIvH1aSycrpoSx3cpBfz3+xOYrZKpgxp+ESbER7IjrVgLz4Q0/GK7PtE7b/DdFFd3rqbdiFcDf5RSWlq70UkpXwJeAkhISOi4jsYdSL6t154Q8GlyjkOEVdRquVQdmZRv56HLXRcidSbE34fiqnpySo0smRTX5nhF5zFlYARBvnrunjeUO2YNbnbNag2DXsfU+Eh+aiMvrN5s5cXNaUwZGMGMs0ihsP9/zSpxb4XkiYIqfvX2HqxSsjW1iJLq+lYb0Hc26md0V1JbDm8thaxdcPWarhVgCo+SXWrkdEUtiYOau9wvHNWLsAADr2w9iRA0akeUYPNKDI5R4ZlOJBtwzjaOA5p2I04A1gohMoCrgeeFEN1yBUp+hVbI9JIxvfnmSD419Vrj7BxbIra7fSM7mtAAA4dyy7HKs6v4rjh7LhgZy+GHL+GeeUPbJcDsnDckihMFVRRUtlyn8uN92eSW13LfBUPP6toWE+yHn4+uzX6XoHl/V7yehK+Pjhd/MQWzVbLhoHsN4TsLrxRhQojFQoiXysubF7LsthhL4c0rtVWJ174BY5Z42iLF/2/vvsPjrK7Ej3+Peq9WsS3Lknsv4AZmAdMhGFMTTAl1gQSSzW6S/UGWTVt2A5tkk02WhDhAIIGEOKaZFtMDxAZsU4w7ttxkWb2M2kgazf39McUjaSRLtjTvOzPn8zx+0LzzzsyZF5Uz9557bgj5Wk0sLOmbhCXGxbJ87mhcbsO0wowey/jnF2cRI0f3mFMjYiMwWURKRSQBuBpYG3iCMabUGFNijCkB1gBfNcY8F/pQT1y1w0lCXAw3nFpCW2c3r233tHY43DD8PcKGIj0pjrIab3sK/X4Pa77msxv2Bh8Nc3W7efCtvcwpyuSMKSe2v6eIeBcSDDwS5mkNtIlKh5NVX17AuTMKmJSfxtpPe3/eCi1bJmER1zG/rd7TY6tqK3zpDzB9udURqRDbuL+B9KS4fmsWLj/JM/2yqKRnLUx6Ujw/WDGLm5aWjniM0coY4wLuwrPqcQew2hizTUTuEJE7rI1u+FU5nBRkJLKoJIfRmUk8/4nnj5BvJGEkpiMHI7BLeukxeoQpe5s5JpP0pLh+W1W8sKWCg/Vt3LXsxEbBfIqyU/y7PQTjaw20cX8DP71qLicVZyMiXDJ3DBv311NhYbNXWyZhEaW11tNdvnonXP1HmHqh1REpC2zcX8+C8dn9bicyf1wW935hOjcGSbauXzL+uPrnqMEzxrxsjJlijJlojPlP77GHjDEPBTn3xnDuEVbl6KAgPYmYGM8foXd211Df2snhxnaS4mPItag+xtemIjc1gcxh7FOmQi82RlhcmhN0JKzT5eaXb+xhWmE650wvGJbXO9ZI2BPvH/C3Bgps63PJ3DEYAy9usW40TJOwkdRSDY9d7Glies1TwZugqojn64K/MEg9mI+IcOs/TNBpRzXiqpqdFGR4OsmvmDcWl9vw0pYKyhvaGZs1/D3CBsvXNV+nIiPDkgm57K9r40hTz+To9xv2U1bbyrfPnzrk7vj9GZeTQmNbF83OrqD3v7ajmikFaf7WQD4lo1KZW5TZ75Sks6ubrYdHtixKk7CR0nQYHvsCNB6Aa/8CE8+yOiJlkU0D1IMpFWo1jg7yMzwrbaePTmdKQRrPf1IxYj3CBss3HakfRCLDqd49LANHw6qbnfz89c9ZNjWPs4dpFAwG3u8SPD3BZo/NCvoBY/ncMWw97GBvTUuf+/7jxe1c/qv1gyr6P16ahA232j3wwj/BL+aDowKuexpKT7c6KmWhwC74SlmptcNFc4fLPxImIqyYN5ZNBxrYXdVs2cpIODoSpklYZJhWmE52SnyPJOzHf91Fh6ubf794xrC+1rhsX6+wvklYTXMHtS0d/u3eels+dwwinp1JAq39tIInPzjITaeVjOiHE03ChoMxcPB9+NM18H8L4JM/wbyVcPs7MP5Uq6NTFvtwfwPzirJIjAu+6a1SoVLd7GlPUZBxtOfcJd4amQ6X27KifDhaE6ZJWGSIiREWl+b6m01/cqiRv2wu5+alpf4t2IbL0ZGwviNWO444AJgxOvh2SwUZSSwpzeWFTyswxtPab19tK/c8vYWTx2fzrfOmDmusvWkSdiLc3bD9eXjkXHj0fDi4Hk7/NvzzVlj+v5A70eoIlcXaOl1sO9zEghLtAK6s52vUWpCe5D82LifF349ubJZ1SdiYrGREPCMoKjKcMjGXw43tHKxr43trt5GXntinLms45KQmkBwfG7Rhqy8Jm95PEgZwybwxlNW2sq3CgbOrm68++RHxcTH8cuX8Ed+VRDvmH4/ONvjkSdjwIDTsg+wSz16M866BBP0Up4765GBjny74SlnFl4TlZyT1OL5ivmdKcryFrSFOnzyKt791pqUxqOHl6xd29zNb+PRQIz+9ai7pScO/8lVEGJeTHHQkbPsRB6Mzk8geYNXvhbMK+e7zW1n7aQWtHS52HHHw6I0LGBOCDyWahA1Fay18uAo+/C2013v2YDzn+56+XzE61RTNjDFBiz437m9AhBHZj0+poap29J2OBLh64TgKM5KYa2HdoohoAhZhJuenMSotgfV765g3LovL5o8dsdcqyk4JWhO244hjwFEwgKyUBM6YkscfNhygvaub28+YwFnThm/hwEB0OnIw6vbCC9+An82Evz0AxUvgplfg1jdg5qWagEW5KoeT0x54i1Xv7O1z38b99UwrzOjRiFIpq1Q5nKQkxJKW2PPzd3xsDOfOKNCtsdSwEhGWePeF/MElM4etJUUwRdnJfRq2Oru62VvT2m9RfqDlc8fQ3tUdkjqwQDoSdix7XocnvwgxcTD3ajjlLsibYnVUykbWbC7ncGM7//XyTrq6DXcu89Q8uLrdfHSwgatO1s2IlT1UNXdQkJGkyZYKmW+dN5Xlc8cwd4QbTo/LTqHZ6aKpvcu/9due6ha63YYZo489wnvBrELuvnAal80fO+J1YIE0CRtI4yF4+h8hbxpc/yykh2Z4UoUPYwxPby5nwfhsxmYn8+N1u3C7DV87ezLbjzho6+zWejBlG1UOJ3npicc+UalhUjIqNSQNeH0rJA/Vt5E51pN0bfcX5R97JCwxLpY7zgj9YjpNwvrj6oS/3AjdXfDF32sCpoL66GAjZbWt3HHmRK44qYhYEX762m66jfFP+WiTVmUX1Q4ns4t0CywVeYoCeoXN8iVhFQ6S42NtXWuoSVh/Xr0XDm/yJGCjhn9JrYoMazaXkxwfy0WzRxMbI/z4qrnExAg/f/1zslPiKc5J8TfGVMpKxhiqHB2coyNhKgKNy+nbK2zHEQdTC9P73bPXDmxZmC8iy0VkVVPTyO7Z1K+tT8OHv4Eld8KMFdbEoGzP2dXNi59WcOHsQv+oV2yM8N9XzOGLC4poaOvSUTBlG80dLtq7uvVDgYpImcnxpCXG+VdIGmPYccTBjDEDr4y0mi1HwowxLwAvLFiw4B9D/uI1u2Ht12HcYjj3ByF/eRU+1m2rpLnDxZW9Cu9jYoT7L5/D3HFZnDZplEXRKdVTtb9HmI6EqcgjIhRlH+0VVtHkxOF0HbM9hdVsmYRZprMVVn8Z4pLgqscgVtsKqP6t2VzO2KxklpTm9rkvJka4dvF4C6JSKrgqf48wHQlTkcnTK8yThG2v8G1XZO8dGGw5HWkJYzy9wGp2whUPQ8YYqyNSNnakqZ339tRyxclFI9r7Rqnh4t+ySJMwFaGKspM5VN/mn4oUgamF9h4J0yTMZ9Oj8NlqWPYdmLjM6miUzT3z0WGMgStOGrkO0EoNJ99IWL4W5qsIVZSdTGtnN41tXew44mB8TkqfxsR2o0kYwOGP4K93w6Rz4R++ZXU0yuZ8vcEWlebYeumzUoGqHE7SE+NItfkfJaWO17ico20qBrNdkR1oEtZWD6tvgLQCuHwVxOglUQPz9QbrXZCvlJ1VNzu1KF9FNF/D1p2VDvbXtYVFEhbdH4ncbnj2Dmg+AjevgxRtJ6COLbA3mFLhosrRofVgKqL5Gra+vqMKgBlhkIRF97DP338Gn6+DC34ERSdbHY2ygZYOFzXNHf3e7+8NNqvQ9rUGSgWqcjg1CVMRLTM5noykON7ZXQvAdJv3CINoHgnb9w68eR/MugIW3mp1NMoGut2Ga3/7PlsON3FycTYXzR7NBbMKGZOV7D+nv95gStmZMYbq5g6djlQRryg7he1HHGQkxTEm0/4fOqJzJMxxBNbcDLmTYfkvQLTFgII/fnCAT8ubuGz+WFo6XPzwxe2cev+bXParv/Pwu2WUN7Qd7Q02oW9vMKXsqqm9i06Xm4J0+/9RUupE+LYvmj46AwmDv+3RNxLW3QVrboLONrjhRUhMszoiZQO1LR38eN0uTpmQy0+vmouIUFbTwitbK3n5syPc99IO7ntpBwBfP2uS9gZTYcXfnkJHwlSE89WF2X27Ip/oS8Le+AEc3ACXPwz506yORtnE/a/spL2rm/+4dKb/09OEvDTuXDaJO5dN4kBdKy9/VsnHBxu4dol2wlfhRRu1qmjhWyEZDisjIdqSsB0vwPpfemrA5lxldTTKJjbtr2fN5nLuOGMik/KDb3ExPjeVr5w5McSRKTU0VQ4nb+yoZuWicT2mYvxJmE5Hqgg3c0wmsTHCScXZVocyKNFTE1ZfBs99FcacBOf/l9XRKJtwdbu597mtjMlM4utnT7I6HKVOyFMfHuI7z37GRwcbehyvbtbpSBUdFpXmsPnec5iUHx6lRtGRhHW1w5+/DBIDX3wc4vQXkfJ4fMMBdlY2893lM0hJiK6BYXWUiFwgIrtEZI+I3B3k/hUiskVEPhGRTSJymhVxHsvemhbA08suUJXDSWZyPEnxsVaEpVRIZaUkWB3CoEVHEvbyt6HqM7j8t5BVbHU0yiaqHE5+9tpuzpiSx/kzC60OR1lERGKBB4ELgRnAShGZ0eu0N4C5xph5wM3Aw6GNcnDKaj1J2IufHsHZ1e0/7ukRph8+lbKbyE/CPn4CPv6DZ0/IKedZHY2ykf98aQed3W5+cMnMsFjKrEbMImCPMabMGNMJPAWsCDzBGNNijDHem6mAwWaMMZTVtDKtMJ3mDhevbq/y36fd8pWyp8hOwio/g5e+CaWnw7LvWB2NspH1e2pZ+2kFd5wxkZJRugl3lBsLHAq4Xe491oOIXCYiO4GX8IyG9SEit3mnKzfV1NSMSLD9qXQ4aevs5prFxYzNSu4xJVntcJKvRflK2U7kJmHOJlj9ZUjOhisehRithVAenS43//78VsblJPNVXfGoINgwaJ+RLmPMs8aYacClwH8EeyJjzCpjzAJjzIK8vLxhDnNge6tbAZiUn8Zl88fy3uc1VDmcuN2ebvk6HamU/URmEmYMPH8nNByAqx6DtND+MlQjp8PVzf2v7OSHL2xn0/563O6hzwo98t4+9ta08oNLZmqhsgLPyNe4gNtFQEV/Jxtj3gEmisiokQ5sKHz1YBPz0rji5CLcBp79+DD1bZ243EanI5WyochcDrbhQU9PsPP+E4qXWB2NGiZtnS5u/8Nm3v28loTYGB79+z7y0xO5cFYhF84ezcKSHGKP0cn+cGM7v3jjc86dUcBZ0wpCFLmyuY3AZBEpBQ4DVwPXBJ4gIpOAvcYYIyInAQlAXcgjHcDe6hbSEuPIT09ERDh5fDZrNpdz2iRPrqgjYUrZT8iSMBG5FPgCkA88aIx5dURe6MAGeO27MH05nHLniLyECr2m9i5ufmwjHx9s4CdXzeX8mQW8ubOaVz6r5M+bDvH4hgOMSkvgvJmFXDRrNEsm5BAX23eg974Xt2MwfG9578VvKloZY1wichewDogFHjXGbBORO7z3PwRcAXxZRLqAduBLAYX6tlBW28qEvFT/IpMrTy7inmc+4/UdngL9fB0JU8p2BpWEicijwMVAtTFmVsDxC4D/xfOL62FjzP39PYcx5jngORHJBn4CDH8S1lLj2RcyezyseFA35o4QtS0dfPmRD/m8uplfXXsSF8waDcCKeWNZMW8sbZ0u3t5Vw8ufHeG5jw/zxw8Okp0Sz7kzCrhw9miWThxFQlwMf9tdwytbK/n2+VP9+4spBWCMeRl4udexhwK+fgB4INRxDcXe6hYWB2ws/4U5o/n+2m08tn4/oFsWKWVHgx0Jewz4P+D3vgMBvXXOxVNTsVFE1uJJyH7U6/E3G2OqvV/f633c8HJ3w9M3Q3sDXPsXSMoc9pdQoVfR2M51j3xARWM7j9ywkNOn9K3vS0mI46LZo7lo9micXd2eZOuzI7zyWSWrN5WTnhTHuTMK2LS/gQmjUrn1H0oteCdKBefqdvP3vXVMGJXKuJzj+3DQ1umiosnJhICVvhlJ8Zw3s5AXPvWUt+Wl6XSkUnYzqCTMGPOOiJT0OuzvrQMgIk8BK4wxP8IzataDeMbI7wdeMcZ81N9richtwG0AxcVDaKz61n/Bvnc8I2CFswf/OGVb+2pbue7hD3C0d/HELYtZUJJzzMckxcdy/sxCzp9ZSIerm7/vqeXlzyp5dVslDqeLJ25ZTGKcFuMr++jsdnPDox9yz4XTuP2M/lfrrnpnL8U5Kf6R4EBlNZ6VkRN7bdVy5clFvPBpBTmpCSTEReY6LKXC2YnUhAXrrbN4gPO/BpwDZIrIpMCh/kDGmFXAKoAFCxYMruZi9zp49ycw/3qYf92gHqLsbWelg+se/hC3MfzptiXMGjv0kc3EuFjOmuYpwO+8bDZVDudxjzQoNdKO9cvuN38rY2x2ctAkzLdd0cS8nknYaZNGUZCRSHYYbeOiVDQ5kSRsUL11/HcY8wvgFyfwev1LzIDJ58FFPx6Rp1eh9fHBBm783UaS42N54tYlw7IRa0JcjCZgypbE+6t0oDL/TpebutZOGto6cTi7yEiK73F/WU0rIjA+t+f3eGyM8N9Xzj2uVi5KqZF3IknYkHrrjKjxp8D4v1jy0mp4rd9by62PbyIvPZEnblmsiZOKeL71Q2aAsbDqZicAbgMb99Vz9vSe7VX21rQwLjslaN+7M4LUUSql7OFEigT8vXVEJAFPb521wxGUiCwXkVVNTU3D8XQqTLy+vYobf7eRouxk/nL7KZqAKeVV5ejwf/1+Wd/2ZGU1nvYUSqnwMqgkTET+BGwApopIuYjcYoxxAb7eOjuA1caYbcMRlDHmBWPMbZmZusIxWjz/yWFuf2Iz0wvT+fNtp2hPIxV1BpqOrHJ4RsJyUxPY0CsJc7sNZbUtferBlFL2N9jVkSv7Od6nt45SQ/XkBwe497mtLCrJ4ZEbF5KWGJkbOSgVzGDaGfqSsIvnjOb37x+gqa2LzBRPXdgRhxNnl1tHwpQKQ7pmWVnqob/t5d+e3cqyqfk8fvMiTcBU1JGga5x6qnQ4SYiN4YJZozEGPtxf779vb3XwlZFKKfuzZRKmNWGRzxjDj9ft5P5XdrJ87hh+c/3Jupm2imoD7YJU7eggPyOR+cVZJMbFsGHv0SnJMm97Ch0JUyr82DIJ05qwyOZ2G76/dhsPvrWXlYvG8fMvzSM+yD6PSkUD/+rIY9SEFWQkkRQfy0nF2T2K8/fWtJKeFKcd8ZUKQ/qXT4WUq9vNt9Z8yuMbDnDb6RP4r8tmExuje3yq6OX77h+ok1elw0mhd7HKKRNz2VHpoLGtE4Cy2hYm5KX5N+5WSoUPTcJUyHS4urnzjx/xzEeH+ea5U7jnwmn6h0NFvcH8DPimI8GThBkDH+zz1IXtrW5lok5FKhWWNAlTIdHW6eLWxzexblsV31s+g6+dPVkTMKUC9Dcd2dLhoqXD5R8Jm1OUSVK8py6spcNFpcOpRflKhSlbLkUTkeXA8kmTJlkdihoGTe1d3PzYRj4+2MCPr5zDVQvGHftBSkWJo9ORwbMwX3uKAm8SlhgXy4LxObxfVsc+38bdOhKmVFiy5UiYFuZHjtqWDlauep8t5Y08eM1JmoAp1cuxCvOrmjxJmG86EmDJhBx2Vjaz0duqQkfClApPthwJU5GhorGd6x75gIrGdh6+YaHuYadUEMealq/y7htZGLCLxCkTcwF4auNBYgSKc3WLL6XCkSZhakTsq23luoc/wNHexR9uWczCkhyrQ1LK1vpbHenbN7IgIAmbPTaL5PhYdle1UJKbQmKc9thTKhzZcjpShbf2zm6+9JsNtHd186fblmgCptRg9DMfWdnkJD0xjtSA3SQS4mJYUJINwASdilQqbGkSpk7I4cZ23tld0+PYgfpWqps7+O7FM5g1Vuv6lDqWgWYkq5udPerBfHxTklqUr1T4smUSptsWhY/fvlPG7X/Y3GPLlfoWTxPJwOkTpdTA+puOrGxyBv1ZOmWCJwmbnJ8+glEppUaSLZMwXR0ZPmqaO2jv6qalw+U/VtvqScJGpSVYFZZSYUUYYHWko6NHUb7PvHFZrLr+ZC6ZN2Zkg1NKjRhbJmEqfNS1eoqG67yjX56vPcdyUjUJU2owRCRonzC323inI/smYSLCeTMLdeN7pcKYJmHqhNR7R718yZjvWIxAVoomYUoNRn8lYQ1tnXR1GwqD1IQppcKfJmHqhPiSsNqAkbDalk5yUhN0Y26lhiDYdGRlr275SqnIokmYOm5ut6GhrQvwdMb3qW/t0KlIpYZAJHhhfrWvR1imJmFKRSJNwtRxa2rvotvt+dPRsyask9xUnT5R4UNELhCRXSKyR0TuDnL/tSKyxftvvYjMHdbX72dCsve+kUqpyGLLJExbVISHuta+xfi+47m6MlKFCRGJBR4ELgRmACtFZEav0/YBZxhj5gD/Aawa7jgGmo7MS9MPNUpFIlsmYdqiIjzUByRhtb0SslydjlThYxGwxxhTZozpBJ4CVgSeYIxZb4xp8N58Hyga1giEoKsjqxwdjEpLICHOlr+qlVInSH+y1aAcbmynq9vd41i9d0VkWmIctc2erztdbhxOF7n6yV2Fj7HAoYDb5d5j/bkFeGU4AxAIWhRW5XCSn65TkUpFKk3C1DE1O7s4+6dv8+eNh3oc901HTi5I83/d0Ob5rxbmqzASrCAraOtUEVmGJwn7f/3cf5uIbBKRTTU1NcFOCR5APwuJqxxOCrUoX6mIpUmYOqbDje04u9zsOOLocdy3PdHk/DR/TZhvlaR2y1dhpBwYF3C7CKjofZKIzAEeBlYYY+qCPZExZpUxZoExZkFeXt6QggiW9VU5nBRojzClIpYmYeqYKhrbAThQ19bjeF1rJ+mJcYzOTKahrQtXt9u/SlKnI1UY2QhMFpFSEUkArgbWBp4gIsXAM8D1xpjdwx2AID32XwXo6nZT29KpKyOVimCahCkAPj7YgKtXzZdPRaNnhdb+utYex+tbO8lJS2BUuifhqm/r9Bfr63SkChfGGBdwF7AO2AGsNsZsE5E7ROQO72nfBXKBX4nIJyKyaThjEOm7OrLGW2epSZhSkSvO6gCU9Q7WtXHZr9bzbxdN5x9Pn9Dn/iNNnpGwisZ2OlzdJMZ59qqrb/V0xh/lTbhqmzuPTkdqnzAVRowxLwMv9zr2UMDXtwK3jtTrBysJO9otX3+WlIpUthwJ0z5hobW7qhmAP2861GdKBOCIdyTMbeBQfbv/eF1rJzkpCf6px7rWDupbO4mLETKSNb9Xaih6/+RVa6NWpSKeLZMw7RMWWvtqPdOMe6pb+ORQY5/7Dze2kxTv+VY5EDAl6dueyNeYta6lkzrvvpHS33IvpVQfItJnOrKySZMwpSKdLZMwFVplta2kJ8WRHB/L6k3lfe4/0uRkwfgcAPZ7i/ONMUdrwrwjYbUtHd5u+Tp9otRQBPvIUtXcQXyskJOi9ZVKRSpNwhT7aluYUpDOhbMLeeHTCto7u/33ud2GyiYnM8dkkJ4U5x8Ja+5w0dVtyE1NICMpjvhYobalk7pW7Zav1PHo3TG/qsnTqDUmRkeVlYpUmoRFsA/31bOlvO/0Ym/7alspHZXKFxeMo6XDxV+3HfHfV9faSWcKsmBUAAAWwElEQVS3mzFZyZTkpvpHwnw9wnJSExERclMT2Xygnq2Hm5iUnzYyb0ipSBVkdWRVs/YIUyrSaRIWwe5+egs/fGH7gOe0driocnRQOiqVxaU5jM9NYfXGo1OSvpWRozOTGJ+b4h8J83XI94165aYlsHF/A0lxsXx12cSReDtKRaygqyObnFoPplSE0yQsQrV3drOvrpVdVc1BVzz6+IryJ4xKRUS46uQiNpTVcajeM+Lla9TqGwkrb/DsIdm7H5ivLuyfzpmse90pNUTBFrJUOzo0CVMqwmkSFqH2VLdgDDQ7Xf5+Q8H4krDSvFQAVszz7Fv8xo4q4GijVt9IWLfbcLih3b95ty8Jm1uUydxxWdxwasmIvB+lIl3gh6XWDhfNHS5NwpSKcJqERaidlUf3edxd1dLveb4krCTXk4SNy0mhOCeFv+/1bI13pKmdxLgYclITKBnlOWd/XevR6Uhve4p/OW8qz331VOJj9VtKqaESOdonzNnVzb3PbQW0UatSkU7/YkaoXZXNxHlXVe2ubO73vH21rYzNSiYpPtZ/bOmkXN4vq8PV7aaiycmYrGREhPG5KYBnD8l9Na0kxceQknC0Kav2BlPq+AhHC/N/9fZenv34MACFOhKmVESzZRKmHfNP3K6qZqaNTic/PZFdVf0nYWXelZGBlk4aRbPTxWeHmzjS2M7oTM8fgry0RFISYvn123v5y+ZyLphZOKLvQaloEfgBpr3T5f86X5MwpSKaLZMw7Zh/4nZWNjO1IIMpBen+bYl6M8awr6alTxJ2yoRcANbvraOi0cnozGQA72hYKpUOJ9ctKeYnV80d2TehVBTp3ScMoDBTkzClIplu8GdTVQ4nv3zzc97ZXQtAjHiSIBHP1EVhZhKP3LCwxzSiT31rJzXNHUwrTCczOZ4/fngAt9v0afpY39qJw+nqk4TlpiUyfXQGf9tVQ3WzkzFZR/8QfOu8KdS1dnLVyUU6/ajUMAmcjgyUlqi/opWKZBHxE97a4WLdtkouP6nI6lBOWENrJw/9bS+Prd9Pt9twzvQCkhNicRuD24DbGJraunhvTy0f7KvnjCl5fZ5jl7cGbEphOhnJcTi73BxqaGN8bs9kq/fKyEBLJ+by8Hv7APwjYQBnTy8YtveqlPLQzzNKRaeISMKeeP8AP3plJ9kpCSyblm91OMelpcPFI+/u4+F3y2jpdHHZ/LF84+wpFHuL4QM5u7qZ+4NXeWtndT9JmGdl5LTCdDKSPP+Ld1e19EnCygJ6hPW2dPIofxIWOBKmlBoZvoEwHWFWKnrYsiZsqG5cWsLk/DS+8+xnNDu7rA5nSJxd3Tz8bhmn//db/Oz13Zw6KZd13zid//nivKAJGEBSfCynTszl7V3VQe/fVdVMVko8+emJTC5IBwhaF7avtpX4WGFsVnKf+xaV5PhXV44Jcr9SajhJ0OlIpVRki4gkLDEulgeunEOlw8kDf91pdTjH1NTexUtbjvCtv3zK0vvf5L6XdjBzTAbP37mU31y/gCnexGkgy6bls7+uzT+lGMhTlJ+OiJCWGMfYrGT/FGWgfTWtFOekEBekt1dqYhzzi7MA/KsjlVIjwzP45cnCdBxMqegREdORACcVZ3Pz0lIeeW8fF88ZwxLvCj87MMawu6qFt3ZV89bOajYdaKDbbchIiuP0KXlcs7iYUyeOGtJznjklH9jG27uqKR1V2vO1Kpu54uSj9XFTC4OvkPRs3N3/ZtuXn1REt9uQnhQ/pNiUUkOjiZdS0SlikjCAb543hde2V3H301v46zdOD7pyMFQ6XW7e/byGN3dW8/auGg5792CcPjqD20+fwLJp+cwflxV0FGowinNTmJiXylu7arhp6dEkrLyhndbObqYWHh1Nm1KQzruf19DV7fZ3tHe7DfvqWjljat+aMp+Vi4pZuaj4uOJTSg2NfzpSMzKlokZEJWEpCXHcf/lsrnn4A3722m7uuWi6ZbHc/cwWnvnoMCkJsZw2aRR3nTWJM6fm9VhpeKLOnJrPH94/QFuny9+53jftOC0gCZtamEZXt2F/bau/RqyiqZ1Ol7tPewqlVOiJBG9RoZSKbBFRExbo1EmjuHrhOH77bhlbyhstiaG8oY3nP6ng2sXFfPzdc1n15QWsXFQ8rAkYwLKp+XS63Gzw7vMI+LvjB9aVTfEX5x/dQ/Lzas/XmoQpZT3R4S+lolLEJWEA91w0nbz0RP51zRY6Xe6Qv/7j6/cD8NVlk0iMG7kp0YWl2aQkxPJWwCrJnZXNjM1K7lHHNTEvjRihx/ZFf/zgIJnJ8cweq7sSKGUHwTrmK6UiW0QmYZnJ8dx36Wx2Vjbz0N/2hvS1m51dPPXhIS6aPTpo64fhlBgXy9JJo3hrZw3GO5exu7K5Rz0YeFpalOSm+jfy3lnp4LXtVdy0tIRU7citlOUCpyNrmjusDUYpFTIRmYQBnDujgOVzx/DLNz/n8wE2sB5uqzeV09zh4pbTSo998jBYNjWfw43t7KluodPlZm9NS58kDOixh+Sv3tpLakIsN55aEpIYlVIDE442a33mo8NWhqKUCqGITcIAvr98BmmJcXx7zRa63SM/1O/qdvO7v+9jYUk288ZljfjrAZzpXd341q5qympbcLlNj6J8nymF6eyva2VXZTMvbqnguiXjyUpJCEmMSqmB+brkb69wWByJUiqUbJmEichyEVnV1NR0Qs+Tm5bI9y+ZySeHGnnMW6c1kl7dXkV5Qzu3nDZhxF/LZ0xWMtMK03l7V41/ZWSwkbCpBem4Dfzr01uIi43hln8IzUidUmpwjIGLfvGu1WEopULIlkmYMeYFY8xtmZknXjR+ydwxnDUtn5+s28XBurZhiK5/j7y3j+KcFM6dEdpNrs+cms/G/fVsPtBAXIwwIUgD1ikFnmOfHmrk6oXjyE/XLvhK2YkW5isVfWyZhA0nEeE/L5tFbIxw9zNb/AXsw+2jgw1sPtDATUtLiI0J7XLzZVPz6Oo2rNlczoS8VBLi+v5vLRmVSnysEBcj3HZ66EbqlAoHInKBiOwSkT0icneQ+6eJyAYR6RCRbw3/64PmYEpFn4hPwgBGZyZzz0XTWL+3jtWbDo3Iazzy3j7Sk+K4asG4EXn+gZw0Ppv0pDjaOruZWpgR9Jz42BhOn5zH9aeMpyg7+MbgSkUjEYkFHgQuBGYAK0VkRq/T6oGvAz8ZmRhG4lmVUnYXFUkYwMqFxSwuzeG+l3ZQ5XAO63Mfqm/jlc+OcM2iYtIsaPngS7CAoEX5Po/cuJDvLZ8ZqrCUCheLgD3GmDJjTCfwFLAi8ARjTLUxZiPQNVJB6ECYUtEnapKwmBjhgSvm0Oly82/Pbh3WacnH1+9HRLjBwpYPvlWSgZ3ylVKDMhYIHCIv9x4LGUFGrFRCKWVfUZOEgacu6pvnTeH1HVW8uOXIsDxns7OLpzYe4guzRzNmhJuzDmT53DF8b/kMzpjS/4bcSqmggk0GHldGJCK3icgmEdlUU1MzhMcdz6sppcJdVCVhADcvLWVuUSbfX7uN+tbOE36+1ZvKaelwcavFLR+S4mO5aWlp0KJ8pdSAyoHAYs4ioOJ4nsgYs8oYs8AYsyAvb2gfiJqdruN5SaVUGIu6v9hxsTE8cOUcHM4ufvjCthN6Ll9z1kUlOcwpCk1zVqXUsNsITBaRUhFJAK4G1oYyAFe34Y2d1T2OfWHO6FCGoJSyQNQlYQDTCjP46pmTeO6TCt7cWXXcz+NvzqqNT5UKW8YYF3AXsA7YAaw2xmwTkTtE5A4AESkUkXLgX4B7RaRcRIIvRT4Ohxvb+xz76VVzh+vplVI2FbW7N9+5bBKvbD3Cvz27lVf/OYf0pPghP8fD75ZRnJPCOdND25xVKTW8jDEvAy/3OvZQwNeVeKYpQyYhNio/IysVVaL2pzwhLob/vnIuVQ4n97+yc8iP33yggY8ONnKzBc1ZlVKRL0Z/rygV8aI2CQOYNy6Lm5eW8uQHB3m/rG5Ij33UwuasSimllAp/UZ2EAXzzvKkU56Rw99NbaO/sHtRjDtW38crWI1yzuJhUC5qzKqUi2+26tZhSUSHqk7DkhFjuv2I2++va+Pnruwf1mMfX7ydGhBstbM6qlIpc2mpGqeigP+nAqRNHsXJRMb99t4xPDzUOeK6/Oeuc0YzOtK45q1Iqcrnc2j1fqWigSZjXPRdNIz89if/39BY6Xe5+z/vzxkO0dLi45TRtS6GUGhndmoQpFRU0CfPKSIrnvktnsbOymV+/vTfoOZ7mrPu1OatSakQlx8daHYJSKgQ0CQtwzowCLpk7hv9763N2VzX3uX/dtioON2pzVqXUyPrKmROtDkEpFQKahPXyveUzSE+K51/XbOkzJfDIe2WMz9XmrEqpkTN7bCZJOhKmVFTQJKyX3LREvrd8Bp8cauR3f9/nP360OWupNmdVSo2Y1ERNwJSKFpqEBXHJ3DGcPS2fn7y6i4N1bYCnOWtGUhxXnhzSnUuUUlFmYl6a1SEopUIkZEmYiEwXkYdEZI2IfCVUr3s8RIT7LptFfEwMdz+zJaA563htzqqUGlH/fvEMq0NQSoXIoJIwEXlURKpFZGuv4xeIyC4R2SMidw/0HMaYHcaYO4AvAguOP+TQGJ2ZzD0XTWf93jpuemwjMSLccOp4q8NSSkU4rQdTKnoMdiTsMeCCwAMiEgs8CFwIzABWisgMEZktIi/2+pfvfcwlwHvAG8P2DkbQykXjOGVCLnuqW7Q5q1JqxG2+9xyrQ1BKhdCg5taMMe+ISEmvw4uAPcaYMgAReQpYYYz5EXBxP8+zFlgrIi8Bfwx2jojcBtwGUFxcPJjwRoyI8MAVc7j3+a187axJlsailIpc1y0pJi8tidy0RKtDUUqF0IkUOI0FDgXcLgcW93eyiJwJXA4kAi/3d54xZhWwCmDBggWWt40uzk3h9zcvsjoMpVQEu+/S2VaHoJSywIkkYcH6NPSbNBlj3gbePoHXU0oppZSKGCeyOrIcGBdwuwioOLFwlFJKKaWiw4kkYRuBySJSKiIJwNXA2uEISkSWi8iqpqam4Xg6pZRSSinbGWyLij8BG4CpIlIuIrcYY1zAXcA6YAew2hizbTiCMsa8YIy5LTMzczieTimllFLKdga7OnJlP8dfZoAie6WUUkopFZxuW6SUUkopZQFbJmFaE6aUUkqpSGfLJExrwpRSSikV6cQYy/uh9ktEaoADAYcygaZ+bo8CakcwnN6vPZyPGei8/u4Ldnwwx/SaHfv4sW6P5HWL9ms23hiTN4jzbC/I76+BjPTP4kgL5/g1dmtEauxD+x1mjAmbf8Cq/m4Dm0L52sP5mIHO6+++YMcHc0yv2dC+r/q5PWLXTa9ZdP4L9+sTzvFr7Bq7lbHbcjpyAC8c43YoX3s4HzPQef3dF+z4YI7pNTv2cb1mQz9u5TVTSqmwZOvpyKEQkU3GmAVWxxFO9JodH71uQ6fXbGDhfn3COX6N3Roau0e4jYQNZJXVAYQhvWbHR6/b0Ok1G1i4X59wjl9jt4bGTgSNhCmllFJKhZNIGglTSimllAobmoQppZRSSllAkzCllLKQiFwgIrtEZI+I3G11PL2JyDgReUtEdojINhH5J+/xHBF5TUQ+9/43O+Ax93jfzy4ROd+66P3xxIrIxyLyovd2WMQuIlkiskZEdnqv/ylhFPs/e79ftorIn0Qkya6xi8ijIlItIlsDjg05VhE5WUQ+8973CxGRY712xCZhIpIqIo+LyG9F5Fqr4wkHIjJBRB4RkTVWxxIuRORS7/fY8yJyntXxhAMRmS4iD3n/uHzF6nisJCKxwIPAhcAMYKWIzLA2qj5cwDeNMdOBJcCd3hjvBt4wxkwG3vDexnvf1cBM4ALgV973aaV/AnYE3A6X2P8X+KsxZhowF897sH3sIjIW+DqwwBgzC4j1xmbX2B/zvm6g44n118BtwGTvv97P2UdYJWHBslXv8WCfJC8H1hhj/hG4JOTB2sRQrpkxpswYc4s1kdrHEK/Zc97vsRuBL1kQri0M8ZrtMMbcAXwRCMsl6sNoEbDH+7PXCTwFrLA4ph6MMUeMMR95v27GkwiMxRPn497THgcu9X69AnjKGNNhjNkH7MHzPi0hIkXAF4CHAw7bPnYRyQBOBx4BMMZ0GmMaCYPYveKAZBGJA1KACmwauzHmHaC+1+EhxSoio4EMY8wG41nx+PuAx/QrrJIwgmSrA3ySLAIOeU/rDmGMdvMYg79myuMxhn7N7vXeH60eYwjXTEQuAd7D8wkzmo3l6O8pgHLvMVsSkRJgPvABUGCMOQKeRA3I955mt/f0c+BfAXfAsXCIfQJQA/xOPFOpD4tIKmEQuzHmMPAT4CBwBGgyxrxKGMQeYKixjvV+3fv4gMIqCesnW+3vk2Q5nkQMwux9DqchXjPF0K6ZeDwAvOIbLYhGQ/0+M8asNcacCkR7qUCwmhFb9g0SkTTgaeAbxhjHQKcGOWbJexKRi4FqY8zmwT4kyDGr/n/EAScBvzbGzAda8U6J9cM2sXvrp1YApcAYIFVErhvoIUGO2fLngP5jPa73EAnJSX9Z6TPAFSLya3QLld6CXjMRyRWRh4D5InKPNaHZVn/fZ18DzgGuFJE7rAjMxvr7PjvTW7T6G+Bla0KzjXJgXMDtIjzTNrYiIvF4ErAnjTHPeA9Xeadg8P632nvcTu9pKXCJiOzH8yHgLBF5gvCIvRwoN8Z84L29Bk9SFg6xnwPsM8bUGGO68Pw9PpXwiN1nqLEGDvwEHh9QJCRhQbNPY0yrMeYmY8xXjDFPhjwqe+vvmtUZY+4wxkw0xvwo5FHZW3/X7BfGmJO91+2hkEdlb/1ds7eNMV83xtxujInmKVyAjcBkESkVkQQ8Bb9rLY6pB+8Kr0eAHcaY/wm4ay1wg/frG4DnA45fLSKJIlKKp0D5w1DFG8gYc48xpsgYU4Ln2r5pjLmO8Ii9EjgkIlO9h84GthMGseOZhlwiIine75+z8dQShkPsPkOK1Ttl2SwiS7zv+csBj+lX3PDHHXJ2zKDtTq/Z0Ok1Gzq9ZsdgjHGJyF3AOjwryB41xmyzOKzelgLXA5+JyCfeY98B7gdWi8gteP7oXgVgjNkmIqvxJAwu4E5jjN3qcsMl9q8BT3oT9DLgJjyDJ7aO3RjzgXhW2X/kjeVjPFv9pNkxdhH5E3AmMEpEyoHvcXzfI1/BUx+bDLzi/Tfwa4fbtkXewtAXvcte8a682I0n0z6M55PlNTb8RWYZvWZDp9ds6PSaKaXU0ITVdKQ3W90ATBWRchG5xRjjAnyfJHcAq/WX/FF6zYZOr9nQ6TVTSqmhC7uRMKWUUkqpSBBWI2FKKaWUUpFCkzCllFJKKQtoEqaUUkopZQFNwpRSSqlhICIlvfdPVWogmoQppZRSSllAkzCllFJqmInIBO/G2wutjkXZlyZhylZ0OF8pFe68Ww09DdxkjNlodTzKviJh2yKllFLKLvLw7Bl4hTYnVseiI2HKtnQ4XykVhpqAQ3j23FRqQDoSpmzJO5z/FJ7h/E+Odb5SStlEJ3ApsE5EWowxf7Q6IGVfmoQpO9LhfKVU2DLGtIrIxcBrItJqjHne6piUPWkSpuwocDhfkzClVFgwxuwHZnm/bgS0lEINSJMwZUc6nK+UUiriaRKmbEmH85VSSkU6McZYHYNSSimlVNTRFhVKKaWUUhbQJEwppZRSygKahCmllFJKWUCTMKWUUkopC2gSppRSSillAU3ClFJKKaUsoEmYUkoppZQFNAlTSimllLLA/wcAdbOsgNhdrQAAAABJRU5ErkJggg==", "text/plain": [""]}, "metadata": {"needs_background": "light"}, "output_type": "display_data"}], "source": ["fig, ax = plt.subplots(1, 2, figsize=(10, 4))\n", "piv = df.pivot(\"k\", \"name\", \"average\")\n", "piv.plot(ax=ax[0], logy=True, logx=True)\n", "ax[0].set_title(\"top k for 2000 rows\")\n", "piv[\"ratio\"] = piv[\"topk_cpp\"] / piv[\"topk_sklearn\"]\n", "piv[[\"ratio\"]].plot(ax=ax[1])\n", "ax[1].set_title(\"ratio\")\n", "ax[0].set_xlabel(\"k\")\n", "ax[1].set_xlabel(\"k\");"]}, {"cell_type": "markdown", "metadata": {}, "source": ["The implementation is half faster in all cases and much more efficient for small values which is usually the case for the nearest neighbors. This implementation is using *openmp*, maybe that's why it gets 50% faster on this two cores machine."]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [], "source": []}], "metadata": {"kernelspec": {"display_name": "Python 3", "language": "python", "name": "python3"}, "language_info": {"codemirror_mode": {"name": "ipython", "version": 3}, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.7.2"}}, "nbformat": 4, "nbformat_minor": 2}