{
"nbformat": 4,
"nbformat_minor": 0,
"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.3.5"
},
"colab": {
"name": "2. - Matrices for data scientists.ipynb",
"provenance": [],
"include_colab_link": true
}
},
"cells": [
{
"cell_type": "markdown",
"metadata": {
"id": "view-in-github",
"colab_type": "text"
},
"source": [
""
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "qmxOoUHSKz1-",
"colab_type": "text"
},
"source": [
"# Matrices for data scientists"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "fjZox9_qKz2D",
"colab_type": "text"
},
"source": [
"#### Guillermo Moncecchi"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Pag1HfZfKz2J",
"colab_type": "text"
},
"source": [
"If you wanto to do machine learning, you need to work with matrices with the same fluency you have with numbers.This notebooks aims to review the main properties of matrices, show the intuition behind them, and inspect how to manipulate them using `numpy` and `scipy` (see [the difference](http://www.scipy.org/scipylib/faq.html#what-is-the-difference-between-numpy-and-scipy)). It is not a numpy/scipy tutorial, but a brief introduction to matrices, showing also how to manipulate them using Python 3.\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "aBvRL6jlKz2L",
"colab_type": "code",
"colab": {}
},
"source": [
"%matplotlib inline\n",
"import numpy as np, scipy as sp, matplotlib.pyplot as plt"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {
"id": "ZFEdlHaWKz2X",
"colab_type": "text"
},
"source": [
"### 1. Very basic operations"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "GHiCw09DKz2a",
"colab_type": "text"
},
"source": [
"First, let's create some numpy arrays, the common structure for dealing with n-dimensional matrices. I will mostly work with two-dimensional matrices since are easier to interpret, but most results admints n-dimensional matrices."
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "3ceVDWyXKz2d",
"colab_type": "text"
},
"source": [
"First, let's create a 2D-numpy array, and show that its elements are integers."
]
},
{
"cell_type": "code",
"metadata": {
"id": "LtYv3WU0Kz2f",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 146
},
"outputId": "4e6efbce-dc2d-4922-c6b9-d4c9fc2c6ac9"
},
"source": [
"# Specify each row of the matrix as a Python list\n",
"A=np.array([[0,0,1],[1,1,0],[1,1,1]])\n",
"print (A)\n",
"print (A.dtype)\n",
"\n",
"print (np.sum(A))\n",
"print (np.sum(A,axis=0))\n",
"print (np.sum(A,axis=1))"
],
"execution_count": 2,
"outputs": [
{
"output_type": "stream",
"text": [
"[[0 0 1]\n",
" [1 1 0]\n",
" [1 1 1]]\n",
"int64\n",
"6\n",
"[2 2 2]\n",
"[1 2 3]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "iD6R6NKKKz2o",
"colab_type": "text"
},
"source": [
"Create an matrix of 3 rows by 4 columns, filled with zeros and another filled with ones."
]
},
{
"cell_type": "code",
"metadata": {
"id": "Yk71MWwAKz2r",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 72
},
"outputId": "1a80459c-a76e-433c-cb3b-76694c01039c"
},
"source": [
"print (np.zeros((3,4)))\n"
],
"execution_count": 3,
"outputs": [
{
"output_type": "stream",
"text": [
"[[0. 0. 0. 0.]\n",
" [0. 0. 0. 0.]\n",
" [0. 0. 0. 0.]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "c3qPlp62Kz2z",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 72
},
"outputId": "5850c8bc-9cd5-4ea1-ca25-8a616a2a5f72"
},
"source": [
"print (np.ones((3,4)))"
],
"execution_count": 4,
"outputs": [
{
"output_type": "stream",
"text": [
"[[1. 1. 1. 1.]\n",
" [1. 1. 1. 1.]\n",
" [1. 1. 1. 1.]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "JSWKOcmLKz27",
"colab_type": "text"
},
"source": [
"1D-arrays in Python are always row vectors, i.e. **vectors are just $1\\times n$ matrices**:"
]
},
{
"cell_type": "code",
"metadata": {
"id": "SLU8_-XFKz2-",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"outputId": "9647a36a-3ba0-4ca1-da37-3eb58aba47c1"
},
"source": [
"print (np.ones(10))\n",
"print (\"Size:\"+ str(np.ones(10).size))"
],
"execution_count": 5,
"outputs": [
{
"output_type": "stream",
"text": [
"[1. 1. 1. 1. 1. 1. 1. 1. 1. 1.]\n",
"Size:10\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "i6dqXAwpKz3F",
"colab_type": "text"
},
"source": [
"**First operation: matrix sum** (both matrices should have the same dimensionns)"
]
},
{
"cell_type": "code",
"metadata": {
"id": "QHKz4WuSKz3H",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 72
},
"outputId": "f1018735-8615-46b7-d7ba-49a8b3b8c394"
},
"source": [
"A=np.array([0,1,1,0,0,1,1,1,1]).reshape((3,3))\n",
"B=np.array([1,1,1,1,0,1,0,1,1]).reshape((3,3))\n",
"print (str(A + B))\n"
],
"execution_count": 6,
"outputs": [
{
"output_type": "stream",
"text": [
"[[1 2 2]\n",
" [1 0 2]\n",
" [1 2 2]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "72MTq0yzKz3O",
"colab_type": "text"
},
"source": [
"If the two matrices have different dimensions, numpy __upcasts__ matrices (adding elements to make both matrices compatibles). In the following example the only row in b is repeated to make b a 2x2 matrix"
]
},
{
"cell_type": "code",
"metadata": {
"id": "ZMh8gUN2Kz3P",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 109
},
"outputId": "e6e9a1a7-69ac-4b23-a2d3-07ad7154f1fa"
},
"source": [
"A=np.array([0,1,2,1]).reshape((2,2))\n",
"B=np.array([0,1])\n",
"\n",
"print (A)\n",
"print (B)\n",
"print (A + B)"
],
"execution_count": 7,
"outputs": [
{
"output_type": "stream",
"text": [
"[[0 1]\n",
" [2 1]]\n",
"[0 1]\n",
"[[0 2]\n",
" [2 2]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "g711pbAiKz3Y",
"colab_type": "text"
},
"source": [
"**Second operation: multiply a scalar by a matrix**. "
]
},