From 261a46b13039ad9e9e8dff2a50533cdc8c615c02 Mon Sep 17 00:00:00 2001 From: Louis Oliphant <ltoliphant@wisc.edu> Date: Thu, 24 Oct 2024 06:02:56 -0500 Subject: [PATCH] finished lec 22 recursion --- .../22_Recursion/Lec_22_Recursion.ipynb | 519 ++++++++++++ .../Lec_22_Recursion_Solution.ipynb | 772 ++++++++++++++++++ 2 files changed, 1291 insertions(+) create mode 100644 f24/Louis_Lecture_Notes/22_Recursion/Lec_22_Recursion.ipynb create mode 100644 f24/Louis_Lecture_Notes/22_Recursion/Lec_22_Recursion_Solution.ipynb diff --git a/f24/Louis_Lecture_Notes/22_Recursion/Lec_22_Recursion.ipynb b/f24/Louis_Lecture_Notes/22_Recursion/Lec_22_Recursion.ipynb new file mode 100644 index 0000000..203ea31 --- /dev/null +++ b/f24/Louis_Lecture_Notes/22_Recursion/Lec_22_Recursion.ipynb @@ -0,0 +1,519 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Warmup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Warmup 0: What is the difference between these two pieces of code?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "groceries = [\"apples\", \"bananas\", \"coconuts\", \"dragonfruit\"]\n", + "groceries_dicts = []\n", + "for grocery in groceries:\n", + " grocery_dict = {}\n", + " grocery_dict['name'] = grocery\n", + " grocery_dict['size'] = len(grocery)\n", + " groceries_dicts.append(grocery_dict)\n", + "groceries_dicts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "groceries = [\"apples\", \"bananas\", \"coconuts\", \"dragonfruit\"]\n", + "groceries_dicts = []\n", + "grocery_dict = {}\n", + "for grocery in groceries:\n", + " grocery_dict['name'] = grocery\n", + " grocery_dict['size'] = len(grocery)\n", + " groceries_dicts.append(grocery_dict)\n", + "groceries_dicts" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Warmup 1a: Use 'in' to determine if something is in my_list\n", + "my_list = [\"meet\", \"me\", \"after\", 84]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Warmup 1b: What about this list? \n", + "my_list = [11, \"meet\", [\"me\", \"them\", \"us\"], [84,19, 22], \"school\", 2.54]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Warmup 2a: Write a function to find a thing in a list that may have lists in it\n", + "my_list = [11, \"meet\", [\"me\", \"them\", \"us\"], [84,19, 22], \"school\", 2.54]\n", + "def search_list_depth2(target, some_list):\n", + " pass\n", + " \n", + "print(search_list_depth2(\"school\", my_list)) # in list\n", + "# print(search_list_depth2(22, my_list)) # in nested list\n", + "# print(search_list_depth2(\"house\", my_list)) # not anywhere\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Warmup 2b: Will our function work on this list? Guess:\n", + "list_3_deep = [22, [33, 44, [55, 66], 77 ], 88]\n", + "\n", + "# let's try it with our previous function\n", + "print(search_list_depth2(22, list_3_deep)) # in list\n", + "print(search_list_depth2(99, list_3_deep)) # not in list\n", + "\n", + "# Write other tests to be sure that it works\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Warmup 2c: What about ANY depth list? \n", + "# That is the goal of today's lecture\n", + "\n", + "list_3_deep = [22, [33, 44, [55, 66], 77 ], 88]\n", + "\n", + "def search_list_depth_any(target, some_list):\n", + " pass\n", + "\n", + "search_list_depth_any(55, list_3_deep)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Recursion\n", + "\n", + "## Readings\n", + "\n", + "- [Downey Ch 5 (\"Recursion\" through \"Infinite Recursion\")](https://greenteapress.com/thinkpython2/html/thinkpython2006.html), [Ch 6 (\"More Recursion\" through end)](https://greenteapress.com/thinkpython2/html/thinkpython2007.html)\n", + "\n", + "## Objectives\n", + "\n", + "After today's Lecture you will be able to: \n", + "\n", + "- Define recursion and be able to identify\n", + " - the base case\n", + " - the recursive case\n", + " - infinite recursion\n", + "- Explain why the following can be recursively defined\n", + " - lists\n", + " - dictionaries\n", + "- Trace a recursive function\n", + " - involving numeric computation\n", + " - involving nested data structures\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What is Recursion?\n", + "Recursion is defined as the process of defining something in terms of itself.\n", + "\n", + "This is commonly done when writting a function. A recursive function is one that calls itself. This can be very dangerous because you can get infinite recursion:\n", + "\n", + "```python\n", + "def func():\n", + " func()\n", + "```\n", + "\n", + "What happens if you were to call this function?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def func():\n", + " func()\n", + "\n", + "\n", + "func()" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlsAAAEBCAYAAABPOGB9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAGP+SURBVHhe7d0HfBRV4gfw3+6mNwIhEAIJvfdQpB2CNEEBEYycgAU8FfHEAoeHIn+KHBwW8ESsqDQRQQSU0EEMBCEJLQFCDQklEEJIQvpm9//ezGyyGxKSQJb6+34+k92dnZ2dnZns/Pa9N290ZgFEREREZBd67ZaIiIiI7IBhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7EhnFrT7RFQC/rsQEVFZMWwRlaC4fxH+6xARUWkwbBEVofC/RUmPLYoezX8xIqIHGcMWkRXrf4ei7hfcKn+V+1Lhx0RERBYMW0RCccHKEqKKHqfeKn/VG43NAyIiesAxbNEDzXr3tw1S1kPBOEmv1yuDTqezGYiIiIrCsEUPLMuub31beDCZzEqQMhj0YjAoIYuIiKgsGLbogWO9y1tClfUgA5bZbFLClWUgIiK6WQxb9ECx7O7Wt5Zwpd43KaVXjo6OLMUiIqJywbBFDwzrgGU9yLAlQ5ZsduXg4KAMRERE5YVhix4Ilt3cErDkIAOW5VaWYjk7OyvTEBERlSeGLbrvWXZxeauGK3lrUkKWHGSVoRyIiIjsgY1S6L52o6CVl2eCk5MTgxYREdkVwxbdt4oLWjJk5eXlwdnZie2ziIjI7hi26L5UOGipg6XqUAYtZwYtIiK6LRi26L6lBiz11tI+S5ZqyWpDBi0iIrpdGLboviPDlUVB/1lq4JI9wct2WkRERLeLXc5GFMc1XMsCos7mIVoMMRdMOHslD1czAKPRDFcnHXw8dahZWY+m1Q1oVdOAQHHfhe2U6RZZdmd5q4asghIt+djd3U15noiI6HYp17AlQ1Ziqhn7YvOw/YgRCSlmEbrMyMoFcvPMEMc7ccAD9LLzSAPgaNCJ4AVUcNOhcTU9ejV3QJ2qeriJMPagyzUZ8VfCAaw9vQ2pOdfg5eSB/rW74yG/lnDUswqsOJaQZRnUoJWnhC3ZTsvRkeuOiIhur3KpRpQBSgaqg3F5WLIzF4vFsO9MHuKTTEhONyMzxwxjnjqdJENZjhFIzzbjcpoZJy+a8MfRPHy7PQebo4xIFOPkNA8yk9mES5lJOJQUg/BLUcqtfCzHU9GsfzfIu5awJasQZfUhgxYREd0Jtxy2ZCiSYepQfB6+2pqDLdFGXLhqUsKVvPyJLLmq5K6Dn7cONSrpEeCjR/WKelTx0sHLVQdHg5hOzCctS8zjrAk/7c7Fzhij8nqisipcqmVpq8V2WkREdKfcctjKzjXjYLwJc9Zn48RFE7LEYxmeDGLO7s5A29oGPNPJEeP6OWPqEGdMf8oZ7w1yxpheTujf2gGBInw5OahVi1JWDpSwlvegF21RmdiWasmwpbbRkrcGg0EZiIiI7oRbClu5eVAClizRktWBsk2W5O6sQ9s6ekwb4oKxjzqjT0sHNK1hQPVKelTz1qO2rx7t6jgguIMjpge74B/dnZQSL19PHR5pqhfhzAnOjmy3RWVjKdGSuUveFpRq8cwLIiK6c24pbJ1NMmH57lycS1arDSUZmPq2csBLjzijob8B3m46pcG7LL1yEO8mS7xk1aGzOP55uOhQWQlYDkpJ16huThjczkmpXrSUdBGVnSV0maDT6dmnFhER3VE3HbYycsz462QeDp8rCFoyJHVp6ICBbRxRq7IezuIYJ9tt3YgMVfJsxOYBBjzc2AFVK+hLfA2RNRmsLApKt9SSLTaKLw+JWPNaHdSpMw+R2hgiIiq9mw5bl1LNCD8t+85SD3QyNDWopkfflg6o5l32tCRLvpTG8gxadBMKhyw5yJItlmoREdGddtNha+/JPMRdVhtpyYDk4qjDk+0clY5Kie4EkbOsQpfcN3VsGF8ufDHgs1M4dWoMgrQxRERUejfVqWlOHvD+imzsj81TOiuVJVJtahvwai8n+HvfxmpAoxF5F84h90QMjIcPiftnYc7Ohs7NHQ6BteDYrBUcateF3rdq6YrMzLkwZ56GOW0fkLJbuQ9TJmDwFPNsBJ13J+g8molkGSAmLnl+8oTKpGuyH7E8HD5rwoWrZhjFSF9PPVrW1KOenwGeLsBFMT49RwYEiMc6+HrJdkY5+D12O76J/hmJmcnwda2IF5s+hcdqdYOzoVA3BrLTzvNnYTxxDLlHo2FKvCRGmqD38YVj46ZwqN8IhuqBIlrff0HYsvvKW7WrB7UTU6PYN/R6A3uMJyKiO+6mjr4Xr8rOSk1K0JJko/eWgXolKNyWoGXMRV7CeWT88iOuzfsIGQvmI3vLeuTuj0Bu9EHkRuxBVsgaXPvqU1z7Yi6yNofAlJqihJIimXKAzFiY4j6F6dibMJ2cDFPCMpiTt8N8NQzmK1tguvAdTCf+jbzj/4L5whIgN0kc4Y3aDGzJkCU7c90clYvPNubgiy05WHfAiN0njdh7Kg+boozKGZxfy37JxP2lYbmYJ6b7bGO20s/Y1YxSdlwqAoUpKRGZq37Ctc8/Rvp388VnXYecvbvEsFtZJ+nff4Vr8+cg87dfYEpJLn4d3OPU0izLrTrIjkxvm33zUKfOaKw5GY1FY3vjoTp18PDIjxAmVrkiLxFhP0zGyEcfEtPVQZ3uQ/DO/zbgRIb2vLVC0z706EhM/iESqdrTUuT/imtDFYl5cv7/s3rmRstWeLke6o1h/5qHDSez1dcqimuzlY347d/gnWHqPOvUeRhD5GuPWS+pkLAGo8Xz88RvmMQwMf3gh9X3kuvgqzAk3p+7JBFRvpsLWylmpT8sC4NehwbVDCV212ASGUJezkdexqe0g5xednhqYRYBwxgfh8yVPyLj5yXIidyjlG7JMGXOygJycsRtJkxXk5F35jRydv+J9B++Qtb6tTAli4BUOGwopVnHYIqfK8LWJyJYbRXB65QapvLEkdAk5pmXLuabCHP6EZgv/468U1NF+PpBjLt4XeCSB/zEVJPSE77sST/suBHxSWYlfGWI41emWG+pmWacvWJWnlv4Zw4OnMlTutA4cdGM8yLIymlKJAPnpQRkrFyGjJ8WifWwVyndMqdcFZ8nQxnkOpHj5HMZS79H1rrV6jow3V9HNxmstHtWYUvsl7e9CvEsFv7rVaz3fRGzlszHiw93QtOKYnSGCEDPPo5hU7bD+bF3sWDJEsx/vh7iF49G7xEiwFgHLjlt8ENW0y7Auz2A9VOGoL8YVyjGlEFRy5aIDf8Sy/X5CVT5+1QsEcu14L2B8Nr7EUb3Go3lZ7SXFilbBL5hIrR9jfiawXh3wRIsmf8i6p1biNEyHG6J16YrELX4DTw+MQIBz08R7zUfUzo6Y9vMYXj8/27lcxER3f1uKmzJRvFGrVRLkqVZsod4WZ14I7L68fsdOfhma+kHOf1fJwrCgfnqFWSu/lkpuTInX1ESnM7JGTpPL+gr+ShVZ/qKlaBz9wAcHGEW4ct08QIyly5A9o6tIjBd0+akMudcgjl+PkznvxcLeEmMEO+ldwEcxVHSyQ9w9he3VcW8KojxTuL9RGLKioP59H9gurRShJ4UbU4qeQmiLdF5WCa7xBCBSvY9JteL7HusorsOPh7qrZt4LM/ivCJynKxqlKVhZSGDlAyQWb8uF8FSroe8gvXgU1ldD94VoXN1U9aRLAGToSx7d6hYB+JN70MyYKmDGrj0t73aNBqRdSdi/nvB6NaxD0Y81xFecuyyGfgorArGLN+I+f8cIJ7riD7PzcSSlXPQZ58INvPCRHRRRS+ejI/2NbWathsGjF+AFTO6If6Hj7D8sDZhmRWxbGfD8OuqRPR5ZyZmPtcHHcVydes/BvO/n4luNVOxa+8J7bXXyw77DKM/iUTQm/OxYMaLGNCtIzr2GYGZC5dgSrdILJr4DbZbSvU0G0KBdxfNx5j+3cR7iWWYMR9Th4gfJ0u2IZJpi4juYzd1NJLVh9bhQJZnuTqWXIUoX7dbBKcdMcZSD6ExeTgQp1WriQNopggY2Tu3w5ydpY4Tb+rYvBU8XnkD3p8uQKXvfoL3h5/DbegIOATUlBMorzOJgCGrHXP2h6uvU4iD8rnvRGharZZiKWPEKvHuAn392XBo9yccOhyEIWgj9DXHAW4NxBTyQ5pgNqbCdOZ/MCVvV15nEXHKhM2HjEjRztKU6lTRY3gXR8wc6oL5I13xQbALBrZxEAH1JsOA+DyymjBrvQicOeIwLR7DYIBDs5bweG08Ks5fhEoLlsPrg0/g0ncA9CKAyWlk0JQlgrmHD2ozun+opVvqoNyVW/IOtFHr07GJErAKRGL7l5FAv3/g2bbO2jhNjT549iURNuaLsKGkrWhs/za6yGkDuj2BPjWdEXW4+ABUkuuXTXU25qRtVV7NYCzYtgJzhtTTRhSWirB185CIF/H2S0GwWVJDPQSPfFF8qEX4NSxRG6kZ9DT61NDuK7zQRIQu4BJSi6pOJSK6T9zU0chBbxus5LEt2ygPeOrjG5ElPWUZckWqy8qVD/KQd+YUcsL+hDlN/AwWb6ZzcoLLI33g/o/X4Ny5Gwy+vtC5usNQPQAu/QbB/cUxcGjYRH1jMb0pKUkJKbKUR1b/mdMPw5y0DjDKn+Bi4fUu0PsNFceLGdD7DgScq4sP6ynmWRf66qPE+A+ACm3V+cnpcxOApI3iw59XPrsMWL/vz0FCirxUjFqiFVRLPXHg0RYOypmaFd10Sg/6g9s54rm/3dzZm6bEi8iN/EtthyaJjSE/v8dL/4Rzh85qiZabm3JygEvvx+DUpZs6nVwHlxKQsydMqWa916kBqyhq4NKVlP7tIMC3inZPk3AWUTJzeKXgRFgYwmyGSMQbZaCJRrzYlZBwUp22YQ34ihsbfgMw/4YBqGTXLVuNjnhikC+ivxqJh+rL9lYzsHxDJE6UuGvEI1rs9ujTDDUK5UfJuV4zyAi15qRtVWLTKl62wUxwUXrmOItLV5SHRET3pZsKW14iMDgaCg5k8sAm+90q6eLRsr1yYGUd6oiwUdwgw4evly7/xDn5LjLcmfOMSuN3U9JlpWG4ztFRBKPqcH1ShKOAWtB5eIg30HpRdRDPVfCGY9MW4vmnlfvQiRnm5sB4/CjyzomDgAxbsvF79gVxP1etInStDX3Aa9C5N1SrDXXySCDmJ59zrAxdhY7Q13gNcKqszs+UrZy5aM48qQTDYwkmpZ2ZDJ7ys8pOXoe0d1RKtuR9Gb7k55J9ismqxNYiiMl+yeTjssQCY/wZGE+dUNaDLNGS4dJ1wGCxHmoqZ2Kac3OVz5izaweyfl8t1tsB7ZXio2ZnI/fEMe2MxfuL3A8tg/irjLvdKsgLglq7EI8N8nbZZAwbNuy64Z0FsqQqDIm3IWxct2wi0vX5aBPWzn0bwa2ByBXf4J3RQ9C7TR08/No3iCw2dGUDMhSK/dlFHVEqNQqHvXzRELslEdF9S4s0ZVNFhCF5uR0L2fD9REKeclHqG3ESAW1MT2eMfdSp2GF0TyelJ3nLiWQO4jXysj6yZEuGLdnwW+HiCqe2D8EQWBs65yJ+Xgs6D084NmwCh9r11PQjmJKvwBhzRByLRdhKCRPz1dpwGdyhq9RLBK3GYq24quMKc/CGzqutmG9z8UBroCbbfKVGwCjWwdHzeUjXDhpO4unG/no0C9ArlysqiryUkQxcVSvolOxWWnL5TSlXlfs6EbbkZ9RXriLWTSaMp0+IkPUH0n/4Ete+mYesDWuRF3taCWV6rwrK+nKoESg+v1jg+5K6D6qB6y7gG6CU8jR9by1OnZJ9VRU9jBFhp1yI1GLbirAkXmjafwxmrvwDp6L+wNoFc/B2/3rIWjcDQ95ejuubuUvi/00WvYkfV1plPhER3cBNhS3/ijqlpMYSiGTfUQfi8nAt+8ZHOAcRQBoqAcRQ7FC3ql4p5ZE90kvykj9VRbiTiU6eWSdLpyTZ8NuhURMlRNyILOkx1G+ghBLJnJUh5iNLtkTYyDiplE4pZF9aIkiJCdXHxdA5eImw1UreUR6bZVjLPAmTOLrHXTYrJwFILiJgyc8jS+WKIwvhPJx1yqWNrAoKSyTPvpTBSiFSmr6aP/ISLyJr7S+4NmcW0v47BdnbNiknBijXB3Rzg75KNTj36gfP1/8Fj9FvwKGBCJX3Hdv9T/a5dcf5+kL2yhYdeVIpDLKVjbCZD6H3sBlqY3K/GmgmQ0zM2SKmjcRHsluGTwoa00PEqutKhBLiEa3dLUnilhkY9ugQfGNpdO8WgKbdBmDM3CV4t594vD2xiOWQxHS9xc2GCJwsomF79okopTRvQF35yYmI6KbClpODDq0C1aoxSZbqyO4LlE47S6hKLEl6lhnHE0Sw0o6TslSrpq9YTHEclY3czdoBVOfgAJ27p5pYbkAnEp6hQiUllCjEAprTZemYmGFemrjVFljnqFYdlrRKZMhyEkdEy/xk1w9G2YZMLLvIgZbju7zotlw/JTUbkgFUfsayNC8yya4dtC4szCJ8Zm/ZgLRpE5Hx00LkHjssFkntjkIp2WvZBu6jxsD7w3lwf+5lODZroZ6p+QCQl+y545yD8OibTYF1X2NhWKFkcngRPvoqESeqt0GQ7CICQeg2Sk67EMv32aao7ND1WJ54AgFNmirtnnx9O4q/YYgWvxcKZCNyzXIxtnR869WD87FIrN4QaRXgpBSkyEVt4nxdGyuVFzr2GwNfLMJnPxR6bd4JLF/wjbgTjL4dr2t5RkT0QCohWRRN5oL29RxQvZKaEGSVTVoWsCbCiHPJN1+akJULxF8xK1WSlrAlS9Gqi0G+qVJdqIUcGTaU0p0S6ovMYkamjPSC6WRxnLPaA7tZqS60Ck0m2SVCCQdo2TWEDFeW6XQGdT5i+ZS2V+oqgewZIyvXXNLclLM6ZRuvstA5OonVoC23LPFLvKj1M5aptGVzCKgF14FD4PXvqfAc8zacH+kNg28VpYRLtmcrU7K7p9h+LtNd0Z+YM4JGTcHbraMxb1h/jP7fGmwPC8OGH97BsBdmINJ3AOa83if/LMGmw+W0kfjolZF454cNCAvbjjX/G43ez4oAM2gOxvRRpwzo9jT6IBozXhiJj9ZuR9j2Nfhm4kiM3l4DA7ook5Ss5kC89mYQosX8R05chA2y0b6Yz7zXRmFyqC9GvBkMEf2K5NzxNcwXr438RL72G6zZLl67YRHeeXYYJm8PQPBnY9BHCZBERHRTYUvy99YpZ9rJXuMlGRqizuYpnXnKjkjLSpaOxSaa8Nu+XFwTP5VlNpJtnRr4GVDRXSymCFmGqn5KmFCIYCHPTswvSiqGDCDGWDmdeuDVObuI+fgr89PJy+7otEvfyI5L0w+rYeoGzGI6eRZj/nR6NzGfQOhFgJFt2Sx9jeWIAHX6krx8zI3XRWaOGQlX5XTaiFJQgpP4HPlE8JT9ajm1eQiug4bC/ZWxcBv6HBxbtVUazStdP+hvXD16/1D3R5kn5WV77gpuQRiz/C8smdwN2b9/gJHDhmH055Fw7j0FK9bPwQDr7hAs044KQPyP72PYsJH44PdsdJu8Aps+GqBUSSr8REjbNB9vdziL5WNHYtiEz7DL62ksWfQuHimqf4ciiSD4zwXYOHcgvGK+wWjZaH/kR9jmFoz56zdhSo8bzUi+dgk2zn8WAWeW44OR4rXvL0J89WfFa9diZj9WIRIRWdzUtREtjl0wYd7mbBw5V1DtJxt7y24O+rZ0hLe7TqlOu1FBinx3WbJzKdWEZWG5+DPGqPS0LtWtole6TWhV06D0q5X568/IXLFU6QVdduBpqF0XXpP+A0NlX8BBbUNlTb4m90iU0obJdDlRCWaGwFrwGP0mnIJawXR2Hkxxc9We4PUuSsN3ffOlIsjIMGZ1BoBFXibMqX/BdHiUmPd5JXDp3BspfXLlVuiDP44asWB7jnJmpqwe9BPr4oOnXFDVW58fwqzJkq/9Z0yYsTobGdq1EWWD+n/2dkZAZWOx10bErp1I/+Yz9axKSXx2t+ARcH64h3INRJ1LoXPE5GV9MkRITEuD3tsbOlfX+yJ8WXZdeVv4uohGY55YLeLHgKenMg0REdGdctMlW5LsL2p4ZydU8tDnN2iXl/L5Za8RX2/LwZnLJiVIySAmC3jksdEyyMdyfLbRrJzFJ68huP2IGrTkrGSVXL/WDkqDeUlncFA6L9V5yS4ZdEpnnnmxp5C17letB3UxM+3gq9yKg26evKzPmpUwXRJhSj4vXifPTJQXqYbeATrvLiJT+ci5i+ezYE6Phun8twU9yedXAopbefZixjExzy9hzpIN7OXzYtk8milnMMpQ2bS6Ht5qjaLSdk2Grl/Cjbgie4iXi6fMS9zKxROPZUne6ohcpdd5y6KXhuw/S4ZGS4qVbbRklapswyb7HsunrGgRQlKuKusp5T+TkL1rh9L2rUxveJcqvh8ttQ2cDF1ERER3muH/BO1+mcmAJfvc8vXUKaVblo5NZdA4n2zGrmN5OHdFHS+r1XLFeHlNRXm5n7NivCzV+XlPLlbsMSqP5fOSDFq9mqulY7I/KuWYKv7IzjrzzpxUzsaT10CUVYOyvynZXknvIYKGu7tydqJZPM7ZH4mMZd8jd1+4UrIj6Xx8lR7VnZq3FtOJsCUbul+LFkHltBK2lAB17ZBY0CSRaLyhc/BUQpk59zLMyX/AFPtfsfDbxHS5yvzgVA16/xegq9gZOr1BuQTP1Uyzci1EeX1DGSjPXDYrYUs2gpeX7JFdWaRmmXFAfHZ5SZ+D8QXt06QqFXR4qK4DKriZcPxqLCITDyPDmAV3R1cEVWmKBt614ODuAVNaqtqFRXaWEu7yzsUpnb0aKlVWLtkjz76U3WQYj8cga80KZP4mQmfiJRgPRopQmQaHmrXvu4byct+TpVzyDExZfStLuZxE+LwTPckTERFZ3FI1oiSDQka2GWEn8vDzX/J6gGq4kmQYkwHE0wXwdNXBxVGndHEg22fJtkrygsyyuwgZTORSyFAlz+Dr3MCApx5yhF8FvRK8rBlPHlf6kMoN/0u9VI0g+4/S+1ZVrgkIRye1PdelBKUDVLNsHC9mrHNxhcuAwXAdMASGqtWU10nmtIMwnZ4Cc9ImNXBJjj7QOdcAnMV0emfxIdNhzooTweaCuC/PYBQLanCHvvrL0AW8IuYtLwukOp9swpKdOdhxNA8Z4nNJsl2b7Ki1sgil8kxOWX0oSwDlNRHlurNWmmpEZ4OTUoWYsWwhsreEKJ2YSsp68PNXr4vo7KJ2c3E5Uek1Pr9fLjd3OPfsC4/nxbLLUsJ7nBqu1MFSjahWJarVia6uLnCTJwYQERHdIbdUsiXJQCUDRPWKelQV4UieUSjbH8nAJUt2ZInWNZFhZLCQAUP2sC6r166km5UOQC2lWS6O8sxDPbo2csDANo6oUanodk6yp3h9RR+YrlxWL1cjgoZsmyXbcckAkhcfq/ZDpT2nk73JV6wIly7d4fpEMAxV/MRCF5R06BwrQCcvNJ2ToJZomWSRVIZ4fFEkwhPiw8SI21Pqc2bxnOxN3qkKdL6DoA8YrTSOt+6bS4bLSh46pfTuqsh58vPJdZEsPu+5ZDPikkxKqZ8MmpKrmJ2zCKGW9VCqki29QWl3ZfAPEOshCWbx2c1GsR4yM5VLEcnqU2PcKeSdjVMDp7yOpE6vNJR3bNUGro8PgqFadZv1cC+T1Ylq4JKPLOFLXjJJLd1ylW3UiIiI7pBbDluSLJGSwUgGpIZ+BqUUS4YrOV6epSdvrcnHso2To4MMGzpl+rq+BgR3cETvZg5KaCuuL1DZdkv2lu5Qr6EIVFeVKjEZGpT2O9qg9MHl7Ay9u4cIV1Xh0rs/XJ8eDoN43XUN6XVyWn/oPFtBZ5Sh5aoYJxZO6WJCm6devEbvIl4rgplLDeirPQdDzTfF60RgKdSQXi63bMNWT6wHWWInQ5dcNqvFU9aVPNOyivicshQvUwRUOZ0MC/IEAxm2vETYOnk1DvsuH0GWMVuELTe08W2G+t411bAle4T38IRD46ZK6Z0SLgU5fxk4FHK9yG4iXN1gEIHT6aEucB82EoY6dZUQev9RP7elpMsSthzEZzWU0PktERGRvdxyNWJRZIlWWqYZkbF5iIo34cQlk9K9gbxQszHPrJTkyDMVq3mLUFJVh6DaDmha3YDrLt1WEmMucg9HIWfvLuQeOwrTxQSlalEve42vHgCHZi3h1K4DHGrV1V5QAlMOzCm7Yb6yUYSXSJgz48S4TBFMvEQ6qgeddyfoKvWGzqO43odsWS7hs/t4nrg1qdePFCunsqcezWro0bWhQelp/uOQbMSI5+X0LWsa8FovJ9TwycPm+DAsPbYWV7KuopKLN55p0B89AzrCyWAblGRHr8aoA8jZI9bD4YPIO39OqUqFiwsMfv5waNQMzh26wFGsj6LO2rzXWYKVbKcl+9bKy5PVieoZifJWhq0KFUrdHwIREVG5skvYkmTgktdKlFVossG8HOQlbeSbycIXg1693I8s5ZHhS7bNKq40q1hyfjkiIMlqslxxK99EjNPJGcnSLSeR3pxdkN83V4nE0sl2W3kZ4jZbzEo2PhPzk2cdyhIsg4tYSNltQulSofysuWIWso2WrE6V7dvkOKVfVfF5ZRu2+CQTpq/OVtq6yec71jfg1Z5OIojqkG7MRIYYjCJAyNIsNwdXuIuhqLPw5AWmlfUgwqbSg7zcrGI6Wcon27HJNmvKmYpFvPZeZwlbauCSQcvSdqsgcFWsWFHsEvdf0CQioruf3cLWg0oGq8tp6iWHZLs0eUalq8hpRWUcGcQOxOdhyi9Z+ScJ9GvpgBcfcUIF1/svFNmLZRe2hK2C/rYKApejCNws3SIiojtBNkyiciJLpiJO5+H7HbnK8PPuXOWxPOOycKSVJX+X0kwI1Tpxlc/LkwRkiZZsz0WlZ13Sp7aPUwe9Xt7qldvs7GxlICIiut0YtsqJzFIybG06ZETYcbXfMFmytfDPHESfVdurybM0ZQmW7MRU9r21LToPO2O00xAFXy+1YX1RZ2FSWVgClxq01Fs9rl27pj1PRER0+7AasZxFns7DN9tzEHNBJC9BNh/zdAXa1Dagsb9BOftSnqkppzuekKeciWjZAn/v5Ign2zmikjtLtsqqqKrEwtWJ8r6zszO8vFidSEREtw/DVjmTpVZ/HMlTrvN4LlkNXJYG8fJEABm+ZAmY7NRV9q0lqxNlSVbrWga89IgTAirplesqUtnJXdky2J6ZWBC25ODu7iEGdnRKRES3B8OWHcgqwr2n8hCyPxcnE03KJYpkqCpM9jXm7aZDi5oGDAxyVK4DKTs5pZtj2ZUtYUt2bKoGLHlbELbkY9lY3qXwBbuJiIjsgGHLTuRleE6LoLXhkBGnLpqQJntlMKoN5WVJl+xfq6IIWrJ68W+NDEqfY3I83Rq5O1sPlqpE2xIu9X7Fit5KtSIREZE9MWzZmTiuK5fpURrMXzMpnbq6OslLG+kQ6KMvuNA2lQvL7mwdttTAZQlbBYMc7+1dgSVcRERkVwxbdN+xDlwyUMlbGbbUNlyWQQ1f8nlPT9mGy115DRERUXljxRXdd2z73VKvmym7gJDdP+j1BmUwGPTKIMelpV3D1avqtSWJiIjKG0u26L5kXbplGQqqFNWSLcvZivJWjpchTJZysVqRiIjKE8MW3bcsu3ZB2JK3avutwkFLva8OMmx5eLgrl/ghIiK6VQxbdF8rLnAVBKzrw5Yc5LQydMn+uJzkBbyJiIhuEsMW3fcsu7i8lYN14LIM14cteatO7+DgAFdXFyV8yftERERlwbBFDwTLbi5vLYMaqqzbchUVtizTyNebYTAYlOpFOcjgJQe14T3PNSEioqIxbNEDw7Kry1vrQQapgoBlGQrCmHUplwxc8ka9X3BbtBs9R0REDwqGLXqgFA5J8ta2BKugRMv2tmAa+VL19er9ApZ5KjdEREQKhi164Fjv8mp4sh1sw1fBfdvBMh/1fgH+OxERkS2GLXpgWXZ969vCQ0Gplu1QELIst1L+HRsFzxMR0YOIYYseaNa7vxqklHvafctw/ThlTP6t8le5L2mjiYiIFAxbRIL1v4F1mFLv2gasgnHqrfJXvdHYPCAiogccwxaRFet/h6LuF9wqf5X7UuHHREREFgxbREUo/G9R0mOLokfzX4yI6EHGsEVUguKDFf91iIioZAxbRGXAfxciIiorhi0iIiIiO+IF3YiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsSGcWtPtEVI6MJ4/htEsuPLx9Uc29ijaWLOLizyIjI1N7dGNubq4IDKihPaLboSzbx4LbiahoDFtE5ch8LQ3X5n+CrA2/KY+/HdYeK90S4OnojpeaBWNog8eU8bcuBzsXJCP4MPDy0xXxfjsnbbxFBlb9Nw2vVXPFuRFe4nEqPh2XiUN9PPF1Lzd1kjsodGcYvvluofaodF584Vl06dxRe1SyI1+Mxqxw7YGF3hH+Tfvi5ef7omYFbVy5S8CW96ZgUY2X8P0rrbVx95ZvFvyA0F27tUdlI7eR3FYlSgjB9PfWoOar8zEiSBtH5U7+r11OuqI9Kp3KlX3QpVMH7dGNWf7P6j05Ge/189PGWon8Cs9/fgEjpk9GjyKeflAwbBGVk9wDEUiZ/C8lcDl3ehiGeg0Q2bEBjmRfxG+x23AhPRFtqjTF7C7/UsLXLclOwaxJWdjpCkRUcsaRsd6QkarA3R22Pv3sC0TuP4B3xr+JuLizWPrTz9ozQEBADQwb+pT2SDVz9icIatUSr7/2ijamZMpB4GRrjHyqNby1cUiJwcpfduKMcztMmDUSjZ218eXq3g5bskTr/SkfoFHD+nhiwOPa2NL5dc1vOBpzHFMnv1tyCRfDlt1NEtsxXmzPmyG3n9yOJcn/UaOvg1dmjUeHiur4fAxbCrbZIioHMmDJoAXx28X7o/nwmjob7s/+A3+r/7BSorXm8flKqVbEpWhM/Wue9qqbl/pXDj6FAyY/7YBm8TnYckl74h6RkZmh3DZq2ACBgbYHZXc3V2W89SBZXlMmzgFo3L4dWliGXsMxZXxP+F/bi5VbLmsTkbWMDHU9y6BVeDuUNFjCmWUedOccjTmmBK3ePR9RftSUZZCvkaFbzqNUGrVGV5dT+HbhTvEzj4rCsEVUDq59/rESuCqIkOXYso021tbbrV/Aw9XbYfu5Pcpw8zIRus+EZm2c0KaJM56vYMYve9K156hEdeqgsbw1GZWHdGOytOrV19/Cp/O+0MbQvSSodUslCKt0yhAYEHDdOMsgx8vXlMnVAPR4uhlwaCWW7SlbO78HBcMWUTnI2vi7UnVYXNCymPzQa8rtH2dvIWydz8SP8cCTrT3FAw90bq3D1r+yEKU+SyU5dQpH4Iqa/j7aCMGUijObvsKsN17H8y+OxvMvvY6Js5bh4KVcbQIrl/Zi5axJePUlMZ2Y9h9vzMCCTTHIMGnPFyPxtxn4h5h++m8JyuOM45uxYPpbyrjnX3wdY6d/hR1HU5Xn7iYbNm1VGspH7jtQ+pKOmyGrm16cgvUH5PqdoK4XuR3mbsZ5uRlSYrBlrmW9y+2zEiesi1EyTmHHFzMwdrS2XcZMwKzv9iKx0Ca0Xe+j8eo787Dl+ClseU88/mKfNpWQexkHv5uB8WMs85uEjxfvRYr1djaJaRbPxsRC0xR+z7uBrIqfOftjZYiLF18ghcZZhpvl1nkERtXPxI6lP+JItjayOOJ/aNn0Cfn/Q6++Mxsr91hKmuOx/h2xLq23hZTyBz6W22z6ZqRooxSmfVgk5jNxhfhMd/H2YNgiukXyrENJttEqiWyrVd+7Fo5djdXGlF1cuBFbKzmir/Z2ge0d0S/TiJ1H89QRVCA7Hkf27MVBbdj921eY/NEeVHviNQwOclSnMSVgy7QJmPxzFHIb9cUrL43EKwNaofIl8eX+3lQsO1TwSz1DBIKxExdg/WUv9HhqJN56aTAG1M5F2E9z8O+P/0BiMYFLBq2JvyaojYgf9wOS/8AXs1ciLCMQA54W83m2L1pmRWHBh/+HZYe1F90lGueXgMh2PAHaPXtJwMp5C7A7rzVGiO0wsqsf0g+txOSPv8IXk+dgfXpTDH1RjO8WgNyTmzHrf3+oB97cKCybOBsLDuSicY/BYrsMx9CgyrgctgATZ4QgUZm3uv3+LUJaWHI1PCrXu9h+PbzisGzWZ1hpnXMzxAH8HXGgDktBtY5yfiMxoqMXLuxYgHHTxPy07Xxi8Qx8vP0CKgQNUPYbyzQTxb5gEwjuUk8MeOy64eZ5ocNzA1AvYy+++ClGG3e9jMgFGP/eAmxJrpz/P9TD6zLWfzVJ+yESgBatvZAbuRdHrP6fcqOicFAkFsfYfThivXKjoxFmqoyuDwXc1duDYYvoFuk9L6Pi+zq49izdKe9Nc9+B+/l/a4/KyJSGkL1m9GvngkBtFKq4YJA4Bn6x6xpK+kF5N/PxqaTdK0fJ+7DgqwX4WBu++HUfzmRn4sLJeKRrX+Tnf5mHRecCMHTSR3jvlb7o0L4dOjwuDgKzJ2NEdXEQ+HYlTshps/diofy13XYk5s4aj8G9ZDuwnug/djLmvtoaOLoMi7ZdXzKVuM4StCZiguVsrdMxOCgOEINHv4H+cj5d+2Lk1Il46+kR6FFfneRuIU9KkO14Pv/0Y6VrB3tzbDUSUyYORVexHboOF+uslzjwHt+Hgw2sx4/Hm70ri/F71AOvYzMMGPMSpnw0Ga8M6Sm2S2f0GDUeU15sDcf4TdgiA6wpBmsW7kNGwADMmF2w/QZPnIUZT4h5WZWSnVixCFtS/DB08iy8NVzOT33P2f/sDLf4NVi2Q27nBJw5JoJ4y79jwih1v5HTTPnncIx6ujXsdrJrOZJt7AoPt8SvL14W+3jKjsVYe0obZ03ZBnuRWKVvoW0wHRM6u+LEmmXYLbanf7v28DUdxYGj2uuQi4PhUfDvPQA93E5hV3jB/9mJfZHIqNwKLQLu7u3BsEV0i/Re/uK7IBLI2quNubHoM27wuNmzEY/l4JdMHeoZcrFzX4o25MClig6XjuYi/B5MW25ubuJL/jF8NOsD5aBerqUnfgMw+5v5+N4yfPUpZj/bEOmHlmH6YvnrOwY7dlyGW8cBeDRAK+my0Puhx5Pi4HptJ8IOiV/kodux2xSAwU+3g1uhb063oKEYXAs4GLrT6he0UQ1av8TDv9/4gqAlNe2EHh6XsWzGFHyxOAS7D8cjI9cPLXq1hm+hxbgbyHY8tyNoydKRvo+K9as9kvzr1xV/ixhfR+4nGUjXCh7daonpwldiwawpGD9+Br4QIflg5TpogUzkZokJju7FjmuuYpv2hW+h7efbry+65o+LQXi4mGnzbujokYqMFKshsB16VgYiDhwSh3+xvToFwPHAAoyf8RXWborCmUuZcGveGR1q2Z4bfLdSqw5lVWLBcKt8B4zA4MqXsXLBmutLepVtAHTo2QnuadbrNhP+D7WHvwhj+6NygTqt0bViJnaEayVk2Xuw95AXOgb1Rdu2rjgYJde/dApHDonXthWvvcu3B8MW0a1yEUdZhwowX1ikjSjeiYsmXEwxo2oF2Ri1rHKwc5cRUTDj03VZCF5SMIyIMItfjXlYt1ceVe4t8hRzyy9qeVB/plC3D+VK7wjfri/h2ZZAighGR8TBWpZo+PuKI2hRfH3El7iQB3FQl0UfleFb+NR2hReUWYgjQI46QhxYfsT0Xy7DW/ykPrPjD7V0zMK5GUbMnoa3elRGyr4QfPvxDLw6xqp90gPLTYQ67a6N4sZrlGq/CZj8YxRyqrfH4Kd6oUmFJOz6ag0itEmQlSG2dgX4+mqPremrwT+/32F1n4AI5GPfnoBXbYY5WCmbFiWm4qq48e03EXPHDUYbwwVs/mUeJk98C/8YMwUrD9x9be9kVx6WQf7AKSB7f7IebpG+Dvo/2xkVEkLw5Tq1fWI+ZRsAuxdPKrRexfDxHzgvnrucnCT+1kGbtl7IOBSljMuN3I+Iiu3Rpg5Qr20Q3A7tx0H5wzJ+H8KS1SpE6W7eHgxbROVAX+d9mLNiYTo1VRtzvWtZZkxeoYah57oW7oS0FLIzlOoQ2YnpuQ+rFhoqYnkT4PuILNx9X/N3G0cR8EQyUs5GdIOjOO6cTyymG4jEJOXLHgbA3VUeoC4jMVmOKCwVyiwcgfwtK37Bt331A8weL9ux7MT/vtqnHGjyOVZGiyFjMOGjT/H1/I8xY1QrOEavxPTFd++pDpcvywOhiCMZmUpfXLJ7gLtByvYQtdrvvcl4ZbhWhTTkJbz178HqmaeSiwhsSEGipQGXNdMFnM/vPkXdJ3x7jS8oES08TO8LS2Zza9QTQydMxtz58/H1zDcwtHYK1v7vM+wocj+5c94Z/1b+YOkDzXqcZSgXTZ7GKx1lteACbFH+gTTKNvDC4IlFrFNtUNo0CkpVYrIIVfFqFaJ329bqD59GrdDVLQp7w3OReECEMaUKUXmJ4m7dHgxbROVAH/A6dBW7wnR6GkzH3gaM8ndvAVmi9fK3mUhIMaNlTQP8bqJkK/WvXHwpjvo9WhQV1JzQtqUBVeJz8Lv1lxtdz3QKu3eLZFS/IWqiIbp2rYyMsDVYL77UbciG87/sRIZHZ3RsLr7Eu3RDB308Vv6097ozDzMil2FlLNCii/hFr41D2xEYEeSqtmN5IgAZ4YuwMlKt8zq/bgZefeMrHLSkL0dX+Hccgh6BYl5x8Xdl42rZq/z7U9WAtXTZcuVWVkOV9ZI+9pBjktuuArxtSh0zceTH1TioPUIjEcA8MsU2LWjgbpG4LgQ78sc1VKqqEreEKO2HbKTsxYK3p2CZLCm5tg+Lxr+O6b8WlN44Vm6IHn2CRKCIx5k4beRdQnbh8eua30scyocjGv/97+jqEo9la6zOKlS2QSrWrBX/V4X/h8K+wvj3Fhc0fleqEi8jPGIzDh/yQtd2ddTx+mZo29oVEZGbEbE/Ab6ttRB2l28Phi2icmJosRI63wEwxX8K4x++yIvsiXm/n8OweRkFQSvQgANn8vDf38rauCoDW3aLb6faDmheTK/nzs0cMVRvxrpI9rmVr9DZiAd3hGDB+3Ow8koARgx/WHwJi1/QT47BiOrioDDtbUz/QhxglbMWF+Dj8VOw6FxlPDpqMOrJb0rndnhW9ggfvgBjJ8zGyk1ynpuxdu4UjP1cHFAaDcWI7kW3DfHtNxJDA8SB/vtFSsDyDxIHiIx9+FgcuBf8tlOdz8ezsUgEtnrt7r7G1ZbL91hKtCyX8pGPb6W7gPLi27a92EYx+HaStl3kdn5vAmYdlRFMo2+IAc+2Vhq4TxxfsP1WzpiAiZuBmlZBrd6QEejhGYUvxk/Ax99a9omvMPmdBdiRVw0t64vt7CEO+o0ccOK3KRg/Yxl2aPvNrG9lQG8nntNmdpdQw5QMXDceyo1bOwyVfW9ZhyplG7SDd/RijBXbYJmy7+/Eli/E/9C3+5BTo6nVZbTUqsQT69Zgh0tzNNayliSrEh0PrRE/cKxC2F2+PRi2iMqLg7cSuAwtVkBX7VkgNxknEg1KK4jezR2wZIwbPh7uotzfcNBYtsB1Pgu/XAKeb+mCYpt6OruiSwOofW4V+tX4wCp0NuLHC0NwwKU93po+Hj2qa9PIhvCTZmHKU83geDQEX8izFtfsx+UqD4vp3sfQ5gUNw92CXsLcGSPxaOVUbPlZznMl1px2RMen38B/3nr4uobXBcR7vDwA9bL24X9fiy9/v754T8ynfy0jwtcsVuYTcs4VPUZNK/r6cndQSddJlCVcZb3OZbkT6/Ot8YPR0SMe63+y2s7v/R1ttUkkuf3+M0FMV/GCOt03axDh3g3vTRmJjtY/YtxaY8TMaXira2Vcjlyj7hO/H4Vb+5GYPfslNFaaPDmi8agPMOXp1qh8aZeyn33xexQyag/AFDE/+1wK6uZZ9xB/o6E8qX1vaQ80bkFiHU4X/0NVUrFD2fcXY9lRR2Xfnyt+zCirVuPfvDncxHeZY9t2qKeNUzRtCnmV1FytHZfq7t4evDYi0R0wa202Nh4yok8LB/zr8bvsW/k2kKUh8hp6so1GacgOCmXD3nJrU0LFkh2XyrPS5IG3oJfx0rmV19428ofIdaE4CotemocT/SZjyhN3V9i9WZZt0bvXIwhq1UobWzqR+/dj46atd/d2vMcwbBHdIQ9y4LKErdKGJzl9WS9ETTdHllSpF6IuuNZhaclqKHmQ/3DmdFSubNVD/10hExH/m4AvLvbEjKkDbEohM3bMw9iFJ9Fj7McY2lwbeR+4lQtRywvCTyvFhaipdBi2iO4gGbhOXjQp1YseLjfTHcS9KXRnWJmrnl584Vl06SwrD8jeSqo6vJG7ORQrPch/vg8ZFerg0Ue7oX6FFJwJ24k1hxLg1vYl/KdQNdb9QP6vXU5SzyItrco+PvxfK2cMW0R3mOwS4kEKWhayBCUjw6YzhGLJL/+7r6Tk/laW7WNxL2wneW3EZT+tQ1hsptIxpqNHADo+NhhDezS8rrNaovLCsEVERERkR8zxRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHakMwvafSIqo+rjLmr37h3nPqyq3SMiotuBJVtEREREdsSwRURERGRHusTERFYjEt2kljPztHv3jgPvGLR7RER0O7DNFhEREZEdsRqRiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiI6P6WGY1FHy9FZIr2mO5qxuMhmPnZdlw0aSPuAwxbROUp5wC+fuddvPmvhdido42zEY3v/vUuZm5O1B4TPeCilor/lznYdEl7XO4SselLEbRMvqjuqY2i2+7i5jliOy/FQe3xjTjU8IXP2U2YuzwGRm3cvU5nFrT7RHSLjJELMX75Gbg6Z6FSz3cw7m+Fv91l2FqKi73fwDs9fbVxt5E8sC28hH7j3kCvKtq4YhmR9NdyzF0VjdrDP8ALzbTRhZnScHzrKvz0RwySssVj54qoFdQLwwe2hI/1z7nMOGxfuRYbD59HpvgGdXD3R9v+z2BwUEU4aJMo5Px2rsXqrTE4ly4ndEH1VgPwwpNifjYTFs2YdACrf9qE3XHJMIpfxg4VG6J38CD0qlvEkbZM7yXWR2QIFm8IR2yymFbvAJ8G3fH0U91QvzQH8bRT2L46pOTPL93O5brTitgn5YF55sYqeOG/z6CFOuqmZYYvxMTll9DttXEYGKiNlG5hP4tc+C4WRWkPrLV4Bp8Mb6o9yELsn79ghWX+xf1fPCDKuk2L3W73KMP/Cdp9Iroladjx82rE1HwSI6udxPbDjmjdqRY8tGdVidi/6RDS63ZAlzru2rjb6NIhbDiQjvqdOqDujd5eBKNNCz7DtzsvIEf8HKvasgdaFxnOsnBwycf4elcKKrXvhSe6BqG2ayIO/7ULOy/6oVOLKnCUk5lO4af/fI0tCS5o8kgf9H6oMfyNsfhzy2ZEObRAp9qWhUlD5A9zxPsmwq1xdzzeoy3qeWchbu8OhOy6CP+HmqOqMsOiGeNCMGduCKKNVdCpdx883Nwf+stHsGPrVkTpxPvYrPOyvJcRsb9/idm/H0Felfbo+1gntPLTI/HwLmzachSGZu1R13ZD20o5gK8/WYzQ/M9fG94ZZ7F7+2bssF5Pitu4XHeDIvbJ9FO7EXrSHa17ic+qjrpJ57HuhxDE1hmAMQ/7WVXl3Mp+loioTbtxNqAb/t67PVo2b1owNKqFahWcxTTi/2LxbHzxp2X+LVHTdBb79u3F9mgDWrcX3ws6dW4PirJuU0e/isiOCMX2y5XRs5X1trs3sRqRqLyIA2r4WRd0aNsSjTu0heelcOw+rz13L8mJxqIZX2Jdgj/6DewAH210kdLP4PglI6r3fAXjBnVBUKuW6DboZfx7UB1kHtyO0CRtusO7sTvdE91eeQMv9GwrpmuLXsPfwMi2Lji3PRTHtcnSdi7FosNAi2f/jXeGd0MHOb/HnsU7r/dC9cxofPdjODK1aa8jAt3K70Jxzq8X3nn3ZQz+W0sEPdQNI14T79lCvM/GH7A6TptWKNN7HV+Lr/44j+q938DU1/qjm5i2Q89gjB0nfqW7igP6d+KAXmz7kjSELlmOw2iKFyZZPn8XDBz5Bsb19hfraSkWh2dp097O5XoAHP0LfyWL/8kOLW1KD29pP8MlnL0EVKott6PYx6yHQLUo0Ri5HN8dFPN/xjJ/dX+fOrwpXM9vwqKdacp0dAP6QDzSxV/97rgPVhdLtojKybkty7HhUiMMeKoxfCq4IzV8B/7KrI0eTSpqU0gFJVuNU7fi62+X4qffNmPDtl2ISvJGw4Z+cLP+CSSrOkJX4rvvV+DndWK6LTsQfuwaPOrURTVtQlk8P+mL3TC0LFxaJass52KDrgW61IlV7i88INuKZeD4rq3YsGkrLlQrosTKUAV+AX7oNqAPmrldwK5dp+BRXMmWU2U06dgdnQoVk2WdDsO2Y7mo31FdprTju7AtJgs12nZBE29tIuFy9A5EnK2I1j2bwhfnsX7JZsRW7oUx/etAlg/k86iF5s5HsW1XLJyv+5wq4761+G5fOjo89RwesqmhdUDVZn5I2fkXQq/54dEW8oOU5b2MiFy7FBHX2uLvL7SBr3WJhGMVtPZLxY6w3Uj1L2Ydnd+KhevjUOnRURhU1+adxHZsDJcjoeIXv7NWCnr7lkvdb07Bu34SQuZ/h8Vrxf51UVs/cr/b8hO+XvQLVsr9Tu6fFwzwrx8Ib0uJjykZkb8uxLdLV2HVerE/7diHmBR31K+v7sOl2y/FE9YlW+nbMXPK19hwMkNMJ/9X5H56KH8embGhWLzwByxduREhm3Zgx5ELMFSuhVqVbNerRWzYaoQmNlH/J7VxZdv22nhrSYexZecp+HR6rJjSXiDmj+WIyOiAocGNYbW7i83ih+zI3dhvCtT2w8Jk1eNyfGP5f9fWu2/tQPhYLWjaye1YuGARlv1qtR6q1kctb9v6z7SToVi62LK+tmJL+AmkedZFEz9XbQqhFN8xSlXvh1tgqu6Kgz8vxncrf0fIRjm/c9AFNERd6/c1iv1ixQL8b8lq/LZBTLNHvKdXXQRmHLAp2SrNtnR2zcD+XfuQ7vcw2vjf22VD9/bSE9014hC+Pxk+7R9CfeWxPzq080XmwQM4UkTJQkbED5i5LBpo0gsjnhmEfuKLN1X8Gp7+n+U4aPlJbUrEpk9n4vPfY2Cs2x1PPxOMp0Uo8UzajUWz5+CnowWlISULRHfx+hGdZeMHT7R4TNwXj7sHqM8WVrV+01K1j7KWFncAkfvDsWmZrNY6L1ZBK1iOJ55BHdDCNQ2hX83Bd5vD1ekWz8GC8Cy4tmuLxnKipGM4ngzUatNSLOH1POs3EAfMRBw+XvTP3OPHYgDXZghqpI2wpm+I+nXF7XHxHvJxmd7rJKKPilm3aInGRX1jNqijbPPjMafUx4UkifFJYv13aFXkO6FxIxHGL8VAeavbuFyqaPz0xSYcc6yLoKCWaFJFbHS53332IT7feBKw7HeP1IXxcAjm/ndp/v55fNVnWBR2CS5NeynTDAzyVNr4Tf9qN266IMK7KQbKeTWTnz4QXeQ++0xftJCJJWU3vvoiRLy/P7r0F+MHd0f9nBis/lL8L1iKRm2k4Wy8WJKq1eCnjVHc4n6GK8m4gopwOL8KH06ZjDf/9S7enCT26z/j8kvDco3aneI4FP3PlbbzB8xdG40s/w7KerCs988/XoXj2vfIxW3zMPVLsc1QF70HW62Hz2fju6iC74SLYd/iP1+G4HBOTW199UILz2SELv0QH1pO0CnTd4yYdqEIkcaGeGyomK63+I5Ii8G6L35AqOUsT1kq+MGHWBSZhqot1P3isSbAgWViX7FatlJvyyqBqC1y4ekzVkXS9yiGLaLycDQCf6X44qF2/toI8R0vQkT1zHCE7r/+mzct2RW933gHY5Wqt7boNfRlTH2jF6qnH8CyderB8VzID0pVXq/XJ+VXdShVRO++gX5+ydj9U0j+F3DJPFFLVnMojcRdUKOxWu1Rq4L6bHk4vWM5Fi1dhXWRcUir0AFjX+tW0DbDtSVeeL0vaokv7IMbV6nTHUyEY5NBeHtQHXWai5dwTtx4VSjqECj4+aO6uMnMLCpkJuNsgrjxrAgvdcR1qvv7yherB8SyvFfSBeUU9GKn1fujhgiVmWLeRbl0UdYle8KrmJdX9Zf7jFgu+fLbuFwWrs2ewdRxz2KEOID+o3dDpIX9gnVnHayqwOR+9wzeeVtsP3EwXbZeHvgSEXtaLEOTAXhjqFYNJ6uPnx+EpweIg7U667Jz8kVjMa/G/i7igSfqy322VUNUdRIP408h1lQRvUaMwkCtiviFt17DiP5Pomdt5dWFZCFTFpCJFW+zPLe0nwHGtDSxtZIRuf0MfDr3V8JgN/H+h9d+iWmLo5X9q3ZdsU+nhGPbftt5ZEZtUqrWmzSQyf96p0+LdVtRfK5/iHla1vvrInwO7oba8mgtQsqyDefh2CxYbLNn0Oshy3p4AwNrZeHgyk2IlTOS060W3yMtgvH+W8/mry+1St0TFw9HK+ugrN8xrk2CMel1S3W1WLZXusDHFIeIKDWYHl/3ixKg+snvNqv9YuobfwMSrMJrqbelJyqJzVTSPnwvYNgiKgdHDkYh070ScF6W7mjDaQdUFQe7wwejUThueYov6V42P7cFv27o3Ux8sRw8gOM4hdA9yXAN6ol+/oV+Bet90evRtnBND8fuo9q4u0CL4R/gk/9+gNnvjkI3192Y97lVPzmZMfjpm01IE1/+70zXpntrEGqfWYvv/mA3GHdOQwwIboqCSqU0HDggD/it0KVuLtJEsMgfnJqiTQOxKcWBOha+aNFGtqdZjqmfLcXqP2MQm5QFx0Zt0aHGTUetG2vQBkHuydj02Rx8vWo7dh+XZ3X6IuhvZS+FvRUOQc+KffcZvPR6ofZ3PWVJdgg2imzt+dAA8X8rws/S/2DmYrGsWknu+zKM+ffCgKCiF7hJUEu4Jm/HnA8XYuXmcBw/nwVjFRFYmqlnrKZFHVBCSpuOdZTQl79t0h3QvHVDID0acvOp0/mjd/+W8LQ5yruIEP0OZr/eTQTKsn7HeOKhbmL5tEeKwECrYHoKkQezlPkV9d02pLPVfnGXbMvbiWGL6FblHEBopPiySY/BuqWydMcyrEWk7DuoiAaebq42X1n5qvpZSl8ykSF+zHlVEgGuKJXUEhzZtcHdxqFCHQx8WQSpswUNgY+sXY7dpg54YWhLtZRCcPBri3881xapIV9gpfw5LpKp/OJOTSmm+ibhvPJr3NVVlnoUVhE15Bd8WjJS1RHXOXdehDqx3pU1X5b38qmGquKbsthpTeeVBtOuxWzTKlVlyVUaUot5+cXzsuRLLJd8+W1cLpUD3LTtodJKg5J34/NpM/G+zfAhVsoDb4q6jqt2H4OpL/dFff0l/BWyEHNnTcP4SXOw8nAxy3OrnBpixLvjMKJzJaREbcNPX8/DxPcm4/0FoThXZLWdC1zdxI1Y8TZLdEv7mcrBrykaFwoUVTt2QC0k43hMshpWXhfL2tEfGYc34SfxXfDn6TTxo8sf/YZalfgW4tAkGFMnBKNLJRF6/1iFz+eIdfreTHz953nlB1uGUsKTjNCvC2+bmZi+KkY8l4YrYuOo01VEpaJKrvOP+mX9jnGBW/GrRLjx/GzWZ6m3pfg8YjPdeB++NzBsEd0i48EDOGxqiKe1EhubYXowmujjxC9b2y929cvwehcTLIHAVQQycUC4ckV7ppAr6gHP4Ub/wZcScVG7azfGNMT+JX9Fa48tXMUBTXzRn1PaWiTibJwIo9XV6hkbbp5wEwf44yfE5/ZpgPoVgdiIA7YHR03a8WNIgi+aFNN5VP0G4pd9ZhQiiyrtM8Xg+ElxW1+8h3xcpveqi6aNxKyLaX+HY6eUdmD1G2rVoYX4iPE+uH4fUKXhyFFxcK7SUO0T6zYuV9G0gNJoEGYX3pfzh4J+kjzrdsGIV9/AjBkfYPa/R6FfjTSEfr8Q22/UU/ut7JcOFRH02LMYN2kKPpkxCeOGNoXTsRDM+0UGjcI8USNArKeLFyBrmPPd0n5mROzO5fg6pIh2cM4iuGp3FXqxrLIKTaybT6YEo7YpC7X6P3t9qU8hDj4tMXCkCLLTxDqdMgYjWjjg8NpvlaCr/kgr5rtGG2R/eOp0ybhywx7zy+E7xsaN53ddtWxptuWlOJwWX5W1a977HW0xbBHdEnFw2SW+HBo1QVubEgKNrHoRB8RzoeIXmzZKStu5FptsjgBCwnZsjBJfWS1aikBQB13aV0Rm5GasO1/oZ7ts1Lo+HJnubdFBzFtt85OI2LPW02Xh4MY/7RK2jOJLM//X7onN+GrlcqzYalsVmBkVir/EF3115UuyInwqi5vDB7C7UMa8eDBaLKOL+DKVpw/645GuYvqz27DCujGtJNbNl7LRfaMu6GJ1EpcxXSyLdt+hVRd0cM/C7vWFL/Mhq3OWi/euiG5dLR1OluW9HBDUuS1cM8Pxe6HPqTQI/klsi4pd0L2JNk6wXi74d0G3WmIf2Lq24OQHzcXNC7H6LNCkWwettMO+y1UyT7RsKd7/6Hasji203xnPY92cmZj7h1iG9Ggs+mAyZm4seF+HinXQ6+FmYqnOI17s7OW9X57bNg/jpyxFpGUdyk5Ig/pC9g6Qef6CCEjXq9WooVg/hQN4GfeznCykyU5JFQ5wvBqHw3+EXPf/e3HHXzgs9vX6DUWSsyb/X79ciuO1g/GSdVXadc5j06eTMXHhAaXdl+Tg6o+gvh3Ej5QsxF9Ihmezlqilj8HmkLiC/UthxLmQeXj/M/V7Rp3uPDauFYGy8P/C4mkY/8FaHMkp/XdM6dRBUAsXZX5FfbetsOruorTbMi1Gfj8EonHDe79ukV0/EN2KS2FYtv4UfDs/gU6BRZ1+roev6Rw2hceK3NUJjTzVrh8u6tJwfPdexIjvH6fsS4javhY//LoPl12bYsTzXZUOFb3q1YchehM2bAnF/gQdHEwpOBu1AyuXrsbe5IroMHwYuvqKL6EKDkj86wAOHjiAC3CCOfUUdq1YjjUnMgAz4GHdgarxLMJ3H8Xxizlwd7iI2CsVEehb9GnzivRYESYLun4wHl6O9+csF1/OWkeDlWvD9+Ie7Ni1G/svqst4Imw1FoWcQLpHW/z96ZbwNehRzc+AqN17EPbnIVwwO4hlPI+ozcuxaNdF6Gv0wjP9ApXOX50Dm8H/4i5s2LijYH4RG7FsxR5ccGmKF17pgxpa1wPyrKzJ3/yOyJzG6NpAHMR0FdGskXifzZsQslu8v94RWQlHsfnXFQg5loHqvV/ByNYF5/KX5b3g0xjNdEcRsnETdsVkQOeUhQS5LZZvRkyGP/qNfgZttOPodcsFZwQ288OFnVuxYavl85/CnnW/YNlfF+Hc4hn881H//E5N7bVchRXXyaRzjZowHA3Fli3i/eNFaNRl4MrxvVi+eBUikyuj0+M9ULdSJTid34UdO0Nt3ndZyD6kOLVE/4FN4VuplPtlEZ2aulw9hk1RRxCf5AyP9FPi9bXQsFoGDv4pljl/HxLrcO1qbIjNQvUuA9Azv2NcKz4VcC08DKEpth1jln4dx2Hl9I/xw6YDyFb+f8X/ZUAFJIbLz379tnRvG4x/dKhsVYohws2ST/HzhYYY8VKvgu1WJE94ZBzGdvG/9MeBi9AZTEg5vQ+rVm1FbLY//jawK+r61EBtw1Fs27odWw6cQ2YekJF8QqzXZVh2IAm+Dz2OR+U6dRHTucfirz9Cse2gNp3V/0K1h4dgYH330n/HFNsZsm0nzT61K+PCnl0IDRXfbZdFgDOq3wcLVorvNjm5uYqyv9V3L8W2NMVh/Y/bEVunD0Y+dO93asqwRXQLzm1fgU1nqqBHcCcUmbUEvU8u4rfuQ5SxBno0NSlfTugxCsNqnMf+vRHYvV+En8Rs+LZ+EmNf7oXalvno3FG3fXvUdUnC8chwhEUeQvTpJBiqtceQl0agV6BWlGaojJYtK4sv5mgc2BeF/YdikehZFwNf6A7H3dG2vdV71kdDt3OI2LsPkQdikVmzPToEyiqHYhQKW/qrp/DH/rPIqdwUvZWDlwOqtngIjVwScVRbxphEPfzbDcBro7oh0HJw8aiFTm0qIz3uBPbt24f9B4/i9DVvNHk0GKOHtESl/D6iZJ9YQajrWvCZY86lw7tVoXUjmBMO4c+jyXCp1V4LNYJ4n/atKyPz1BHsDo/A/sOnkKivjUef+wdGtC1U4lCG95I86gShnU8WThwOx197tW1Ru4c4MAeL8dpEQpHLJfu9alMbLldOYe+evYg4cAJnM73RdvDLGNMn0LavJzstV2HF9ugt97t2bdX3F0Fpr3j/gycSCs1T/IhoJrd7Ek4ePqRME30mBW61u+O5Fx8T+5iYpLT7ZREHcn21hqh5TWzDiAPYfzQObk26o1nNwvuQWIe5ldD+yZcxspNPMQdjT9R0PYct2w8ht6EIS/ltmEq7jnNw6WC4CK5+aNM9CIGy2ZHYli07B6FK8mGEhtluy9E9a4g5W0k7ie1/HEOVJ/6B3v4lxwWP2u3RzjcDsTHqOj144jxyKwXh6VeeQRdf9fVymo51nJF4aj8iwsX6OXQC54vYxz0CgtDeeroj8n/BD52e/AdeFOtLUdrvmFKGLWU/7yLWjQjLe8W+s/9AtPJ9UO+RYXiq1lnsPaXtb+4lb8vMiNX4NsKEbk8/iSbleNb0ncJrIxJR6cnL7nwQgkovjynFtRXtLGU35n4ah94TgtG4qCrcO+VuXa4HViI2zZmDdcZueOetXspJBXSXywzH11NW4XSrZzF1aEPbAHuP4m5HRKWWGRmKhC7Bdz5oCbGhEfAb/ORdF2ju1uV6cPmi18vPIEifiHNFtYinu47xbCKSavTC2OD7I2hJLNkiIiIisiOWbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR3pzIJ2n4huRsIaXB4+Hdf9Izn5QNfkETj0ewquD9eCs0Ebby0vDemHYoHazeFeQRtXkoi5SJywBOj/LXzHNtdGEt2PspB6LA7HUQVtGnhr44juPSzZIio3ntBVb1gweOTAvP9n5M4IRupzc5GaqE1mJWPlG8gYNwoZkzcgUxtHRFICVr30Gxq3PYgBbTdj1o4sbTzRvYdhi6jcDIDzD4tQ2TIs34JKKxfB8eGG4rixBNmvz0XaNW1SjaFqbfHXCbqG/nBQRxGRtO8Ipi7T7sMAb29H7T7RvYdhi8iODBUawnvSt3DpXwtIXIKsbw8hV3tOcn74PfhuDkXl0c3BQwmRlcAqGNpV3FY1YNDsFni+RVH18ET3BoYtIrtzgueosTA4ibtrFyPjijqWiG7Apykm/DYE544Pwmcv14WzNproXsSwRXQ7eLSDQxd5ZxuMEWnKKCnz1zeR2LM9Euce0sYUyEsMR/KkUUjsJ56X0wRPwJX1scjRnr+hazuRJF/T801cTdDGWTvynTrPwd/hWp42TjAmHMLVjyfgcn/tPfsH4/KkJUgtYh5pc9VpLv+apI2xIk8aUN5/Lgo+bdEs87kSIdbHniVIejVYfe+eXZD44mxcPZYGuYh5KTG4OuPVgmUbPApJ34cj02r5rWWGiXm92FebVw9cflXMa3+SMq/r5CUh9ftJuBzcw2r6SUgOS4JRm8TCenlzjm3AlXHWyztJvIe6vPkSNuCy3IYv/4z0Ypa1sOxtG1Hda4U6fBCN1MN7MPXpVWgtHr+26pI2lZCVgJ2LN2Pc4+pzcvpuT2/E9zusprFmvISIFdtspu/Y4zdMXXEaqdokUtS8Vfnv32feSW2symbZBoYhThkbhx8HauO8fsOqU5ewc24IBrQSj+tvQ5QyjVDE+7fusArjZkXgeIr1yknAqmGW+a3A1G2F22ulIm5TKN59bhU63nA+YsqQkPz5tP7oiFiXEfj01VXoVl8d17FHCL4U25nInhi2iG4LJzg26azcM8XEKrc3knduDZKfexXGMBHCDLXUBvdOB5H3YTBSP9ypTXUDItw59pJFaTth3H39geTan6vVO306wUOrncmJmI+rI0chd902mF21Rv6uSTCHzUX28GAkbTpfdFApJ6ZPRuDaxPkwpTpr7y1iZezPyH11FFLXi/Xx9xHIDT0NVBLP+fkAKYdgWvwqrk3aBptDcd55pPxfsBg/F6aLlpMWfGA+JuY1biCSf7X9HHnntiFpeF9kL94AMxpC328Y9A3k9BtgnDQQVwtNb2FaPgGpIpDlndaWV55NGrtBvMcopOwviMTZh0Jhlg9PHoSxUJu94hyPLIg+bY6dxvAOcfgyJA+X4IjOLauIsXlI3bYZwc1DEfzqVfy4Qz6nOh6Sincf32EbyoTsY2EY13YHBoxMspk+bm8WvhwZgeGzjiBbHYNDGws+8SNBtbR7Kutla9a7CgLlnYuJ2LlNGaVYN2UHgielI+KUeDDUB/XFTXHvf+lwHn784DS6PbkDEenayJQLCF+r3YcL2jZx0e4LcRGY+vhGdBycgO9X5Wlhr5j5iD3j0K78B6iy7ige7nAasxbn4fhFdVzc3nRM7bMHW1PUx0T2wLBFdJs4VPRX75SYWJKQNnO6coDW9foEHr8uVxvcLw5Bxe+mQYeSw5oMd66dByr3zL9tRYZyzyIWxp3nxW1DOPZuqI66sg1pk74T71kLhonifZYXNPL3mvGCCHqxMM2ajbRz6uT2YL5SGY7fhcJ3sfbev26Bs2zrJpf3Q7E+Wk2D+9oQq3Xxnlgu8fSexciKV2ahSP9xEnJCxTpq9h7cLevuh+Xa9DkwfzYJafnTp+HavEkwJTpBN/pX8bk/h89bY+HzuZj+87FiXcvp5+NaEQdic8Rp6OW6Wqkt78qtats8sbx56/bmt81zfuRfcPvwc7h88y94lKp7DxF2dmh3hYhVWYjQ7qNFRTSvI4LL3h0YPvAqdmqBof4Qb7w/zRuDmqiPpVUfHS0oUYrbg7cfO4cfZfgR6vf1wuuFpo/44CS2yPmlJCEqPzi5o10T67ZStsvWuUl15Tb7cBJWKfekLKwreIDnOwXCOWkfpua/vwHPf94Ay39rjOULvNFGmUrYm4RfdlxV74v5fa/eA7r7oFlV7b74HK/1OI0vtWUIbOeOl6dVwctDDJARVCHmM2WxCOWKc1afBYjam4cKRawrsdcg6ph2l8gOGLaIbhNHD5kMSuHIGuQeEbcVRsNlXGe4Wh3rHAL6wOuVp7RHN+bYcQAclNKW9cixCiOI3QujDE21BsBJK7TI2LwYJln6MngaKjziY3NmpHP70XB9RvbntRO5Kw7ZrXRLN2o8vAO0B5LBE14DnxKBR+oOp3F94GazLsTyPyLvHYLplFaSlBmO7KWySlZM//6A66Z3f0mWLh6C8Q9LYE2Dzn8YDE9Mgks/2zNCHRo8CofG8t4G5J1QRtnQDf9voXXlBM8hw9XljTimlRIJ4nO4t2oLz1qeImaUQqFSojbD/bAovCuOxPfEkd/bo9m5CLz9TJIWwAyYsKE3ti/oiZfH9sRnWxrgeWW8cDAVx5VwfBJfvhCHVVowG7SgC7b/1BsT5PTbG+N1S5ARWzZFFgJZB53+PqhnHRBtls0dXYLUEifr0i5UdcTrC1ogTC6vGN7v5Y24kDh8bwmGk5vig+Et0LlrU3Qe0gKvvOiIzt3Voaq3Or+oyILK5ypdfdTSM1lV+abV5/i0DbZv6Yv3x3bF+wt647Ox6ngpYleiWnJ26hK2HFRGCS74ILxvwbpaHoh+2jPivwW+PtpdIjtg2CK6TbKvXNbu3VjmCe3o0L1tfhWftVKHNkNDOPaUpWkiXITJkixVxp71Sgesut6d4aaMOY+cLTKgiLDRrWGRgcC950A1ROwIt19/YIYimkC7WMb5Q19Ju2tFp53CaUrWDs4xe5Enc1f7R+FSxPSuDVsot+bDp7Uw5A+v10aj0mt94OGqjCg97yLCk2VESur1ndyWkk0pUXc/fPR5FzzSoAq8KniLQUTeb07nB45m01rg9Y5e6gPJ3RFWj+AskmDq2mOYulcbMbw2Zgzx0x4ILr7oMqEK3p+mDg1E4LAOOs06WYKOynbZvLUgZlva9fznPTFhSAMEKsvrrSxD4rmCc3CPf3EEs1YcRFTcVWQbq6DfxwOxfLU6vN5Rhq0EHN9VEOkHBalLkBoSjf9uUu4CvarjX8/Xtmo07476La2qGjWpMVfFTwTN0Gro18Bde1CYKwK1gmcie2DYIrpNTOlag50SijdMKWoo09W49W9/j25aVeLGnVpVYhJy/pTBqjkcOlrmnwST0ga6NnQVlRHX86utflncQoi4HTLjtbqgPROQqjRaLzT8c776fFoaTOo9hTEhHFdnTLBqIC+HvmoJ421m2yaqmtLeKV/WMWz5SLsvRE3al9/4Wx2i8an2HFp4IbDqVYRvK2iz9Hz/ujZhDKiCzi92xctj5dARbSrYBp3r2msdLphX0e213NGj/fWBpllvn4Lqwou5+HTkMfRpthl1Kq3AiLdCEZFkVV5aZHst8Tk2pee38/r7841tQqCUZX2mRwNP8cls22t17uRbUNUopEYnYZ12X2lXdn1WIyo3DFtEt0UOcg+rv7H1DW0PYHbVuDscZbMaS1Viwk4YZYBoPBDO1lV29wvL8dZVO6mguKGKpzahCGhrJyB5+KvIDT0ItBoCw6hpcJ72uRimwaA2SbqNbEuJCocdHLFuG1WC7t6onxWH0G+0x3BEs4YlXPLGJugU0V7LquF8ke21Clc7apxbd8ea443x/nDDdSFp6zcJGNBhG3ZaznIosr3WBezN/xwu6Nyy8Oe4iqg9BaVnzwdVE3+t22sZ0EMrIVPliVBbfBAjKm8MW0S3w7W9MIbKO93h0KbgQF8UfYXKyq35UumqHW+sFpwek+2t1KrErP07lZIp/WPdUVBr5gN9XXl7GuZkZcT1zp1WS4IqeGltqO5OrgFaOOk4FhWUhvHFDJO0z58Zjsz54ojs9BScfwxB5YmjUenvfeDVsa0y6G2LgeyvUCmRbdgBLsUWlO6gf3Vs19pFFTm82xTOSVkoaK7njgZ1tLuKPGSnXEWqNmTLPi5u1F6rUMP5otprFa52tFG1KV7+fBDCUh/HkajW+HqyY0HAuXgVEVrvJ0W21zqXBptmc4VLh08dwY+LtftVZemaCGM27bXc0ayBdlcRi/AQ7e51QYyo/DFsEdldDtK+nau2Jeo/HG5FtCWy5tq8kxpoNuyy6QPLIielpJ6rbLl1fFSZn3njamTskEdLEfjaWwc+fxEAZZXieRi3xxTZAD5922q1+rB98/x2Mnof7UzGa0UsT1EzuR3qtVC/1EJ3IbOYbhbyrJfN0sarbkM4Xlciky033W1VUimRi4tVytgjwk+Kp9aWSxuQjPDDWep962kV6TimnY2oiIvA2203o3GAGNqGI1yErbiYgtIeW+k4/vM5qxKnottrXVcSd3Efpg5cjWBlCNXOjnSBV2Bd9Hu7AYYqjyUXBCi12kW317KVi2NxVsuZfho/zjyHrdrDR0TIfMSnUHutF33R3LqaMC4J4cUGMaLyx7BFZEfGKzG4+n/DkbU2FvAdBpdRpbgsT61H4NDMCUiZj6wPd9p02mmMX4O0T9Zoj0op4FE4ygYzsd8hb4+4bfMInAsFPo8hY6GX7e5XTkLKVtuOPLP3f4dM5Qw/sexPt81ffqdaWmPz31fbXPNR6Xx09n/vTNuuCp3h9IQ44Of8jOz3fr6uy4asiO+Q/MQoXLF0LOtXXQ22R7YhS+s8VSE7Of1sEnJt+/O8OWJe18LCkRZbqLPTIpRUSuTV0BvKCZjSxSy81mMNXpu0A1/O3YGpr65Cx4AIjOgTjlVx2jtV90FbdTMJuRj35G+YKqad9dZqdOtRcGbf85+2RWcRRlKTrC4mtTYO417fLOa9GeN6hKDbWwW9mRXXXqtwSZzIUMjeliumkUMCZn20DzsPnkTUjn34/tWj+e3LqowNRD9ZK1lc/1o2nyMPnz67Uf3ck0IwoHMExmnXUKwyNBAfPC+XrFB7rRY+Nm3VbNprFQ5iRHbAsEVUbtYg+7kRuGwZgnsgOVh2xCmClt8wOH86Fp4e2qQ35APP8ZOgdxVBZtObuPZEsDq/4X2R/MJ0mD3K2ubLE87du2v3xT99z07yGGirUnd4TlP708qbId5HLLflPVPHzVf639JPmAZPq7d27PgUHOVjec3H4L75018ZLD7zRf87VN3oBM/Rc0S49ASiZiNzcA+b7ZE2QXwWj9ow+Gkle36Pan157YTx1R64onzuYCT26YvsdTnQ+aqT4drNF3FlrpuOzEmvIuvVxYX6OyushFIiqU57fLDAxar6LQ+r5l7C1EmX8OVitYPPwEHeqJ9fIlYXg962mv5Ulggol/DpN7lap54GPP9TF3zQV20DVb+dt03bpZ3fXxXzvoof4wxokx92ytBeq0Jj/H1yQQDbOuUkgrvsQ5/HT+JdsbxS4PBArJ7cQi0xLbK9llQXz39i3che+9xztY5Thc5jamP15+21gHqj9lo3DmJE9sCwRVRu0mA+F1MwZPpA10oEkmm/wvuHsfCyHLhLwVC9D7wXL4LjI83FD/lYdX45LWAYtxxe49Se6MvCpeOj2j97n0JViAWc2oyG94Jv4divO3SZ2mdI8YSu41g4L14On17+tk1lDLXgPWc5nOT0hiTtM1eGrt80uH4twqI22W1n8If3jF/hNnEs9LWcCraH7B1++OfwWPweKuQ3fBfhbOxiuI4bBl0lsV6uiOkS09TPvGARXB9Tq0rzDp++6ZpRp3pt1c5Xm9ex6cfrOucSsPVGpUQKAwKH9MGGLYGYYN3YvI4B/V6sgs+2dEXYD13QrELBa6sM6os/Nvjh+UEF0we2c8Hz02pjw+nHRdAq6ArCuWtHpaPRRywdfor5/v3d2tge3gg9tVKwgvZaeYjaU1J7LRc0e/tx7PvN9v2riM8ml/fr0J4IkwFJWzFF96+lcm7XFYt311Y+d31LCFM+tx8W7e+N5f9pkz+fG7fXulEQI7IPnVnQ7hPR/erKBiQFT4LpkU/gPbFzyVWZRERUbliyRfQAyNqzFSY4wdC1HYMWEdFtxrBFdJ/LS9yJjK+3ARWegmObUvY+T0RE5YbViET3qcz105G+eCfMCUnikRP0E0Lg06vo9lpERGQ/LNkiul+Z0tSgVaEzDDNWw5tBi4jojmDJFhEREZEdsWSLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyG6A/wfwoM2GteajqAAAAABJRU5ErkJggg==" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Define recursion and be able to identify \n", + "- the base case\n", + "- the recursive case\n", + "- infinite recursion" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# In math, you can define the factorial of a number in terms of the number before it. \n", + "# Q: What is the value of 84! (84 factorial)\n", + "# A: \n", + "\n", + "# What are we still missing?\n", + "# A: " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A recursive algorithm must have 2 parts:\n", + "- the base case....which stops the recursion\n", + "- the recursive case...which defines the same process in a smaller way\n", + "\n", + "#### If there is no base case what happens in the above example? \n", + "- recursion never ends......infinite recursion\n", + "- infinite recursion can also happen if the recursive case does not move towards the base" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Writing Definitions Recursively" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Define the sequence 1, 3, 5, 7, 9, 11... recursively\n", + "# Base Case: \n", + "# Recursive Case: " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Define whether a positive number is odd recursively\n", + "# Base Case: \n", + "# Recursive Case: " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Writing Recursive Code" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def factorial(n):\n", + " pass\n", + "\n", + "print(factorial(0))\n", + "# print(factorial(3))\n", + "# print(factorial(6))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Write and try `is_odd` in [PythonTutor](https://pythontutor.com/render.html#code=def%20is_odd%28n%29%3A%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%20True%0A%20%20%20%20elif%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20False%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20if%20n%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20is_odd%28n%20%2B%202%29%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20is_odd%28n%20-%202%29%0Aprint%28is_odd%28-3%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def is_odd(n):\n", + " pass\n", + " \n", + "is_odd(7)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Can we write them iteratively instead?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def factorial_itr(n):\n", + " pass\n", + "\n", + "print(factorial_itr(0))\n", + "# print(factorial_itr(3))\n", + "# print(factorial_itr(6))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Other Recursive Problems" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Go back and complete Warmup 2.C" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# The Collatz Conjecture problem \n", + "# Conjecture: Any positive integer n, put through the below equation\n", + "# will always converge to 1.\n", + "#\n", + "# https://en.wikipedia.org/wiki/Collatz_conjecture\n", + "# https://www.youtube.com/watch?v=5mFpVDpKX70\n", + "# >$1 million award for solving. And likely an honorary doctorate.\n", + "# Run this in Python Tutor on your own\n", + "\n", + "def collatz(n):\n", + " print(n)\n", + " if n == 1:\n", + " return 1 # base case\n", + " elif n % 2 == 0:\n", + " return collatz(n//2)\n", + " else:\n", + " return collatz (3*n+1)\n", + "\n", + "collatz(13) # try other numbers\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Trace a recursive function involving nested data structures" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "fav_stuff = [ \"road bike\",\n", + " [\"PB&J\", \"brownies\", \"spaghetti\", \"apples\"] , \n", + " (\"Brooks Ghost 13\", \"hoodie\", \"gloves\"), \n", + " \"macbook air\", \n", + " [ \"Johndee.com\", \"https://www.weather.gov/mkx/\"],\n", + " [\"A\", \"K\", (\"S\", \"D\", \"K\")]\n", + " ]\n", + " \n", + "print (\"road bike\" in fav_stuff)\n", + "print (\"brownies\" in fav_stuff) # Why is this False? " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write a recursive function to search *ANY* list of lists/tuples for a given word\n", + "# Modify your code from Warmup 2.C\n", + "def search_list_recursive(target, some_list):\n", + " pass\n", + "\n", + "print(search_list_recursive(\"apples\", fav_stuff))\n", + "# print(search_list_recursive(\"D\", fav_stuff))\n", + "# print(search_list_recursive(\"road bike\", fav_stuff))\n", + "# print(search_list_recursive(\"pizza\", fav_stuff))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Write a function that prints nested lists with indenting\n", + "# \n", + "def print_with_indenting(directory, indent_level):\n", + " for thing in directory:\n", + " if type(thing) == list or type(thing) == tuple:\n", + " print(\"\\t\" * indent_level + str(type(thing)))\n", + " print_with_indenting(thing, indent_level + 1)\n", + " else:\n", + " print(\"\\t\" * indent_level + str(thing))\n", + " \n", + "print_with_indenting(fav_stuff, 0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dictionaries can have a recursive structure\n", + "As can...\n", + "- lists\n", + "- dictionaries\n", + "- JSON objects" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ancestry = {\n", + " \"name\": \"Evan\",\n", + " \"age\": 28,\n", + " \"born\": \"Sheboygan\",\n", + " \"parent\": {\n", + " \"name\": \"Dean\",\n", + " \"age\": 53,\n", + " \"born\": \"Milwaukee\",\n", + " \"parent\": {\n", + " \"name\": \"Mike\",\n", + " \"age\": 74,\n", + " \"born\": \"Racine\",\n", + " \"parent\": {\n", + " \"name\": \"Bill\",\n", + " \"age\": 96,\n", + " \"born\": \"La Crosse\"\n", + " }\n", + " }\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# let's try to search through a deep dictionary. \n", + "def find_place_of_birth(target_name, ancestry_history):\n", + " if ancestry_history['name'] == target_name: # base case\n", + " return ancestry_history['born']\n", + " else:\n", + " if 'parent' in ancestry_history:\n", + " return ???\n", + " return \"Unknown!\"\n", + "\n", + "find_place_of_birth(\"Evan\", ancestry)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Extra practice...can you predict the outcome?\n", + "# run this on your own in Python Tutor\n", + "\n", + "def mystery(a, b): \n", + " # precondition: a > 0 and b > 0\n", + " if a < 0 or b < 0:\n", + " return None\n", + " if b == 1: \n", + " return a;\n", + " return a * mystery( a, b - 1 )\n", + "\n", + "# make a function call here\n", + "mystery(7, 5)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/f24/Louis_Lecture_Notes/22_Recursion/Lec_22_Recursion_Solution.ipynb b/f24/Louis_Lecture_Notes/22_Recursion/Lec_22_Recursion_Solution.ipynb new file mode 100644 index 0000000..700297a --- /dev/null +++ b/f24/Louis_Lecture_Notes/22_Recursion/Lec_22_Recursion_Solution.ipynb @@ -0,0 +1,772 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Warmup" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Warmup 0: What is the difference between these two pieces of code?" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'name': 'apples', 'size': 6},\n", + " {'name': 'bananas', 'size': 7},\n", + " {'name': 'coconuts', 'size': 8},\n", + " {'name': 'dragonfruit', 'size': 11}]" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "groceries = [\"apples\", \"bananas\", \"coconuts\", \"dragonfruit\"]\n", + "groceries_dicts = []\n", + "for grocery in groceries:\n", + " grocery_dict = {}\n", + " grocery_dict['name'] = grocery\n", + " grocery_dict['size'] = len(grocery)\n", + " groceries_dicts.append(grocery_dict)\n", + "groceries_dicts" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[{'name': 'dragonfruit', 'size': 11},\n", + " {'name': 'dragonfruit', 'size': 11},\n", + " {'name': 'dragonfruit', 'size': 11},\n", + " {'name': 'dragonfruit', 'size': 11}]" + ] + }, + "execution_count": 2, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "groceries = [\"apples\", \"bananas\", \"coconuts\", \"dragonfruit\"]\n", + "groceries_dicts = []\n", + "grocery_dict = {}\n", + "for grocery in groceries:\n", + " grocery_dict['name'] = grocery\n", + " grocery_dict['size'] = len(grocery)\n", + " groceries_dicts.append(grocery_dict)\n", + "groceries_dicts" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n" + ] + } + ], + "source": [ + "# Warmup 1a: Use 'in' to determine if something is in my_list\n", + "my_list = [\"meet\", \"me\", \"after\", 84]\n", + "print(\"me\" in my_list)\n", + "print(84 in my_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n" + ] + } + ], + "source": [ + "# Warmup 1b: What about this list? \n", + "my_list = [11, \"meet\", [\"me\", \"them\", \"us\"], [84,19, 22], \"school\", 2.54]\n", + "print(\"meet\" in my_list)\n", + "print(84 in my_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "# Warmup 2a: Write a function to find a thing in a list that may have lists in it\n", + "my_list = [11, \"meet\", [\"me\", \"them\", \"us\"], [84,19, 22], \"school\", 2.54]\n", + "def search_list_depth2(target, some_list):\n", + " ''' returns True if thing in some_list, False otherwise'''\n", + " for list_item in some_list:\n", + " if target == list_item:\n", + " return True\n", + " elif type(list_item) == list and target in list_item:\n", + " return True\n", + " return False # after all possible searching....not found\n", + " \n", + "print(search_list_depth2(\"school\", my_list)) # in list\n", + "print(search_list_depth2(22, my_list)) # in nested list\n", + "print(search_list_depth2(\"house\", my_list)) # not anywhere\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "# Warmup 2b: Will our function work on this list? Guess:\n", + "list_3_deep = [22, [33, 44, [55, 66], 77 ], 88]\n", + "\n", + "# let's try it with our previous function\n", + "print(search_list_depth2(22, list_3_deep)) # in list\n", + "print(search_list_depth2(99, list_3_deep)) # not in list\n", + "\n", + "# Write other tests to be sure that it works\n", + "print(search_list_depth2(33, list_3_deep)) # in nested list\n", + "print(search_list_depth2(55, list_3_deep)) # in nested nested list" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Warmup 2c: What about ANY depth list? \n", + "# That is the goal of today's lecture\n", + "\n", + "list_3_deep = [22, [33, 44, [55, 66], 77 ], 88]\n", + "\n", + "def search_list_depth_any(target, some_list):\n", + " ''' returns True if thing in some_list, False otherwise'''\n", + " for list_item in some_list:\n", + " if target == list_item:\n", + " return True\n", + " elif type(list_item) == list:\n", + " is_in_next = search_list_depth_any(target, list_item)\n", + " if is_in_next:\n", + " return True\n", + " return False # after all possible searching....not found\n", + "\n", + "search_list_depth_any(55, list_3_deep)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Recursion\n", + "\n", + "## Readings\n", + "\n", + "- [Downey Ch 5 (\"Recursion\" through \"Infinite Recursion\")](https://greenteapress.com/thinkpython2/html/thinkpython2006.html), [Ch 6 (\"More Recursion\" through end)](https://greenteapress.com/thinkpython2/html/thinkpython2007.html)\n", + "\n", + "## Objectives\n", + "\n", + "After today's Lecture you will be able to: \n", + "\n", + "- Define recursion and be able to identify\n", + " - the base case\n", + " - the recursive case\n", + " - infinite recursion\n", + "- Explain why the following can be recursively defined\n", + " - lists\n", + " - dictionaries\n", + "- Trace a recursive function\n", + " - involving numeric computation\n", + " - involving nested data structures\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## What is Recursion?\n", + "Recursion is defined as the process of defining something in terms of itself.\n", + "\n", + "This is commonly done when writting a function. A recursive function is one that calls itself. This can be very dangerous because you can get infinite recursion:\n", + "\n", + "```python\n", + "def func():\n", + " func()\n", + "```\n", + "\n", + "What happens if you were to call this function?" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def func():\n", + " func()\n", + "\n", + "\n", + "func()" + ] + }, + { + "attachments": { + "image.png": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAlsAAAEBCAYAAABPOGB9AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAAEnQAABJ0Ad5mH3gAAGP+SURBVHhe7d0HfBRV4gfw3+6mNwIhEAIJvfdQpB2CNEEBEYycgAU8FfHEAoeHIn+KHBwW8ESsqDQRQQSU0EEMBCEJLQFCDQklEEJIQvpm9//ezGyyGxKSQJb6+34+k92dnZ2dnZns/Pa9N290ZgFEREREZBd67ZaIiIiI7IBhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7Ihhi4iIiMiOGLaIiIiI7EhnFrT7RFQC/rsQEVFZMWwRlaC4fxH+6xARUWkwbBEVofC/RUmPLYoezX8xIqIHGcMWkRXrf4ei7hfcKn+V+1Lhx0RERBYMW0RCccHKEqKKHqfeKn/VG43NAyIiesAxbNEDzXr3tw1S1kPBOEmv1yuDTqezGYiIiIrCsEUPLMuub31beDCZzEqQMhj0YjAoIYuIiKgsGLbogWO9y1tClfUgA5bZbFLClWUgIiK6WQxb9ECx7O7Wt5Zwpd43KaVXjo6OLMUiIqJywbBFDwzrgGU9yLAlQ5ZsduXg4KAMRERE5YVhix4Ilt3cErDkIAOW5VaWYjk7OyvTEBERlSeGLbrvWXZxeauGK3lrUkKWHGSVoRyIiIjsgY1S6L52o6CVl2eCk5MTgxYREdkVwxbdt4oLWjJk5eXlwdnZie2ziIjI7hi26L5UOGipg6XqUAYtZwYtIiK6LRi26L6lBiz11tI+S5ZqyWpDBi0iIrpdGLboviPDlUVB/1lq4JI9wct2WkRERLeLXc5GFMc1XMsCos7mIVoMMRdMOHslD1czAKPRDFcnHXw8dahZWY+m1Q1oVdOAQHHfhe2U6RZZdmd5q4asghIt+djd3U15noiI6HYp17AlQ1Ziqhn7YvOw/YgRCSlmEbrMyMoFcvPMEMc7ccAD9LLzSAPgaNCJ4AVUcNOhcTU9ejV3QJ2qeriJMPagyzUZ8VfCAaw9vQ2pOdfg5eSB/rW74yG/lnDUswqsOJaQZRnUoJWnhC3ZTsvRkeuOiIhur3KpRpQBSgaqg3F5WLIzF4vFsO9MHuKTTEhONyMzxwxjnjqdJENZjhFIzzbjcpoZJy+a8MfRPHy7PQebo4xIFOPkNA8yk9mES5lJOJQUg/BLUcqtfCzHU9GsfzfIu5awJasQZfUhgxYREd0Jtxy2ZCiSYepQfB6+2pqDLdFGXLhqUsKVvPyJLLmq5K6Dn7cONSrpEeCjR/WKelTx0sHLVQdHg5hOzCctS8zjrAk/7c7Fzhij8nqisipcqmVpq8V2WkREdKfcctjKzjXjYLwJc9Zn48RFE7LEYxmeDGLO7s5A29oGPNPJEeP6OWPqEGdMf8oZ7w1yxpheTujf2gGBInw5OahVi1JWDpSwlvegF21RmdiWasmwpbbRkrcGg0EZiIiI7oRbClu5eVAClizRktWBsk2W5O6sQ9s6ekwb4oKxjzqjT0sHNK1hQPVKelTz1qO2rx7t6jgguIMjpge74B/dnZQSL19PHR5pqhfhzAnOjmy3RWVjKdGSuUveFpRq8cwLIiK6c24pbJ1NMmH57lycS1arDSUZmPq2csBLjzijob8B3m46pcG7LL1yEO8mS7xk1aGzOP55uOhQWQlYDkpJ16huThjczkmpXrSUdBGVnSV0maDT6dmnFhER3VE3HbYycsz462QeDp8rCFoyJHVp6ICBbRxRq7IezuIYJ9tt3YgMVfJsxOYBBjzc2AFVK+hLfA2RNRmsLApKt9SSLTaKLw+JWPNaHdSpMw+R2hgiIiq9mw5bl1LNCD8t+85SD3QyNDWopkfflg6o5l32tCRLvpTG8gxadBMKhyw5yJItlmoREdGddtNha+/JPMRdVhtpyYDk4qjDk+0clY5Kie4EkbOsQpfcN3VsGF8ufDHgs1M4dWoMgrQxRERUejfVqWlOHvD+imzsj81TOiuVJVJtahvwai8n+HvfxmpAoxF5F84h90QMjIcPiftnYc7Ohs7NHQ6BteDYrBUcateF3rdq6YrMzLkwZ56GOW0fkLJbuQ9TJmDwFPNsBJ13J+g8molkGSAmLnl+8oTKpGuyH7E8HD5rwoWrZhjFSF9PPVrW1KOenwGeLsBFMT49RwYEiMc6+HrJdkY5+D12O76J/hmJmcnwda2IF5s+hcdqdYOzoVA3BrLTzvNnYTxxDLlHo2FKvCRGmqD38YVj46ZwqN8IhuqBIlrff0HYsvvKW7WrB7UTU6PYN/R6A3uMJyKiO+6mjr4Xr8rOSk1K0JJko/eWgXolKNyWoGXMRV7CeWT88iOuzfsIGQvmI3vLeuTuj0Bu9EHkRuxBVsgaXPvqU1z7Yi6yNofAlJqihJIimXKAzFiY4j6F6dibMJ2cDFPCMpiTt8N8NQzmK1tguvAdTCf+jbzj/4L5whIgN0kc4Y3aDGzJkCU7c90clYvPNubgiy05WHfAiN0njdh7Kg+boozKGZxfy37JxP2lYbmYJ6b7bGO20s/Y1YxSdlwqAoUpKRGZq37Ctc8/Rvp388VnXYecvbvEsFtZJ+nff4Vr8+cg87dfYEpJLn4d3OPU0izLrTrIjkxvm33zUKfOaKw5GY1FY3vjoTp18PDIjxAmVrkiLxFhP0zGyEcfEtPVQZ3uQ/DO/zbgRIb2vLVC0z706EhM/iESqdrTUuT/imtDFYl5cv7/s3rmRstWeLke6o1h/5qHDSez1dcqimuzlY347d/gnWHqPOvUeRhD5GuPWS+pkLAGo8Xz88RvmMQwMf3gh9X3kuvgqzAk3p+7JBFRvpsLWylmpT8sC4NehwbVDCV212ASGUJezkdexqe0g5xednhqYRYBwxgfh8yVPyLj5yXIidyjlG7JMGXOygJycsRtJkxXk5F35jRydv+J9B++Qtb6tTAli4BUOGwopVnHYIqfK8LWJyJYbRXB65QapvLEkdAk5pmXLuabCHP6EZgv/468U1NF+PpBjLt4XeCSB/zEVJPSE77sST/suBHxSWYlfGWI41emWG+pmWacvWJWnlv4Zw4OnMlTutA4cdGM8yLIymlKJAPnpQRkrFyGjJ8WifWwVyndMqdcFZ8nQxnkOpHj5HMZS79H1rrV6jow3V9HNxmstHtWYUvsl7e9CvEsFv7rVaz3fRGzlszHiw93QtOKYnSGCEDPPo5hU7bD+bF3sWDJEsx/vh7iF49G7xEiwFgHLjlt8ENW0y7Auz2A9VOGoL8YVyjGlEFRy5aIDf8Sy/X5CVT5+1QsEcu14L2B8Nr7EUb3Go3lZ7SXFilbBL5hIrR9jfiawXh3wRIsmf8i6p1biNEyHG6J16YrELX4DTw+MQIBz08R7zUfUzo6Y9vMYXj8/27lcxER3f1uKmzJRvFGrVRLkqVZsod4WZ14I7L68fsdOfhma+kHOf1fJwrCgfnqFWSu/lkpuTInX1ESnM7JGTpPL+gr+ShVZ/qKlaBz9wAcHGEW4ct08QIyly5A9o6tIjBd0+akMudcgjl+PkznvxcLeEmMEO+ldwEcxVHSyQ9w9he3VcW8KojxTuL9RGLKioP59H9gurRShJ4UbU4qeQmiLdF5WCa7xBCBSvY9JteL7HusorsOPh7qrZt4LM/ivCJynKxqlKVhZSGDlAyQWb8uF8FSroe8gvXgU1ldD94VoXN1U9aRLAGToSx7d6hYB+JN70MyYKmDGrj0t73aNBqRdSdi/nvB6NaxD0Y81xFecuyyGfgorArGLN+I+f8cIJ7riD7PzcSSlXPQZ58INvPCRHRRRS+ejI/2NbWathsGjF+AFTO6If6Hj7D8sDZhmRWxbGfD8OuqRPR5ZyZmPtcHHcVydes/BvO/n4luNVOxa+8J7bXXyw77DKM/iUTQm/OxYMaLGNCtIzr2GYGZC5dgSrdILJr4DbZbSvU0G0KBdxfNx5j+3cR7iWWYMR9Th4gfJ0u2IZJpi4juYzd1NJLVh9bhQJZnuTqWXIUoX7dbBKcdMcZSD6ExeTgQp1WriQNopggY2Tu3w5ydpY4Tb+rYvBU8XnkD3p8uQKXvfoL3h5/DbegIOATUlBMorzOJgCGrHXP2h6uvU4iD8rnvRGharZZiKWPEKvHuAn392XBo9yccOhyEIWgj9DXHAW4NxBTyQ5pgNqbCdOZ/MCVvV15nEXHKhM2HjEjRztKU6lTRY3gXR8wc6oL5I13xQbALBrZxEAH1JsOA+DyymjBrvQicOeIwLR7DYIBDs5bweG08Ks5fhEoLlsPrg0/g0ncA9CKAyWlk0JQlgrmHD2ozun+opVvqoNyVW/IOtFHr07GJErAKRGL7l5FAv3/g2bbO2jhNjT549iURNuaLsKGkrWhs/za6yGkDuj2BPjWdEXW4+ABUkuuXTXU25qRtVV7NYCzYtgJzhtTTRhSWirB185CIF/H2S0GwWVJDPQSPfFF8qEX4NSxRG6kZ9DT61NDuK7zQRIQu4BJSi6pOJSK6T9zU0chBbxus5LEt2ygPeOrjG5ElPWUZckWqy8qVD/KQd+YUcsL+hDlN/AwWb6ZzcoLLI33g/o/X4Ny5Gwy+vtC5usNQPQAu/QbB/cUxcGjYRH1jMb0pKUkJKbKUR1b/mdMPw5y0DjDKn+Bi4fUu0PsNFceLGdD7DgScq4sP6ynmWRf66qPE+A+ACm3V+cnpcxOApI3iw59XPrsMWL/vz0FCirxUjFqiFVRLPXHg0RYOypmaFd10Sg/6g9s54rm/3dzZm6bEi8iN/EtthyaJjSE/v8dL/4Rzh85qiZabm3JygEvvx+DUpZs6nVwHlxKQsydMqWa916kBqyhq4NKVlP7tIMC3inZPk3AWUTJzeKXgRFgYwmyGSMQbZaCJRrzYlZBwUp22YQ34ihsbfgMw/4YBqGTXLVuNjnhikC+ivxqJh+rL9lYzsHxDJE6UuGvEI1rs9ujTDDUK5UfJuV4zyAi15qRtVWLTKl62wUxwUXrmOItLV5SHRET3pZsKW14iMDgaCg5k8sAm+90q6eLRsr1yYGUd6oiwUdwgw4evly7/xDn5LjLcmfOMSuN3U9JlpWG4ztFRBKPqcH1ShKOAWtB5eIg30HpRdRDPVfCGY9MW4vmnlfvQiRnm5sB4/CjyzomDgAxbsvF79gVxP1etInStDX3Aa9C5N1SrDXXySCDmJ59zrAxdhY7Q13gNcKqszs+UrZy5aM48qQTDYwkmpZ2ZDJ7ys8pOXoe0d1RKtuR9Gb7k55J9ismqxNYiiMl+yeTjssQCY/wZGE+dUNaDLNGS4dJ1wGCxHmoqZ2Kac3OVz5izaweyfl8t1tsB7ZXio2ZnI/fEMe2MxfuL3A8tg/irjLvdKsgLglq7EI8N8nbZZAwbNuy64Z0FsqQqDIm3IWxct2wi0vX5aBPWzn0bwa2ByBXf4J3RQ9C7TR08/No3iCw2dGUDMhSK/dlFHVEqNQqHvXzRELslEdF9S4s0ZVNFhCF5uR0L2fD9REKeclHqG3ESAW1MT2eMfdSp2GF0TyelJ3nLiWQO4jXysj6yZEuGLdnwW+HiCqe2D8EQWBs65yJ+Xgs6D084NmwCh9r11PQjmJKvwBhzRByLRdhKCRPz1dpwGdyhq9RLBK3GYq24quMKc/CGzqutmG9z8UBroCbbfKVGwCjWwdHzeUjXDhpO4unG/no0C9ArlysqiryUkQxcVSvolOxWWnL5TSlXlfs6EbbkZ9RXriLWTSaMp0+IkPUH0n/4Ete+mYesDWuRF3taCWV6rwrK+nKoESg+v1jg+5K6D6qB6y7gG6CU8jR9by1OnZJ9VRU9jBFhp1yI1GLbirAkXmjafwxmrvwDp6L+wNoFc/B2/3rIWjcDQ95ejuubuUvi/00WvYkfV1plPhER3cBNhS3/ijqlpMYSiGTfUQfi8nAt+8ZHOAcRQBoqAcRQ7FC3ql4p5ZE90kvykj9VRbiTiU6eWSdLpyTZ8NuhURMlRNyILOkx1G+ghBLJnJUh5iNLtkTYyDiplE4pZF9aIkiJCdXHxdA5eImw1UreUR6bZVjLPAmTOLrHXTYrJwFILiJgyc8jS+WKIwvhPJx1yqWNrAoKSyTPvpTBSiFSmr6aP/ISLyJr7S+4NmcW0v47BdnbNiknBijXB3Rzg75KNTj36gfP1/8Fj9FvwKGBCJX3Hdv9T/a5dcf5+kL2yhYdeVIpDLKVjbCZD6H3sBlqY3K/GmgmQ0zM2SKmjcRHsluGTwoa00PEqutKhBLiEa3dLUnilhkY9ugQfGNpdO8WgKbdBmDM3CV4t594vD2xiOWQxHS9xc2GCJwsomF79okopTRvQF35yYmI6KbClpODDq0C1aoxSZbqyO4LlE47S6hKLEl6lhnHE0Sw0o6TslSrpq9YTHEclY3czdoBVOfgAJ27p5pYbkAnEp6hQiUllCjEAprTZemYmGFemrjVFljnqFYdlrRKZMhyEkdEy/xk1w9G2YZMLLvIgZbju7zotlw/JTUbkgFUfsayNC8yya4dtC4szCJ8Zm/ZgLRpE5Hx00LkHjssFkntjkIp2WvZBu6jxsD7w3lwf+5lODZroZ6p+QCQl+y545yD8OibTYF1X2NhWKFkcngRPvoqESeqt0GQ7CICQeg2Sk67EMv32aao7ND1WJ54AgFNmirtnnx9O4q/YYgWvxcKZCNyzXIxtnR869WD87FIrN4QaRXgpBSkyEVt4nxdGyuVFzr2GwNfLMJnPxR6bd4JLF/wjbgTjL4dr2t5RkT0QCohWRRN5oL29RxQvZKaEGSVTVoWsCbCiHPJN1+akJULxF8xK1WSlrAlS9Gqi0G+qVJdqIUcGTaU0p0S6ovMYkamjPSC6WRxnLPaA7tZqS60Ck0m2SVCCQdo2TWEDFeW6XQGdT5i+ZS2V+oqgewZIyvXXNLclLM6ZRuvstA5OonVoC23LPFLvKj1M5aptGVzCKgF14FD4PXvqfAc8zacH+kNg28VpYRLtmcrU7K7p9h+LtNd0Z+YM4JGTcHbraMxb1h/jP7fGmwPC8OGH97BsBdmINJ3AOa83if/LMGmw+W0kfjolZF454cNCAvbjjX/G43ez4oAM2gOxvRRpwzo9jT6IBozXhiJj9ZuR9j2Nfhm4kiM3l4DA7ook5Ss5kC89mYQosX8R05chA2y0b6Yz7zXRmFyqC9GvBkMEf2K5NzxNcwXr438RL72G6zZLl67YRHeeXYYJm8PQPBnY9BHCZBERHRTYUvy99YpZ9rJXuMlGRqizuYpnXnKjkjLSpaOxSaa8Nu+XFwTP5VlNpJtnRr4GVDRXSymCFmGqn5KmFCIYCHPTswvSiqGDCDGWDmdeuDVObuI+fgr89PJy+7otEvfyI5L0w+rYeoGzGI6eRZj/nR6NzGfQOhFgJFt2Sx9jeWIAHX6krx8zI3XRWaOGQlX5XTaiFJQgpP4HPlE8JT9ajm1eQiug4bC/ZWxcBv6HBxbtVUazStdP+hvXD16/1D3R5kn5WV77gpuQRiz/C8smdwN2b9/gJHDhmH055Fw7j0FK9bPwQDr7hAs044KQPyP72PYsJH44PdsdJu8Aps+GqBUSSr8REjbNB9vdziL5WNHYtiEz7DL62ksWfQuHimqf4ciiSD4zwXYOHcgvGK+wWjZaH/kR9jmFoz56zdhSo8bzUi+dgk2zn8WAWeW44OR4rXvL0J89WfFa9diZj9WIRIRWdzUtREtjl0wYd7mbBw5V1DtJxt7y24O+rZ0hLe7TqlOu1FBinx3WbJzKdWEZWG5+DPGqPS0LtWtole6TWhV06D0q5X568/IXLFU6QVdduBpqF0XXpP+A0NlX8BBbUNlTb4m90iU0obJdDlRCWaGwFrwGP0mnIJawXR2Hkxxc9We4PUuSsN3ffOlIsjIMGZ1BoBFXibMqX/BdHiUmPd5JXDp3BspfXLlVuiDP44asWB7jnJmpqwe9BPr4oOnXFDVW58fwqzJkq/9Z0yYsTobGdq1EWWD+n/2dkZAZWOx10bErp1I/+Yz9axKSXx2t+ARcH64h3INRJ1LoXPE5GV9MkRITEuD3tsbOlfX+yJ8WXZdeVv4uohGY55YLeLHgKenMg0REdGdctMlW5LsL2p4ZydU8tDnN2iXl/L5Za8RX2/LwZnLJiVIySAmC3jksdEyyMdyfLbRrJzFJ68huP2IGrTkrGSVXL/WDkqDeUlncFA6L9V5yS4ZdEpnnnmxp5C17letB3UxM+3gq9yKg26evKzPmpUwXRJhSj4vXifPTJQXqYbeATrvLiJT+ci5i+ezYE6Phun8twU9yedXAopbefZixjExzy9hzpIN7OXzYtk8milnMMpQ2bS6Ht5qjaLSdk2Grl/Cjbgie4iXi6fMS9zKxROPZUne6ohcpdd5y6KXhuw/S4ZGS4qVbbRklapswyb7HsunrGgRQlKuKusp5T+TkL1rh9L2rUxveJcqvh8ttQ2cDF1ERER3muH/BO1+mcmAJfvc8vXUKaVblo5NZdA4n2zGrmN5OHdFHS+r1XLFeHlNRXm5n7NivCzV+XlPLlbsMSqP5fOSDFq9mqulY7I/KuWYKv7IzjrzzpxUzsaT10CUVYOyvynZXknvIYKGu7tydqJZPM7ZH4mMZd8jd1+4UrIj6Xx8lR7VnZq3FtOJsCUbul+LFkHltBK2lAB17ZBY0CSRaLyhc/BUQpk59zLMyX/AFPtfsfDbxHS5yvzgVA16/xegq9gZOr1BuQTP1Uyzci1EeX1DGSjPXDYrYUs2gpeX7JFdWaRmmXFAfHZ5SZ+D8QXt06QqFXR4qK4DKriZcPxqLCITDyPDmAV3R1cEVWmKBt614ODuAVNaqtqFRXaWEu7yzsUpnb0aKlVWLtkjz76U3WQYj8cga80KZP4mQmfiJRgPRopQmQaHmrXvu4byct+TpVzyDExZfStLuZxE+LwTPckTERFZ3FI1oiSDQka2GWEn8vDzX/J6gGq4kmQYkwHE0wXwdNXBxVGndHEg22fJtkrygsyyuwgZTORSyFAlz+Dr3MCApx5yhF8FvRK8rBlPHlf6kMoN/0u9VI0g+4/S+1ZVrgkIRye1PdelBKUDVLNsHC9mrHNxhcuAwXAdMASGqtWU10nmtIMwnZ4Cc9ImNXBJjj7QOdcAnMV0emfxIdNhzooTweaCuC/PYBQLanCHvvrL0AW8IuYtLwukOp9swpKdOdhxNA8Z4nNJsl2b7Ki1sgil8kxOWX0oSwDlNRHlurNWmmpEZ4OTUoWYsWwhsreEKJ2YSsp68PNXr4vo7KJ2c3E5Uek1Pr9fLjd3OPfsC4/nxbLLUsJ7nBqu1MFSjahWJarVia6uLnCTJwYQERHdIbdUsiXJQCUDRPWKelQV4UieUSjbH8nAJUt2ZInWNZFhZLCQAUP2sC6r166km5UOQC2lWS6O8sxDPbo2csDANo6oUanodk6yp3h9RR+YrlxWL1cjgoZsmyXbcckAkhcfq/ZDpT2nk73JV6wIly7d4fpEMAxV/MRCF5R06BwrQCcvNJ2ToJZomWSRVIZ4fFEkwhPiw8SI21Pqc2bxnOxN3qkKdL6DoA8YrTSOt+6bS4bLSh46pfTuqsh58vPJdZEsPu+5ZDPikkxKqZ8MmpKrmJ2zCKGW9VCqki29QWl3ZfAPEOshCWbx2c1GsR4yM5VLEcnqU2PcKeSdjVMDp7yOpE6vNJR3bNUGro8PgqFadZv1cC+T1Ylq4JKPLOFLXjJJLd1ylW3UiIiI7pBbDluSLJGSwUgGpIZ+BqUUS4YrOV6epSdvrcnHso2To4MMGzpl+rq+BgR3cETvZg5KaCuuL1DZdkv2lu5Qr6EIVFeVKjEZGpT2O9qg9MHl7Ay9u4cIV1Xh0rs/XJ8eDoN43XUN6XVyWn/oPFtBZ5Sh5aoYJxZO6WJCm6devEbvIl4rgplLDeirPQdDzTfF60RgKdSQXi63bMNWT6wHWWInQ5dcNqvFU9aVPNOyivicshQvUwRUOZ0MC/IEAxm2vETYOnk1DvsuH0GWMVuELTe08W2G+t411bAle4T38IRD46ZK6Z0SLgU5fxk4FHK9yG4iXN1gEIHT6aEucB82EoY6dZUQev9RP7elpMsSthzEZzWU0PktERGRvdxyNWJRZIlWWqYZkbF5iIo34cQlk9K9gbxQszHPrJTkyDMVq3mLUFJVh6DaDmha3YDrLt1WEmMucg9HIWfvLuQeOwrTxQSlalEve42vHgCHZi3h1K4DHGrV1V5QAlMOzCm7Yb6yUYSXSJgz48S4TBFMvEQ6qgeddyfoKvWGzqO43odsWS7hs/t4nrg1qdePFCunsqcezWro0bWhQelp/uOQbMSI5+X0LWsa8FovJ9TwycPm+DAsPbYWV7KuopKLN55p0B89AzrCyWAblGRHr8aoA8jZI9bD4YPIO39OqUqFiwsMfv5waNQMzh26wFGsj6LO2rzXWYKVbKcl+9bKy5PVieoZifJWhq0KFUrdHwIREVG5skvYkmTgktdKlFVossG8HOQlbeSbycIXg1693I8s5ZHhS7bNKq40q1hyfjkiIMlqslxxK99EjNPJGcnSLSeR3pxdkN83V4nE0sl2W3kZ4jZbzEo2PhPzk2cdyhIsg4tYSNltQulSofysuWIWso2WrE6V7dvkOKVfVfF5ZRu2+CQTpq/OVtq6yec71jfg1Z5OIojqkG7MRIYYjCJAyNIsNwdXuIuhqLPw5AWmlfUgwqbSg7zcrGI6Wcon27HJNmvKmYpFvPZeZwlbauCSQcvSdqsgcFWsWFHsEvdf0CQioruf3cLWg0oGq8tp6iWHZLs0eUalq8hpRWUcGcQOxOdhyi9Z+ScJ9GvpgBcfcUIF1/svFNmLZRe2hK2C/rYKApejCNws3SIiojtBNkyiciJLpiJO5+H7HbnK8PPuXOWxPOOycKSVJX+X0kwI1Tpxlc/LkwRkiZZsz0WlZ13Sp7aPUwe9Xt7qldvs7GxlICIiut0YtsqJzFIybG06ZETYcbXfMFmytfDPHESfVdurybM0ZQmW7MRU9r21LToPO2O00xAFXy+1YX1RZ2FSWVgClxq01Fs9rl27pj1PRER0+7AasZxFns7DN9tzEHNBJC9BNh/zdAXa1Dagsb9BOftSnqkppzuekKeciWjZAn/v5Ign2zmikjtLtsqqqKrEwtWJ8r6zszO8vFidSEREtw/DVjmTpVZ/HMlTrvN4LlkNXJYG8fJEABm+ZAmY7NRV9q0lqxNlSVbrWga89IgTAirplesqUtnJXdky2J6ZWBC25ODu7iEGdnRKRES3B8OWHcgqwr2n8hCyPxcnE03KJYpkqCpM9jXm7aZDi5oGDAxyVK4DKTs5pZtj2ZUtYUt2bKoGLHlbELbkY9lY3qXwBbuJiIjsgGHLTuRleE6LoLXhkBGnLpqQJntlMKoN5WVJl+xfq6IIWrJ68W+NDEqfY3I83Rq5O1sPlqpE2xIu9X7Fit5KtSIREZE9MWzZmTiuK5fpURrMXzMpnbq6OslLG+kQ6KMvuNA2lQvL7mwdttTAZQlbBYMc7+1dgSVcRERkVwxbdN+xDlwyUMlbGbbUNlyWQQ1f8nlPT9mGy115DRERUXljxRXdd2z73VKvmym7gJDdP+j1BmUwGPTKIMelpV3D1avqtSWJiIjKG0u26L5kXbplGQqqFNWSLcvZivJWjpchTJZysVqRiIjKE8MW3bcsu3ZB2JK3avutwkFLva8OMmx5eLgrl/ghIiK6VQxbdF8rLnAVBKzrw5Yc5LQydMn+uJzkBbyJiIhuEsMW3fcsu7i8lYN14LIM14cteatO7+DgAFdXFyV8yftERERlwbBFDwTLbi5vLYMaqqzbchUVtizTyNebYTAYlOpFOcjgJQe14T3PNSEioqIxbNEDw7Kry1vrQQapgoBlGQrCmHUplwxc8ka9X3BbtBs9R0REDwqGLXqgFA5J8ta2BKugRMv2tmAa+VL19er9ApZ5KjdEREQKhi164Fjv8mp4sh1sw1fBfdvBMh/1fgH+OxERkS2GLXpgWXZ969vCQ0Gplu1QELIst1L+HRsFzxMR0YOIYYseaNa7vxqklHvafctw/ThlTP6t8le5L2mjiYiIFAxbRIL1v4F1mFLv2gasgnHqrfJXvdHYPCAiogccwxaRFet/h6LuF9wqf5X7UuHHREREFgxbREUo/G9R0mOLokfzX4yI6EHGsEVUguKDFf91iIioZAxbRGXAfxciIiorhi0iIiIiO+IF3YiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsSGcWtPtEVI6MJ4/htEsuPLx9Uc29ijaWLOLizyIjI1N7dGNubq4IDKihPaLboSzbx4LbiahoDFtE5ch8LQ3X5n+CrA2/KY+/HdYeK90S4OnojpeaBWNog8eU8bcuBzsXJCP4MPDy0xXxfjsnbbxFBlb9Nw2vVXPFuRFe4nEqPh2XiUN9PPF1Lzd1kjsodGcYvvluofaodF584Vl06dxRe1SyI1+Mxqxw7YGF3hH+Tfvi5ef7omYFbVy5S8CW96ZgUY2X8P0rrbVx95ZvFvyA0F27tUdlI7eR3FYlSgjB9PfWoOar8zEiSBtH5U7+r11OuqI9Kp3KlX3QpVMH7dGNWf7P6j05Ge/189PGWon8Cs9/fgEjpk9GjyKeflAwbBGVk9wDEUiZ/C8lcDl3ehiGeg0Q2bEBjmRfxG+x23AhPRFtqjTF7C7/UsLXLclOwaxJWdjpCkRUcsaRsd6QkarA3R22Pv3sC0TuP4B3xr+JuLizWPrTz9ozQEBADQwb+pT2SDVz9icIatUSr7/2ijamZMpB4GRrjHyqNby1cUiJwcpfduKMcztMmDUSjZ218eXq3g5bskTr/SkfoFHD+nhiwOPa2NL5dc1vOBpzHFMnv1tyCRfDlt1NEtsxXmzPmyG3n9yOJcn/UaOvg1dmjUeHiur4fAxbCrbZIioHMmDJoAXx28X7o/nwmjob7s/+A3+r/7BSorXm8flKqVbEpWhM/Wue9qqbl/pXDj6FAyY/7YBm8TnYckl74h6RkZmh3DZq2ACBgbYHZXc3V2W89SBZXlMmzgFo3L4dWliGXsMxZXxP+F/bi5VbLmsTkbWMDHU9y6BVeDuUNFjCmWUedOccjTmmBK3ePR9RftSUZZCvkaFbzqNUGrVGV5dT+HbhTvEzj4rCsEVUDq59/rESuCqIkOXYso021tbbrV/Aw9XbYfu5Pcpw8zIRus+EZm2c0KaJM56vYMYve9K156hEdeqgsbw1GZWHdGOytOrV19/Cp/O+0MbQvSSodUslCKt0yhAYEHDdOMsgx8vXlMnVAPR4uhlwaCWW7SlbO78HBcMWUTnI2vi7UnVYXNCymPzQa8rtH2dvIWydz8SP8cCTrT3FAw90bq3D1r+yEKU+SyU5dQpH4Iqa/j7aCMGUijObvsKsN17H8y+OxvMvvY6Js5bh4KVcbQIrl/Zi5axJePUlMZ2Y9h9vzMCCTTHIMGnPFyPxtxn4h5h++m8JyuOM45uxYPpbyrjnX3wdY6d/hR1HU5Xn7iYbNm1VGspH7jtQ+pKOmyGrm16cgvUH5PqdoK4XuR3mbsZ5uRlSYrBlrmW9y+2zEiesi1EyTmHHFzMwdrS2XcZMwKzv9iKx0Ca0Xe+j8eo787Dl+ClseU88/mKfNpWQexkHv5uB8WMs85uEjxfvRYr1djaJaRbPxsRC0xR+z7uBrIqfOftjZYiLF18ghcZZhpvl1nkERtXPxI6lP+JItjayOOJ/aNn0Cfn/Q6++Mxsr91hKmuOx/h2xLq23hZTyBz6W22z6ZqRooxSmfVgk5jNxhfhMd/H2YNgiukXyrENJttEqiWyrVd+7Fo5djdXGlF1cuBFbKzmir/Z2ge0d0S/TiJ1H89QRVCA7Hkf27MVBbdj921eY/NEeVHviNQwOclSnMSVgy7QJmPxzFHIb9cUrL43EKwNaofIl8eX+3lQsO1TwSz1DBIKxExdg/WUv9HhqJN56aTAG1M5F2E9z8O+P/0BiMYFLBq2JvyaojYgf9wOS/8AXs1ciLCMQA54W83m2L1pmRWHBh/+HZYe1F90lGueXgMh2PAHaPXtJwMp5C7A7rzVGiO0wsqsf0g+txOSPv8IXk+dgfXpTDH1RjO8WgNyTmzHrf3+oB97cKCybOBsLDuSicY/BYrsMx9CgyrgctgATZ4QgUZm3uv3+LUJaWHI1PCrXu9h+PbzisGzWZ1hpnXMzxAH8HXGgDktBtY5yfiMxoqMXLuxYgHHTxPy07Xxi8Qx8vP0CKgQNUPYbyzQTxb5gEwjuUk8MeOy64eZ5ocNzA1AvYy+++ClGG3e9jMgFGP/eAmxJrpz/P9TD6zLWfzVJ+yESgBatvZAbuRdHrP6fcqOicFAkFsfYfThivXKjoxFmqoyuDwXc1duDYYvoFuk9L6Pi+zq49izdKe9Nc9+B+/l/a4/KyJSGkL1m9GvngkBtFKq4YJA4Bn6x6xpK+kF5N/PxqaTdK0fJ+7DgqwX4WBu++HUfzmRn4sLJeKRrX+Tnf5mHRecCMHTSR3jvlb7o0L4dOjwuDgKzJ2NEdXEQ+HYlTshps/diofy13XYk5s4aj8G9ZDuwnug/djLmvtoaOLoMi7ZdXzKVuM4StCZiguVsrdMxOCgOEINHv4H+cj5d+2Lk1Il46+kR6FFfneRuIU9KkO14Pv/0Y6VrB3tzbDUSUyYORVexHboOF+uslzjwHt+Hgw2sx4/Hm70ri/F71AOvYzMMGPMSpnw0Ga8M6Sm2S2f0GDUeU15sDcf4TdgiA6wpBmsW7kNGwADMmF2w/QZPnIUZT4h5WZWSnVixCFtS/DB08iy8NVzOT33P2f/sDLf4NVi2Q27nBJw5JoJ4y79jwih1v5HTTPnncIx6ujXsdrJrOZJt7AoPt8SvL14W+3jKjsVYe0obZ03ZBnuRWKVvoW0wHRM6u+LEmmXYLbanf7v28DUdxYGj2uuQi4PhUfDvPQA93E5hV3jB/9mJfZHIqNwKLQLu7u3BsEV0i/Re/uK7IBLI2quNubHoM27wuNmzEY/l4JdMHeoZcrFzX4o25MClig6XjuYi/B5MW25ubuJL/jF8NOsD5aBerqUnfgMw+5v5+N4yfPUpZj/bEOmHlmH6YvnrOwY7dlyGW8cBeDRAK+my0Puhx5Pi4HptJ8IOiV/kodux2xSAwU+3g1uhb063oKEYXAs4GLrT6he0UQ1av8TDv9/4gqAlNe2EHh6XsWzGFHyxOAS7D8cjI9cPLXq1hm+hxbgbyHY8tyNoydKRvo+K9as9kvzr1xV/ixhfR+4nGUjXCh7daonpwldiwawpGD9+Br4QIflg5TpogUzkZokJju7FjmuuYpv2hW+h7efbry+65o+LQXi4mGnzbujokYqMFKshsB16VgYiDhwSh3+xvToFwPHAAoyf8RXWborCmUuZcGveGR1q2Z4bfLdSqw5lVWLBcKt8B4zA4MqXsXLBmutLepVtAHTo2QnuadbrNhP+D7WHvwhj+6NygTqt0bViJnaEayVk2Xuw95AXOgb1Rdu2rjgYJde/dApHDonXthWvvcu3B8MW0a1yEUdZhwowX1ikjSjeiYsmXEwxo2oF2Ri1rHKwc5cRUTDj03VZCF5SMIyIMItfjXlYt1ceVe4t8hRzyy9qeVB/plC3D+VK7wjfri/h2ZZAighGR8TBWpZo+PuKI2hRfH3El7iQB3FQl0UfleFb+NR2hReUWYgjQI46QhxYfsT0Xy7DW/ykPrPjD7V0zMK5GUbMnoa3elRGyr4QfPvxDLw6xqp90gPLTYQ67a6N4sZrlGq/CZj8YxRyqrfH4Kd6oUmFJOz6ag0itEmQlSG2dgX4+mqPremrwT+/32F1n4AI5GPfnoBXbYY5WCmbFiWm4qq48e03EXPHDUYbwwVs/mUeJk98C/8YMwUrD9x9be9kVx6WQf7AKSB7f7IebpG+Dvo/2xkVEkLw5Tq1fWI+ZRsAuxdPKrRexfDxHzgvnrucnCT+1kGbtl7IOBSljMuN3I+Iiu3Rpg5Qr20Q3A7tx0H5wzJ+H8KS1SpE6W7eHgxbROVAX+d9mLNiYTo1VRtzvWtZZkxeoYah57oW7oS0FLIzlOoQ2YnpuQ+rFhoqYnkT4PuILNx9X/N3G0cR8EQyUs5GdIOjOO6cTyymG4jEJOXLHgbA3VUeoC4jMVmOKCwVyiwcgfwtK37Bt331A8weL9ux7MT/vtqnHGjyOVZGiyFjMOGjT/H1/I8xY1QrOEavxPTFd++pDpcvywOhiCMZmUpfXLJ7gLtByvYQtdrvvcl4ZbhWhTTkJbz178HqmaeSiwhsSEGipQGXNdMFnM/vPkXdJ3x7jS8oES08TO8LS2Zza9QTQydMxtz58/H1zDcwtHYK1v7vM+wocj+5c94Z/1b+YOkDzXqcZSgXTZ7GKx1lteACbFH+gTTKNvDC4IlFrFNtUNo0CkpVYrIIVfFqFaJ329bqD59GrdDVLQp7w3OReECEMaUKUXmJ4m7dHgxbROVAH/A6dBW7wnR6GkzH3gaM8ndvAVmi9fK3mUhIMaNlTQP8bqJkK/WvXHwpjvo9WhQV1JzQtqUBVeJz8Lv1lxtdz3QKu3eLZFS/IWqiIbp2rYyMsDVYL77UbciG87/sRIZHZ3RsLr7Eu3RDB308Vv6097ozDzMil2FlLNCii/hFr41D2xEYEeSqtmN5IgAZ4YuwMlKt8zq/bgZefeMrHLSkL0dX+Hccgh6BYl5x8Xdl42rZq/z7U9WAtXTZcuVWVkOV9ZI+9pBjktuuArxtSh0zceTH1TioPUIjEcA8MsU2LWjgbpG4LgQ78sc1VKqqEreEKO2HbKTsxYK3p2CZLCm5tg+Lxr+O6b8WlN44Vm6IHn2CRKCIx5k4beRdQnbh8eua30scyocjGv/97+jqEo9la6zOKlS2QSrWrBX/V4X/h8K+wvj3Fhc0fleqEi8jPGIzDh/yQtd2ddTx+mZo29oVEZGbEbE/Ab6ttRB2l28Phi2icmJosRI63wEwxX8K4x++yIvsiXm/n8OweRkFQSvQgANn8vDf38rauCoDW3aLb6faDmheTK/nzs0cMVRvxrpI9rmVr9DZiAd3hGDB+3Ow8koARgx/WHwJi1/QT47BiOrioDDtbUz/QhxglbMWF+Dj8VOw6FxlPDpqMOrJb0rndnhW9ggfvgBjJ8zGyk1ynpuxdu4UjP1cHFAaDcWI7kW3DfHtNxJDA8SB/vtFSsDyDxIHiIx9+FgcuBf8tlOdz8ezsUgEtnrt7r7G1ZbL91hKtCyX8pGPb6W7gPLi27a92EYx+HaStl3kdn5vAmYdlRFMo2+IAc+2Vhq4TxxfsP1WzpiAiZuBmlZBrd6QEejhGYUvxk/Ax99a9omvMPmdBdiRVw0t64vt7CEO+o0ccOK3KRg/Yxl2aPvNrG9lQG8nntNmdpdQw5QMXDceyo1bOwyVfW9ZhyplG7SDd/RijBXbYJmy7+/Eli/E/9C3+5BTo6nVZbTUqsQT69Zgh0tzNNayliSrEh0PrRE/cKxC2F2+PRi2iMqLg7cSuAwtVkBX7VkgNxknEg1KK4jezR2wZIwbPh7uotzfcNBYtsB1Pgu/XAKeb+mCYpt6OruiSwOofW4V+tX4wCp0NuLHC0NwwKU93po+Hj2qa9PIhvCTZmHKU83geDQEX8izFtfsx+UqD4vp3sfQ5gUNw92CXsLcGSPxaOVUbPlZznMl1px2RMen38B/3nr4uobXBcR7vDwA9bL24X9fiy9/v754T8ynfy0jwtcsVuYTcs4VPUZNK/r6cndQSddJlCVcZb3OZbkT6/Ot8YPR0SMe63+y2s7v/R1ttUkkuf3+M0FMV/GCOt03axDh3g3vTRmJjtY/YtxaY8TMaXira2Vcjlyj7hO/H4Vb+5GYPfslNFaaPDmi8agPMOXp1qh8aZeyn33xexQyag/AFDE/+1wK6uZZ9xB/o6E8qX1vaQ80bkFiHU4X/0NVUrFD2fcXY9lRR2Xfnyt+zCirVuPfvDncxHeZY9t2qKeNUzRtCnmV1FytHZfq7t4evDYi0R0wa202Nh4yok8LB/zr8bvsW/k2kKUh8hp6so1GacgOCmXD3nJrU0LFkh2XyrPS5IG3oJfx0rmV19428ofIdaE4CotemocT/SZjyhN3V9i9WZZt0bvXIwhq1UobWzqR+/dj46atd/d2vMcwbBHdIQ9y4LKErdKGJzl9WS9ETTdHllSpF6IuuNZhaclqKHmQ/3DmdFSubNVD/10hExH/m4AvLvbEjKkDbEohM3bMw9iFJ9Fj7McY2lwbeR+4lQtRywvCTyvFhaipdBi2iO4gGbhOXjQp1YseLjfTHcS9KXRnWJmrnl584Vl06SwrD8jeSqo6vJG7ORQrPch/vg8ZFerg0Ue7oX6FFJwJ24k1hxLg1vYl/KdQNdb9QP6vXU5SzyItrco+PvxfK2cMW0R3mOwS4kEKWhayBCUjw6YzhGLJL/+7r6Tk/laW7WNxL2wneW3EZT+tQ1hsptIxpqNHADo+NhhDezS8rrNaovLCsEVERERkR8zxRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHbEsEVERERkRwxbRERERHakMwvafSIqo+rjLmr37h3nPqyq3SMiotuBJVtEREREdsSwRURERGRHusTERFYjEt2kljPztHv3jgPvGLR7RER0O7DNFhEREZEdsRqRiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiI6P6WGY1FHy9FZIr2mO5qxuMhmPnZdlw0aSPuAwxbROUp5wC+fuddvPmvhdido42zEY3v/vUuZm5O1B4TPeCilor/lznYdEl7XO4SselLEbRMvqjuqY2i2+7i5jliOy/FQe3xjTjU8IXP2U2YuzwGRm3cvU5nFrT7RHSLjJELMX75Gbg6Z6FSz3cw7m+Fv91l2FqKi73fwDs9fbVxt5E8sC28hH7j3kCvKtq4YhmR9NdyzF0VjdrDP8ALzbTRhZnScHzrKvz0RwySssVj54qoFdQLwwe2hI/1z7nMOGxfuRYbD59HpvgGdXD3R9v+z2BwUEU4aJMo5Px2rsXqrTE4ly4ndEH1VgPwwpNifjYTFs2YdACrf9qE3XHJMIpfxg4VG6J38CD0qlvEkbZM7yXWR2QIFm8IR2yymFbvAJ8G3fH0U91QvzQH8bRT2L46pOTPL93O5brTitgn5YF55sYqeOG/z6CFOuqmZYYvxMTll9DttXEYGKiNlG5hP4tc+C4WRWkPrLV4Bp8Mb6o9yELsn79ghWX+xf1fPCDKuk2L3W73KMP/Cdp9Iroladjx82rE1HwSI6udxPbDjmjdqRY8tGdVidi/6RDS63ZAlzru2rjb6NIhbDiQjvqdOqDujd5eBKNNCz7DtzsvIEf8HKvasgdaFxnOsnBwycf4elcKKrXvhSe6BqG2ayIO/7ULOy/6oVOLKnCUk5lO4af/fI0tCS5o8kgf9H6oMfyNsfhzy2ZEObRAp9qWhUlD5A9zxPsmwq1xdzzeoy3qeWchbu8OhOy6CP+HmqOqMsOiGeNCMGduCKKNVdCpdx883Nwf+stHsGPrVkTpxPvYrPOyvJcRsb9/idm/H0Felfbo+1gntPLTI/HwLmzachSGZu1R13ZD20o5gK8/WYzQ/M9fG94ZZ7F7+2bssF5Pitu4XHeDIvbJ9FO7EXrSHa17ic+qjrpJ57HuhxDE1hmAMQ/7WVXl3Mp+loioTbtxNqAb/t67PVo2b1owNKqFahWcxTTi/2LxbHzxp2X+LVHTdBb79u3F9mgDWrcX3ws6dW4PirJuU0e/isiOCMX2y5XRs5X1trs3sRqRqLyIA2r4WRd0aNsSjTu0heelcOw+rz13L8mJxqIZX2Jdgj/6DewAH210kdLP4PglI6r3fAXjBnVBUKuW6DboZfx7UB1kHtyO0CRtusO7sTvdE91eeQMv9GwrpmuLXsPfwMi2Lji3PRTHtcnSdi7FosNAi2f/jXeGd0MHOb/HnsU7r/dC9cxofPdjODK1aa8jAt3K70Jxzq8X3nn3ZQz+W0sEPdQNI14T79lCvM/GH7A6TptWKNN7HV+Lr/44j+q938DU1/qjm5i2Q89gjB0nfqW7igP6d+KAXmz7kjSELlmOw2iKFyZZPn8XDBz5Bsb19hfraSkWh2dp097O5XoAHP0LfyWL/8kOLW1KD29pP8MlnL0EVKott6PYx6yHQLUo0Ri5HN8dFPN/xjJ/dX+fOrwpXM9vwqKdacp0dAP6QDzSxV/97rgPVhdLtojKybkty7HhUiMMeKoxfCq4IzV8B/7KrI0eTSpqU0gFJVuNU7fi62+X4qffNmPDtl2ISvJGw4Z+cLP+CSSrOkJX4rvvV+DndWK6LTsQfuwaPOrURTVtQlk8P+mL3TC0LFxaJass52KDrgW61IlV7i88INuKZeD4rq3YsGkrLlQrosTKUAV+AX7oNqAPmrldwK5dp+BRXMmWU2U06dgdnQoVk2WdDsO2Y7mo31FdprTju7AtJgs12nZBE29tIuFy9A5EnK2I1j2bwhfnsX7JZsRW7oUx/etAlg/k86iF5s5HsW1XLJyv+5wq4761+G5fOjo89RwesqmhdUDVZn5I2fkXQq/54dEW8oOU5b2MiFy7FBHX2uLvL7SBr3WJhGMVtPZLxY6w3Uj1L2Ydnd+KhevjUOnRURhU1+adxHZsDJcjoeIXv7NWCnr7lkvdb07Bu34SQuZ/h8Vrxf51UVs/cr/b8hO+XvQLVsr9Tu6fFwzwrx8Ib0uJjykZkb8uxLdLV2HVerE/7diHmBR31K+v7sOl2y/FE9YlW+nbMXPK19hwMkNMJ/9X5H56KH8embGhWLzwByxduREhm3Zgx5ELMFSuhVqVbNerRWzYaoQmNlH/J7VxZdv22nhrSYexZecp+HR6rJjSXiDmj+WIyOiAocGNYbW7i83ih+zI3dhvCtT2w8Jk1eNyfGP5f9fWu2/tQPhYLWjaye1YuGARlv1qtR6q1kctb9v6z7SToVi62LK+tmJL+AmkedZFEz9XbQqhFN8xSlXvh1tgqu6Kgz8vxncrf0fIRjm/c9AFNERd6/c1iv1ixQL8b8lq/LZBTLNHvKdXXQRmHLAp2SrNtnR2zcD+XfuQ7vcw2vjf22VD9/bSE9014hC+Pxk+7R9CfeWxPzq080XmwQM4UkTJQkbED5i5LBpo0gsjnhmEfuKLN1X8Gp7+n+U4aPlJbUrEpk9n4vPfY2Cs2x1PPxOMp0Uo8UzajUWz5+CnowWlISULRHfx+hGdZeMHT7R4TNwXj7sHqM8WVrV+01K1j7KWFncAkfvDsWmZrNY6L1ZBK1iOJ55BHdDCNQ2hX83Bd5vD1ekWz8GC8Cy4tmuLxnKipGM4ngzUatNSLOH1POs3EAfMRBw+XvTP3OPHYgDXZghqpI2wpm+I+nXF7XHxHvJxmd7rJKKPilm3aInGRX1jNqijbPPjMafUx4UkifFJYv13aFXkO6FxIxHGL8VAeavbuFyqaPz0xSYcc6yLoKCWaFJFbHS53332IT7feBKw7HeP1IXxcAjm/ndp/v55fNVnWBR2CS5NeynTDAzyVNr4Tf9qN266IMK7KQbKeTWTnz4QXeQ++0xftJCJJWU3vvoiRLy/P7r0F+MHd0f9nBis/lL8L1iKRm2k4Wy8WJKq1eCnjVHc4n6GK8m4gopwOL8KH06ZjDf/9S7enCT26z/j8kvDco3aneI4FP3PlbbzB8xdG40s/w7KerCs988/XoXj2vfIxW3zMPVLsc1QF70HW62Hz2fju6iC74SLYd/iP1+G4HBOTW199UILz2SELv0QH1pO0CnTd4yYdqEIkcaGeGyomK63+I5Ii8G6L35AqOUsT1kq+MGHWBSZhqot1P3isSbAgWViX7FatlJvyyqBqC1y4ekzVkXS9yiGLaLycDQCf6X44qF2/toI8R0vQkT1zHCE7r/+mzct2RW933gHY5Wqt7boNfRlTH2jF6qnH8CyderB8VzID0pVXq/XJ+VXdShVRO++gX5+ydj9U0j+F3DJPFFLVnMojcRdUKOxWu1Rq4L6bHk4vWM5Fi1dhXWRcUir0AFjX+tW0DbDtSVeeL0vaokv7IMbV6nTHUyEY5NBeHtQHXWai5dwTtx4VSjqECj4+aO6uMnMLCpkJuNsgrjxrAgvdcR1qvv7yherB8SyvFfSBeUU9GKn1fujhgiVmWLeRbl0UdYle8KrmJdX9Zf7jFgu+fLbuFwWrs2ewdRxz2KEOID+o3dDpIX9gnVnHayqwOR+9wzeeVtsP3EwXbZeHvgSEXtaLEOTAXhjqFYNJ6uPnx+EpweIg7U667Jz8kVjMa/G/i7igSfqy322VUNUdRIP408h1lQRvUaMwkCtiviFt17DiP5Pomdt5dWFZCFTFpCJFW+zPLe0nwHGtDSxtZIRuf0MfDr3V8JgN/H+h9d+iWmLo5X9q3ZdsU+nhGPbftt5ZEZtUqrWmzSQyf96p0+LdVtRfK5/iHla1vvrInwO7oba8mgtQsqyDefh2CxYbLNn0Oshy3p4AwNrZeHgyk2IlTOS060W3yMtgvH+W8/mry+1St0TFw9HK+ugrN8xrk2CMel1S3W1WLZXusDHFIeIKDWYHl/3ixKg+snvNqv9YuobfwMSrMJrqbelJyqJzVTSPnwvYNgiKgdHDkYh070ScF6W7mjDaQdUFQe7wwejUThueYov6V42P7cFv27o3Ux8sRw8gOM4hdA9yXAN6ol+/oV+Bet90evRtnBND8fuo9q4u0CL4R/gk/9+gNnvjkI3192Y97lVPzmZMfjpm01IE1/+70zXpntrEGqfWYvv/mA3GHdOQwwIboqCSqU0HDggD/it0KVuLtJEsMgfnJqiTQOxKcWBOha+aNFGtqdZjqmfLcXqP2MQm5QFx0Zt0aHGTUetG2vQBkHuydj02Rx8vWo7dh+XZ3X6IuhvZS+FvRUOQc+KffcZvPR6ofZ3PWVJdgg2imzt+dAA8X8rws/S/2DmYrGsWknu+zKM+ffCgKCiF7hJUEu4Jm/HnA8XYuXmcBw/nwVjFRFYmqlnrKZFHVBCSpuOdZTQl79t0h3QvHVDID0acvOp0/mjd/+W8LQ5yruIEP0OZr/eTQTKsn7HeOKhbmL5tEeKwECrYHoKkQezlPkV9d02pLPVfnGXbMvbiWGL6FblHEBopPiySY/BuqWydMcyrEWk7DuoiAaebq42X1n5qvpZSl8ykSF+zHlVEgGuKJXUEhzZtcHdxqFCHQx8WQSpswUNgY+sXY7dpg54YWhLtZRCcPBri3881xapIV9gpfw5LpKp/OJOTSmm+ibhvPJr3NVVlnoUVhE15Bd8WjJS1RHXOXdehDqx3pU1X5b38qmGquKbsthpTeeVBtOuxWzTKlVlyVUaUot5+cXzsuRLLJd8+W1cLpUD3LTtodJKg5J34/NpM/G+zfAhVsoDb4q6jqt2H4OpL/dFff0l/BWyEHNnTcP4SXOw8nAxy3OrnBpixLvjMKJzJaREbcNPX8/DxPcm4/0FoThXZLWdC1zdxI1Y8TZLdEv7mcrBrykaFwoUVTt2QC0k43hMshpWXhfL2tEfGYc34SfxXfDn6TTxo8sf/YZalfgW4tAkGFMnBKNLJRF6/1iFz+eIdfreTHz953nlB1uGUsKTjNCvC2+bmZi+KkY8l4YrYuOo01VEpaJKrvOP+mX9jnGBW/GrRLjx/GzWZ6m3pfg8YjPdeB++NzBsEd0i48EDOGxqiKe1EhubYXowmujjxC9b2y929cvwehcTLIHAVQQycUC4ckV7ppAr6gHP4Ub/wZcScVG7azfGNMT+JX9Fa48tXMUBTXzRn1PaWiTibJwIo9XV6hkbbp5wEwf44yfE5/ZpgPoVgdiIA7YHR03a8WNIgi+aFNN5VP0G4pd9ZhQiiyrtM8Xg+ElxW1+8h3xcpveqi6aNxKyLaX+HY6eUdmD1G2rVoYX4iPE+uH4fUKXhyFFxcK7SUO0T6zYuV9G0gNJoEGYX3pfzh4J+kjzrdsGIV9/AjBkfYPa/R6FfjTSEfr8Q22/UU/ut7JcOFRH02LMYN2kKPpkxCeOGNoXTsRDM+0UGjcI8USNArKeLFyBrmPPd0n5mROzO5fg6pIh2cM4iuGp3FXqxrLIKTaybT6YEo7YpC7X6P3t9qU8hDj4tMXCkCLLTxDqdMgYjWjjg8NpvlaCr/kgr5rtGG2R/eOp0ybhywx7zy+E7xsaN53ddtWxptuWlOJwWX5W1a977HW0xbBHdEnFw2SW+HBo1QVubEgKNrHoRB8RzoeIXmzZKStu5FptsjgBCwnZsjBJfWS1aikBQB13aV0Rm5GasO1/oZ7ts1Lo+HJnubdFBzFtt85OI2LPW02Xh4MY/7RK2jOJLM//X7onN+GrlcqzYalsVmBkVir/EF3115UuyInwqi5vDB7C7UMa8eDBaLKOL+DKVpw/645GuYvqz27DCujGtJNbNl7LRfaMu6GJ1EpcxXSyLdt+hVRd0cM/C7vWFL/Mhq3OWi/euiG5dLR1OluW9HBDUuS1cM8Pxe6HPqTQI/klsi4pd0L2JNk6wXi74d0G3WmIf2Lq24OQHzcXNC7H6LNCkWwettMO+y1UyT7RsKd7/6Hasji203xnPY92cmZj7h1iG9Ggs+mAyZm4seF+HinXQ6+FmYqnOI17s7OW9X57bNg/jpyxFpGUdyk5Ig/pC9g6Qef6CCEjXq9WooVg/hQN4GfeznCykyU5JFQ5wvBqHw3+EXPf/e3HHXzgs9vX6DUWSsyb/X79ciuO1g/GSdVXadc5j06eTMXHhAaXdl+Tg6o+gvh3Ej5QsxF9Ihmezlqilj8HmkLiC/UthxLmQeXj/M/V7Rp3uPDauFYGy8P/C4mkY/8FaHMkp/XdM6dRBUAsXZX5FfbetsOruorTbMi1Gfj8EonHDe79ukV0/EN2KS2FYtv4UfDs/gU6BRZ1+roev6Rw2hceK3NUJjTzVrh8u6tJwfPdexIjvH6fsS4javhY//LoPl12bYsTzXZUOFb3q1YchehM2bAnF/gQdHEwpOBu1AyuXrsbe5IroMHwYuvqKL6EKDkj86wAOHjiAC3CCOfUUdq1YjjUnMgAz4GHdgarxLMJ3H8Xxizlwd7iI2CsVEehb9GnzivRYESYLun4wHl6O9+csF1/OWkeDlWvD9+Ie7Ni1G/svqst4Imw1FoWcQLpHW/z96ZbwNehRzc+AqN17EPbnIVwwO4hlPI+ozcuxaNdF6Gv0wjP9ApXOX50Dm8H/4i5s2LijYH4RG7FsxR5ccGmKF17pgxpa1wPyrKzJ3/yOyJzG6NpAHMR0FdGskXifzZsQslu8v94RWQlHsfnXFQg5loHqvV/ByNYF5/KX5b3g0xjNdEcRsnETdsVkQOeUhQS5LZZvRkyGP/qNfgZttOPodcsFZwQ288OFnVuxYavl85/CnnW/YNlfF+Hc4hn881H//E5N7bVchRXXyaRzjZowHA3Fli3i/eNFaNRl4MrxvVi+eBUikyuj0+M9ULdSJTid34UdO0Nt3ndZyD6kOLVE/4FN4VuplPtlEZ2aulw9hk1RRxCf5AyP9FPi9bXQsFoGDv4pljl/HxLrcO1qbIjNQvUuA9Azv2NcKz4VcC08DKEpth1jln4dx2Hl9I/xw6YDyFb+f8X/ZUAFJIbLz379tnRvG4x/dKhsVYohws2ST/HzhYYY8VKvgu1WJE94ZBzGdvG/9MeBi9AZTEg5vQ+rVm1FbLY//jawK+r61EBtw1Fs27odWw6cQ2YekJF8QqzXZVh2IAm+Dz2OR+U6dRHTucfirz9Cse2gNp3V/0K1h4dgYH330n/HFNsZsm0nzT61K+PCnl0IDRXfbZdFgDOq3wcLVorvNjm5uYqyv9V3L8W2NMVh/Y/bEVunD0Y+dO93asqwRXQLzm1fgU1nqqBHcCcUmbUEvU8u4rfuQ5SxBno0NSlfTugxCsNqnMf+vRHYvV+En8Rs+LZ+EmNf7oXalvno3FG3fXvUdUnC8chwhEUeQvTpJBiqtceQl0agV6BWlGaojJYtK4sv5mgc2BeF/YdikehZFwNf6A7H3dG2vdV71kdDt3OI2LsPkQdikVmzPToEyiqHYhQKW/qrp/DH/rPIqdwUvZWDlwOqtngIjVwScVRbxphEPfzbDcBro7oh0HJw8aiFTm0qIz3uBPbt24f9B4/i9DVvNHk0GKOHtESl/D6iZJ9YQajrWvCZY86lw7tVoXUjmBMO4c+jyXCp1V4LNYJ4n/atKyPz1BHsDo/A/sOnkKivjUef+wdGtC1U4lCG95I86gShnU8WThwOx197tW1Ru4c4MAeL8dpEQpHLJfu9alMbLldOYe+evYg4cAJnM73RdvDLGNMn0LavJzstV2HF9ugt97t2bdX3F0Fpr3j/gycSCs1T/IhoJrd7Ek4ePqRME30mBW61u+O5Fx8T+5iYpLT7ZREHcn21hqh5TWzDiAPYfzQObk26o1nNwvuQWIe5ldD+yZcxspNPMQdjT9R0PYct2w8ht6EIS/ltmEq7jnNw6WC4CK5+aNM9CIGy2ZHYli07B6FK8mGEhtluy9E9a4g5W0k7ie1/HEOVJ/6B3v4lxwWP2u3RzjcDsTHqOj144jxyKwXh6VeeQRdf9fVymo51nJF4aj8iwsX6OXQC54vYxz0CgtDeeroj8n/BD52e/AdeFOtLUdrvmFKGLWU/7yLWjQjLe8W+s/9AtPJ9UO+RYXiq1lnsPaXtb+4lb8vMiNX4NsKEbk8/iSbleNb0ncJrIxJR6cnL7nwQgkovjynFtRXtLGU35n4ah94TgtG4qCrcO+VuXa4HViI2zZmDdcZueOetXspJBXSXywzH11NW4XSrZzF1aEPbAHuP4m5HRKWWGRmKhC7Bdz5oCbGhEfAb/ORdF2ju1uV6cPmi18vPIEifiHNFtYinu47xbCKSavTC2OD7I2hJLNkiIiIisiOWbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR0xbBERERHZEcMWERERkR3pzIJ2n4huRsIaXB4+Hdf9Izn5QNfkETj0ewquD9eCs0Ebby0vDemHYoHazeFeQRtXkoi5SJywBOj/LXzHNtdGEt2PspB6LA7HUQVtGnhr44juPSzZIio3ntBVb1gweOTAvP9n5M4IRupzc5GaqE1mJWPlG8gYNwoZkzcgUxtHRFICVr30Gxq3PYgBbTdj1o4sbTzRvYdhi6jcDIDzD4tQ2TIs34JKKxfB8eGG4rixBNmvz0XaNW1SjaFqbfHXCbqG/nBQRxGRtO8Ipi7T7sMAb29H7T7RvYdhi8iODBUawnvSt3DpXwtIXIKsbw8hV3tOcn74PfhuDkXl0c3BQwmRlcAqGNpV3FY1YNDsFni+RVH18ET3BoYtIrtzgueosTA4ibtrFyPjijqWiG7Apykm/DYE544Pwmcv14WzNproXsSwRXQ7eLSDQxd5ZxuMEWnKKCnz1zeR2LM9Euce0sYUyEsMR/KkUUjsJ56X0wRPwJX1scjRnr+hazuRJF/T801cTdDGWTvynTrPwd/hWp42TjAmHMLVjyfgcn/tPfsH4/KkJUgtYh5pc9VpLv+apI2xIk8aUN5/Lgo+bdEs87kSIdbHniVIejVYfe+eXZD44mxcPZYGuYh5KTG4OuPVgmUbPApJ34cj02r5rWWGiXm92FebVw9cflXMa3+SMq/r5CUh9ftJuBzcw2r6SUgOS4JRm8TCenlzjm3AlXHWyztJvIe6vPkSNuCy3IYv/4z0Ypa1sOxtG1Hda4U6fBCN1MN7MPXpVWgtHr+26pI2lZCVgJ2LN2Pc4+pzcvpuT2/E9zusprFmvISIFdtspu/Y4zdMXXEaqdokUtS8Vfnv32feSW2symbZBoYhThkbhx8HauO8fsOqU5ewc24IBrQSj+tvQ5QyjVDE+7fusArjZkXgeIr1yknAqmGW+a3A1G2F22ulIm5TKN59bhU63nA+YsqQkPz5tP7oiFiXEfj01VXoVl8d17FHCL4U25nInhi2iG4LJzg26azcM8XEKrc3knduDZKfexXGMBHCDLXUBvdOB5H3YTBSP9ypTXUDItw59pJFaTth3H39geTan6vVO306wUOrncmJmI+rI0chd902mF21Rv6uSTCHzUX28GAkbTpfdFApJ6ZPRuDaxPkwpTpr7y1iZezPyH11FFLXi/Xx9xHIDT0NVBLP+fkAKYdgWvwqrk3aBptDcd55pPxfsBg/F6aLlpMWfGA+JuY1biCSf7X9HHnntiFpeF9kL94AMxpC328Y9A3k9BtgnDQQVwtNb2FaPgGpIpDlndaWV55NGrtBvMcopOwviMTZh0Jhlg9PHoSxUJu94hyPLIg+bY6dxvAOcfgyJA+X4IjOLauIsXlI3bYZwc1DEfzqVfy4Qz6nOh6Sincf32EbyoTsY2EY13YHBoxMspk+bm8WvhwZgeGzjiBbHYNDGws+8SNBtbR7Kutla9a7CgLlnYuJ2LlNGaVYN2UHgielI+KUeDDUB/XFTXHvf+lwHn784DS6PbkDEenayJQLCF+r3YcL2jZx0e4LcRGY+vhGdBycgO9X5Wlhr5j5iD3j0K78B6iy7ige7nAasxbn4fhFdVzc3nRM7bMHW1PUx0T2wLBFdJs4VPRX75SYWJKQNnO6coDW9foEHr8uVxvcLw5Bxe+mQYeSw5oMd66dByr3zL9tRYZyzyIWxp3nxW1DOPZuqI66sg1pk74T71kLhonifZYXNPL3mvGCCHqxMM2ajbRz6uT2YL5SGY7fhcJ3sfbev26Bs2zrJpf3Q7E+Wk2D+9oQq3Xxnlgu8fSexciKV2ahSP9xEnJCxTpq9h7cLevuh+Xa9DkwfzYJafnTp+HavEkwJTpBN/pX8bk/h89bY+HzuZj+87FiXcvp5+NaEQdic8Rp6OW6Wqkt78qtats8sbx56/bmt81zfuRfcPvwc7h88y94lKp7DxF2dmh3hYhVWYjQ7qNFRTSvI4LL3h0YPvAqdmqBof4Qb7w/zRuDmqiPpVUfHS0oUYrbg7cfO4cfZfgR6vf1wuuFpo/44CS2yPmlJCEqPzi5o10T67ZStsvWuUl15Tb7cBJWKfekLKwreIDnOwXCOWkfpua/vwHPf94Ay39rjOULvNFGmUrYm4RfdlxV74v5fa/eA7r7oFlV7b74HK/1OI0vtWUIbOeOl6dVwctDDJARVCHmM2WxCOWKc1afBYjam4cKRawrsdcg6ph2l8gOGLaIbhNHD5kMSuHIGuQeEbcVRsNlXGe4Wh3rHAL6wOuVp7RHN+bYcQAclNKW9cixCiOI3QujDE21BsBJK7TI2LwYJln6MngaKjziY3NmpHP70XB9RvbntRO5Kw7ZrXRLN2o8vAO0B5LBE14DnxKBR+oOp3F94GazLsTyPyLvHYLplFaSlBmO7KWySlZM//6A66Z3f0mWLh6C8Q9LYE2Dzn8YDE9Mgks/2zNCHRo8CofG8t4G5J1QRtnQDf9voXXlBM8hw9XljTimlRIJ4nO4t2oLz1qeImaUQqFSojbD/bAovCuOxPfEkd/bo9m5CLz9TJIWwAyYsKE3ti/oiZfH9sRnWxrgeWW8cDAVx5VwfBJfvhCHVVowG7SgC7b/1BsT5PTbG+N1S5ARWzZFFgJZB53+PqhnHRBtls0dXYLUEifr0i5UdcTrC1ogTC6vGN7v5Y24kDh8bwmGk5vig+Et0LlrU3Qe0gKvvOiIzt3Voaq3Or+oyILK5ypdfdTSM1lV+abV5/i0DbZv6Yv3x3bF+wt647Ox6ngpYleiWnJ26hK2HFRGCS74ILxvwbpaHoh+2jPivwW+PtpdIjtg2CK6TbKvXNbu3VjmCe3o0L1tfhWftVKHNkNDOPaUpWkiXITJkixVxp71Sgesut6d4aaMOY+cLTKgiLDRrWGRgcC950A1ROwIt19/YIYimkC7WMb5Q19Ju2tFp53CaUrWDs4xe5Enc1f7R+FSxPSuDVsot+bDp7Uw5A+v10aj0mt94OGqjCg97yLCk2VESur1ndyWkk0pUXc/fPR5FzzSoAq8KniLQUTeb07nB45m01rg9Y5e6gPJ3RFWj+AskmDq2mOYulcbMbw2Zgzx0x4ILr7oMqEK3p+mDg1E4LAOOs06WYKOynbZvLUgZlva9fznPTFhSAMEKsvrrSxD4rmCc3CPf3EEs1YcRFTcVWQbq6DfxwOxfLU6vN5Rhq0EHN9VEOkHBalLkBoSjf9uUu4CvarjX8/Xtmo07476La2qGjWpMVfFTwTN0Gro18Bde1CYKwK1gmcie2DYIrpNTOlag50SijdMKWoo09W49W9/j25aVeLGnVpVYhJy/pTBqjkcOlrmnwST0ga6NnQVlRHX86utflncQoi4HTLjtbqgPROQqjRaLzT8c776fFoaTOo9hTEhHFdnTLBqIC+HvmoJ421m2yaqmtLeKV/WMWz5SLsvRE3al9/4Wx2i8an2HFp4IbDqVYRvK2iz9Hz/ujZhDKiCzi92xctj5dARbSrYBp3r2msdLphX0e213NGj/fWBpllvn4Lqwou5+HTkMfRpthl1Kq3AiLdCEZFkVV5aZHst8Tk2pee38/r7841tQqCUZX2mRwNP8cls22t17uRbUNUopEYnYZ12X2lXdn1WIyo3DFtEt0UOcg+rv7H1DW0PYHbVuDscZbMaS1Viwk4YZYBoPBDO1lV29wvL8dZVO6mguKGKpzahCGhrJyB5+KvIDT0ItBoCw6hpcJ72uRimwaA2SbqNbEuJCocdHLFuG1WC7t6onxWH0G+0x3BEs4YlXPLGJugU0V7LquF8ke21Clc7apxbd8ea443x/nDDdSFp6zcJGNBhG3ZaznIosr3WBezN/xwu6Nyy8Oe4iqg9BaVnzwdVE3+t22sZ0EMrIVPliVBbfBAjKm8MW0S3w7W9MIbKO93h0KbgQF8UfYXKyq35UumqHW+sFpwek+2t1KrErP07lZIp/WPdUVBr5gN9XXl7GuZkZcT1zp1WS4IqeGltqO5OrgFaOOk4FhWUhvHFDJO0z58Zjsz54ojs9BScfwxB5YmjUenvfeDVsa0y6G2LgeyvUCmRbdgBLsUWlO6gf3Vs19pFFTm82xTOSVkoaK7njgZ1tLuKPGSnXEWqNmTLPi5u1F6rUMP5otprFa52tFG1KV7+fBDCUh/HkajW+HqyY0HAuXgVEVrvJ0W21zqXBptmc4VLh08dwY+LtftVZemaCGM27bXc0ayBdlcRi/AQ7e51QYyo/DFsEdldDtK+nau2Jeo/HG5FtCWy5tq8kxpoNuyy6QPLIielpJ6rbLl1fFSZn3njamTskEdLEfjaWwc+fxEAZZXieRi3xxTZAD5922q1+rB98/x2Mnof7UzGa0UsT1EzuR3qtVC/1EJ3IbOYbhbyrJfN0sarbkM4Xlciky033W1VUimRi4tVytgjwk+Kp9aWSxuQjPDDWep962kV6TimnY2oiIvA2203o3GAGNqGI1yErbiYgtIeW+k4/vM5qxKnottrXVcSd3Efpg5cjWBlCNXOjnSBV2Bd9Hu7AYYqjyUXBCi12kW317KVi2NxVsuZfho/zjyHrdrDR0TIfMSnUHutF33R3LqaMC4J4cUGMaLyx7BFZEfGKzG4+n/DkbU2FvAdBpdRpbgsT61H4NDMCUiZj6wPd9p02mmMX4O0T9Zoj0op4FE4ygYzsd8hb4+4bfMInAsFPo8hY6GX7e5XTkLKVtuOPLP3f4dM5Qw/sexPt81ffqdaWmPz31fbXPNR6Xx09n/vTNuuCp3h9IQ44Of8jOz3fr6uy4asiO+Q/MQoXLF0LOtXXQ22R7YhS+s8VSE7Of1sEnJt+/O8OWJe18LCkRZbqLPTIpRUSuTV0BvKCZjSxSy81mMNXpu0A1/O3YGpr65Cx4AIjOgTjlVx2jtV90FbdTMJuRj35G+YKqad9dZqdOtRcGbf85+2RWcRRlKTrC4mtTYO417fLOa9GeN6hKDbWwW9mRXXXqtwSZzIUMjeliumkUMCZn20DzsPnkTUjn34/tWj+e3LqowNRD9ZK1lc/1o2nyMPnz67Uf3ck0IwoHMExmnXUKwyNBAfPC+XrFB7rRY+Nm3VbNprFQ5iRHbAsEVUbtYg+7kRuGwZgnsgOVh2xCmClt8wOH86Fp4e2qQ35APP8ZOgdxVBZtObuPZEsDq/4X2R/MJ0mD3K2ubLE87du2v3xT99z07yGGirUnd4TlP708qbId5HLLflPVPHzVf639JPmAZPq7d27PgUHOVjec3H4L75018ZLD7zRf87VN3oBM/Rc0S49ASiZiNzcA+b7ZE2QXwWj9ow+Gkle36Pan157YTx1R64onzuYCT26YvsdTnQ+aqT4drNF3FlrpuOzEmvIuvVxYX6OyushFIiqU57fLDAxar6LQ+r5l7C1EmX8OVitYPPwEHeqJ9fIlYXg962mv5Ulggol/DpN7lap54GPP9TF3zQV20DVb+dt03bpZ3fXxXzvoof4wxokx92ytBeq0Jj/H1yQQDbOuUkgrvsQ5/HT+JdsbxS4PBArJ7cQi0xLbK9llQXz39i3che+9xztY5Thc5jamP15+21gHqj9lo3DmJE9sCwRVRu0mA+F1MwZPpA10oEkmm/wvuHsfCyHLhLwVC9D7wXL4LjI83FD/lYdX45LWAYtxxe49Se6MvCpeOj2j97n0JViAWc2oyG94Jv4divO3SZ2mdI8YSu41g4L14On17+tk1lDLXgPWc5nOT0hiTtM1eGrt80uH4twqI22W1n8If3jF/hNnEs9LWcCraH7B1++OfwWPweKuQ3fBfhbOxiuI4bBl0lsV6uiOkS09TPvGARXB9Tq0rzDp++6ZpRp3pt1c5Xm9ex6cfrOucSsPVGpUQKAwKH9MGGLYGYYN3YvI4B/V6sgs+2dEXYD13QrELBa6sM6os/Nvjh+UEF0we2c8Hz02pjw+nHRdAq6ArCuWtHpaPRRywdfor5/v3d2tge3gg9tVKwgvZaeYjaU1J7LRc0e/tx7PvN9v2riM8ml/fr0J4IkwFJWzFF96+lcm7XFYt311Y+d31LCFM+tx8W7e+N5f9pkz+fG7fXulEQI7IPnVnQ7hPR/erKBiQFT4LpkU/gPbFzyVWZRERUbliyRfQAyNqzFSY4wdC1HYMWEdFtxrBFdJ/LS9yJjK+3ARWegmObUvY+T0RE5YbViET3qcz105G+eCfMCUnikRP0E0Lg06vo9lpERGQ/LNkiul+Z0tSgVaEzDDNWw5tBi4jojmDJFhEREZEdsWSLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyI4YtoiIiIjsiGGLiIiIyG6A/wfwoM2GteajqAAAAABJRU5ErkJggg==" + } + }, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Define recursion and be able to identify \n", + "- the base case\n", + "- the recursive case\n", + "- infinite recursion" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "# In math, you can define the factorial of a number in terms of the number before it. \n", + "# Q: What is the value of 84! (84 factorial)\n", + "# A: 84! = 84 * 83!\n", + "\n", + "# What are we still missing?\n", + "# A: The base case: 0! = 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### A recursive algorithm must have 2 parts:\n", + "- the base case....which stops the recursion\n", + "- the recursive case...which defines the same process in a smaller way\n", + "\n", + "#### If there is no base case what happens in the above example? \n", + "- recursion never ends......infinite recursion\n", + "- infinite recursion can also happen if the recursive case does not move towards the base" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Writing Definitions Recursively" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Define the sequence 1, 3, 5, 7, 9, 11... recursively\n", + "# Base Case: seq_0 = 1\n", + "# Recursive Case: seq_n = seq_(n-1) + 2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Define whether a positive number is odd recursively\n", + "# Base Case: 1 is odd\n", + "# Recursive Case: True if (n-2) is odd, False otherwise" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Writing Recursive Code" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "6\n", + "720\n" + ] + } + ], + "source": [ + "def factorial(n):\n", + " if n == 0:\n", + " return 1\n", + " return n * factorial(n - 1)\n", + "\n", + "print(factorial(0))\n", + "print(factorial(3))\n", + "print(factorial(6))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Write and try `is_odd` in [PythonTutor](https://pythontutor.com/render.html#code=def%20is_odd%28n%29%3A%0A%20%20%20%20if%20n%20%3D%3D%201%3A%0A%20%20%20%20%20%20%20%20return%20True%0A%20%20%20%20elif%20n%20%3D%3D%200%3A%0A%20%20%20%20%20%20%20%20return%20False%0A%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20if%20n%20%3C%200%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20is_odd%28n%20%2B%202%29%0A%20%20%20%20%20%20%20%20else%3A%0A%20%20%20%20%20%20%20%20%20%20%20%20return%20is_odd%28n%20-%202%29%0Aprint%28is_odd%28-3%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=311&rawInputLstJSON=%5B%5D&textReferences=false)" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "def is_odd(n):\n", + " if n == 1:\n", + " return True\n", + " elif n == 0:\n", + " return False\n", + " else:\n", + " if n < 0:\n", + " return is_odd(n + 2)\n", + " else:\n", + " return is_odd(n - 2)\n", + "is_odd(-3)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Can we write them iteratively instead?" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1\n", + "6\n", + "720\n" + ] + } + ], + "source": [ + "def factorial_itr(n):\n", + " prod = 1\n", + " for i in range(1, n + 1):\n", + " prod *= i\n", + " return prod\n", + "\n", + "print(factorial_itr(0))\n", + "print(factorial_itr(3))\n", + "print(factorial_itr(6))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Other Recursive Problems" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Go back and complete Warmup 2.C" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "13\n", + "40\n", + "20\n", + "10\n", + "5\n", + "16\n", + "8\n", + "4\n", + "2\n", + "1\n" + ] + }, + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 12, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# The Collatz Conjecture problem \n", + "# Conjecture: Any positive integer n, put through the below equation\n", + "# will always converge to 1.\n", + "#\n", + "# https://en.wikipedia.org/wiki/Collatz_conjecture\n", + "# https://www.youtube.com/watch?v=5mFpVDpKX70\n", + "# >$1 million award for solving. And likely an honorary doctorate.\n", + "# Run this in Python Tutor on your own\n", + "\n", + "def collatz(n):\n", + " print(n)\n", + " if n == 1:\n", + " return 1 # base case\n", + " elif n % 2 == 0:\n", + " return collatz(n//2)\n", + " else:\n", + " return collatz (3*n+1)\n", + "\n", + "collatz(13) # try other numbers\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Trace a recursive function involving nested data structures" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "False\n" + ] + } + ], + "source": [ + "fav_stuff = [ \"road bike\",\n", + " [\"PB&J\", \"brownies\", \"spaghetti\", \"apples\"] , \n", + " (\"Brooks Ghost 13\", \"hoodie\", \"gloves\"), \n", + " \"macbook air\", \n", + " [ \"Johndee.com\", \"https://www.weather.gov/mkx/\"],\n", + " [\"A\", \"K\", (\"S\", \"D\", \"K\")]\n", + " ]\n", + " \n", + "print (\"road bike\" in fav_stuff)\n", + "print (\"brownies\" in fav_stuff) # Why is this False? " + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "# Write a recursive function to search *ANY* list of lists/tuples for a given word\n", + "# Modify your code from Warmup 2.C\n", + "def search_list_recursive(target, some_list):\n", + " ''' returns True if thing in some_list, False otherwise'''\n", + " for list_item in some_list:\n", + " if target == list_item:\n", + " return True\n", + " elif type(list_item) == list or type(list_item) == tuple:\n", + " is_in_next = search_list_recursive(target, list_item)\n", + " if is_in_next:\n", + " return True\n", + " return False # after all possible searching....not found\n", + "\n", + "print(search_list_recursive(\"apples\", fav_stuff))\n", + "print(search_list_recursive(\"D\", fav_stuff))\n", + "print(search_list_recursive(\"road bike\", fav_stuff))\n", + "print(search_list_recursive(\"pizza\", fav_stuff))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "road bike\n", + "<class 'list'>\n", + "\tPB&J\n", + "\tbrownies\n", + "\tspaghetti\n", + "\tapples\n", + "<class 'tuple'>\n", + "\tBrooks Ghost 13\n", + "\thoodie\n", + "\tgloves\n", + "macbook air\n", + "<class 'list'>\n", + "\tJohndee.com\n", + "\thttps://www.weather.gov/mkx/\n", + "<class 'list'>\n", + "\tA\n", + "\tK\n", + "\t<class 'tuple'>\n", + "\t\tS\n", + "\t\tD\n", + "\t\tK\n" + ] + } + ], + "source": [ + "# write a function that prints nested lists with indenting\n", + "# \n", + "def print_with_indenting(directory, indent_level):\n", + " for thing in directory:\n", + " if type(thing) == list or type(thing) == tuple:\n", + " print(\"\\t\" * indent_level + str(type(thing)))\n", + " print_with_indenting(thing, indent_level + 1)\n", + " else:\n", + " print(\"\\t\" * indent_level + str(thing))\n", + " \n", + "print_with_indenting(fav_stuff, 0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Dictionaries can have a recursive structure\n", + "As can...\n", + "- lists\n", + "- dictionaries\n", + "- JSON objects" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "ancestry = {\n", + " \"name\": \"Evan\",\n", + " \"age\": 28,\n", + " \"born\": \"Sheboygan\",\n", + " \"parent\": {\n", + " \"name\": \"Dean\",\n", + " \"age\": 53,\n", + " \"born\": \"Milwaukee\",\n", + " \"parent\": {\n", + " \"name\": \"Mike\",\n", + " \"age\": 74,\n", + " \"born\": \"Racine\",\n", + " \"parent\": {\n", + " \"name\": \"Bill\",\n", + " \"age\": 96,\n", + " \"born\": \"La Crosse\"\n", + " }\n", + " }\n", + " }\n", + "}" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'Sheboygan'" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# let's try to search through a deep dictionary. \n", + "def find_place_of_birth(target_name, ancestry_history):\n", + " if ancestry_history['name'] == target_name: # base case\n", + " return ancestry_history['born']\n", + " else:\n", + " if 'parent' in ancestry_history:\n", + " return find_place_of_birth(target_name, ancestry_history['parent']) \n", + " return \"Unknown!\"\n", + "\n", + "find_place_of_birth(\"Evan\", ancestry)" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "16807" + ] + }, + "execution_count": 18, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Extra practice...can you predict the outcome?\n", + "# run this on your own in Python Tutor\n", + "\n", + "def mystery(a, b): \n", + " # precondition: a > 0 and b > 0\n", + " if a < 0 or b < 0:\n", + " return None\n", + " if b == 1: \n", + " return a;\n", + " return a * mystery( a, b - 1 )\n", + "\n", + "# make a function call here\n", + "mystery(7, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "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.10.12" + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} -- GitLab