{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# 1A.e - TD not\u00e9, 11 d\u00e9cembre 2015\n", "\n", "Calcul des int\u00e9r\u00eat d'un emprunt pour acheter un appartement, strat\u00e9gie d'investissement."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["Populating the interactive namespace from numpy and matplotlib\n"]}], "source": ["%matplotlib inline"]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [{"data": {"text/html": ["
run previous cell, wait for 2 seconds
\n", ""], "text/plain": [""]}, "execution_count": 3, "metadata": {}, "output_type": "execute_result"}], "source": ["from jyquickhelper import add_notebook_menu\n", "add_notebook_menu()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Apr\u00e8s chaque question, on v\u00e9rifie sur un petit exemple que cela fonctionne comme attendu."]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Exercice 1 : Louer ou acheter un appartement ? \n", "\n", "A surface \u00e9gale, est-il pr\u00e9f\u00e9rable de louer ou d'acheter son appartement~? Cet exercice propose diff\u00e9rentes questions afin d'y r\u00e9pondre."]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q1 \n", "\n", "On suppose qu'on a $X$ euros d'apport, \u00e9crire une fonction qui calcule la somme d'argent obtenue apr\u00e8s $n$ ann\u00e9es d'un placement \u00e0 *r%* ? Par exemple, pour $n=2$, la fonction retourne $x + rx + r(1+r)x = (1+r)^2 x$."]}, {"cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [{"data": {"text/plain": ["1.0404"]}, "execution_count": 4, "metadata": {}, "output_type": "execute_result"}], "source": ["def rendement(x, n, r):\n", " return x*(1+r)**n\n", "\n", "rendement(1, 2, 0.02)"]}, {"cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [{"data": {"text/plain": ["1.0612080000000002"]}, "execution_count": 5, "metadata": {}, "output_type": "execute_result"}], "source": ["rendement(1, 3, 0.02)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q2\n", "\n", "Une banque pr\u00eate de l'argent \u00e0 un taux annuel $p$, c'est-\u00e0-dire au taux mensuel $m=(1+p)^\\frac{1}{12}-1$. Ce taux s'applique chaque mois sur la somme du capital restant \u00e0 rembourser. On emprunte $K$ euros avec une mensualit\u00e9 fix\u00e9e \u00e0 $M$ euros, \u00e9crire une fonction qui d\u00e9compose la mensualit\u00e9 $M$ en capital rembours\u00e9 et int\u00e9r\u00eat."]}, {"cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [{"data": {"text/plain": ["(570.6769646931234, 429.32303530687665)"]}, "execution_count": 6, "metadata": {}, "output_type": "execute_result"}], "source": ["def decompose_mensualite(K,M,p):\n", " i = K * ((1+p)**(1.0/12)-1)\n", " return M-i, i\n", "\n", "decompose_mensualite(180000, 1000, 0.029)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q3 \n", "\n", "Ecrire une fonction qui calcule toutes les mensualit\u00e9s.\n", "\n", "Lors d'un pr\u00eat \u00e0 taux fixe, en France tout du moins, ce que paye l'emprunteur \u00e0 sa banque est un montant fixe par mois : la mensualit\u00e9. L'emprunteur paye le m\u00eame montant chaque mois. Chaque mensualit\u00e9 se d\u00e9compose comme suit :\n", "\n", "* les int\u00earets correspondant \u00e0 la somme $K$ pour un mois : $i=Km$ o\u00f9 $m=(1+p)^{\\frac{1}{12}}-1$\n", "* la partie servant \u00e0 rembourser le capital : $cap=M-i$\n", "\n", "Cette partie $cap$ va \u00eatre \u00f4t\u00e9e au capital $K$ \u00e0 rembourser de sorte que le mois prochain, la somme pr\u00eat\u00e9e pour le mois sera moindre. Le r\u00e9sulat souhait\u00e9 pour cette question est une liste qui contient ce m\u00eame montant $M$ $n$ fois. Ce $n$ correspond \u00e0 la longueur du pr\u00eat. Et pour \u00eatre plus pr\u00e9cis, le m\u00eame montant $M$ r\u00e9p\u00e9t\u00e9 $n$ fois except\u00e9 pour la derni\u00e8re mensualit\u00e9."]}, {"cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [{"data": {"text/plain": ["19.666666666666668"]}, "execution_count": 7, "metadata": {}, "output_type": "execute_result"}], "source": ["def mensualites(K,M,p):\n", " res = []\n", " while K > 0:\n", " cap, i = decompose_mensualite(K,M,p)\n", " if cap < 0:\n", " raise Exception(\"probl\u00e8me avec K={0} cap={1} i={2} len={3}\".format(K,cap,i,len(res)))\n", " K -= cap\n", " if K < 0:\n", " res.append(M + K)\n", " else:\n", " res.append(M)\n", " return res\n", "\n", "len(mensualites(180000,1000,0.029))/12"]}, {"cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [{"data": {"text/plain": ["[1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000, 1000]"]}, "execution_count": 8, "metadata": {}, "output_type": "execute_result"}], "source": ["mens = mensualites(180000,1000,0.029)\n", "mens[:12]"]}, {"cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [{"data": {"text/plain": ["[1000, 1000, 1000, 1000, 1000, 459.63104825975415]"]}, "execution_count": 9, "metadata": {}, "output_type": "execute_result"}], "source": ["mens[-6:]"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Parfois ce calcul entre dans une boucle infinie : cela signifie que la somme $K$ ou le taux d'int\u00e9ret est trop grand pour la mensualit\u00e9 $M$. Par cons\u00e9quence, les int\u00e9r\u00eats \u00e0 rembourser chaque mois d\u00e9passe la mensualit\u00e9. Le capital \u00e0 rembourser, plut\u00f4t que de d\u00e9cro\u00eetre augmente. La boucle infinie signifie que l'emprunteur a emprunt\u00e9 une somme au-dessus de ses moyens."]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q4\n", "\n", "Un emprunteur souhaite contracter un emprunt pour $Y$ ann\u00e9es. La mensualit\u00e9 maximum qu'il peut consacrer par mois est $M$, le taux de l'emprunt est $p$. Quelle est la somme maximale qu'on puisse emprunter ? On se contentera d'une valeur approch\u00e9e \u00e0 1000 euros pr\u00e8s.\n", "\n", "La fonction pr\u00e9c\u00e9dente estime la dur\u00e9e du pr\u00eat. Moins on emprunte, moins la dur\u00e9e est longue. On n'a pas besoin de 20 ans pour emprunter 1000\u20ac. L'id\u00e9e consiste simplement \u00e0 tester de 1000 en 1000 toutes les sommes jusqu'\u00e0 ce que la dur\u00e9e du pr\u00eat d\u00e9passe $Y$ ann\u00e9e soit $12Y$ mois."]}, {"cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [{"data": {"text/plain": ["183000"]}, "execution_count": 10, "metadata": {}, "output_type": "execute_result"}], "source": ["def somme_maximale(M,p,Y):\n", " K = 20000\n", " l = mensualites(K, M, p)\n", " while len(l) < Y*12:\n", " K += 1000\n", " l = mensualites(K, M, p)\n", " return K\n", " \n", "somme_maximale(1000, 0.029, 20)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["**Remarque :** On pouvait \u00e9galement chercher la somme maximale au del\u00e0 de laquelle le capital \u00e0 rembourser augmente car la mensualit\u00e9 est utilis\u00e9e int\u00e9gralement pour payer les int\u00e9rets. C'est-\u00e0-dire que la fonction ``decompose_mensualite`` retourne une valeur n\u00e9gative ou nulle soit la valeur de $K$ telle que $M = K \\left ( (1+p)^{\\frac{1}{12}}-1 \\right)$. Dans ce cas, c'est comme si la dur\u00e9e du pr\u00eat devenait infinie. Cette somme est n\u00e9cessairement sup\u00e9rieur \u00e0 la valeur cherch\u00e9e qui correspond \u00e0 une dur\u00e9e de pr\u00eat finie."]}, {"cell_type": "markdown", "metadata": {}, "source": ["**Remarque :** Est-on s\u00fbr que la longueur des bien ``Y*12`` ? \n", " \n", "En effet, rien de le garantit. Il faudrait s'assurer que le nombre de mensualit\u00e9s ne saute pas des ann\u00e9es comme la version suivante o\u00f9 on passe 10000 en 10000 et la valeur est"]}, {"cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["K 140000 mois 171 ann\u00e9es 14\n", "K 150000 mois 186 ann\u00e9es 15\n", "K 160000 mois 202 ann\u00e9es 16\n", "K 170000 mois 219 ann\u00e9es 18\n", "K 180000 mois 236 ann\u00e9es 19\n", "K 190000 mois 254 ann\u00e9es 21\n"]}, {"data": {"text/plain": ["190000"]}, "execution_count": 11, "metadata": {}, "output_type": "execute_result"}], "source": ["def somme_maximale_step(M,p,Y,step=10000):\n", " K = 20000\n", " l = mensualites(K, M, p)\n", " while len(l) < Y*12:\n", " K += step\n", " l = mensualites(K, M, p)\n", " if len(l) >= (Y-3)*10:\n", " print(\"K\", K,\"mois\", len(l), \"ann\u00e9es\", len(l)//12)\n", " return K\n", " \n", "somme_maximale_step(1000, 0.029, 20)"]}, {"cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["K 139000 mois 170 ann\u00e9es 14\n", "K 140000 mois 171 ann\u00e9es 14\n", "K 141000 mois 173 ann\u00e9es 14\n", "K 142000 mois 174 ann\u00e9es 14\n", "K 143000 mois 176 ann\u00e9es 14\n", "K 144000 mois 177 ann\u00e9es 14\n", "K 145000 mois 179 ann\u00e9es 14\n", "K 146000 mois 180 ann\u00e9es 15\n", "K 147000 mois 182 ann\u00e9es 15\n", "K 148000 mois 183 ann\u00e9es 15\n", "K 149000 mois 185 ann\u00e9es 15\n", "K 150000 mois 186 ann\u00e9es 15\n", "K 151000 mois 188 ann\u00e9es 15\n", "K 152000 mois 190 ann\u00e9es 15\n", "K 153000 mois 191 ann\u00e9es 15\n", "K 154000 mois 193 ann\u00e9es 16\n", "K 155000 mois 194 ann\u00e9es 16\n", "K 156000 mois 196 ann\u00e9es 16\n", "K 157000 mois 197 ann\u00e9es 16\n", "K 158000 mois 199 ann\u00e9es 16\n", "K 159000 mois 201 ann\u00e9es 16\n", "K 160000 mois 202 ann\u00e9es 16\n", "K 161000 mois 204 ann\u00e9es 17\n", "K 162000 mois 206 ann\u00e9es 17\n", "K 163000 mois 207 ann\u00e9es 17\n", "K 164000 mois 209 ann\u00e9es 17\n", "K 165000 mois 210 ann\u00e9es 17\n", "K 166000 mois 212 ann\u00e9es 17\n", "K 167000 mois 214 ann\u00e9es 17\n", "K 168000 mois 215 ann\u00e9es 17\n", "K 169000 mois 217 ann\u00e9es 18\n", "K 170000 mois 219 ann\u00e9es 18\n", "K 171000 mois 220 ann\u00e9es 18\n", "K 172000 mois 222 ann\u00e9es 18\n", "K 173000 mois 224 ann\u00e9es 18\n", "K 174000 mois 226 ann\u00e9es 18\n", "K 175000 mois 227 ann\u00e9es 18\n", "K 176000 mois 229 ann\u00e9es 19\n", "K 177000 mois 231 ann\u00e9es 19\n", "K 178000 mois 232 ann\u00e9es 19\n", "K 179000 mois 234 ann\u00e9es 19\n", "K 180000 mois 236 ann\u00e9es 19\n", "K 181000 mois 238 ann\u00e9es 19\n", "K 182000 mois 239 ann\u00e9es 19\n", "K 183000 mois 241 ann\u00e9es 20\n"]}, {"data": {"text/plain": ["183000"]}, "execution_count": 12, "metadata": {}, "output_type": "execute_result"}], "source": ["somme_maximale_step(1000, 0.029, 20, step=1000)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["M\u00eame dans ce cas, on ne tombe pas exactement sur 20 ans. Il faudrait avoir une valeur pour ``step`` variable pour traiter tous les cas. Par exemple, d\u00e8s que le nombre de mois augmente de plus de 1, on divise $K$ par 2. La pr\u00e9cision serait au mois pr\u00e8s."]}, {"cell_type": "code", "execution_count": 12, "metadata": {"scrolled": false}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["K 175312.5 mois 228 ann\u00e9es 19 step 312.5\n", "K 175625.0 mois 228 ann\u00e9es 19 step 312.5\n", "K 175937.5 mois 229 ann\u00e9es 19 step 312.5\n", "K 176250.0 mois 229 ann\u00e9es 19 step 312.5\n", "K 176562.5 mois 230 ann\u00e9es 19 step 312.5\n", "K 176875.0 mois 231 ann\u00e9es 19 step 312.5\n", "K 177187.5 mois 231 ann\u00e9es 19 step 312.5\n", "K 177500.0 mois 232 ann\u00e9es 19 step 312.5\n", "K 177812.5 mois 232 ann\u00e9es 19 step 312.5\n", "K 178125.0 mois 233 ann\u00e9es 19 step 312.5\n", "K 178437.5 mois 233 ann\u00e9es 19 step 312.5\n", "K 178750.0 mois 234 ann\u00e9es 19 step 312.5\n", "K 179062.5 mois 234 ann\u00e9es 19 step 312.5\n", "K 179375.0 mois 235 ann\u00e9es 19 step 312.5\n", "K 179687.5 mois 235 ann\u00e9es 19 step 312.5\n", "K 180000.0 mois 236 ann\u00e9es 19 step 312.5\n", "K 180312.5 mois 237 ann\u00e9es 19 step 312.5\n", "K 180625.0 mois 237 ann\u00e9es 19 step 312.5\n", "K 180937.5 mois 238 ann\u00e9es 19 step 312.5\n", "K 181250.0 mois 238 ann\u00e9es 19 step 312.5\n", "K 181562.5 mois 239 ann\u00e9es 19 step 312.5\n", "K 181875.0 mois 239 ann\u00e9es 19 step 312.5\n", "K 182187.5 mois 240 ann\u00e9es 20 step 312.5\n"]}, {"data": {"text/plain": ["182187.5"]}, "execution_count": 13, "metadata": {}, "output_type": "execute_result"}], "source": ["def somme_maximale_mois_step(M,p,Y,step=10000):\n", " K = 20000\n", " l = mensualites(K, M, p)\n", " l0 = l\n", " while len(l) < Y*12:\n", " while True:\n", " l = mensualites(K + step, M, p)\n", " if len(l) > len(l0) + 1:\n", " step /= 2\n", " else:\n", " K += step\n", " l0 = l\n", " break\n", " if len(l) >= (Y-1)*12:\n", " print(\"K\", K,\"mois\", len(l), \"ann\u00e9es\", len(l)//12, \"step\", step)\n", " return K\n", " \n", "somme_maximale_mois_step(1000, 0.029, 20)"]}, {"cell_type": "markdown", "metadata": {"collapsed": true}, "source": ["### Q5 \n", "\n", "A Paris, on loue un appartement pour $L$ euros du m$^2$. Un parisien loue son appartement de $S m^2$ pour $SL$ euros. Ce parisien peut d\u00e9penser $A$ euros par mois r\u00e9partis en $SL$ le loyer et $A-SL$ les \u00e9conomies. Ecrire une fonction qui calcule les \u00e9conomies r\u00e9alis\u00e9es au bout de $Y$ ann\u00e9es.\n", "\n", "Apr\u00e8s les \u00e9tudes, ce parisien ne dispose d'aucun apport financier. Il commence par louer un appartement. Chaque mois, il envisage de consacrer $A$ euros. Il loue un apprtement suffisamment de petit de telle sorte que le loyer est inf\u00e9rieur \u00e0 $A$. Chaque mois, il \u00e9conomise la diff\u00e9rence. Chaque euros \u00e9conomise est plac\u00e9 \u00e0 taux fixe annuel $r$, donc au taux mensuel $rm = (1+r)^{\\frac{1}{12}}-1$. Cette fonction calcule les \u00e9conomies r\u00e9alis\u00e9es."]}, {"cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [{"data": {"text/plain": ["25862.65218705509"]}, "execution_count": 14, "metadata": {}, "output_type": "execute_result"}], "source": ["def economie(A,S,L,r,Y):\n", " delta = A - S*L\n", " rm = ((1+r)**(1.0/12)-1)\n", " eco = 0\n", " nbm = Y*12\n", " while nbm > 0:\n", " eco = eco * (1+rm) + delta\n", " nbm -= 1\n", " return eco\n", "\n", "economie(1000,40,20,0.015,10)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q6\n", "\n", "En consid\u00e9rant que ce m\u00eame parisien ne peut d\u00e9penser plus de $A$ euros par mois, qu'il ne poss\u00e8de rien au d\u00e9but de sa carri\u00e8re professionnelle, on veut savoir \u00e0 partir de combien d'ann\u00e9es il sera en mesure d'acheter son appartement \u00e0 supposer qu'il peut se constituer un apport en capital issu de ces \u00e9conomies. On suppose que le prix au m\u00e8tre carr\u00e9 \u00e0 Paris est $C$ et qu'il veut emprunter avec un pr\u00eat d'une dur\u00e9e fixe. \n", "\n", "\n", "Si on r\u00e9sume, le parisen n'a pas les moyens d'acheter son appartement d\u00e8s la fin de ses \u00e9tudes. Il commence \u00e0 louer et \u00e9conomise. La somme $A$ correspond \u00e0 un tiers de son salaire, il sait \u00e9galement qu'avec une mensualit\u00e9 de $A$, il peut emprunter au maximum sur 20 ans `` somme_maximale(A,p,20)``. Il pourra donc acheter un appartement de la m\u00eame surface lorsque ses \u00e9conomies ajout\u00e9es \u00e0 la somme maximale qu'il peut emprunter d\u00e9passeront le prix de l'appartement.\n", "\n", "On regarde chaque ann\u00e9e si les \u00e9conomies accumul\u00e9es permettent \u00e0 ce parisien d'acheter."]}, {"cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [{"data": {"image/png": "iVBORw0KGgoAAAANSUhEUgAAAdEAAACaCAIAAAB5SeXXAAAAAXNSR0IArs4c6QAAAARnQU1BAACx\njwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAEw1SURBVHhe7Z13vBTFsscfICB6DaCSFQURRIIE\nyQhPUVEQVHISSQIqFwUBySB4RZSoIKBIlhwliwQJooAiIDkoQYlyiZJ9X7fWfs2k3Z2zZ8852L8/\n9lPTOzNdXd3966rZna7/+dPAwMDAIFYwnGtgYGAQOxjONTAwMIgdEinn/s//JIHFIEkoGa8wFjAw\niBTXOef+8ccfp06dCh5EG4ZxjAUMDCLF9cy5K1asyJ8/f5s2bYLH0UYUGWfXrl0tW7a8evVq8NgJ\nFy5cWLt2bfAgccBwroFBpLieORcMHTo0SXDu1q1bGzVqdOXKFTkcOHCgCAo47E8//XTHjh2Dx4kD\nhnMNDCLFdc65n3zySZLgXAteeOGFoPQ3RowYkdicXGA418AgUkQ2Z3bu3DllypT169cfP358zpw5\n3333XfCLANatWzdx4sRFixaJv8Y5M2fOnDdvHj7asmXLli9ffunSJeQFCxbMnTv38uXLcpUjPCbz\n4sWLv/zySz6RT506tWLFiqVLl54/f/7o0aMUjh8//tixY3Im0DmXyB01pk2btmbNGg5Rb8aMGdOn\nTxcZVTlEJoSnaZMnTz5z5gyF+/bt++tiJ7gpSUU0cPTo0efOnRN5zJgxSqYc+2BDqvvvf/8rl2AT\nzrl48eLp06dxcpMlS0YbASVywk8//YSqKOZttxjDo5sOHjyItcFXX31F2ymx21+GB31HD2IZ5ebb\nrzUwuG4QGeceOHCgRo0aDRo0gOmYQnXq1GGqyFft27eHESjcsWNH3bp1YS4IsXfv3oULFx47dizc\nMXz48GbNmk2dOhX5s88+a9GihVzoCI/JzCxNly7d4MGDkaHFJ554YsCAAZBXrVq1qB3CzZ8/P3rK\nyYpz+apx48ZLlixB7tOnD24j6vXr1++hhx6i5OTJk++8847ILAywW+bMmSdNmgQ/Nm3alEJHeHAu\nC0+qVKlYBpAxS4oUKUSGW5FnzZpFjdu2bStWrJhcAumkTJkSwqVFmzZtSp48OZ9AGBZtUY/LYSuM\nL5ckBrhZgF7o2rUrAjrXrl37t99+Q7Dbn+FRtGhR1h6GxNChQxlCjtciGxhcN4iMc8HHH3/89NNP\niwxntWvXDgGXpEyZMlII2rZty1cIW7duvfXWW+Ff5M2bN9988804NcjQzQMPPPDXqS7w4FzQsWPH\nt956S+RBgwbxCaNVrFhRGKphw4bCyEBx7vz588uVKyeF+/fvv//++xG2bNkiPAtQVckgTZo0uO1M\new+/0lvJ9OnTo5XIGTJk0OVvv/0WgZvfdtttkKyUZ8mSBc4VGV4WAcBBd955p3L30Bz9RU5wuFlg\n48aN5cuXFz1ZOWiXo/314fH999/Dvwj2axEMDK4b+OHcV155RcmvvvoqQufOnZs0aSKFAKZ75pln\nEJhUefLkkcKdO3cqnt27d2+OHDlEdoQ3nXF5xowZmavMyW+++UYV9u3bF8/0+eefx5OSQsW5HTp0\neOyxx74IYPbs2f/+978p1HnWwrk33nhjyNnuraSFZ3X5yJEjSlblbpy7cOHCu+66SzQHNOSXX34J\nfpfQcLMAy8mbb76ZNm3a3LlzM0g4dLO/Gh7K/vZr5QQDg+sDfjhXeFaX33333fr160sh+PDDD2vW\nrImgExmcmytXLpHjyLkATp8wYcKnn34qcxIv6eGHHz548CAyrvf7778v/KU4lxLlnivo6kHfOufi\ngQYld4TPuXfccYcb/3pw7qVLl7777ru1a9fidCdO6nGzAKvCqVOn0J8AqEiRIl9//XVI+yvZfq2c\nYGBwfSBizh0yZIju54q8Z88eHBb1g0+NGjXmzJmDQPDu5udmz55dZEeE5NxZs2YVK1Zs/Pjxcti2\nbdvWrVuLXLduXWb4qFGjkIcPHy7l+/btg+UVqc2cOZNP+E6pNHHixAcffFBkCI6YV2QPeCsJg/z6\n668IBw4cSJ48+eHDh6U8ffr0up+r5MyZMyv18OJ///13LodwL1++nD9/fhYV+QoWVk+rExxuFvjy\nyy8/+ugjkRkJI0eOdLS/PjzgXJHt14psYHB9IDLOxekoXrw4PDVjxoyVK1eWLl2aAFB+7p8/fz7s\nRiDcu3dv/FxKfv7559q1a+OjEfLv37+/YcOGBOxE/VBG48aNU6dOzZmBuzogJOfiB8FEx48fl8Nv\nvvmmbNmyEDFgolaoUGHcuHGrV68uU6YM3Ec8yzkLFizAGZ8+ffqkSZOU99SoUSNm9aJFi8aOHZss\nWbJevXqdO3eOhuBp4i9DBHKaI7yVFBd76dKl1HjvvffWq1fvt99+69ixI3du0aLFoUOHunfvnjJl\nytdeew3a7dSp0w033PDGG2/Iw82ePXt27dp18ODBf/zxB4e7d++uVavW6NGjaRrefeD2iQIenNuk\nSRMaPnfu3G7dusnfMyz214cHvm2DBg1uuummfv36OV5rYHDdIDLO9QbuIdE9bBg8jgNCci6Qn+N0\n4EvKT15uP3yhoYrlFU6cOHH27FnUxq8UygsTIZWEvnFXEbgzVUhhmIBrLMqwwHj8oJcgcLMAxsTU\nZ86coeH6UxFH+1vgdq2BwfWBaHJuFBEO5yY4koSS8QpjAQODSGE41z8M4xgLGBhECsO5/mEYx1jA\nwCBSGM71D8M4xgIGBpHCcK5/GMYxFjAwiBTOc4a5ZGBgYGDgG0EytSGR+ikeGiceJAkl4xXGAgYG\nkSJOc+bHH38MStGG4dxIsWjRoqAUQyR1zr169erp06flxRNdTuRIQqoa2OF/zuzevTtdunQRvUQQ\nPuIymS9fvjxlypRt27YFjwNjdMKECX369OncufOuXbuCpYF3T4cMGcJX+kv9v//+O4UTJ06cPHmy\n93/yEw/jXLlyBYWDB37x3nvvLV26NHgQHpI6544cOZIxLK8p6rI/HD58WB9d8Ye4qxrf2Lx588mT\nJ4MHCYe5c+fKO7GJCv7nzODBg2+//fZ46njfk3nhwoXjxo3LlSuXTh/vv/++vMULEWfKlGnTpk3I\nR48erVq1qrw19+qrr86fPx8Bkq1WrZrs2QqLderUCcENiYdxli1b9mtgb4e4oFu3bgsWLAgehIek\nzrmgVq1aagzrcqTYu3dv3rx55T34GCAuqvqG7CEVEowiJmBslh9vTJs2TW0xmHjgc87ATf3792/a\ntCl9HyyKKuI4mUuVKqU4F1WLFSu2Z88eOWzSpEmzZs0Q2rdvP2LECCncsGFDiRIlEGBetUEa/nKW\nLFlOuacNTjyMg0selGKL64Bz69atq8hLlyMCcUavXr3CpKSowLeqcUE4NR44cKBv374mu4cHfM6Z\n77//Ht9q+fLladKk8WAl34gu57I2bNmyRQ5btWpVvXp1BM5RSS6OHz+ePHlyZg6Obdu2baUQ5MuX\nj2YGD2zwVhJnGa+HlfbEiRMc7ty5E2ZctWqVyFOnTl29ejUyik2aNAk3fP369V9++eVfVwY2W+CE\n6dOnq61y0e2bb75BGT7XrVsnhQLsP2/ePJHXrFnz+eefM/l37949Z84c2fl7+/bt3I0SOQdcvHiR\ngAB9qFRKcNM4RzZTBz/99BN1gRUrVkiJIzwsgA5yBz2/jo/sTeGcIwiZvgjPi/vQI2oDPODGuXYT\nufUgYIyhm0o7JLAMADuItCzZpDyqsMBbVUlYZc9fZdHz8OHDaEjJvn37Zs2apbbPd0M4nEvXcNqU\nKVP08cbomjBhAsZXpnA0b3Tzfp08eZJGzZ49O3CDv2AZIR5zKl7hk9oGDhyIxuDuu+8eO3ZssDR6\niCLn6kDh3Llzw3HIWbNmlUEJIAVqZA7Uq1evc+fOUgiKFi3KOAge2OChJF1Yp06dCxcuMJ3Kly/P\n/Vn/ublsNwwVVqtWTeSff/75mWeeQf7hhx8ITiFZWLhBgwZMALTt0qWLDHTcKHl6wLeWtEYMLLXd\nz6ZNmwjrcOF37NhBIWuGPNpGLliwoIR7p0+fJjoRx5+B261bN4RDhw6hnuw1jFkkRkZt+6a3Otws\n4Jhfx1/2pnDOASHTF7GcYEOElStXPvroo9hWyh0519FEbj1IpZa0Qwj2AUChjrNnz1IF13KCyibl\nVoUd3qrCTWnTppVHmQykp556ChllLHrCgIz2ihUrciFWVTujukEZyg34CpUqVaIVkBr9Lr+xQ4IE\nl1hAhhPk6Gbe6Ob9wsLE4pwjN7GPEI85Fa/wQ22MV8mIAzBHhQoVRI4i4olzP/jgA/oGuyNnyJCB\n5VHKoSRqZGWuWbNmjx49pBAUL15cPX+ww0PJYsWKsX6KzEAfN24cwpAhQ9QU0rd+f/fddytXrowg\ny2+5cuXwDQPf/DWIs2TJwmBl+uEUyAm6MwUsqwJNeO+990TmKsaZyIxyXGCE7t27Q+VSCFhXxNdQ\n+7vTuTj7DGtkS10WuFnAnl8Ha/jO3hTyHGgrZPoixoNEMPT+fffdh8sj5Y6c62Yixx50TDvkOAB0\nsMA7ZpNyGyQWhFSVNU96EwwbNoxPRz1x8W677TZsIpp4IyTnwgboIzJsCNXSa5kyZcKxoIRhwIpC\niZvOtDe6eb/wnYVzHUeIx5yKV/ihNoYvyyMrJ8AuKVKkUBtyRwvxwbmUvP7668rByZMnD7GJyCyJ\n1Pj777+/8sor0tOCRx55hGAkeGCDm5LEOMmSJfv0008Zo6Bv377yRy59Clk498033xSZcYM9xesR\nwLnEWXjBhQoVYpBVqVJFT0WMs2DJwQ7nMpJEZmYKzwLWdolISpcurVMA58jvDIpzCdyo5V//+hfE\n4Z2mwc0CzGFLfp24ZG8KeQ5Rajjpi+AXWkqUwx1U6OrIuW4mcuxBe9ohtwFgAfrzlSWblNsgsSCk\nqgcPHkyfPj0sA50JozmmR8ImRYoU+etKJ3ATIh6Fjh07BqUAcCqD5/2NEiVKtGrVSqqgXfDDhg0b\n7ClXPMwb3bxfinMdR4jbnIpv+KE2PHZxFQUEsBg3eBAlRJ1zWQnx/kRtvDA+Cbhk/QcseiyDfAv9\nERNJIaDzuDB4YIObktA6hKWejSroUwiLKZlKgcisumnSpFHPwlDpjjvuYHiJX3bo0CFa8fjjj8u3\nACdX7wsA5yrPl9Gs9jhXnEvDdee9atWqKIagOFfqIiadOHHivffeq7wDO9wswIDGTSaKxEmR/Do0\n0Hf2ppDnhJO+iPCTqSVuEY4Vl+B2ISvy0mU3Ezn2oD3tkNsA0OGWTcptkFgQUlVQvXp1Am2oXw7t\negI4lzsED0JBGcoNeO4qxhIwklOlSmVxosMxr5LjMnIU5zqOELc5Fd+ImNpwBlmcgwcB9OzZk0Ec\nPIgS4si5JUuWlOdWAhYxFtLffvvt119/xTEcOHAghQRxKp0Pi3bLli0RYFi17OPuFShQwGMmeyj5\n2muvSQQETp48Kc8KoMKXX35ZCps3b64eIf0nAJFBs2bN1IjcsmULvjZzmHGG9ySFxEQioNvUqVNF\nVqhRo4abnztmzBgEWFgNYjgIZ0FmPqwknItnIcsSwF1lEItsh5sF7Pl1MDsVKc8oouxNIc9hSodM\nX4QZ5ecUTr777ruZhJK9qU6dOupnFiW7mcixBx3TDjkOAB3EyI7ZpNwGiQUhVQW4HfhD06ZNk0NH\nPVevXv3kk09KSUiE5FxGY+XKlWXK8EkVfOIAyR8xwbp161DDTWemZHTzfu3YsUM413GEOM6pGCAy\naoPIypYt++CDD6qf+TZt2sQyxRrCGGLlkcK4wzfnomGPHj2IF9CKFZ5QHcKCOgnYFeTZGb0IDXE+\nnde4cWOVA4Z1lb7H83399de9X7TzUBInkXsy6xhteNPiXh07dqxSpUqEmUyDrl27ZsmSBXKEnvB3\nChYsiEsi1zIrWADgR0YwU1eehdWrVw8WW758Od6oev2BCaMmmICrMmXKhB9BOMnIzpYtW/ny5eEX\nAur77rsPmdHGNGAF+uCDD9ANkpWAYMWKFSxU8j8NFtG333578eLFXKViXkd4cC7xoCW/DtX5yN4U\nzjncCn+qlmf6IuYw80oaRY9wLTILEvxLp9DRuuxoIuDYg5QvsKV9chwAOnAw7dmkKHerQkc4qgK+\nevTRRxWtAIue27dvf+6559KlS8cd5PG9N0JyLjXSHazT9Duzj/6ikE8WFWIsmiltdNQZfaKb9wty\nZ2WCCljyucQ+QhznVAzgk9riG745NyLQ9zh0GzZsQAgWBUBovGrVKvs8sSCkkkw8S0oeKiKWYdWF\nWI8ePWqJuXRwLdMvePB3xhoYVo/0lQvjA9yQu1kaLuArPlHvhMufnBTcLCDa0gRLfh1pgtw/PkBo\n4mFSVl/5BwXwOE3B0UQcOvYg5RyKrGAfABY4ZpNyq8IDjqrSXj2EFzjqGSbEwQwJlJGUVDoYS5bn\nv446u4HTojJy9BHC3eS2Hk/P4gP/aM6NIxJWSSaz+g0woZAkuukfiEaNGp08eRKvFkIJFkUD9h/N\nDHzAcK5/JKyS8ofw4EECwXBu4kT79u2nTp0K5waPDRITDOf6R8IquXPnzqCUcDCca2AQKQzn+odh\nHGMBA4NIYTjXP6Ki5KVLl678/ZpGkoPhXAODSGE41z/iruS4ceMmTJjQo0ePzp07h/kDbqKC4VwD\ng0jhZ86cPXt23bp1x48fF1kKo4t/AuceOHBA3nmDbe+//371NmoSQvx109GjRzdt2hR/EcC5c+fU\n2wEhQSyi/jZHZ8X4r0UG1xkinjPz5s3r0qULnDtt2rSPP/64UaNGwS+iithw7rJly4YNG0ZzaIty\nM/v06TNo0KDZs2f37t1b3tVxQxyVZCarP5kXLVrU4yXjRIt46ibGWLt27dq0aWN5kTRaWLhwIYtc\nz549g8ee2LdvX5UqVdT2VKNGjUqXLl2C/2PEIOkisjlz4cKFMmXKKHras2dPqVKlRI4uYsC5S5Ys\ngV4RcKZKlizJ+iHl1atXz58/P+3q16+ft58VLSWh/lrxs/V7fCOeuqlEiRK7d+/+5Zdf5EWm+ECv\nXr3C5Fywbds2xbn//e9/x40bt337djmMJeSd9Vgi9jX+ExDZnNmyZYsafALZJjXqiAHnTpw4UTYv\nBw0bNnzxxRdFVuQbElFREpPi0IV85y1xIp66KUuWLOG8fBUXvP/+++FzrtoqRUBUlCB+7gsvvBCU\nYoXY1/hPQGRz5syZM7feeisRnxpzhw4dEiG6iAHnKuC258uXb9asWXII51Jif3nRDg8lT548+cUX\nX5w4cQJDIUyePBnh0qVLq1atQlYPBPfu3fvJJ59QnbxtLIVJCB4WOHhtnghoi4bbMyCw5EzS0mRA\ntXzecccdfMqOJNhtxYoVLJCW3Tww3YRrUw+Iqadcm6HAAq6aPn36unXrdM7F/ugJk7ptoqpzLn6u\n2raNC7nVzJkzly5dikwJa+ecOXPGjh1Lk+fPnz979mzZx8CtXGBPYEGT8aZp2qJFi7DD6dOncTmT\nJUuGWYCcZlGbw7lz544ePZrgDGNSC4OQQmw+Y8YMZSVgz2BCi7jkuJagwbFGg6ggYmpj9KcJ4LHH\nHhs6dCg8EvwiqogN5zI6YYS2bduq/e7Am2++yWResGBBs2bNvJ+xeigJkzJ2n3/++eHDh589exa6\nadKkyZgxY5gGzLfmzZtzDnLOnDmzZct2zz333HLLLVHfgzgGcLPAMVueiAPhpcmAEzdt2pQ+ffpv\nv/0WmROwG5ZhmFWsWFG9WGVPPQAVVrJlKLDgww8/xF2A/uhWKhXORcPGtiwPFuicez6Q4UbkAQMG\nLA6kGunVq1fnQHoRNEG3lClT0u+4I7SldOnSe/bscSvnEscEFvBs1qxZ+/fvv3Hjxty5c+PrcEny\n5Mn5BLTRrjYl2CdFihSjRo1iaO3YsSN//vxwK5ZhEXrooYfkziwSdWwZTOwJGuw1cq1BVOCH2pgD\nLMLE46lTp46nnBax4VxAW6BdBh8DS0rUNiiMe1jA45Gum5JMMIgVV65YsWIyWBn63IpyZHyxqlWr\nBk5M8nCzgD1PBIJbBoR3r02TAbJkyaL+VFC/fn3xcPHg5FkQfGFPPWDPUCCywk8//XT//fer3oQi\nhXPxB+3ZEyzQOVdH3759ZYcqwpS77rpLCgHzAi4TefDgwSy9IjuW4yM7JrB46qmnZDdIZRb4VATg\npnaGDBnUvr133nmnCp4yZswoeWgcE1jQHfYEDUCv0SBaiIzaGOL6n8PwJm644Yb4cNBixrkCJkCe\nPHkY9ECFUTQWNTx+LfFWslWrVuoniE6dOqldyTt27CjbD14HcLMAZrTkiaBQ51kL53KyyAKdcxE4\nWf5eIgkCHFMP2DMUBL/4G4MGDdI35+7WrZtwrmP2BAvcOJd2EZXj7cK8N910U7A0wK2yvgJWboIY\nsYBbuWMCC7S17OOlM6Cb2nDukSNHRMaMwrOAcApq/sM9g4k9QQMwnBsfiIza1q5d++XfuWkFdLxa\nmaOIGHAuA0t25wQMbmr8/fffP/roo+eee04KCdDiwrlEdrCDyGXKlGFeITDHmFfbtm0LZ7vSxA83\nC9jzRFCoT2Y4UedctSAJFOeywLMWEvMiz5s3r2LFirAGUbM99YA9Q4EFn3zyybPPPhs80Dj3fafs\nCRa4cS4utmiO93rzzTcjiNo6txLv33333SI7lrslsIBzZcwoCANyB3jZTW04V23ViBlV0Caci5sf\nMoOJnXOlRikxiDsi5lziYlmcAV1IgBMfz9djwLk4Teo3E2Zgzpw5adf06dPlGRng2wcffNDHswXA\nuCfYlGvPnDmTLl06sRIMnjdvXgS1Q3mShpsFWJgteSIQ3DIgWNJkAMhC1qS5c+cWKlRICiFNiBUS\nl38oElxL+bpA6gF7hgL5VuHQoUPcVv2U1KxZM0k26pg9wQJYXqmhgIZQEgszMosoTivdjYvNIdwq\nbwwB/Ef13x7HcrcEFk8++aQl0XrGjBlxC3BdOcdN7fTp07v5uVyC4JjAwjFBA9BrlBKDuCMyamO5\nq1+/PpEgTgerZdu2bSU2iTpiwLkMo+7du69atQqCKFmypOTpY9oQ5THW+bZatWqOP8UoeCgJI0jW\nJrBy5cpKlSqJfOzYMRat8ePHS9rzpA4Pzm1iyxPhmAGBMy1pMqDClClTQg1ECSxdjz76KLHw4sWL\nly9fzgKPMws34bLZUw/YMxRYsDSQhJQ1dcyYMc8//zyrrBA3Lqcly4MObtWgQQMoVeW6FlBjw4YN\nqZFlgDid5aRTp07ysxjcOmLECG7OwtO6dWvxYd3K4Th7Aguc37Rp0zJU9LASxxy7DR48GGefQ4va\nDN2OHTuyDLCYQbtiRpYWFptevXoRGaAh7IkHQBV6AguPBA2WGg2igsiojRjq/PnzDPqtW7cy1GQu\nxQdiwLkA35OVA3qVLM0C5hKtw3tSU8UNHkpyQ/X0gFqUPwIo16tL0nCzANEoZmR6M8kRgqUB20IB\njB8MAp9ang+4AXeMWyFAK/rdcFotMRb1ev/Jj8sPHz7MJ9fickogIuUqJI8IDBKVzkM1B26lHE0s\nHe1WjhphJrBgxunD0rfa2DPMt/YtNRrEHbGgNh+IDefGEUlCyXiFsYAdkCYOpt0xdCs3+KfBcK5/\nGMYxFrCAQLBt27aFCxdu3769POoVuJUb/ANhONc/DOMYCxgYRArDuf5hGMdYwMAgUhjO9Y8kzThX\nr16N+28jhnMNDCKF4Vz/SLqM89VXX40ZM2b48OF169aVvwT4g+FcA4NIYTjXPxKVkhH9Ufrpp58W\nqm3SpIlsIuwPCW6Bixcv6jtmhYNLWtIHA4PYI7I5s3Xr1s6dO995551VqlSxv9IeRcRmMq9evRrG\n6dix49KlS4NFMcwTEUVcuXJl4sSJwYMw8MUXX8g/W9u1a6deGPOBuFsANZo3b37gwIHgcSTYsWPH\nY4899vjjjwePw4Al6UNSB81xfPsjUeHChQvmNTYdEc+Zq1evMtPie7PXGNAZjiE8RXNOnjxZpEgR\n9R5U7PNExB3Lli1Tb3mGjyNHjpQrV877JQJvxN0CTMh69erJJmE+sHLlyog4F+hJH5I6lixZkjt3\nbrUlHvj+++/tr9IlIP744w+CKtya4LGBD84FzDTL7htRRwzorG7dugsXLhR53LhxuXLlEvnj2OaJ\niAomT54clMLG6dOnW7Ro4YOpdSS4BXCgIuVctw1rkigOHz7cpUsX9aoFIZoetCU4RowYYZxcC/65\nnDtgwAC14f+MGTPU/qdwLs5vON6ft5L23fjDSZTw15WBFy45Yfr06b/88ouU4HFjc/xZPtetWyeF\nglOnTs2bN0/ky5cvs5Ds2bOHJnDy+PHjDx06hLx582ac+oMHD8ppTFG8eHkjWXaA9Qc3C0AEtB1N\nqB0j43nJK61SjmIExbNmzTpz5gytRgFp5nfffYcFAOVcKLLjs1d6Z86cOXyLNYRzjx8/zp2xmMgz\nZ87kMHCuFRbOpWos88UXX8irChs3bly+fLmql/7iEGWQf/rpJ+5PvdIWSyoHSizA7JYsEnzODaRy\nOHfunMhjxoxBlvMVRH/6lG7CVihw6dIl5AULFnCJ1C6wqIRJGcYffPAB+mNqu7U5h3opUdklHGHP\nwXH06NHFixcznNSLzpZxS7yCGoxwakF52U8HWDQ0AP9cztXRtGlTtc3Vm9HIE+G4G384iRKgAEZz\ngwYNGLvwLC4MdMBpvXr1Ep+Uby37xDOd1Pv7DHr4qECBAsOGDaMWeL9gwYLMDWYRMzlfvnxyWtWq\nVTNnzpwtWzamKN9KoQ+4WYC52rNnz+zZszO3YXZot2LFiliD8s6dOyMzLTEvc5hJi1bSRprWqFGj\nnDlzwi8sD1xOc/StKgSQXePGjVmWaF379u2Fc1l4WEUeeughZNjznXfeEdkOnXNZ2N5++23ogFrq\n16+/a9cu4vTixYu/+OKLwlAdOnRAzyNHjuCvcU8IC6qid/gKntVTOQTudw3sWSS4HIJOlSoVFIYM\nE6VIkcK+YQJt6d27N0qOHTv24sWLw4cPRwdURf7ss89U79tVQvlixYpxDgJGsFubky3ZJQJ3ugbQ\nepNrc3CcPXu2Vq1aXMtgzp8/vzx8t4zb3bt3w60MKoYTiwoTinPsGhoAw7l/7RhdqlQptV+P2m2E\nSeUvTwRw3I0/zEQJ5cqVkx32AFplyZKF0Q9HQ0BygsVDUd46wK9hDt96661C0PDvjTfeKEluuFX6\n9OkDZ0UNHhbAqkWLFg0eBJ6Syw7ulN92223MQ+X41K1bVzgXUPjEE09gLhxAyFEKdcA7d999t7QI\nQGrq2QKUrXgWKg/JuRgkQ4YMaqsXuEZ6AUriBDRE/vTTTyEduObOO++kFwIn/nn//ffLL1f2VA46\n3LJI0AuKZ/XtbnWgP53IKoXMwn/zzTfLsrpt27YHHngAwU0lrKE/W7BYe36opBjUaM/BgYYQt9yh\nYcOGgwcPDpzrkOAjTZo0eBtSnZuGBlHgXKaBejAaLcSMc2FY6EARLsOF5ojMmEMNH3uW46a57cbv\nxrkqUQJTC99H/x0fziXoxpsoVKgQ87BKlSoqcAN79uyxPC+DdlUyGII+lRwBHSpUqCBytODNuaxk\nwYNAxhfZ0JLyIkWKSKFA51zADIdWPv/88+DxtcCpZBURQgTwi+JcnWfD4Vz4WicdyqE2llhuzrXf\nfvst/YinyVcMb0hTehPg/MrDEHsqBx3ch+XQnkVC51kPzs2TJ4/IKCY8C1hscuTIgeCmkp1zdWuH\nTIrhmIMDUC/DGAeWoaX+XKiPWwFdo+ISNw0NosC569evx0cIHkQJseFcgrh27drJKGEy8xmVPBHM\n25C78bslSsBBwFlQmWuZt3fccQczUJJxHDp06L333lMsA5jVioAETCTmuchdunRRd3755ZeHDh1K\nyKy8krgjfM596623CN4RKFfLgMDCuawiXbt2ffjhh9Xs1QEBsfCE5FyC65CciyYqgwPgEjxQuTOu\n3Isvvjht2jR5rM+qRqdY7AzsqRx0uGWR0HmWznXjXKU/CqsfeBXnuqmkOFd+LbBYO2RSDAaePQcH\nAR/dIT8GMF+4iTQkMGyvSfCh87WbhgYRUxtG1DmXQyYzXpgcRgsx4FyCph49ejCICcPxHCVVwfQo\n5Ylw3I0ffgwnUUKzZs3Ugzbi5UceeQQdatasidslhdWqVRMB40+dOlVkhbx588r6AUqWLKl6KnPm\nzEeOHBk5cmQUp4E356rHx9QIg4gR4IInn3xSygV16tRRnAsByTTu37+/PEOUcgVKSpQogf8uh7iQ\n//u//ysy1yp/cOLEifSdyBaopA8ENNhKbR4/ZMgQ5bXRZcTF6h/ocFD+/PnVD2WEHRKI2FM5KLCc\nu2WRwBTy5IebJE+e/LBTOkH63c3PzZ49O4KbShiNMYwguScs1maceyfFwLyslLKVO1gXyMHRtm3b\n1q1bSwkLJJwrmSws45ZrWQ6DB+4aGkRGbZs3b8aNYjA1bNgQToGz6CEOVTqQaCEGnNuyZUs0V6hR\nowaFTAxCJ0Yqq3Rc8kTgTlp246fwWHiJEpgS6DZmzBj4FO6Wh2s4Tfjgy5cv/+STT9TrD+ip/oog\nOHv2bKZMmWSdYNBnzJhRPSp59tlnUUY9KY4KvDk3Z86cNIoacY5kFSFoIIxIly4dRoaVKCF4xw6V\nK1fGwxo0aBCEItMbZ41OqVq1qj1cIERt2rQpbcE+7du3J55Vr3U0atSIRQULc9tkyZJJDnMd+69N\n+gCdsQpCT6gH4aqHj4BFUf9/COpBZ5DmnDlz5CmtYyoHBQjILYsEPdimTRsaCDnee++99KyFdunx\n2rVr4yQSzqMw96GNWAzOYlClTp1acpjaVQJE9CzPjBCmqt3awDspBqBGiBUDclv5HYKuLFu27KwA\nKKxQoQLllnGL6eg4uoy+xkkP3MlZQ4N4pzZ/iAHnuoHZwqBhvglReiCkkjCvZTd+bn4ovEQJXAtH\nBw/+zrwAw+q8AHcHpb/BOXqsqv/jLT7eefXmXBxS9IFQPGIF3zh+/DjLCdbAnmpdAbQRm9NYfMmQ\nPSjAYpZuAjBjUNJApR5dZgcKqE7UL0Rt6RqUtFcdEewqnT9/XvxrN1gGiSMwo25VQD9KRRFZAERq\ntOsehnP9I2GVZK6qv+UmFDwsgA9VrFix4EHSAYHzmjVr8CjxB4NFBgZRheFc/0hYJeU/88GDBIKb\nBYhqCeGLFy/+cdgv9SUSECnj4RJZ4wwGiwwMogrDuf6RsErudPr7aoyRJLrJwCBRwXCufxjGMRYw\nMIgUhnP9wzCOsYCBQaQwnOsfhnGMBQwMIoXhXP8wjBMDC1yMPBPEdYOrV6+ePn065C+lV65cOX78\nePAgFCz3PBfY4UzkRIUZM2bIv/5RVf25OPb48ccfLfY5c+aM/T+aEeF65tz58+ePHDnys88+k9cK\n7NiyZcuQIUMmTJhg+XM4ZlVvkXnAcG58W8BHJojrCYzedOnS6S9G2wElNW3aNEWKFMHjULDc8957\n71X7JyQeMB/lHbkVK1bkz5+/TZs2Uv7ee+/pu0nEN1jMsmXLpr8aI1i2bFlcXvG4bjl3yZIlsoHe\npUuXypYtq3YLUzh69GjVqlX5FvnVV19V7zuODSAcBQznxsACPjJBxAXfJ7I8C7Vq1fLmXHD58mXZ\nzyFM6Pdcu3Yto13k2AAi807rxZRs0qRJ8ODPP4cOHao4t1u3blH533SYvQzjZ8+eXdWuA8bwfvHE\nA9ct5xYrVmz33zvFDBgwoEOHDiIrtG/fXm1rsGHDhhIlSogM6HXDueEgBhaAFGLJuYktz4JlAyA3\nOG4G5gb9nvC1epU8Nti4cSPUGTxwwqRJk/Rd5eRV6eBBlBBmL/fv33/8+PGZM2e2v0e3cOFCeQPb\nByKbMwTjWGTrtUkN4gNxnMznzp0j2lJvVU6bNk1tG6pQqlQptR3a8ePHkydPrl5RNZwbJtws4Jih\ngCiYqT5lyhRZC7E58eO8efPOnz/PBKAv9FeEf7dlghBY8g6sWbOG+Xnw4EHuSaHs0Lp9+/apU6eq\nFReEWTWq3qXlWQhceg2uuqd+4A5MClot+4K6lVM1smxDI2pwiCywZ1Xw4NwLFy589dVXs2fPPnHi\nhM65hHTckzHv9hxcvyfVqbeTify8k0FIIZOL+6P5oUOHsDPsQyHt1dNPuFmY+5QsWbJ+/frcbdu2\nbX/dzobatWvrUani3L1791Kd7L8h+gBpo0rn4Zi8wzubhpxjx8WLFz/66COGLjGEfZcSjK82V4oU\nkbGGZXP4+NsQM450tmvXLu6gBi59b9/ZL2vWrLKNP2AYcb56Cd1wbphwswCD3pKhAMapVKnSgQMH\n6BQm1Y8//ngqkA2haNGiTGDGNyEkkYdc7pgJAtjzDmzatClXrlycs2PHDqZ3vnz5IFYmM3LBggVl\nz7Dwq7bkWfirymvhmPqBaJcFnpnMJVQtbzy7lVN1P5d8FvbWATfOxTLVqlWj1ZACLHPjjTdKOUuC\nJUGJlOvQ74mhRMBBqRUqGQTzHZ0hTdY2iCxLlixcDp1xlSX9hJuF9+zZ89prr7Vo0QILy+Zqdli2\nV1acC6XWq1dPZJxlbv7SSy/Jck4UiwIQKDxrSd7hOGa8e1kAR2NeBCrl5lKoo1ChQjQteBAJImaN\nd22bw8cH4khnrMzJkiULHgT2UtJ3ShVkyJCBtVFkhg41Ks/IcG6Y8LAA/qmeoYAp1717d/lq7Nix\n8sCOblLZEJgtkleCceyYCQIucMw7ULNmzffee08KoSEmmMgwiISo4VcNqMsj6nRL/cBYEv+L9tJq\nIQK3cpxHxbOoIbJb69w4l8Vj5MiRImOxG264QWTYxJ6gxALHe+JwhJMMAk9TLYEPPvjgypUrEeY7\npZ9ws3DPnj09ni1gqAIFCgQPAtCfLegynmzx4sVF/vjjj6Ui8JSWvMPNqt69LFCbUNM6+k7900OB\nJc1t2fCGH861bA4fH4gjnR05coQ7KFsT2rB0i6yQJ08e/F+RWeQ5X+3CZTg3THhYAM7VHZYSJUq0\natWKqQ6IuOVXFKal2iVWsQ8eimMmCLe8A3Du5L/THsMm6lEgTo38OhR+1cB7NqIVfrRj6ge1nam+\nJbljuV6dkt1a58a56dKlw8LBgz//lP8twAuOCUoscLsn61zIZBC4t9gNO8BoLI3SIrS1p59ws7A3\n5+L9yI7yCm6ce+XKlRw5cmzYsIElR/bzFejJO9ysGpJzT58+3ahRI4YKwGumr+3/D2Mp8kho4AE/\nnAuCB/GGONIZ/cG8VRZh7ql9vhXom2HDhonM6sd6qOa54dww4c25eoYCfCjljSo4ss9Ol0wQbnkH\n4Fx4UGTYRP2JR3Fu+FUDNRsdNyMPJ/VDSFmvjvBWZLfWufEjcf369euDB39zLsPeMUGJBY73xBUN\nJxkEBNe2bVs4joVH/fTvmH7CzcKKc922e3d7tmCRAQtDs2bNYPlDgcTMAkadWo3crOrdy4BRpPuw\nLVu2rFq1avDgb7DMqM6NCBGzhmVz+HhC3OmsRo0aslU+wM2RZYoRM2bMGAlDhgwZona/nzFjBmYV\nGXAaCti7ygLDuR4WYDTrGQqISfELxKR8zgz8+1LPhsC0FJlvHTNB4Fg55h2go938XPoaIfyqQa1r\n8yzoOOWe+iF9+vS6P6tkx3Imqj2fhVvr6tSpY9cE4LJ16tRJ5N9++039AuyYoMQCx3uGmQwCUqZe\nec6g4Jh+ws3CQ4cOFUfYsV1Atl0OHgT2hleKIeuciz3x9yW3qYKevMPNqh69DKi9S5cuwYMAVqxY\nkTp1an03alC0aFGxeaSIjDWYCZakBvGEuNMZQUT9+vXpbIbdG2+8Ib2IP3vPPfdIfAGxMi2XLFnC\n4JBfbALX/clEbdq0KV4Mqz1cLIWOMJzrZgF7hgLs37t3b6LUuXPnEvzSEXo2BHqEviCCE77g0DET\nxG5b3gE6K1OmTLg2OH2UZMuWrXz58ng3kyZNuu+++5CZZhFVTTSq8ixwqIP72FM/7Nq1q2PHjnBx\nixYt8La6d++eMmVKiA/ZsVxo1zGfhb11rB/E75UqVbLnK8HRfv3118ePHy8v/tARzZs3PxMAg5m2\nUK4SlOhwuye+YchkEAAjEPvnzJmTQuisc+fOBIWUL7g2/YSHhSFo+oVa6I7ALa3A+1F75sGeZcqU\nwUfG4BBfyZIl8+XLpx5YA9YPlUwL2JN32K0KPHp5z549L7744m233aZOhhlYkFKlSlW9enX1qzvr\nmTzm9oFEyhpRobPz58/TZ/Rx8NgGBtDGjRs3bNiAECyKBIZzI7UA89PiLHjguEsmCMotflY4CL9q\nho3Hz9mw2DGn1A+R4oRLPouIWscdZEnDfdN/5IF51R8lI0LIZBAsOeqZBp3CusIyJodMojBjbdxD\nZUM7Vq1ahZcdPAgFOisoecJuVe9eDgkWe/VEK1Jcz5wb3zCcayzwT0ONGjXU0xKAM/iJUxKjOKJV\nq1ZhkmmCgDWDSMX3ims41z8M4xgL/NOAV967d+9x48aNHTu2X79+gwYN8k09Hti/f39izjAyevTo\nn376KXgQOQzn+odhHGMBg3jC9u3b/f0rIL5x9uzZ7777LnjgC4Zz/cMwjrGAgUGkMJzrH4ZxjAUM\nDCKF4Vz/MIxjLGBgECkM5/qHYZwwLXDxYgLkergSh+wJFy5ckL+dGhhEHZGxxrhx4x5//PF//etf\nXbt2DRYF/htYqFChRx55ZNKkScGiOCM2dLZ69eo+ffp07NhRf/n6999/HzJkyMSJEydPnuz9v92Y\nce7mzZvj8l/C+EM4FohjrofDhw/L9mARAfaMS/aEl1566ZlnnhHZwCC6iJg1Dh06lDZtWsuf8lq3\nbu3vP9huiAGdLVq0CGKFVaGzIkWKyJs2HFarVk227+Rb9XqlI2LDuQsWLMiVK5cP3okBwrSA71wP\ne/fuzZs3r/fbgG64HIfsCbt377a8UZp48H0iy2RhECn8sMann356++23Q75yCCmE3FYjUsSAzurW\nrbswsN0ywH+H1xDmz59fv359KWTSZsmSRd7zcUQMlCSG6Nu3r9ogLbEhTAv4y/Vw5cqVXr16ya4r\n/nCb3+wJQO3bkNiQ2DJZGEQKP6zBZChTpkydOnWQz5w5AylIeRQRAzobMGCAensPT0q2Q8Wxbdu2\nrRQCy8vdFngriWc6b968adOmqfdW9aQG1Lhnzx7vckCMDBGgJ18Fi2z73tMd33zzDXryac+XF6/w\ntsDvtlwPx12yJBx2yitBzEGJSj0gsLTdjgvRyJ6wYcMG9R9MixqiNj1L11C+fPnyS5cuIeN5zJ07\nV7RCBzQcO3YsiyWrOMrIyi3lkydPpoHchMbu3LmTw1WrVvEt8tSpU2V/FmQ6ff369VTHJUoZjMNA\nDZnjwCAxwye1bdmyJWXKlIyz/v37x8ejxhhwro6mTZu2aNECoV69erL/v6Bo0aIeb1V7KInjLxuX\nEFY/+uij0CLypkBSg969e+/YsYNZWqBAAXmI4VZuT3BAoX3feyqSfefoFGlFzOBhAcdcD1BPP6cs\nCfCgJa8EDeRyPfUAgmMmBR3UFd3sCXY1aAI9VbhwYSiV1XT48OEoDFcif/bZZ2J/WBj+ZYLwLeEg\n/Vu6dGmWUspZMDJnzjxp0qTRo0cz6uhchtyrr77KVfv370d5kSmvUaMGbcSM6IDysiMMtwonx4FB\nYoZ/auvQoUPWrFl9b/TgjVhyLl5YqVKlZF+xmjVr9ujRQ8pB8eLFZbY7wkNJoj/xl5kw9913n3pT\nkPurvVwrV66sNk13LLcnOHDc956Jiq8kHpbuEsYAbhaAgBxzPQAWBsdtVekF3FLMJQ3BPbSkHnDb\n819H1LMn2NVAQG2VAWHz5s0333yzcPS2bdvUJo0gderUStvBgwc///zzIqdJk4Y1QLV0yJAhwrPg\n448/1mW1KS0LVbt27UTGkubZQpKGf2oj/mLKybiJOmLGuXhG1atXVxs5vvLKK2pwg0ceeUQCYUd4\nKwmJ4Bnh0TAPVWwIt6rNXpHViuVYbk9w4Ljv/Q8//FCoUCFYoEqVKh6bqMUH3CzglusB6Dxr4Vx9\ns2p76gG3Pf91RD17gl0NClFb7Qa7c+dOxbOsMTly5BAZwLnqD2fff//9LbfcIgbBMmqrWWDhWV1m\nNCpZlRvOTerwT21EN/HHjLHhXOJEGFYmADTB57vvvouvFPjyLzCF7DtsKngoSVAJA4orVLRo0bVr\n10otFp71lu0JDhz3vRcnmhiWkxW1xQZuFoCJHHM9AJ1nGUI65+p5JeypB9z2/NcR9ewJITMg0FL5\n9RV4cO4CLSOf5Zc9nU9ZVt341865amdug6SFuHKu9xzwjRhwLoTYo0cP5smvv/6Keyib4cOwyts6\nfvx4gQIFPBrooSQOsmxBTxzAZIMvZNd9PakB3Kpkx3J7ggPuZt/3nvNx5aTEnoIoXuFmAbR1zPUA\nHLMkABhEzytBj1hSDzi2XWQF3NLoZk+wq8GnngHB4udmz55dZADnMoRExmOVv7RjGVYjKRSwvr78\n8ssiN2/eXD2RHzJkiO7nKtk7x4FB4odPamOlZXrjPnTr1o0hGCyNHmLAuS1btsQPUoD1pBxXl+G+\nf//+119/3b4/vw4PJZkk2Gfx4sWTJk0aNmxY48aNkfWkBuPHj4eL8aGQ3cqZn5YEB9zZvu99vXr1\nPvroo+XLl3/yySewWKD+GMHDAm65HoA9S4I9rwTAN9RTD1Bib7sF56KdPQFY1NAzINAjDRs2pGmo\nzQJAFfAsXSYXIo8YMYIaaXjr1q2pFPUQGGxEVzjLctqxY8eoF2tMmzYNXsZVZ8WlouLFi8PmM2bM\nWLlyZenSpXPnzi3/8fDIcWCQJBDv1OYPMeBcD8AXq1atss9MC7yVxMOSvx+AuDz1Jj61JzjAgVL3\n5ATY+eDBg+oXm5ghZDeh50WnXA8nXLIkWEC77Bv66W13RNSzJziqERJwLk2j70Juv839sQ+NwqGm\nopCjJY45DgwSFoZz/SNJKBmvMBZwA7yZMmVKnfENDASGc/3DMI6xgCPw69u2bVu4cOH27dsbh9TA\nAsO5/mEYx1jAwCBSGM71D8M4xgIGBpHCcK5/JGnGuXr1asgfCUPCcK6BQaQwnOsfSZdxvvrqqzFj\nxgwfPrxu3bpnAhvK+IPhXAODSOF/zly+fHnjxo1qcyP1+mxUYDg3Uji+z+qGp59+Wqi2SZMmffr0\nkUIfSHALXNQyUOC5R/pvOS45raWHMDCIAfzMGcboG2+80bZt2zlz5syaNWvQoEGrV69m9ga/jgZ8\nT2Ym4ciRIwcOHNizZ0+1wy+QP8l/9tlnP//8c7Ao8ELRkCFDJkyYoG8CnQjzRITElStXInob4osv\nvpB/y7Zr1069quADcbcAajRv3tz+Rlk4sGSgGDVqVLp06SIi0BEjRqRNm5axETxO9GBR2bBhQ/Ag\nseLChQtr164NHhjYEPGcwaDFixfX30xnwteoUYMoNXgcDfiezHht8vd1/LiGDRvKI8slS5bIDo2X\nLl0qW7asvKrAaVWrVpU34l999VWZeJBstUSWJyIcLFu2TLZzjAhHjhwpV66c/YWL8BF3C9BB9erV\n0xfCiKBnoCDSGjdu3Pbt2+UwTNDdane3kGCof/jhh8GDhABuRJ48efR38BJcJQtY84iiOnbsGDw2\nsCHiOYP/WLNmzeDB32DOMHOCB9GA78kMjQalP//8z3/+I/u/FCtWTO35PWDAgA4dOiC0b99e7dOI\n71CiRAkEmDdR5YkIE2qvhvBBTN2iRQsfTK0jwS2AP6Vv6zNt2rRIHxQwmGVr2nCwcePGbt26BQ8S\nCKxSffv23bZtmxwmBpV0MKeMk+uNyOYMbmD69OkldZgFat/SqMD3ZH744YchUyYewPVmgBKOpUiR\nQr30ybSUHVFLlSqlJtvx48dlP5Qo5onAWdYTE+x0yQiwZcuWSZMmbd26df369WpTGFw2Tpg+fbra\nrhDdvnFJBsGqoDw11omFCxfu2bOHnuLk8ePH4xkhb968Gbdd5bnBOP369ZOtWxw3LggTbhaQvA9o\nQu1Tpkz5+uuv5X1Wez4IWo0C0szvvvsOCwDKuVBk9bhWhz0DBcBoam82YM/TAeScmTNnqr194Vxu\nRY9QqGfoIAxavHgxBjx27JiUoGrJkiVZkqlXUZ4O7EzXcJ+lS5ciSwljbPTo0QxCkceMGWN/6KxO\no5ephYX/5MmTFDJaMJduAcugsqjEaKctDDMMiBpqY8+QyTXsZrE33z5QV6xYQWCBJosWLVJ7D4Ws\nyyAyamPSMs1k2/x4hW/OhVxyBtCqVSvZ1Ym5x93UCGAeykZ8WbNmZVRJIdOAcxhn0coTYU9McMAl\nIwAhwjPPPIP8ww8/5M2bF/ZhcDdo0IBpwwzs0qWLPMbxSAYBeak3+plv8FGBAgWGDRtGLUzRggUL\nMlWYS1iDJUROIxrInDlztmzZ7rrrLr6VQh9wswDzkHgoe/bssAPMjg0rVqyINSi35INgDqOVtJGm\nNWrUiL5jSWCkcTnNkYVBh2MGCoARhOmAY54OKJWwV57ycwd5CgHnYnxkKs2fP7/wFCt0rVq1uBvd\nR6E8buby1157DeNv2rTJMT4ghJIRRdUyirgDfJQqVSqGFjJMxPKPHDj9/8FXCxYs4KtRo0bBtjt2\n7KBSuJU2Ep8xXEV/+6CyqHTJloeCq3A8vZNr2M3i2Hz7QIVnmUT9+/fH186dOzfnhKzLAERGbRia\naebh+kULHnTmDcbHu++++8orrzCCZfc8ZnWyZMnkW6B2Ms2QIcPy5culkOlKjYxvZmBU8kQ4JiZw\nywiAwpUrV0aQhQE3XG02yKzLkiULswuOhoDkBEsyCH1VYKIypW+99VYhBfj3xhtvFOeFWxGjBM6K\nGjwsgAfKihU8+PPP6tWrSyZdyvV8EEDfuJbCJ554AnPhD+J7SqEOnFa6T7ljcJz+bEEBT9Oep4OV\nBiYKfP8n30LxCPS4nqEDzkLAhiwMomHDhg0HDx4c+P6vB2segTwhvwQNTBNJryfA7IpnGXV2zhXw\nldrk984775SQCGTMmFF603FQ2VXS81BAmiGTa9jN4tZ8y0AFTz31lGySGWZdBiAyaqMj77jjDtkK\n1oLo/pzqj3Nx5YizJJZkdMJWcNCRI0e4mxoKBHEs3Qh58uRRITkLO+fAUJB13PNE4DE5JiZw24Wa\nofzmm2+KDPuzWui/49MKgm63ZBA4KZbHZzRZpYEhBlQbgaNDhQoVRI4WvDm3VKlSwYNAdplKlSoh\nUK7ngwCWzcKZ8A888IBb2l1cKrcMFBZQkSVPx+23344Z5VsFOJfFTMlqAYPW6TjICGOqv9N5cy5a\ncTneLsx70003BUuv5VlvzmWsikynK1eacATychtUdpX0PBThJNdwNItj8/WBKmB04byLHE5dBiBi\nauvYsaOaxgoENcSJwYNowB/nMtb1SBnabdWqFXEZo1D9nD127Fh8RgRaQQAuhYxplmjmDKMq7nki\nqNExMYHOs3pGACoFIuMv4KeoX/xkkcNVd0sGwSRXBCT497//zbQXuUuXLurOL7/88tChQ8+cOaOc\nlLgjfM5966235MdJyi3jx8K5rCIEKA8//LD9qQLA+XXLQKHDMU8HDvKKFSvkBAWdZ5VM1IwC8vib\nNfj9998XZRTBOeZoqFevnlibBf7mm29GkKt0nqU3PThXfQXnyp9ngHCu26Cyq6TnoaDhIZNr2M3i\n1vzAOA0OJwFdSYeKHE5dBiBiamO9LVCggGWPeohMDZGowB/nMuz0JwNMSPm5r0aNGkphWHjatGkI\nRPqtW7eWQnzDli1bIkQrT4RjYgLms2NGgP8EIDJo1qyZeqBBoIevzXyDDrC8FMqaAdBt6tSpIivk\nzZsXZ1DkkiVLqimROXNm3KiRI0dGcVZ4c656fEyNDz30kBiBPtLzQYA6deoozoV0ZFb3799fHilK\nuQIlbhkodDjm6ejUqVP79u3lBEhEnr06ZuggxFZjgyUB0pHYjkVLUqLZczScOnWKAEV2Edu2bdst\nt9xCr0nMTtvFaSV8SZ48uVuO9PTp07v5uRLZOA4qi0rYR89DQfOJ6ryTa9jN4tZ8y0AFdKXi+nDq\nMgB+qI1IHB+NflqwYAEdP3DgQGXoaMEf5wLGBKOQQT937lxcQvHpiHFwsvAW0faNN96QmXzx4sUG\nDRosWbIEXpPfZAI3+Gsxj3ueCNxJ7skMmT///xMTHHPKCAB94FMULFhQ/RuEcc8CMGbMGPiUaSb/\nXcWHsieDYLirvyII6JpMmTIx25Fpe8aMGdWv9s8++yzKyESNFrw5N2fOnDSKGvGVZBUh2rDkg2C1\nxg6VK1fGtR80aFD27NlltrNeQmFVq1a1e3b0plsGCgXHPB0sWoxbOoVxywnnz58nOMuaNSvO2vq/\nM3RUqFABGeXLli07KwBiZwrl4SncV758eQoZXVKRAoOqYcOGhN5EVywhLK5wGT47X9Flbdq0oUXT\np0+/99576UoL7dJfhI+0l2UY2sVvSJkyJUsvYU2vXr1SpUrF3aBgx0Glq4R/bc9DgWG9k2vYzeLY\nfPtAJZhImzYtfaSWwJB1GQCf1AboctwHHEO7MxJ3+OZcwEiFmyzPkhhJMJT+JBSgOS7hhg0bLE3g\n2rjniQBMEkgweBAAFaEebAix4tPJkuAIroWjgwcuySDEYdfBOXroqr/vwB1OOP3vKi7w5lwcUvSB\nX2QNiC6IQlhOsAb2VOuKDipVsZduZyjG4z/XOtBcLtQv57Z6v1jAmFHf6lehp/QF1GkZEpHCPqi8\nVRJgLo/BBuxmcWx+OAhZ1z8c/qktXhEXzo0ZElZJJl74L1DFEzws8PXXXxcrVix4YGBg8DcM5/pH\nwioJ4aonvAkFNwts3769QYMGxYsXJ1YNFhkYGARgONc/ElZJx7+vxhhJopsMDBIVDOf6h2EcYwED\ng0hhONc/DOMYCxgYRArDuf5hGMdYwMAgUhjO9Q/DOP80C4TzP7OrV69yTsg/Giro9+Qq2dA5yeHi\nxYvqH+4G3rieOXe+U24IHVuc8kTs27evT58+Xbt2HTVqlPffDA3n/qMssGLFivz587dp0yZ47IIP\nP/wwTZo09peMHWG550svvfTMM8+InISwbdu2xx9/3L4lQPxh7ty5iWqn9ohw3XKuY24IHUed8kT8\n+uuvPXr0YNHGW2nevPmLL74YONcZhnO9LSAbiV1PGDp0aEjOBeXLlw+Tc4F+z927dydao13xTEix\ncuXKWHLutGnT1M47SQ7XLec65obQ0d4pT0T//v3feecdKTxw4ABqeOwjYTjXwwKECNWrVw8eXC+Q\nt3iDB+6oWLFi+JxruafbhmoJDu+EFN/Yti4ycENkrEEwPnnyZBhq69atEydO9NhzK46II52dc8kN\nocMxTwTecZcuXaTwxIkTqCEbejnCcK6bBfbv39+kSROi5i8DqRykkMBi8bWpB3a65M4IP2GEPRnE\nmjVroK2DBw+y4s6YMUN2PHArJ5phDIx2yePAcsuZ3FxV7c2569ev5+S9e/fqnPvHH3988cUXU6ZM\nUR6ABfo9mVmy7SRAn2XLlnFD2S5ZqcoopSLCspO2XBIXAnkixo4dSxM4Yfbs2fKkWMoxNfaU/BEM\neK6SfUqRKeRQyZj0/PnzS5cupUaqo5waS3rmyBDOJUzkchRGMSlHcMudIQ2hXv1BMEs1tTMS+EpK\nMCDGhG3UDhI0fNasWbKnz2Fb5hEKqUI3XWJDZKzxyy+/PP/88xUqVKBJNA9XsXv37sHvooo40plb\nbggdjnki5FAAO6gt+h1hONfNAswEJlWRIkU2bdok726w/tlTD/DpmDuDpT2chBGOySCoMVeuXL17\n996xYweXFyhQQCIVx3L0ccvjYE/KQKEb51J148aNGWaXLl1i2c6RI4dwLmxSqVIlmslQrF27tuOW\nSfo9YToRUIYbcitkgmgCMkpC5pKgdugsZcqUw4cPZ62iyaVLl2Z1odySPwIu7tevn0wK7kZsJzLl\nmKho0aLcmWVs6NChsuUYN/HOkQHn0k3UzlW0ncbKKuiYO0MaAkVSNQyu3hHnkipVqsi6SxNYPBBY\nvBlONIGVjAspYSwRjxYuXBiZxcaSecRuOoREhYhZ491331W7ejOSMmXKZN/wOO6II52xJDrmhtCR\nwSlPhBwCZhqUoTZFdIThXA8LMPHKli0bPHDPvOCWO4MzvRNGAFwnezIIUPPa1A9Qochu5Y55HByT\nMrhx7rBhw/RUNDCdcK7ulMAg0IfIOhzviZeqIjNWo/vvv19k1PPOJQFSp06tXHXsrDaw1/NHcMjC\nphwR5osu33rrrfK/i++//14l+/Derx3O1bfXwGKDBg1CcMudoRqCPrfddpv4px9++CFjI/D9n6wN\nLLQIsiOglKinVQwJ4VxA1XrmETfTJR744Vw9Azlj94MPPggeRA9xpLMjLrkhdDjmiZBDFlWmEEu6\nHLrBcG74nAscUw/oPKvLAO7zSBghYL5xKz0ZBFDb4Iqsb0nuWK5vFi4yjrBjUgY3zn3hhRf0zbxp\nuHBuiRIlWrVqJTeh4Y6/QTnes0OHDo899phcSBAtO+QC1HPbYxd+ERnOZQCLDGnecsst8BGynj8C\nWHhWl5kaSlblITlX36J+4MCBkhaEqrGzY+4M1RBl/+eeew4HVgoV0JmBwarWpUsX9acOC+fqmUfc\nTJd4EFfO9c4Y5htxpDPiLMfcEDqecsoTgcwnw0uuZSg4RlICw7nhcC4BNV4Mk98x9YDOs1CSzrnE\nsx4JI4BjMghkC8+GlHXOlTwOjB/HpAxunFu3bl14OXigcS6uvfKs3eB4T+zz9NNPBw806Krac0mI\nrHOuHuHp+SOAzqe4F278a+dctUm5DgvnshDWq1cPIZzcGUrGpaUWKRTgDLEAiDHxkLAnyyGts3Cu\n/vOdm+kSD/xwrqRUAIcOHSJeUOtVFBF3OnPMDXHx4kViVZmljnkiACywZs0aRvOBAwdYrtXIsMNw\nrocFtm3bJrEF7gYU5pZ6AOJzzJ2B2WWuuiWMAI7JIDh0TP0A3MqhFVlZ6XGVx8ExKQMsr1qhY+HC\nhYpxaGzu3LnlsdXUqVMJBNVaPnPmzMAp18Dxnvv27cuRI4dabNSFIXNJADj3eCDjNXjllVckEyu1\n6/kjABYmOBB54sSJDz74oMhbtmzR/VwlWxJSWADx0WrVTU8++eTixYtPuefO0BsC54pMMIEPp5uL\nCLVQoUKBs/5anODcZcuWETDt2LFDcS5rgJ55xM10iQd+OJdhhOEwUOPGjbF18IuoIu509otTbgh8\ngXvuuUe2M4d/7XkioABGiQKj4a97ucBwrocF4EGiy88//3zkyJEcMk7w/v5KPHBt5oVjTrkzwkwY\nwepoTwbBmpopUyYcn/V/p37A60F2K+c+4mla8jjgm3NDPSkDc7tMmTIQNKuIKKCD5RnnjsEGh+bL\nl++JJ55g7DHqevfu/eabb8Idn376qXJFFTzuiYvKAEYlWvf111/DVuHkkuBCOJfQE7U/+ugjbIjm\n+JgIXKvnjwCNGjWidzA+gWCyZMm4z88//1y7du00adLgtjNNmCA33XSTrD1wmVuODICb8p///Id6\nMePbb79NYymk+fbcGbt27VINQfnu3bvTEFY4oV08IWYrLi13QBkWhkcffRSZnmUZK1euHHEDnFun\nTh2WEJS3Zx4BFtNJYeKBH87t0KEDM0otU/GBqNCZY24IHYwJxzwRYcJwbkgLMGd028Jl8kOHfAo4\ngblHCb4J5+tfhQRMpOLriC60AFZyzOMA8+qH3iDmlb/B0Uzmv2o45XrCjvDBHTBI8CBswLnwLDWq\nf0F44MSJEzQQDWm4xH8ewNrSQA9AC5wWPAiA26qrwukjzrHUgqcsP7Jx5zCnqj/TxQYRswaLmPx9\nJF6RJOjMcK6xQGIDhIXb+EdCb2Zv4IHI5gxhyDMBELkEi+IHhnOTBIwFEhXw1tu2bVu4cGG8InmK\napAIkUjnjOHcJAFjAQODSGE41z8M4xgLGBhECsO5/mEYx1jAwCBSJNI5Iz9TJnIkCSXjFcYCBgaR\nwvgpBgYGBrGD4VwDAwOD2MFwroGBgUHsYDjXwMDAIHYwnGtgYGAQK/z55/8B+1GIF3f4Z00AAAAA\nSUVORK5CYII=\n", "text/plain": [""]}, "execution_count": 15, "metadata": {}, "output_type": "execute_result"}], "source": ["from pyquickhelper.helpgen import NbImage\n", "NbImage(\"exam2016_values.png\")"]}, {"cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [{"data": {"text/plain": ["29"]}, "execution_count": 16, "metadata": {}, "output_type": "execute_result"}], "source": ["def bascule(A,S,L,r,Y,C,p):\n", " Y = 0\n", " possible = C*S\n", " while possible > 0:\n", " Y += 1\n", " eco = economie(A,S,L,r,Y)\n", " somme = somme_maximale(A,p,Y)\n", " possible = C*S - somme - eco\n", " return Y\n", "\n", "bascule(1000,40,20,0.015,20,8000,0.029)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q7 exo 1\n", "\n", "Ecrire une fonction qui d\u00e9termine la plus petite surface que ce parisien ne pourra jamais s'offrir avant 20 ans au m\u00e8tre carr\u00e9 pr\u00e8s.\n", "\n", "Le raisonnement est toujours le m\u00eame, on regarde des plus petites surfaces aux plus grandes la surface que ce parisien pourra s'offrir. La fonction ``bascule`` indique quand un parisien peut acheter son appartement pour la premi\u00e8re fois. Il suffit de partir d'une petite surface et de lui ajouter des m\u00e8tres carr\u00e9s jusqu'\u00e0 ce que le moment de bascule se produise 20 ans apr\u00e8s avoir commenc\u00e9 \u00e0 travailler."]}, {"cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [{"data": {"text/plain": ["34"]}, "execution_count": 17, "metadata": {}, "output_type": "execute_result"}], "source": ["def surface_max(A,L,r,Y,C,p,delay=20):\n", " S = 1\n", " wait = bascule(A,S,L,r,Y,C,p)\n", " while wait < delay:\n", " S += 1\n", " wait = bascule(A,S,L,r,Y,C,p)\n", " return S\n", "\n", "surface_max(1000,20,0.015,20,8000,0.029)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q7 exo 2\n", "\n", "D\u00e9terminer la somme $A$ qu'il faille investir pour acheter 40 $m^2$ \u00e0 30 ans en supposant que ce parisien a commenc\u00e9 \u00e0 travailler \u00e0 23 ans et commence \u00e0 louer un appartement de cette surface.\n", "\n", "Le raisonnement est identique au question pr\u00e9c\u00e9dente. On commence par des mensualit\u00e9s $A$ \u00e9lev\u00e9es qu'on fait d\u00e9cro\u00eetre jusqu'\u00e0 ce que le parisien ne puisse plus s'offrir son appartement."]}, {"cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [{"data": {"text/plain": ["2600"]}, "execution_count": 18, "metadata": {}, "output_type": "execute_result"}], "source": ["def A40a30(L,r,Y,C,p):\n", " A = 10000\n", " S = 40\n", " wait = bascule(A,S,L,r,Y,C,p)\n", " while wait < 7:\n", " A -= 100\n", " wait = bascule(A,S,L,r,Y,C,p)\n", " return A\n", "\n", "A40a30(20,0.015,20,8000,0.029)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q8 \n", "\n", "Ce mod\u00e8le ne prend pas en compte tous les param\u00e8tres de la vie r\u00e9elle. Citez-en un. \n", "\n", "* L'inflation\n", "* Les augmentations de salaires\n", "* L'augmentation du prix au m\u00e8tre carr\u00e9\n", "* ..."]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q9 version dichotomique de Q4\n", "\n", "On utilise la fonction *decompose_mensualite* pour calculer la somme maximale qu'une personne puisse emprunter avec une mensualit\u00e9 *M*, \u00e0 savoir tout passe en int\u00e9r\u00eat ``M / ((1+p)**(1.0/12)-1)`` o\u00f9 celle qui correspond \u00e0 un nombre de mensualit\u00e9 infini.\n", "\n", "La r\u00e9ponse que l'on cherche est une somme mais celle-ci est une fonction croissante de la dur\u00e9e du pr\u00eat. Plut\u00f4t que de donner plus d'explications \u00e0 ce sujet, je sugg\u00e8re de lire le probl\u00e8me [Problem C. Egg Drop](https://code.google.com/codejam/contest/32003/dashboard#s=p2). La m\u00eame solution ne s'applique pas ici mais c'est le m\u00eame \u00e9tat d'esprit qui permet de la trouver. La solution que je propose n'est pas n\u00e9cessairement la meilleure mais elle est certainement plus rapide que la premi\u00e8re propos\u00e9e. \n", "\n", "La ligne avec ``###`` est la plus importante. On multiplie les pas de recherche pas un coefficient. Sup\u00e9rieur \u00e0 1 : l'algorithme ne peut pas converger. Inf\u00e9rieur \u00e0 1 : le pas doit \u00eatre suffisamment grand pour converger vers la vraie valeur. Cela d\u00e9pend de la d\u00e9riv\u00e9e $\\frac{df}{dK}$ o\u00f9 $f$ est la dur\u00e9e du pr\u00eat ``len(mensualites(K, M, p))``."]}, {"cell_type": "code", "execution_count": 18, "metadata": {"scrolled": true}, "outputs": [{"data": {"text/plain": ["182199.99817640134"]}, "execution_count": 19, "metadata": {}, "output_type": "execute_result"}], "source": ["def somme_maximale_dicho(M,p,Y):\n", " K_max = M / ((1+p)**(1.0/12)-1)\n", " K = K_max / 2\n", " step = 0.5\n", " dk = K * step\n", " l = mensualites(K, M, p)\n", " while len(l) != Y*12 and dk > 1e-5:\n", " if len(l) < Y*12:\n", " K += dk\n", " K = min(K_max - 1000, K)\n", " else:\n", " K -= dk\n", " dk *= step ###\n", " l = mensualites(K, M, p)\n", " if len(l) != Y*12:\n", " raise Exception(\"il faut augmenter step\")\n", " return K\n", " \n", "somme_maximale_dicho(1000, 0.029, 20)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Le param\u00e8tre ``dk`` donne une indication de la pr\u00e9cision. On compare les temps d'ex\u00e9cution :"]}, {"cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["10 loops, best of 3: 25.7 ms per loop\n", "100 loops, best of 3: 2.8 ms per loop\n"]}], "source": ["%timeit somme_maximale(1000, 0.029, 20)\n", "%timeit somme_maximale_dicho(1000, 0.029, 20)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["## Exercice 2 : coder les num\u00e9ros de t\u00e9l\u00e9phone"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q1 \n", "\n", "Michel perd souvent ses carnets de num\u00e9ros et pour \u00e9viter d'importuner ses proches de recevoir des coups de fils impromptus, il utilise un code. Si la premi\u00e8re lettre est une voyelle, il permute les num\u00e9ros 3 et 4 sinon il les laisse en l'\u00e9tat. Si la seconde lettre est une voyelle, il permute les num\u00e9ros 5 et 6, rien en cas de consonnes. Exemple (on enl\u00e8ve volontairement les accents) :\n", "\n", " adele 06 64 34 22 67 --> 06 46 34 22 67\n", " gerard 06 64 34 22 68 --> 06 64 43 22 86\n", " \n", "Ecrire la fonction qui transforme un num\u00e9ro. Il est recommand\u00e9 de ne pas tenir compte des espaces."]}, {"cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [{"data": {"text/plain": ["'0646342267'"]}, "execution_count": 21, "metadata": {}, "output_type": "execute_result"}], "source": ["def transforme_numero(prenom, numero):\n", " res = numero[:2]\n", " for i, c in enumerate(prenom):\n", " if c in \"aeiouy\":\n", " res += numero[i*2+3] + numero[i*2+2]\n", " else:\n", " res += numero[i*2+2:i*2+4]\n", " if len(res) >= len(numero):\n", " break\n", " return res\n", "\n", "transforme_numero(\"adele\", \"0664342267\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q2 \n", "\n", "Ecrire la fonction qui effectue la transformation inverse. La r\u00e9ciproque est en fait la m\u00eame fonction."]}, {"cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [{"data": {"text/plain": ["'0664342267'"]}, "execution_count": 22, "metadata": {}, "output_type": "execute_result"}], "source": ["transforme_numero(\"adele\", \"0646342267\")"]}, {"cell_type": "markdown", "metadata": {"collapsed": true}, "source": ["## Exercice 3 : coder les num\u00e9ros de t\u00e9l\u00e9phone"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q1\n", "\n", "Michel perd souvent ses carnets de num\u00e9ros et pour \u00e9viter d'importuner ses proches de recevoir des coups de fils impromptus, il utilise un code. Si la premi\u00e8re lettre est une voyelle, il fait la somme des chiffres 3 et 4 et remplace le chiffre 4 par celui des unit\u00e9s de l'addition, sinon il les laisse en l'\u00e9tat. Si la seconde lettre est une voyelle, il additionne les chiffres 5 et 6 et remplace le chiffre 6 par celui des unit\u00e9s de l'addition, rien en cas de consonnes. Exemple (on enl\u00e8ve volontairement les accents) :\n", "\n", " adele 06 64 34 22 67 --> 06 60 34 24 67\n", " gerard 06 64 34 22 68 --> 06 64 37 22 64\n", "\n", "Ecrire la fonction qui transforme un num\u00e9ro. Il est recommand\u00e9 de ne pas tenir compte des espaces."]}, {"cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [{"data": {"text/plain": ["'0660342467'"]}, "execution_count": 23, "metadata": {}, "output_type": "execute_result"}], "source": ["def transforme_numero(prenom, numero):\n", " res = numero[:2]\n", " for i, c in enumerate(prenom):\n", " if c in \"aeiouy\":\n", " res += numero[i*2+2] + str ( (int(numero[i*2+2]) + int(numero[i*2+3])) % 10)\n", " else:\n", " res += numero[i*2+2:i*2+4]\n", " if len(res) >= len(numero):\n", " break\n", " return res\n", "\n", "transforme_numero(\"adele\", \"0664342267\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Q2\n", "\n", "A votre avis, est-il possible d'\u00e9crire la fonction qui effectue la transformation inverse. Justifiez.\n", "\n", "Oui et voici la r\u00e9ciproque. On consid\u00e8re un groupe de chiffre modifi\u00e9, l'important est de comprendre que si le second chiffre est inf\u00e9rieur au premier alors la somme des deux chiffres initiaux d\u00e9passe n\u00e9cessairement 10."]}, {"cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [{"data": {"text/plain": ["'0664342267'"]}, "execution_count": 24, "metadata": {}, "output_type": "execute_result"}], "source": ["def transforme_numero_envers(prenom, numero):\n", " res = numero[:2]\n", " for i, c in enumerate(prenom):\n", " if c in \"aeiouy\":\n", " res += numero[i*2+2] + str ( (int(numero[i*2+3]) - int(numero[i*2+2]) + 10) % 10)\n", " else:\n", " res += numero[i*2+2:i*2+4]\n", " if len(res) >= len(numero):\n", " break\n", " return res\n", "\n", "transforme_numero_envers(\"adele\", \"0660342467\")"]}, {"cell_type": "markdown", "metadata": {}, "source": ["**Remarque :** Beaucoup ont affront\u00e9 l'erreur suivante"]}, {"cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [{"ename": "TypeError", "evalue": "unorderable types: str() < int()", "output_type": "error", "traceback": ["\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[1;34m\"3\"\u001b[0m \u001b[1;33m<\u001b[0m \u001b[1;36m4\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[1;31mTypeError\u001b[0m: unorderable types: str() < int()"]}], "source": ["# d\u00e9clenche une exception\n", "\"3\" < 4"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Comme l'exemple le stipule, cela survient lorsqu'on essaye de faire une comparison num\u00e9rique entre une cha\u00eene de caract\u00e8res et un type num\u00e9rique. Il faut convertir la cha\u00eene de caract\u00e8res."]}, {"cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [{"data": {"text/plain": ["True"]}, "execution_count": 26, "metadata": {}, "output_type": "execute_result"}], "source": ["int(\"3\") < 4"]}, {"cell_type": "code", "execution_count": 26, "metadata": {"collapsed": true}, "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.6.1"}}, "nbformat": 4, "nbformat_minor": 2}