
{
"cell_type": "code",
"metadata": {
"id": "e0DOdCOXKz3a",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"outputId": "10dbcfdc-8e5d-444b-ee3b-b9550e269d3c"
},
"source": [
"a=8.1\n",
"B=np.ones((2,3))\n",
"print (a*B)"
],
"execution_count": 8,
"outputs": [
{
"output_type": "stream",
"text": [
"[[8.1 8.1 8.1]\n",
" [8.1 8.1 8.1]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "4w3iydjPKz3i",
"colab_type": "text"
},
"source": [
"**Third operation: Matrix product**. Given $A(n,p)$ and $B(p,m)$, $A.B=C$, where $C=((c_{ij}))$ and $c_{ij}=\\Sigma_{h=1}^p a_{ih}b_{hj}$"
]
},
{
"cell_type": "code",
"metadata": {
"id": "BwIreZvPKz3k",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 146
},
"outputId": "434d20b4-d5da-459f-bee9-feb835fc8602"
},
"source": [
"A=np.array([1,2,1,0,1,1,0,1,1,0,0,0]).reshape(4,3)\n",
"print (A)\n",
"B=np.array([[2,1],[1,1],[0,0]])\n",
"print (B)"
],
"execution_count": 9,
"outputs": [
{
"output_type": "stream",
"text": [
"[[1 2 1]\n",
" [0 1 1]\n",
" [0 1 1]\n",
" [0 0 0]]\n",
"[[2 1]\n",
" [1 1]\n",
" [0 0]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "code",
"metadata": {
"id": "mfe0AV0gKz3t",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 90
},
"outputId": "fa422ce0-0314-49c0-ef5e-1e7fe8dab39b"
},
"source": [
"print (A.dot(B) )"
],
"execution_count": 10,
"outputs": [
{
"output_type": "stream",
"text": [
"[[4 3]\n",
" [1 1]\n",
" [1 1]\n",
" [0 0]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "2GdRd7onKz3z",
"colab_type": "text"
},
"source": [
"or..."
]
},
{
"cell_type": "code",
"metadata": {
"id": "NedUvvhpKz3z",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 90
},
"outputId": "159d1ef1-228b-4817-865c-4efb5e0b6d34"
},
"source": [
"print (np.dot(A,B))"
],
"execution_count": 11,
"outputs": [
{
"output_type": "stream",
"text": [
"[[4 3]\n",
" [1 1]\n",
" [1 1]\n",
" [0 0]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "gk4Qi-r4Kz37",
"colab_type": "text"
},
"source": [
"I find easier to see matrix product as a matrix where each row in the product is the dot product of the corresponding row in A ($A_i$) and B. numpy allows to slice columns and rows:"
]
},
{
"cell_type": "code",
"metadata": {
"id": "qxfBuclZKz3-",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 109
},
"outputId": "8ae402b5-3a6c-45c6-93ad-bddb31c96b4a"
},
"source": [
"print (\"Shape of A:\"+ str(A.shape))\n",
"for i in range(A.shape[0]):\n",
" print (np.dot(A[i],B))"
],
"execution_count": 12,
"outputs": [
{
"output_type": "stream",
"text": [
"Shape of A:(4, 3)\n",
"[4 3]\n",
"[1 1]\n",
"[1 1]\n",
"[0 0]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "a5SFi1c6Kz4F",
"colab_type": "text"
},
"source": [
"Alternatively, we can see the product matrix as a matrix where each column is the dot product of A and the corresponding column in B ($B^j$)"
]
},
{
"cell_type": "code",
"metadata": {
"id": "MAlRiD21Kz4H",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 54
},
"outputId": "dcd4faf4-f702-4d07-c939-7dba89a76476"
},
"source": [
"for j in range(B.shape[1]):\n",
" print (np.dot(A,B[:,j]))"
],
"execution_count": 13,
"outputs": [
{
"output_type": "stream",
"text": [
"[4 1 1 0]\n",
"[3 1 1 0]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "XQ9CQc7YKz4L",
"colab_type": "text"
},
"source": [
"Note that resulting arrays are row arrays, not (as you could have expected) column arrays. The reason is simple: **1-D arrays in numpy are all the same (no matter if they row or column)**. If you want a column vector, you must use v.reshape(rows,1)"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "Ib2bLgedKz4N",
"colab_type": "text"
},
"source": [
"**Matrix transposition**: change columns into rows, and viceversa"
]
},
{
"cell_type": "code",
"metadata": {
"id": "Js2vA_vuKz4Q",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 146
},
"outputId": "dee67a5e-d134-41e3-c8ff-167fa37e11a0"
},
"source": [
"print (A)\n",
"print (np.transpose(A))"
],
"execution_count": 14,
"outputs": [
{
"output_type": "stream",
"text": [
"[[1 2 1]\n",
" [0 1 1]\n",
" [0 1 1]\n",
" [0 0 0]]\n",
"[[1 0 0 0]\n",
" [2 1 1 0]\n",
" [1 1 1 0]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "ZEG2N9kpKz4V",
"colab_type": "text"
},
"source": [
"An interesting property (prove it!): \n"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "m9SnUErPKz4X",
"colab_type": "text"
},
"source": [
"$(A\\cdot B)^t = B^t \\cdot A^t$ **[1]**\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "E47OYjugKz4Y",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 90
},
"outputId": "e4d01d7b-1849-4913-87d0-8320780ec929"
},
"source": [
"print (np.transpose(A.dot(B)))\n",
"print (np.transpose(B).dot(np.transpose(A)))"
],
"execution_count": 15,
"outputs": [
{
"output_type": "stream",
"text": [
"[[4 1 1 0]\n",
" [3 1 1 0]]\n",
"[[4 1 1 0]\n",
" [3 1 1 0]]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "PSVZRKA_Kz4e",
"colab_type": "text"
},
"source": [
"### 2. Matrices as linear transformations"
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "W2X7PHilKz4g",
"colab_type": "text"
},
"source": [
"From [Wikipedia](http://en.wikipedia.org/wiki/Matrix_%28mathematics%29): \n",
"\n",
"*A major application of matrices is to represent linear transformations, that is, generalizations of linear functions such as f(x) = 4x. For example, the rotation of vectors in three dimensional space is a linear transformation which can be represented by a rotation matrix R. If v is a column vector (a matrix with only one column) describing the position of a point in space, the product Rv is a column vector describing the position of that point after a rotation. **The product of two matrices is a matrix that represents the composition of two linear transformations.** *\n",
"\n",
"The following picture shows how the unit square is transformed under a linear transformation represented by a 2-by-2 matrix. I found that this use of matrices can let us imagine better the abstract properties we will describe. \n",
"\n"
]
},