Skip to content

Instantly share code, notes, and snippets.

@wasade
Last active December 5, 2017 20:24
Show Gist options
  • Save wasade/8352109 to your computer and use it in GitHub Desktop.
Save wasade/8352109 to your computer and use it in GitHub Desktop.
Python programming tutorial for the Workshop on Genomics 2014.
Display the source blob
Display the rendered blob
Raw
{
"metadata": {
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Programming Tutorial \n",
"\n",
"[Workshop on Genomics](http://evomics.org)<br />\n",
"Cesky Krumlov, January 2014\n",
"\n",
"Author: [Daniel McDonald](https://sites.google.com/site/danielmcdonaldisalreadyused/home)<br \\>\n",
"License: [CC0](http://creativecommons.org/publicdomain/zero/1.0/)<br \\>\n",
"Twitter: [@mcdonadt](https://twitter.com/mcdonadt)"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Introduction"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Programming is a form of expression in which you describe structure and operations on that structure. Practically, programming offers ways to automate repetitive tasks, construct workflows, and organize data such that you can effectively ask questions. In the context of genomics, being able to organize and manipulate data is critical as the volume of DNA sequence returned from next-generation sequencing technologies is staggering and beyond human interpretation in its raw form.\n",
"\n",
"Programming is an incredibly powerful tool for data analysis for researchers as often times questions arise that cannot be answered with the present tools available. Having a cursory handle on how to use at least one language expands the utility of your computer infinitely, and in turn, widens the types of questions that, as a researcher, you can ask of your data. And, more importantly, programming is FUN!\n",
"\n",
"Beyond this very light tutorial, Zed Shaw's [Learn Python the Hard Way](http://learnpythonthehardway.org/) is excellent and free. LPTH will go into much more depth than we can do within this tutorial. When working through this tutorial, or any tutorial on programming, it is essential to work through the exercises. Like a spoken language, you won't learn without using. And, once you've mastered the basics and are itching for more bioinformatics challenges, go check out [Rosalind](http://rosalind.info/problems/locations/) for exciting problems to tackle! Additionally, there are a large number of IPython Notebooks (like this one) available [here](https://github.com/ipython/ipython/wiki/A-gallery-of-interesting-IPython-Notebooks) for programming pleasure.\n",
"\n",
"This tutorial will discuss the following topics:\n",
"\n",
"* IPython, which provides these really sweet notebooks :)\n",
"* How to get help when you're on your own and creating the next generation of awesome\n",
"* Variables and types to store and refer to data\n",
"* Programmatic flow to structure logic\n",
"* An intermission, because caffeine is the programmers petrol\n",
"* A quick interlude on making pretty pictures\n",
"* Complex types that let you store and refer to data more efficiently, these are the powertools of Python\n",
"* Introduction to functions, or the discrete little building blocks of a program\n",
"* The basics of reading and writing files"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Why Python?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Python is a mature programming langauge that has a wonderful community of developers, and broad support within the sciences. The language is fast and friendly, and can interface with external programs and code written in other languages quite easily. In general, Python tends to be easier for beginners to adopt as it is considerably more readable and quicker to debug than many other languages, but it is by no means just a \"beginner\" langauge. It is a powerhouse. If you're interested, below are a few major Python projects and organizations using Python:\n",
"\n",
"* [IPython](http://ipython.org), elegant extensions to Python (which we're using!)\n",
"* [NumPy](http://www.numpy.org) and [SciPy](http://www.scipy.org), which underpin many of the numerical and scientific capabilities of Python\n",
"* [Pandas](http://pandas.pydata.org/) for your data analysis needs\n",
"* [SciPy](http://scipy.org/) provides a wealth of functionality geared for the scientific community\n",
"* [Scikit-learn](http://www.scikit-learn.org) for all your supervised and unsupervised machine learning needs\n",
"* [Tornado](http://www.tornadoweb.org/en/stable/), the web-framework that powers Facebook\n",
"* [Google](http://www.google.com) relies heavily on Python and even employed the author of Python, [Guido van Rossum](http://en.wikipedia.org/wiki/Guido_van_Rossum)\n",
"* [Reddit](http://www.reddit.com) is 68% Python (and you can look at their [source code](https://github.com/reddit/reddit)!)\n",
"* [Dropbox](http://en.wikipedia.org/wiki/Dropbox_(service) is written in Python\n",
"* ...[the list goes on](https://wiki.python.org/moin/OrganizationsUsingPython) "
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Getting started"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Getting started is quick and easy! This tutorial assumes that you have IPython available on your system, which is true for all the Workshop on Genomics participants. Below are the 4 steps to take to get started:\n",
"\n",
"* open the [notebook](http://nbviewer.ipython.org/gist/wasade/8352109)\n",
"* download the notebook (look in the upper right corner). Make sure to right-click and save as.\n",
"* from a terminal, change to the directory the notebook was downloaded to and start the IPython Notebook (this will open a new browser tab):\n",
" * ``cd ~/Downloads``\n",
" * ``ipython notebook``\n",
"* select \"Python tutorial\" from the list of available Notebooks in the new browser tab that opened"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"IPython"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"[IPython](http://ipython.org) is an extension to Python that provides a more interactive environment. Recently, the IPython project pushed out their Notebook interface with the intent of [facilitating reproducibility](http://nbviewer.ipython.org/) and with an emphasis on the sciences. These notebooks can be saved and distributed later very easily, and essentially any content can be embedded. Further details and tutorials about the Notebook itself can be found [here](http://ipython.org/ipython-doc/dev/interactive/htmlnotebook.html). \n",
"\n",
"The notebook is based on cells. Each cell can be executed in any order. Executing a cell makes the code and variables run within the cell available to the entire notebook. The cells can be executed by clicking either the play button or by pressing \"shift + enter\". Cells can contain code or text. For instance, try double clicking on this text.\n",
"\n",
"You can change the \"type\" of a cell by selecting from the pull down menu above. This cell will have \"markdown\" selected as its type. "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now lets try writing a really small piece of code and executing it. To do so, select the \"Insert\" menu and click \"Insert cell below\". This will create a new box below that you can type into. Please add the following:\n",
"\n",
"``print \"Hello world!\"``\n",
"\n",
"And then execute the cell (hint, press \"shift + enter\"). You're now a programmer -- time for [champagne](http://xkcd.com/323/)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One other quick note about IPython, just like in the terminal, the tab key is your best friend."
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"How to get help"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Google is your number one ally. Often, you can search for the types of errors you encounter and get a direction to follow to resolve your problem. If that fails, [Stack Overflow](http://www.stackoverflow.com) is a free user-driven programming community that is highly regarded and is an excellent source of information and a place where you can ask questions. It is very easy to use and people are eager to respond as there is a motivation system built in. Additionally, the search interface actually works and you may be able to mine for your problem there. Last, [seqanswers](http://www.seqanswers.com) may be able to assist on problems that may be more bioinformatic in nature.\n",
"\n",
"Python itself contains a heavy amount of documentation. This stems from the easy mechanisms to document code within the language. You can call help() on just about everything and generally get back useful information. Try the following into the free cell below and executing it:\n",
"\n",
"``help(1)``"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Who knew the number 1 was so detailed... IPython has some syntactic sugar though for you and you can simply prefix on a question mark:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"?help"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"IPython Notebook extends the help() with tool tips. Type the following into the open cell below (but don't execute the cell):\n",
"\n",
"``plot(``\n",
"\n",
"Don't put the closing parenthesis and wait a few seconds. A help box will appear describing the function and what to pass. This is a good place to start, at least for how to use a particular function."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Before we go on..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The only way to learn to program is to actually program. This tutorial is setup to be interactive (and fun!). Parts of the tutorial will require that you execute a cell in order to get output, parts of it will require that you write your own code in a cell. The cell below has not been executed, but once it is run (hint, press shift + enter), it will tell you the version Python being used and the current date and time:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import sys; import datetime\n",
"print \"The version of Python being used is %d.%d\" % (sys.version_info.major, sys.version_info.minor)\n",
"print datetime.datetime.now().ctime()"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Don't worry the above does not make sense yet. Please play with the examples in the tutorial, and try to break things: you will learn a lot by what does not work."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now, lets learn a little bit more about how IPython works before we get a head of ourselves. An executed cell can change the state of your environment, which is a really just a fancy way of saying \"your actions have consequences.\" To illustrate this, there are two cells below. The first cell will complain about an unknown variable when executed (we'll discuss variables shortly). The second cell will create the variable and assign it a value. What happens when if you re-execute the first cell?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print \"The answer to the Ultimate Question of Life, The Universe, and Everything is: \", ultimate_answer"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"ultimate_answer = 42"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The next set of cells highlight show what comments are, and two common errors that you will likely encounter as you experiment in this tutorial. Don't worry to much about these right now, this is mostly for reference."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# anything following a # is a comment and is not executed"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print does_not_exist # Python will whine and complain when trying to access an unknown object "
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print ,\"the comma is wrong here\" # Python complains when it cannot interpret what you're telling it to do"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Variables and types"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Variables hold information, like a string that represents DNA, or a floating point number representing G+C content, or maybe an integer that describes the number of sequences that came screaming off your friends HiSeq2000. Variables have a type that is associated with them. This is incredibly important within programming: the type is how the machine interprets the 1's and 0's that reside in the systems memory, and different types have different properties and constraints. Types are important for optimization as the language can make more efficient use of memory and low level processes if the types used match your problem well. Lets explore a few basic types that are available within Python (and many programming languages, for that matter)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"First, lets create an integer (a whole number):"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_int = 5\n",
"print my_int\n",
"print type(my_int)"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So what though? Since an integer can only be a whole number, what happens if you divide by 2?"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print my_int / 2"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That's a little annoying but it is important to realize this can lead to \"fun\" bugs in your program. If you instead divide by a floating point number, or one that has a decimal, Python will perform what is known as a type promotion where the number that is not a float will become one.\n",
"\n",
"So what are these floats? Lets create one"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_float = 2.123\n",
"print my_float\n",
"print type(my_float)"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"How are floating point values represented in 1's and 0's? In short, a portion of the 1's and 0's of memory that holds the number describes the mantissa, and a portion describes the exponent. While this works very well, it is possible that floating point numerical errors can happen if you perform operations on very large numbers and very small numbers -- logarithms are your friend. As a consequence of how floating point numbers are represented, there is a limit to the resolution of the numbers. The smallest difference between two floating point numbers that can be represented on a computer is known as machine epsilon. Let's see what it is:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print sys.float_info.epsilon"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"That syntax was slightly weird though, right? In the last cell, we were asking Python to fetch the object ``epsilon`` from the ``float_info`` object, which we were in turn asking to retrieve from the ``sys`` object. (hint, type ``sys.`` and then press your tab key to see what is contained within ``sys``)"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Last, lets create a string. Strings are one way that a piece of DNA can be represented on a computer:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_str = \"aattggcc\"\n",
"print my_str\n",
"print type(my_str)"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Strings have some additional operators associated to assist pulling out substrings, or parts of the string. Try the following:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print my_str[0]\n",
"print my_str[1]\n",
"print my_str[2]\n",
"print my_str[1:5]"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now try over reaching, or stepping out of bounds (this will trigger an error):"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print my_str[10000]"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The output you're looking at is known as a traceback. This helps the programmer debug by identifying the offending line of code. In a complex Python program, the traceback may contain many lines indicating the path of execution and the location of the failing piece of code. They always end with the specific exception that was thrown. Try Googling the exception (``IndexError: string index out of range``) to learn a little more."
]
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Variables and types exercises"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Before moving on, lets work through two exercises:\n",
"\n",
"* Using a single print statement, print three lines such that the first line contains a string, the second line contains a float and the third contains an integer. (hint: a line break, or newline, can be represented with a \"``\\n``\" character)\n",
"* Explore the string using your tab character to see what methods are part of the string. Try to figure out what a few of the methods do, and see if you can use them. (hint: my_str.some_interesting_method())\n",
"\n",
"Remember, you can add new cells by using the \"Insert\" menu above, or one of the shortcut keys on the toolbar."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Flow"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In some senses, programming can be conceptualized with a [flow chart](http://xkcd.com/518/). Right now, we can add in lines into a single cell in the notebook and execute them, however, the execution will only be linear. Do this, then this, then this. Pretty boring. What we really want is to be able to, say, walk over a piece of DNA (i.e. looping) or perhaps execute different code based on the presence of a particular k-word (i.e. if-statements). More generally, these operations are forms of flow control. Lets first experiment with an if-statement. The idea is simple: if this thing is true, do this, otherwise do that."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"if 5 > 0:\n",
" print \"thats refreshing\"\n",
"else:\n",
" print \"this language is broken\""
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One important comment about if-statements. Python cares about whitespace (the emtpy space preceeding the two print statements), and uses whitespace to define scope, which is a fancy programming word that is similar to parantheses in math as it groups operations. Scope may also be described as blocks. In Python, 4 single spaces are used to denote a level of scope. There are two important pitfalls here, the first being that scope matters and the second being that the amount and type of whitespace matters. Below are a few more examples:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# the first print statement is only indented 2 spaces\n",
"if 5 > 0:\n",
" print \"thats refreshing\"\n",
"else:\n",
" print \"this language is broken\""
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"if 5 > 0:\n",
" print \"that's a refreshing\"\n",
"else:\n",
" print \"this language is broken\"\n",
" print \"this print statement is within the else block\"\n",
"print \"this statement is outside of the else block\""
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"if 5 > 0:\n",
" print \"that's a refreshing\"\n",
"else:\n",
" print \"this language is broken\"\n",
" print \"this print statement is within the else block\"\n",
"print \"this statement is outside of the else block\"\n",
" print \"only certain statements, such as an if-statement, can create a new scope\""
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The if-statement operates on boolean logic. If the conditional (the 5 > 0 part) evaluates as ``True``, the block of code underneath the conditional will be executed. Try just typing ``5 > 0``:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print 5 > 0"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Variables can be used in the conditional as well. For instance:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"length_of_dna = len(\"aattggcc\")\n",
"if length_of_dna > 5:\n",
" print \"our DNA is over 5 nucleotides long\"\n",
"else:\n",
" print \"our DNA is really short!!!\""
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In the preceding example, we used a Python built in function called ``len()``. Before moving on, learn a little more about it and experiment with it. Does ``len()`` work on integers? How can we use a if-statement if we have multiple conditions? (__hint__: ``elif``)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We can now perform conditional operations. That's super cool, right? Think of all the things you could conditionally do now, like, drink a beer if the right one is available. But, what if there are a lot of different types of beer, and we want to evaluate each of them? In pseudocode, or Englishy-programming-sounding-code, we'd say something like \"for each beer, if I want the beer, drink the beer.\" (we could simplify the logic: \"for each beer, drink the beer.\") This construct is called a for-loop. Try the following:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_dna = 'aattggcc'\n",
"for nuc in my_dna:\n",
" print nuc"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We've now iterated over our DNA. We could interpret the code above as: for each nucleotide in ``my_dna``, store that character in the variable ``nuc``, and then print the contents of the variable ``nuc``. But, what about the beer???"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for beer in ['lager','pale ale','pilsner','stout','porter']:\n",
" if beer == 'pilsner':\n",
" print \"when in cesky, go pilsner or go home\""
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We've introduced a few new things here. First, what's this funky thing in the square brackets? It's known as a list, and we'll dive into lists in the next section (but please experiment!). Second, we introduced a new type of evaluation, the ``==`` operator. A single equals sign is used to denote assignment, like when we stored the integer in my_int. Two equals signs together indicates the equals operator and is used to test whether two things are equal to each other. For instance:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print 5 == 5\n",
"print 5 == 6"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A few other important boolean evaluations are: ``<``, ``>``, ``!=``, ``>=`` and ``<=``. What do they do? "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"There's one more important loop known as a while-loop. The structure is: ``while <conditional>``. See if you can recreate either of the for-loops above using a while-loop instead of the for-loop. (__hint__: replace ``<conditional>`` with some type of logical test). (__hint2__: it is possible to enter an infinite loop if your conditional will always evaluate true. If this happens, select the \"Kernel\" pull down menu, and click \"Interrupt\".)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Before moving to the next section, there are a few more interesting and very useful operators (beyond ``+``, ``-``, ``*``, and ``/``). Play with the following and try and figure out what they do: ``%``, ``+=``, and ``-=``. "
]
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Flow exercises "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Lets experiment a little bit with programmatic flow:\n",
"\n",
"* Given a sequence, determine if it contains an ambiguous base (i.e., N)\n",
"* Produce a sequence that is 30 bases long that repeats AT (i.e., ATATATAT....)"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"sequence_1 = 'AATTATGGCACAGAT'\n",
"sequence_2 = 'AATGACNATAAT'\n",
"sequence_3 = 'GATANNATATTAC'\n",
"sequence_4 = 'GGCCAGAGACAG'"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 1,
"metadata": {},
"source": [
"INTERMISSION!!! "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We've learned quite a bit so far. First, we discussed IPython and how to get help when you're on your own, hacking away and making your computer do your bidding. Next, we talked about basic ways to represent data, some of the primitive types and variables which let us store data such as a DNA sequence, or the location of a SNP in a genome. We them moved on to programmatic flow, and ways we can control what happens in a program. Flow lets us, for instance, iterate over a set of GenBank records and only process those that correspond to a particular organism. \n",
"\n",
"There are a few more basics to go through: \n",
"\n",
"* Complex types, the power tools of Python\n",
"* Introduction to functions\n",
"* The basics of reading and writing files\n",
"\n",
"But before we get there, lets make some pretty pictures and work through a few complex examples. Don't worry if these don't make sense yet as we've still got a few concepts to go through. And, it is useful to see the types of things that you'll be able to do in the near future!\n",
"\n",
"In the first example, we're going to create a histogram showing bimodal distributions. The data will be randomly drawn from an exponential distribution and from a normal distribution. This example will cover things we have not discussed yet, the intent is to highlight what can be done with relative ease. Further examples of histograms, including source code, can be found [here](http://matplotlib.org/examples/pylab_examples/histogram_demo_extended.html)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# make sure pylab is available (this is an IPython \"magic\" command)\n",
"%pylab inline\n",
"\n",
"# numpy is a numerical library that provides additional (and very useful) functionality. Basically,\n",
"# its a bunch of code that already exists and we're reusing it. This next statement lets is telling\n",
"# Python to import two functions, exponential and normal, from the random module of numpy.\n",
"from numpy.random import exponential, normal\n",
"\n",
"# pull 10000 random values from an exponential distribution\n",
"exponential_values = exponential(size=10000) \n",
"\n",
"# pull 20000 random values from a normal distribution with a mean of 1 and std of 2\n",
"normal_values = normal(loc=1, scale=2, size=20000)\n",
"\n",
"# Create the histograms. The histogram function returns information about the histogram\n",
"# which we're storing in the variable hist_info simply so it doesn't clutter the output.\n",
"# We are passing in a few different pieces of information into these functions:\n",
"# color : the color of the histogram\n",
"# alpha : the level of transparency, where 0.0 is completely transparent and 1.0 is opaque\n",
"# bins : the number of bins to use in the histogram\n",
"# histtype : the type of the histogram (in this case, we are not showing the boundaries on the bars) \n",
"hist_info = hist(exponential_values, color='red', alpha=0.5, bins=100, histtype='stepfilled')\n",
"hist_info = hist(normal_values, color='blue', alpha=0.5, bins=100, histtype='stepfilled')\n",
"\n",
"# let's label our plot\n",
"title(\"A pretty picture\")\n",
"ylabel(\"Number of values\")\n",
"xlabel(\"The actual value!\")\n",
"legend([\"Exponential\", \"Normal\"])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"output_type": "stream",
"stream": "stdout",
"text": [
"Populating the interactive namespace from numpy and matplotlib\n"
]
},
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 2,
"text": [
"<matplotlib.legend.Legend at 0x10f74fad0>"
]
},
{
"metadata": {},
"output_type": "display_data",
"png": "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\nSUVORK5CYII=\n",
"text": [
"<matplotlib.figure.Figure at 0x10f716050>"
]
}
],
"prompt_number": 2
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The second example will (naively) generate random DNA sequences, compute G+C content and the number of unique k-mers in each sequence, and produce a scatter plot. Here is another [example](http://matplotlib.org/examples/pylab_examples/scatter_symbol.html) of a scatter plot with source code. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# random is a builtin Python module\n",
"from random import choice\n",
"\n",
"# join will let us combine individual nucleotides together into a sequence\n",
"from string import join\n",
"\n",
"# Create 1000 sequences that are each 1000 nucleotides long\n",
"n_sequences = 1000\n",
"sequence_length = 1000\n",
"\n",
"# Set the kmer_length to use\n",
"kmer_length = 4\n",
"\n",
"gc_content = [] # This is a list, we'll learn about them shortly\n",
"number_of_kmers = []\n",
"for i in range(n_sequences): # range is nifty, what does it do?\n",
" nucleotides = []\n",
"\n",
" # build up a list of individual nucleotides represented as single characters. The probability\n",
" # that any given nucleotide will be chosen is equal\n",
" for j in range(sequence_length):\n",
" nucleotides.append(choice('ATGC'))\n",
" \n",
" # smash all the nucleotides together to form a string. The seperator between each nucleotide\n",
" # an empty string.\n",
" sequence = join(nucleotides, sep='') \n",
" \n",
" # sequence is a list here, and lists know how count items contained within\n",
" guanines = sequence.count('G')\n",
" cytosines = sequence.count('C')\n",
" gc = (guanines + cytosines) / float(sequence_length) # why are we using float here?\n",
" gc_content.append(gc)\n",
" \n",
" # what is all this voodoo?\n",
" kmers = set() \n",
" for nucleotide_position in range(0, sequence_length, kmer_length): \n",
" kmers.add(sequence[nucleotide_position:nucleotide_position + kmer_length]) \n",
" number_of_kmers.append(len(kmers))\n",
"\n",
"scatter(gc_content, number_of_kmers)\n",
"ylabel(\"Number of k-mers\")\n",
"xlabel(\"G+C content\")\n",
"title(\"Meaningless points\")"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 3,
"text": [
"<matplotlib.text.Text at 0x10f7b9910>"
]
},
{
"metadata": {},
"output_type": "display_data",
"png": "iVBORw0KGgoAAAANSUhEUgAAAYoAAAEVCAYAAAD+TqKGAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzsnXd4VMX6x79bs3t2N70npCekQgIBQk1QkCIgAkJAEMFe\nwAIWuAiIKCpyVe61oD+Vy7Wg4FVEQYoYRQSliAaQJhBKQkggpLfd/f7+OCdLIiEJGBKE+TxPnmd3\nzsw775yzmffMzDvvqEgSAoFAIBBcAHVrKyAQCASCKxthKAQCgUDQIMJQCAQCgaBBhKEQCAQCQYMI\nQyEQCASCBhGGQiAQCAQNIgyF4Krm6NGjsFgsaA4v8NmzZ2PcuHHNoNXlZePGjYiOjm5tNQRXEcJQ\nCC4rISEhcHJywunTp+ukJyUlQa1W4+jRo5e1/qCgIBQXF0OlUv1lWc0hoyXo2bMn9u7d26S8GRkZ\naNOmzWXWSPB3RxgKwWVFpVIhLCwMH330kSMtMzMT5eXlf5uOtwaxN1VwrSIMheCyM3bsWCxZssTx\n/T//+Q9uu+22Oh1vZWUlpk6diuDgYPj6+uK+++5DRUUFAODs2bMYNGgQvL294e7ujsGDB+PEiROO\nsmlpaZg5cyZ69OgBZ2dn9OvXzzGCOXLkCNRqNex2e6N5AWDJkiUIDg6Gp6cn5s6di5CQEGzYsKHe\ndm3ZsgXdunWDm5sbEhMT8d133zmuLV68GOHh4XB2dkZYWBg+/PBDAMDBgweRmpoKV1dXeHl5IT09\nvV7ZNXq//fbbCAgIgL+/PxYsWFDnfj388MMICAhAQEAAHnnkEVRVVQE4f5QQEhKCBQsWoH379nB1\ndUV6ejoqKytRWlqKAQMGIDs7GxaLBc7Ozjh58iR+/vlnJCcnw8XFBb6+vpgyZUpDj1dwLUCB4DIS\nEhLC9evXs23btvz9999ptVoZGBjIrKwsqlQqZmVlkSQffvhh3nTTTSwoKGBxcTEHDx7MadOmkSRP\nnz7N//3vfywvL2dxcTFvueUWDh061FFHamoqIyIieODAAZaXlzMtLY1PPvkkSfLw4cNUqVS02WyN\n5t29ezfNZjM3bdrEqqoqTp06lTqdjt988w1JctasWRw7dixJ8vjx4/Tw8ODq1atJkuvWraOHhwfz\n8/NZUlJCZ2dn7t+/nyR58uRJ7t69mySZnp7O5557jiRZWVnJTZs21XvfavQeM2YMy8rKmJmZSS8v\nL65fv54k+dRTT7Fr167My8tjXl4eu3Xrxqeeeook+e233zIwMLDOM+jSpQtzcnJ45swZxsTE8M03\n3yRJZmRk1MlLkikpKXz//fdJkqWlpdyyZUuTn7fg6kSMKAQtwrhx47BkyRKsW7cOsbGxCAgIcFwj\nibfffhv//Oc/4erqCrPZjGnTpmHp0qUAAHd3d9x8880wGAwwm82YPn16nbd3lUqFCRMmICIiAgaD\nASNHjsTOnTvr1aOhvMuXL8eQIUPQrVs36HQ6zJkz54LTY++//z4GDhyI/v37AwD69OmD5ORkfPXV\nV1CpVFCr1Y4pNh8fH8TGxgIA9Ho9jhw5ghMnTkCv16Nbt24N3rdZs2bBaDQiPj4eEyZMcEzhffDB\nB5g5cyY8PT3h6emJWbNm4b///e8F5UyePBm+vr5wc3PD4MGDHW1mPdNper0eBw4cQH5+PiRJQpcu\nXRrUUXD1IwyF4LKjUqkwbtw4fPDBB/VOO+Xl5aGsrAwdO3aEm5sb3NzcMGDAAOTn5wMAysrKcM89\n9yAkJAQuLi5ITU1FYWFhHRm+vr6Oz0ajESUlJRfU50J5s7OzERgYWOeah4dHvTKysrKwbNkyh75u\nbm7YtGkTTp48CUmS8PHHH+PNN9+Ev78/Bg0ahH379gEAXnzxRZBE586dER8fj/fee6/Be1d7Ciko\nKAg5OTkAgJycHAQHB9e5lp2dfdFtro933nkH+/fvR0xMDDp37oyvvvqqQR0FVz/CUAhahKCgIISF\nhWH16tUYNmxYnWuenp4wGo3Ys2cPCgoKUFBQgLNnz6KoqAgAsGDBAuzfvx8///wzCgsL8d1334Fk\nsy8u+/v74/jx447v5eXl53lr1W7PuHHjHPoWFBSguLgYjz/+OADghhtuwNq1a3Hy5ElER0fjrrvu\nAgD4+PjgrbfewokTJ7Bo0SLcf//9OHTo0AV1qu0VdvToUfj7+zt0PXLkSL3XLob6RkwRERH48MMP\nkZeXhyeeeAIjRoxAeXn5RcsWXD0IQyFoMd555x1s2LABRqOxTrparcZdd92Fhx9+GHl5eQCAEydO\nYO3atQCAkpISGI1GuLi44MyZM3j66afPk30xRuNCeYcPH46VK1di8+bNqKqqwuzZsy+Yd+zYsVi5\nciXWrl0Lm82GiooKZGRk4MSJEzh16hRWrFiB0tJS6HQ6mEwmaDQaAMCyZcscxsjV1dUxTXUh5s6d\ni/LycuzevRuLFy/GqFGjAACjR4/G3LlzkZ+fj/z8fMyZM+eS9nj4+Pjg9OnTDqMMyNNqNc/BxcWl\nUR0FVz/i6QtajLCwMHTo0MHxvfbb7AsvvICIiAikpKTAxcUFffv2xf79+wEADz/8MMrLy+Hp6Ylu\n3bphwIAB570J1/6uUqnO+96UvHFxcfjXv/6F9PR0+Pv7w2KxwNvbG05OTuflDQwMxIoVK/Dcc8/B\n29sbQUFBWLBgAUjCbrfj5ZdfRkBAADw8PLBx40a88cYbAIBt27YhJSUFFosFN910ExYuXIiQkJAL\n3rPU1FRERESgT58+eOyxx9CnTx8AwIwZM5CcnIx27dqhXbt2SE5OxowZMy7Y5j+3v+Z6dHQ0Ro8e\njbCwMLi7uyMnJwdr1qxBfHw8LBYLHnnkESxdutRxDwTXJio29/hdILhKKCkpgZubGw4ePFhnPaAl\nOHLkCMLCwmC1WsXbvKDVafZf4MSJE+Hj44OEhARH2s8//4zOnTsjKSkJnTp1wtatWx3X5s2bh8jI\nSERHRzumGgSC1mLlypUoKytDaWkppk6dinbt2rW4kRAIrjSa3VBMmDABX3/9dZ20xx9/HM888wx+\n+eUXzJkzx7Hgt2fPHnz88cfYs2cPvv76a9x///2OjVECQWvwxRdfODax/fHHHw4X3dbg77ZzXXD1\n0uyGomfPnnBzc6uT5ufnh8LCQgDyLtsaH/oVK1Zg9OjR0Ol0CAkJQUREBH7++efmVkkgaDJvv/22\nw+tq3bp1iIyMbBU9QkJCYLPZxLST4IpA2xKVPP/88+jRowemTp0Ku92OzZs3A5D91lNSUhz5AgMD\n64RmEAgEAkHr0yKG4o477sDChQtx8803Y9myZZg4cSLWrVtXb976httiCC4QCASXRnP4K7XIuPbn\nn3/GzTffDAAYMWKEY3opICAAx44dc+Q7fvx4ndAOtanZYHU1/s2aNavVdRDtE+27Ftt3NbeNbD6H\n1hYxFBEREY7YPBs2bEBUVBQAYMiQIVi6dCmqqqpw+PBhHDhwAJ07d24JlQQCgUDQRJp96mn06NH4\n7rvvkJ+fjzZt2mDOnDl466238MADD6CyshJGoxFvvfUWACA2NhYjR45EbGwstFotXn/9dTHNJBAI\nBFcYf4sNdyqVqlmHUVcaGRkZSEtLa201LhuifX9vrub2Xc1tA5qv7xSGQiAQCK5SmqvvFE7aAoFA\nIGgQYSgEAoFA0CDCUAgEAoGgQYShEAgEAkGDCEMhEAgEggYRhkIgEAgEDSIMhUAgEAgaRBgKgUAg\nEDSIMBQCgUAgaBBhKAQCgUDQIMJQCAQCgaBBhKEQCAQCQYMIQyEQCASCBhGGQiAQCAQNIgyFQCAQ\nCBpEGAqBQCAQNIgwFAKBQCBoEGEoBAKBQNAgzW4oJk6cCB8fHyQkJDjS0tPTkZSUhKSkJISGhiIp\nKQkAcOTIERiNRse1+++/v7nVEQiaFbvdjj179uDXX39FdXV1a6sjELQI2uYWOGHCBEyaNAm33Xab\nI23p0qWOz1OnToWrq6vje0REBH755ZfmVkMgaHYqKipwww1DsWPHXqhUTmjTxhkbN34NDw+P1lZN\nILisNPuIomfPnnBzc6v3Gkl88sknGD16dHNXKxBcdubNm4+tW40oLT2IkpK9OHgwBZMnP9naagkE\nl51mH1E0xMaNG+Hj44Pw8HBH2uHDh5GUlAQXFxfMnTsXPXr0qLfs7NmzHZ/T0tKQlpZ2mbUVCOqy\nY8fvqKgYjpp/m+rqW/Drr9NaVymBoBYZGRnIyMhodrktaig++ugjjBkzxvHd398fx44dg5ubG3bs\n2IGhQ4di9+7dsFgs55WtbSgEgtagQ4cYrF//KSoq0gFooNN9gvbtY1tbLYHAwZ9fop9++ulmkdti\nXk9WqxWfffYZRo0a5UjT6/WOaaoOHTogPDwcBw4caCmVBIKLYtq0x9CpUzlMpgiYzW0REfETFi58\nvrXVEgguOy02oli/fj1iYmLg7+/vSMvPz4ebmxs0Gg0OHTqEAwcOICwsrKVUElwDVFVV4Z//fBXb\ntu1CQkIUnnhiCgwGwyXJMhgMyMhYhb1798JqtSImJgY6na6ZNW5eSGLx4v9g1aoMtGnjg+nTH4On\np2drqyX4u8FmJj09nX5+ftTr9QwMDOS7775Lkrz99tu5aNGiOnk//fRTxsXFMTExkR06dOCXX35Z\nr8zLoKbgGsBut7N//2E0GvsReIcGw1B2796XVqu1tVVrMaZNm0mTqT2Bt6nT3c+AgEgWFha2tlqC\nFqK5+k6VIuyKRqVS4W+gpuAK49ChQ4iP747y8iMAnABYYTLFYOPGTxx7ea5mSMJgMKOq6iAAPwCA\nyTQYb745CmPHjm1d5QQtQnP1nWJntuCqpaqqCmq1AYBeSdFArZZQVVXVmmq1GHa7HTabFYDZkUZa\nrpn2C5oPYSgEVy2RkZEIDfWBXj8JwI/Q6Z6Ep6cd7du3b23VWgSNRoPhw0fDaBwNYBNUqn9Dq92A\n/v37t7Zqgr8ZwlAIrlo0Gg0yMr7CzTeXISrqYQwadAI//rjukhez/44sWbIId98dh7ZtH0Va2lr8\n+OM3dRxKBIKmINYoBAKB4CpFrFEIBAKBoEUQhkIgEAgEDSIMhUAgEAgaRBgKgUAgEDRIiwYFFAgu\nlp07d2Lt2rVwdXXFrbfeCpPJBKvVio8//hjHjh1Dly5d0Lt379ZWs0UhiVWrViEzMxORkZEYNmwY\nVCrVJcs7deoUPv74Y1RXV2Po0KGXPYxOVlYW/ve//0Gj0eCWW26Bn5/fZa1P0Aw0y/7uy8zfRE1B\nM/PFF1/QaPSiTvcwJWkwIyPbs7CwkH36DKHJ1J1a7RRKUjDnz3+5tVVtUR555EmaTNHUaqfSZErk\nrbfeSbvdfkmyjh07Rk/PNjQYxlGvv5dmsxd37NjRzBqfY9euXbRYvKnX30Unp9vp6urHQ4cOXbb6\nrnWaq+/8W/TAwlBcmwQEtCXwDQESsNNovJmTJk2i2ZxAoEpJz6JOZ2RlZWVrq9si5OTk0MnJlcBp\npf0llKRA7tq165Lk3XffQ9RoHlNkkcAipqYOamatzzFw4C1UqV521KfRzOK4cXdftvqudZqr7xRr\nFIIrlqKiAgBtlW8qVFZGIzc3FypVOICaqK1toFJpUVJS0jpKtjAFBQXQ6TwBuCspJuh0bXDmzJlL\nkpebWwCbrW2tlLbIz780WU0hL68A5Ln6bLZo5OZevvoEzYMwFIIrlhtu6Acnp8cA5AP4CU5O72HM\nmDEgNwH4AkABNJqZCA9ve8Hjd682wsPDYbEQKtVCAAUAlkCtzkK7du0uSd6wYf1gMi0AsBfAcUjS\nLAwd2q8ZNT6/PkmaAyALwEFI0jwMG3b56hM0E80yLrnM/E3UFDQzxcXFHDp0DI1GF3p6BvHDDz8i\nSX7//fcMCoqhk5OFKSl9ePz48VbWtGXZv38/27XrRicnM6OiOnDnzp2XLMtut3PevPl0cfGlyeTO\n++57hNXV1c2obV1sNhsfffRJmkwetFi8OXPmM5e8viJonObqO/8WPbAwFFceBQUFvOmmMXR3b8Po\n6E7ctGlTq+jxySfLGBQUR0/PEN533yOsrKxkcXEx09Mn0sMjiBERSVy/fn2r6Ha5OHr0KHv2HEA3\nt0B26tSbe/fubW2V6uWXX35hu3bd6eYWyBtuuJm5ubmtrdI1R3P1nSLWk+CSSEu7EZs3+6OqajqA\nbTCZ7sfu3dsQHBzcYjps3LgR/fqNRHn5RwD8YTQ+iDvuaI9jx07g66+JyspnAeyBJE3Atm3fIyYm\npsV0u1xUV1cjKioJx46Ngs02DirVSnh6LsChQ7tgNpsbF9BC5OXlITKyHQoL5wFIg1b7b8TG/oid\nOzf9JVdewcUhYj0JWo2qqips3LgOVVWvAwgFcAuAG5CRkdGienz++ZcoL38AQBqAKJSXv4Lly1dg\n9eoVqKx8A0AYgEGw2W7B2rVrW1S3y8Uff/yB/Pxy2GwzAISAnITKSh/s3LmztVWrw+bNm0EmArgd\nQAis1vnYt28v8vPzW1kzwaUgDIXgotFqtdBqdQCylRRCpTrW4m+0rq4W6HRHa6UchdlshsFgAVCT\nTmg0R2GxWFpUt8uFxWKB1XoWQLGSUgmrNfeKa5/FYoHdfgKATUnJh81WAUmSWlMtwSXS7IZi4sSJ\n8PHxQUJCgiMtPT0dSUlJSEpKQmhoaJ1jKOfNm4fIyEhER0dfNW99VztqtRpz586FJF0H4BkYjTcj\nLMyKQYMGtage99xzN9zd10GnuwMq1UwYjePx8stz8NJLz0KSbgQwBwZDOvz9j2HUqFEtqtvlIiAg\nALfeOhom03UA5sJk6ovrr0+5ZK+ny0WvXr2QmOgPSRoA4BmYTGmYMmUqTCZTa6smuASafY1i48aN\nMJvNuO2225CZmXne9alTp8LV1RUzZszAnj17MGbMGGzduhUnTpxAnz59sH//fqjVde2XWKO4vOTk\n5GDr1q3w9PRE165dG5xDPnv2LH788UcYDAaUlpZi06bN8Pf3xV133QWj0diCWsvk5eXhnXfeRXFx\nCW66aTA6d+4MANiwYQPWrfsGXl4euOuuu2CxWEASW7duxcmTJ5GUlIQ2bdq0uL7NAUksXboUO3f+\nhrZtIzF+/HhoNJpmkX3mzBls3rwZkiQhKCgIu3btQkBAAJKTky9aVlVVFd59910cOXIUXbp0wtCh\nQ8X6RAvTbH1nsyyJ/4nDhw8zPj7+vHS73c42bdrw4MGDJMnnnnuOzz//vON6v379uHnz5vPKXSY1\nBSS/++47ms1edHYeQJMpgsOGjaXNZqs374EDB+jpGURn5+toNicxKakHS0tLW1jjS8Nut3P8+Htp\nMoXS2XkgJcmTa9asaW21rih+//13ursH0Nm5Dw2GEKrVZjo730iTKZj33vtwa6snuASaq+9s0TWK\njRs3wsfHB+Hh4QCA7OxsBAYGOq4HBgbixIkTLanSNU96+h0oKXkPRUWrUFqaiTVrduOLL76oN+/d\ndz+KM2cmoajoG5SUbMPvv/vi5ZdfbWGNL41vvvkGy5dnoLQ0E0VFX6Gs7FOMGjVejFRrMXHiZBQU\nPImiojWoqCiC3b4eRUVforT0N/z3vyvxww8/tLaKglaiRaPHfvTRRxgzZkyDeS40NJ09e7bjc1pa\nGtLS0ppRs2uXU6eyAFynfDPAau2GrKysevMePpwFu70mrxoVFWnYv//86cUrEblNXQDUzJH3RFFR\nPqqqquDk5NSKml05HDmSBfI6yAvllZDvFwA4Q61ORlZWFnr06NF6CgoaJSMj47J4H7aYobBarfjs\ns8+wY8cOR1pAQACOHTvm+H78+HEEBATUW762oRA0H7Gxydi9+zXY7VMBHINGsxIdOrxfb96UlGRk\nZ7+Jqqo3AJRAkt5H9+4TW1TfSyUpKQnkUwD+ABAOleotBAdHCyNRi86dk7Fq1euorn4VgA+AxZDd\nW/fBZstAYuJTrameoAn8+SX66aefbh7BzTKB9SfqW6NYvXo109LS6qTt3r2b7du3Z2VlJQ8dOsSw\nsLB6t/NfJjUFJP/44w8GB8fSaPSmXm9qMGR3QUEBO3fuTScnN+p0Jt5xxwMXXM+4Enn99UXU6800\nGr3p7x/B33//vbVVuqLIz89nhw496eTkTq3WSKPRk0ajD52cLHznnfdaWz3BJdBcfWez98Dp6en0\n8/OjXq9nYGAg3333XZLk7bffzkWLFp2X/9lnn2V4eDjbtm3Lr7/+un4lhaG4rNhsNp44cYIlJSWN\n5rXb7Tx58iQLCgpaQLNzlJaW8qGHHmfnzn05btzdjnAQ27ZtY//+I9it2wC+8cZbtNvttFqtnDdv\nPlNS+vGGG4YyIqI9TaYghobGsm/foUxKSuOMGU+zqqqqSXXv37+fN900hl263MABA26km1sYnZ1D\neN11fdit2wD27z+CP//880W3qaysjI888iQ7d+7LsWPvajDEhc1m4wsvLGBKSj8OGTK6USP3wQcf\nsnv3gezT52Z+//33Tdap5vmeOnWKTzzxFBMTe3LYsLE8evRok2UIrhyuWENxORCG4trGbrezd+8b\naTDcQmAVdbqHGRoax+3bt9Nk8iTwOoHPaTLFcf78f3LSpKmUpG4EPifgQSCdwFICbgSeIvAVJel6\njht3V6N1Z2dn08XFl2r18wTuJWAh8B8CnxDwJnAjgTdoMnkyMzPzotrUp88QGgzDlTY9yuDgmAt6\nkT388BOUpBQCX1Klmk9nZx8eO3as3rzvvbeYkhRGYDmBd2g0enLLli1N1o0kR4wYR6NxAIFV1Gie\noo9PSIu/HAj+OsJQCK4ZsrOz6eTkXuuwIjstls4cPXosVapptQ7d2crAwBgajS4EjhP4moAnASuB\n9wkMrZW3kBqNvtFIqW+88QaNxnFKmTgC/6olYwWBQOXzDD722JNNblNubq5yAFGlQ56zc1euW7eu\n3vwmkzuBo468BsNELly4sN688fHdCaypped8TphwX5N1Kysro0bjRKDUIcNi6c9ly5Y1WYbgyqC5\n+k4RwkNwxSN7whGAvVaqDSqVCiqVrVaaVcmrghw6QquUYa20c+WbXveFytkUuYBKZb2ozWTnNkLV\ntIkgG5LxZz0unPd8na1Qqy9ON5nz77fgGqVZzM1l5m+ipuAyYbfbOWDAcBqNgwgsp15/N6OikpiZ\nmUmz2Ysq1XwCH1KSIvnvf7/Oxx+fQUnqqEw3eRIYokwXuRN4lMAySlIP3n33pEbrzs3NpYdHINXq\nmcrUk0mZ6lqsTGUNokr1Ek0mz4sO9z1o0EgajQOVNt3LyMj2LC8vrzfv9OmzKElJBD6mWj2brq5+\nzM7Orjfvhx9+RElqQ2AJgYWUJE9u3779onQbN+4uSlJvAsuo1T7KgIBIFhUVXZQMQevTXH2nCDN+\njWK323H06FHodDr4+/tfEW+LeXl5KCwsREhICLTaup7bVVVVmDp1Gtau3YAOHdrjtddehpubG3bt\n2oU5c17C2bMlGD9+GG69dQxIYuHC1/Dxx1/Ay8sFR44cw9GjefD3d0N8fBzy84vQr19PTJny0Hmh\nL6qqqpCVlQVPT0/odDpkZ2fDZrNh1qx5OH78JPz9XfH997/AZiNSU9ujtFQFZ2cTZs6cWie+2Z8h\niePHj4Mk/Pz8cPToURgMBixa9C5++GE7oqND8cQTD6OyshJBQUEwGAyOckePHoVarcaKFV/i88/X\nwdfXA9OnPwKtVgt/f/86wRhzcnJQXl6OnTt34u23l8Jg0GP69IfQqVOni3oWVqsVL774T3zzzWaE\nhgbg2Wefgo+Pz0XJELQ+V3QIj+bmb6Lm34bCwkJ26pRGo9GXBoMHBw0a2WQPoMuB3W7nQw89Tr3e\nmSZTEENCYnnkyJE6eSZPnkzASMCHgBN79+5zQXn79++nv38ETaYQOjk5c8aMOU3SIzMzk97ewTSb\nQ6nVmqjVWmg2h1Gnc6FWa1bkuVOvd6XR6MtOndJYWFjYqNzy8nJed90gGgxedHLyopOTJyUpkE5O\nLpw0aSrtdjsXLfo/Ojk502wOo6urH7ds2cKioiKmpFxPo9GHBoMn+/cfxsrKSq5bt45msyfN5jAa\nja785JPltFqtHD16Ip2c3ChJAYyP78K8vLwmtVtw9dJcfeffogcWhqJ5mTDhfjo5TVAWecspSf34\n3HMvtJo+n332GU2mOAKnCZAazbNMSTlnCE6dOqUYia+VxdVdBExcunRpvfJiYztTpVqo5D1Jkym8\nSafcBQfHEnhPKXeMQACBfxMIIZCjpC8k0JGAlU5OEzhhwv2Nyn388Rk0Gocpi/HVBG4m8ASBMzSZ\nEvjqq6/SaPQmsF+p43O6uwfw7rsn08lpnPKcKmg03sjp05+i2exJIEPJu4OS5MHnn3+BktSdQAkB\nO3W6hzh06K1NfwiCq5Lm6jvFYvY1yM8/70Rl5e0ANAAMKCu7FZs3t97BNzt37kRZ2c0A3AEANttE\n7Np1Tp8NGzYAkAD0U1LiALTDypUr65W3f/+vIGt2jPuguvrGRg/2qa6uxtGj+wDcpqQEKvV9D2AQ\nAF8l/U4AvwHQoLJyPLZu/bXR9m3evBPl5eMA6CAvsE8EsBOAG0pLb8b332+ETtcNQKRS4iaUlpZj\n06atqKwcD/k5OaG8fCy++24LVCoPAKlK3iTodNH49ttNKCtLhxyiRIXq6gnYvv3KOsxI8PelUUPx\nyiuvoLCwECRxxx13ICkpCWvWrGkJ3QSXiZiYCGi1q5RvdhgMXyM2NrzV9ImIiIAkfQM5vhAArEJw\n8Dl9unbtCqAEwC9KSjaA3ejZs2e98gICwgHUtK8Mev13iIiIaFAHnU4HD48AADVnohQB2AggAcC3\nAEqV9NUAZN202tWIjm78vsXFhUOvXw3Z+4oAvlRkVMJk+gYJCfGwWrcByFNKbIFWC8THR0OnW4Ua\njy8np9Vo1y4W1dW5APYoebNQWbkXHTokwGhcA8AKANBoViEysvWeqeAqo7EhR0JCAkny66+/5tCh\nQ5mZmcnExMRmGc40lSaoKbgIsrOzGRwcQ4slmWZzHBMTu7O4uLjV9LHZbBwyJJ0mUyhdXHrSzc2f\nv/32W522/6UoAAAgAElEQVQ8gwYNISARSCZgYXh4wgXl/fTTT3R29qGLSy9KUhveeuud9YaG+TM1\nIdddXFKp1/tQo3GhxdKLGo0r9Xo/OjunUq0202gMpcWSzODgGObk5DQqt6CggNHRHWmxtKfJ1J5q\ntTMtli40mUI5ePAoWq1WTp/+NI1GH7q4pNFk8uSXX37J3NxchoXF02LpSIslgQkJKSwqKuKSJe/T\naPSgi0sajUZPvvzyv1hRUcHu3W+g2dyWzs4p9PML5+HDhxvVTXB101x9Z6NeTwkJCcjMzMTkyZOR\nlpaGYcOGISkpCb/88ktDxZoV4fXU/JSXl2Pr1q3QarXo3LnzeV5GTeGxxx7DqlUZCAz0wHvvvQt/\nf38UFBTgX/96Dbm5pzFwYB/ceOONFyxfWVmJ119/A/v2HUZsbDgyM3cjL+8MevfugaNH5WNWJ068\nDXFxcSCJKVOmYPXqNUhMbIfFixefF9Dvl19+wZIlH0Gn08DPzxsZGT/C398LUVGR2LfvCCIiglBR\nUYHs7Dxcf31PDB8+HADw008/4cMPl0GSDBgx4macPXsWPj4+MJlMOHjwILy9vbFo0ds4fjwbPXt2\nxa+/ZqKysgq9e/fC3r1/wGIxISDAF5mZ+xAaGogHH3wAkiQhLy8Pr732BvLyCuDhYcEnn/wPJJGQ\nEIPt2/fA1VXCyJHDkZV1Eu7uZrz55psoLrYhKMgD6eljUFxchkGD+sFoNEKj0aBTp07Q6XQAgGPH\njmHv3r0IDw9HWFgYAMBms2Hbtm0oLy9HcnLyeUfTVlRUYMKECfj11wNISmqL9957D3q9vtHnXFVV\nhTfeeBO///4HYmLCcObMWeTnn8WQIf3Rr1+/RstfDlasWIE1a76Fv783Jk16AC4uLo2WIYlly5Yh\nI+NHBAf748EHH7jqT9xrMa+n8ePHs2/fvgwPD2dpaSkLCwvZoUOHZrFSTaUJagpamLS0fgSCCbxE\nYAR1OncePnyYQUHR1OsnEJhPSQrlq6/+u97yVquV3bv3VfYRLCAQT5UqkcAkZeTwDwIzaDJ5ctu2\nbbzjjgcoSZ0ILKDROJDdu/el1Wp1yNu4cSMlyZPAbGWhWCIwlSrVOKpUbgRmU6Xyolo9gsBLlKRo\nzp79LNesWUNJ8iYwl2r1FLq4+PCPP/5wyC0qKmJwcAz1+vEE5hPwI3AD5bAgLgTmUaV6gICZwEwa\nDMPZrl1X5uTk0M8vjDrd3QRepBxKZDCBDsrnFwgkEohR2n+9snj+lCLrHgLP02j049KlH//l52Wz\n2ejtHUagq1JfZ/r5RTUa1NFmszE1dQCNxv4EniHgQpVqIoEXKUlBfOut//vLul0sL7ywgJIUQeAl\n6vXjGBYW36QR8fTpsylJsQReopPTLYyN7XTBfStXC83VdzYoxW63Mysri9u2bXPEecnPz+evv/7a\nLJU3FWEoriyqq6sJaCmHyZBDagBd2LdvX0pS7TAZu+ns7F2vjI0bN9JsjlU8ekjgLOU4SjcrnkU1\nMhayf//h1OstSh4SsNJsjuUPP/zgkNer142UN8HVlHuWwN3K56FKx9tb0VX2atLpjGzfvheBTx3l\n1OppnDTpUYfcd955h5I0pJbcvZQ38SWxbpiMBwnMImCn2dyFd999Nw2GW2td30rZe8qVwI8EzigG\nocDRJiCewB2KrjXlNjAk5MLTbE3liy++UAxUhSK3jIBro95gP/30E83mKMreWv8iMKqWbtvp4RH0\nl3W7GOx2Ow0GZwJ/OH57JlN//ve//22wXHV1NbVaA895r9lpNvfg559/3kKatw7N1Xc2Ot8wcOBA\n7Nq1y/Hdw8MDHh4ef30oI/jbUlFRAXmB1VNJUQHwQ0lJLmy22guoPqisLKtXRllZGdRqL8gePQBg\ngezZVIJzHkYA4IvCwlJoNJKSBwA0UKs9UVZ2TnZJSRnkMxTOlQN+d+ghy/VBTcgNwAt2uw2lpaV1\nytntPigq2ltHT7u9tlwfAGXKX109gUIAKqhUPigpKYHV6ltPOavyuRyAAYCzo02Al6JndJ1y5eX1\n38OLoaCgAIALgJrpOgMAs5J+YeTn5AnZW+v8Nl/o+V4uSKK6ugLnnpkKpG+d30J9VFdXK1MwNX2X\n/JwaKydQaMyS3Hbbbfzpp5+axSpdKk1QU9DCeHiEEBhJeU/DewQkLl++XInmupRAJg2Gmzhq1O31\nlj979iw9PYOoVr9MYDeB+wjEKtMbbQj8QOAHSlIkFy9ewoSEFOp0DxHYTbX6ZXp6BvHs2bMOef/6\n1+uUpHgCWyjvMfAl8KqiiwvlcBauiq676OR0K/v1u5nPPvsCJSmZwDYCaylJ/nUC8x04cEBp00cE\nMgkMUP7uoLyfYgeBryiH8/gvVapFdHHxZUZGhjIV9imBXwmkEhiutLEngZ3KCOIepf0vE/Ai8H+K\nnisJ/EJJSuXDDz/xl59XQUEBNRoXylNzuwn8g1qta6NTNkVFRfT2DqFaPZ9yEEQXylFpf6PROJDj\nx9/7l3W7WIYMSVciCWcSeJ9msxcPHTrUaLm0tBvp5DRe+c3+H52dfS4YBuVqobn6zkalREVFUa1W\nMzQ0lPHx8YyPj3d4QrUUwlBceeTk5DAkJJ5qtRuNRj++//77JMkffviB7dp1Z0BANO+8cxLLysou\nKGP//v3s0aM//fyi2LVrH0ZFdWRgYAxTU29gcHACQ0La8bXX3qDdbmdeXh4HD06nr28ke/Toz/37\n99eZX7darZw//59s0yaOwcEJ7NWrL/392zImpgs7d06ln18UO3bsyfj4rvT3b8tbb72TxcXFtNls\nnD37WQYFxTMysiOXLv24joeU3W7njz/+yPbte9Dfvy179erH0ND2DAqKZ2pqPwYGxjIysiO7d7+O\nfn5R7Nz5eofH1oYNGxgX15WBgTGMiEigWu1OlcqNLi7+VKvdqdN5MSYmmX5+UQwMjKE89WahSmVm\nUFA8AwNjOWXKdFZWVjraWlu32ms0NdhstguuO2zZsoWuriFUq13p7h7KrVu31pFbn2eY3W7nwYMH\n2bPnAPr5RTElJY3R0Z0YEBDN++57hBUVFRd8vrV1qi3vr1JSUsLx4++lv39bJib2bPKLbGFhIdPT\nJ9Lfvy2Tk3tz586df1mXK50WMxSHDx+u968lEYbi2uTs2bPs23coNRodJcmdvr6hVKs1tFh8KO/U\nVlGlMhNwIqBR3na1BPTU6VypUmno4uLDDz/8iKQ8T+/uHkC1Wsvk5DSeOHGiTn3Z2dns1Kk31Wot\nnZ196OkZSLVaQy+vNjSbvahWa9m9ez+eOnWqTrmsrCy2b9+darWGnp5BXLNmTZ3rNpuNkyc/Rr3e\nRL3exMDAaKrVOprNHo7F4JdeeokqlYWAik5OXvzuu+9YXl7OqKgkAjoCOprNvlSrtTQYXB3tB8yc\nMWMGSbJfv8GOexEQEH3e+RHvv/8+NRpXpZykyFBTr/ekTidRpzPyttvuZlVVFY8ePcrExB5UqzX0\n8GjD1atXX/TzW7BggaNNGo0zDQZXajR6Dhw4QgQYbCFazFCQ5Pfff+84qe7UqVNNGuY1J8JQXJsM\nHjyKev1EyuciZFKO8/SNMi3jTnnxOpDAPgLFlBfCb6O8yB5NYCyBbTQafbh8+XJKkpcypVVBjeYf\nTEzsUae+Dh16UaudRnnBd5NSx1LKi8BbCZRTp3uIPXsOcJSx2+2MikqiWv2sUm4DJcmzzsvUggWv\nKIcO5RDIpbwX5FkCuyhJgXzttdeUjnutImMetVo39ujRl7KXUh6BEwQSKC8o76C8oL5JmQaSOG7c\nOGXK7g8ChQQGMCYm2aHDiRMnqFJJBD5U2uJB4GcC5QQeIuBP4DSNxhv4+OMzGB3dkRrNHEWfbylJ\nnnW8wRpj69atSpvWKFNzfgT2ECihk9NYjhxZ/5SkoHlpMUMxa9YsDho0iJGRkSTJ48ePs1u3bs1S\neVMRhuLaxGz2UjrIGi+b6QSeVj73ITCCwHOs65EUrnxeQqAtAVKvn8RRo0bRZBpXK6+VarXOMXVS\nVVVFtVpL2bunJs/tlL187q+VVkKt1smhY0FBAXU6M895U5EWy/A6cahSUweztmcV8AXldQ5SpZrB\nrl27Ke2puW4nINHJyV8xHjXpH1BeF6LSub+kfE6gi4sf5TWZmrw7qNF4OHR45513CEQp1/5FOWR6\nTd5yAmoCNgLfMTq6M7Va6U9tGskPPvigyc/uySefpOxlRgLTaj03Evijxb2lrlWaq+9sNITHZ599\nhhUrVjg2pgQEBKC4uPgyLa0LBOdwd/cCkKl8I4BfIXsGlQE4CMAPctwlKnl+U64DciwlMwA7dLpM\nBAQEQKXag5oQF8DvcHKSHBvOtFotDAYLzoXGsAHYBSBA0aHmEJ9MODvX1AGYzWaoVATwh5JSBXIv\nvLzO5fH394JG81utltW0gzAYMhEQ4A9gH86FMDkCoBoWi1HJ++dy9lptLQJwDJ6ezgB21Mr7W50N\nifKmvBwABUq52m36DbIXlBoq1W/w9/dVDjo6qFyvBvl7nTY1RlBQEID9ACqU+mo/p0x4eDRdluAK\noDFL0qlTJ5J0hO0oKSlpcDF7woQJ9Pb2Znx8fJ30hQsXMjo6mnFxcXz88cdJyusfBoOBiYmJTExM\n5H331X9cYxPUFFyFyJvhPGkw3E29vhdVKhfq9XdRpQqnPA01jvJehFTK00wSgesIDCIgUae7mWZz\nL3bqlMaysjJed90gms0pNBjupST5csmSur73//3v+0pI73up1XagWu1Jne5OZeG5Cw2Ge2k0enH5\n8k/rlHv99UWUJH8aDPfRZOrIQYNG1lnAPXLkCN3dAyhJo+jkNIqARL1+FE2mPoyN7cTi4mL6+UVR\nni67k4A7hw1L5+rVq5U2jXS0Sa+/lSpVJ8rrMRMIBNPVtQ0PHjyoeDX1JXArAYmLFy+uo2f79l0p\nT9VNpOxZ1UH5bKFGE0Gj8TZaLN7MzMzkokX/52iT2ZzMAQOGN7o5rzY2m43+/m2VUd14pY5eNBrv\npCR58ttvv734H4TgommuvrPREB7z58/HwYMHsXbtWkybNg3vvvsuxowZg8mTJ9ebf+PGjTCbzbjt\nttuQmSm/DX777bd47rnnsGrVKuh0OuTl5cHLywtHjhzB4MGDHfkuhAjhUZfKykp8/vnnKCoqQu/e\nvRsNeHcp2Gw2rFy5Erm5uejatSvatWvXYP4NGzZg//79iIuLu2Cwvj9DEmvXrsXhw4eRmJiIlJQU\nAEB+fj6+/PJLAIDRaMSKFSvg4eGBG2+8EQcOHEBQUBA2b96MgwcPonPnzlizZg2Ki4uRnJyMr7/+\nGhqNBtOmTUNZWRk8PT0xfPhw6HQ62Gw2fPbZZ8jJyUHbtm3x+eefo6ysDA888IDjYJ8XX3wRn3zy\nCQIDA+Hm5obffvsNKSkp6NWrF/Ly8hAREYHPP/8clZWV6NWrFzIyMuDs7AyTyYT169cjLCwM77//\nPvR6PUpKSjBz5kzk5eUhNTUVmzZtAgAMHz4cWVlZcHFxwYgRI2AwGFBdXY2xY8fiwIEDGDhwIObO\nnQsA2LFjB15++WVoNBqkpKTg+++/h7e3Nw4fPozt27ejbdu2cHNzw9GjR9GhQwd88cUXqKqqwp13\n3onIyEg4OTkhPDwcv/32G3x8fPD7779j27Zt6NChA06dOoXs7GwMHDhQ2Z9QjRtvvBGBgYEAgK1b\nt2LLli0IDAzETTfdBLVajaqqKqxYsQIFBQVITU1F27ZtHc9/8eLFcHNzw9NPPw1XV1fY7XbMnDkT\ne/fuRVpaGlxcXFBcXIw+ffogKirqvN/Djz/+iN9++w0RERG4/vrrGzxMa9euXdi0aRO8vb0xZMiQ\n8w6gEsi06MFFa9as4ZQpUzhlyhSuXbu20fyHDx+uM6K45ZZb+M033zSa70I0Uc1rgrKyMiYkpNBs\nTqMk3X5Z3s6sViv79BlCs7kTjcY7aDR6NxhGYvLkx2gyRdJovJMmUwhnzpzbaB12u53jx99LkylW\necsM5EsvvcIjR47Q07MNTabhNBiGEjDRYBhBs7kX27fvVifkQnFxMdu2TaLZ3IcGgzyiMBiup8l0\nE319wy4YsO/QoUPK23dvZZ1D4tKlSzlp0mTKLqrjKO93cFNGKr7s0aMvMzMzqVZbCPQj0Iuy19BI\nZe7fRSkXRT+/KJ4+fVo5Y6ITgTHKCCeeJtMIengE1lnsttvtHDHiNprN7ZR74cfXX19UR+cvv/yS\nkuRJSZpIvT6ZarWbElbEhecW7p0phwQZQcBIrbYvDYZ+VKnMNBhupdncidddN6het9qmUFFRwY4d\ne9Fs7klJmkBJ8uSaNWv4yiuvKCOf0QRS6OTkcdGHJj3zzPOUpCDlN9SW99778AXzLlu2nEajFyXp\nDprNXZiaOvCS23S101x9Z5OlnD17lvn5+Tx9+jRPnz7dYN4/G4DExETOmjWLXbp0YWpqKrdu3erI\nZzKZmJiYyNTUVG7cuLF+JYWhcPDaa68pZ0fXLDR+wbCw9s1ax4oVK2g2J/Pcwu4Oms0e9frA79u3\nj0ajD8+FojhJJydXnjx5ssE6tm/fTkkKouytRAJZ1OvNHD58LDWaWbUWPmcq0yN2StJAvvnmmw4Z\nL744n05OI2vdi6WUvYRIrfZR3nvvQ/XW3b17qjIdUlPHWzSZAggYKHsUUWl7R8qbzHIJSAwPj6cc\ni4oEulNeXK5Wpr/2KekVBILZsWNHAmm1dFutGB5So3mat9wy3qHPxo0baTJFUV5UJoGD1OtNrKys\ndOTx8Qkj8K1y3aZMtw0jEEn5QCRS9gxzVup8h3L8KFLe1DeNQDXN5k787LPPLvIXISOHM+mr1E8C\naxkQ0JY6nQeBz3luIb4/R4wY0WS5+fn5dHJyJpCtyCikJPlz9+7d9eZ3cfEh8BPPhXNJ4fLlyy+p\nTVc7zdV3NhrCY9GiRZg1axacnJygVqsdw5lDhw41edRitVpRUFCALVu2YOvWrRg5ciQOHToEf39/\nHDt2DG5ubtixYweGDh2K3bt3w2KxnCdj9uzZjs9paWlIS0trcv1XEydP5qK8PAnnQlEk4fTp3Gat\nIzc3F3Z7AuSwDQDQDmVlhbBarY7opTWcOnUKen0oystdlRQf6PW+yMvLa/CM5dzcXOh0UZAXnAEg\nCFqtC7KyTsBmG1ErZwcA2wGoUF6eiJMnz7U1OzsXlZV17wUgX7dak3Ds2Ff11p2TcxZA7TOkOyhh\nSaoA1EyxaZXPuQC8AXghP78YQHJNC5T6SpTvNYcOOQGIR27urwCu/5NuFQAAmy0Jx49vrnMvNJoY\nyAvKABAOlUqPwsJCxwJyQUFNfYB8jEwSgE2KjjXPJFapo0K5by872gf8BEALu70dcnMv7feSm5uL\nyspEnDvGJglnzuSiutpaSzcVgM7Izv62yXLz8/Oh03mhstJPSXGGTheO3NxcxMbG1slrt9tRXJwP\nIFFJ0cBmu/Q2XW1kZGQgIyOj+QU3ZknCw8Mvehj55xFF//79mZGRUUdmfn7+eeXS0tK4ffv289Kb\noOY1wzfffKO8ie8jUEG9/k4OHpzerHXs2rWLRqMXZT/7amo0T52356CGM2fO0NnZh8BnlAPbLaGH\nR5sGd2ST8s5u2f31awJWqlRv0M8vnHPnPk9J6kEgX/nrTGAegb2UpDZ1fkfydEw45b0DZQRuUaZ/\nTlKSkvn662/WW/ekSZMIhBI4Svno0BsZE5OsjIz+oYwSfqa8j+JXAu9TpTJx+PCRytROjjIiGU55\nj0csZTfdagLfEzApdXhQ3jtQSXmROpTAaUpSLz7zzPMOfY4cOaKE+/iWQDVVqn8yJCSuzgguLe1G\nJYRJFYHfCHhTdo81Edis1D2TcrDCEsqRau/huT0l7xHYRknyPu+sj6byww8/UJICKIcAqaROdz/7\n9h1KX98o5b5XUD7O1ZsvvND0o3UrKiro5RVM4F3lN/QFLRbvevsIkuzUqTc1mieVNm+n0eh9Teyy\nvhSaq+9sVErfvn1ZUlJyUUL/bCjefPNNzpw5k6Q8VdGmTRuSZF5enmNu8Y8//mBAQMB5u0lJYSj+\nzL///QaNRhdqNDped93geu/ZX2X58k/p7OxNtVrDpKSePH78+AXzbt68mX5+4VSp1AwKimnyP+23\n335LL69gqlRqRkS05++//06r1cp77plMrdZArdZAP79IqlQaGo0u583bk+T8+S/TYLBQo9HR378t\nNRo9dTojH330yQuGi5BDZ99AecezxrGmsHXrVsVYqCmvPxgo7yp24dKlS2mz2Zic3JPy7m811WpX\nJa+OKpULATVVKolz5swhSY4ZM57yTml597NaradWa+Cddz543pz6mjVr6O4eQJVKzejojjx48GCd\n66dOnWLXrn2Vndku9PCQ8zo5mXlul7ZF0U1DtdqVarWOOp1EX98wqlRqWixe/OSTZU16Nhfi7bff\noSS5Uq3WsmfP/szPz2dWVhbd3IKVe6Hn8OEX/+KSmZnJ0NB4qlRq+viE1okM/Geys7OZnJyq7NL3\nbJYw7FcrLWYotm/fzoSEBN5999188MEH+eCDD3LSpEkXzJ+enk4/Pz/q9XoGBgby3XffZVVVFceO\nHcv4+Hh26NDBsfj66aefMi4ujomJiezQoQO//PLL+pUUhqIOGzZsYEJCdwYHJ3DKlOmsqqq6YN7d\nu3eze/d+bNMmjmlpAxkT05khIe3Yt++NDAtLYtu2nR0hLurDarXypptuUt6u3RgREXfBhcOG0qdP\nn83Q0PaMiUlhWpqsT8eOvdip03UMDIxlr179GReXwuDgBPr6BlGez3elRuNM2ZXTlWFhCWzTJo6d\nO1/HDh16sU2bOLZr14l6vQ+1Wk9263Y9y8vL67hxZmZm0ts7khqNO93dQ7llyxaS8oawmnJubv7U\naDyo1/swPj6RgYGxjI1NpotLEDUad7q5BTMmJplBQfGMi2tPnc6bWq0XhwwZXqe+yspKHjp0iL17\nD2abNnHs1asv4+O7MSgonjExidTpvKnTeTE6uj1DQtoxOrozPT3lOlxcgrh+/foL3sPCwkLGx6dQ\no/Ggk5MPLRZfajTudHYOYlxcMgMCYnjddf0ZFZXM4OAEzpkzj1VVVQ5jabVauXXrVnp6hlGjcaeX\nVzh/+eUXkuRHHy1ldHRnhocn8aWXXm40HpPdbq9Xz9oxqS6VP8tduXIl4+K6MjS0PWfPfva8+F6C\nhmkxQ9GxY0c+8sgjfPfdd7l48WK+99575/lnX26EoTjHr7/+qkxTLFOmEnrzwQen1Jv31KlTdHX1\no0r1GuVopekEulA+2CeccjiLtZSkwAsa6XvuuUfpqFcpUxzRjIq6uKCQTzzxFCWpmzKd8zllT523\nlOmTeYpudxGIo+yx469Mw4wkUFMuTpm+2amU8SbwtiLrcyVPB3bpkuaot7y8nDqdO4FHlXKzqNG4\ncO7cuUq5r5Q2xVI+T2KV0tb7lbfzp5RyU5X8E5XppLXKvQvjyJFjHPUVFRXRxyeUavXzlHdiOxP4\nWNG3pk0ZlPcyzFGeoTOBTwi8SJXKzKysrHrvYWhoAuXF6R2UF9GdKS+0P63o+rJizL8ksIWSlMw5\nc+Y5yhcWFiqeXv9Q2vQ4tVo3JbRJIOVQG5soSfEXPGyqpZEPo/KhHLJlCyWpM2fPfra11fpb0WKG\noqXPx64PYSjOMXv201SrH+c5j52DdHMLrDfvJ598QotlcK281co0RU/WPXTnLQ4fflu9MiwWPwKv\n1Mq7kYD7Rens6xtJeV69RsYsyqExetVKsymdf4jSuZJyqPDDlNcSvHnO24ZKG0YqsmrSfqNa7eqo\nd+XKlYoMe608UfT2DqF8yltN2ibKHk5UOtxQngsFUuPJ46/o9lat9K9pNAY46lu/fj2dnbsr154j\n8IjyeSjlMOU15ZZR3kBHAo8rRoMEOnHu3PpdiwE9Ze+rGhn3KbqS8hrE9ZRP4Ku5voVhYef+d//z\nn/8o7ardpkCmpKQSeKNW+jq2a9fzop7v5eK++x4i8Hwt3X5mcHDLRq7+u9NcfWejITwGDBiARYsW\nIScnB2fOnHH8CVoHSTJCq82vlZIPg8FYb16j0QgyH+dCJxRCDtsgAchz5FOp8mA21y9Dp1MDOFUr\nJa/BjVAX0gOoqzNgAnAacqgMQPYeKod8gE9N3ppyRuVaqZJuA3AGssfU6Tq6qdXnHPlcXV0hh/uo\nUFKqARTCaNT/qU01dcgyZC+iYsheUIAcWqNUSc+rU06rPbfRy2g0wm4/o+hnrJXXeF65uvUZHW1y\ndnZG/WhR9x7WlJPb9OdnCuQp911GPlP6z20qgbOzBSpVXbmSVP9voaUxm41Qq+v+bmq3SdCCNGZJ\ngoODGRISUucvNDS0WaxUU2mCmtcMubm59PIKolY7icA/KUlBfOedd+vNW1FRwbi4zkrYiIWUwymk\nUA4IZybwHFWqGTSbvbhr1656ZchvokbK01UvELDw1ltvvSidP/poKSXJn8BLVKkeVuqeRZWqDVWq\n/opu7ZUzs9Mpb956msBNlKOkvkygPYF2BBZSpepPlaqNMpow8VyAPDdOmjTZUa/NZlNCY3RR6uhN\nN7cgrl27VqnjMcrnWTtTDgD4hNLWeylPMaUp5bpSPlRoonL9H8qIwcwFCxY46rNarezatQ+NxsHK\ndWeqVPdSnvqSFH3nKJ8nK6MCC+VIsgNpMvlc8AznoUNHUI7A+oqih4vytn0d5Smn6cq9mEr5PGtf\nrlixos69kA+b6qW0qRu9vcO5a9cums1eVKn+QWAejUavRo9HbSkOHz5MFxdfqtWPEZhPo9H3kveA\nXKs0V9/ZaAiPK4FrOYTHqVOnsGfPHrRp0wbh4fIxozk5OXj11X8jP78QI0YMQv/+/S9YvqSkBK+8\nshCHDh1HfHwEfvklE0VFxejRows2b94OvV6HmTOnneevXpv//Oc/eOSRJ2G12jFhQjpeffXV8/Ic\nPb/KL2sAACAASURBVHoUhw4dQmRkJM6ePYvTp08jNjYWhw8fhtVqRWFhIT77bBWcnU1Qq+3IyPgB\nbdtGIjIyEocOnUBsbBg2bdqMU6fyEBDgg7VrvwMAhIUF4NChUzCZtOjTJxX79mUhPj4S1dVW7Nt3\nGB06xGLt2m9RWlqFiRPTMXjwYGi1WoSGhmLPnj1wdnbGpEmTkZm5D1FRoVi06A0UFRUhLy8Pkyc/\nisrKanTt2hG7dx+EwaDH8OFDkJNTAG9vN3z/fQb27TuC2NgIeHt748SJHCQkxGDFilWw2ex44IG7\nUFJSAk9PT0yYMAH79u2Dp6cn5s2bh23bdiI1tTvc3b2Ql3cWJpMGS5Z8DECFUaNuwvHj+fD0dEFJ\nSRF+/fUgIiIC8Nxzz6CwsBDR0dH47rvvcPr0aQwbNgy+/8/edYdHVaXv906fe6cmkx7SEwhJqCbU\nSBWQjqiriOJaVhRRFEVEFNQFFRuiuKirrliw/VxFBEQRkEVAQEGaEAgEQi8JCSlkJvP+/jhnMhMI\nUkR31+V7njy5OfeU7zv35Jx7v/J+0SL96IgRI/DRR1/A7dYQFxeDLVt2IyMjDu3bd8C+fUeQlZWK\nr79ehOPHj+Puu+9EbGwsTCYTEhMTsWnTJtjtdtxzz2hs3LgNzZplYO7cL2CxWLBlyxb87W9/R02N\nF8OGXYs2bdqcdi2QxMaNG3H06FE0bdoUhYWF8Pv9aNWqVR3A4oEDB7B582YJDCjWRtOmTREZGdng\nuvnss8/qwYSE0s6dO/HSSzNQXl6JIUMGo1OnTqfl7SKdSr8rhEeAbr311gtyOp0rnSObfxiaN28e\nNc1Dp7MjrdYITpw4+bz7qqmpYY8eA6lpybTZWlCvd1LTcmizNWZubidWVFQ02K6qqoodOvSgzZZO\nh6MVGzVqfIqr7PTpr9BqDafT2ZF6vYNGYxgdjjzq9U5arRm025szNbUZDx48yMmTJ8s36uYE7MzP\n70Gv18u4uCbyrT2TgI0WS2PabFnMyspjSUkJx459ULZrIb9IVPmFYaMACMwgYKPVmk2rNYM6nZMO\nR550Ww2Mp1FRbLTZcuWbfKz8ytJosWTQZktnhw49WF1dLV1btZAx3PJapbCXxMr7mXJ8O222trJM\nk+OpHDBgIL/77js5XhKBOAIqNe0SqmoCBw26jrW1tZwwYRKt1ghp47DLMZpSUWxcsGAB33vvPZlP\nIkd+QThot7en1RrOF1/8G8vLy+lyNZJfHY0J2KiqWbRY4qnX2+lwtKdOF5iLFgRU3nzzbee0hvx+\nP6+55s9U1Xg6HLnU651U1Sa023PYuHErHjlyRMa2hNPp7EC93kmDwU2nsyM1zcO5c+fW6+/999+n\nomhSpnAmJWX/aq+pi1SfLtTeeU69/LsM2/+LB4XX66XNFk5hPBbQGKoaW+fSeK40ffp0qmo3iuCv\nGwmMojBo+mix/Injxj3SYLtJk56k1dqfATgPvf4R9u59Vd39Xbt20WIJowh6C8BIuAiMpjA21xLw\n02i8h1ddNYwiNmGJrHuAQDi7d+8uN+FKCjXSTZI3P02mW3jjjbdRxCOsku12U6iLRlJAWZyQbe6S\n7Wrl2KMlL+sZMPyLTTadAmU1AFHyMIEUAl5arf04YsRdckMtoFAXJRMok3U/oPCSasSgofUEBaRH\nmtzkd8nyNQTMNBrdFAFpfgIdCbzMQB4ITWvHxx9/XKrm9lMYy/MpgtdI4FlqWiwNhjAC78iycinD\nWAKFtFrD2b17Dwo1VECmiRRG9BQK76i9FIfdVnl/EwErN23adNZr6MMPP6SmtaYIMrxPylQrn9Md\nHDbsNmpaGIUn2ToKR4J9DDgMaFpYPVduAf3xD3n/OIHGvO+++85rfV+khulC7Z1nNGaH0i9BMlyk\nC0tHjhyBzwcAHWVJFAyGPGzbtu0XWp2eNm4sQGVlLwAmiDwBgyDgFvSoru6Dn34qaLDdhg0FqKrq\njQCcR21tP/z8c7Duzp07YTY3BpAiS7Ih8kRsANAfAu5BgdfbD+vWbZJ/XyrrRgLIxebNmwH0gzDO\nFgAYIHlTUFPTD6tX/wRhuA7AZ8TLcdYAuFzKVABgoGynk2NvABAr6wJAKoDGAEpl3YDheyBEXgcD\nqqp6Y+XKHwAkAUiDyAHRA0AAVqafHKtMtoMcfyCEYT0LQCNZ3gqAA14vAVwheSuQvAGABRUVl2Ht\n2nUwGPIARMn7l0NAgQDAAFRWlsPnK5djQ85FL4gcD8kwmZpg06adEM80VKatELkt+gAokvIHoEYy\nAcRgzZo1OFsqKChAVVU3CMN54DmJ51tT0xfr1v0Mv98EoC1Efo5cANGydXvU1upx+HDQOO31lss+\nAOHccPkZkaQv0r+HznhQ7Nixo+56/vz5AAT88EX6bcnj8UjvnABeUSF8vuW/aEv4JWrdOgeq+n8Q\n3kXNALwJ4QF1Albr+2jTpmEY8by8ZlDVDyG8jgiT6W20ahWsm56eDq93K4IJdr6DwEHKBfAOhJeN\nH2bzO+jQ4RIIh6nZsu4OAMslxPcHEBt4DoCZEAmGfLBY3sOll7aF8F5aKNv9LMfLB/CRlCkHwD+k\nTDVy7DwA+wEEcJXWQSQIigLwdp1MYi7CAVRBVT9Ct24dITbYHwG0B/A5gh5Fb8mxwmQ7yvHfgTjA\n1gPYLOsuAlAOi0UvefNBHFr/kPdLoWmfoWPHDvD5lgMolH1/BOGhRABvwel0w2x2ybEB4f30T8nb\nT/B6f0br1plSpsoQmZpDHIxvQxwS2yEOVwD4HsA+dOjQAWdLOTk5sFrnQCQ/ypH9egHUwmx+F+3b\nt4LJRABfQuBOrUAwodNcWCz6esmPLJZQmY4A+ATt2rU7a34u0u9IZ/rkaNmyJXfv3l339+LFi5mV\nlXVBPmfOls6CzT8kLVu2jE5nFO32DFosTr70UsPYRWdDtbW1vO66W2ixhFPTEmgyeWi1xtNqjWLP\nnoPqIZWGktfr5cCB19JiiaCmJTArK+8U7K/33/+QVqubdntjGo12Go0qbbZUmkzhNJsjqarxbN36\nUpaWlvK1116Tah2B1jp48LWsra1ldnYbCo+iKAIOms3RVNVYdujQgxUVFXz22Wfl/XiphjJS2Als\nFDaBCAIOWiyxNJsjaTKF02ZLo05noVB3ifEUxSLxoRyybQQBOy2WKFosERw48Fp6vV7ec899sl28\n7N/CoF1Co/A6slHYEjQCdtlv6HhW3nbbbSwoKJDjuerGVdVkms1uDh8+in6/ny+9NIMWi5M2WzoV\nxS77jKLB4OL333/P+fPnS4jzGAJWKoqddntjWq0uzpr1Pk+cOMG4uMZ1MimKg1ZrLE0mN00mF+32\njJC5iCdg4UMPjT+nNeT3+3n33WNoNruoaSk0mcJpsURTVePYtm1XlpeX89tvv6XDEUm7PYMGg0aD\nwUa7PYMOR9QpsBwLFiyoJ1OrVv8Z8Rt/JLpQe+cZvZ5WrVqF22+/HXPmzMEPP/yABx98EHPmzEGj\nRo1+qdkFpf9lr6fKykrs2LEDMTExCAsL+9X9FRcXo6KiAsnJydi1axf0ej3mz1+A2bMXIibGg8ce\nG4f4+Hjs27cPjzwyGcXFB+DxqFi4cAVqanzo0qUlqquN0DQLHnzwbjRv3hwAcOzYMRQXF0NRFDz+\n+NPYs+cg8vKaYuPGHfB6a5GX1xQ//VQIu12Fy6Vi5cr1SEtrBLfbhaKi/cjMTMTWrTtx8OAR/OUv\n16FLl85QFAUpKSlQFAW7du1CenoOamoM0Om8eP31aQgPD0d4eDgee+xplJSUY8SIYWjfvh1qa2vR\ntGkL+P1mAF6EhdlQXa1DZKQdhw+Xo7raj/h4J2JjE3D8eCVUlVizphCK4ofbbcHRo16YzQr0ej+O\nH/fDbtfjxAkfamqIpKRIhIV54PX6cPjwXhQXHwFAdOrUDj6fEUlJsaipOYH16wuQmBiBZcvW4MQJ\nIiMjEjqdhtpaPxITI7BixWZomhEejxO7dx9FRIQNXm8tjhwpR+vWmXj00YdQXl6ODz74ALNmzYei\nEImJYdi3rwJOp4rXX59W59X07LMvoahoH7KzU/DjjxtQXn4c99wzHK1bt4bBYMAnn3yGTz+dD5fL\nhq+//gbV1X5YrTr07t0bFRU1yMlJwY4d+1BT40N2djLWrdsOu13F+PH3IisrC2VlZZg4cTI2bdqO\nNm2a4+abb0BFRQX27duHKVNehN9PPPDASHTr1g1erxd//euTWLjwX2jaNB1jx96L6upqJCUlQVVV\nAMDChQvx4otvwmDQY/jw61FdXY2EhIQzJsdqiA4fPox+/a5EQcEepKfH4fPPP4bH4/nV/yeno5KS\nEkyYMAlbtxYhMzMJBw+WoLT0OIYM6Y/rrhvym417vvS7ej0tW7aM2dnZzM3N5YEDBy7ICXUudJZs\nXqTzoLFjH6aqtiTwLvX6B+nxNGJBQQGjo1NoMNxHYbDVKOIU3qCILxhO4Blqmofr16+v6+vAgQMM\nD4+nXj+OIg7CRuGzf718G3+LImbARhEbcav8gniOwgg8gcDbVNVMPvXUs/X4FG/iXSginK8nYOfC\nhQtlDMATBN6iqqZwxoxX5RdLYwqoi7EMxkyEURi8n5IyPS1l8lAgraZQGNXfozCquwn8ncDlsr93\nKKKgoyigRaKlTO0oEhS9TWHkHiL57CL7e0jK9zKFkT1B1p0g5+JFisRDsQRmEmjPhISmHDp0qPxy\neUXWsVEYqcdRUTQuX76ccXHpNBhGSZ5bUBj336SqJnDmzLc5atQYqmoehdHYQWCQ5K2ffJZvUXhu\n9aJIrRpF4B9UlKdos4nnm5PTlmbzMAKzaLX2Ya9eV3DJkiVU1QgC0wnMoKpGccGCBRw8eKjMWTGL\nJtOtzMhoUS82ZP78+RJ48RUCL9Fq9XDZsmXntXaFw0csRbzN+wQG0GaLpdfrPb9/hjNQVVUVMzJa\n0GS6Vc5hR4qI/repqhl8/vlpv8m4v4Yu1N552l769u1b7yc1NZUdO3Zk37592a9fvwsy+NnSxYPi\ntyOr1cmglw5ptf6JN910E222/rJsJIMQE6TAQ2pPgFSUibzjjmAmspdffplW6xBZ788MQn9kEfgu\npI/RFJ5GfooAsD/LjToIxREenlDX7xtvvEGhdgok9vETyGB8fCPqdPeFtFvGhIQsCtXUjpDywRSe\nS33k36PkhhuE4hBw5gYCh0LK+8kN3UuhrtlCoIgCTiPgkVYpxyujgBhvwSBkSBXF4dSPQeiPZAqs\npVAojidkm0sILKTwADJRp4tgfeiPaQRukNdXs23btrTZeoXcPyp5qyHwFTMycmk0Wim8y56hONh8\nDMK5eChwlIopDqHmDHqkkYoylkOGDKXNlhMiUzUtFg+7dx9AYEbI2G+xY8fLaTLZKbyixHOy29vU\ny4p56aV9KQ7wQLvpHDRo6Hmt3U8//ZRC9RcqUyQ//fTT8/+H+AVasGAB7fY2IXNRIeftCIE1jIpK\n/U3G/TV0ofbO0yYuGj169Gk/Y84VwuEi/eeS31+LoIcNAJjh8/lAmuTftQgm1IGsK2A3SDN8vtq6\nO7W1tSDNIe1Cr00N9KHIax+CXkXivuBLUGVlJQS0R2C5KgBMqK09HsKnaFdbWwthzA2VydIAP/Vl\nFmU8DZ86OXagHUPG8Et+jPJ+aGIng+TbdxZjK3Ls2jo5hcagobpCJiFr6P0A76ybC9Ivy2tkvwH/\nlYBM3hA56j+nwPNVlNA50UNR9PD5fKfMlUhgFOgXABQoiknyKUisl5Pb1eJ8yOv1NiiTKL/wVFsb\nmIvA/hd4vuI5hK7ZPxxdkOPmN6b/Ejb/K+m22+6iqnYisICK8iwdjiiuXbuWbnesREF9gUJl8RaB\n2fLNegSBf9Bq9XDlypV1fe3atYsORxQV5XkK9Y6LQiVyI0WMwRcUiK92+Yb9kHyr/Zsse4nAfKpq\nLseOfbiu35qaGnl/MIGvKCAxNH744YcSSfc1Al9QVXM4efIUCrVSLgXw4XMMQpC4CDwu38wdFOqY\nzylUQXdQBMTlU6DDTpL1P6RQC6VTpDNtQ2EAb0sBHPgFherpMgrk1lgKtdVXkt9sCjVcGEUMxjUU\ncRjzKNQ2NoqkQvfKN/7ZBPrS40lmz5695BvzJxRfFi6Kr4/nCaicO3cuw8PjqdNNkjx3pvhC+5yq\n2oTTpr3EG274C63W7rIPO4W67yv5TNyS5zyKPOA3U6jf5hB4narq4YoVK5icnE2j8V4CX9FsHsp2\n7bpx7ty5tFpjpEwCgfbjjz9mt279aLFcReArGgwPMi4uneXl5XXP8sMPP6KqNqJA132fVms0v/zy\ny/Nau1VVVTSbPZLvrwncTLPZc1oYlF9L5eXlUtX3oJzDfhSJouZSVVvx4Ycf+03G/TV0ofbOixAe\n/wby+Xw4cuQIPB4P9Hr9mRucgY4dOwZFUWC323HkyBHYbDZYLJYztistLQVJTJv2N8ye/TWioyMw\nZcoj8Hg8KC0txejRj2DXrn2IjNSwatVm+Hy1aNEiGeXlftjtGiZPHofMzEy4XK46+IbNmzfjrrvG\nYe/efWjZsjG2b98vjaSJWL9+B2w2FXFxHmzZsgsxMRHQ6xUUFx9Eeno8Dh48hpKSYxgyZAD+8peb\noNPp6mTavHkzOnXqC1K8wf3tb09h0KBBKCwsxPjxT6G8vALXXz8Id955Ow4fPoyoqGSQ4ktCVQm/\nX4PNZsSxY5Xw+YiwMDOSktJRXV2D6uqj2L79EABCVXWoqgL0ekKnI7xeBWYz4fUCtbVARIQNycmp\n8HqJnTs3o6TEB8CPjIx46HQWJCTEwWQyYceOPbDbjVi1agP8fiA6WkNMTDJIQFGqsXHjLlgsBmia\nEYcOHYPDYQNJlJdXIzMzGa++OhVlZWV49tlnsWDBD1AUwuMxo6ysFqpqwSuvPI0mTZrAYDBg7NjH\nsWvXXmRmJqG4+BCqqk7glluuwZVXDoKiKJgyZSr+7//mwOFQsW7dRvh8OhgMfrRu3QJVVT7k5KSh\nqEg8p8zMRvjpp+2w2zU88cRDaN++PQ4ePIhRo8bh55+3Iy+vOf761/EgiRUrVuDJJ/8Gv9+Pe+65\nGc2bN4OmaZgy5QX861+rkZaWiKlTJyM2NhaAMDwfOXIEa9euxdSpb0Kv1+HBB0egT58+p6zNmpoa\nlJaWwuPxnALrEUo7duxAjx5XYM+eQ4iLi8CCBZ8gOTn5PP6Lzo727t2LUaPGYdu2ImRkJODgwRKU\nl1fi2mv74557Rv7HaVv+LRAe/y76L2HzrGjevHm02cJpsYTT7Y45b0MeKUD/+ve/hkajRoNBpd0e\nS5PJSaPRWi/V5slUUVHB7t3702i00WCw8vrrb6XP5+O3335LlyuaFks4LRYXjUYLzeYw2mxR1OvN\nNBhs1OvdFC6WRhoMLppMbprNNr766uskyX79BlO4rqpUFIdsp9HhiKPJ5KDBYOX99z90SnKciRMn\n0Wi00mRy0m6PpV5vpV5vpd0eS7PZRYPBQqs1jBZLeF0/ZnMYo6NTTkntWVRUxLS05jSb3dTrzbRY\n3LRYwmm3e/jll1/S5/PR7W4k+TTLrwszAT2D7rZ6KopKiyWcRqND3hMyiUx1QZl0OmNIOxN1OjMt\nlnBarWE0GCw0Gh1y3kzyxy7nUEdhaNfk+Ir8+lElb1YGs9YZ5LUawreNgIWPP/54PfnLysrYqVNv\nmkx26vUWWc9KwMjWrduRJF94YTpNJo1ms5spKTksLCzk0aNHmZfXpW5+R40ac8pzmjRpCo1GK81m\nFzMzL2FxcTE3bNhAiyWibowOHbrXa1NbW8t27brWyWSxRP5iRPibb75Fs9lOszmMcXHp3Lx582nr\nXqRfpgu1d562l65du5Ik77///gsy0K+hP8pBceDAAWqah0FYjjl0OqNOi7N0JnrggYdptfalMJpW\nUOQkeIzAHmpaKufPn99gu9tvv4cWy9UU0BNlVNVLOWnSk7TbIykMu6RIsBNOkbf6OQpD580Uahgv\ngRIKw+3fCWyhqkbzgQceoFDLFFEY/B6j8KK5isJTqpbAQWpaNj/4IJi+cu7cuVTVNAqYCT8FPEQv\n+XOfLNtLYQiey2A+610E/sHo6JR6G1rLlvnU6/9KAXURKduQwBJqmoeXXJJLoRIqkbIMlbKFURjg\nD0vZFzNo7I4gcIzAX2Wf11CocQJqsb8zCGFik7InEdhDoZbqQmH4riLQg0IVpjGYe2O1PAT6U6h/\nDsr5ukP+HU3hJeWX8xspeV1KQK2H/nvjjbfTbA48p1IKz5y/UUCYuHnzzTfL3NeFBPzU6Z5idnZb\nXnHFUJpMt1EYhw9T01rwnXfeqev3q6++oqalUBi//dTrx7Ndu8sYFpbEICTMfgIJfOihh+rajRkz\nRs7FASnTSIaHpzS4NtevX0+rNZICYoRUlBlMTMw8r/+Pi/Q7HBSZmZlctmwZGzduzDVr1nD16tVc\ns2ZN3c/vSX+Ug2LRokV0Ojsy6PFB2u0Zp4X4PhO1bduTQp8c6O8TBhLi6HRj63I3n0xZWe0Z6t0C\nvMVLL+1NhyO7Hm9Cz79M/nPrKVw914Tcf4nAXwiQmnYDmzVrRmG/CNwvl+2SGcQYIoEnePfdwax8\nEyZMoKKMD7m/l8J24WEQK4gUNo2At9JlFPYB0mRy1gsCNBjMFJ5D6yjsAUGZnM628u13ekj5agpg\nOp2UdRmF3j50LrII/EhxIOso7BM/y83WclLdPrL9gwx6Ov0z5P7n8r77pHYdKA6oySFl2ygOIiPF\nQRUoH0mgt7xuzqlTp9bJn5bWmsCKkLqvUHiWkcBQJiQk0Gy+I+R+NXU6vYRk3xhS/gyHDw/Ctk+a\nNIl6fWjSrEPSa05jqOccMIHt2nWsa5eX147CNhS4X0hFsTW4Nt966y3abENC6vqp15vr2Tku0tnT\nhdo7T6v8e/TRR/HYY49hz549GD16NO677z6MHj267ucinTs1atQINTVbICAuAKAQXu8BxMTEnFd/\naWkJMBiWhJQsBpAAwAer9bs6mOeTKTU1EXp9oB1hNn+Lpk1TUVNTDIEJBAB7ISAl4gEsg8BlSpBj\niHbAEllWCUVZjbS0NFkWSI7zLQSGT2g7P6zWfyElJchbYmIirNZ/QXgHBdolyJ8Anz4AS2XZEQgc\npwQAa6HXB5IUCYqMDLSLBbAHAo4DAPajpmYbPB4NwNdSBsi6iRDeUcsAxEFAT+yV94tkP7GSB1uI\nTHGynx9k3XJ53QRAQCYngG8QpMUQ0BqVADbJsqMQ0B+xkreAB80SOYdayFzUyOs0iLVUiJycnLre\nk5MToNMFn2/wOVUBWI6kpCQYDMshkhcBwLfweBohISEBihJo54fF8i+kpgafU0JCAiyW7yA8pUS7\n6OgEmM2hvNUCWIjU1KS6dikpiRDwK7V17USbUykhIQHkagSTVK2CxaJB0xquf5F+JzrTSfLoo4+e\n08nz5z//mZGRkczOzq5XPm3aNDZp0oRZWVkcM2ZMXfnkyZOZlpbGxo0bn9b74SzY/K+hiRMnU1Vj\n6XAMpKpG/SpYjn379jE+PoN2e2eqagcqip0222W02bLZrVu/0wYe7dy5k1FRSXQ4utNub8+MjBYs\nKSnh1KkvUVWj6XAMpF4fTqMxmnZ7fyqKjVZrhsx7rVIEGmURsNFm601NS+OQITezpqaGkZEpBBIJ\ndCeg0mRKpqq2oaJotNl60WZryby8Lqyurq7jp6amhp0796bNlkO7vQ8VRaOqtqSqtqSiaLTb+9Bs\nbkKdzkW7vT8NhigaDBF0OAZQVSP40Ucf15Nv8eLFtNki6HD0p8kUR73eLec7ln/961MsLCykojik\nDB2kTK0p1Euq5D2cgIt2+0AKbyOPLLfSZEqiprWVMvWkwRCA8biMQtXmpN3enzqdk2ZzE2paJ3m/\nNcVXmkYRi+KiUFNdJsezU3gu2Sm8rDpR6P1TKbzNVAr1YhKFXaU7ATc7d768nvzbtm2jx5NAh6MH\njcbmcozOBOJptUaypqaGAwcOoaY1psPRn5rm4cKFC7lx40a63bF0OC6n3d6arVrls7Kysq5fr9fL\nyy4bQJstiw5HP9psEfzuu+/49ttvS966EEinwxFXT51aXl5Ouz2WAgq+CwGN7733XoNr0+/388Yb\nb6empcrn66mXgOkinRtdqL3zrLyePvvsM3z77bdQFAWdOnVCv379Tlt36dKlsNlsuOGGG+qQIBct\nWoTJkydj7ty5MBqNOHToECIiIrBp0yYMGTIEq1atwp49e9C9e3ds3br1FC+HP5rX09q1a7Ft2zY0\nbdr0vEH+AnT8+HEsXrwYiqKgSZMm+Omnn+ByudCpUyfodDocP34ct99+O3bu3IUePbrj4YcfBiCg\nWaZOfQFmswnjxo1DWloa/H4/brjhBqxZ8wNycrIxYsQIHD58GNHR0XjzzTdRVVWFmJgYfPzxxzCb\nzXjyySfh9/sRGRmJnTt3YuvWAqSmpuDzzz/H/v0H0K5dWyxevBherw8DBvRHQUEBHA4H1q9fjw0b\nNsHjCcP3338Pj8eDnTt3YujQoSgpOYasrEwsXfovAECnTpdi/foNcDodSEhIwLp1PyElJRm1tbUo\nKtqF5s2bYf369aioqMLAgf3h8UTAYBAopfPmzYfHE46uXbti/foNSE9Pw4IFC3Do0BHk5rZGUVER\nqqqqkJGRgUWLFsFoNKJNmzb44YcfERsbg5deegnFxcVISEjAlClTsHfvXrRv317K5EVubi5Wrvwe\nNpuGkpISFBbugMNhx4033oidO4vQpk0eioqKcOjQYXg84XjvvVkAgNTUFGzatBlmswmapmH//v1w\nOp3Iy8vD1q1b0aFDB3z55ZeoqqpGixbNsX79Buj1OuTl5WH9+g0IC3Ojffv2+PHHtWjcWPBeWlqG\nVq1aoE+fPqisrILRaMD7778Ps9mMyMhILF++EuHhbuTn56OgYDtatGiGK6+8EkeOHEGjRo3wXgkx\nNwAAIABJREFUzTffoKbGi4SERpg//0vY7TZMnDgRsbGxqK2txTvvvINt27ajWbMchIeHo7S0FG3b\ntq3zaJo1axZeemk6wsPD8Nprr52CNF1dXY1p06ahpKQEQ4cORVZW1mnXdHV1NSZMmIDCwh3o27cP\nhg0bdlb/C5WVlXjzzTdx4MBBdOnSGV26dDmrduXl5XjjjTdw9GgJevS47JyAEv/T6XfzenrggQfY\ntWtXvv766/z73//O7t27c+zYsb/YZseOHfW+KK666iouXLjwlHqTJ0/mk08GvXN69uzJ5cuXn1Lv\nLNi8SA1QVVWVfJPLp4iEjmP37n35/fffU9M81OvvpdE4nC5XDAsLC5me3oICouJhAjls1Kgpi4qK\nGB4eT6PxFirKaPnm+CcCw6goGlevXs0rr7yemtaWwINUFDf1+r4U9gS3fJO9S74Z95VvwnFyjI4E\nHNy0aRP1eieBK+SPlcKIe4e8voLC1pAo27WmiFe4V74tX0NgjLxuQkXpIsd+SL6ZpxN4hMIOkSj5\n0SiinAOpV0czmPJ0PK3WPmzRogOPHj3KJk1a02odSOBOWfcWilwPNjnuNfL6XilTJIH7qSgu6vVX\nUKQpdVIYsXvJORhLAafhoIAXyaPBEMYNGzZIoLw/yfmyUtgjusovkIcobCAu2UczijiQhyi+ZiLk\nF4oq+elA8TU0Tv7OlnPYlKmpzbljxw66XDE0Gm+jTnclARsVZQxNphsZFZXE/fv3s2/fq6lpHQg8\nQk3L4V131Xdw+fTTT6mqUVSUcTSbhzA+PoNHjx49rzVbU1PD3NzOVNWeBB6mqqZwypTnzmqtZ2e3\nodXan4ryMFW1EV9++ZUztisvL2dqajNaLFdSUR6i1RrDd95597x4/0+kC7V3nrGX7Oxs+ny+ur99\nPt8paqWT6eSDokWLFpwwYQLbtGnDTp06cdWqVSTJO++8s55Xxc0338yPP/74lP4uHhTnR48//rjc\n+AMQB8UEDOzY8XKKIDVhMNTpHmbfvlfIzS6QoKeCgJsDBlxJvf5eBo2L78lNSxhUs7JaygCqSgKv\ny40wAHHwAwUyKCngHhpRuHnulWU+AumMjIyUGy8pMJWeDhnvabnR2yi8kUjhrZVOAftxU0jdL+QG\nGi3H3k3hyRQwAldSqHBupgiKI4Uq5D3Js50iWZEwotps+RwxYgQ1rae8fweBgNH9EorguMDYt1J4\nOvkItJJ1B4fc/xeFCqkJgUUh5ddQBNDVEGjExMQkCi8sUng7BYzucRRGd0pe+lB4WlXJg2IdBWyJ\nQc7527KekwJ6ZJ6cm+MMOhrY2bfvIOp042RZGwKf1vFmMAznLbf8RXo6BRIpHaXJ5ODBgwfr1llC\nQlMK6BHRzmy+js8888x5rdnZs2fTZmtD4VRAAkU0Gq319qCG6N1336WmdQtZe5uoqu5T3HtPphkz\nZlBV+zP4PFbS40n4xTb/TXSh9s7TQniEfrqUlpYiPDwcgAjSOtegEp/Ph5KSEqxYsQKrVq3C1Vdf\njcLCwtOO1xBNnDix7rpz587o3LnzOfHwv0hHjhyBSMATCOqLAaDDkSMlAIJBSX5/Mg4cWAzAjSCU\nhgogAgcPHkVtbaeQXpMBHJPXaTh27EsYDNEQSYfKIBIYKQ3UTYEwnuoh8kFAXieisnIFggl1ahBM\nghRoVy35CqDnmiCM7Echci6E8uaXfCRDGKDDATjkfaucg6MQOTkQUtcnxwkYbxWQyTh69Chqa5Ol\nTGUIJk8KtAvl83CdTGKMUDkCc2FqoN0xCOiPOJSXF0IYqU+ei9DxlJB2FinTMYgcEIQwNgfmolLy\nsxyAB8IoDgiDfBgOHToCvz+5gTEAny8Zhw+vhsEQiyBUiAtGowtlZWV1uSXKy+u3q6lJRmnpMZwP\nlZWVSX4D6uc4+P1+nDhxog599nTt/P4kBNdeEk6cOA7ylyGHysrK4PWGPo9kVFScH+//CbR48WIs\nXrz4wnd8ppPkvffeY0JCAocNG8YbbriBiYmJnDVr1i+2OfmLolevXly8eHHd36mpqTx06BCfeOIJ\nPvHEE3XlPXv25IoVK07p7yzYvEgN0KpVqyhUEB/It+u7aLVGcdKkKVTVNhTunT9QVdP5xhtvUqdz\nUEBvFBOYRkWxc+bMmVTVJIrYhQIKt867CKwkEMlx48bR40mgokyXb5UuiriDXRTxE70IbKZQeXST\nb+2jJD+zCFg5fPhwWf4NhTomjSIeYb28HkhhCB0neXudQo3yBoWqZSmFm2oX+ebdS469Tb5tT5bt\nXqT42nhFvnWvlLLkSdnyKaAtdhP4jJrm4fz58yVMyFz5dp9A8bVyE4WxeTvF10KEnOcPKNReM+Xv\nrwnspIB7GESBHttLli2i+OL5nALGw8rRowPpW7+lgNXIoogp6E3xhVJEAU3iooCRmE6hctpM4ars\nolB/XULhknwphYptHcVX2VQ5F09Tp3PwjTfelDEsayhUavlSpu+oqvH89NNPGRYWR0V5jUAx9frH\nmJycXc9RYtiw4bRY+lN80Symqkbzu+++O681W1RURJstgsDHBHbTaLyTbdp0PWO7LVu2yOf0OYFd\nNJluYvfuA87Ybu3atRIFdwGBIprN1/CKK84PpPA/kS7U3nlWvezZs4effvopP/vsM+7du/eM9U8+\nKGbMmMFHHhE5mbds2cJGjRqRJDdu3MjmzZvzxIkTLCwsZEpKSoOfihcPivOn119/nSaTh4DGsLBk\nbtq0ibW1tRwzZjzDwxMYGZnCqVNfJCniPDQtloBKqzWa8+bNI0m+8sprjI5Oo9vdiOHhCQQ06nRO\n3nDDn0mSmzdvZsuW+XQ4oti4cQvGxTWh0xnDmJh0AnYqip2RkUl0OmPodsfIzUwl4OSf/yz6GDt2\nrIxeVqnX2+WmZpPXIiJayKHSYAiXNg1N3ncQ0GgyhdPlimNYWAIdjrg6PuPjm9DhiGJERLLsV6Ve\n72B4eCJdrjhaLOF14zmdcXQ6o5ma2qLu5WbBggVMSsqh0xnD2NgU6TFlo8XiodDpO6Q8KgEHXa5Y\nOhxRzMxsxdjYxnS5YmmzRTGY9MheVzfQTlFcdfa6kSPvok7namAuXFJmN+Pj0+lwRNHlCiRWUgm4\n6HbH0umMZUREokyA5JB4SBp1OjuNRjGHmhZTZzd88cXpjIpKpdsdz+bN29PtjmdsbAbfemsmSREE\n16xZezocUWzfvgeLiorqrbGqqioOGzacLlcs4+ObNKg+PhdatmwZ09Nb0eGIZq9eg09JlHU6Wrhw\nIZOTm9HpjOaAAdeytLT0rNp98cUXTEjIotMZw6uvvvEPFbPxux4U50LXXHMNY2JiaDKZGB8fzzfe\neIM1NTUcOnQos7Oz2apVKy5atKiu/qRJk5iamsrGjRufNpL44kFxYejNN//BiIgk2mwRHDZseD0X\n1XOlQ4cOsXv3gVTVMMbEpDIpKYeq6marVpeyoKDgtO327t3L/PzLqapupqY2r4Mw6dOnLwPQFlZr\nFAsLC3n8+HFeddUw2mweRkQkMy1NjBEVlUC9PoyApe5wAay02WK5b9++euMVFBSwVatLqapuJiXl\nMCYmlaoaxsjIwEaqUqdzUhiNNWlItlBR7DQYxBgmk4fh4Y2oaeHS/VdszGFhCbTZIuh2x8vDxkK9\n3sGoqDSqqpuqGjgcBIyG3R5FlyuW48c/Sr/fz88++4w6XRgFHEcolIgmebPS6Yyn3R5FtzuWmZm5\n1LRwGUHvlHUDvy1SBltdu9LSUq5evZpGY4S8b6fbHUdVdbNFi47csmVLvbk6duyYdGgQB/OwYTeR\nFG/dmZm5VFU3c3O7cMeOHfT7/Xz00cl0u+PocESzadPcuueUni6eU3p6S37//fckyXfffY9RUSm0\n2Ty87rpb6rndXqTfjv5jD4rfgi4eFL+evvrqK6pqPIUKaTet1t4cPnzUmRuehtq1606jcaRUUwQS\n0RykTvccY2PTGkyt6vf7mZ3dhgbDWAo4h49ps0Vw5MiRcpNcSmHoHkirNYpXX32jhBrZK++FU6iP\nVKmaOEDhrdSMQl10GZ3O+LrxqqurGRubRp3uOQpIjBmS1zsoVFA/UqhyOlB4NP1IYeyeIe//TbZ7\nTpbvpDA0X0YR6dxVjvu97DeQBOkt2e4xCgP2ExRG7J8JbKWqtuLTTz/PYLKmb6RMH1FEcEdQRFYX\nM6h+6k1h+N4oD58pcoxAatlA0qE1FGq/fEZEJMkD9VYKaI2AQXs5FWUao6KS623YIh1tFynTKgIe\njh8/ni5XDAXS7kHqdE8yMTGTL788g6qaQ6HyuobCuL6HIu9IQAU0iw5HlPSKiiWwnMAeWiwDOWzY\n8PNeexfp7OniQXGRzolGjryXIltdwLtjA2NiMs6rrxMnTkggPC+Ffr4+3MXpYEmOHDkiE9v46+o6\nHAMYERFJ4WYa6GM3AVW+OReHlI+lCFTrEVIW8FY6SqHLd9SNt2HDBtpsGfV4EwFvGRRQ40FPFwEX\nTQpYkgEULrih7ZoQ+InCK8xC4XW1IeT+ExR2kc4n8RZHERj3UUj5p8zMbENxOPop3GO7yXsPUMCS\nB+puYTC/91GKLHkxrM9bNsXB9nxI2WqKrw0dhZdYoPxGBpIo2e1Z/PHHH+vmS6dzSxkDdZ9iUlIm\nnc78euNpWgLbt+/FIE5VHOsninpY/pAOR09eeeXVVJTQRFEF9HgSz2vtXaRzowu1d54evxfCW6lx\n48YX3oJ+kX538njcMBq3hZRsqwd7cS5kNBphNJohoDHcEN5FlfJuKWpqDjXYt6ZpIH2yPgD44PeL\nIDXg53q8AXo4HG55HaACCM+dQgThPvbIa1XWDS5pl8sFn+8wgFJZUgEBy2EDsOWk8QL8FgCIkPUC\nMBLHABySdQJ1G+ItHMAuBKExjkB4EnnkfUGKsg0xMREQXlYHAUQD2CHlOLnfbRCeUoHyNClPibxf\nCWCflP9kmXQQ3lQBD0NCQJO4AJTB6z1Q7zkZjaaTxv4ZYWE2+HzFklchk9dbiqiocOh0gboNzYUb\nQA38/iJERnpgMtWXyeE4v7V3kf5NdKaTpH///ty5c+cFOZXOl86CzYt0Bjp06BBjY1NpsVxLg+Fe\nqqqHX3/99Xn39+KLL1NVG1FRHqBen0SdLos63YPUtBzefvs9p203efIUqmoKdbqx1LRO7NKlDzdt\n2iTfmPtQqJLsvOKKK/jPf/6TVmsk9fr7aTD0o6I4KbyUXPIrZox8k25O4Uml8aabbqo33u2330NN\ny6FO9yB1uizq9UnyrVolcC2DQXSDKVQoGkV60gSKmI4HCKRSUVKp041h0KuoH4VNYxR1usGS/zsp\nAgGbUVHGUsSNNKFQC1mpKDfRaLyddnskN27cyPj4DAqV1v3y7T9XymeTXzX3ELBRp8ujXt+FgJM6\n3f2ShxTJW5Zse4OU42rZh8q7776bubkBoMExFF5aYVSUMdS05rzlljvrzdUzzzwj5b+bwJXU6ezc\nvHkzBw0aQk1rI59vJu+990Fu3bqVTmcUTaa/UK/vTWFsH02DYSAVxUFFGUVN68iePQfxyJEjTEho\nQovlaur199FqjeAXX3xx3mvvIp09Xai984wQHvn5+fjxxx+Rl5dXB8ylKApmz579OxxjqBvvDGz+\nT9Dy5cuxc+dOZGVlYe/evSgrK0OzZs2wefPmOgiPdevWwe12o1u3bqckRTp69CjeeecdVFRUID8/\nHwcOHIDRaER6ejrWrVsHj8eDsLAwbNmyBWlpaVi6dCl27tyJgQMHomvXrgCAQ4cOYcmSJbBYLDh0\n6BDmzZuHhISEOmiO9u3bY9SoUVAUBTt27MD9998Pn8+HESNGoLS0tG4N/fDDD4iPj0d6ejp27doF\nTdMwevRolJeXo3///nC73QCA6OhofPTRR/B4POjQoQNWr16Nxo0bY+3atdi5cydatmwpITwqcOut\nt2LMmDEAgKKiIqxYsQJhYWF44YUXsGrVKjRp0gQ6nQ7FxcVo3749Vq5cierqamRlZWH58uUwGAzI\nzc3FTz/9hMjISLhcLmzduhXZ2dmwWCzYv38/WrdujU8++QS1tbW49tprcfDgQTgcDpSVlWHp0qWI\nj49H165dsXXrViQkJGD69Onwer11UC0kMX78eOh0OjgcDkyePLlu7svKynDs2DGkpKTA4/GgvLwc\nTZo0wdy5c6HT6TB8+HAUFRUhPDwcq1atQkFBAeLi4qBpGg4fPozs7Gz89NNPqK6uxsiRIzFu3DgA\nwODBg/H111/D5XLh+uuvx5YtW9CmTRuMHj36lBiDTz75BK+++qpMQDQFqamp8Pv9eP/997F9+3Y0\nbtwY8+bNw/79+3HZZZdhzpw5IIl+/fph1apVcLvd6NSpEwoKCpCYmIikpCQUFxcjNTUVK1euxPHj\nx9GrVy+0bNnylPUtoF02IC0tDbm5ub/qf6Wqqgpff/01ampq0Llz57o4sIKCAqxZswaxsbHIz88/\nRf79+/dj2rRp8Pl8uPPOO08LrPnfQr8bhMeiRYtO+QmNifg96CzY/MPTyJH3U9OSabdfRZ3OSZMp\nmZrWi4pio6p2pap2pqLYqGm9abO14KWXXs6ampoG+yosLGRERALt9stptXaUYIL9aDI1pk7npqpe\nId9SE+VbvsYJEyZw8+bNdLtjabf3pcWSR0Vx0GYbSKMxhXp9OG22K6mqMXzuuWlcuXKlfDPOo/Dl\nV2k2X0KbLY+tWuWzqqqKo0Y9QE1Los02mDqdi2ZzNjWtP4X3To78sVIYdDMIOGizDabBEEuDIZJ2\n+1W0WiM4a9b79eRbuHAhNc1Du30whYHXxSB0RiMKw7Amy9swCGjXQvLcU94Lk/I7KKDCO8n7ufJa\npcXSngZDiizvSyCWihJGVR1AYTvJkP2pFLYEAaxotfagXp8g6/SliLmIkePZCITTaGws2+XLebTR\nbM6lzdaMl102oF60cnl5ObOy8miztaPd3o8uVww3btzIiRMnSln7UBiZw2i3X0VVjeWTTz57Tmuw\nvLxcepmlMwDuJ+avAwGNqtqTNltrtm3bjSdOnOBtt91NTUuR40Vy5sx3Ttv3tGkvU1WjZd0Ejh07\n4Zx4C6WSkhKmpzen3Z5Pu703w8PjuW3bNn788f9RVSNot19JTcvgddfdUs8dPwgl05ZAPnU6e53X\n1n8rXai986x62bFjB7/66iuSIjvasWPHLsjgZ0v/6wfFjz/+KD2WSiiMgT/LDWYY6xuB76FQm/io\naZ355ptvNthf375/knmWAwbXW2Q/J+QmeDVFoFuVrLOMgJWXXtqbijItpN01FHkGqqQK5EuKoCUn\n3e54Cm+bAG8TKTCQammx9OeYMWNk8pyjFFAUXRiEGvmIwrjcgsK7KQD30VnWPUphQF1H4CdaLI56\nAWDR0akUQX8HKQ68IjlXKSEyLacwSvdm0AjsJzCEAuJDo/AU+kjOyQm5gdzMoDH+cTlPTgJrGYTG\nSJX9tg2R6RMK7yzKub5RPsOfJS/JDMKnbKDIhOdkwCgsfm6TbWqoae3rBb4+/vgkms3X1PGmKC+x\nQ4deVBSVwmOsiOLgC8CnFNNicZ9VXFSAOnXqJOfCS5F35O4Q3h6kCEL0UVV78oEHHqCqJjIIn7KR\nZrO9QZfso0eP0mx2MGgQP0SrNeoU992zpfvvH0eT6c91c6HTTWGPHldQVd0MwqBU0GZrwm+++aau\nXWZma9bPp/IQ4+P/u5MmXai98xeN2QDw6quv4qqrrsJtt90GACguLsagQYN+/afMRTprKi4uhtGY\njaDBtTGEQXYXgPyQmvkAigHoUVXVFsXFxQ32t3NnMfz+AEKmEtLOBCAPwuDZBgIeAvL6BIqKdoMM\nbddRtrMAaC2vE2AyxaK8vAZAp5N48wPQobq6HbZs2QajsSmE0bMYQHsEoUY6yLJieQ15L1DuhoCr\n2AMgB36/gmPHgrALhw8H2u2HyO+QAGFgzQ2RKQ8CIqNIyhE6F9sgYCSi5Hht5NyUSJkC6op8CIO3\nH0EoERuAlrLfTg3IFGhXBAFL0liWN0cQPiULwgitB3BpyBx2kuVG1NTk1Xu+27cX48SJ9nW8kR2w\na9dukFUA2kEY55Mh4D4AIA4mUyPs27cPZ0t79uyRPBgkz6FrL7AW9KisbIeCgu0wGJohCJ/SFIpi\nRklJCU4moQKNhICbAQAPTKYMOd65U2FhMWpqOiAwF35/B+zYsQs1NVUAWslaKoCW9ebwwIFS1J/v\nfBw9Wn5ePPzR6IwHxfTp0/Gvf/0LDod44BkZGTh48OBvzthFClLz5s3h9a4GsFKWvAvxz9oRwFQI\nz5cKAC8AaAtgNyyWD9C2bdsG++vcuR0slmkQ3jnHAEyH2Ay3A/g/AP0BzIHwRCKAZ2EyhaFTp/Yw\nm6dCYAkdAfCKHG8zgHkQOEizodOVIC0tWvJTBuEx8yzEJnoAmvY2evfuCa/3BwgMonYA3oHYaPwA\nnoLY1PMAPCnLimWddrLNGgA5AP6OiIhIhIUFcKCAFi3aQa9/BmJjPAJgNoArJI+bZa2pkp+OAKZI\nmY4CmAGgF4RH10I5Lx/LucmRMh2Tc/cMxIESLdsBwDoAi2QfbwHYHSJTnnxWU+W4OvksW0Ikawok\nP3pd3quVY1RDJER6QT6PnTAa/w9t2rSpk7lLl3bQtDelvD6YzVNx6aXtYDKFA3gaQIaU6SvZYi6A\nAzLZ1NlRt27dAMyEeEFpK+U4DpEQ6Xk5V3uhqu+id+9e8PkCzwkA3oLL5UBkZOQp/SYlJcForATw\niSz5Fj7f5l+EIv8l6tq1HVT1NQjvsBpYLC+gS5f2aNQoDYoyXdbaAL9/IVq3bl3XLje3qZSpXMr0\nLLKyUk7u/n+TzvTJkZubS1IgwJIieUlOTs4F+Zw5WzoLNv/wNHv2bGpaGE0mO222SOr1Jur1Vrpc\njajXW6jXm+l0xtNgUGk0WvnUU6fXP1dWVvLyywfTYAi0i6PBoNJgsFJV3TSZ7DQYVIr0m2YaDG4u\nWrSIZWVl7NKlDw0GK/V6Mx2OGBoMGo1GlRaLkyaTnWFhcfzuu+9YWVlJuz2GAs3UID1hzDQYLBw3\nbiL9fj/nzJkTIpOHer1F8h9OkUJVL9UvJgIGmkxiDLPZQZNJpdFoY3x8Bjdu3FhPvt27dzMz8xIa\njRoVxUhh5zBLXozy2kZAkWVOWW6Q5SaK+AOrVE9Z6uQQ9wPXDup0Fup0RhlJbSZgosGgyngRq6xn\nkiojvZwLJ/V6K3U6E4OR24F6gcjsAK/2k8Y20WRS+fzzL9aT2e/3c9SoMTQYzDQYrOzUqTePHTvG\nJUuW0Gh0y371NJkcNJnsdLtjuHTp0nNeh02atAiZxyBvRmMY9XorDQYLH310Mknyk0/+SVV10Wi0\nMTY2jevXrz9tvytXrqTH04gmk512u4cLFiw4Z94CVFtby9tuu4t6vZiLHj0G8vjx49yyZQsTE5vS\naLTRYrHz3XfrJ0+qqqpicnJ2nUzR0em/u5r9QtOF2jvP6PV0//33w+VyYebMmXjppZfw8ssvo2nT\nppg0adLvc5LhotcTID77R4wYgy1btqFjxzaYMuVR6PV6OBwOVFZWQlEUWK1WlJWVwWq1wmg0/mJ/\nN998K2bNmgedTsH999+CUaNG4eDBg+jZ80rs2XMQ0dHh+Oyzd+B2u7FlyxZMnPgcqqqqodefwIYN\nRTAY9Jgw4S7ceuutsNvtUBSh/nG5XHWeJHPmzMHDDz8Dr9eHMWNuw6BBA1FbW4uHHnocS5asQEpK\nAqZOnQS3243Zs2fj7rsnoLr6BDp2bIWZM19DbW0tOnfuhcLC/dDpFLhcZhw/XguzWYfy8koACgyG\nWjRvfgl8vlpkZiZgy5ZiGAx6JCfHYMOG7XA6bdi1aycOHixDeLgDSUmNcOjQEeTkZGL37oOorq7G\niBE3YODA/jAajXjiiecwZ85XiImJhKpasW3bLrRp0wJTpjwKr9eLDRs2YPz4p1FTUwOjsQY//7wX\nRqMBkybdh/79++PAgQMYNGgYDh8uhcXiQ1mZD4ACTdMjMVG8vRcVbUdFhUgLmpERDdKCxMR4+P1E\nYWERmjdvjIMHj6G8vBKaBqxevRk6nQF5eU1QUlIDVTVh06YtqKrywmTSo3nzTFRW+nDZZfmYOPFB\nAMAdd9yNTz75Cnq9DmPH3obrr78eJSUl6N//OuzffxhOp4aaGi+qq2vh8VhQWuqF3+9HRIQFhw5V\nQ6/XoVWrTBw9WoHExDhMm/YEUlJS8OOPP+Kuux6SHmCZ2LJlD0g/HnjgDvTp0/uUtef3+1FWVgan\n03lG1GmSKC0txeHDh3H33Q9h9+696NatA5588lFYLJZfbAsAmzdvxqhR47F37wH06dMV48bdB51O\nB5vNVm+MY8eOobKyEqNGjcOmTQXIzW2OqVOfgNPpBCC8A/1+PzweDwCgoqIC9903HkuXfo/U1ES8\n+OKTSEhIwMqVK/HAA39FSckxXHttf4wZc+8pSdf+3fS7eT35fD6+8sorHDx4MAcPHsxXX331jBjv\nF5rOgs0/NJWXlzM2No16/XgCS2g2X8f8/J7n/RxuuukWCn//ORTGWicnT54sQe5uIbCEwEgajW4J\n/RFJkbPhDgqj63z5t42vvfZag2MsWLCAqhpDYYyeQ1VN4cyZb7Nnz0G0WK4ksJh6/eOMjEzkxx9/\nTOHd8yoFAm0LXnJJPqOikikM2gvlPTsFVIiHAvri77LsHxRIqk0ojMR9KQzJ31BEYDsIfEiRAMgh\n5e5KYRyfT1VtyqlTX+Sf/nQjrdbLZV+JUt4lNJmGMyenrZQpWs7ZHDmH91FAdmicMWMG9XoHhbF6\nrPyimCH5b0Xh2STiLASq7GuyzhAK2I5HKFBk7fJ3QKYb5Dy6pHwOCuP8Eor4ERuBf9Jq7ccrrriO\nf/rTdRRxIPMoEHrtfP7552k0htXJJIzyqQSekf1+SJHPI4C+217+Xkyd7gmGh8dz9epERH4oAAAg\nAElEQVTVEtl1BoFJ8jl8QuAzqmoiP/jgw1+zzEmKeJ/w8HjqdE8SWEyLpT/797/mjO327NlDhyOK\nijKVwCJarT14/fW3NlhXfDlk0WC4X/4/3czWrS9lbW3tKXX9fj+7du1Li+UaAkuo109kdHQyV65c\nSU3zUCAZf01VzeW4cRN+rfgXnC7U3nlWvVRXV3Pt2rVct25dgxg+vzX9rx8UX375JR2Ojgx6Y3hp\nNodx//7959Wf1RovN7pAfy9LVNgoBhPG+AkkMj+/O4OJhC6Rm0wQ4qFJk1YNjjFo0PVyQwnUnc1W\nrbpIlVYQUsJu78HmzVtQBKsFIR4URaC8BhMJkcLLZiiDEB4PMphIiBTw303kRrsvpPwmCowoP4Xn\n0xsUCXxMFAmDljA9PZd6vYnC82gVRUa9gHdTLTUtmT16DKKA0Aj0O4fCW4sEJjA+PonCBZYUbrF3\nhNTdLuWxUXg6hcpko4D5EJ42Qq7A/bUU7qikOFiiKQLoQp9TGsXhVEG93kSTKZriIAr08RwjI5Mp\nXIP9Ie1SKQINXwypO4/CTdfMoIcYabf34dChQ2k0BmS6iuKADrT7kPn5fX/NMidJzpo1izZbaCKh\nSur1pjMCWL766qtU1etC2pXQYLA0uPkvXbqUdnures9XVWNZWFh4St3Dhw/TZHLIdSL6dji6cMiQ\n66jT3Rcy3iZ6PEm/Wv4LTRdq7zzjd9IXX3yBtLQ03HXXXRg5ciRSU1Mxd+7cX/8pc5HOmoxGo/Re\noSypAemDwXDGvFMNkk6nQBjrAlQBg0EPYdCtlWV+ADUwm01QlEBd4yntjMaGl5DZfHLdSqmSIIJw\nEJTlBgQhQCCvFQiD7snlRvmbIdeh9w0N8Bko90MYoU3yfnAMo9EARdHJcqOs55fta0GKuWh4PAA4\nLuewSrYzQhh6T5bp1LkPyhmQqSHeA9d6CKiPAISJH2I+LXXthPojlM8KGAw6CC+vwPP1SRkbmsPA\nMz1Rr9xkMkGnC10LlSfdP7/1GEpijYT2Ww1FUc6o0jEajVCU+vzodPoG1V3i/6kawf8nL/x+b4P/\nTwaDAWQtgnNBkJUwmYwhcyHGO9//x/8KOtNJkpGRUQ82etu2bczIOD8wufOls2DzD00nTpxg06a5\nNJtvIDCTqtqNV111w3n3J4KwnPLt+GkCKt9++226XAnybX0mgf602WL4ww8/UNM8VJQnKOIiwijU\nP5MJWPn55583OMaqVatkIplnCUyn1RrFefPm8cYbh1NV8wm8RZPpVqalNeOyZcukv/+D8m2/EQcM\nGMysrJbyLfgNClWOjUJVEkmheglATjxCoYaKovji6CPflv9BEVvipEjwM4BC/fM6RdxHZwKvUFXj\n+P77H/Ceex6gql5C4E0qSiqFCmsm/5+96w6Polrf7/admd1N7z2U9EIgEQglEHoXpYmACHpBudeC\noFcFsVxEROxdRLzWn2C7Knq9IqDSRSmhk4SEEiChhSSbbHbf3x8z2SSyoW4ouu/z5GF35pTvm1nO\nmTnfd95XEAaye/cB3LBhg+LTPOXa1VGKPEpA5Ndff02jMYDyPpTplJeVHlDsj1SuXRRl2o63lbcH\ngTLFRzBVqjFK26Y/+HSTch1FxW9vyiSC77Jed/tNStJ1vPPOezl9+nTFz9cokxWK/PjjjxX99AFK\nvV6U33oeZT0b7auKT/0pb6JLU+7TJMbEJHHv3r309Q2jRvNPyiJSJsp7UF6kKAY69S0uBeXl5YyK\nSqBON5nAIopie06adNc56x07dozBwbHUau8h8A4lqQ3vv/9hl2VtNhszMjory0nvUhD6sm/fG5pc\nyh09egJFMUe5FrcyLi6Du3fvppdXMNXqmQQWUBRb8KWXXrkk35sD7ho7zxnMzszMxPr16xtOLMjK\nymp0rLnhCWbLko1PPPEUduwoQKdObXHvvXdd8BMMSRQWFqKiogJfffUVXn75PWi1KjzxxAMYPXo0\nTp06hcGDh2Hbtn1o1SoMb7zxImw2G6xWK+bMeQ4VFVUICJCwfPlvMBq1eOKJfyIxMRGBgYEICQlx\n9rN+/Xrs27cPPj4+eO6512Gz2XH33bchPDwcRqMR//nP11i+fB1iY8Mxc+YD8PHxwc8//4yJE/+O\nU6eqcf313dG/fz8AwLPPPo+fftoMg0GFwEAL9u8/Cj8/Lxw5UgabTQMfHy26ds1FeXkVOnZMw44d\nRdBq1YiJCcHq1ZsRGOiD3bt3YM+eYkRFhSAzMwulpaeQlBSLbdt2o7KyClOmTMCgQYNAEq+//iaW\nLl2B0FA/AERe3h507NgWt902HqdPn0Z5eTmmTZuJ6moboqMDsHz5RoiiHs8//yRatGgBjUaDiROn\noLDwMPz8tNi1qxh2OxAZ6YuUlHZwOIgdO35DYeEJaDQOdOrUBiUlx5GUFAeDwYgdOwrQvn0atm3b\njWPHTiIhIRL/+98aaDRq9OnTGUVFpfDz88Latetw+HA5fH2NyMrKwMGDRzF0aH9cd10WTp06hd9+\n+w2vv/4R9Ho15s9/HMOGDcOxY8fQv//12LVrPyIi/FBdXYsTJ6rQokUgCgtLYLPZkZgYgV27DkMQ\ndMjNzUZJyUnExIRh5swH4Ovri6KiIjzwwCMoKSlFhw7pyM8/CJK47bbRCAwMhMViQVRUlPO3kJeX\nh61bt6Jz586oqalBeXk5WrZsicLCQmg0GoSHh2PPnj3w8fFBREQEAFnC97HH5qCw8CB69szGHXdM\nOq8gcUlJCR577CkcOHAE/ft3w223TWgygF5RUYGHH34Ev/6ah65d22PmzAebTACx2+147rkXsXLl\nerRqFYkZMx6Al5cX8vPzMXv2MygrO4VRowZh+PBh5/tf8bKh2YPZixcv5uLFizlp0iT27duXCxcu\n5MKFC9mvXz9OmnR5ueTPYqYH54na2loOHz6OghBIk6kVY2KSuH///ibLz5z5BI1GH5rNidRqfWgw\nBNFkasG4uAweOXKEGzZsoI9PKC2WJBoM3pw1S06JzMjopDyhykp4en0ABSGCOp0vTaZWFIRAjhw5\n3uXaMUkeOnSIkhRCObgbQEkK4aFDh9i3b1/l6TuacjqpXvksUKMRaDK1ZlRUIouLi5mXl8eAgCia\nzYlUq+vSW+WykydPoc1m44ABwykIwTSZWrJ16zZnxHs++OAjCoIPLZZkarUW6nReNJkSFN8sypO+\nWfnXQpXKTLNZvhZPP/0c7XY7ExLaKU/dddfCn0ZjKHU6H5pM8VSrhT/4VG+n/Bei9CELFalUJprN\nCdTpvKnVetFsTqJKJSllo1gfAwklYKYghFMQQtinz1DW1NTwo4/+z+mTIPhwyZJPWV1dzR49BlEU\nQ2kyxTI5+TqWlZW5vDcOh4OTJ99Do9GPZnMCg4JiuHPnTubn5zM8vDXN5ngajf4cN24SHQ4Hb7hh\nVAP/BGq1Ek2mltTpfCmKUTQag6jTedNsTqDR6Ms775x62RJlFi58l0ajNy2WZEqSH7/55pvL0u/l\nhrvGziZbGTduHG+55RbecsstLj9fTngmikvHm2++SVHMJlBBwEGNZiZzc11rCv/0008K/UIJZdGe\nbgSsBBzU6e7lkCGjGRLSgnKmDAkcoihG8vbbb1cGxTLl+GuUs30GKEspJHCaktSBb7/9tsu+09I6\nUA6U1ip/NzI+PkMZRJcrbexSBsQfKGtZCwSqqdE8ypycAWzdOoNyltQ+5dxapd4WAiLvu286RTGX\ncrDWQZ3uPg4aNMppQ0lJCQXBl7I2w38pL2OVKm28RTkTy045QyxVuabtKQebiyiKIRw3bhzlIPQJ\npd6zlAPR3Sjrkpcrti1T7AqiLIxEylllwZSD4bcofbVjfSD9GOVlo7soB7braDkWK4Oyg3I2VksC\nVgpCb86cOUvxqY5qZANF0ZcPPjiDgtCfcoKBg3r9HRw1aoLLe/P5559TkpKdPqlULzA1tSPbt+9B\ntfoppd1TlKS2vO+++5QJtY6W47+Kv5MJjFF8ymJ9IP04JSmRX3755aX/2M+BoqIiCoIfZf0SElhF\nSfL7U0mg1qHZJ4qrCZ6J4tJxxx13sz57iQS2Myiohcuyr7/+OkXxVqXcBDbOXlrPmJg0qtVaNhQg\nkqRxTE1NZWOunHLK2TMxyuBed3wO77prqsu+zeZoAl80KPsF9foAZUBkg7+OlPmjqAxAqwnsYkBA\nDLVaA+Wspk8oP2k3rJfCzMxOlGMWdcd+ZXR0qtOGX375hV5edWJMz7JxRlYl5c1mpDxx1YkIPU05\nVZU0m4cxMTGRcnyirt5hypNdEGUxplWU4whU7BzyBzt9KccJ6rKXRNbzJpFy7CWT8qRad8xB+U2r\nQpkQfJXjbzA3dxC9vNo16sNiSWXXrgMop+LWHf+JCQntXd6bf/3rXwrVel3ZUgqCF728Qiir6tUd\nn8X27TuwXoyp7s+s2Pyd8t3Eev4yUqudyieffPLSf+znwA8//EAvry6NbDOZWnL79u3N3vflhrvG\nznMu/OXn5+Oee+7B9ddfj4EDB2LgwIEYNGjQpa95eXBZkZISB1H8GnXZGxrNZ4iPj3dZNi4uDirV\nCsiUFnEAPoecEUVotZ8hKSke/v5hkGk+AJk2YiUyMjIgU0OcUo5/qtSPg0wNAgBWiOI3SEpyLYgV\nGRkI4BPI2TwOAJ8gKioEcnbQGqXUPgBbINNILIOcvZIBtfozxMXFITIyDsBnkGlADkOm1QCAXQD2\nokOHdhCErxSfAK32MyQm1tsTExODmpo9kIWA4iDTXtRxSX2mHKPik69yTb9Ujh+G3b4aaWlpyrE6\n8aNPIfMexSmfkyBnKa2CTK+xBjIfEwCsgJzdlASZPoQN6gEyxcR3kClTVgAoVY5/AyAQgKDY5g3A\nBkH4DzIzU1BdvRf1FCZbYbMVIysrBUbjl5CzoAid7jMkJ7u+N3FxcRCE/6Ium0ul+gwxMXFo1SoO\nKtVnSqkqSNK3yMrKBLAB9SJVK5Xrnd6ET6dhMHx/WYTSWrRogZqaPMi0LACwEQ5HGcLCwpq972sW\n55pJUlJS+Pzzz/OHH344L5rx8ePHMzAwkMnJyc5jjzzyCMPCwpiens709HQuXbqUpMxKazQanccn\nT57sss3zMNODc8Bms7F//2EUxQhaLGkMC2vFgoKCJstPnfogBSGAFktbajTeNBojaTanMCYmiQcP\nHuQvv/xCiyWIXl6ZFIQATpv2MO12O+Pj21HOnImnTC0eSklqSY3Gi2ZzGkUxnAMHjmhEkd0Q+/bt\nUzKHIgiE02gMYHFxMbOzOytvDgnK07VR6UOgRiPRYklnaGhL5ufn87fffqOPTyi9vNpRra5bw08k\nIHLs2FtZXV3N3NyBlKRoms0pjIpKPCNes2DBOxQEX1osmdRovKjX+9Nsbqv07a+8qdTFH/wImGk2\nt6PR6MdZs2bTbrczOjqZcoZSawISjcYQimIMNRoLzeY21GikBj4JlOMfdZ/NlN/E6voIICDRbM6g\nXu9PjcaLFkumct7U4Lp4U14qM1EQYilJMezatS+tVisXLnyXguBLL68sCoIv33vvA1ZVVTE7u6dC\nB57Eli3TePjwYZf3xuFwcOzYv1EQQmixtKWfXwS3bt3KnTt3MjAwmhZLG4piGIcNG0u73c7evQc3\n8kmnM9NsTqFG401RbE1BiKBGY6HFkkFBCOb48XdcthjFK6+8QaNRvhai6MclSz69LP1ebrhr7Dxn\n1lNWVhbWrVt33hPPTz/9BJPJhLFjx2LLli0AgEcffRRmsxn33ntvo7KFhYUYOHCgs1xT8GQ9uQck\nsW3bNlRUVKCiogL//vcnMBh0mDLldpcEbPn5+Th8+DA0Gg3mz38RFRWV+Mc/JqFnz54AgBMnTmD7\n9u0ICgpCbGw9edr333+Pffv2oXfv3igrK4PdbkfLli2xc+dOSJKEX35ZheXL1yIyMhharQb5+QcQ\nHu6H779fgZMnK9G5cxsUFR0GAMye/Qg6dOiAmpoa5Ob2xMaNOxEVFYhp0+7Bjh070KpVKzz99Iuo\nqKjGxIkjMWvWLABAeXk58vLy4Ofnh+rqavzyyy/IzMxU3npkaom8vDxYrVYcP34cH374GQTBiOjo\nUGzatAuhof5wOGqxefMOZGdnYsSIYTh58iRiYmKwaNEiVFdXIyIiAm+++R68vU1o0yYF69b9jqio\ncOzevRsFBYeRlBQNnc6AI0dKMXHiGGRkZIAkPvzwQ3zwwX9gsRgxffpd2L59Ozp16oSAgABs3rwZ\nZrMZ06c/jIqKamRkxGPbtnyo1WoMGdIHe/fuR3BwIIKD/fHrr9sQERGIL7/8CuXlNqSmtsADD0x3\nigMVFxdDr9cjOTkZarUaNTU1eOyxJ7B27W9o3ToKa9f+htLScnTsmAKbjaiurkFQkA+WLVsPUdTj\nxRfnIicn54zfxc6dO3H8+HEkJyc76TEqKiqwdetWWCwWxMfHO7ONVq9ejS1btiAnJwe1tbU4ffo0\n4uLisGfPHmg0GkRHR2PHjh2wWCz4/vsfsHbtJiQltcTUqXefF23HpeDAgQPYt28fWrZs6ZKs8M+A\ny0bh8e677/KRRx7hqlWr+Ouvvzr/zoaCgoJGbxSzZs3ivHnzzlmuKZyHmR5cAOppOZ6mSvUYJcmf\nmzdvdll2x44dNJkCqFLNIDCfohh8SQHHyZPvpihmEniJKlUEVaoBrA96p1OWQpUo5/8/SVH056pV\nqxgdnUQ5oPsagYEUxSAuW7ZMeYqeRpmqw4+TJ99xQfZ8+eWXCi3HfMq7vOV9GSpVC6pUuQReoyj2\nZL9+NzZ62v3ggw8VPY3nKe+ZMFGmFfGhHLyfSzmYO4XASxTFWL700iu8+eZxlOMULxK4myqVxE2b\nNjnbXbNmjbKn5D6nT8AIAn0p02u8TJVqsvLWNls5P5ryHog4BgXFuPTTbrczN3egQlHyrPLmMUHx\nWVRsn6e8yUymLLMqcsWKFRd3oy8QQ4eOpih2I/AaBWEwO3To0eRbpwfnD3eNneds5f7772doaCi7\ndOnCnJwc59/Z4GqiiIqKYmpqKm+99VYeP37cWU6SJKanp7Nr165Nsll6Jgr3okOH3pS5muRAnkr1\nJMeMud1l2TvuuFuZJOoCf58zNbXzRfVbUVFBrdZIOWtnJWUFuzoqinJlYL1eGfTq+nuFXbv2U5aa\nyllHuQC0YIsWrdg4eP4jtVq/C7IpNbUzGwfPZ1DOyolmPW2DlYIQzD179jjrxcbWcVDV1bub8ka1\nGMW+Zylvjqs7/xv9/aOoVnsRWNfg+Dj269fP2W5OTncCkxqcX0l5c2AQge0Njg+nvAEyl/VJBYcJ\naFhZWXmGn1u3bqUoRio+vU158yGVSeGJBu1+RKAn6wLm7dtf3L2+EOzfv59Gox/lRAESqKXJ1Pqa\nV5e7GuCusfOcO7Y++eQTFBQUQK/XX/Rby+TJkzFz5kwAwIwZMzB16lQsWLAAoaGhKC4uho+PDzZu\n3IghQ4YgLy8PZrP5jDbqlhQAICcnx+UrsQfnB6u1GrL4jwzSF1VVO1yWray0gmyoG+yL6upql2XP\nBZvNBpVKA1kHwgrAC/V0EQIAA+QAr0+DWr6oqKij1RCVY2oAFlitZQD8GpV1OBy4EFit1j/05wNZ\nh8OMeuoMPTQaqZHf1dWu6lVBDlirFf8an6+psUKmg2h43B9Wa714jnxv/BrVk4Plf2zPF3JQ2Rv1\nQkqyZszp06chCMIZfmo0JsWnhvffqrTVsN06P/1gtdaguWG1WqFWC6gXldJArfa66N/ZXxnLly/H\n8uXL3d/wuWaSwYMHXzD53NmWlM52Licnx+Wy1nmY6cEF4NVX36AoxhP4kcDXFMVQZ4LBH7F8+XJl\naeZzAispSamcN+/Zi+67a9d+NBjGKH0HUaaQWK88fSdTlhcNppx3/1+KYjQ//PBDimIQZXK/9QQe\np1pt5gsvvEB5yef/KMu1prFjx9wLsmfevGcpSanKk/vnlJeOXqQcQJ5GYD11unsZF5fRSG515szH\nKYpZBH5mHQOvvAxlUnz6P+UN6d8EVlMUu3Hy5HuYnt6R8v6B1cpbnchPP60PpL733ntKGx87fZLZ\nYwdS1s5eQzmd1UKZisSb8hLVOgKDqdO5fqOyWq2MjU2mVvsAgS+V+m+wfnnrK8rpvtGUl70WEzBz\nwYIFF3ejLwB2u50pKe2p000hsJ5a7SMMD2/NioqKZu/7zw53jZ3nbKVLly709vZmz549OWDAAA4Y\nMIADBw48a50/TgYNdXnnz5/PUaPkzU1Hjx51rkPu3buXYWFhzmWpRkZ6JoqLgtVqdZlF4nA4+NJL\nrzA+/jqmpGTzk08+OWs7X375JVNTOzMuLovz5j3L6urqi1o/Li8v57Fjxzhu3CTGxrZh+/a5zM7u\nzdjYdLZt25mCEEKdLpCxsQmMi8tifPx1fOedRSTJwsJCRkYmUav1p59fLFeuXEmr1cq5c+dSEEKp\n1QYwJ6cPKysrnbY15X8dKisrefz4cc6b9yzj4rKYktKJffoMYkxMGjMzc9ilS1/GxKRyyJDRPHz4\nsJPBtLq6muXl5XzssScZE5PK5OSO7NVrAKOikpiW1p7e3lHUav0ZGBjDlJRstmjRhtOnP0ybzcaq\nqip27JhLrTaQohjGF1988Qw7582bR0EIpU4XyICACOp0gdTrg5iefh1jY9OZkZHD7t37MTY2nYmJ\n7ahW+xLwoZdXOPft29ekv4cOHeLAgSMZE5PGtm070WQKo1YbwMjI1kxK6si4uCy2bp1CrTaAghDK\n2bNnO21zOBznZHC9WFitVh49epTDho1jbGw6+/a9kUVFRc3W318Jl22iqEuJ/eNfUxg5ciRDQkKo\n0+kYHh7OBQsWcMyYMUxJSWFqamqjN5QlS5YwKSmJ6enpzMjI4FdffeXaSM9EcUHYsmULIyMTqFZr\n6eMT2khA/lJQUVHB/v2HUaPRK0p1j5xXOmNxcTF9fKIoK7zp2KtX03TUNpuN48dPVhT89Bw/fjJt\nNhu3bt3KqKhEqtVaSpIPRdGXarVWUW/TEFBTpfKiWi3XCwiIpVqto9Fo4YIFCxv1UVtby7CwVpSV\nzDTU6/24b98+FhUVMSnpOqrVWhoMZloswVSrtfTyCqLBYKZKpVVSd+X+5KdyjdKOqBwzKP+qqVLJ\n6n9qtY4dOvTg0aNHWVZWxk6delOt1lGnE+jrG0G1Wktv7xCnqtucOfOo18v1unUbwBMnTrCkpITt\n2uUoPpn5xhsX/qS/evVqBgZGU63WMjg49qwxgL179zIuLoNqtZaC4ENJkq93RERck4kPF4rDhw8z\nK6ub06fXXpO1TZYs+ZQmkx/Vai3j49u5pP/24Pxw2SaKqwGeieL8UVNTw8DAKGV5wkHge5pMATx0\n6NAltz1hwhQajcMoU18coiim8N//fu+c9cLDEygzoFZT3sEbzoceeshl2ccfn0NR7EqZJuIERbEr\nH330X4qI0VuUdR18Ke9sdlAOGsdRztLJpRzw7kbgXsoUINsoiqFcs2aNs4/u3XMp01scUnwZTIsl\nnCkpHajRPEaZgiRAWaJZS5lrKY/ybu40AkcpB7xHUKY2KaYcxF6sLClJlJlwQyjradio0/2dPXoM\nYb9+w6jXT6IcuI2mzMTrIPAjJcmf77zzDkWxBWU6j2rq9bdy6NCb2alTH2q1UxWftlMUQ7lq1arz\nvncnTpygxRJEeXnNQWAxvb1DXNJWOBwOtmiRSrV6HuXA/Frlmu8ksIgBAZFu0aXp0qWfwvZaS2An\nRTGM77//PkUxgPISo51q9VNs3brNJff1V8VlmygkSaLJZKLJZKJer6dKpaLZbHZL5+cLz0Rx/ti7\ndy8lKZIN6Qm8vLrzu+++u+S2Y2LSCGxo0PZLHDv2b+esp1J5KYNMXb0n2aZNlsuynTr1Vwaz+iyr\nzMxcimK48v1jAkMb+SfHBzqwPgupYYYUqdf/nc88U68hbjKFEnipQf0NBHyoUmmUQWsVZaoJEniO\n9ZlVN1FWs6My0TTMQppLmVaDBPop5xtSeJRQFH1psQQrE0sR6+k/6u5Tbw4ZciNl9bi647vp7x9F\nvV5iPW8UqdPdzaeffvq8792aNWvo5dW2UX8WS4rLmODJkycVgSlHg/LDCbxHme4ihrt27TrvvpuC\nwWCmnAFXR+FxL4cPH06TaVSDfh3UaAw8ffr0Jff3V4S7xs5zUnjUUSuXl5ejqqoKn376Ke644w73\nR9U9cAv8/PxQW3scQJFy5BRstl0IDg6+5LZDQoKhUm1QvhF6/QZERp67Xb3eCJnOQa4HrEJ4eJDL\nspGRwdBoNji/azQbEB0dhtraEwAKAYQA2Ip6cZ8dkMV4wgDUUd8HN/hsh073WyMadB8fI4DVii0A\nsF7RVvYB8BuAIKWvMqWtjUofwQDqNp827IPK52DIWURbAUQoPtdlYW1AQEAIAgKCleO+kKk4CpTz\np1FbuwMxMREwGjc0sG0DAgOD4etbV0/2Sa/feEH3NCgoCNXVhain+ziM6ur9CAo68z5IkqSIMG1T\njlghU6aEAChGTU2pU0/6UuDn1/AaOmAwbERkZKTSV13G01bodIYzsrg8uMy4mNklLS3NLbPU+eIi\nzfzLYv78FyiKYZSkcZSkVpw06W63tLtp0yZaLEGUpOE0mXqwRYsUnjhx4pz13n77bcpr+NcTyKJe\n79ckTURRUREDA6NoMg2iyTSIgYFRLCoq4nPPvURRDKUojqVGE0ittiUFYQzlOEEs5dx/gTrdABqN\n7QhIlKSbaTJlsnPnPo0yljZv3kw5s6gjgUEEBM6fP5+ffLKYghBASRpLnS6cGk0oRXEM1Wof6vWp\nFIQbKS8rdVXeYATK+xHqqDSup7wEZVHeeizUaNpQkkZTFP25bNkyrlixgpLkT0kaTb2+FdVqX4ri\nOEpSHCdMuJMVFRVMTr6OJlMXStIomkwBXL16Nb/99luKor/iUxazs3uxpqbmgigSJN8AACAASURB\nVO7fAw/MpCRFK7+LKM6c+USTZd99998UxSDlWrSmRhNAURxLUQzj008/d0H9NgVZg7zOp+vYoUMP\nVldXc8iQm2gypVKSxlIQAvn++x+4pb+/Itw1dp6TwmPJkiXOzw6HA7/++itWrFiB1atXN/MUVg8P\nhUfTOHjwID777DOoVCoMHTrU+ZT56quv4scff0RKSgoefvjhJgVcAGDjxo1Yvnw5AgICMGLEiLPu\nmVm1ahVeeeUViKKIQYMGYdcu+W1l+PDhZwgpHT16FIsXL4bdbkd4eDi+/vpreHt746GHHoK3tzdI\n4vPPP0d+fj4SExNRUlKCEydOICsrC4WFhQCAvn37wtdXzvP/9ddf8fvvvyM8PByvvfYaCgoK0LVr\nVxQWFuLEiRMYPHgwNm3aBI1Gg9GjR6OoqAh+fn7QarXYvn07oqOjsWzZMuzfvx8xMTF45513UFtb\niwEDBsBms0EURWRmZmLVqlWIjIxEnz59UFBQgMjISDzzzDM4fPgwBgwYgJMnTzoFnZYsWQKDwYDk\n5GRs2rQJwcHBGDNmDHbu3IkuXbrA19cXJ06cQJcuXZw0J9999x0WLVoEX19fDBs2DHv27EFMTAy6\ndesGlUoFq9WKr7/+2kl3sWHDBmg0GrRp0wbbt2+Hn58f9Ho98vLy0KpVKwwcOPCs97chfvnlFyf1\nyb59+3D06FGkpaVh9+7dsNlsSE5OxubNmyGKIpKTk7F9+3aEhYVBr9cjPz/fSb9x/Phx5ObmIjU1\n9Yw+VqxYgQ0bNiA6OhrXX3/9WUWH9uzZg59++gm+vr7o37+/Ij1KfPfddzh48CCysrKQnJzcZH2S\nWLp0KbZv346EhAT07dv3vK4FSXz55ZfYs2cP0tLS0KNHj/O6ftcaLhuFR0MtiokTJ/KJJ55o8mmw\nuXAeZv4lsWvXLnp5BdNoHEejcQx9fEK5d+9ezpz5BEUxlnr9XZSkdI4adWuT2UkfffQxRTGIev3f\nKUnd2LZtlyYDlWvXrqUk+dNguJ06XSZVKh+lXid27tynUcpscXEx/f0jKAg30Wi8lWZzILdu3eo8\n73A4OGzYWEpSG+r1d1GlCqZOl0CD4U6KYkCTQjI2m40BATGUdSDuIODPIUOGc+vWrTSbA2k03kpB\nuIn+/hEsLi7m1KkPUpJaU6u9U4lltFXqeVOmDLlFedvpT5l6Q6JON4GS1JnZ2b14/PhxZQ9HB8q7\nmC38xz/u5sqVKymK/jQYJlGj6aO8UUwgkEY/v+hGbzANIb8ZBNBguIOi2JdxcW2aXH/Py8ujxRJE\no3E8BeEm+vmFs6ioiPffP4OS1Eq5vym85RbXZJpNobq6mpmZOZSkbtTpxlMWVRpGvX48AZE63TCK\n4hBGRsbz2LFjznqVlZVMSsqiJPWiXj+FghBwBp3LnDnzKIpR1Ov/QUlqy+uvv6lZif7uvHMqJSlB\nuRYJvPNO1/T1DeFwODhmzO2UpFSlXks++OCsZrPxSsJdY+c1MQJ7JgrXGDr0ZqrVTzoDf2r1Y7z+\n+tHU682UM3pIoIKiGNUkP5ePTyjrKSUclKQcvvee60ymrKxcJZjrUJZX6oRfamkyZfKLL75wlp04\ncQo1mvpgrkr1PHv1Guo8v27dOkpSDOtpGw4qyzonCPyXEREJLm2YN2+esrxTR69RQEDH7t0HU6V6\n3tmfRvMAb7ppPA0Gb8qiQw9RpsKoVcpsU3xwKD7VaSfcQTkIXUuTqT379OlDWZSoLrC7jiqVxKSk\n9pQ32tUFXcdQDkLXEGjBp556yqX9UVHJlIWJ5OttNF7PF154wWXZPn1upEr1bAOfHuTIkbfQYPCi\nnHklU5+IYijz8vJctuEKH3zwASWpC+WMpnsoZ4jV+fEy5c19pF4/no8++riz3htvvEFR7NfgWvzI\nkJCWzvPl5eVK0L2YddQnktSKv/zyy3nbdiHIz8+n0ejPek2L4zQa/c/KikzKS49ycsRppd4R6vUW\nHjlypFnsvJJw19jZJIXHo48+2uSrDAAnJYcHVw4lJWVwOBKd3x2ORBw8+DN0Om/U1NQFOkXodLEo\nKytz2UZ5eRmAujZUqK1NbLLs0aN1ZWsgB5NbK2c0IOMb1SspKYPdnuX8TibhyJFPnd/Lysqg1cZC\npu4A5ECpF4ATAJJw4oRrGw4cOACgFWRKDwCIAqDBoUNHQNYz4NrtiThwYCv0+iBUV/sBOKTYrlFK\ntFZ8sCnH6/pLAvA7AA0cjngcObIZQFvU02QkgrQqvtZfeyAZsvaFDkCcYueZkP2qv97V1UkoLXXt\n65EjZSDr+7Dbk3DgwO/Q6wNRXV0XTDZBp4tCaWmpyzZcQWb0TYBMNVIGoOsf/HgfAFBTk4jDhw80\nqlddnYj6a5GEkyfrbT916hTUahFyYgEAGKDVtmzy93SpOHbsGPT6MFit3soRb+j1YSgrK0N0dHST\n9crKyqDTRQOQlCMB0Ov9cfz4cQQEBDSLrdc6mlw8lCQJJpOp0Z9KpcKCBQvw1FNPXU4bPWgCgwf3\ngCg+CVkcpgiiOAfDh/eHj48Aleo5yFxAS0BuQ5s2bVy20alTD+h090POwFkFjWYxunbt6rLsgAE9\nIAiPKGXbAJiufP4R5FJkZ2c3sk2S5kHO6imBKD6OwYN7Os9nZGTA4dgCWQjoNIC5kLl+zDAYHkCP\nHvVlG2LEiBEAfgawVKn3KHQ6ETfe2Bei+DiAEgAFkKR5GDFiAAShGirV6wAGQhb2+VGxeTqADMgi\nSw8AyIYsbPQ0gE6QBYG+ws033wzgI8gCQ+UApsLbOxR9+/aE0TgDsrhTHoAXlDa+A7Acw4cPd2l/\njx49YDA8CHlC/A2CsBC5ud1dlh08uCdE8QnIk1whRHEuRowYCFGshUr1quL/h1CpCl3GCppC165d\noVJ9CuAXxdc5kEV8DgN4UDm2DaL4Cvr1q1+779atGwyG9yBnKp2EXv8AunWrv0/BwcEICQmEWj1X\nse1L2O0b0K5du/O27UIQHx8Pna4MwELIAlELodOVNSnIVQf5Wu0B8DGA01CpXobZrDrr5PKXx/m8\ndpw8eZKPP/44o6OjOX36dE+M4iqB3W7n3XdPpyB4URC8ed99D9Jut3P37t1MTm5PrdbAqKjERpvN\n/ojS0lJ26zaAOp1AP7+IRrxDf4TVauXNN99Gg8FEUfRlVFQStVojAwOjz4gpOBwOzpjxGEXRh0aj\nhZMm3XXGuv2qVasYGZlArdbA8PAEms0B1OtF9us3jCdPnmzSjmeeeYZqtYWAlqIYzDVr1tBms3HS\npLtoNFooij6cMeMxOhwObtu2jXFxbanVGujjE0iVykxAq+ztMBDQUaWyUJY3FejtHer06euvvyZJ\nTps2nSqViYCW3t6R3LVrFysrK3njjWOp10uUJD/qdN4EtFSrLS4p9etw6tQpDhw4gnq9SG/vEC5c\n+E6TZWtrazl58t1Onx56aBYdDge3b9/OhIRMarUGxsQkc8OGDU220RQ+++wz+vtHUqs1Mjo6kaLo\nS4PBzJiYFOr1Ei2WQD7//Etn1Hv//Q/o4xNKnU5g795Dz8h6KygoYFpaNrVaI8PD45pkhHYXNm/e\nzJYt06nVGtiyZfp57xpfv349o6OTqNUamJiYxR07djSrnVcK7ho7z9pKaWkpH3roIUZHR3PmzJmN\nAluXE56J4vKgqKiIOTkDGBAQw06d+lwUdcLy5cuZkJDFoKAWHDv2b81C7PbUU09RpfIhYKZW68Ww\nsAQGB7fiXXdNP2vK6Nq1a5mS0pGBgbFs2TKVGo0P1Wpvtm/fzS07jf+IXr16KUFzM3U6vzPWzg8f\nPsy+fW9kQEAMMzO7cdu2bY3OOxwOzp49l2Fh8YyMTOJrr71Bkly0aJGzXcCbc+fOJUl++OFHjIlJ\nZVBQS3bs2J0hIa0ZEZHI9u27MzAwlq1bt2FaWjYDAmLYtWv/s/JCNcTOnTvZvn0PBgTEsEePIU7u\ntpdeeoUREYkMD0/g00/Pp8Ph4JEjR9iv3zAGBMSwXbucRgkM54sNGzYwLa0TAwNjOXToGJf8b82F\nl19+lRERSQwLi+ecOfMum+Jec6HZJ4qpU6cyNjaWc+bM4alTp9zS2cXCM1E0P6qrqxkVlUiN5lEC\nu6hWP8XQ0JYutQ2awvbt2ymK/gSWENhBo/EG3nDDGLfauWLFCiVL6S0CH1Jme/0vga0UxW68++77\nXdbbt28fTaYAAu9T3iU+kjIb6yYCbdi5cy+32nnXXXcpwfn/UN7B3ZNara/zvN1uZ3LyddRq7yWw\niyrVK/T1DWv0MPbCCy9TFFMp7xxfRVGM5YIFb1POsHqQwC4CTxOQlEBzKIFllLUxUgj8TiCHwDDF\nz3DK2hO7qNE8zsjI+HMS7508eZL+/pFKosAuarUPsHXrNly06F2KYivKbLbrKUlJfPXV15ma2oE6\n3d2KT6/RxyeUpaWl533d9u/fT7M5kMC7BHZSr5/Azp37XPgNuAjIYlQtKdOwbKAoJvPll1+7LH03\nF5p9olCpVDQYDE76joZ/HgqPPx+2bNlCk6l1g+wX0mJJ59q1a8+7jeeee44Gw+QGbZRRr5fcaueg\nQYMaZCjdT5nSu66/rQwObuWy3jvvvENJakgNUa0sN1UTWE2tNsCtdvr6+rKe0oNKJpDgPH/gwAGF\nYNDR4Hp3b0T33q5dLoFvGrSxiK1bp1HmnmpIr5HA2NiWBJ5Rvl9HmTa9VvGxkjJ3Umqj+2s2x/P3\n338/qx/Lli2jl1d2g3oOimI4O3Xqx4biV3VUK7IAkb2BTz2bJPt0hffff58m040N2rVRozFc0APL\nxaJPn2GsoymR//7D665z7wPE5Ya7xs4ms54uVADGg2sbkiTBbj8BOSgoAbCitrbUqYl8vm1oNA2z\nfQ7CaDz/+ucDHx8fALshU2NIkAP5dTgASXLdnyRJUKkOQqbGUEEOeusgC/kcgFarc1nvYiHrPRc1\nOHIQ9RlXgCiKcDiqIAe1fQDUwuEoaXS9LRYTGvqnUh2An58P5EBsBWQBqBoAZfDyioBGcwB2OyBf\nl4OQc1WMkIPhEuQMJ6tyrBK1tcfPeX9NJhNqa49Azg7TASiH3V4Ob28TVKqDqN/LdQDe3hbY7VbF\nJ18A9jN8Ohckqc72uvt0BCqV6pKE084XXl4mqFQHGvnk5eXe3+81C7dMN82Ma8TMaxoOh4MjR46n\nJHUgMIei2IUDB464oDXaU6dOMSYmiQbDaAKzKYpRfOUV9766nzhxQpET7aksv5goCxo9RkEI4uef\nf+6yXlVVFRMTM2k03kBZjzuMQDZlrWgTn3zySbfaKS+RSQRuVpZ7fBkXl9iozJQpUylJ6QTmUBB6\ns3Pn3o02La5Zs4ai6EeV6kGq1VNpMgVw27Zt1Gp9lKWlOQQ6UKXyYn5+Pn18QpWNheNYr/3dlTL5\n4Gyq1S2pUrVT7m9HDh8+7pz31263s0ePQRTFXAJzKEntOGHCncobqD/V6mlUqf5JSfLnhg0beNdd\n0ylJaQSepCD0YXZ2zwvSLrFarUxN7UCjcQhlzfQ4zpr1rwu7+BeJvLw8mkwBVKvvo0r1ICXJ/5qX\nY3XX2HlOCo+rAR4Kj8sDh8OBRYsWYdOmPCQlxeHWW2+FRqNpsvzBgwedtBWiKGLv3r0IDQ3Ft99+\nhyNHypCb21V5U7Gjffv2ytPipaOkpAS9evVCSckxpKbGIyoqGidPnsZtt41H7969AQBHjhzBxo0b\n4efnh3bt2kGlUqGiogIzZsxAfn4x0tISsXz5T6iqqsaUKX/D2LFjz6vvmpoarF69GjabDR06dHDp\n0/bt21FQUIATJ05gypS/w2p1IDe3E/7zn/8AkPP/169fD7PZjMLCQqxbtxGtWsXgtttug16vh8Ph\nwJo1a3D69Gmo1Wq89dZC6HRaPPjgA0hISIDVakViYiL27y9FYKAFW7duhbe3NwoLC/Hoo4+joqIC\nbdu2wTfffAtBMKJbtxysWbMOERHhaN26FfbsKURqaiJuueUWqNXqRj61b9/+jDcAm82Gt956Czt3\n7kW7dukYPXo0VCoVdu3ahUWL/g2SuPnmm5CYmAiS+Pjjj7Fmza9o2TIKt99+eyOfysvLkZycjB07\ndkCj0aBDhw4wGAyN+qusrMTrr7+OoqKD6No1G0OGDLmYn8lFYffu3Vi06N+w2+24+eabkJSUdO5K\nVzEuG4XH1YBrxMy/FP73v/9Rkvzp5dWTOp0/NRofenn1oiD488033+bJkyeZmJhJs7kNLZYOjIiI\na6R06A5UV1eza9e+NJkSaLHk0M8vnNu3b+eqVatoNgfSyyuXkhTD4cPH0W63c+LEv1MUI+jl1ZOS\n5M///e9/F9TfqVOnmJx8Hc3mdFosHRge3poHDhxoVOaxx+ZQEIKc1+KPhHa///47vb1DaLF0oyS1\nYp8+Qxs9cdfU1LBbt/40meJpMnWkWm2mJGXRbM5gQkI7njhxggsWvENB8Ff6COTcuc+yqqqKWVnd\naDIlUZI6Ug74JypvTiItllyKYiTHjZvU6C2ivLycqakdaDKl0WLpyLCwViwuLr6Iu9E0ampqmJs7\nkCZTHM3mHKrVJopiCs3mDMbFZVzWrKa/Gtw1dl4TI7Bnori64HA46OMTQln/oZCy5nKREgDcSaPR\nm3fccTcNhnHOoKtW+wCHDRvnVjteeuklCkIvAjbKNCEvMSsrlxER8QQ+VeyppCS14aOPPkpJak3g\nlHL8B/r4hF5Qf9OmPajofdf59CCHDr3ZeX7Hjh0UhCDW06dsodHo1YjLKTm5PWVRKTmgLkmduXDh\nQuf5V155haLYQ/FpPGX9ajmIrNffykmT/kGj0YvADmeQXBD8ef/9/6TROJj1FCVzKFNxRLKeMqSc\nJlNiI22Sf/5zhrJUKPuk0czg4ME3XfxNcYHXX3+dotid9bQrrxHoovg0kVOmnJufyYOLg7vGznPq\nUXjgwR9RU1ODkyePAugGOWDbGrL+AgC0hk4Xgi1bdqG6uifq6B5qa3th5858t9qxe3cBqqq6Qw5I\nA2QvFBTk49ChAgC9lFICbLbO2Lp1K8gOAMzK8W44efIIqqurz2y4CWzfXnCGT7t2FTjPFxYWQq9P\nhqxLAQDJ0Gi8UVJS4ixTVFQAoG43sx4VFd2wd2/9ddm9uwCVlXU+5QPoo5xRoaamJ7Zs2QWdLhhA\nnHI8HHp9HDZt2g6rtQfqA+Z9IO+23g+gbne1CXZ7R+Tn1/cn+9TD6ZPd3gu7drn3Pu3dW4DKym6o\np13prfgm+7RjR0HTlT24KuCZKDy4YBgMBkREtAbwNuQBayfqBX2WAShFt27tIYrvQuZTqoXBsAAd\nOmS41Y7MzDaQpI8hZ9kQOt0baNs2AwkJGVCrX1dKHYJO9x/k5uYC+B6yIBEAvI2IiNZnrI+fDZ06\nZZzhU/v29T4lJiaipuZ3yFxRALAUWq0V4eHhzjKpqW2g0bwBOaunFJK0GG3b1reRlZWh+HQcMsXI\na5AzjqwQhEXo1q09ZNqQH5Qa62Gz7UBubjZE8X3INCMOAC8r9ZMA1F2LIqhU3zaic+nYsQ1E8d8A\nKhWf3mrkkzvQrl0GJOkTxW4CeBUyBYzsU3a2e/vzoBnglveSBhg/fjwDAwOZnJzsPPbII48wLCyM\n6enpTE9Pb0T3MHv2bLZs2ZJxcXFNynU2g5keXCK2bt3KoKAYimIYNRojdTozRTGcJpM/f/jhB9bU\n1HDIkFHU671oNPqxU6deLvWZLwUOh4OTJ99Nnc5EQQhiYmImDx8+zD179jAiIo6iGEqdTuJjj8kZ\nTc899xL1ehNFMYxBQTEXvGvYZrNx6NDRik/+7NChxxmbUT/++BMKghdFMZxeXkFnUFgUFxezVat0\nCkIw9XoTp059sFHMwOFw8M4776VOZ6LRGEhBCKLB4EeDwZuDBo1gTU0Nly1bRrM5gKIYTkHw5mef\nfU673c5x4/5Gvd5MgyFAoSgxEdBTrbZQFMOo15s4b15j0SGbzcYbbxzj9Kl9+1y3b7B1OBz8xz+m\nKfcpmIIQSIPBhwaDN/v3H9Ysu+I9kOGusdPtI/DKlSu5cePGRhPFrFmzGmkW1yEvL49paWmsqalh\nQUEBW7RoQbvdfqaRV/lEUVhYyJEjb2WnTv355JNPX1A64LUMm83GgoICnjp1ipWVlczPzz9jp29J\nSQkPHDjgMg2ztLSUEybcyezsfpw27SFWVVVdlB1lZWUsKirip59+ytzc69m794384YcfWFhYeAYX\n0alTp1hQUNCkXoQr/PjjjwwPT6DFEs3+/YfywIEDjXyqqanhzJmPMzu7H8eMuZ179+5lfn5+kwOg\n3W7nvn37zkqJU+dTbW0tDxw4wJKSEue506dP8+9/v49t23bnqFG3cNiwMezUqT8fe+xJHjp0iMXF\nxfzggw/Ztm0Ou3Tpy5UrV7KgoKBJ/qyVK1cyN3cws7P7cvHiJed9XS4UZ/OpoqKC99zzALOz+/H2\n2//h8tp88slidu8+hP36DefPP//cbHb+mXDVThSkTAz2x4nCFVHa7NmzOWfOHOf33r17c/Xq1Wca\neRVPFEePHqW/fwQ1mkcIfE5R7MS//e0fV9qsqx5VVVVs0SKVOt2dBL6gIAxhz56DL5pbZ/HiJRSE\nMGVn7VsUhAC3ENJt2rSJKpVEeQf4ZwTSmZ7esVGZ4cPHKUH1L6jVTmNoaMuzkhpeChwOB7Oze9Fo\nHEHgCwJjCUQRWExR7MaxY29XZEyjKFOcvEZR9Of69etdtrd69WoKgj+BNwh8QFGM4Ecffdwstp/N\npy5d+tBoHEbgC+r1tzM+vm2jifb99z+gKEZS3g3+OkXR/4JYA/6quOYmiqioKKampvLWW291psNN\nmTKlkUjOhAkTuHjx4jONvIonioULF1KSbmD9tv9SarVGl29GHtTjhx9+oNmcyXoqimoaDD4XnUKb\nldWTMsdU3X14kTfeOO6S7Rw1ahRlrqS6dg8Q0DvPV1RUUKs1EqhwljGbe5yVhfdSsGfPHoXTyebM\nhpIFmdYQOEmNRs+kpA4Eljaw+SmOH+9aBW/06IkE5jco+yXbtMlpFtubQkFBgZItVu+T2ZzaSPAo\nNbUzga8b2DmPY8bcflntvBbhrrGzSQoPd2Ly5MlOoaMZM2Zg6tSpWLBggcuyTendzpo1y/k5JycH\nOTk57jbTAw888OCaxvLly7F8+XL3N+yW6eYP+OMbRVPnnnzyyUbUCb1793apndBMZroFnqWni8Of\nc+npc+fSU3MxLp+59DSGQPRZlp5evSaXnhIS2nmWntwAd42dl2WiaLicMH/+fI4aNYpkfTC7urqa\n+fn5jI2NdTlQXM0TBVkfzO7c+c8VzD558uQFB34vBKWlpZw4cQqzs/tx+vSHncFsh8PBgwcP8uDB\ng+c1cZSWljYKZvfpcyOXL1/uNjt//PFHRkQk0mKJcQaz9+/ff0Ywu1On/hw79m/OYHbDwL7D4eCh\nQ4fO26ezoaKignfffT+zs/vx5psnNApm192rjz/+P2fgd9WqVWdtb+XKlezXbzi7dx/CTz5ZzKKi\nIpaWlrKmpob5+fksLy9nRUWFy2QFd6GiooJTp/7TE8x2M67aiWLkyJEMCQmhTqdjeHg4FyxYwDFj\nxjAlJYWpqakcPHhwo2yHf/3rX2zRogXj4uL47bffujbyKp8o/oyYP/8FJZU0nEFBMczLy7ss/VZV\nVbFnz8FK+qQPe/Yc3GQ2VF16rF5vdqbHNvxtuRsXkh4rSRHO9Fir1creva9XfPJlbu7Ay0KbfaE4\ncuQIU1LaUxCClPRcPwpCGLVaiVqtyenTypUrr7SpHpwnrtqJojngmSguL9auXUtRDKNMz0ECrzM2\nNuWy9D1t2kMUhCGUdSKqKQhDOH36wy7Lvvfee5SkNgSOE3BQp7uPffrc0Gy2zZnztEKvUUnARoNh\nDCdO/LvzfFFREQXBj8BvynX7hl5eQZw27UEKwiACVgLVNBqH8t57/9lsdl4sBg4cSZ3uLiVAfoJA\nGwLvENhNIIDAZgLf0ssr6Kqc6Dw4E+4aOz07sz04A7///jtkmoUo5chEFBRsg81ma/a+V636DVVV\n4wHoAehRVTUev/yy0WXZ9et/Q0XFCADeAFSw2W7Hr7+6LusO/PzzRlRWjgUgANCiunoC1qyp72/b\ntm3Q69MBpCtH+qK21ogff1yt+GQAoIfVOh6rVjWfnReLDRs2wma7HTKdhxeAmwFsBNASQHcAmwD0\nht0uobi4+MoZ6sFlh2ei8OAMxMTEQKVaBeC0cuQH+PqGQKdzr7iPK8THx0Cn+y9kqgdCp/svEhJi\nXZZt1SoGgrAMQC0AQKX6L2JiXJd1BxISYmAwfK/YBmi1/0Xr1jHO89HR0aip2QJZFAkAtsJuP4GU\nlHjo9fU+6fXfIz6++ey8WMTGxkCl+q/yzQ6Z8iQWMkXKWuVzHmpryxASEnKFrPTgisAt7yXNjGvE\nzD8NHA4Hb731DopiJL28elCS/Lls2bLL0ndpaSlbtEil2ZxJszmTLVqkNqm5XE8zHk+LpauTZry5\ncGE04z0pijLNeFlZGVu1SqPZ3I5mcxZbtEjh0aNHm83Oi8XOnTvp7x9JL6+uNBrjqFZ70WLJpU4X\npNDI96Qg+PPdd987d2MeXBVw19jpES7ywCVOnz6Nhx+egX37ijBkyCCMGzfO7X3U1NTgzTffxO7d\nBcjKysCoUaOgUqlgtVqxatUqAEDHjh0VWVHXsNvtWLt2LU6fPo2srCx4e3u73c6TJ0/i1Vdfw+HD\npejevQssFgtqa+W3mG+//R5ms4TbbpvofMquEy5KTExEdHQ0AGDz5s2YO/dpOBzEtGlT0aZNG5DE\nRx99hLVrf0XLltFOkZ8riZMnT2LdunUQRRERERHIy8tDaGgo9Ho9CgoKkJCQgJiYmHM35MFVAXeN\nnZ6JwoMzUFVVhbZtO6OgIBZWawZEcQFmzpyE+++f6rY+7HY7cnMHYt06jo04BgAAE59JREFUO6qq\nukOSPsbYsV3xyivPuq0Pd+D06dNIS+uAAwdSUV2dDFF8A3PnTkdkZDhGjrwNlZV3Qqs9BG/vr7B5\n81qXSzKbN29Gx465qKycAEAFUXwLK1d+h4ULP8DChT+gomIkBOFHtGsH/Pjj12dVFfTAgwuBR+HO\ng2bDRx99RJOpewN6jQLq9dIl5/83xM8//0yTKaEBbcNx6nQmlpWVua0Pd+Dtt9+mJA1oQB2RR7M5\ngC1bZjSiydBq7+DMmbNctjFkyOg/0GS8yF69rqdebyJwTDlmo8mU6JZNgh54UAd3jZ2eYLYHZ6Ci\nogJkKOrEbIBg2O01sNvtbu1DrQ5CnegQ4AWtVkJFRYXb+nAHKioqYLeHNjgSBqv1NCorKwCEOY/W\n1obh5MnTZ9QHgFOnGpcFQnH8+Cmo1QLkjC0A0EKtDsbp067b8MCDKwnPROHBGcjNzYVK9R2ADwHs\ngsFwO7p37w+t1n3UYFlZWdDp9kClehnAbuh00xETE4mwsLBz1r2c6NWrF9TqTwEsAbATRuNt6N//\neowcORSi+HcAWwF8D1F8ETfcMMhlG2PHDoUozoCcObQeovgwJkwYiZYtY6HV3gdgN1SqV6HV7sR1\n1113uVzzwIPzh1veS5oZ14iZfyqsWbOGKSkdGRgYyxEjxjcLd9H27duZlZXLgIAY9ulzAw8fPuz2\nPtyBlStXMjHxOgYFteCYMbfz9OnTtNlsvOeeBxgc3IotWqSflS3W4XDw+edfYkREIsPDE/jMM8/R\n4XDwyJEj7Nv3RgYExDAzszu3bdt2Gb3y4K8Ad42dnmC2Bx5cBKqqqjB27CR8+eUSGI0SZs+ehTvv\nnHylzfLAg0Zw19jpWXrywIOLwJ133oevvjqNmpoinDq1DNOnz8XSpUuvtFkeeNAs8EwUHnhwEVi6\n9HtYrY8D8AWQhMrKyVi69H9X2iwPPGgWeCYKDzy4CPj5+QHY5vyu1+chKMjvyhnkgQfNCE+MwgMP\nLgI//fQT+vQZCrv9Rmg0hxAQsAu//76qWXaGe+DBxcKzM9uDqxK1tbX45ptvUFZWhuzsbLRu3fpK\nm9Rs2LlzJ7799ltIkoQRI0bAbDafV72CggKsWLECFosFAwYMOIO2w2q14uuvv8bp06cRERGBTz75\nBFqtFtOmTUNkZGRzuPKngN1ux9KlS3HkyBF07NgR8fHxV9qkKw7PROHBVYfa2lp07z4Qv/1WBjIe\n5FIsXvwu+vbte6VNu2qwcuVK9Ot3A4DeUKkK0aqVCqtWfe/ks6qsrMR113VHYaEBtbVmWK0/AugK\noBpq9Xps2rQKycnJV9KFqxJ2ux19+gzFmjUHQCbB4fgGH374FgYPHnylTbui8FB4eHDV4f3336ck\ndSJQq9BSLGNgYPSVNuuqQosW6Yr2Ngk4KAj9+MorrzjPz58/n0bj9Qp9yigCTzSg/riL8fEZV9D6\nqxdLliyhyZTVgBJmFb29Q660WVcc7ho7PcFsD9yGkpIS2GwZAOpI7drh2LGSs1X5y+Ho0RIA7ZRv\nKlitbXHoUP012r+/BFZrO8j0KYcANNypfR1KS8svm63XEkpKSmC3p6OeEqYtTp06AofDcSXN+tPA\nM1F44DZkZ2dDo/kEwHYAdmi1TyAzs/OVNuuqQqdOnaHX/wuADUA+BOHf6NKl/hp169YZovg2gH0A\nsgHMBlAO4BiAuejUKe0KWH31o0OHDgC+ALAFgAMazRNIT8+GWu0Z4twCt7yXNMD48eMZGBjI5OTk\nM87NmzePKpXKyRBaUFBAo9HI9PR0pqenc/LkyS7bbAYzPWgmLFiwkEajhWq1ju3adWVJScmVNumq\nQllZGTt37kO1Wke9XuKzz754Rpk5c+ZRrxepUmlpMPgT0BDQMDk5kzab7QpYfW3gvffepyh6U63W\nMS2tI/fv33+lTbricNfY6fZg9k8//QSTyYSxY8diy5YtzuPFxcW47bbbsHPnTvz666/w9fVFYWEh\nBg4c2KicK3iC2dcWSKKmpgYGg+FKm3LVoqamBjqdDiqVyuV5h8OB2tpa6PV6WK1WqNXqKy5qdC3A\n89trjKuWwqNz587w8fE54/i9996LuXPnurs7D65CqFQqz3/Uc0Cv1zc5SQBoNDEYjUbPJHGe8Pz2\nmgeXZQHviy++QHh4OFJTU884V1BQgDZt2iAnJwc///zz5TDHAw888MCDC4D7BAaaQGVlJWbPno3v\nv//eeazuVSg0NBTFxcXw8fHBxo0bMWTIEOTl5bncuDRr1izn55ycHOTk5DS36R544IEH1xSWL1+O\n5cuXu73dZtlw1zD2sGXLFvTo0QOiKAIA9u/fj7CwMKxbtw6BgYGN6nXr1g3PPPMMMjIyGhvpiVF4\n4IEHHlww3DV2NvsbRUpKCg4fPuz8HhMT4wxml5aWwsfHBxqNBvn5+di9ezdiY2Ob26T/b+/eY9os\n9ziAf4uUXRjbhDE8rgwQ0HEtBYQMQxRjxDHnyMTJRZvBJlPC4uYSL+cfZmLOBpNkDtzcnLItGFkC\nBoxBRCNkKGcggssyjAi2SYGNcJF7uPY5f+ysAWFd6R3y/SRN6Nv3bX7f0jw/6PO+T4mIaAnMPkeR\nkpKCmJgYtLW1wdPTE0VFRfMenzuBd/XqVcjlcigUCrz00ks4d+4cF1UjIrIzXOuJiGiFstvTY4mI\naGVhoyAiIr3YKIiISC82CjKKEAJnznyC3bvTcOjQUfT29tq6JCKyEE5mk1HefPNtXLhQi/HxbEil\nTfDw+A43b/6C9evX27o0Ivo/fsMd2czs7CxWr3bGzEwngE0AgHXrEvDpp0okJyfbtjgi0uFZT2Qz\nWq32/2++NXO2rsXMzIytSiIiC2KjoCWTSqXYsycZa9a8DKAWDg4fQir9L5599llbl0ZEFsCPnsgo\nk5OT+Pe/30d19VXIZP/C6dP/gb+/v63LIqI5OEdBRER6cY6CiIisgo2CiIj0YqMgIiK92CiIiEgv\nNgoiItKLjYKIiPRioyAiIr3YKIiISC82CiIi0svsjSIjIwMeHh4ICQlZ8Fh+fj4cHBwwMDCg23b8\n+HH4+/tj27ZtqK6uNnc5y0Jtba2tS7Ao5lveVnK+lZzNnMzeKNLT01FVVbVgu0ajwffffw8vLy/d\nttbWVly5cgWtra2oqqpCVlYWtFqtuUuyeyv9zcp8y9tKzreSs5mT2RtFbGwsHnzwwQXb33rrLeTl\n5c3bVlFRgZSUFEilUnh7e8PPzw+NjY3mLomIiExglTmKiooKyGQyhIaGztve3d0NmUymuy+TydDV\n1WWNkoiIyFDCAlQqlQgODhZCCDE2NiaioqLE0NCQEEIIb29v0dfXJ4QQIjs7WxQXF+uO279/vygr\nK1vwfAB444033ngz4mYOjrCwjo4OqNVqyOVyAEBnZyciIiLQ0NCALVu2QKPR6Pbt7OzEli1bFjyH\n4BLjREQ2Y/GPnkJCQtDT0wOVSgWVSgWZTIbm5mZ4eHjghRdeQElJCaampqBSqfDnn38iKirK0iUR\nEdESmL1RpKSkICYmBm1tbfD09ERRUdG8xyUSie7nwMBA7N27F4GBgdixYwfOnDkz73EiIrI9szeK\nL7/8Et3d3ZicnIRGo0F6evq8x//66y+4uroCAKqqqnD58mVIJBKkp6cjPj5+0ef85Zdf4OjoiK++\n+mre9tnZWSgUCuzatcvcMcyiqqoK27Ztg7+/P3Jzc++532L5BgcHkZSUhICAAAQGBuLatWvWKHlJ\nlpqvrKxMt+348eMICgpCSEgIUlNTMTk5aY2Sl+R++Wpra7FhwwYoFAooFAp88MEHBh9rD4zNp9Fo\nEBcXh6CgIAQHB+P06dPWLv2+TPndAct/bNGXz6ixxSwzHUaYmZkRvr6+QqVSiampKSGXy0Vra+ui\n+8XFxYmdO3eK0tLSeY/l5+eL1NRUsWvXLmuVbTBT8ymVSvHZZ58JIYSYnp4Wg4ODVqvdEKbkU6lU\nwsfHR0xMTAghhNi7d6+4ePGiVeu/H0Py1dTULPreM/S1sSVT8t26dUu0tLQIIYQYGRkRjz76qF3l\nMyXbXct9bNGXz5ixxWZLeDQ2NsLPzw/e3t6QSqVITk5GRUXFgv0KCgqQlJQEd3f3eds7OztRWVmJ\nAwcO2OVktyn5hoaGUFdXh4yMDACAo6MjNmzYYLXaDWFKvvXr10MqlWJ8fBwzMzMYHx9f9CQGWzI0\n32LvPUOPtSVT8j300EMICwsDAKxbtw4BAQHo7u62eM2GMiUbsHLGlsVqN3ZssVmj6Orqgqenp+7+\nYtdQdHV1oaKiAm+88QaA+fMbR44cwcmTJ+HgYJ/LVZmST6VSwd3dHenp6QgPD8drr72G8fFx6xVv\nAFPyubq64ujRo9i6dSsefvhhbNy4Ec8884z1ijeAIfkkEgnq6+shl8uRkJCA1tZWg4+1NVPyzaVW\nq9HS0oLo6GiL12woU7OthLHlXvmMHVts9koYMml9+PBhnDhxAhKJBEIIXYf85ptvsHnzZigUCrvs\n+IBp+WZmZtDc3IysrCw0NzfD2dkZJ06csHTJS2JKvo6ODpw6dQpqtRrd3d0YHR3FF198YemSl8SQ\nfOHh4dBoNLh+/ToOHTqExMREK1RmHubINzo6iqSkJHz00UdYt26dpUpdMlOyrZSx5V75jB1bLH4d\nxb388xoKjUYz7yptAPj111+RnJwMAOjr68O3334LR0dHNDQ04Ouvv0ZlZSUmJiYwPDwMpVKJy5cv\nWzWDPsbmk0qliI6Ohkwmw+OPPw4ASEpKsrtGYcrvb3JyEjExMXBzcwMA7NmzB/X19UhLS7NegPsw\nJJ+Li4vu5x07diArKwsDAwOQyWT3PdbWTMnn6uqK6elpvPjii3jllVfsrkEam62/vx/19fUrYmzR\n9940amwxZjLFHKanp8UjjzwiVCqVmJycvO+E3759+xa9aru2tlY8//zzlizVKKbmi42NFX/88YcQ\nQoicnBzx9ttvW7zmpTAl32+//SaCgoLE+Pi40Gq1QqlUisLCQmuVbhBD8t2+fVtotVohhBANDQ3C\ny8vL4GNtzZR8Wq1WvPrqq+Lw4cPWLtsgpmSbazmPLfryGTO22Ow/CkdHRxQWFiI+Ph6zs7PYv38/\nAgICcO7cOQDAwYMHDX4ue7z2wtR8BQUFSEtLw9TUFHx9fRdcj2JrpuSTy+VQKpWIjIyEg4MDwsPD\nkZmZaa3SDWJIvtLSUpw9exaOjo5Yu3YtSkpK9B5rT0zJ9/PPP6O4uBihoaFQKBQA7pzu/Nxzz9ks\nz1ymZPun5Tq26MtnzNgiEcJOP4gjIiK7YJ/T+kREZDfYKIiISC82CiIi0ouNgoiI9GKjoGWvp6cH\nqamp8PX1RWRkJGJiYlBeXm7w8aOjozh48CD8/PwQGRmJuLg4i30l79DQEM6ePWvSc1y6dAm3bt0y\nU0VE98dGQcuaEAKJiYl46qmn0NHRgaamJpSUlKCzs3PBvseOHcOlS5cWbD9w4AA2bdqE9vZ2NDU1\noaioCH19fRap9++//8aZM2dMeo6LFy/a1dpKtPKxUdCy9uOPP2LVqlXzrsPYunUrsrOzF+wrkUgW\nnBff0dGBxsbGecswe3t7IyEhYcHxVVVViIiIQFhYmG5tqoGBASQmJkIul2P79u24ceMGgDtNKSMj\nA3FxcfD19UVBQQEA4N1330VHRwcUCgXeeecdAMDJkycRFRUFuVyOY8eOAbizhlJAQAAyMzMRHByM\n+Ph4TExMoLS0FE1NTUhLS0N4eDgmJiZMePWIDGOzC+6IzOHmzZsIDw83aF8xZ72puceHhYXd98Kq\n3t5eZGZmoq6uDl5eXhgcHAQA5OTkICIiAuXl5aipqYFSqURLSwsAoK2tDTU1NRgeHsZjjz2GrKws\n5Obm4ubNm7p9qqur0d7ejsbGRmi1WuzevRt1dXXw9PREe3s7rly5gvPnz+Pll19GWVkZ0tLS8PHH\nHyM/P9/g3ESmYqOgZe2fA3x2djZ++uknODk5obGxETdu3IBSqQQA3L59G05OTjh16hQkEgl++OEH\ng6+8vXbtGp588kl4eXkBADZu3AjgzlXKd79wKi4uDv39/RgZGYFEIsHOnTshlUrh5uaGzZs3o6en\nZ0Gjqq6uRnV1te4K57GxMbS3t8PT0xM+Pj4IDQ0FAERERECtVuuO43WyZE1sFLSsBQUFzfvmvMLC\nQvT39yMyMhLAne9sv/vX+/vvvw8fHx9d4wDufB3v9evXodVq9S4rfXcF3MXca7uTk5Pu5wceeAAz\nMzOL7vfee+8tWMJErVZj1apV846f+zGTPS4tQSsX5yhoWXv66acxMTGBTz75RLdtbGzsnvv/c1C/\ne6ZUTk6ObptarUZlZeW8/aKjo3H16lXdX/UDAwMAgNjYWN0S6bW1tXB3d4eLi8s9m4eLiwtGRkZ0\n9+Pj4/H555/rau7q6kJvb6/e2l1cXDA8PHzPjETmxv8oaNkrLy/HkSNHkJeXB3d3dzg7OyMvL2/R\nfRf7S/zChQs4evQo/Pz8sGbNGmzatAkffvjhvH3c3d1x/vx57NmzB1qtFh4eHvjuu+90k9ZyuRzO\nzs66s6oWmzgHADc3NzzxxBMICQlBQkICcnNz8fvvv2P79u0A7jSB4uLiRY+/e3/fvn14/fXXsXbt\nWtTX12P16tVLf9GIloCLAhIRkV786ImIiPRioyAiIr3YKIiISC82CiIi0ouNgoiI9GKjICIivf4H\nU2scxruJWfEAAAAASUVORK5CYII=\n",
"text": [
"<matplotlib.figure.Figure at 0x10f71ec10>"
]
}
],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The combination of IPython Notebook, matplotlib and NumPy is quite powerful. These are rich, mature and well documented libraries that are invaluable within the sciences. More details on matplotlib and NumPy, with tutorials, can be found here:\n",
"\n",
"* [matplotlib](http://matplotlib.org/) home page and [plotting examples with code](matplotlib.org/examples/pylab_examples/)\n",
"* [NumPy](http://www.numpy.org/) home page and [examples](http://wiki.scipy.org/Tentative_NumPy_Tutorial)\n",
"\n",
"There are of course libraries that are focused on the manipulation of genomic sequence as well. One that is availabile already within your Workshop on Genomics environment is PyCogent:\n",
"\n",
"* [PyCogent](http://pycogent.org/) home page and [examples](http://pycogent.org/examples/index.html)\n",
"\n",
"Now lets get back to learning more about programming!"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Complex types"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We've played with a few basic types but now lets dive deeper. The first thing to know about data types is that there are an infinite number, and you can even create your own (though that is outside of the scope of this tutorial). The types used in your programs should be intuituve, such as using a string to represent a sequence identifier. Programming languages come with builtin types, commonly referred to as primitives and we discussed a few of them in the Variables and Types section. These are basic building blocks that are widely used. However, often times the primitive types are insufficient: what if you wanted to represent a phylogenetic tree, or an alignment? \n",
"\n",
"One of the absolutely fantastic things about Python is that it comes with a few incredibly useful and rich data types that are built directly into the language. Sure, we could always implement complex data types (and it is done quite often in practice), but there are a few data types that are used so frequently that the designers of Python opted to just include them (and uber optimize them).\n",
"\n",
"The first type is a ``list``. A ``list`` is an ordered array of items and can be created by using the square brackets. Besides just storing data, they also support dynamically adding members, slicing and fancy indexing."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_list = [10,20,'attggcc']\n",
"my_list.append(1.23)\n",
"print my_list[1:3]\n",
"print my_list[-1]\n",
"my_list[1] = 30\n",
"print my_list"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"If you've programmed before, you may be shocked to see that the list can contain multiple different types. In this case, we have a list of two integers and a string. Each item can be referred to by its \"index\". The first element in the list is at the 0 index position (e.g., ``my_list[0]``)."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can also test whether an item is present in a ``list`` using the keyword \"``in``\". For instance:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"print 10 in my_list\n",
"print 100 in my_list"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"However, when performing lookups on lists, Python has walk through the list and evaluate each item until it finds the item you're looking for (or doesn't find the item). This can be expensive if the list is large or if the lookup is performed repeatedly. A more formal way to describe this is that the lookup time for a list is linear to the size of the list. The fancy notation used here is called Big-O, and a list look up is O(N), where N is the size of the list."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The second type is called a ``set``. ``set``s act like sets from math. They are unordered data structures, with a lot of fancy logic behind the scenes that enable near-instantaneous lookups (in other words, very fast for testing membership). These are effectively O(1). In addition, they support typical ``set`` functionality such as unions, intersections, and set difference. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_set = set([1,2,3,4,4,4,4,5,'aattggcc','ccggttaa'])\n",
"my_second_set = set([0.123, 4, 5])\n",
"print my_set\n",
"print my_set.union(my_second_set)\n",
"print my_set.intersection(my_second_set)\n",
"print my_set.difference(my_second_set)"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What happens if you try to index into a ``set`` like you did with ``my_list``?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One common use for sets is to help with lookup. Try the following:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"if 1 in my_set:\n",
" print \"1 is in my set\"\n",
"if 10 not in my_set:\n",
" print \"10 is not in my set\""
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next type up is the Python dictionary, or ``dict``. ``dict``s allow you to associate a key with a value (e.g., a GenBank accession to a DNA sequence), and allow instantaneous lookup like ``set``s. And just like a real dictionary, they are excellent if you need to find something. Behind the scenes, Python dictionaries actually use the same logic as sets and are so powerful and awesome that they are used almost where within Python itself."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# {key:value, ...}\n",
"my_dict = {'seq1':'aattggcc', 'seq2':'ttggttgg','seq3':'tgtgccc'}"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"You can add more items to the dictionary easily using square braces: "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_dict['another sequence'] = 'tatatat'\n",
"print my_dict\n",
"print my_dict['seq1']"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"All three of these types support whats known as iteration, which is a fancy way to say that Python knows how to walk over them with a for-loop. Below are examples of iterating over a ``list``, a ``set`` and a ``dict``."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for element in my_list:\n",
" print \"The element is:\", element"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for element in my_set:\n",
" print \"The element is:\", element"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for key in my_dict:\n",
" print \"The key is:\", key, \"And the value is:\", my_dict[key]"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Imagine the possibilities... for example, you could load a large number of GenBank records into a dictionary and pull them out by their accession when needed (e.g., ``{accession:record}``). Or, perhaps you could store loci annotation information such that you could get back the start and end positions for proteins by querying this data structure (e.g., ``{annotation:[start, stop]}``). \n",
"\n",
"There is one other builtin type that is worth knowing about called a ``tuple``. This is very similar to a ``list`` except that it is immutable, or cannot be changed. We'll take just a quick peek at it here (notice the use of parentheses instead of square braces):"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_tuple = [10,20,'attggcc']\n",
"print my_tuple[1:3]\n",
"print my_tuple[-1]"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Finally, there is one last type worth mentioning for performing numerical work called an ``array``. This data type comes from an external library that is widely used in scientific work called NumPy. Let's add it to our environment and create an ``array`` and show a quick example."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from numpy import array\n",
"a = array([[1,2,3],[4,5,6]])\n",
"print a\n",
"print a + 10\n",
"print a.sum()"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Complex types exercises"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"These complex types are fantastic, so lets learn a little more about them on. It will be necessary to use what you learned in the programmatic flow section.\n",
"\n",
"* Create a ``set`` from a ``list`` of sequences\n",
"* Given a ``list`` of sequences, produce a ``dict`` of all sequences longer than 10 nucleotides where the keys are the sequences and the values are all 3-mers in the sequence\n",
"* Reverse a ``list``"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"list_of_sequences = ['AATTGGCC', 'AATAAATTT', \"GCGGCAGATTTAGAC\", 'ATATATGGCCACCA']"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Functions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Functions offer a mechanism of abstraction, and abstraction is central computers. For instance, a web browser abstracts out the complex interactions with the internet protocols when you type in a web address. Behind the scenes, the web browser may have some function called get_url() that accepts a web address, but as a user, you don't need to care about those details. Functions offer a means to abstract out and encapsulate complexity. In addition, they make it easier to verify that the small components of your program are correct and adds verbosity. For instance, say you wanted to compute G+C content on a set of sequences:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_dict = {'seq1':'aattggcc', 'seq2':'ttggttgg','seq3':'tgtgccc'}\n",
"\n",
"for key in my_dict:\n",
" gc = 0.0\n",
" sequence = my_dict[key]\n",
" for nt in sequence:\n",
" if nt == 'c' or nt == 'g':\n",
" gc += 1\n",
" sequence_length = len(sequence)\n",
" print gc / sequence_length"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"But that's hard to read, and you have to think about it in order to understand what is going on. What if instead we chopped out the code the computes G+C into a function, and gave it a pretty name."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def compute_gc(sequence):\n",
" gc = 0.0\n",
" sequence_length = len(sequence)\n",
" for nt in sequence:\n",
" if nt == 'c' or nt == 'g':\n",
" gc += 1\n",
" return gc / sequence_length"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"We have added in a few new terms here, ``def`` and ``return``. ``def`` tells Python that we want to create a function, and in this case, the name of the function is ``compute_gc``. And ``return`` allows us to have the function give a result back. A function is analogous to a function in math: \"y = f(x)\". We can now rewrite our for-loop from above in a much more elegant form:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for key in my_dict:\n",
" print compute_gc(my_dict[key])"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"It is much easier to read the code and see what's going on now, right?"
]
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"Function exercises"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Functions are a great segue into algorithms. Algorithms are ways of doing things, and are an integral part of programming, and can be incredibly elegant. As a thought exercise, how would you sort a list of a billion numbers? \n",
"\n",
"Now some hands on challenges:\n",
"\n",
"* Write a function that takes an array of gene expression values and compute the mean and return the mean and standard deviation of those values.\n",
"* Given a ``dict`` of sequences where the key is the sequence ID and the value is the sequence, return the sequence ID of the longest sequence.\n",
"* Given two strings, write a function that determines if they are anagrams of each other."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"expression = randn(500) # 500 normally distributed values\n",
"dict_of_sequences = {'seq1':'AATTATATAGG',\n",
" 'seq2':'ATAGACCCAGCAGCGAA',\n",
" 'seq3':'GTGTCGATGTAGCAC',\n",
" 'seq4':'AACGATGTGTGACCCGACTGTCGTAG'}\n",
"word1 = \"quite\"\n",
"word2 = \"quiet\"\n",
"word3 = \"queen\""
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 81
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"File Input and Output (I/O)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So you've got your sequences in a file and you want to play with them. How? Writing robust parsers is outside of the context of this tutorial, and in the case of Python they aren't necessary (e.g., using [PyCogent](http://pycogent.org)). However, basic file input/output is pertinent. Lets first open a file and write some data to it."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_file = open('a_test_file.txt','w')"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"What we're doing here is specifying the name of a file to create, \"a_test_file.txt\", and the mode to open the file with. Computers are stupid, and must be told exactly what to do: when opening a file, you have to tell the computer _how_ you want to read and/or write data to it. In this case, we're setting the mode to write with 'w'. The default mode is to read, or 'r'. Be careful though, the 'w' is destructive! Any file open with 'w' will destroy its contents. How would you open a file to append data to it? (__hint__: Google \"open file python\").\n",
"\n",
"Lets put some sequences in our file:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"my_file.write('aattggcc\\n')\n",
"my_file.write('aattc\\n')\n",
"my_file.write('aattttaggcc\\n')\n",
"my_file.close()"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The write method is naive, and you have to structure the output exactly as you want. We added the newline character so that there is a single sequence per line. (You can look at the file on your filesystem as well if you open a new terminal window and change to the directory you started IPython from). Now, lets read the sequences back in:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"ro_file = open('a_test_file.txt','r')\n",
"\n",
"all_the_sequences = []\n",
"for line in ro_file:\n",
" print line\n",
" all_the_sequences.append(line)\n",
"\n",
"print all_the_sequences "
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The output from the above cell looks unusual, right? Can you figure out why there are gaps between the printed sequences, and how to remove those gaps? (**hint**: what does the ``.strip`` method of a ``str`` do?) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Files \"remember\" where the are when you are reading them, like a bookmark. In the above operation, we read the entire contents of the file, which means our bookmark is now at the end. To place the bookmark back at the beginning of the file, we ``seek`` to the first byte (the zeroth byte)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"ro_file.seek(0)"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The file datatype in Python is smart and nows how to iterate over itself line by line. This is particularly handy for very large sequence files as you don't need to read in the whole file all at once, and instead can work on it a small piece at a time."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"for line in ro_file:\n",
" print line"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "heading",
"level": 4,
"metadata": {},
"source": [
"File Input and Output (I/O) exercises"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Reading and writing files is essential when manipulating data. Lets learn alittle more about the ``file`` objects:\n",
"\n",
"* Excel and Google Spreadsheets and save CSV (comma separated value) files. These and tab-delimited files are common place. Write out a ``list`` of numbers to a file using either commas or tabs to delimit the values. \n",
"* Read the values back in from the file, are the types right?"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Final comments"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Thank you for working through the tutorial, you're well on your way to becoming a programmer and being able to tell your computer what to do. As is all things worth doing, it will be frustrating at times, but with practice comes experience. One of the biggest challenges when learning to program is coming up with small tasks to do. An excellent source of challenges in which you can hone your skills is [Rosalind](http://rosalind.info/problems/locations/). The problems are biological in nature, and you will learn quite a bit quickly. Or, if you're interested in learning mroe about Bayesian methods and probalistic programming, there is an [excellent tutorial](http://camdavidsonpilon.github.io/Probabilistic-Programming-and-Bayesian-Methods-for-Hackers/) using IPython and the Notebook.\n",
"\n",
"Programming is both an art and a skill, and something that can be incredibly powerful and rewarding. Good luck, and have fun!"
]
},
{
"cell_type": "heading",
"level": 2,
"metadata": {},
"source": [
"Toy De Bruijn graph"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The above tutorial covers the basics, but what does this all look like in practice? Below is a light example of a De Bruijn graph based on Rayan's [assembly lecture](http://evomicsorg.wpengine.netdna-cdn.com/wp-content/uploads/2013/01/2013-evomics-assembly.pdf) using the sequences from slide 27. Graphs are insanely satisfying data structures to play with and enable some incrediby elegant algorithms.\n",
"\n",
"This example covers a few topics that we did not discuss in the tutorial, specifically:\n",
"\n",
"* ``None``, or no value, null, etc.\n",
"* the ``is`` operator which checks for identity, or if two variables refer to the same piece of memory. It turns out that the notion of equality is ambiguous: are two objects equal by value (e.g., is value of ``x`` the same as the value of ``y``?) or by identity (e.g., does ``x`` refer to the same piece of memory as ``y``?).\n",
"* the ``in`` operator checks (by value) if an object is contained in another object (e.g., ``5 in [1,2,3,4,5]`` would be ``True`` while ``5 in [1,2,3]`` would be ``False``)\n",
"* doc strings, or those things that start with triple quotes at the beginning of the functions. It is good practice to provide a succint piece of documentation with each method that describes what is going on, any pitfalls, and often what the inputs and outputs are.\n",
"* updating data structures in place, which can be seen in the ``insert_vertex`` method where ``graph`` is modified but does not need to be returned. The complex datatypes typically can be updated in place, which can be very useful but can also lead to accidental bugs, and sometimes it is important to copy the data structure prior to making updates.\n",
"* generators, or co-routines, are used to incrementally return items and are created in Python whenever a ``yield`` is used. (generators are quite possibly one of the most amazing features of Python, and there is an additional example below).\n",
"* recursive functions (see ``depth_first_traversal`` below). Recursive functions call themselves, and can be more succint than iterative code in some instance (though they can also be more confusing if used inappropriately...)\n",
"\n",
"The data structure being used to represent the graph is designed such that the vertices (in this case, a k-mer) are the keys and the edges (in this case, which k-mers are connected) as values. The edges are stored within ``set``s so that we don't have to worry about adding an edge multiple times as ``set``s are non-redundant, and additionally, we can test for membership efficiently as ``set``s are optimized for lookups. The algorithm that \"walks\" the graph known as a [depth first](http://en.wikipedia.org/wiki/Depth-first_search) traversal and is implemented using [recursion](http://en.wikipedia.org/wiki/Recursion).\n",
"\n",
"Do not worry if this example does not make sense, but it is worth while poking at it and trying to understand it. As you learn to program, you will need to push your comfort boundaries. Reading and trying to understand other people's code is an excellent way to expand your horizons as you'll learn about new ways to approach problems, things that work well (and things that don't), style, amazing new functionality, etc. "
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def initialize_graph():\n",
" \"\"\"Create a new graph\"\"\"\n",
" return {}\n",
"\n",
"def insert_vertex(graph, vertex):\n",
" \"\"\"Insert a vertex into a graph if it doesn't already exist\"\"\"\n",
" if vertex not in graph:\n",
" graph[vertex] = set()\n",
"\n",
"def add_edge(graph, vertex_u, vertex_v):\n",
" \"\"\"Add an edge from vertex_u to vertex_v\"\"\"\n",
" if vertex_u not in graph:\n",
" insert_vertex(graph, vertex_u)\n",
" if vertex_v not in graph:\n",
" insert_vertex(graph, vertex_v)\n",
"\n",
" graph[vertex_u].add(vertex_v)\n",
"\n",
"def depth_first_traversal(graph, vertex, touched=None):\n",
" \"\"\"Yield vertices and edges from depth first traversal\"\"\"\n",
" if touched is None:\n",
" touched = set()\n",
" touched.add(vertex)\n",
"\n",
" edges = graph[vertex]\n",
" for v in edges:\n",
" # make sure to visit each node only once\n",
" if v not in touched:\n",
" for u, u_e in depth_first_traversal(graph, v, touched):\n",
" yield (u, u_e)\n",
"\n",
" yield (vertex, edges)\n",
" \n",
"def to_kmers(sequence, k):\n",
" \"\"\"Yield overlapping k-mers\"\"\"\n",
" first = sequence[:k]\n",
" for i in range(1, len(sequence) - (k-1)):\n",
" second = sequence[i:i+k]\n",
" yield (first, second)\n",
" first = second\n",
"\n",
"\n",
"g = initialize_graph()\n",
"k = 3\n",
"sequences = [\"ACTGCT\", \"CTGATA\", \"GCTAA\"]\n",
"for sequence in sequences:\n",
" for first_kmer, second_kmer in to_kmers(sequence, k):\n",
" add_edge(g, first_kmer, second_kmer)\n",
"\n",
"for vertex, edges in depth_first_traversal(g, 'ACT'):\n",
" print \"Vertex %s is connected to: %s\" % (vertex, ', '.join(edges))"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Generators by example... so awesome."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"def returned_list():\n",
" items = []\n",
" for i in range(5):\n",
" print \"in returned_list:\", i\n",
" items.append(i)\n",
" return items\n",
"\n",
"def generated_list():\n",
" for i in range(5):\n",
" print \"in generated_list:\", i\n",
" yield i\n",
"\n",
"print \"*********\"\n",
"for item in returned_list():\n",
" print \"in for loop:\", item\n",
"\n",
"print \"*********\"\n",
"for item in generated_list():\n",
" print \"in for loop:\", item"
],
"language": "python",
"metadata": {},
"outputs": []
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One thing that generators allow you to do easily is to avoid loading things completely into memory, which could be prohibitive for some types of data. For instance, loading a full HiSeq2000 run in memory would take a _lot_ of memory. But, with a generator, you can walk over the fastq and ``yield`` a sequence for subsequent processing. So awesome."
]
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment