{ "metadata": { "name": "" }, "nbformat": 3, "nbformat_minor": 0, "worksheets": [ { "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "Author: Karen Yin-Yee Ng \n", "\n", "Stat 250 Winter 2014 with Prof. Duncan Temple Lang\n", "\n", "Assignment 1\n", "\n", "Written with an ipython notebook (v 1.1.0)\n", "Github repository: https://github.com/karenyng/HW1_Stat250_Winter14/tree/master" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#%install_ext https://raw.github.com/minrk/ipython_extensions/master/extensions/nbtoc.py\n", "#%load_ext nbtoc\n", "%autosave 60" ], "language": "python", "metadata": {}, "outputs": [ { "javascript": [ "IPython.notebook.set_autosave_interval(60000)" ], "metadata": {}, "output_type": "display_data" }, { "output_type": "stream", "stream": "stdout", "text": [ "Autosaving every 60 seconds\n" ] } ], "prompt_number": 72 }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Methods" ] }, { "cell_type": "code", "collapsed": false, "input": [ "#%nbtoc" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 73 }, { "cell_type": "markdown", "metadata": {}, "source": [ "We benchmark different approaches for computing the statistics of airline delays between 1987 and 2012. \n", "\n", "Design considerations, due to the large size of the data, we have to : \n", "\n", "* avoid holding all the data in memory at same time but only want to extract the relevant data\n", "\n", "* avoid numerical instabilities \n", "\n", "* make it fast - avoid expensive operations such as making copies of data or I/O to hard disk\n", "\n", " * may want to make it parallelizable depending on performance\n", " \n", "Other possible consideration if this was made into a production code: \n", "\n", "* extensibility\n", "\n", "Major consideration if this is to be used once .........\n", "\n", "* minimizing development time " ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Exact approach 1" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "frequency table approach using the shell & R (or item 5) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pros: \n", "\n", "* development time is faster than using any of the compiled language \n", "( other than probably python for me)\n", "* one of the shortest implementation in terms of lines of code\n", "* no fancy algorithms are needed \n", "* good for prototyping which is what usually people do in industry\n", "* super cool that the shell can do so much stuff so fast with so little code\n", "\n", "Cons:\n", "\n", "* runtime may be slower than using pure compiled language for doing string manipulation \n", "* the computation of the frequency table is not the most parallelizble\n", "* some implementation for fetching column values were hackish - not very extensible\n", "* a lot of the parameters are hard coded\n", "* not a good production / extensible code due to the above cons \n", "\n", "Other thoughts about implementation:\n", "\n", "Not going to write the code in the most general / extensible / parallelizable way but I focus on getting an estimate of the answer from this first method\n", "\n", "I usually write code as functions and use OOP concepts but I don't have time for this.\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Shell scripting part" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Observation: there are two types of files with two different headers. \n", "\n", "* month-by-month csv \n", "* year-by-year csv\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "extracting columns from the csv files is quite straight forward except that, in the month-by-month csv, there are some values with \",\" in them, making the naive use of cut with \",\" as delimiter fail to fetch the correct column. My quick and dirty solution is to increment the column number count by 2 as a correction.\n", "\n" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Manual testing" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "I made sure that the functions work on individual files before looping them over more files.\n", "Test codes are called 'exam_col.sh' and 'test.ipynb' \n" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Other possible tests that I do not have time for: " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* output all the headers of the year-by-year csv and month-by-month csv and make sure there are no variety within each type of csv\n", "\n", "Also, on second thought I should have written a test code, using python or R to write out mean, median and standard deviation for each of the csv files.\n", "\n", "Then also use my code to write output of same format.\n", "Then just use diff in the shell to check if there is any differences to check for as many possible exceptional cases as possible.\n", "\n", "Now I'm just manually comparing statistics of individual files / writing out fake data for testing.\n", "\n", "I really should have done a better job planning for unit tests ......" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "R part - computing the statistics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When I write in a scripting language, I usually \n", "\n", "* keep code short \n", "* avoid loops and use vectorized operations \n", "\n", "Since R is not particularly strong in string manipulation or \"developers of R did not have string manipulation in mind when they designed R\" (Temple Lang 2014), I try to keep all string operations within the shell script." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Considerations for preventing numerical inaccuracies with the frequency table approach:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To get a sense of the order of magnitude of the numbers that we are computing : \n", "\n", "* total unique frequency count is $\\omega_{total} \\sim 10^8$\n", "* range of the delay time around [-1437, 2598]\n", "* all delay time are integers which simplifies that problem by a lot \n", "* precision requirement is lax (up to one minute - I will report the answer with one or two more decimal places at most or else we are over confident about the precision of the data)\n", "\n", "Of course these stats are obtained after I have run them through my scripts.\n", "On second thought I should have find/guesstimate the properties of the data before deciding on what languages / tools to use for this homework.\n", "\n", "For R, \n", "\n", "* the maximum value that an integer can hold is $\\sim 10^9$, and \n", "* double can hold much larger integer $\\sim 10^{308}$ and is the default R data type for numbers\n", "* Machine precision for double is $\\sim 10^{-16}$. \n", "\n", "Since R uses double for storing the ArrDelay field by default and data take integer form, we really shouldn't have to worry too much about numerical inaccuracies like overflow (when summing number), underflow (dividing by large number) or cancellation error (subtraction). I argue we do not need more rigorous algorithms in the world for just computing the statistics of ArrDelay with the frequency table approach. If we compute the statistics with other methods, we may have to worry more, especially when computing the standard deviation." ] }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Computing the mean:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "danger of loss of accuracies of this naive formula???\n", "\n", "$$ \\bar{t} = \\frac{ \\sum_i^n (t_i ~\\omega_i)}{\\omega_{total}}$$\n", "\n", "where $t_i$ denotes the delay time $\\omega_i $ denotes the corresponding count for that $t_i$.\n", "Numerator may overflow if we are just summing a bunch of positive numbers that are too large, but some of the numbers in the summation are negative.\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a safety precaution I will compute the mean using \n", "\n", "$$ \\bar{t} = \\sum_i^n \\frac{(t_i ~\\omega_i)}{\\omega_{total}}$$\n", "\n", "Note $t_i, w_i \\ll w_{total}$, by multiplying before dividing, there shouldn't be any underflow problems. \n", "And also I am using the default R sum() method which uses partial sums so I think it should be accurate enough.\n" ] }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Computing the std. dev.:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After reading John Cook 's entry I decide to use an adapted version of the two-pass\n", "formula because \n", "\n", "* I have already computed total frequency\n", "* it is not less accurate\n", "* I can write vectorized code instead of using Welford's recursive formula in R (looping is slow and recursion performance may be worse than looping)\n", "\n", "$$s = \\sqrt{\\sum_i^n \\frac{w_i}{w_{total}}(t_i - \\bar{t})^2} $$ " ] }, { "cell_type": "heading", "level": 4, "metadata": {}, "source": [ "Computing the median:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I tested total frequency count is odd or even to avoid grabbing the wrong median.\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Results of method 1 :" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "> mean = 6.(566504) min\n", "\n", "> median = 0.(00000) min \n", "\n", "> standard deviation = 31.(556326) min \n", "\n", "should probably just report up to 1 or 2 significant figure(s).\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "......eyeballing if answer make sense by plotting the frequency counts\n", "Maybe I should have made bar plots but I am just trying to quickly visualize this.\n", "\n", "Being able to visualize the results is a great strength of the frequency table approach\n" ] }, { "cell_type": "code", "collapsed": false, "input": [ "import pandas as pd\n", "import matplotlib.pyplot" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 74 }, { "cell_type": "code", "collapsed": false, "input": [ "# somehow pandas has trouble reading the sorted frequency table\n", "a = pd.read_table(\"sorted_freq.txt\", names = ['col']) \n", "c = []\n", "for i in range(a.shape[0]):\n", " b = a['col'][i].split()\n", " if (len(b) == 2):\n", " if (b[1] != 'NA') and (b[1]!='ArrDelay'):\n", " c.append([float(b[0]), float(b[1])])\n", "c = np.array(c).transpose()\n", "\n", "delay = c[1]\n", "freq = c[0]" ], "language": "python", "metadata": {}, "outputs": [], "prompt_number": 75 }, { "cell_type": "code", "collapsed": false, "input": [ "plt.plot(delay, freq, '.b')\n", "plt.xlabel('Delay time (min)', size=14)\n", "plt.ylabel('Frequency', size=14)\n", "xlim_low = -100\n", "xlim_high = 100\n", "plt.title('Truncated view of frequency table from'+\\\n", " '{0} to {1}'.format(xlim_low, xlim_high), size=15)\n", "\n", "plt.xlim(xlim_low, xlim_high)\n", "plt.axvline('6.566504', label = 'mean', color = 'r', ls = ':', lw = 3 )\n", "plt.axvline('0.00', label = 'median', color = 'g', ls = '--', lw = 3 )\n", "plt.legend(loc = 'best')" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 76, "text": [ "" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\nH8VDk0JZyFZRAAAAAElFTkSuQmCC\n", "text": [ "" ] } ], "prompt_number": 76 }, { "cell_type": "code", "collapsed": false, "input": [ "plt.plot(delay, freq, '.b')\n", "plt.xlabel('Delay time (min)', size=14)\n", "plt.ylabel('Frequency', size=14)\n", "xlim_low = -100\n", "xlim_high = 100\n", "plt.title('Total view of frequency table', size=15)\n", "plt.axvline('6.566504', label = 'mean', color = 'r', ls = ':', lw = 3)\n", "plt.axvline('0.00', label = 'median', color = 'g', ls = '--', lw = 3 )\n", "plt.legend(loc = 'best')" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 77, "text": [ "" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\ngg==\n", "text": [ "" ] } ], "prompt_number": 77 }, { "cell_type": "markdown", "metadata": {}, "source": [ "It makes sense that the mean is slightly positive which is explained by the longer tail on the positive end.\n", "\n", "It also makes sense that the median could be at zero, the positive tail is offset by the taller and fatter peak on the negative end if you look at the truncated plot.\n", "\n", "Standard deviation is also plausible given the long tails." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Computation time: ~5 mins" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This is probably not the fastest approach in terms of CPU time. \n", "\n", "Possible improvement in the bash script: the bash script grabs the columns from different csv and write them all out to a big file before sorting then counting frequencies. \n", "I expect the I/O to hard disk to be one of the bigger bottlenecks.\n", "Dynamic arrays in the shell can be used to remedy this but I am not familiar how bash handles the memory for growing array to comment on if it will not use up a lot of memory.\n", "\n", "Also the computation of the frequency table is also a place for possible improvements. Currently I have sorted all the 500 MB of ArrDelay column data before using \"uniq\" to compute the frequency table. If we can implement a fast hashing method then we might be able to avoid holding all 500MB of data. Even though 500 MB data should not be a limiting factor for even laptop as old as 5 years old but if the data is bigger than this is not an extensible solution.\n" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Memory usage: " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Negligible amount of swap was used as far as I am concerned" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n" ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Exact Method 2: Python with Pandas and Numpy (calling compiled code from python)" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Background:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "This implementation is probably the most straight forward with only around 47 lines.\n", "\n", "Python pandas is a data analysis python package that imitates R syntax and it has a C backend highly optimized for speed.\n", "I took a quick look at the relevant source code on github. \n", "The relevant C / Cython code are scattered in mainly in \n", "\n", "and \n", "\n", "The actual \"python\" implementation of the read.csv function looks like it is mostly in Python:\n", "\n", "BUT, it is naive to think the read.csv function is really written in python since it parses a bunch of C libraries to replace original Python parts.\n", "For example the imported pandas.lib \n", "seems to replace the python data variables such as integers, nans, infs with C variables and make calls to C standard libraries.\n", "\n", "here 's an excerpt of parsers.py where the calls to wrapped libraries are made: " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", " import pandas.lib as lib\n", " import pandas.tslib as tslib\n", " import pandas.parser as _parser\n" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "What my code does:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* loop over all the csv files , extracting only relevant column\n", "* first extract columns of the year-by-year csv into one pandas dataframe then the month-by-month csv into another pandas dataframe\n", "* remove the \"column name\" of each dataframe by turning them to numpy arrays\n", "* concatenate them together using numpy.append() -- this is NOT slow since Python libraries pass most objects by reference not by value\n", "* convert them back to pandas dataframe since a dataframe can handle nan values automatically, numpy array handles nan more clumsily\n", "* call existing methods of pandas dataframe to compute mean, median and standard deviation\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Pros of this method: \n", "\n", "* short and simple \n", "* fast \n", "* extensible - pandas can do subsetting and group by and apply functions very easily, and also handles NA among other things. If you want a different field you can just grab that column by changing the script by one variable.\n", "\n", "Cons of this method: \n", "\n", "* most of the code is hidden away from me so if pandas developer has a bug somewhere it is harder for me to debug but it is doable since pandas uses a BSD license so I can fix the bug myself by downloading it\n", "* code compatibility of future pandas version is at the mercy of pandas developers -- I better document exactly the version I am using in case pandas change drastically in the future" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Tests of the code" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* informative with print statements\n", "* results agree with first method" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Runtime of method 2: ~3.1 min" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " user system elapsed\n", " 89.872 16.604 185.723" ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Method 3 - Approximate approach using FastCSVSample" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Background" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The idea is to reduce the amount of data to be analyzed by sampling uniformly across all the csv files using https://github.com/duncantl/FastCSVSample\n", "\n", "Therefore in the coding process, it is important to ensure the (almost) same percentages of lines are sampled from each csv file. Since I do not usually do sampling as a physics student I would like to see what percentage of lines I need to sample in order to get results close to the exact method. " ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Design considerations:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Total number of valid lines in all the files $\\sim 1.3 \\times 10^8$\n", "so if we just sample $1\\%$ of the lines, we still have to go over $\\sim 10^6$ lines. My patience runs out for a computation that takes more than half an hour so let's see how we well we need to do on the speed for me not to explode due to impatience:" ] }, { "cell_type": "code", "collapsed": false, "input": [ "print 'each line should at most take '+\\\n", "'{0}s'.format( 30 * 60 / (1e6))" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "each line should at most take 0.0018s\n" ] } ], "prompt_number": 78 }, { "cell_type": "markdown", "metadata": {}, "source": [ "And that is a long time for the computation of each line--- good sign to reassure myself that I am going to finish this on time... " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "the R functions for grabbing column and removing NaNs only takes $10\\mu~s$\n", "\n", "This is similar to method 1 but then the number of lines should be even fewer, so I expect the total runtime to be less than 5 mins unless I write some loops that are awfully slow." ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "How to compute the statistics for this method:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is ok to hold all the sampled lines in memory $500MB \\times 1\\% \\approx 5MB$ and just use R default mean, median and standard deviation function.\n", "\n", "So I will just piece all the sampled lines into one big list (or whatever R object it is) then use default functions. " ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "Other options ... " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "do statistics completely on the run so only have to go through the files only once: " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* first pass through the data -> use recurrence formale provided by Duncan for the mean and standard deviation \n", "\n", "* for the median, use selection algorithm" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "but I really want to avoid writing loops in R ............" ] }, { "cell_type": "heading", "level": 3, "metadata": {}, "source": [ "(Manual) Tests " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* sample all the lines in 2008_May.csv and 1987.csv respectively and see if output agrees with exact approach --- and they agree! " ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Result" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ ">mean = 6.(591345) min \n", ">median = 0.(000000) min \n", ">sd = 31.(465116) min\n", "\n", "Sampling only 1% of the lines give results good up to 2 significant figures." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Dependencies of the codes" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* move all the csv files inside the data directory\n", "* R version 3.0.2 (2013-09-25) -- \"Frisbee Sailing\" (method 1 & 3)\n", "* Python v. 2.7.4, numpy v.1.7.1, pandas v.0.10.1 (method 2)\n", "* a forked R package \"NotSoFastCSVSample\" " ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "How to call the codes for different methods:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Rscript \"PATH TO GIT DIR\"/methodN.R" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "replace N with the method number." ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Machine specification:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "* Corsair Vengeance 2x8GB DDR3 1600 MHz Desktop Memory, \n", "* Intel(R) Core(TM) i7-4770K CPU @ 3.50GHz, \n", "* GeForce GTX 770 SuperClocked\n", "* Samsung 840 Pro 256 GB SSD\n", "* Motherboard: Asus Z87-Deluxe DDR3 1600 LGA 1150 \n", "* Linux Mint 15 Olivia (GNU/Linux 3.8.0-19-generic x86_64)\n", "\n", "\n", "Thanks to an anonymous physicist in Portland who has kindly allowed me to use his gaming desktop for the computing of this homework. He helped me repair the partition table to my Linux partition and installed a HDD for use." ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Discussion" ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Comparison of results of different methods" ] }, { "cell_type": "code", "collapsed": false, "input": [ "y = [1, 2, 3]\n", "result1 = [6.566504, 0.00000, 31.556326]\n", "result2 = [6.56650421703, 0.0, 31.5563262623]\n", "result3 = [6.591345, 0.000000, 31.465116]\n", "\n", "plt.plot(result1, y, 'rs', markeredgewidth=1, \n", " alpha = .25, markersize = 10, label=\"Method 1\")\n", "plt.plot(result2, y, 'gx', markeredgewidth=3, \n", " alpha = .25, markersize = 10, label=\"Method 2\")\n", "plt.plot(result3, y, 'b*', markeredgewidth=1, \n", " alpha = .25, markersize = 10, label=\"Method 3\")\n", "\n", "plt.legend(loc='lower right')\n", "plt.title('Comparison of statistics from different approaches', size = 15)\n", "label = ['mean', 'median', 'std. dev',]\n", "plt.yticks( y, label, size = 15)\n", "plt.margins(0.2)\n", "plt.xlabel('Arrival delay (min)', size = 15)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 87, "text": [ "" ] }, { "metadata": {}, "output_type": "display_data", "png": "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\n", "text": [ "" ] } ], "prompt_number": 87 }, { "cell_type": "markdown", "metadata": {}, "source": [ "No idea how to make the plot above better, the differences of the data points are too small to be noticible" ] }, { "cell_type": "code", "collapsed": false, "input": [ "plt.title('Comparison of runtime of different methods', size = 16)\n", "\n", "y = [1, 2, 3]\n", "time_taken = [282.900/60., 181.094/60., 269.420/60.] \n", "\n", "plt.plot(time_taken, x, 'o')\n", "label = ['Freq table - Shell + R ', 'Python Pandas', 'FastCSVSample + R',]\n", "plt.yticks( y, label, size = 12)\n", "plt.margins(0.2)\n", "plt.xlim(0,6)\n", "plt.xlabel('Wall clock time (min)', size = 15)" ], "language": "python", "metadata": {}, "outputs": [ { "metadata": {}, "output_type": "pyout", "prompt_number": 80, "text": [ "" ] }, { "metadata": {}, "output_type": "display_data", "png": "iVBORw0KGgoAAAANSUhEUgAAAeoAAAEdCAYAAADD+iSbAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAIABJREFUeJzt3Xl8Dff+P/DXnOyRPREhqyVii8YuqhINgqD2nRAt2qtU\n1XJtSVGlLS29ra1uYomirYsm9pDQEqpFa7tUQ4TYQxZLtvfvD7/M15GTSIhmuK/n43Ee7fnMZz7z\nnjnHec3MmTlRRERAREREmqQr7wKIiIioaAxqIiIiDWNQExERaRiDmoiISMMY1ERERBrGoCYiItIw\nBjXpOXDgAHr37g1XV1eYmZnByckJ7dq1w6pVq5Cfn1/e5T0X58+fh06nw8qVK8u7lKf273//G97e\n3jAzM4O9vX15lwMA2LhxIz7//PNC7fHx8dDpdNi7d285VPX0fvzxR/j6+sLCwgI6nQ7p6emlmt/L\nywtDhw5Vn0dFRUGn0yE5OVlty8rKwqBBg+Ds7AydTof3338fwMN/l82aNYOVlRV0Oh1+//33slmp\nMnT06FFEREQgLS2tvEtRxcfH48MPP8TjdyEX/Jtfvnz5c12+odf4aTCoSfXFF1+gZcuWuH37Nj75\n5BPExcUhMjISNWvWxMiRIxEbG1veJT4XVapUQWJiIkJCQsq7lKdy+fJlDB8+HC1btsSePXsQFxdX\n3iUBeBjU8+fPL9TeqFEjJCYmokGDBuVQ1dPJzc3FgAED4O7ujp07dyIxMRFWVlalGkNRFCiKoj7v\n1KkTEhMT4eLiorZ99dVXWLt2LebPn4/ExESMHTsWADBs2DDk5+cjJiYGiYmJ8Pb2LpsVK0NHjx7F\njBkzXoigLvDo66FlxuVdAGnD3r178f7772P06NH44osv9KZ17twZH3zwATIyMsqpuudDRJCbmwtT\nU1M0bdq0vMt5amfPnkV+fj4GDx6MFi1alHr+7OxsmJqaPofKDLO2tn7htvelS5eQmZmJXr16oWXL\nlmUyppOTE5ycnPTaTp06BVdXVwwcOFBty8/Px5kzZzB16lQEBgaWybKf52uuxd/Q0mJNpSJEItKx\nY0epWLGiPHjwoET9Dx48KEFBQWJlZSUVKlSQoKAgOXTokF6f0NBQcXNzk0OHDknz5s3FwsJCfHx8\nJCYmRkRE5syZIx4eHmJraytdu3aV69ev682vKIpMmTJFZs2aJa6urmJhYSGtWrWSo0eP6vXbvn27\ndOjQQSpXriyWlpZSr149mTdvnuTl5en18/T0lIEDB8ry5cvFx8dHTExMZOPGjZKUlCSKokhUVJTa\n99ChQ9KmTRtxdHQUCwsLqVatmrzzzjtPvQ2OHDkiLVu2FEtLS/H29pbFixeXaDufPn1aunbtKnZ2\ndmJhYSHNmzeXbdu26Y2vKIreY+jQoUWOFxAQIC1btpTNmzeLn5+fmJmZyRdffGFwG4iI7NmzRxRF\nkYSEhEJj7Ny5Uxo0aKBu8//85z/F1lW1atUnjrllyxapX7++mJubS8OGDSUxMVGys7Nl/Pjx4uLi\nIg4ODjJkyBDJysrSqzMrK0smTJggXl5eYmpqKlWrVpWPPvpI8vPzn7iNL1++LIMGDRInJycxMzOT\n+vXry+rVq9Xp4eHhhdYlMDCw2DG/+OIL8fT0FHNzc2ncuLHs3btXvLy89F6byMhIURRFLly4ICJS\naBkFr8fjbV5eXuoY8fHx8vrrr4u1tbVUqFBBgoOD5fjx43q1FPWai4j89ddf0r9/f6lYsaKYmZmJ\nn5+f3uv46PqfPXtWOnbsKFZWVuLp6SkzZsxQt2/Bujz+KFg3Qwr+Pa5YsUK8vb3FwsJCXnvtNTlz\n5oykp6dLWFiYODg4SKVKleSDDz6Q3NxcvfmvXbsmI0aMEFdXVzEzM5NatWrJ0qVLi33dFEUREVHf\n70uWLJFp06ZJ5cqVxc7OTjp37iwpKSl6y8nOzpYpU6aIp6enmJqaipeXl0ydOlVycnL0+p07d046\nduwolpaWUrFiRRkzZowsXry40HaIjo4WPz8/sbKyEhsbG/H19ZUlS5YUuZ1ERBjUJLm5uWJhYSED\nBgwoUf9jx46pH0A//PCD/PDDD9KkSROxsLCQY8eOqf1CQ0PFxsZG6tSpI5GRkbJt2zZ57bXXxNzc\nXEaNGiWdO3eWLVu2yL///W+xsbGR3r176y1HURRxd3eXli1byqZNm2TdunXi4+Mjjo6OcuvWLbXf\n4sWL5dNPP5XY2FiJj4+XTz/9VKytrWXSpEl643l5eYmrq6v4+vrK2rVrZffu3XLu3Dn1H+2KFStE\nRCQjI0Ps7e2lQ4cOEhMTIwkJCRIVFSUjRox46m1Qu3ZtWbp0qezatUv69+8viqLInj17it3Oly5d\nEicnJ6levbpER0fLjz/+KO3btxcjIyPZunWriDz8cPjyyy9FURRZtGiRHDx4UP76668ixwwMDBRn\nZ2epWrWqREZGSkJCgvzxxx+FtkEBQ6EaGBgolStXlrp160p0dLRs27ZN2rZtK8bGxvLnn3+qdYWE\nhIizs7McPHhQDh48qO5gFTWmi4uL+Pr6yrp16yQmJkbq1KkjlSpVkkGDBklYWJjs2LFDvvjiCzEx\nMZEJEyao8+bk5EjLli3F0dFRFixYILt375aPPvpIzM3NZdy4ccVu48zMTPH29hZnZ2dZtmyZbNu2\nTQYMGCCKoqgf+ikpKfL999+Loigyffp0OXjwoJw6darIMb/55htRFEXCwsJk+/bt8q9//Uvc3NzE\n1ta22KBOTEyU9u3bS+XKldVtduHCBfn5559FURR566239LZjTEyMGBkZSdeuXWXz5s2yadMmadGi\nhdjb28vFixef+JonJydLxYoVxdfXV6Kjo2XHjh0SFhYmOp1ONm/erM5fEHj16tWT+fPnS1xcnIwZ\nM0YURZHIyEgREbl+/bpMmzZNFEWRH374Qa2/uB1/Ly8v8fDwkBYtWsimTZtk/fr1UqVKFfH19ZUO\nHTrI+PHjZdeuXeq4X3/9tTrvnTt3pGbNmuLp6SnffPONxMXFyfjx48XIyEi+/PJL9XV78803RVEU\n2b9/v1qTyP8FtZeXlwwYMEC2bdsmK1asECcnp0I7Yf369RNjY2MJDw+XnTt3SkREhJiYmEj//v3V\nPg8ePJBq1aqJq6urREVFSWxsrHTp0kXc3Nz0XuN9+/aJTqeTsWPHSlxcnOzcuVMWLlwon3zySZHb\nSYRBTSJy5coVURRFJk+eXKL+PXr0EHt7e7lz547alp6eLg4ODtK9e3e1reCoat++fWrb77//Loqi\nSK1atfSOdt5//30xMTHRa1MURSpWrCh3795V286fPy8mJiYybdo0g7Xl5+dLTk6OzJo1S+zt7fWm\neXp6SoUKFeTq1at67Y+H1C+//CKKosgff/xRZtsgPj5ebXvw4IE4OjrK8OHDixxfRGTcuHFibGws\n586dU9vy8vLEx8dHGjZsqLbt3LmzUPAVJSAgQHQ6nd7OhEjhbVCgqKNfU1NTNZRFHh7dGBkZyezZ\ns/XW3c3NrVANxY2ZlJSktm3evFkURZG2bdvqzd+9e3f16FxEZOXKlYXeZyIiH330kZiamsq1a9eK\n3B4FOzmPb7s2bdqIs7Ozelbm7NmzBrfP4/Ly8sTNzU06dOig175u3bpCZzseD2oRkQEDBuitm8jD\nHRFFUeTDDz/Ua69evbq0adNGry09PV2cnJzkvffeU9uKes3DwsLE2dlZb6dXRKRt27bi5+enPi8I\n6sfPtvj6+kq7du0Krc+j79fieHp6iqOjo6Snp6ttCxcuVHdKHtWwYUNp3bq1+nzGjBlibm6u9x4U\nEXnrrbfEyclJfd0Kan/87FrB+/3RMUVEPvvsM1EURVJTU0VE5I8//jC47WfNmiWKosjvv/8uIiJL\nly4VRVHUHQGRh59FdevWFZ1Op77Gn376qTg4OJRo+zyKF5NRqe3duxedOnWCjY2N2mZtbY0uXbog\nISFBr6+VlZXed3o+Pj4AgDZt2uhdyOHj44Pc3Fykpqbqzd+xY0dYWFiozz09PdG8eXMcOHBAbUtN\nTcWIESPg6ekJMzMzmJqaYtq0abhz5w6uXbumN17z5s3h7Oxc7Pp5e3vDzs4Ow4cPR3R0NC5evPhM\n26BChQoICAhQn5uamqJmzZoGx318Gf7+/qhWrZraptPp0LdvXxw9ehSZmZnFzl+UqlWron79+k81\nbwFvb29Ur15dfV6xYkU4Ozs/cZ2KU7NmTXh5eanPC94rwcHBev18fHyQkpKiPt+2bRs8PT3h7++P\n3Nxc9dG2bVvk5OQgMTGxyGXu3bsXbm5uaNWqlV77gAEDcP36dZw6dapU65CSkoJLly6hd+/eeu3d\nu3eHsXHJLgmSEnyfevbsWfz111/o37+/3jpbWFigefPmha6oN/Sab9u2DR07doSNjY3eGO3atcOx\nY8cKvb8ev9iybt26z3w1s7+/P6ytrdXnxb3mj763tm3bhubNm8PLy6tQ7Tdv3sTJkydLtPyOHTvq\nPa9Xrx4AqOtVsB0fvWbg0ecF0w8cOAAPDw+9ay8URUGvXr30Xs+mTZsiLS0NgwYNQkxMDG7fvl2i\nOhnUBEdHR1hYWODChQsl6p+WlobKlSsXaq9UqVKhKz7t7Oz0nhdcwPL4LUQF7ffv3y805uOcnZ1x\n+fJlAA8vtOnSpQu2bNmC6dOnY8+ePTh8+DCmTJkCEdEbT1EUg3U/ztbWFnv27EGVKlXwzjvvwNPT\nE76+vtiwYcNTbQNDt0uZmpoWWtfH3bp1y+AyXFxcICJPfXVtSbbBkzg4OBRqMzMze+I6Faeo94Sh\n9tzcXPV2wWvXruHChQswMTGBqamp+mjWrBkURcGtW7eKXGZx27hgemkU7Gg+/r41NjaGo6NjqcYq\nTsEO6LBhw/TW2dTUFLGxsYXqNrSO165dw4oVKwpttwkTJkBRFNy8eVOv/+Ov+bO+3oqilOo1f3RZ\n165dQ0JCQqHae/fubbD2ohhaJ+D/PocKtuPj26/g9S2YnpqaavCz6vG2Vq1a4bvvvsPFixfRvXt3\nODs7o23btvjjjz+KrZNXfROMjY0RGBiIHTt2lOhqUAcHh0JHvgBw5cqVQm/8khwdFOfq1asG21xd\nXQEA586dw6+//orVq1ejf//+ap9NmzYZHK+kt2O88sor+P7775Gfn49ffvkFH3/8MXr37o3ff/8d\nderU+Vu2gaOjY5HLMPQhV1KGtoG5uTmAh1cDP6qkH3jlycnJCVWrVsV3331ncLqnp2eR8zo4OODM\nmTOF2q9cuaJOL42CD/TH37e5ubm4ceNGqcYqTkHoz5kzB23atCk0/fF/w4ZecycnJ7Rq1QoTJ040\nuIyy2KF7XpycnODi4oIFCxYYnF6zZs0yWU7B65+amqp3Zuvx90flypUNHsUb+vzq0aMHevTogbt3\n72LPnj2YOHEi2rdvj5SUlCI/n3hETQCASZMm4ebNm5gwYYLB6UlJSepeX0BAALZs2aJ3aiwjIwM/\n/vhjodtHnvU+xS1btuDu3bvq8/PnzyMxMRH+/v4AoE579LRiTk4OoqOjy+QeSZ1Oh2bNmmHGjBnI\nz89XT4X+HdsgICAAiYmJemc68vLysG7dOjRs2LDU9/EWp1KlSjAzMyu0Z/8s986bmZnh3r17z1ra\nE7Vv3x4XL15EhQoV0LBhw0KP4o5kAwMDkZKSgv379+u1r1mzBpUqVUKdOnVKVYubmxvc3d2xbt06\nvfYffvgBeXl5JRqjJO+XWrVqwcvLC8ePHze4zgWncIvTvn17HDt2DHXq1DE4Rklu33q01oKj0Uf/\nvT4v7du3x6lTp+Du7m6w9oJ/G89aU8FXVmvXrtVrj46OBgD133qLFi1w8eJFHDx4UO2Tn5+P9evX\nF/l6WlpaIiQkBMOHD0dqamqxZ294RE0AgNdeew3z58/H+++/j5MnT2LIkCFwd3dHWloa4uLisHz5\ncnz77bfw9fXFtGnTEBMTg6CgIHVvfO7cubh//z6mT5+uN+6zHlGbm5ujXbt2GD9+PO7fv4/w8HDY\n2dmpPwRRp04deHp6YsqUKTAyMoKxsTE+//xzKIpSaNklrSUmJgZLly5Ft27d4OXlhaysLCxcuBA2\nNjbqDkJZbIMn1TN27FhERUWhbdu2+PDDD2FtbY2vv/4af/755zMFqKHlKoqCPn36YPny5ahZsyZq\n1qyJ2NjYQt+3FzfG421169bFsmXLsHjxYjRq1Ajm5ubw9fUtVV0lMWDAAERGRiIoKAjjxo1D/fr1\nkZ2djXPnzuHHH3/Exo0b9a5zeNSQIUOwYMECdO/eHR999BFcXV0RHR2NXbt2YenSpaXeydLpdAgP\nD8ebb76JsLAw9OnTB3/++Sfmzp0LGxubEq1jSbfDV199hTfeeAPZ2dno1asXnJyccPXqVezfvx+e\nnp7qv5GixpwxYwaaNm2KVq1aYdSoUfD09ERaWhqOHz+OpKSkEv1q16Pj1q1bV61r8ODBMDExwSuv\nvAITE5NnWk9Dxo4di3Xr1uG1117D2LFjUbNmTWRlZeH06dP46aefsHHjRr2a5s2bh/bt28PIyAiN\nGzcu8XLq1q2Lfv36ISIiArm5ufD398eBAwcwa9Ys9O/fXx0/NDQUc+bMQffu3TF79mxUrFgRixcv\nRkZGht56Tp8+HdeuXUPr1q1RuXJlpKSkYOHChWjQoEGxO5QMalKNGTMGTZs2xeeff44PPvgAN27c\ngLW1NZo0aYKlS5eiU6dOAABfX1/Ex8djypQpCA0NhYjA398fCQkJeh/Ej/8S05MY6hsaGgpLS0uM\nGjUKN27cQNOmTbF+/Xr1u28TExNs3LgRo0aNwuDBg+Ho6IiwsDC4u7tj+PDhTxzfkJo1a8LS0hIz\nZ85Eamqq+gMdO3fuRJUqVcpkG5Rk21SuXBk//fQTJk6ciLfffhsPHjxAgwYNEBsbi3bt2j3VuhW3\n3AULFiA/Px8RERHIz89Hnz598OWXX6Jz584lGuPxtjfffBOJiYmYPHkybt++DS8vL/z1118G+5bm\nvfJ4X2NjY2zfvh1z5szB0qVLkZSUhAoVKqBGjRoICQkp9sjQ0tISCQkJmDBhAiZNmoSMjAzUqlWr\n0FcppREWFobMzEzMnz9f3bldu3YtBgwYYHC9i1u34nTo0AF79+7FRx99hLfeegv37t2Di4sL/P39\n0a9fvyeO6e7ujsOHDyMiIgKTJ0/G9evX4ejoCF9fX4SGhj5x/sfb69evj4iICCxduhTLli2DiCAp\nKQkeHh4G6y9qPUuyLBsbG+zfvx8zZszA3LlzcenSJdjZ2aFWrVro0aOH2q9Tp05455138PXXX2PG\njBkA8MQzG48vPyoqCtWqVcO///1vzJo1C66urpg0aRLCw8PVPiYmJti5cydGjRqFd955BxUqVMCA\nAQPQqVMnvP3222q/5s2bY+HChRg7dixu3boFZ2dnBAcHY+bMmcXXJM96yEP0nOh0OkydOlX9B0ZE\n9L+I31ETERFpGIOaiIhIw3jqm4iISMN4RE1ERKRhvOqbSqQs7kkmIvpf9KwnrnlETSUmD/+Iy0v5\nCA8PL/cauH5cv//F9XuZ102kbL5ZZlATERFpGIOaiIhIwxjURECh3+d+2XD9Xmwv8/q9zOtWVnh7\nFpWIod/OJiKi4pXFZyePqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjUREREGsagJiIi\n0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjUREREGsagJiIi0jAGNRER\nkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGINaI86fPw+dTof8/PzyLoWIiDTkmYPay8sLlpaW\nsLa2hrW1NWxsbHDlypWnGisqKgqvvfZaofZDhw6hY8eOsLe3h6OjI5o1a4aoqCh1+uzZs1GtWjVY\nW1vD3d0dffv2BQCMHDkSoaGhhcY7duwYzM3Ncfv2bdy+fRthYWGoXLkybGxs4OPjg7lz5z5V/S+a\nIUOGwMzMDNbW1nBwcEBQUBBOnDhR3mUREdEjnjmoFUVBTEwMMjIykJGRgfT0dLi4uJRFbQCAAwcO\nICgoCK1bt8a5c+dw8+ZNLFq0CNu3bwcArFixAqtXr0ZcXBwyMjJw+PBhtGnTBsDDINqwYQPu3r2r\nN+aqVavQuXNn2NnZYezYsbh79y5Onz6N9PR0bN68GTVq1Ciz+v9u58+fR9WqVUvUV1EUTJw4ERkZ\nGbh8+TI8PDwwdOjQ51whEWlRbOxeBAdPRWBgBIKDpyI2dm95l0QF5Bl5eXlJXFycXltaWpqEhIRI\nxYoVxd7eXjp16iQpKSnq9MjISKlWrZpYW1tL1apVJTo6Wk6dOiVmZmZiZGQkVlZWYm9vLyIir776\nqowaNarI5Y8aNUree++9Iqf7+PjIypUr1ee5ublSpUoV2bx5s4iI1KtXTzZu3Fjk/KNHjxZ3d3ex\nsbGRRo0ayb59+9Rp4eHh0rNnTxk4cKBYW1uLr6+vnDlzRmbPni3Ozs7i4eEhO3bsUPsHBATIpEmT\npGnTpmJjYyNvvPGG3Lp1S0REkpKSRFEUycvLExGR27dvS1hYmFSuXFlcXV1l6tSp6rTiJCUliZeX\n1xP7iYgMGTJEpk2bpj6PjY0VS0tLg33L4K1CRBoVE5Mg1atPFkDUR/XqkyUmJqG8S3vhlcVnZ5l8\nR/2wlv+Tn5+PYcOGITk5GcnJybCwsMCoUaMAAFlZWRgzZgy2bduG9PR0HDhwAH5+fqhVqxaWLFkC\nf39/ZGRk4NatW7h79y4SExPRs2fPIpfdvHlzrFy5Ep999hkOHz6MvLw8vemDBw/GypUr1ee7du1C\nTk4OOnbsqM4/ZcoUREVF4ezZs4XGb9q0KY4dO4a0tDT0798fvXr1QnZ2tjo9JiYGgwcPRlpaGho0\naIC2bdsCAC5fvoxp06ZhxIgReuOtWrUKkZGRSE1NhbGxMUaPHm1wvYYMGQJTU1OcO3cOR44cwY4d\nO/DNN98UuR2eVsFrl5WVhW+//RbNmjUr82UQkbYtXLgD5859pNd27txH+PLLneVUEel51qT39PQU\nKysrsbOzEzs7O+nWrVuhPkeOHFGPkDMzM8XOzk5++OEHuXv3rl6/yMhIadmypfo8JSVFFEWR//73\nv8XWEB0dLW3atJEKFSqIo6OjzJ07V5124cIFMTExkUuXLomISP/+/fWOwO/duyezZ8+WRo0aiYmJ\nidSoUUO2bt1a5LLs7e3l999/F5GHR9Tt2rVTp23evFmsrKwkPz9fRETS09NFURS5c+eOiIgEBgbK\nP//5T7X/yZMnxdTUVPLz8/WOqK9cuSJmZmZy7949te+aNWukdevWxW4HkdIdUYeGhoq5ubnY2dmJ\nTqeTatWqyfXr1w32BSDh4eHqY8+ePSVaBhFpX0BAuN7RdMEjICC8vEt74ezZs0fvs7IMYlaey6nv\nrKwsGT58uHh6eoqNjY3Y2NiITqdTA2z79u3Stm1bsbOzk5CQEDl9+rSIFA7qrKwsMTIykvj4+BLV\nkpubK999952YmprK9u3b1fagoCCZM2eOZGRkSIUKFeS3334zOH96erpMnjxZrKysJC0tTUREPv30\nU6ldu7bY2tqqgbZ7924ReRjUAwcOVOffuXOnXkjm5OSIoijqTkJgYKB8/fXX6vTMzExRFEWuXbum\nF9QHDx4UnU6n7vzY2dmJjY2N1KtXz2Dd0dHRev0endfe3l4uXrxocL5HT30nJydL7dq1Zd68eQb7\nlsWbjYi0qV27KQaDOjh4anmX9sIri8/O53J71rx583DmzBkcOnQId+7cQUJCAuThTgEAoF27dtix\nYweuXLmCWrVq4a233gLw8OKmR1laWsLf3x/ff/99iZZrZGSEnj17on79+npXL4eGhmLVqlX44Ycf\nULVqVTRo0MDg/NbW1vjnP/+JrKwsJCUlYd++ffj000/x3Xff4fbt20hLS4OtrW2hU/2lkZycrPf/\nJiYmcHJy0uvj7u4OMzMz3Lx5E2lpaUhLS8OdO3fwxx9/GByzf//+ar/ff/8dHh4e6vNbt27Bzc2t\nyHoK1sXd3R0LFy7EzJkzkZ6e/tTrR0QvntGj26F69Sl6bdWrT8a777Ytp4roUc8lqDMzM2FhYQFb\nW1vcunULH374oTrt2rVr2LRpE7KysmBiYoIKFSrAyMgIAFCpUiWkpKQgJydH7f/JJ58gKioKn332\nGW7evAng4e1V/fr1A/Dwlq4tW7YgIyMD+fn52Lp1K06cOKH3XWuPHj2QnJyMiIgIDBkyRK/WmTNn\n4vDhw8jOzsb9+/exYMEC2Nvbw8fHBxkZGTA2NoaTkxOys7MxY8aMZwoxEcHq1atx6tQp3L17F9On\nT0evXr0K7aBUrlwZ7dq1w/vvv6+u17lz57B375OvwizNTsTjfdu0aYMaNWpg0aJFJR6DiF58ISGt\nsGBBMIKDpyEgIALBwdOwYEF7hIS0Ku/SCM8pqN977z3cu3cPTk5OaNGiBTp06KCGUX5+Pj7//HO4\nurrC0dER+/btU4MhKCgIdevWhYuLC5ydnQEA/v7+2L17N3bv3o3q1avD0dERI0aMQEhICADA1tYW\ns2fPhqenJ+zt7TFp0iQsXrwYLVq0UOuxtLREjx49cOnSJQwYMEB/A+h0GDp0KCpWrAhXV1fExcUh\nNjYWlpaWaN++Pdq3b4+aNWvCy8sLFhYW8PDwUOdVFKVQyBb3XFEUDBo0CEOGDEHlypWRnZ2NhQsX\nGuy7cuVKZGdno06dOnBwcECvXr1KfH/64zUU1+/xvuPHj8fChQv1dpaI6OUXEtIK27bNRHx8BLZt\nm8mQ1hBFnuU8LpVK69atMWjQIISFhZV3KaWmKMoznfInIvpfVBafnfwJ0b8Zw46IiEqDQf03K+lp\naSIiIoCnvqmEeOqbiKj0eOqbiIjoJcegJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1AT\nERFpGIOaiIhIwxjUREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOa\niIhIwxitJDkjAAAgAElEQVTUREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1AT\nERFpGIOaiIhIwxjUREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOa\niIhIwxjUREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjU\nREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjUREREGsag\nJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjUREREGsagJiIi0jAG\nNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjUREREGsag/v+8vLwQFxdX3mWU\nmYiICAwaNKi8yyAiomf0Qge1l5cXLC0tYW1tDRcXFwwdOhRZWVlPnG/IkCGYNm2aXpuiKFAU5XmV\nqoqIiICJiQmsra1hb2+PV199FYmJiWW+nL9jXYiI6Pl7oYNaURTExMQgIyMDv/32Gw4fPoxZs2aV\nd1nFUhQF/fr1Q0ZGBq5fv46WLVuie/fu5V0WERFp1Asd1I+qUqUK2rdvj+PHj+P7779H48aN9abP\nnz8fXbt2xbJly7BmzRp88sknsLa2xhtvvKH2OXLkCF555RXY2dmhb9++ePDggTpt2bJl8Pb2hqOj\nI9544w2kpqaq03Q6HZYsWYKaNWvC3t4eo0aNKrJOEYGIAACMjY0xePBgXLlyBTdv3sScOXNQo0YN\n2NjYoG7duti4caM6X1RUFFq2bInx48fDwcEB1apVw7Zt29TpSUlJCAgIgI2NDdq1a4cbN27oLbdX\nr16oXLky7OzsEBAQgJMnT6rTtmzZgrp168LGxgZubm6YN29eSTc7UbmLjd2L4OCpCAyMQHDwVMTG\n7i3vkojKlrzAvLy8ZNeuXSIikpycLHXr1pXp06fLgwcPxMHBQU6dOqX29fPzkw0bNoiIyJAhQ2Ta\ntGl6Y3l6ekqzZs0kNTVVbt26JbVr15bFixeLiEhcXJw4OTnJkSNH5MGDB/Luu+9Kq1at1HkVRZHO\nnTvLnTt3JDk5WSpWrCjbtm0zWHN4eLgMHDhQRETu378vH3zwgXh6eoqIyHfffSepqakiIrJu3Tqp\nUKGCXLlyRUREIiMjxcTERL755hvJz8+XRYsWSZUqVdRxmzdvLuPGjZPs7GzZu3evWFtby6BBg9Tp\nkZGRkpmZKdnZ2fLee++Jn5+fOs3FxUV++uknERG5ffu2/Pbbb4XqfsHfKvSSiolJkOrVJwsg6qN6\n9ckSE5NQ3qURiUjZfHa+0J++np6eYmVlJXZ2duLp6Sn/+Mc/5P79+yIiMnLkSJkyZYqIiBw/flzs\n7e0lOztbRB4G9dSpU/XG8vLykujoaPX5hAkTZOTIkSIiEhYWJhMnTlSnZWZmiomJiVy4cEFEHgb1\nzz//rE7v3bu3zJkzx2DN4eHhYmpqKnZ2duLs7CxBQUEGg1Hk4c7Fpk2bRORh0NaoUUOdlpWVJYqi\nyNWrV+XChQtibGwsd+/eVaf3799f3SF4XFpamiiKIunp6SIi4uHhIUuWLJE7d+4Y7C/CoCZtatdu\nil5IFzyCg6c+eWaiv0FZfHYal+/x/LNRFAWbNm3C66+/XmhaaGgo+vfvj1mzZmHVqlXo06cPTExM\nih3PxcVF/X8LCwv19HZqaqreqfQKFSrA0dERly5dgoeHR6F5LS0tkZmZWeRy+vTpg5UrVxZqX7ly\nJT7//HOcP38eAJCZmYmbN28arM/S0lLtc+3aNdjb28PCwkKd7unpiYsXLwIA8vLyMGXKFHz//fe4\nfv06dDodFEXBjRs3YG1tjR9++AGzZs3CpEmTUL9+fcyZMwfNmzcvVF9ERIT6/4GBgQgMDCxyHYn+\nDg8eGP4Iu3/f6G+uhOih+Ph4xMfHl+mYL3RQF6d58+YwNTXF3r178e233+Lbb79Vp5X2iugqVaqo\n4QkAWVlZuHnzJlxdXUtdl6Io6nfUj7pw4QKGDx+O3bt3w9/fH4qioEGDBgb7Pq5y5cpIS0vD3bt3\n1QC/cOECjIweflitWbMGmzdvRlxcHDw9PXH79m04ODioYzdu3BgbN25EXl4evvzyS/Tu3RvJycmF\nlvNoUBNpgZlZrsF2c/O8v7kSooceP4j58MMPn3nMl+ZiMkMGDRqEUaNGwdTUFC1atFDbK1WqhL/+\n+uuJ8xcEWb9+/RAZGYljx47hwYMHmDx5Mpo3b64eTRc1X2mmZWVlQVEUODk5IT8/H5GRkTh+/PgT\nawQeHj03btwY4eHhyMnJwU8//YSYmBh1emZmJszMzODg4ICsrCxMnjxZnZaTk4Po6GjcuXMHRkZG\nsLa2VgOeSOtGj26H6tWn6LVVrz4Z777btpwqIip7L31QnzhxAgMHDtRrHzZsGE6ePAl7e/sib416\n9L7qoKAgzJw5Ez169ECVKlWQlJSEtWvX6vUtat7ixn1UnTp1MG7cOPj7+8PFxQXHjx9Hy5Yti53v\n0edr1qzBwYMH4eDggBkzZiA0NFSdNnjwYHh6esLV1RX16tVTj9gLrF69GlWrVoWtrS2WLl2K6Oho\ng7UTaU1ISCssWBCM4OBpCAiIQHDwNCxY0B4hIa3KuzSiMqNISc6tvqDu3buHSpUq4ciRI6hevXp5\nl/NCK+qUPRERFa0sPjtf6iPqRYsWoWnTpgxpIiJ6Yb20F5N5eXlBURS9Hw0hIiJ60bzUp76p7PDU\nNxFR6fHUNxER0UuOQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjUREREGsagJiIi0jAGNRERkYYx\nqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjUREREGsagJiIi0jAGNRERkYYxqImIiDSM\nQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjUREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRh\nDGoiIiINY1ATERFpGIOaiIhIwxjUREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiIN\nY1ATERFpGIOaiIhIwxjUREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFp\nGIOaiIhIwxjUREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOaiIhI\nwxjUREREGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhDGoiIiINY1ATERFpGIOaiIhIwxjURERE\nGsagJiIi0jAGNRERkYYxqImIiDSMQU1ERKRhL0VQnz9/HjqdDvn5+QanR0REYNCgQX9zVU+uqzTz\nBgYGYvny5WVdIhERadwTg9rLywuWlpawtraGtbU1bGxscOXKledaVFRUFF577bUyG09RlDIb63Ep\nKSno0aMHKlasCDs7O/j6+mLFihVlvhxFUcp8PYYMGQIzMzNYW1vDwcEBQUFBOHHiRJkug4iIns0T\ng1pRFMTExCAjIwMZGRlIT0+Hi4uLXp/c3NznVmBZEJHnNvagQYPg6emJ5ORk3Lp1C6tWrUKlSpWe\n2/Ke5Pz586hatWqJ+iqKgokTJyIjIwOXL1+Gh4cHhg4d+pwrJCKi0njqU986nQ5ff/01vL294ePj\nAwCIiYmBn58f7O3t8eqrr+KPP/5Q+x85cgQNGzaEjY0N+vbti759+2LatGmFxj116hTefvttHDhw\nQD3SA4DY2Fg0aNAAtra28PDwwIcfflho3uXLl8PV1RVVqlTBvHnziqw9MTERLVq0gL29Pfz8/JCQ\nkPC0mwGHDx/GkCFDYGFhAZ1OBz8/P7Rv316vz+rVq+Hp6YmKFSti9uzZaruIYM6cOahRowacnJzQ\np08fpKWlPXUtz8Lc3By9evXiETURlUhs7F4EB09FYGAEgoOnIjZ2b3mX9NIqUVAXdUS6adMm/PLL\nLzh58iSOHDmCYcOGYdmyZbh16xZGjBiBLl26ICcnB9nZ2ejatStCQ0ORlpaGXr16YcOGDQZP5dau\nXRuLFy+Gv78/MjIycOvWLQCAlZUVVq9ejTt37iA2NhaLFi3Cpk2b9OaNj4/Hn3/+iR07dmDu3LmI\ni4srNP6lS5fQqVMnTJ8+HWlpafjss8/Qo0cP3LhxoySbopDmzZvjnXfewbp165CcnGywz88//4wz\nZ84gLi4OM2bMwH//+18AwMKFC7F582bs3bsXqampsLe3xz/+8Y+nquNpFby2WVlZ+Pbbb9GsWbO/\ndflE9OKJjd2LMWO2Y8eOWUhIiMCOHbMwZsx2hvXzIk/g6ekpVlZWYmdnJ3Z2dtKtWzcREVEURfbs\n2aP2GzlypEybNk1vXh8fH0lISJCEhASpUqWK3rQWLVoU6l8gMjJSWrZsWWxdY8aMkbFjx4qISFJS\nkiiKIv/973/V6RMmTJBhw4aJiEh4eLgMHDhQRETmzJkjgwYN0hsrODhYVqxYUezyipKWliaTJk2S\nunXripGRkfj5+ckvv/yiV9elS5fU/k2bNpV169aJiEitWrUkLi5OnXb58mUxMTGRvLw8dd68vDwR\nEQkMDJTly5c/sZ6kpCTx8vIqUe2hoaFibm4udnZ2otPppFq1anL9+nWDfUvwViGi/xHt2k0RQAo9\ngoOnlndpmlMWn50l+o5606ZNSEtLQ1paGjZs2KBOc3d3V///woULmDdvHuzt7dVHSkoKUlNTcfny\nZbi6uuqN6+npWarvjg8ePIjWrVvD2dkZdnZ2WLJkCW7evKnX59F6PDw8cPny5ULjXLhwAd99951e\nnT///LPBC+Sio6PVi+hCQkIM1mVnZ4ePP/4Yx48fx9WrV+Hn54euXbvq9Xn0O31LS0tkZmaqtXTr\n1k2to06dOjA2NsbVq1dLvF0AYM2aNeoYr7zyCpKTk9XnDg4OSElJMTifoigYP3480tLScP78eZiZ\nmWHlypVFLiciIkJ9xMfHl6pGInp5PHhgbLD9/n2jv7kS7YmPj9f7rCwLhrd2CT166trDwwNTpkzB\n5MmTC/VLSEjApUuX9NouXLiAGjVqPHHcAv3798fo0aOxfft2mJqaYuzYsYVOVycnJ6vflycnJxfa\nOSioc9CgQVi6dOkT12/AgAEYMGDAE/sVcHR0xLhx47BixYoSfdfs4eGByMhI+Pv7F5p2/vz5Ei+3\nf//+6N+/P4CH2zUwMBBJSUklmrdgZ8nd3R0LFy5Er1698Oabb8LGxqZQ37J60xHRi83MzPAFxObm\neX9zJdoTGBiIwMBA9bmh66lKq8zuo37rrbewePFiHDp0CCKCrKwsxMbGIjMzEy1atICxsTEWLlyI\nnJwcbNiwAb/88kuRY7m4uCAlJQU5OTlqW2ZmJuzt7WFqaopDhw5hzZo1hQJ91qxZuHfvHk6cOIGo\nqCj06dOn0NgDBw7Ejz/+iB07diAvLw/3799HfHx8oR2Jkpo4cSJOnDiB3NxcZGRkYNGiRfD29oa9\nvf0T5x05ciQmT56sfrd9/fp1bN68ucj+JTkDUZqzFI/3bdOmDWrUqIFFixaVeAwi+t8zenQ7VK8+\nRa+tevXJePfdtuVU0cvtqYP68ZBs1KgRli1bhlGjRsHBwQHe3t7qaVQTExNs2LABUVFRcHR0xPr1\n69G9e/ciQ+X1119H3bp14eLiAmdnZwDA119/jenTp8PGxgYzZ84sFMKKoiAgIAA1atRAmzZtMH78\neLRp00adVlCvm5sbNm3ahNmzZ8PZ2RkeHh6YN2/eU/0oCQDcu3dPPX1dvXp1XLx4US9si7v3ecyY\nMejSpQvatWsHGxsb+Pv749ChQ0XOW9L7qEvT7/G+48ePV3eoiIgMCQlphQULghEcPA0BAREIDp6G\nBQvaIySkVXmX9lJSpDSHYGVo6NChcHNzw8yZM8tj8VRKiqI81/vRiYheRmXx2VluPyHKD30iIqIn\nK7egfh4/iUlERPSyKbdT3/Ri4alvIqLSe6FPfRMREdGTMaiJiIg0jEFNRESkYQxqIiIiDWNQExER\naRiDmoiISMMY1ERERBrGoCYiItIwBjUREZGGMaiJiIg0jEFNRESkYQxqIiIiDWNQExERaRiDmoiI\nSMMY1ERERBrGoCYiItIwBjUREZGGMaiJiIg0jEFNRESkYQxqIiIiDWNQEwGIj48v7xKeK67fi+1l\nXr+Xed3KCoOaCC//hwXX78X2Mq/fy7xuZYVBTUREpGEMaiIiIg1TRETKuwjSPkVRyrsEIqIX0rPG\nrHEZ1UEvOe7PERGVD576JiIi0jAGNRERkYYxqOmJtm3bhlq1asHb2xtz584t73LKVFhYGCpVqgRf\nX9/yLuW5uHjxIlq3bo26deuiXr16WLhwYXmXVGbu37+PZs2awc/PD3Xq1ME///nP8i7pucjLy0OD\nBg3QuXPn8i6lzHl5eaF+/fpo0KABmjZtWt7llLnbt2+jZ8+eqF27NurUqYPExMSnGocXk1Gx8vLy\n4OPjg127dsHV1RVNmjTBt99+i9q1a5d3aWVi3759sLKywuDBg/HHH3+Udzll7sqVK7hy5Qr8/PyQ\nmZmJRo0aYePGjS/N63f37l1YWloiNzcXLVu2xGeffYaWLVuWd1llav78+fj111+RkZGBzZs3l3c5\nZapq1ar49ddf4eDgUN6lPBehoaEICAhAWFgYcnNzkZWVBVtb21KPwyNqKtahQ4dQo0YNeHl5wcTE\nBH379sWmTZvKu6wy89prr8He3r68y3huXFxc4OfnBwCwsrJC7dq1cfny5XKuquxYWloCALKzs5GX\nl/fSfeCnpKRgy5YtePPNN1/aCzpf1vW6c+cO9u3bh7CwMACAsbHxU4U0wKCmJ7h06RLc3d3V525u\nbrh06VI5VkRP6/z58zhy5AiaNWtW3qWUmfz8fPj5+aFSpUpo3bo16tSpU94llamxY8fi008/hU73\ncn5UK4qCNm3aoHHjxli2bFl5l1OmkpKSULFiRQwdOhQNGzbEW2+9hbt37z7VWC/nq09lhvdPvxwy\nMzPRs2dPLFiwAFZWVuVdTpnR6XQ4evQoUlJSsHfv3pfq5yhjYmLg7OyMBg0avLRHnT///DOOHDmC\nrVu34quvvsK+ffvKu6Qyk5ubi99++w3vvPMOfvvtN1SoUAFz5sx5qrEY1FQsV1dXXLx4UX1+8eJF\nuLm5lWNFVFo5OTno0aMHBg4ciK5du5Z3Oc+Fra0tQkJCcPjw4fIupczs378fmzdvRtWqVdGvXz/s\n3r0bgwcPLu+yylTlypUBABUrVkS3bt1w6NChcq6o7Li5ucHNzQ1NmjQBAPTs2RO//fbbU43FoKZi\nNW7cGGfPnsX58+eRnZ2NdevWoUuXLuVdFpWQiGDYsGGoU6cO3nvvvfIup0zduHEDt2/fBgDcu3cP\nO3fuRIMGDcq5qrIze/ZsXLx4EUlJSVi7di1ef/11rFy5srzLKjN3795FRkYGACArKws7dux4qe6+\ncHFxgbu7O86cOQMA2LVrF+rWrftUY/GXyahYxsbG+Ne//oXg4GDk5eVh2LBhL80VwwDQr18/JCQk\n4ObNm3B3d8eMGTMwdOjQ8i6rzPz8889YvXq1egsMAHz88cdo3759OVf27FJTUxEaGor8/Hzk5+dj\n0KBBCAoKKu+ynpuX7Wuoq1evolu3bgAeniYeMGAA2rVrV85Vla0vv/wSAwYMQHZ2NqpXr47IyMin\nGoe3ZxEREWkYT30TERFpGIOaiIhIwxjUREREGsagJiIi0jAGNZFGLF++HDqdrtBPfE6cOBE6nQ7R\n0dF67Tt37oROpyvxD/1HRESgYsWK6vP4+HjodDqcPHnymerW6XT46quvnmmMxz1tbUuXLjX4E7de\nXl6YMGFCWZX31A4dOgQnJydkZmY+81hDhgxR79EtjS5duuDDDz985uXT34dBTaQRr776KoCHt1Q9\nav/+/bC0tMT+/fsLtZubm6NRo0YlXsbzusVHK7cOFRXUmzZtwujRo8uhIn2TJk3C6NGjy+TX4aZP\nn44VK1aUer5p06Zh/vz5uHnz5jPXQH8PBjWRRvj4+MDBwUEvkHNycvDrr78iNDTUYFA3atQIJiYm\nJV7G/8LdmIbW8ZVXXin3X9Q7duwYEhIS1D/S8KyqVav2VL9t3qRJE3h4eGD58uVlUgc9fwxqIo1Q\nFAX+/v56gXzkyBEAwNtvv43jx48jKysLwMM/RnHw4EH1KDw2NhZt27ZFpUqVYGtrC39/f+zcubNM\n6rp58yZGjBiBKlWqwMLCArVq1cKCBQuKnedf//oXvL29YW5uDm9vb3zxxReF+vz+++/o3Lkz7O3t\nYW1tjWbNmmHXrl1Fjrl27VqYm5tjyZIlBqcHBgbit99+w4oVK6DT6aDT6dRf8vLy8sL48ePVvgWn\njWNjY1GnTh1UqFABISEhSEtLw+nTpxEYGAgrKys0adKk0J8/zc/Px5w5c1CjRg2Ym5vDx8enRL8Y\nFhUVhWbNmuntMBSc4t+9ezfeeOMNWFlZoWbNmtixYwdycnLw/vvvw8nJCW5uboW24eOnvqOioqDT\n6XD8+HG0bdtW/Wtp//nPfwrV0rNnT0RFRT2xZtIGBjWRhvj7++Po0aN48OABAODAgQNo3Lgx6tWr\nB1tbW/X76BMnTiA9PV0N6vPnz6NTp05YtWoVNmzYgBYtWqBDhw6FjsJL6969ewgMDMTmzZsxffp0\nbN26FePGjUNqamqR8yxbtgyjR49G165dERMTg169emHcuHGYO3eu2uf06dN49dVXcfXqVSxZsgQb\nN25Et27dkJKSYnDMyMhIhIaGYunSpRgxYoTBPosWLUKtWrUQEhKCxMREJCYmIiQkBMDDnaBHT88r\nioLk5GRERERg9uzZWLp0KQ4cOICwsDD07dsXAwYMwPfff4/c3Fz07dtXbznvvvsuPvroI4wcORJb\ntmxBt27dEBYWhtjY2GK35e7du+Hv729w2ogRI9CqVSts3LgRnp6e6NWrF4YPH4779+9j7dq16Nmz\nJ95///1Cv4Vt6CuH/v37o2vXrti4cSO8vb3Rt2/fQn/xrnnz5jh9+jSuXr1abM2kEUJEmhEfHy+K\nosi+fftERKR3794yYcIEEREJCQmRGTNmiIjI4sWLRVEUuXHjRqEx8vLyJCcnR4KDgyUsLExtDw8P\nFycnJ/X5nj17RFEUOXHiRJH1LF68WHQ6nRw7dqzIPoqiyFdffaUuu0qVKnrLFRF55513xNbWVh48\neCAiIn379hV3d3e5f/++wTELajt+/LgsWrRIzMzMZN26dUXWUKBx48YydOjQQu1eXl4yfvx49Xlo\naKgYGxvLX3/9pbZNmDBBFEWRVatWqW1btmwRRVHk9OnTIiJy9uxZ0el0en1ERAYPHixNmjQpsq6c\nnBwxMjKSb775xuB6FryuIiInT54URVEkKChIbcvPzxcXFxeZOHGi3jo0btxYfR4ZGSmKokhkZKTa\ndvPmTTE2NpbFixfrLTclJUUURZEtW7YUWTNpB4+oiTSkSZMmMDY2Vo+E9+/frx6FNW/eXK+9Zs2a\ncHR0BACkpKQgNDQUbm5uMDExgampKXbs2IGzZ88+Uz27d+9Gw4YNUb9+/RL1T0lJQWpqKnr16qXX\n3rt3b6Snp6unkXfv3o0+ffrAzMys2PEWLFiAsWPHYv369ejdu/fTrUQRqlatiqpVq6rPq1evDgB4\n/fXXC7UVHJHGxcVBp9PhjTfeQG5urvp4/fXXcfTo0SKvAbh16xby8/Ph4OBgcPqjv1FuqA5FUVCt\nWrVCdwQY8ujvZTs4OMDZ2bnQEXXB++batWtPHI/KH/8oB5GGWFpaws/PDz///DNSUlJw6dIltGjR\nAsDDoJ43bx6Ah0HdqlUrAA+/M+3SpQuysrIwc+ZM1KhRA5aWlpg+fTquX7/+TPXcvHlT/VOEJVFw\nSrxSpUp67QXPb926pf63JONu2LAB3t7eeqFVVuzs7PSem5qaFmovaLt//z6Ah3+xKy8vD7a2toXG\nUxQFqampqFKlSpHLLCrIDS3z8fpMTEzUOopjaL0en6+oOkibGNREGvPqq68iOjoaBw4cgJeXF5yd\nnQEATZs2RUZGBuLj43Hu3DlMmjQJAPDnn3/i6NGj2LZtm97R1N27d5+5FicnJ/z5558l7l8Qvo8f\nqRV8F1pwROno6Fiio8M1a9Zg5MiR6NKlC7Zu3frEI/DSeJqwcnBwUM946HSFT0g+ep/6oxwdHWFk\nZKSZW6IKdpgK3lukbTz1TaQxLVq0wI0bN7BixQr1aBoAbGxsULduXXz66acA/u++63v37gH4vyMx\nALhw4UKh+7GfRlBQEI4cOVLoyueiuLm5oUqVKli/fr1e+/r162Fra6v+veGgoCCsX79evWiuuPHi\n4uJw5swZ9OjRA7m5ucX2NzU1VbfHkzzNvd+vv/468vLycPv2bTRs2LDQo6hb5YyMjODr64vjx4+X\nepnPUm9RCup4mf5+98uMR9REGlMQzlu3bsXChQv1pvn7+2Pp0qVwcHBArVq1AAC1a9eGm5sbxo0b\nh5kzZyI9PR0RERFwc3N75lOcgwcPxldffYV27dohIiICNWvWRFJSEs6ePYuPP/64UH+dToeIiAiM\nGDECjo6OaNOmDRISErB48WJ8/PHH6s5EeHg4mjRpglatWmHcuHFwcHDAkSNH4OTkVOjvgVetWhU7\nd+5EQEAABg4ciG+//bbI0KpVqxa2b9+OHTt2wMHBAdWqVYODg4PB7fA028bHxwcjR45E3759MWHC\nBDRq1Aj379/HiRMncPbsWSxbtqzIeYOCghAfH1/qZT5a79PUbGieAwcOoFatWnBxcXnqeujvwyNq\nIo1xdXWFh4cHABS6nafg+aPtpqam2LBhA4yNjdGzZ0+Eh4dj8uTJCAgIKHRL0uMB96SjNDMzM+ze\nvQBBSs8AAAE7SURBVBudO3fG9OnT0bFjR3z22WdwdXUtcp4333wTCxYswH/+8x907twZ69atw/z5\n8/V+wrNmzZr46aef4OTkhDfffBPdu3fHhg0b4OXlZbC22rVrY8eOHdi+fTuGDx9e5LKnTp2K2rVr\no3fv3mjatCliYmIMrqehbVHU9ni87auvvsK0adOwcuVKhISEYOjQodi6dSsCAgKKrAsAQkND8euv\nv+LChQtPXKYhhm4xK8nraajt+++/x5AhQ0q0XCp/ivCqAiKiv0WbNm3QokULzJgxo9xq+OWXXxAU\nFISkpCT16m/SNgY1EdHf5JdffkGHDh1w/vz5Mvm976fRtWtXNGzYENOnTy+X5VPpMaiJiIg0jN9R\nExERaRiDmoiISMMY1ERERBrGoCYiItIwBjUREZGGMaiJiIg07P8BNWcfFczrtggAAAAASUVORK5C\nYII=\n", "text": [ "" ] } ], "prompt_number": 80 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Relevant packages for R that can also extract specific columns from a csv file:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "After googling around it seems like there are also packages in R that can read csv files with specified columns.\n", "Such as: \n", "\n", "* colbycol on CRAN \n", "* limma on Bioconductor\n", "\n", "So it is possible to do the computation purely in R without having to use the shell.\n", "It would be interesting to compare the speeds between a \"pure R\" implementation with these packages vs the \"pure Python\" implementation with pandas and numpy. It concerns me that R seems to pass by value if I try to use the same approach as my python code to append the data frames. The memory usage will definitely be more than my python implementation. Or maybe I will just have to adapt the R version in a different style than my python code." ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Miscellaneous : Bonus question" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "How did Duncan download the data for use in this homework ? \n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Short answer: download & start reading Duncan's new book from P.333 of \n", "\n", "Long answer: I could guesstimate how to fill in the dynamic form on that website with some scripts and pull the links to those forms for downloading the data. But I will just get back to working on the other parts of the homework... \n", "\n" ] }, { "cell_type": "heading", "level": 1, "metadata": {}, "source": [ "Actual code: " ] }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Method 1: shell script to compute entire frequency table then use R to compute statistics" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "(I do not like how the cat command messes with the indentation of my bash script but here it is)" ] }, { "cell_type": "code", "collapsed": false, "input": [ "!cat ../freq_count.sh" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "#!/bin/bash\r\n", "\r\n", "#---------------------------------------------------------------------------\r\n", "# Author: Karen Ng\r\n", "# This script \r\n", "# * reads in airline csv data files \r\n", "# * finds the column that corresponds to delay time\r\n", "# * cut the column then count the frequencies of a certain delay time\r\n", "# * returns frequency count in files named 1.txt 2.txt etc. \r\n", "# * the frequency count files still has header and NA values mixed inside\r\n", "# * have to use R or other language to discard those \r\n", "# version 1: no growing arrays but have slow I/O \r\n", "#---------------------------------------------------------------------------\r\n", "\r\n", "shopt -s nullglob\r\n", "dir=\"./data\"\r\n", "# store all file names in a bash array\r\n", "files=( \"$dir\"/*.csv ) \r\n", "fileno=${#files[*]}\r\n", "\r\n", "# check for csv input error\r\n", "if [ ${fileno} -eq 0 ]; then\r\n", "\techo \"--------SHELL SCRIPT ERROR-----------------------------\"\r\n", "\techo \"ERROR: no suitable *.csv file found in $PWD/data\" \r\n", "\techo \"For this script to work, put *.csv files in $PWD/data\" \r\n", "\techo \"-------------------------------------------------------\"\r\n", "\texit 0;\r\n", "fi\r\n", "\r\n", "# loop through the files one by one\r\n", "for ((j=0; j < ${fileno}; j++));\r\n", "do \r\n", "\t# look at the header, split them by \",\" then store in array\r\n", "\tarr=($(head -1 ${files[$j]} | tr \",\" \"\\n\"))\r\n", "\tarrLen=${#arr[*]}\r\n", "\tcol=-99\r\n", "\r\n", "\t# loop through array of headers and count which column it is in \r\n", "\tfor ((i=0; i < ${arrLen}; i++)); \r\n", "\tdo \r\n", "\t\tx=${arr[$i]}\r\n", "\t\tif [ $x == \"ArrDelay\" ] || [ $x == \"\\\"ARR_DELAY\\\"\" ]; then \r\n", "\t\t\t# definition of column count is off by 1 between bash array and cut \r\n", "\t\t\tcol=$i\r\n", "\t\t\t(( col += 1 ))\r\n", "\r\n", "\t\t\t# if it is a monthly csv, have to add two to the column count for the\r\n", "\t\t\t# column value to be fetched correctly by cut. \r\n", "\t\t\t# This is because some values in the monthly CSV contain commas\r\n", "\t\t\tif [ $x == \"\\\"ARR_DELAY\\\"\" ]; then \r\n", "\t\t\t\t(( col += 2 ))\r\n", "\t\t\tfi\r\n", "\r\n", "\t\t\tbreak\r\n", "\t\tfi\r\n", "\tdone\r\n", "\r\n", "\t#echo \"Writing the file-$j delay time to freq_count.txt\"\r\n", "\t# store the frequency count of all the csv files in one single file\r\n", "\t# possible time improvement: \r\n", "\t# use an array to hold these instead of writing it to a file first \r\n", "\t# the col-finding and the writing out takes around 1 min 8 s real time \r\n", "\tif [ $j -eq 0 ]; then \r\n", "\t\tcut -d',' -f${col} ${files[$j]} > freq_count.txt \r\n", "\telse \r\n", "\t\tcut -d',' -f${col} ${files[$j]} >> freq_count.txt \r\n", "\tfi\r\n", "\r\n", "done\r\n", "\r\n", "# pipe the content of frequency count to sed \r\n", "# use sed to remove the trailing decimal places for some delay time entries\r\n", "# sort them then find unique counts \r\n", "# remove header --- could have just used grep -v \r\n", "cat freq_count.txt | sed -E 's/([0-9]+)\\.00/\\1/g' |\\\r\n", "\tsort -n | uniq -c |\\\r\n", "\tsed -e '/ArrDelay/d' -e '/ARR_DEL15/d' \r\n", "\r\n", "# can output to a text file to check values \r\n", "#> sorted_freq.txt\r\n" ] } ], "prompt_number": 81 }, { "cell_type": "code", "collapsed": false, "input": [ "!cat ../method1.R" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "#----------------------------------------------------------------------\r\n", "# Author: Karen Ng \r\n", "# Purpose: \r\n", "# reads in a two column file with frequency of each entry and entry value\r\n", "#---------------------------------------------------------------------\r\n", "\r\n", "run <- function(){\r\n", " col.names <- c('freq', 'delay')\r\n", " print(\"First method: compute_stat.R: \")\r\n", " print(\"computing and reading in sorted frequency table from bash script\")\r\n", " print(\"This takes ~5 mins for a 3.5 GHz machine with sufficient RAM\")\r\n", " # call the shell script for cutting columns and doing frequency count \r\n", " DF <- try(read.table(pipe(\"./freq_count.sh\"), col.names = col.names, \r\n", " fill = TRUE), silent=TRUE)\r\n", " if (class(DF) == \"try-error\"){\r\n", " print(\"ERROR: failed to read in $PWD/data/*.csv\") \r\n", " print(\"USAGE: place data in $PWD/data/*.csv for this script to work\")\r\n", " q(\"no\", 1, FALSE)\r\n", " }\r\n", " # REMOVE NAN!!! \r\n", " DF <- na.omit(DF)\r\n", "\r\n", " print(\"compute_stat.R\")\r\n", " print(\"compute_stat.R: computing total frequencies\")\r\n", " w.total <- sum(DF[['freq']]) \r\n", " print(\"total number of valid total frequency count\")\r\n", " print(w.total)\r\n", "\r\n", " print(\"compute_stat.R: computing mean\")\r\n", " t.mean <- sum(DF[['freq']] * ( DF[['delay']] / w.total), na.rm = TRUE)\r\n", "\r\n", " print(\"compute_stat.R: computing median\")\r\n", " i <- 1\r\n", " Sum <- DF[['freq']][i]\r\n", " medianFreqCount <- floor(w.total / 2) \r\n", " ## sorry don't know better than to write a loop...\r\n", " while(Sum < medianFreqCount) { \r\n", " i <- i + 1 \r\n", " # this vectorized operation \r\n", " Sum <- sum(DF[['freq']][1:i], na.rm = TRUE)\r\n", " # is faster than \r\n", " ## if ( !is.na(DF[['freq']][i]) ) {\r\n", " ## Sum <- Sum + DF[['freq']][i] \r\n", " ## }\r\n", " }\r\n", " ## check for corner case: \r\n", " ## or else there the median will may be off \r\n", " print(\"compute_stat.R: computing standard dev.\")\r\n", " if( Sum == medianFreqCount && w.total %% 2 == 0){\r\n", " # print(\"going through special case\")\r\n", " t.median <- (DF[['delay']][i] + DF[['delay']][i+1])/2 \r\n", " }else{\r\n", " t.median <- DF[['delay']][i]\r\n", " }\r\n", "\r\n", " # after reading Jook Cook 's entry on computation of std. dev\r\n", " # I decide to go with the (two-pass) direct method because this can be \r\n", " # written entirely in vectorized form\r\n", " std.dev <- sqrt(sum(DF[['freq']] * (DF[['delay']] - t.mean) ^ 2 / (w.total-1))) \r\n", " results1 <- c(t.mean, t.median, std.dev)\r\n", " #print(results)\r\n", " results1\r\n", "}\r\n", "\r\n", "time.method1 <- system.time(results1 <- run())\r\n", "save(results1, time.method1, file=\"results1.rda\")\r\n" ] } ], "prompt_number": 82 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Method 2: Python + Pandas + Numpy (calling a compiled language) " ] }, { "cell_type": "code", "collapsed": false, "input": [ "!cat ../compute_stat.py" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "#!/usr/bin/env python\r\n", "\r\n", "import pandas as pd\r\n", "import numpy as np\r\n", "\r\n", "data_path = \"./data/\"\r\n", "\r\n", "# First read in the data from 1987 to 2007\r\n", "year = [ str(i) for i in range(1987,2008) ]\r\n", "# create empty dataframe\r\n", "delay1 = pd.DataFrame()\r\n", "# loop through the year-by-year csvs\r\n", "for yr in year:\r\n", " # read in relevant column from csv file using pandas\r\n", " file = yr +'.csv'\r\n", " temp = pd.read_csv(data_path + file, usecols=[\"ArrDelay\"])\r\n", " # append the dataframes - this is done by reference not by value\r\n", " delay1 = delay1.append(temp)\r\n", " print 'appending '+ file + ' - total lines = ' + \\\r\n", " '{0}'.format(delay1.shape[0])\r\n", "\r\n", "# create another empty dataframe for handling month by month csv\r\n", "delay2 = pd.DataFrame()\r\n", "year = [ str(i) for i in range(2008, 2013) ]\r\n", "month = ['January','February', 'March', 'April', 'May', 'June', 'July',\r\n", " 'August','September', 'October', 'November', 'December']\r\n", "# loop through all the month-by-montyh csv\r\n", "for yr in year:\r\n", " for mth in month:\r\n", " file = yr + '_' + mth + '.csv'\r\n", " # tell pandas to read only the relevant column in the csv\r\n", " temp = pd.read_csv(data_path + file, usecols=[\"ARR_DELAY\"])\r\n", " # append them to the dataframe by reference\r\n", " delay2 = delay2.append(temp)\r\n", " print 'appending ' + file + ' - total lines = ' + \\\r\n", " '{0}'.format(delay2.shape[0] + delay1.shape[0])\r\n", "\r\n", "# hackish way to remove the column name of the dataframe to append\r\n", "# the two types of csv columns together\r\n", "# so I can compute the statistics in one pass later on\r\n", "delay1 = np.array(delay1)\r\n", "delay2 = np.array(delay2)\r\n", "delay = np.append(delay1, delay2)\r\n", "delay = pd.DataFrame(delay)\r\n", "print 'total number of valid lines = {0}'.format(delay.dropna().shape[0])\r\n", "\r\n", "# note that pandas ignores nans automatically while computing stats\r\n", "#print 'mean = {0} \\n'.format(delay[0].mean()) +\\\r\n", "# 'median = {0} \\n'.format(delay[0].median()) +\\\r\n", "# 'std. dev. = {0}\\n'.format(delay[0].std())\r\n", "\r\n", "print 'saving to results2.txt'\r\n", "f = open('results2.txt', 'w')\r\n", "f.write('mean = {0}\\n'.format(delay[0].mean()))\r\n", "f.write('median = {0}\\n'.format(delay[0].median()))\r\n", "f.write('std = {0}\\n'.format(delay[0].std()))\r\n", "f.close()\r\n" ] } ], "prompt_number": 83 }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this python code I don't even have to do exception handling since Pandas is so smart." ] }, { "cell_type": "code", "collapsed": false, "input": [ "!cat ../method2.R" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "#----------------------------------------------------------------------\r\n", "# Author: Karen Ng \r\n", "# Purpose: \r\n", "# R wrapper around python code so there would be consistent profiling \r\n", "#---------------------------------------------------------------------\r\n", "time.method2 <- system.time(system(\"./compute_stat.py\"))\r\n", "# read in results from python script\r\n", "con = file(\"./results2.txt\",\"r\")\r\n", "results2 <- readLines(con)\r\n", "save(results2, time.method2, file=\"results2.rda\")\r\n", "\r\n" ] } ], "prompt_number": 84 }, { "cell_type": "heading", "level": 2, "metadata": {}, "source": [ "Method 3: (NotSo)FastCSVSample" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this method I forked Duncan's FastCSVSample R package and added some R code (which might have made it not so fast). \n", "\n", "Since we are sampling from files with quite different sizes, it is important that we sample approximately a fixed percentage of lines. " ] }, { "cell_type": "code", "collapsed": false, "input": [ "!cat ../method3.R" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "#----------------------------------------------------------------------\r\n", "# Author: Karen Ng \r\n", "# Method 3.R \r\n", "# Purpose: test what percentage we need to sample for us to be able to \r\n", "# compute statistics that is close enough to those of an exact approach\r\n", "#----------------------------------------------------------------------\r\n", "require(NotSoFastCSVSample)\r\n", "\r\n", "run <- function()\r\n", "{\r\n", " # initialize some options \r\n", " dataDir <- \"./data/\"\r\n", " samplePercent <- .01\r\n", " files <- list.files(path = dataDir , pattern = \"*.csv\")\r\n", "\r\n", " # can actually run these in parallel by splitting the files \r\n", " # in half for a dual core machine and have each cpu run half of the files \r\n", "\r\n", " # create empty dataframe to hold data ... \r\n", " # this might be stupid but I don't care I want to be done i want to be done\r\n", " for(i in 1:length(files)){\r\n", " filepath <- paste(dataDir, files[i], sep = \"\")\r\n", " filelength <- getNumLines(filepath)\r\n", " sampleNo <- as.integer(floor(filelength * samplePercent)) \r\n", "\r\n", " # try to tell the month-by-month csv apart from the year-by-year csv\r\n", "\r\n", " if (grepl(\"([0-9_]+)([A-Za-z]+).csv\", files[i]))\r\n", " {\r\n", " print(paste(\"going through mnth-by-mnth csv\", files[i]))\r\n", " col.Name <- \"\\\"ARR_DELAY\\\"\"\r\n", " }\r\n", " else \r\n", " {\r\n", " print(paste(\"going through yr-by-yr csv\", files[i]))\r\n", " col.Name <- \"ArrDelay\"\r\n", " }\r\n", " # kluegy way of suppressing warnings about NAs ...\r\n", " Iduncare <- capture.output(temp<-csvSample(filepath, n = sampleNo, \r\n", " colName = col.Name))\r\n", "\r\n", " # create a dataframe for appending later files \r\n", " # if this is the first file being processed \r\n", " if(i == 1)\r\n", " {\r\n", " data <- temp\r\n", " }\r\n", " else\r\n", " {\r\n", " data <- c(data, temp)\r\n", " }\r\n", " }\r\n", " results3 <- c(mean(data, na.rm = T), \r\n", " median(data, na.rm =T), \r\n", " sd(data, na.rm=T))\r\n", "}\r\n", "\r\n", "time.method3 <- system.time(results3 <- run())\r\n", "save(results3, time.method3, file=\"results3.rda\")\r\n", "\r\n", "\r\n" ] } ], "prompt_number": 85 }, { "cell_type": "code", "collapsed": false, "input": [ "!cat ../NotSoFastCSVSample/R/csvSample.R" ], "language": "python", "metadata": {}, "outputs": [ { "output_type": "stream", "stream": "stdout", "text": [ "\r\n", "#@example tt = csvSample(\"~/Data/Airline/Airlines/2002.csv\", 100)\r\n", "# read.csv(textConnection(tt), header = FALSE)\r\n", "csvSample =\r\n", "function(file, n, rows = sample(1:numRows, n),\r\n", " numRows = getNumLines(file),\r\n", " randomize = FALSE, header = TRUE, colName = NULL)\r\n", "{\r\n", " file = path.expand(file)\r\n", " if(!file.exists(file))\r\n", " stop(\"file does not exist\")\r\n", "\r\n", " rows = sort(as.integer(rows))\r\n", " if(header)\r\n", " rows = rows + 1L\r\n", "\r\n", " ans = .Call(\"R_csv_sample\", file, rows)\r\n", " names(ans) = rows\r\n", "\r\n", " if(header & !is.null(colName))\r\n", " ans <- getCol(file, colName, ans)\r\n", "\r\n", " if(randomize)\r\n", " sample(ans)\r\n", " else\r\n", " ans\r\n", "}\r\n", "\r\n", "getNumLines =\r\n", "function(file)\r\n", "{\r\n", " txt = system(sprintf(\"wc -l %s\", file), intern = TRUE)\r\n", " as.integer(gsub(\"^ ?([0-9]+) .*\", \"\\\\1\", txt))\r\n", "}\r\n", "\r\n", "getColNum = \r\n", "function(file, colName)\r\n", "{ \r\n", " colNum <- -99L\r\n", " csvHeader <- system(sprintf('head -1 %s | tr \",\" \"\\n\"', file), \r\n", " intern = TRUE)\r\n", " for(i in 1:length(csvHeader))\r\n", " {\r\n", " if(csvHeader[[i]] == colName)\r\n", " # not sure if this is the best way to do string comparison in R\r\n", " #if(grepl(csvHeader[[i]], colName) & !grepl(\"^$\", csvHeader[[i]]))\r\n", " {\r\n", " colNum <- i \r\n", " #print(paste(\"found \", colName, \" at column\", colNum))\r\n", " break\r\n", " }\r\n", " }\r\n", " if(colNum == -99L)\r\n", " stop(paste(colName, \"does not exist in the csv header\"))\r\n", "\r\n", " colNum\r\n", "}\r\n", "\r\n", "getCol = \r\n", "function(file, colName, ans)\r\n", "{\r\n", " colNum <- getColNum(file, colName) \r\n", " ans <- extractCol(colNum, ans, colName) \r\n", "}\r\n", "\r\n", "extractCol=\r\n", "function(colNum, ans, colName)\r\n", "# have not found time to write a fancy one that would match the double quotes \r\n", "# in the csv intelligently\r\n", "# if there is time, should write one that compares consecutive elements \r\n", "# in the split list to see if \\\" and \\\" has been split between two elements\r\n", "# then join them back together\r\n", "# ideally this should also be written in C or C++ for speed \r\n", "{\r\n", " splitAns <- strsplit(ans, \",\")\r\n", " if (colName == '\\\"ARR_DELAY\\\"') \r\n", " {\r\n", " splitAns <- sapply(splitAns, \"[\", c(colNum+2L)) \r\n", " splitAns <- gsub(\"*NA*\",\"NaN\", splitAns) \r\n", " }\r\n", " else if(colName == \"ArrDelay\")\r\n", " {\r\n", " splitAns <- sapply(splitAns, \"[\", c(colNum)) \r\n", " splitAns <- gsub(\"\\\"([-0-9]+)\\\"\",\"\\\\1\", splitAns) \r\n", " # replace all the blank entries with NaN\r\n", " splitAns <- gsub(\"^$\",\"NaN\", splitAns) \r\n", " } \r\n", " \r\n", " # trying to make R stop complaining about NAs introduced by coercion\r\n", " #splitAns <- as.data.frame(splitAns)\r\n", " #splitAns <- na.omit(splitAns)\r\n", " splitAns <- sapply(splitAns, as.integer)\r\n", "}\r\n" ] } ], "prompt_number": 86 } ], "metadata": {} } ] }