
{
"cell_type": "code",
"metadata": {
"id": "IjBmhL4aKz4i",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 423
},
"outputId": "acf9b4a4-02b7-413e-c0f4-3347119155c7"
},
"source": [
"from IPython.display import Image\n",
"Image(url='http://upload.wikimedia.org/wikipedia/commons/a/ad/Area_parallellogram_as_determinant.svg',width=350)\n"
],
"execution_count": 16,
"outputs": [
{
"output_type": "execute_result",
"data": {
"text/html": [
""
],
"text/plain": [
""
]
},
"metadata": {
"tags": []
},
"execution_count": 16
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "NAZqkyS_Kz4n",
"colab_type": "text"
},
"source": [
"The vectors represented by a 2-by-2 matrix correspond to the sides of a unit square transformed into a parallelogram.\n",
"Let's show this in Python. Suppose we have the matrix [[1,1],[2,1]]. This matrix represents a rotation, where each of point in $R^2$ (x,y) is mapped to (x+2y,x+y). Let's verify this:"
]
},
{
"cell_type": "code",
"metadata": {
"id": "UJKu1HtRKz4p",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 35
},
"outputId": "cedf007e-04c8-4996-f802-357afd4e9cb8"
},
"source": [
"Ex=np.array([[1,1],[2,1]])\n",
"print (np.dot([1,1],Ex)) # [1+2,1+1]"
],
"execution_count": 17,
"outputs": [
{
"output_type": "stream",
"text": [
"[3 2]\n"
],
"name": "stdout"
}
]
},
{
"cell_type": "markdown",
"metadata": {
"id": "7b63P95BKz4u",
"colab_type": "text"
},
"source": [
"Let's see how the unit square is transformed under our Example matrix. First let us write a function that shows the transformation of the unit square under any matrix transformation"
]
},
{
"cell_type": "code",
"metadata": {
"id": "Oj3-VWoPKz4v",
"colab_type": "code",
"colab": {}
},
"source": [
"def transform_unit_square(A):\n",
" nxp=20\n",
" nxq=20\n",
" p = np.linspace(-1.0,1.0,nxp)\n",
" q = np.linspace(-1.0,1.0,nxq)\n",
" m=np.meshgrid(p,q) # Create grid for plotting\n",
" xx=m[0]\n",
" yy=m[1]\n",
"\n",
" # Apply transform to every point in grid.\n",
" for i in range(nxp):\n",
" for j in range(nxq):\n",
" x = np.array([xx[i][j], yy[i][j]])\n",
" y = np.dot(A,x) \n",
" plt.plot(x[0], x[1], '.b', y[0], y[1], '.r')\n",
"\n",
" plt.suptitle('Using the transform y=Ax on a grid of points')\n",
" plt.axis('equal')\n",
" plt.show()\n",
" \n"
],
"execution_count": 0,
"outputs": []
},
{
"cell_type": "code",
"metadata": {
"id": "W295AYX4Kz4y",
"colab_type": "code",
"colab": {
"base_uri": "https://localhost:8080/",
"height": 294
},
"outputId": "cbaca693-b2a8-4d1b-9e34-10ea7f572bf2"
},
"source": [
"transform_unit_square(Ex)"
],
"execution_count": 19,
"outputs": [
{
"output_type": "display_data",
"data": {
"image/png": "iVBORw0KGgoAAAANSUhEUgAAAXIAAAEVCAYAAAD91W7rAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjMsIGh0\ndHA6Ly9tYXRwbG90bGliLm9yZy+AADFEAAAgAElEQVR4nO3de5wkZX3v8c9vemaWRbzCGMNlXeWW\ng6yyuILrstk5gDmoKIHxEm4KXvZ4jBE8eEwQbwnxoOGYICEe4YV3ETUOHAwSBFYHdmHAXW4KIoiE\nu8iwQlBAZ2f6d/54qndreqq7q7uqu7qnv+/Xq7cvT3X1Uz29z9T8+ltPmbsjIiK9a6DoDoiISDYa\nyEVEepwGchGRHqeBXESkx2kgFxHpcRrIRUR6nAbyBszsdjMb7dBrfcXM/r4Tr9VOFnzZzB43sx8X\n3R9Jz8xWm9mdddpb/oya2ZFm9oCZ/c7Mlrfey3nrXRKts5TXOntNXwzkZuZmtkfVY580s280eq67\nv8zdJ9rQpxPMbEPe642tf8LM3t2u9TdwEPBaYFd3P6CgPuTCzF5iZmUz+79F96UT3H29u+/dptX/\nH+D97r6Du9+c10rd/f5onbONljWzpdF4MJjX63eDvhjIZb42f5BfDNzr7k81+8Qu/A/2duBx4G1m\ntqjozrRTB977FwO3t/k1+pIGcsDMdjKzS83sCTP7jZmtN7OBqO1eMzs0uv1JM/uOmX3NzH4blV1W\nxNazv5ndHLX9q5l9O+nPUDP7L8AXgJXRn4RPxJqfb2bfj9Zxg5ntHnven5jZlVEf7zSzt9bYnk8B\nq4FzovWfEz3uZvaXZvYL4BfRY5+L/tx90sxuNLPVsfU02t6/NrOHorY7zewQM3sXcH5s2/42WvY9\nZnZ31PfvmdnOsfUk9cvN7H1m9oto/aeb2e5mdl3U1++Y2XDCtg9Hr7Es9tgLzexpMxtJer9qMTMj\nDOQfBbYAb4y1vcbMHjOz3aL7r4hKSX9SY12vMbONZvaf0fVrYm0T0fZdG23rFWa2U431PD/6rE5F\nr3epme1aZxtqfibNbNTMHox+jo8AX648Fnv+cjO7KXr+t4Ht6rzWgJl91MzuM7NHo8/Nc81skZn9\nDigBt5rZL2s8383sA2Z2T/Tenmnb/h8mrjtqm7OX3eD9vCa6fiL6fK40sz3M7OroZ/NYtJ29xd0X\n/AVwYI+qxz4JfCO6fQZhYB2KLqsBi9ruBQ6NPef3wOsJH8ozgOujtmHgPuCkaB1HAdPA39fo0wnA\nhqrHvgJsBg4ABoELgG9Fbc8CHgBOjNqWA48B+9RY/wTw7oT34UrgBcDi6LHjgB2jdZ4CPAJsl2J7\n9476s3N0fymwe9K2AQdHfd0fWAT8M3BNg345cAnwHOBlwB+AdcBLgecCPwPeUWPbPw98Jnb/JODf\nottLgCfqXI6JPW919LrPj/r8b1Wv8yngh8Bi4KeEskFSf15A2Ks/Pnqfj47u7xj7Wf0S2Cta1wTw\n6Rrr2hEYA7YHng38K/D/aixb9zMJjAIzwGein8vi6LEHq57/wej5byb8Qqv1mX4ncHf0M9oBuAj4\ner3/hwmfzx9F79cS4C6iz3C9dRM+ew4MNno/q5eNHrsQOI2wY7sdcFDRY1azl8I70JGNbDyQ/x1h\n0Jj3IWP+QH5VrG0f4Jno9p8CDxH9Aoge21DnQ38CyQP5+bH7rwd+Ht1+G7C+avlzgU/UWP8EyQP5\nwQ3eq8eBV6TY3j2AR4FDgaF62wZ8EfiH2P0dogFhaa1+RY+tit2/Efjr2P3PAmfV2IYDgfvZ9st4\nE/DWFj435xMNksDKqM8vjLUPRf36KXB5/GdftZ7jgR9XPTYJnBD7WX001vY+4PKUfdwPeLxGW93P\nJGHQnib6xR177MHY8x+uev51dT7T64D3xe7vHb1nlQE2zUB+WNX7sK7RukkeyBPfz+plo8e+BpxH\n+E6n8PGqlUu/lFZmCf/p4oYIHwSAMwm/7a+I/qz7mzrreiR2+2lgu+hPup2Bhzz6ZEQeaKGv1evf\nIbr9YuBAC+WfJyyUY44FXtTk+uf0ycw+ZGZ3RH9WPkHY243/WZ+4ve5+N3AyYbB/1My+FS+XVNmZ\nsGcHgLv/jvCXxy61+hX5dez2Mwn3dyCBu98Q9XU0KnXsAXyvRt8Smdli4C2Ev4pw90nCL4djYq+z\nhfDLd1/gs1U/+7g52x+5j7nbX+vnXt2v7c3s3KjE8CShVPA8S05spPlMTrn77+v0u/r51dtRvXy8\n/T7CQPtHdZ5TLd6/+6J1trLuVO9n5MOAAT+2UD58ZxP97Qr9MpDfT/hNHPcSog+Gu//W3U9x95cC\nbwL+p5kd0uRr/ArYJaqrVuxWZ/lmp518ALja3Z8Xu+zg7v+jyfVvfdxCPfzDwFuB57v784D/JHyo\nG3L3b7r7QYRfMk74Ez3Jw9Eyldd9FqFE8FCK/rbqq4Sy0fHAdyuDlW2LqtW6HBs9/0hCWefzZvZI\nVEPeBXhHbDt2AT4BfBn4rNX+MnTO9keWMHf70zqFsDd6oLs/h7DXDMk/szSfyXrve9Lzl9RZvno7\nlxBKN79OXjxRvH9LonXmtW5I2F53f8Td3+PuOwP/nfAz32P+U7tXvwzk3wY+ama7Rl+aHEr44uq7\nAGZ2ePSFhxEGslmg3ORrTEbPe7+ZDZrZEYRady2/Bna1hC/sargU2MvMjjezoejyKgtfnNZa/0sb\nrPPZhP8MU8CgmX2cMHg1ZGZ7m9nB0eD1e8Iecq337ELgRDPbL1r+fwM3uPu9aV6rRd8gDMbHEf50\nBuZE1WpdLogWfQfwJWAZoXyxH7AKeIWZLYs+K18hlI3eRRj0Tq/Rl8sIP7tjos/G2whlqktb2K5n\nE97rJ8zsBYRfJLU0+5lMev4M8IHo83ZUg+dfCHzQQmRzB8LP+dvuPtPEa/4vC1/o7kao7Ve+eMxj\n3RA+62Vi/zfM7C227QvjxwmDfbP//wvVLwP53xFqexsIP6h/AI5199ui9j2Bq4DfET68n3f3HzXz\nAu4+Tfgy6V2EL82OI/xH/UONp/yQEMV6xMweS7H+3wJ/BvwFYe/kEbZ9SZXkc8CbLSQbzq6xzA8I\ntd27CH+d/J705aBFwKcJX2I+ArwQOLVG368CPgaMEwa83aPtaBt3fwC4ifCfcn0zz432tA8h1OAf\niV1uJLxf7wA+QNjmj0WlhxMJv6xWV6/P3TcDhxP2pjcT/go63N0b/twTnEX4Au8x4PqoP4la+EzW\nev4JwG8I39NcVOcpXwK+Tij3/Afh8/RXaV4r5hLC9w63AN8n/KLMa924+9OEL6mvjUqUrwZeBdxg\nIVnzPeAkd7+n2XUXqfJlkLSBmd0AfMHdv1x0X/qRmX0JeNjdP1p0X7pFN38mzcyBPaPvX6QJ3Xbw\nRU8zszXAnYS9pWOBl1Nnj0nax8yWEvYmczsUvBfpM9kfNJDna2/gO4TM9z3Am939V8V2qf+Y2emE\n7PMZ7v4fRfenYPpM9gGVVkREely/fNkpIrJgaSAXEelxGshFRHqcBnIRkR6ngVxEpMdpIBcR6XEa\nyEVEepwGchGRHqeBXESkx2kgFxHpcRrIRUR6nAZyEZEep4FcRKTHaSAXEelxhcxHvtNOO/nSpUuL\neGkRkZ514403PubuI9WPFzKQL126lE2bNhXx0iIiPcvM7kt6XKUVEZEep4FcRKTHaSAXEelxGshF\nRHqcBnIRkR6XeSA3s+3M7MdmdquZ3W5mf5tHx0REJJ089sj/ABzs7q8A9gMOM7NX57BeESnC5CSc\ncUa4lp6QOUfu7g78Lro7FF0863pFpACTk3DIITA9DcPDsG4drFxZdK+kgVxq5GZWMrNbgEeBK939\nhoRl1prZJjPbNDU1lcfLikjeJibCID47G64nJorukaSQy0Du7rPuvh+wK3CAme2bsMx57r7C3VeM\njMw7wlREusHoaNgTL5XC9eho0T2SFHI9RN/dnzCzHwGHAbfluW4RaaPJybD3PToayimV2yqr9ITM\nA7mZjQBbokF8MfBa4DOZeyYinZFUFz/11KJ7JU3Io7Tyx8CPzOwnwEZCjfzSHNYrIp2gunjPyyO1\n8hNgeQ59EZFOiZdSRkdDTbxcDteqi/ecQqaxFZECVZdSzjoLzEJb5Vp6ig7RF+k31aWU8XGYmQH3\ncK3SSs/RQC7Sb6ojhmNjihz2OJVWRPpFvC5+1llhT3xsDNauhWXLFDnsYRrIRfpBvC5eKoVa+MwM\nrF8fBvGVKzWA9zCVVkT6QbwuvmWL4oYLjPbIRRaqehHDyh654oYLggZykYUobcRQccMFQaUVkYWo\nUcRQccMFRQO5yEJUL2I4NKS44QKj0orIQlIvYgjb7ituuKBoIBdZKOpFDAFOPjm0rV+vGQ4XGJVW\nRBaKehHD8XFFDhcwDeQivSx+ouRKxNAsXA8Obrs9Nja3TXXxBUWlFZFe1WzEUDMcLljaIxfpVc1E\nDDXD4YKmgVykVzUTMdQMhwuaSisivSZtxDB+WzMcLmgayEV6SdqI4cSEZjjsIyqtiPSStBFDzXDY\nVzSQi3S7ViOG8TbVxBc0lVZEulkeEUPFDRc87ZGLdLMsEUPFDfuGBnKRblQpp+y449xySb3ySXWb\n4oZ9I3Npxcx2A74G/BHgwHnu/rms6xXpW9XJFPfweJrySeW6VIKzz4bNmxU37AN51MhngFPc/SYz\nezZwo5ld6e4/y2HdIv0nXk4pl8Njtcon9do2b9YMh30ic2nF3X/l7jdFt38L3AHsknW9In0rfsRm\nvSM0dfSmRHJNrZjZUmA5cENC21pgLcCSJUvyfFmRhaHWEZuQ/ujN+H2VU/pGbgO5me0AjAMnu/uT\n1e3ufh5wHsCKFSs8r9cVWRBqHbFZfYQm1D56M94WP5pTFrxcUitmNkQYxC9w94vyWKdIX6l1xGYz\nR2/q5BF9K/NAbmYGfBG4w93/MXuXRPpE2iM20x69qRp538qjtLIKOB74qZndEj32EXe/LId1iyxM\nzR6xGb9da7lly8K5ODXDYd/JPJC7+wZAxwCLNKPREZuQLmIYb5uYCHFDDeB9R0d2ihQh7Ukhmokf\nqpTStzRplkgntXJSiPjtestpT7xvaSAX6ZRWTgrRTPxQccO+pdKKSKe0clIInTxCUtBALtJOeZwU\nQjMcSgMqrYi0S94nhdAMh1KDBnKRdmkmYthq/FAzHAoqrYi0T9qIYavxQ5VTJKI9cpG8tRIxbDV+\nqHKKoIFcJF+tRAxbjR8qcigRlVZE8tRKxLDV+KEihxLRQC6SVR4Rw2bih6qRSxWVVkSyyDNimCZ+\nqBkOJYEGcpEs8ooYpo0faoZDSaDSikgWeUQMm4kfqpQiCbRHLtKKvCOGaeOH2hOXBBrIRZqVd8Sw\nmfih4oaSQKUVkWblHTFsJn6ouKEk0EAukka7I4b12lQjlwZUWhFppFMRw6Q2zXAoKWggF2mkExHD\nem2a4VAaUGlFpJF2Rwx1UmXJSHvkIrV0MmKokypLBhrIRZJ0MmKokypLRrmUVszsS2b2qJndlsf6\nRArXyYihTqosGeW1R/4V4BzgazmtT/pMvIqxcuXc+9Chtq/dxyhXw/LlTNx/DKP276y0DUwOrGLC\n1zDqPwQbZGL70xm1Z4AZJuy/MmrXsLJ8LZP2mvzaShtYWb5WNXJJx91zuQBLgdvSLPvKV77SRSqu\nu8598WL3Uilcn3vutvvDw+6LFnWgbdGMl9jiwzzji3jGSzbri3nKz+U9vpin5rVtvc2Wucvl1Ta0\nxa9771fDmyMSATZ5wpjasRq5ma0F1gIsWbKkUy8rPSAp3Ve5Xy6HZdzb3WbMUqKMRW0DTDPEOEcx\nzTCzDM5pKzMUblNiGt+2XF5tM7NMLHm7SuOSSsfih+5+nruvcPcVIyMjnXpZ6QFFp/tCm1NiC0Ns\nYZgtlAbKDLOFMbuYYabntW29HV1vXS6vNlVUpAlKrUjhVq4sNt0X2kqMf+5hxnwc9l/O+NQaxkY2\nsnbqXhjZyPjNL61quwFuuplxG2Ns+T3blsvQdvzIBNvftJ4L7Whee9K+2huX9JLqLa1cUI1cWtTV\nNXJbm65GXlmuxbZVdq0/xWLfQsmfYrGvGb5O5XGZhxo18rzihxcCk8DeZvagmb0rj/VKf6hXI+9c\n8s+YZZAtDDHNELOVGrkfubVGHm/bepvBucu12Lbar2aYaQaZZYhpVm2ZUOpQUstlIHf3o939j919\nyN13dfcv5rFe6Q+jo9sm+xscDOWO+P22tg2UGdv+MgZLZcJQPsMgsxjOILOMcRGDzCS0VW7PVi2X\nvm0oahtihqtZw3Sser5hcFQ1cklNNXLpCqE6l3xdmQww/zbHt0zDJZfgfjAwhAOGh7ZK32LX8TaL\nWuYul65tCffzZU5kDevZk7s40b7KfxtYxxqf4IflUW40FcglPQ3kUriJiVDmcA/X4+Nz70O72kLk\ncNyPZJZBnBJRE85AaOOoGm2D0e0Ss5Rjy6VrO5pvsZoNDFDmIDZwtH+Tz5RP5VpW4kBpNrwv+sJT\n0tDsh1K4wuKHA143YtjO+OF6DmKaYcoDYan1A6Oa9FBapj1yKVxx8UNrEDHMP34YjxhuXH4Wa6bG\n2TgyxrOmVvLPmvRQWpUUZWn3RfFDiSssfjhQrhsxzDt+GI8YPsOwP8Min7UQN1w1cN28Pit+KNVo\nZ/xQJIvC4odlqxsxzDt+ODdiGJYa8BA3XF2e0KSH0jIN5FK4zsYPnUGbCXFDaxQxzB4/rI4YzlBi\nFmMmqqBXauRXMzqvz6qRS1oayKUr1IsfNlomdVt5Frwcrme2gCdHDKkTP5zbVjtiSBQxvIzDeDdf\n5DIO40U8ApWJtyjxwdLZbHrT6Rw2uI7rbWVin0XS0JedUriOxQ9nLIoARm0NI4bZ4ofVEcM/sIhB\nZijhlJnhBeXNfOzpU7nOk/us+KGkpT1yKVxHSytNlU9aK60MMcMQM1zDamYoUbaQV7+Isa2llVlK\nbBgcrdtnlVYkLe2RS1foyJGdsVJI2qM367UlHb0Zjth8B4PMcBd7YYA5VEoq8es0fRZJQwO5FG4h\nlVaO5pusZgODzPIargPCgF9ihqMYn1NaWT07wfj4ypp9VmlF0lJpRQrXuSM7mzt5RCtHdq63+ORX\nQ3OSKRfb2JyJsa4dGq3bZ5VWJC3tkUvh2n5k536/ZO3m78BJb2X80uEmjt5Md2Tn8ctv57ipe9l+\n5Bq+PnUYG0fO4qU3jzPuYyzfn61Hb947tZYr9lvGzndN8M2HRznmXSvrbo/2xiW1pKOE2n3RkZ0S\n19YjOzMcvZnmyM5VXONPsXjrEZpr7dymjt6stz06slOqoSM7pVu19cjODEdvpjmyczUbGI4doXmk\njzd19Ga97dGRnZKWBnIpXHvjh1kihrXb0kQMZygxw+DWtqSjNxU/lDyoRi5doa3xQ+ZfZ4kfNhMx\nrG5rdntE0tBALoVrb/zQMkQMk9vSRgxhZk7bGia4fnZl6u1R/FDSUmlFCtfW+GGGk0fUaksfMZzb\nlnTyCMUPJQ/aI5fC5R4//OLjjO08CXvtzfgtu2eIGG5ru/LmHTnaL+Tp/Vc3jBhuHGFr29I3LuPP\nnzfBFU+M8qxb5p88QvFDyUVSlKXdF8UPJS7X+OGimdwihpW2Nfxwa6SwUcQw3vYUi33N8HUtb4/i\nh1KNGvFD7ZFL4erFD8vlsIx72rZQEy9v/XJxfoyw2bZVXLc1UuhVEUMjdGLAfV780Jlm1ZZwGH4r\n26MauaSlGrkULvf4YQ4RwwGiGjkXcS2r5sxaWC9i2OwMh4ofSh5y2SM3s8OAzwEl4Hx3/3Qe65X+\nkVv8MKcZDnfjAb7C2/lTNvBKNm4NFKaJGDY7w6Hih5JV5j1yMysB/wK8DtgHONrM9sm6XukfjeKH\nMzNNtM1YFBUM+9bJMcLGbUfzTQ7iWgYosx+3MsgWSgkRw8FonzwpfljaOsNha9ujIzslrTxKKwcA\nd7v7Pe4+DXwLOCKH9UqfyDd+mM8Mh5WIYYgOzp3rsF7EsNkZDhU/lDzkUVrZBXggdv9B4MDqhcxs\nLbAWYMmSJTm8rCwUucQPc5jh8L6bNnO0Xcgdy4/l/Kk/Z+PIWayZGueGkTFuvgnGbJx7ls+PGGaZ\n4VDxQ8lFUpSlmQvwZkJdvHL/eOCces9R/FDiMscPc5jhsFbEcNa2RQzTxA+bneFQ8UNpBm2c/fAh\nYLfY/V2jx0RSyTz7YQ4zHMYjhvEYYZi5MDyjui2PGQ41+6HkIY+BfCOwp5m9xMyGgb8AvpfDeqVP\nZI8fth4xPIgNnM7HeZznJkYMy7YtYpgmftjsDIeKH0oeMtfI3X3GzN4P/IAQP/ySu9+euWfSVzLH\nD5l/3ShieCDXczmvZxF/4BXcuvVkynOihVGssJn4YS4zNip+KE3I5YAgd7/M3fdy993d/VN5rFP6\nR/b4YdIMh40jhmu4mkG2RHvtWyjFYoOVGKHFIoZp4odrmGg+Mqn4oWSkIzulcJnjhy3OcJgmYths\n/LDZGQ4VP5Q8aK4VKVzL8cP9fgl33cn4wysZ2/MnTUUMH1x+BP80dVzDiGGa+GGWGQ4VP5RcJEVZ\n2n1R/FDiWoofDpS3xQjZ0raIYaP4YdYZDhU/lGag2Q+lW7U0+2HZKDMU2igxjbc8i2GIDoYXKuGp\n2/KY4VCzH0oeVCOXwrUWP/RYxHC2bRHDRvHDrDMcKn4oedAeuXSFluKHsDUy2K6IYZr4YeYZGxU/\nlIy0Ry6Fay1+aLGIYaltEcNG8cOsMxwqfih50EAuhWspfjjgVaHA9kQMG8cPs81wqPih5EGlFSlc\n6vhhZYbDv3prdFLlG+Cmmxm3McaW39OWiGGttrxmOFT8UHKRFGVp90XxQ4lLFT+snuHQZhPjh3lH\nDJPa8pzhUPFDaQZtnP1QJJNUsx9Wz3DoA9tmMWQw0yyGzbblOcOhZj+UPGggl8Klix9Wz2LosYjh\nbNsihkltec5wqPih5EE1cukKqeKHxK89FjGc5HJexyKmc48Y1mrLM2Ko+KFkpT1yKVy6+GH1DIcD\nsYjh+theer4Rw6S2PGc4VPxQ8qCBXAqXKn5YPcPhQHlbxJCD2hYxTGrLc4ZDxQ8lDyqtSOHqxg9r\nzXA4tYYPjnyXXW++hAv9aDbun3/EMN528S+WcczOEzy8V74zHCp+KLlIirK0+6L4ocTVjB/WmeFw\nlV2beALkvCKG8bakyKHih1IEFD+UblUzfli2xIjhNMOs9qtrnAA5n4jh3Lb5kUPFD6WbaCCXwtWO\nHyZHDA9iPdewJvEEyHlFDONttSKHih9Kt9BALl2hZvww+rcSMXwVm7ic1/MybqPWCZDzihjG2+J9\nqnW7+jqPNpE0NJBL4WrHDy0xYlhiS80TIOcVMYy31YocKn4o3UIDuRSuZvwwNsPh3IhhvRMgtyN+\nOD9yqPihdBPFD6Vwc+KHVTMcJkUMN47MPwHy8v2zRwyTZjisd1Ll+G3FD6VQSVGWdl8UP5S4rfHD\nqhkOa0UMq0+A3I744aqB6+rGAxU/lCLQjvihmb3FzG43s7KZrcjpd4v0ma3xw6oZDmtHDOeeALkd\n8cPV5Ym68UDFD6WbZK2R3wYcBVyTQ1+kT1XihwPmqSKG1SdAbkf8sBI3rBcPVPxQukWmgdzd73D3\nO/PqjPQvdzjQw4mS00QMK48lteU5w2HSda3bih9KUTqWWjGztWa2ycw2TU1NdeplpQdU4odrmNh6\nouR6EcPqEyC3I35YiRvWiwcqfijdouFAbmZXmdltCZcjmnkhdz/P3Ve4+4qRkZHWeywLzuE7TvIR\nO4Pf2I5zjqa82JLLJ/XaqkskleXStFXPcFgvHqj4oXSThvFDdz+0Ex2RPjU5ybKTD2Hf8jSzAyUG\nzBmYheEh44g3wPD3DZuBkhkDAzRsGyoZ7jDgMDy4bbmBmQZtQyUuf8PZvOxFm3ly+Shv2LySM0dD\nBHDZsrB3XBlYk27XWy5Lm0ga5jkU48xsAviQu29Ks/yKFSt806ZUi8pCd8YZ8LGPhVpC/PQ4pRIc\ncgisW9dcW6vrKJXg9NPh1FM7u/0iTTCzG919XkIwa/zwSDN7EFgJfN/MfpBlfdKH4od15lGTaHUd\nqmVID8t0ZKe7XwxcnFNfpB9Vn1UCsh8S2cw64nUN1TKkR+VSWmmWSiuy1eRkKHFMT4c9Y7MQ3Rge\nDgP8ySc319bMOtat0+AtPaUtpRWRzOJnlcjjkEgdOil9SAO5dN7kZPiSc3IylDQqe8ql0rZDG0ul\nUP5opa3ecqqJywKk2Q+ls+KllErpo5ImsW3HVs57rNm2pPZSCc4+GzZvVk1cFhQN5NJZSSforBzO\nODMTlqncbrWt3nKbNytiKAuOSivSWTXPItGB+KHKKbJAaY9cOqs6btiOMzJUL6eIoSxwGsilsyYn\nt8UB168Pj1XuT0xsiwe22la93LJlYfDWAC4LmEor0llJNfJ2xg8VMZQ+oIFcOqMSOdxxx7lxwFYj\nhvXaVBOXPqPSirRf9dGblaOJs0YMk9oUMZQ+pIFc2i9eTimXw2NZI4b12hQxlD6j0oq0X94zHOqM\nDCJzaI9c2q8dMxxWtyliKH1MA7m0XzxymEfEsLpt/fowk6HKKdKnVFqR9st7hsPqNsUMpc9pIJf2\naPcMhzr0XmQrlVYkf52Y4XDZslBOUV1cRAO5tEEnZjicmAg1cQ3gIiqtSBu0e4ZDlVJE5tAeueSv\nXTMcKmIokkgDueSvHTMcKmIoUpNKK5K/dsxwqIihSE0ayCU/7ZjhUHVxkYYylVbM7EzgjcA08Evg\nRHd/Io+OSY9pxwyHihiKpJJ1j/xKYF93fzlwF6ACZr+qPnozHhusjhGmbZuYCIO3YoYidWUayN39\nCnePAr5cD+yavUvSk9oxw6FKKSKp5JlaeSfw7VqNZrYWWAuwZMmSHF9WukJeMxwqYijSNPNKLbPW\nAmZXAS9KaDrN3S+JljkNWAEc5Y1WCKxYscI3bdrUQnela1XXyCsxwsoh+pUYYb224eFQE9cALpLI\nzG509xXVjzfcI3f3Qxus+ATgcOCQNIO4LFC1zgJUHSOs11aJGGogF2lKphq5mR0GfBh4k7s/nU+X\npGfkNcOh6uIimWStkZ8DLJ1PKKgAAAUpSURBVAKutBAdu97d35u5V9L98prhUBFDkcwyDeTuvkde\nHZEek9cMh5rFUCQzHdkprclrhkOVUkQy06RZ0posMxwqYiiSKw3k0ppWZzjULIYiuVNpRVrT6gyH\nmsVQJHcayKU5rc5wqLq4SNuotCLptTrDoSKGIm2lgVzSq3X0piKGIoVSaUXSa3WGQ5VSRNpKe+SS\nXjMzHCpiKNIxGsglvXjkUBFDka6h0oqkV30WIEUMRbqCBnKpr5kZDlUXFymESitSWzMzHCpiKFIY\nDeRSWzMzHCpiKFIYlVaktmZmOFQpRaQw2iOX2hrNcKiIoUhX0EAutdWb4VARQ5GuodKK1FZvhkNF\nDEW6hgZyma/eDIeqi4t0HZVWZK56MxwqYijSlTSQy1z1ZjhUxFCkK2kgl7kqR2+Wy+G6VAqDuEop\nIl1LA7nMVzlqs1SCs8+GzZtVShHpYhrIZa6JiblHb27erIihSJfLlFoxs9PN7CdmdouZXWFmO+fV\nMSlI9dGcKqeIdL2se+RnuvvHAMzsA8DHgfdm7pV01uTk3CSKkikiPSXTQO7uT8buPgvwbN2Rjque\n4XDdujB4awAX6RmZDwgys0+Z2QPAsYQ98lrLrTWzTWa2aWpqKuvLSl6qj97U0ZoiPafhQG5mV5nZ\nbQmXIwDc/TR33w24AHh/rfW4+3nuvsLdV4yMjOS3BZKNauIiPa9hacXdD025rguAy4BPZOqRdJZq\n4iI9L1ON3Mz2dPdfRHePAH6evUvScaqJi/S0rKmVT5vZ3kAZuA8lVkREOi5ramUsr46IiEhrNI2t\niEiP00AuItLjNJCLiPQ4DeQiIj3O3Dt/VL2ZTRFSLt1iJ+CxojtRML0Hgd6HQO9D0G3vw4vdfd4R\nlYUM5N3GzDa5+4qi+1EkvQeB3odA70PQK++DSisiIj1OA7mISI/TQB6cV3QHuoDeg0DvQ6D3IeiJ\n90E1chGRHqc9chGRHqeBPMbMTjEzN7Odiu5LEczsTDP7eXQe1ovN7HlF96mTzOwwM7vTzO42s78p\nuj9FMLPdzOxHZvYzM7vdzE4quk9FMbOSmd1sZpcW3ZdGNJBHzGw34M+A+4vuS4GuBPZ195cDdwGn\nFtyfjjGzEvAvwOuAfYCjzWyfYntViBngFHffB3g18Jd9+j4AnATcUXQn0tBAvs0/AR+mj8876u5X\nuPtMdPd6YNci+9NhBwB3u/s97j4NfIswx35fcfdfuftN0e3fEgayXYrtVeeZ2a7AG4Dzi+5LGhrI\ngei0dQ+5+61F96WLvBP496I70UG7AA/E7j9IHw5gcWa2FFgO3FBsTwpxFmHHrlx0R9LIemKJnmFm\nVwEvSmg6DfgIoayy4NV7H9z9kmiZ0wh/Yl/Qyb5J9zCzHYBx4GR3f7Lo/nSSmR0OPOruN5rZaNH9\nSaNvBvJa5x41s2XAS4BbzQxCOeEmMzvA3R/pYBc7otE5WM3sBOBw4BDvr2zqQ8Busfu7Ro/1HTMb\nIgziF7j7RUX3pwCrgDeZ2euB7YDnmNk33P24gvtVk3LkVczsXmCFu3fTRDkdYWaHAf8IrHH3qaL7\n00lmNkj4gvcQwgC+ETjG3W8vtGMdZmFv5qvAb9z95KL7U7Roj/xD7n540X2pRzVyiTsHeDZwpZnd\nYmZfKLpDnRJ9yft+4AeEL/i+02+DeGQVcDxwcPQZuCXaM5Uupj1yEZEepz1yEZEep4FcRKTHaSAX\nEelxGshFRHqcBnIRkR6ngVxEpMdpIBcR6XEayEVEetz/B5ZaEa4ykywYAAAAAElFTkSuQmCC\n",
"text/plain": [
"