From 942da1759b2aa560ce395ffc38d28524a227af16 Mon Sep 17 00:00:00 2001 From: Joseph Cruz Date: Sun, 10 Apr 2016 22:50:32 -0700 Subject: [PATCH] First Try --- .idea/.name | 1 + .idea/assignment_09.iml | 12 ++ .idea/encodings.xml | 6 + .idea/misc.xml | 14 ++ .idea/modules.xml | 8 + .idea/workspace.xml | 320 ++++++++++++++++++++++++++++++ FoliumTests.ipynb | 63 ++++++ assignment_09.ipynb | 418 ++++++++++++++++++++++++++++++++++++++++ exit.png | Bin 0 -> 1146 bytes globe.png | Bin 0 -> 32189 bytes point.py | 367 +++++++++++++++++++++++++++++++++++ view.py | 36 ++++ 12 files changed, 1245 insertions(+) create mode 100644 .idea/.name create mode 100644 .idea/assignment_09.iml create mode 100644 .idea/encodings.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/workspace.xml create mode 100644 FoliumTests.ipynb create mode 100644 assignment_09.ipynb create mode 100644 exit.png create mode 100644 globe.png create mode 100644 point.py create mode 100644 view.py diff --git a/.idea/.name b/.idea/.name new file mode 100644 index 0000000..5a4a47d --- /dev/null +++ b/.idea/.name @@ -0,0 +1 @@ +assignment_09 \ No newline at end of file diff --git a/.idea/assignment_09.iml b/.idea/assignment_09.iml new file mode 100644 index 0000000..6f63a63 --- /dev/null +++ b/.idea/assignment_09.iml @@ -0,0 +1,12 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..97626ba --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..f9edad6 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..aada090 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/workspace.xml b/.idea/workspace.xml new file mode 100644 index 0000000..462847e --- /dev/null +++ b/.idea/workspace.xml @@ -0,0 +1,320 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1460347454539 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/FoliumTests.ipynb b/FoliumTests.ipynb new file mode 100644 index 0000000..6efe134 --- /dev/null +++ b/FoliumTests.ipynb @@ -0,0 +1,63 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import folium\n", + "map_osm = folium.Map(location=[33.42,-112.065])\n", + "map_osm" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "import view\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/assignment_09.ipynb b/assignment_09.ipynb new file mode 100644 index 0000000..5c8970b --- /dev/null +++ b/assignment_09.ipynb @@ -0,0 +1,418 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "import point\n", + "import numpy as np\n", + "import scipy.spatial as ss" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "new_pattern = point.PointPattern()\n", + "print(new_pattern.set_of_points)" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "new_pattern.create_random_points(100)" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "100\n", + "0.9142760164698801 0.15245063193191088\n", + "0.48292614290484737 0.9184628109684032\n", + "0.33337651658050294 0.14784305046750346\n", + "0.9327600879601421 0.2358142955339223\n", + "0.5345702139280762 0.1830012587408244\n", + "0.002849203469585393 0.5434766718623576\n", + "0.6251115361250151 0.2645918875037627\n", + "0.7182434387659785 0.2395936701848791\n", + "0.21368200421050754 0.267438850795948\n", + "0.3521725340587013 0.5056825585905379\n", + "0.5439423094433921 0.2712087706030353\n", + "0.82615355908667 0.6547727443633703\n", + "0.08986045973059864 0.9246296996694158\n", + "0.24471380776144358 0.8116256262258893\n", + "0.21024467340906994 0.37991618148937134\n", + "0.5747940828502552 0.8063150200582564\n", + "0.6025047760765152 0.9753594541295302\n", + "0.7866415747670197 0.22319518296945173\n", + "0.2579375000076477 0.8799154276145454\n", + "0.9888673392391436 0.13713011317465384\n", + "0.5702736966115158 0.770253540370834\n", + "0.8766275270801958 0.641916441376012\n", + "0.07201277369943748 0.7742175904664074\n", + "0.9478697924248484 0.1604053259950955\n", + "0.7305570577634707 0.18514257900216402\n", + "0.5537733831272414 0.4397696756607836\n", + "0.1551455561334898 0.48356741119165836\n", + "0.4279734358661875 0.7431233536565317\n", + "0.059476358378460215 0.0855312189522206\n", + "0.9787609352882003 0.9116216475342881\n", + "0.5144408762183188 0.6466992634194961\n", + "0.7665654174343465 0.8116327405751677\n", + "0.04954603647738143 0.12260715200453676\n", + "0.293864892759087 0.22602694869125362\n", + "0.36400690068460106 0.4544533170785756\n", + "0.45493764851109353 0.6516003388905123\n", + "0.29499855187404833 0.7308962595207906\n", + "0.48498111247671694 0.8773148081492596\n", + "0.23332745739723426 0.3401382348786517\n", + "0.3468309538263892 0.3241406065723006\n", + "0.40918925690082286 0.9383262981016628\n", + "0.105568084445395 0.07797118207917819\n", + "0.6817937716026468 0.7904206275561758\n", + "0.07007824361811354 0.556865336462241\n", + "0.2819049352306924 0.16689764114822214\n", + "0.6144378442123944 0.2797050017013618\n", + "0.31649064551762973 0.8441030137320968\n", + "0.8230946562010628 0.30067911209431886\n", + "0.2618994372009026 0.33352195422658415\n", + "0.981869901555576 0.2193626317783588\n", + "0.9269895104965136 0.5088279168426362\n", + "0.849475891067517 0.18481959677726145\n", + "0.2068049066207207 0.7087007874012001\n", + "0.8916661885934265 0.14880488519629842\n", + "0.23707561990224568 0.41691407513779255\n", + "0.2886420631832953 0.3653916005369152\n", + "0.7435969547589796 0.6927859059931808\n", + "0.5222235112808983 0.7990156931243353\n", + "0.6230869279780937 0.5672448689886037\n", + "0.9854109280758173 0.7673786925278128\n", + "0.7879314480728475 0.40910935134790005\n", + "0.0308960116621797 0.7962125987209373\n", + "0.587634060500698 0.351406109599945\n", + "0.4808262378401841 0.5650946324495782\n", + "0.08853053030971048 0.004176858656150029\n", + "0.41498096721400035 0.4296172802136691\n", + "0.745140060664367 0.15938841008146687\n", + "0.7887168376609083 0.20307882866212235\n", + "0.7409672069267957 0.41630659997950914\n", + "0.6269155513832362 0.8408910861033316\n", + "0.01660540098455332 0.11206648725322677\n", + "0.5218590922009425 0.11550308536945275\n", + "0.18937887758506478 0.10953410548782527\n", + "0.36222684192188925 0.8322795568797339\n", + "0.14357517377699935 0.8817086061690274\n", + "0.9302055316266093 0.6029112018423958\n", + "0.07853663510888098 0.09398472590186813\n", + "0.014658941403184134 0.11447865853102557\n", + "0.14529708534678143 0.32752012910329686\n", + "0.6410269827316531 0.4864479883050712\n", + "0.473544960405193 0.22739874008158323\n", + "0.35491532619647814 0.21635264638392082\n", + "0.4373322595213115 0.5417906778459081\n", + "0.8860375525077219 0.14201178855679664\n", + "0.09945908682911275 0.13854368523393434\n", + "0.05931279084493868 0.6757281907181366\n", + "0.1914869579350612 0.40647248738390696\n", + "0.9766361248822688 0.027057545855305953\n", + "0.5373914243497263 0.7900942340523922\n", + "0.361305006192813 0.5213786521648469\n", + "0.8208587933342094 0.970676245567716\n", + "0.6478749011749924 0.11459295410797588\n", + "0.22799010563773037 0.6865104135458886\n", + "0.40828408180197384 0.4639285130096892\n", + "0.4299356804231873 0.2810535030806197\n", + "0.06283394090070793 0.5165536456890886\n", + "0.4834708255248602 0.6378151236470068\n", + "0.4278802294627707 0.35732215757078334\n", + "0.20072055070401662 0.27405623006300184\n", + "0.14163527086350292 0.5786473576092528\n" + ] + } + ], + "source": [ + "print(len(new_pattern.set_of_points))\n", + "for i in range(len(new_pattern.set_of_points)):\n", + " print(new_pattern.set_of_points[i].x,new_pattern.set_of_points[i].y)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "array([ 0.02290187, 0.04119928, 0.05488535, 0.05179219, 0.06868461,\n", + " 0.06574966, 0.01850227, 0.05582604, 0.01455297, 0.01815955,\n", + " 0.07100568, 0.05208556, 0.06875675, 0.06955834, 0.03251291,\n", + " 0.0363437 , 0.13242461, 0.02022312, 0.06863672, 0.04714376,\n", + " 0.0363437 , 0.05208556, 0.04663012, 0.03452273, 0.0295963 ,\n", + " 0.09462909, 0.08523101, 0.09541243, 0.0208508 , 0.14439617,\n", + " 0.03221912, 0.08738527, 0.034586 , 0.06032674, 0.04527967,\n", + " 0.03168871, 0.08037559, 0.04119928, 0.02932803, 0.07132735,\n", + " 0.07636548, 0.03141867, 0.07455794, 0.04095745, 0.05488535,\n", + " 0.01850227, 0.04723975, 0.08563052, 0.02932803, 0.05179219,\n", + " 0.09413824, 0.05547144, 0.0306794 , 0.008822 , 0.04570278,\n", + " 0.04160339, 0.09088781, 0.0175971 , 0.08276461, 0.14439617,\n", + " 0.04751253, 0.04663012, 0.07654732, 0.0493437 , 0.0757356 ,\n", + " 0.03495868, 0.0295963 , 0.02022312, 0.04751253, 0.0625472 ,\n", + " 0.00309956, 0.06868461, 0.08955706, 0.04723975, 0.06875675,\n", + " 0.06627225, 0.0208508 , 0.00309956, 0.07700746, 0.08276461,\n", + " 0.0691419 , 0.0618122 , 0.0493437 , 0.008822 , 0.04922652,\n", + " 0.09930484, 0.03251291, 0.11075005, 0.0175971 , 0.01815955,\n", + " 0.16805537, 0.10708475, 0.0306794 , 0.03495868, 0.0691419 ,\n", + " 0.04095745, 0.03168871, 0.07343688, 0.01455297, 0.07479883])" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "new_pattern.nearest_neighbor_kdtree()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.054670644019223634" + ] + }, + "execution_count": 6, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "new_pattern.nn_kdtree_avg()" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "0.52" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "new_pattern.np_compute_g(.05)" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "tuples = np.random.uniform(-1, 1, (1,2))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[[ 0.66428233 0.53293921]]\n", + "[ 0.66428233 0.53293921]\n" + ] + } + ], + "source": [ + "print (tuples)\n", + "print (tuples[0])" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.532939208977\n" + ] + } + ], + "source": [ + "print(tuples[0][1])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Assignment 8: Pysal" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from point import PointPattern\n", + "import pysal as ps" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "shapefile = ps.open(ps.examples.get_path('new_haven_merged.shp'))\n", + "dbf = ps.open(ps.examples.get_path('new_haven_merged.dbf'))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(-72.976512, 41.337662) [' Thu, Sept. 18th 2014', 'all-cases-dead-on-arrival', ' 1605 WHALLEY AVE', ' AMITY/POND LILY', ' 01:53 p.m.']\n", + "-72.976512\n" + ] + } + ], + "source": [ + "for geometry, attributes in zip(shapefile, dbf):\n", + " print(geometry, attributes)\n", + " print(geometry[0])\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "new_pattern = point.PointPattern()" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "unmarked_point = point.Point()\n", + "\n", + "for geometry in zip(shapefile,dbf):\n", + " unmarked_point.x = geometry[0]\n", + " unmarked_point.y = geometry[1]\n", + " new_pattern.set_of_points.append(unmarked_point)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.5.1" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/exit.png b/exit.png new file mode 100644 index 0000000000000000000000000000000000000000..6d40c5b5ce42abc4b5eb8ecd6432dedc868ad24e GIT binary patch literal 1146 zcmeAS@N?(olHy`uVBq!ia0vp^4Is?H1|$#LC7uRSEX7WqAsj$Z!;#Vf4nJ za0`PlBg3pY5tru*KR~cNZ#+QW0cnLsmavgJa|JwnyICUC8uob4xJ{)@B8NLG%kMrQ&m{w$(xV! z(%-+k6DuYlhyo@q%d}i$%Xo$%*!uo_20qI@d(~btN*@r~z+l5VZEsn~0gDf9Z|pyM zpHBJOF#SM8qh-ZKwrd~j56s#X)_C&Hski0vW=J{ zY&EMHc%-jRI_SsvU6(8J4U<}f>*AI_v}+#5fu)|ZLxNWbBIVb-s@2Hgi*NB;+91|4pH#>S8^ zIZ4qY@5hBV3=aPUR4i*U>KGCVI3~&Nn<`Mw$ZpA3lTh!!eNWk!{99~Ro6K1j^2u-E zEm`)zpn$jH&GxAVOFqav$e*3@V|Nfw!<&V$=toZ%*Ns+ORE?id$1tBaPoGu1(b)1| z?DVebpLLlwu+1@9p?q{LqjD%$gbj<129EwYb4A~;OEqN(}vzSHUN(i<}u_zopr06($x;SM z_BFB#H8FO-r`P-Q{SSWKZr4@Ub(_wd^E{8|<8j}fqRp-vu`-=tf*^?X(na_h1kr#$ z(m;&Iz;FM8e(ZqX==}6ASu%oOVT|s0@ZZPpUcBxHLCjo7{~(~$bbbgDgD$~(mO<$& z`sP_}n>Tzch{w&SSyFwoN zg_gIS=Z-@spp~t)?n8EH6#9o)kjVBXjpUO?EjM(Vq_Vxq^~v~iJh83$m<{6U>gv4P z*31bv6qX*R^hdmhvdNpYFVs#vg$m{BWr0Fz2nc6W%((Bz$>+r9z9-M1!l6vWItyBt zbxHseexex-|2vD5LTK5_@`_$>4BOsOyLYxNE}aKzg9~zVZ(L9&jba5cTS5F>54_H4=9--r zGJ*Xp1K5yVh`Ss(?dk5~uU<6ksu+jMuqP(KTbWp2my_dmc`RB0Jz;}zCNsKMT+cT< zU7tXl$9JS>$Zzd_&ah*(fD&nJ>ik?316RiwQe>~Al;*J}?IZnpg+q+IP!A}Smh`4!deTiV9{4)f`lrr26FSn_8 zX^r7gXv=u2)c=(UvY=io{P7W*XeF<4CP~bUnEFWHNyCqk$%9ioTnh8yd%p@y5hKGLeskoSFCpxNKcB#jTD%*6+c!8E$bxQSIDcX^bWV`#ok*EV z)icU@^4Ag0xApDpMwf}(Ij}#cS5ammgxQxuI_SYEbN6bZX1d!6W#B`kfo#Lr6Iqc5 z+iyt`+|9kd^KNZ&^ml2I4%2E0lfAvYe1ZCHk3NEL4LDjJ`29@Z!TV~85?0EzXh|7a z^Es7`XzM|bD`cX~_hg;D_5BSO{-zSH<>>k@)sOM=!{O9%&6jd^l`5<5aRO(+gTDQ~ z`0s!eB8fAE?k8%Bx?OO2PC78bD3IqViR~G2N-a0&anXk0-hU>{q|2d1(0*gvpmwuK z2P3}el)Bp5gA;+uZ7i+eo|Jz7{#_rkv2+gdP@*J(dpEJP+_-?%(M{=eU>`NUNqWHp zN!}xxU|q{?_Hd-kFXYmA@Qu=jm^H+DgS+xJ^Qg8nDIR=CSx!z4{p`!HMM#IubI7et z3AwF`K0FUcr1#9Lwq_(M;lPJzn0aLh1K+;gt;DBylb;_wqx8Gu%~a#u@ATv2<2~T+ z1t!5ue|_uDor#?C@;~IimWMCEYURaf(@xdvzg~aHBV$$1AE=BC13M+|dNBK;l;wsj zHd7=}r|kz5a=4j1IpUV69pTzQXOatE&js(^Y{U38RiA@uQf4PvAr{>IZOr!Ae?BKU zqc3}xzbfRGfyj6{$9lEx9~P!^$JW)MQat$3(qp{Vv8f_fR#x4$g@x1L2?~9zAOiAI z?zLj5(Q|Y=E;<3f$J#7K+1^{5>2Cd@0IpN^{=IZ39{*2?@;LX}Vo_zlw?|)?puW<)yu8ovZ}nZp z^q;DHH%TCsIl?-+J`?qwM@_<4%I$U*4>Whmeo#9T-^f12>O1cmx9x-a%je}JdiU~J z4PgZI&Fw@JNy^u2h5rnoJ7YC0&p$;x>Dt1FbO-H0(tGfPmt7O+Jh9 zw-CS4*Qm{~D;V96WT8NvePogdR;P!$FL;07cAM~X6e1^xtGM01glrBDT`6z3UU@2x z<^W$9?XMC3hU9qMxvAQ3(a0PVc?q81Zal0y$Sk|ro82~_8G7dwDYE#1QvWXe1IM72HKn9(yYI=&Hmw9T+xsWbQv`nxPE&zqDa zBvJI(gXwg2zwU}-`dAMu=tsG~MnhzwWo-;G5wDq&5q;4o*kv+UlXvs?+lGb=>r%&X zCUm4oGeYUjO=&kloNnQgDD)PY6eZjq{Mu6b3MxAVO+i2tj8kSv^@0ag#oWzUWN-{I z%c?&gzi`WI^4xF4P>z1^BV&xu$!v?T$w<_yy-7eB&8w?5C3Sdw1msMu_8b0k4&#t& zBH08w*Ppe6Of$!ykxJ-6eO(&#J@&$-d(faMQF(Um=R{UFw&MBj&JLT~TnlD{0~0QX zUi#xc)TJ-6#B&(4O<%-wd+oIpV0?9;|uDq z95y0&>`UCYhqLq#BEcr+Vh3;e{JFG%nAT}d@jp~B? zO3djTpsu;jT?UWBXZ_aZ&%e8lGqtN8_=Pm{d8|H_1=k6d#dPHx@xR=@#pjrfm}&}t zE+2lOrN(|WwVF$*w}R$X+Y9T?L#TPW+7GdAgguxnDJf}Uqtb&1d5LdC-nb^Ig?g7v zwC3!^C^T-lmQiY0=5j|yM(%^Aa{=;+(M%~f>tFL3tNxSzU!_6njx+sv)<0Tn7^s$m zayu9q{1UGtNcZs+|Hn_DZS;s`Gowtp;>IO04VD-mi+-v6D`}N&Azu>X=7T{Iir}T8-Z4`fD>a&+5K?%{SKy+0m3-^HVqU zd(BUC>*#!MvZGupE-prcife_&lpbyK;jACM_+C)3q>FHWC|0fAt@Xd_Au{JPBvE{A z!<|iIc^htEH3B8Vi|2y{kTrQRm8Vk=^PuiO;fH(GT!pGRD;+iF7+qZe3bRVCSLA)D zACRilKM(H^wk;>A3W+idT&yw>$!1$IeT}nMYUbrw4~2~F!Y3m=#xBJf&5mn@Y9#nY zdU$xOopvKz_jg7wB#Y;(+EbCeb$&HtElTk|`k?A~&WO&<&=PnpnE3dZ9-AiS=6ZU1 zE+e90R~}c#2Crk*(#Z)6tE&fYW5I-8yE5mG?_ty*H*AED&`fNH1$pe;OLk^SM=Qwk z_+WtPwf?Nua+|AgCe8ZKFrB6_SzlW_JF1M+UeWAX{XTX~0~j)HGub^mv2QrnmaUHg#ZwA|4^ou~_*BNIDM2ntGZ^d=Qdt;i#hxIp2c zssCC7mIsD^nyGwd!fidB59Wi^WS*3ZN@ZJ3QX^Fc&JTMHAil9W7if3qY1j|<_pAIe z@5S1T_wk(3Ud86G0~kl z??5vZXPj6}8Z2BA2YaegahiweaSyGUWSos;2>f1pRp@^I#KfI71M#o3_nKVhYM?tY zE?YgdC80>K@atE~n%*#Z0>)sHrL)h(@{Qx9Gzta3Kgsx@)Rm55i$xMFpWB=!;^Zg1 zM|M7`olb8(3niA;b#-xhIn4krJ(b;nFga#MvmS>Z8wZH?@{21@T0NSU7(1{ZIQ#i$ zFkno8PFaONop8Oa6RZ@a_tfQ=7g^lWT;9>VdXSoyCS{VY_U8mtXq+H}>QSadH?C11 z@xKHtL6oqK=Wt8KM|WUge-&iI6?meH?5EhVi^K1Y`leIo@6`ylbe~G=(f}+m5p@s3 zUEdCiuo!aVZw3Xz(R%}u4!L|DE|~x@^2_}zWCg7)5xzzT+|_i zZi@uU4ska=vT5Q3wk73WOM%MiEG}_W&$+W_S4Mk#mGXqoV4Y_T9+%L4v;E?W*$8ZP zRpQy)eJY@thQQlgzT9~S;6>}7puTU1a?q_E-xbYRu5B+``g@{@fO&*}0ok{aOK;2p z3em$a$0TDG8mcM98QodlCvHyGYOs;bJTbsOm#d+naju7mZl_<*FiyA(w}ZY>-$iFB zI(m%%_1xUt@h|T0((n_GA6=X*`>FJLcYTNc)9%sCz?VSZ`0uZ1ydU#TH<3@N^B=Db z=*hVI>3HB4f^&2Ou@1aoNtzzg{JkX^^-gy*YUeR&y|VbPHdU!;0a)BfhJ3%?uT zpxE|<@nEqXwGJTbLr~&|Fi*`fj^2YW?)O&7M6{+z=!%jZzs;!?-t%y3YAR=6-j!uk zcBOIr8I&ofxhDr*;A4TR;$rVWl;$WG;#Uve z80vOokXx=Y`)0R=mBRQhMsG*Lo;+CAN zAk@*$vdF*M@a`F3BowH6_N)+cvvrbEUz0Gi*D8Nt5aNj8o1<)3Z3g~fz=2jC38^)F z3VwV6qpSFG(4%7b3+mp67+<7wsGIDr^ECw6mRO9oQ1hgWiX<|l3@p%Pm&kU^M<(2Q zZ>ox?eDOLxrK+K!!6;cl@ikyp@;F^cO^jR}aJ%I$8w_S56Xy3@Sl`8>e;aVnAMHK7 zOpkpODF+5xzc)&j&n4bxK`ZNVX#D_O{v^)s=u5)CQR-u*RWbz#Jdn7b163cjOFlbct0lB8y?y1pS0nIC_O&I$IGPEO4y<+D;2 zEBVVFlr(IP#2=A^Feq88ckR%AaNml)9lc*hBL-*Ahd;+ltG9+aa?pt~*7aV{$j}jJ z?ja0E=%6_0KBCEc&kXN=z!6PP%wBHN9Ltizcvo&VCx7r7epd|Ch%Yf6iPA@_vRu2$ z2W~j{%qTqv=U{-YDeOf0c9&_YuW>C>Wu-ZDzKdbqbEv27qPIPuVrBU%M+G#s0xF0m z$nTN5q01cj^YaR9SFLw-(FUm2`zNIwIg=>=`b;BtkGeJ6J)ZZs`=uM!8h1<5v_tPB znl+`BB$2|QQ~xpCu?5!@l~Kyv_OZGVC6;U)j>9)veH1VK8-BR!!T{*rID4~7*~9@4 zfIQutNll+K+E0f?On;6}tSJdiTCQFD3J}DTpaVW5PJ1{+Q&Tgv{b`l}?Ig8H93_fO zih27(Dtj$7Go|>m&0N#4F2c(Lb(Vj>ZppFUmzWA+`mLx|cko=8$`>FoT#VJQXaBVppb&lXf6n6mh#85M70K zUo2_qD>5OpYHioAjZh~b0l+i!l(FR$tzM1YoaW!{J<)8D&b`QUw2H@=`Q)`2&s(2T zIDpQnCvfe2lm%N&b5#Byxhib??*{B&kM}wvVQ;Pa+5c^BHY#WJWF>XZ-pN$=!=iCF zXtlBk+aI9su)jQV-x3o_2>yLq{=lri-|g$fqwFz?i#X2PJh7D=PfibXpsJWB-Z;=r zL-6N%ovRCUa+(w-*ZZ7m2bJg1onEtcq;^4NL4T%yJz*7`xB&b33(Z>};g^Jy6MNef zsVk{xzer@qn*Z$kv_vkzLig`FP_K|exX`9-=)xq9Buzr_7iR{ePeMqqABdsYIeNid3X)tZkK=)Ilp_!JEEI|Qtmnjt|_)7?yql& zX5~@?qq6`q9LPVcL4U154=r`5+Y}~+C?j)S_zo1~3L&Ucp_x0$Q${O?&g<~HhH6%i zf@t@1?Viq<4rQQI8Y+`^o`^9@52UxT$blOuBn`e+c98V}1X#NyKVRxEG3rk@6Amfu zq(y7F1s5Z)K{D{K(Cx5;JYn{{YlRPq+wPcfU1WUi>)6FX0y6}Grwxbwd8Da6euk(d zn;}3pQ$nLZRNyKo)@I8u(~#tsuGzL#seS;ft2GcV<6gb+QHZkW|! z4}l}HpUPGkX^kWgP&YTvB^&2j)2InH@0+v!+C8AhZ*^E<8s>&QvbqvBr`e&#HQnLS z(a|@gl&BX2`|!V(r>;asI=#C^GiuCGz1e?1bpXXOl2PogzJZ2Xe$}r2nf*E#ljnO8 z((^WN8yv<1AX`dXp?@0&4=pl&14l-G@GgJatQ{oOiUY~s(qn4HW` zci3xJz&74~6{`!qwJD#zg`JRFL3djh+hR;ka^}BGdlN?_Rqi$(UV`73eWmVe8vf$& zQlNSAmjRP`#>2$ek%F5N~raqZ{`4G2j~kI0V>~8 zq`YGO3zmx$_cPO9)eH2xD8ATMJ7SHmtnXJj2UF$;Q!?VY=UxFs{)M{F1*OwXoeHfn z{KbZ{o!UJ}(&MmPVYKCn57U`6gkxnCe~b>4Iypr@E}w}Rr{RAzA1umXR^C@`g4rov z+g%e{hy??KrMVSarGy_gmmS;CTJuM$>poiS_lB-+hBryX)n7n?B~ajvop;{-s2qsw z?FpZ3%K08lSO9byh{fCHi3V`~uX{BzIU*kQWi-xE$#NqGW8M1gMXP1f$BDc4gI9`f z8wI=EJWUTYiVXYH-14Wgx!O)JH%npy04n9tmvuWfTe~_Kz2Ik_AdYH)CSLZ;7d!Yf z0=%IMD2E59dA`G5JU$&Xgk_$VTF0Vq| z7!vB|-yriMUV`@0>C6|2#_P!+K#I|LHd1q|6XpX~vk-Vex4|elfmAQwyQIwtzc&Sw zr`5c*H1HfPG`i+<`%?&HonqR#8#?xdA8ik+ldX9$N2q0oHm3DyYvuDS?_x2)hbzJe9*90xzmBKAa5dFyStt3P=(P7x`Q>vmW3~;$jg1sz$=;iI#gZ4M2hyiUO&SX+!5i$!;z$b)n6gh=2wy^7Zwf^I1 zo0WrrJ@WM!Pg@)vT7mt+)B&ixJWhZv0wFpiTlwU#FV7{$1I!fK91u@|9>X@(;ydp` zW+Uy4R{JUDJp*zm1Ej@|2}7!n2aH$2JWY;qMKoey=UevY9(_`NpgjYplx(>=mU2dP zO;7`iMb-NMnQpzGy)4#-L6}J=H^v?8R!8Y$25EvMNn3e$8e~`LfCV;51q+=oAv8V3 zDtInk&}A=G^$rvCKQZNW>%BF1>kx3rCOpJi;-#@03}Ob0viHkan$2q03*xG?$8)k<9+-sI&)r*BS}G#f}D-2L~PZON^Z=3fCdyPsomY(zLUrA z{rvQpA-cl>l7vAGr2>@elZ|(XU8;m^-rqEz$-9y^phRgj|IC-9+2wBd|78JUK@kaP zMr2*hr(*hza`-!cG-Q(+wHY7S0fGEc&i|PJzmdK3QFR9w;gGzm8B4$x^z!_%ji~^W zoDChRnY|tvxjF1H|JL>ciQjxL^;%UGbk1iY%<2)}VH7Z)JOU$DrXI3K*u#~uQf8qK z{Eukcv;~OUlWM<$V_jWcTwowBjC}As>?UWlG;9^!rp78X5(L%&9VDpwOl(8h8f1^n ze~W#(BIYZp7Aa`x$P&6MG#>#yM=_Q{31GTCacG(fc7()uJ`(aGX2T|(_yalJW`idd zNg7f_lZf)19EqG@!DTt_X7`F@%JM>hcGQxQJ!5!vB)M ztYQFIGiY=6NSm$>%^^R*NaWGG5~VPYn0{%_AsmtX0LHQ+$os%9(ljWcaGWlz9i}t6j-!03)JrdF~-Jg^1RD! zpd~WYt{nmqT|C*i_@<|4sDa^gCiDNNH<-YD5J98ut{_msqsqgzlLTO$ET>`;AB;@H zC-^x8+LsQK(iUsBDf6bOTETz!AxGqWFXXT+s#J7U#2XM^WBC5c`qmpr#H?SJt2YDo z_W)bi>BwMk9g8;XqSW(2E9brq8oq(yl-P@*AfC`9O&B47`rySlbdy~&Mz$W14l?nZ zwBPJ>4E<-B73%N){+cY~#CR*Nw)gw@cXl9=!O;Ac@slp$;z_opg$4c;*6O9aBi}I= zf5)X=00<*z$E2#>zh9YC>uv(VGrUb$dIgEluk%5HG}Y*&i(?p_<@!8;i>=WBv1qV2 ze}w%Nart2MooQ*n{0yE5ha6RZP~bNy#K>2q$->R#p`$9&OsL>&UNuiVg|Z`Tr+`KM z1kx>`IU=PmK{c{W?chIUE$&8~tYGOck!QluGxM5UKFOH~`+s!E0Cy_5_yV{Dml0uS zAB34`iSQ+b;ul0P`-14niW{9TLp}d+*@2f(2kMLwt7DI0x9B$@2Jb+ok!;QF06N|- zs0M($1Aw>|^7AO-S3lBDSFv4HL{omg$7tCh#B=S=>V^k|mezVtvrgQ;?BL))wG3Jz z%?3O2;r!`d4+3F(zr96vyksf+XstXU9Z|iTJV`l6O!~skCx4CoJD7%Z57JE@M|V^J z0kQ}9J+Uuez7zl;%mii2IJF@W-ta%!|L%xch2W7thHVs)71KG_QbJ_GCsa zF>cDDy{vF)R*xg>=GoG&|1%@cDOGUYcg*_>hU_ET2GfPwRde{qapyUkX?%wpbhUe) zQpKX=$c1!>(i@=tXM`!ec#_lO{{8zpnlH6lrh+Frp*_L=KO!}kFg*a~U)Mr9d2@MnHA3gX5T^2-?L&-BC{`K~93goKP7H;2mr}Hhcy>bMu?)zZ0ST>{a76aYjOP>IN1KBY~piovyh zc6rD8pl?~elT>Ssgc%zCKhlxd2z8`G6|h5HG79+K8M*QMRVPGi{#RYNG>m_h^bDU4 zy2Q0b2hsAvVVd)pCLBlpxxl{+z?g1fJc%l0kw}Q&sq!WRMrb1kJabZS|Q6hQ7uDQ1+9M-QI4om#64Hi-&O zyecn&8*M7mIZ|qC@tpoVP#kkfIkp+P+!$?{IJKi843SwSUPh1CR&xzufb<;)rn@%I z=>^|>>jNU+$>(1fw0d^`a(L2|NMt|GIYVQ)5ni%v6(X3Y?1$;z!(Z%DNsZA5hO*WL zrHZrQs&Z*v3I8nHQ!SsSIznb5ql!da*!1*|3>Yz+q=PWmydjP%MAt>U>!sQ(}G+!W0iAzcuv`C zHvI6Aad%o8MUM<_`8(Sw$|5cVR6bpRt;9boE6MQ2?pk+#3IBgSt1v!KA*8@^y8W#Qn$c2 zs5;|Af6R(dcVjyu;P(o+@bZ1`)^N*>xb zfbYO!!UGzp^g&siBKmiSzaf^)GTR-2|~{Ss1zjz>>x8P(2nx}6Y_>$ z-~S_1m3+vEtJP7i&cj0gvzQ2qKSjkeztTgeCsVYB1Mu1tc?&R`K+mN9L*f&B-E@1TU;V3p|QYiIaui4X;c9-yHDURf+87 zV|81!3!F)+KQ~% z7j~!rFR-~sz)y%`ueGgw8ynNo!<3@3PggdyVZS^(^{fkPD$5&Nq(ruA1s;beE^%!q zNF!sy8lF?4h@jq?!5L+W(2HaQ(WL6{+@pMFk}* zC%AaI_6jiYnNTBAEA?^1uR-ih3zfL(scU(7!`uRs{LM7>sG*gc#MBV5<{tVZ=$O?qksGO0$Jm;UypW_yYg}5 zwrRciOEE1NKB5}lIos&8uZt@yD*+BvJ4l{U{a+eL7LIln7cXD!;)cjVA+Z;b!(Yjh zLW|4qhP@14n{CCAG9A9O$zb<<9aMpN<@1Q^St;19rHYg|*K#!#qRF$RNQF4j#W)eP z=^ZbxJuw_}XVW1I?qwP0#Fqxrj&9@HsAXh4LHWj4)1&5p4*7TlcLnaIF-xI8f5pC@ zSKdB|AD34)17bix8dd*f&j!SR$dlQAzo&h&Ux4;>D!X&0+l|GsgbMvdV~R!wOk&Kz50 zuO4}i8D)#q+ahTl|Hk4y`xTg86!sQi{;rj_=R7ECgidoaiNbWAJouY7yM84s0-IV>@3=9m$ zg$OT4J1Ct zp$Wdtp*9vUm+G&axKE<6u4GiW~W;m^m@Sng&&0Fd6t>|?l%Skp#k)w-P=1{-8S1f}W2 zhX5N^&kNZAIjXk%*1FVPZgW+|vUwMCpiQxJw!fR4*RwuAE}F0Fci+fc{&qPJMqM8% zB!ZxX*~kLc?BqcLH$d~+Vo4YGj^A&ZWYNQ{iDwHM{*uHtwo><5bK-%h>IGSI^ty=W z-P9LDrGX}o=)cSHLO^&hU@dNHa-gtr?eOd`LV3Z+RUDuJ63BnU*GDE>BmZAGb@hS6 zUY8{c_Nj4h0(LH~ z1-uw~>_k;lHwYXq>0=K*UuEYhZ}`~ZX_h-FVbK7?gzdt6MT>l$?N=TWrD8hBf3MHD z3A+iSCojTPMN3Z95zo@ym+}rf&qAkwpqGt*U$_)%_$z~~0Ww84c^5|8V9g$Q|1n=}d^a!pesh9qI4qSz3LrW;xpmNS+KLo%`Mp+az_eV)-Gs zDQ|L^Ol73PKx_vUzu*B(UJwo}@tB)?N>RjG!tQAF;Um0!=j=TR$Bl_2jt3|*Z*w^` z0mEp_MldSm8b;JG_!y#@Hep7q-mUVe5bQ9etQ+hW2C(}$5Ubb)ysX+S6?!O*EU&bG zmGJ>jp-H^`Z8fQm{wT^&hnHmu-Eo2=#wKTG4gUkZD}&E5=;vOtjCCXArQ7hfwAANL z!6kk)6KRJXwezvkd-UZh$cvq|0>l-Cj9=(Rd0erCtD z1Op9(0$;8Gs&KyC1_BKJhvSW-w!K9>DgB%kjB!T7*N{=lvL$YCb!)Tyg6;2TV)?n~hpR9)KK=g!2($E)aS+6SN^=qjV;E7HN6ruHL;g>LmhL6E z@lMn}kzb3=8Hn-q|1Zr;zFI>6jW>|f_geoA@P@7c)26x0zV zQ1P9##FWy7&Bu3W9u=A$W`j>6xC`i_O`pi6OlWquV}EFHPLNtece;8-*yN#WvcukM z(qMar!5AS}139ZqG#Ns_kaSHu=WQ#FI%GrV;olGJ^yp)FpvU?jZ_GV8>T`iQS)!YZ zj=%!B1g|(|MUO~85wA&WlkaYHnoLqnH^U=mpPjmVa`p4ha}dGhOVaD<;b+G$JOx(q z!}8A^*ovzf8I>)q(l@pAUwA?&5l_{&w2cm=IXh0Z zEyIXss|@sApo=XfHGTtQ#xlvqDIm7&$1%OCiq%1!x3>8sU3|L| z0Y=Fp00oocRX-iFE}nE8cA{h*0E1E;a$@%lvuL;6$Rh780tW2~oe0!12intC8J|VJ zG;)~5dE)LMZFNbV6cSWgRM~zw_2eYAG)B>|FA?wv8FWK~&y zoou|w7_#o9G8P*NQVbl;Df%LlKh7W*FM+_=y_zu)*Y<{vjCBw{bbum{-3`)J2pygS>{Wl-?imO;;y{h~vT;wspYbehblutqX4x`Zl=;>W_ch1$!EQ*t?uCEn+-> zH}ehYGQuRrIn2Tcc9+3XUyd#&*j4hBMZ*48sH7kQo(4M+h|fqim&6 z_qF`ufQ1`s_(tlG?*q%@Ow7PE!8$|2?mUn}+)1cU{vT+F(S^oWd z|IS#j<-?-`S(tvSvcxVj5b;Ley2as7^WE#X1?Cw3soMqlO~9EadGyHQ%s`F3nUY-7 z_OH`7-OqFXN2y}r65n+9>z7Js)6}zzuYf+(6VvL-jx+O_H}sW@wOyfyaAi%mia<2s zW|y%90NqYy3S9?qo&~#N+1AL_vGmC*AY=~j4E5vkVue6zU-_1Qe^wEjGEHZR*Hin)Ay+P8+%e&}@|`UYLe!u+g=f?kK*-)f?~97B`j3TR3zA0p^CO^ITcgA!`V>hUCcqF_<>5Taj`D zzzwBUt=nIY2sHv6X~_cV)KG1-DD%{5l!j2V=cf}!un2a}Ns-dJ&vSE@E#3jD1=#;M z>aQ@MA#eY*=)--}-5(*Sgn?r&e{-f{_^pLZhQ6B&1md1)&NkIS@=L0kEA%fhtsiIqfzbT3tPs3whWl<5xMf$S;h=&MgVO*W% z#$1?=?usJ|a9UC~H#ZZS4mL^|K=_s)Cjr&dH`{-nr2imk*FNxi8DY<11x~>^p5~sQ znc6IKy>O;7k`CrxYT!f;gTo3wCvK{FWo4elUL@Hj-CFsR4UXTTadw?ej@e`9Z@4-+ zIk|$?{H{l5_n*8&?b#Q!c3-{I*5nRrX^y%Fj0~?il}@39onrvOMo-|USlq_l%}7WQe;2}EE5gb)PGHmkGrTc zp=r;UrdWBY>TQQl&;3<^UR73B4kyeA$)VaIwI@Vsf?E6&{7l-P6ATuTboo-!yM zKYRZM18$Ngh(H`HTH?i4j-SE++kM$mb{d3@W12j4d~!em^rg&owIeQaB{4e>F>k@JQ2X_x6Fz*H608?t zyG{RfSu#=3fJyyUTbux;Y+r4G#M^nU`LA}BqV}`SS&^ZQkARXWQm6(Zoj=5pi+)1$ z4M(ZFR&W+b{)m;Gp!*mDBE~;PM|ba`LQ3&t>gj{ZXrSVW^iZxwYnY-nK=i4BEVNXT z1>!xMD)O8g*PypcYajJr-#xZ6(Ik+{*&786HE&-jSCZY)F(7;Sz$-dgxWXWdiM;1%(9P3d1jNd-ZOqhuolvZp4<;7f>aBO|q<$naBSUz2?#5>ciG zvaLs_mCh`I>=Yzqv-(JFp%#g~Z@FO&fKETp*Pb{WevBKdh4~*q1Yw3yTak&M__=$~4<7cm z)6sF4#JP;q8IaMwLaYXJ@UcBQdt%KJ~J~DAZ80)$^^(%A~>cUeng5094u9$ z!0o;-+mccQ_>tqB*m_$V2D4t8S7BE73aEzQoG(3YKDdj#H=#I_w)2VvGEs_*4|4f~ zLIw!m{DIr`Kuqm2MqzTp6aIG}m_pn}jyd22f@2Lha#gnZ)j9)&Ip)n`)r}qy*>8ix zff8Wd3T`5vnn=z+7P{xgK^MtTnI+FS6(!!Ts&W+;fz}g%!}sUtwA(h}j}hE`Ubp=u zSMN4Z47HxTxIm`Vy8)8M1t4ZfcffcufRXuOPYlLEWIsY=G)?#MW6r^TbW)5DDpKU^ct-|A+%6Q=)$Jz2|8gBbgg!7NGcZI*J>C+a58>vv3=xgEOxqh>#>@J!OhxAz?a&0C){5%EJT=edtE$fOWwf|B8{9xyfQxOxwt2n_xZ zL7pjGk^)C2BDWngmHID$l{^Dw4sYvW?^yO1eO)GyY&qysVlGBzJ(B`4CZHsyc40j? z3ub~TbK?>y7m+Lb7cBqCWybJ8AQ+_kl-RQOF-QYw<+hF+K3NCtN?=S(f%LTt$Y-Dl z0DnXlE=?ajy*gknPKgrv$ZJ>~@2CBLMdf&7RbK{%^``^Zm=QfG?AkGI2Xai0`4udA zWS~!(OvASjuLQC77IyHPDYb-@p81saj98@>B%K~xb5CHnJ*LM51n4ZaUL!#g9BNy{J&1ZsF5h5&xV$Q#mD#huSu_Yq5gWdS6B~- z5bV7jNo7Ho6bhs6MXl``7|l-qe_4QYzkP0B1>Mb$9JW*fTx%WRzv#wDjGENoSg z*fxB8IB{%%yw-u>sQanEOqUAi&#SD_71$s^O@Z@(<7wdh4o$(%W3(h^Du^>if!D7B z0&|`Sx;mY1vQ$WBO1yY35+MA^R>`wR=X_dAca8kJW)AkdC1 zQ6V>M{=jd3fP)TBmtKD3{~>>FBJTQ@}&^IOPRZj2r9{)p~q?VmVR22{=KkTvUk z4anJnBv-|Juyy5!55fu3jsoC3bUA%!pPrm7d2*nLrd0#S zMW1W+j51Cg$BgHZOu2e#p*srPOxhqi_Pb47AMMM~4mDGNP2k7XuBo(W-SNyUzk>`eDrBh-vK1Pr|V&XOu=9 zF)ez*AGLD>_$yWO!Gpktep%)x{F*^OK~?5g(CdPWh*zZ7nGpW(f2?FLO{h%(d8S~g zYP!3HQ06sWtHLm~c+hwOp06vh`{0qj)p&Rk9aYJjKPEG$4gWJ53@E*ldyOFq8TbbN z)u=dwG#?slHnV&KG48UP!kT&4*jPciM8N(5I$4ogt6Fi#FM}dEhuI&7oHAk9`h8WE z^?UE#i{QEzP%(7CgSAJ6sN(v;X_*rSZm)M+Sa?51O_^CPMcuX{e1v~Z{8jHPW&XcQ z>W!)MbDhH;d=VSpn5ew}d!#}p^&2BNNAMe*K6lI~fgfJr=F%!xD!6qQaFb?Ay`N0K z{B>Ag4l>KFf~4PZqLYpHGl&M74CmoIWUoD{_RL#C-cI3C7J&DDW5N7f^n(Eu_{YHH z;8$iRb}&g?DhuP8Km>>m*}&Co2i0GNu{1ZG=e(gz?xZMUO)z&kICp4qlo8kOsul%5 zNP-I;)&F8qev-=0e8%dgbU8DQ!*xRfl?K9MlE7Eswlc90#4mgWK`TjcV)dI3!mLp> z0wg|TC*S!me(#m7Ejr2iVCp_p#lCqGxX#cUBmP|#Qmrz$@tXh#WvwnQ4xd|+jcO)S zT|yCPEJ|6&2jN~ZOe719h+IU4ut1jmtA~jSw$jNOGgm(m3h4C8IGZ0n)VeWYVXBQ$ z9d+ugV&1txvBl~X0~vq7M3T!kk{F?N!b%LAIRR9qP@6xWID-*pr@22lLR&W5O_j9H zLgxK-;Fp1eySquUIixE*t)BHqt5p8ZLlBhWIBeQn)iOzVHzK;Fo?j=${NK}#><5nS zNcZEhf(86MIXOfV>kSjycZS>#nH`ZEO98Rw_N9Zd%%>5_r?bDI9s1GFJ8yCev~J|< ze8C-o98?J$>Yiy% zuiDdVBdr|oK9cYFXCTCG0d;_i_A84`(O&x*CEBQ%eEztgh{!|-*&^hV9*jj(s9@}P z&U`h5-;m1BLD$2$75^MNkI547Xta=r}~o72k=VhyZHFbajjCT#FR==Kn~ID-@5gqd~;2)0kQkWCXSB;B2IdaFkR zj^WOdLF(D)ee9KhBYiXmhz-Out;Uu)y+Ja_E4K`r@cxRFK;X>&0^&lxmI3&|2W}aN zS1ck9S#5H-2G^26QRIiuP9glNqk)s*`S-FoUfq(lt2Bu&&`3xTu>?m-)BH2fvaqo1 zO^{!iJ)hHR8LHM)Tbu#5@tVY5M=b-~ zxU_azIP!n`Hm(W-W}X}^dFc|M!Re#}<-B`F#9`?k%0a%p{Jf;yBjRA|izv$v`zLV! zzv{015vu>|UlA?HP-Kg)q6N_?vR79qCCezX(-?aQp_o(*LZ}$Bwi;2{mnIF-uH6e=bYDa6C9A^KwUDxN4RF`)~gc(zcC+kWOgaWBPF+v zxDe@CqI&qx#jRP!hqwr8krZ1M?gVPf8^&aNgWF!!h1+=9Y2WSSp|y;n^}5cTcIWGr z@BzKdOArn{(xxtjcvP&C{mc7#i#D-yaLgRXr@koO^SvRVBmkC$4U~Ne;{k+Yh3uMG zH&EA$ihS8?0xAPVaWRxBe&)r9Dc{^|kn?V&_ebnUi$H@<+gJT;KW8-#T~1YU4%czm zsWp&1o*C}ZjJ%owf*nX&DTYcAsGtu z?%&@AE5vrqmbxTQbPIDmVsq*(pLl+DdV2aw*sG&$i}JHLxGw8fEb-8Ss=F@i)<{aJ zIXf<nT2+5LArKG1iRH6!0+DSG2e^V#&N(R;` zwES$S)T}zr^t*qOHT0{GaAW}YdJ0y3Hdud(}UM%nLALeum>SN z&UCiT-~#WW*!grdO8t5c9tW-_6VRe0A9w9e#^%IK zlZH~Z0F9%>Jf(d4O@xk%Lkvadi&&}DzMpb@-4(pn9JU)DHn&be=SK_cSLtUYnZ9;l z{Z~AfEW--Tc5Jpj5@avh;7qa9oH&#GQ`UrbeEko5Uk%?GyS5OME|W9OP?* zu3}IbNGNij3P8O4WpU_H^V}^BktBd%fB>nAC2_b-3E zFJrD>Z2;A}G-tK&8EtKcy487yiPQ2#B+Zdh-kJ`ur3XyIw16b&Q3U2uu14S5@^^M(FVxx`SVeVoG~6;_7H^{rx!3 zuV_-F={|L=##EoV*YuY8tJZWoLKlcctI4S;`nNxch$%1Ihv(Q%xE1}2?Rpk`ac;;S zom};NMcfHyFczfzYkrE~a%k?4+mNy3^wwEV8YU1b4g`py(< zzSv$mDeZd5=<5b{Pys<>OO6PcMN@|9Q=g?$N4OCE_JM(*rkadM7{av!BLkX6zJ#^Qc#VD?5U!|L2yN!)9cvs=i+58O=fe zuSwNu+A^L{j$g2rk&TG1VP33F;O#l_s;G9Sf+Xq^Ud6A0`4QC2jW~v%4ThxBiige1 zsi3&yUoh>*zO@_EMW#b#o8LZQ%G37Bj^^O!PV*8OE0UtOs@2}>?_^2R6 zuH-d%IH!cDe55-Bq%2y&cq)`ZQ&EC4ei7DlBu!meLE&ME7CB52vAZI+zW=8O;uAt0 zm;@Uc*oh<}ZJC`RnE1_%!BQyosNIj2SdzJeq(NUjIk32qMCtVAClm2L-#fZ;ycC{F z%Od;EX0p^z2<&kE84M>wJCtZI%eXhS>M{4-8Pxv;to8$0V!=j^2;Ie1=m&B?l=5V` z_4JOl*ARe)lpBp9wD*GZ+QRh2MB-27?fJ(C7E^7ADm_YDd`@8Uk>gQ)-H6Vntch(n>ZGzx-scHU z%|nZ)pu#xUG!>#yyD8xSVJ(>=%^m!mpJ7_aOr$do9KyA!gpGenem_T5>G{BAeH5Zm z0DWo}9uZGaD>TXK8&<9>G^DcBk9Y>1wG$yX@WlK83?8CdqxWN}E4lW%A7O5FLC@T`CfG=SLbzF)1AIfoj5>m{C_dHUx9jyiYHnSN6UcPp0S zg3dsUdIE=VzJUB}8(lS&;@4hV-8nmJ;>&wB|120M3ZM;~5z$ro{2zQy9=AM;XK*Fh|J3#cd?AHBiLp&md zDj=>z7yU5jEdm>zaO~2Xk!KwUW^nzSY`hUp*R_vDQzT&t7{YHhn3g+KJBL>@e`T16 zNOZ%gJeXsw-}OCz1J!e0*Uaq<^Hd zsHXzX!b+Nd#(ES-To=Zjm&h0cKcdkQV9esB)(>iM(cd?Cv+L-C93vgO9yTeGE!nso z2{Uv{pST2@2ufd7@ zd)a5fLB0<4Lj*Rg19ucdy}Fzj@5B05x#^TCX&V1n%YL-qD^0FZNEJ!n0#7!aD!e7~f-O zXAdj@M~|_riEB^hS-PP<{o2zLF*|UD4@BnfJZ%O!ck+vc%{e-E2_*gfv>cj2tAqGt ziec5&)xu)_q!iWpqf8OT+3+vYIkW|nwaNycPjdz8nAX8+D zYM(cI!cM@_J&A#plj1OV?jk}${;(+iT=pxcV$yJZBcZ#F%2k8&Gb{oeFl zmXxyuF|TA6$=ccXvM8MAC%SjxH>$it{&;pkXW|gS^^2*rj4Y`Wj(@2W};3g|fel~x@S$@3PmgXNk=BJ-@HZnV!i#9Px^da=- z?L?aPrMBq%CbQH!dj;kvn@@bK@RCcjH|R1NYd3n&P(7v7aGj^M8uY;fc#))V{x?FTb7;&n{DkPtFBO&E~3i@u&Z(} zV3yO$tW(_(f@)KEI6JvrhhXt5_P%rHBkEYbQC=^f$0y!ieoC^cQecdFPJTj2cs~EZ8D&HayY7 z3ieH~+P7L_#y|hd1-7^hFpr|7u6vNg)cDJsyEDsf4aca4j&-`liBbOz<4j{AX0D!z zeN#wML-aP|D|0U%SS>b}wYyZs>Hlvq6ojlCWzB7)g%GgB%DCkXnuW)-;uMmrpp) z`uQXh7Zb*w)s3l4VDFiPu;~ zB!$~InYCUh@=WR^Ph1SO86@iKCRkKNRthZ&*k=yR(w>qv8U-4pOK_HL?20+{#g4`P z9*tXL{ojvr*x4WbSPsIO-D?LZe^7=Lzhm$f4d|SYaKT|WnUgXXaAm9ygji?(1Xz% z1I!#pV(NKkRkAcsOnft#0o|JvnSORz`d64tP~J&`u))q_BXb%CAwp!c?83*CKv9SD zIKRv>KMt6BhbZ;s@f|cLBUyHqgy0kas2&=nHR)jeGH4zoqbMpQ2unB=9{v%PolL2x z$0nThGum{l$Qgp4kX9R&xG#HW>+CgE%v2ku*szDQn|`h1zSiq7DP zsWJBf6>xKnxmPGtZy=6OP42jXm{!p*b36zJa?)MO!u4cU3gtj}#;XbCPsa8%76`p> zXv?!o&PQhhBhUOO@aX7$B)%mFpC{fV&mvL{qbiqIlY_6)umEqR>y?u{MlqRihdP*T zs-b+|eh-F7T|%mUfF2UM;31lJUUf(rQQezlmaJNeS@)kuX&>96Y`i|0Oc>>j$xlpHa*_=}17CN4zo?5+mf{3X-k;5>= zhu@Vz3=t%|P}YP-PDu)r!I;=rlK^|s2wO;1@y!u%XtKyO$y%grS=dZ|EQR7BABOoL zu?BgIruAh`r~v@Ca(hz5qu!qNE!gaoQp{sCe|}3%y-Jj3zgq}k!)Qr!>jbnf$#(SB zNYFSIe4@Ka3d0F?AYAt8zeP5sw#Bulb~z<2sE`n z&fL&2~2Rifp{Y{)@h$%PT7kiq1JzWXni1uC3${o%feFwC*-kCpQ4x_i7#*+0uhqt|2&G&Z z6(--leY@wt?MgCzH3g11oNr$;*w^(`(FLBJkksr>SQ5>_=NAVUia4JG22BKI&sh(; zw9pb|JGa;+pov-a;_m54_YUts1V;!eA(Wi2DhL(Y? z%PN)Prt3kc>y8Tzn;R)01!k^bDl6t|K@1G)?qTJ_F-6AL(Ngtk50)?D=vS{2^Out% zGE@2oBlF-G)xzwFzAqGrqX}J+u&%Xpy!NFZgyiHXe&y6A?;VK{Reo;$)|UyR7YWJl zWox1soR*H!J01jID&=maF;(uDgdFZCbd7zKyGf={s67jun}}`=aCkI*MOwimt8&-k z5(16q)j`jaClO`8a_-;1kJ;?D)WKTtdG0@OCrR>|zlysqgoK6`@w9dCtGn1{kWEPS<yoUgx z{rS1a(g$G;l3mMhA&967^Bn;wGyfC|8T<+I!4&FR>s5YoCNJ*gfPQuq)&0WT)zk&B z`Fg1u2p)mFB1htk=LZjjn>meDx*j92@<6(z`-JxZ%8_%W=vR{mBl-UN`ude>Idf~G z!_fB~BokuDv{T%p&ND>fLJZh=Fj7~YX{GLlKd$b=TOF5^`%Re?(RHFhkb*FGWS{)` zX1dtV>FH!xOAXtqe}7h6?49L7{W)-JAH4UFw|?B3u=QwOyp-``tsG}%5wpvBrSFSD zyD~lq7U{EN7OZkgO8>NpIr}dzQzOqv%;Put5J7^L1b(UDFnGFY3PYDOsD0s^?>z8$ z+&CiZEt)}qeNdgS)Va?oqCV)0&jn%Qb_XeWOB4CoMYEsZDn%Vj*{$ggytI|u5Ex6g zwx`4b>H(2>RgN=yYJ5C_+BmXssol%?Sd+yEq}J|gP|!wp&guL^_;bT|!f81)ldOS( z1x8&;Y_~?3JpOaSl2^{@XXyup$#R@Q*)-iJpYs7|61$M*_8LL}$;xVA0GdDy;mF!S zsHblDBe@x(FD_WXp!DezTB7n^P}f2zpP{UN)6+i#zTHb*b}wHQZpN1Z`KGXQ>Fq&g zKm#EQuDjW|-I&^?!Y^Ys_oR4I@+yfm{zr~;0E|6t+QjXvX0qB3rP%7~z>o9A{FHyR zl1(jF=d2cBKiOLJH0~DwI_dI}@qV=Ki|x;Iyq-OG6eh#m3Wpt_l;u#agH&!Kyv*$j z-0M6r$w_$OYss6tyBX#jBtpfEm@Coa=5i&2-pm>N{T^(BvMhn5u0i?xT{{z&R9IPA z-?^)#63+J^_e~R9zxhH!bJqTmYb>+5eAnjkz6{@e@2oae$+|R*cn)}qW@yRdEKt;_ zui&~L0J%^W9Cmzye??by54SrWp@Tgx;f{In0!qVQU(MsNX=o5=fKiL}9`gzt-ye5tqmv^z?vA*UZ$?XD*2Juoid)@%&g z#J`&s?dk6o!s>>w;o|nJOR0Rmeff87ZUlhXbSpOJ_R+Ne!6w35=_F_ND|1f_P#M$GvKzr+%KWyZyre zvc;1;<_gNn{@*(r?zq0o-Swon%p}WVOc~2EExn$3KPoCPjb~SD8OzkEt3tw0Vn4&yOh`Bn4T$G&dSEv9R79BGBPf@YL8l zh1Nf)%$LuPFAL_qap+~Tj76!j2^fEuP~JO*KmT~}z3+#eb4&iguT$YhZi!N>6BvVc2jM%Wvzy8zE6bc3g)$eT9I-x)v zOjQT;(y>NG1pV7CzU7zK|E@=&2u0Q&Mg3jkk312_#lX2M+QXH#-#DusOhV7)cxg87 z&TMybwg@Hdx^iS4FvQFb-k4*+-tSbUF3Otak6WWoiE0LtKTqPF8zJ<{d_w@y?sX=H zx!|PHIxT~_sC`alD0=zr=67;=C*i28>8#lh-dPQPY0pyGfcN|+^5AJAwJTSSQ|wxD z^`pm*kdY8uQr4E(7Hcb87uOzl?I?qq0c@3^)7{iU|6T0JnR5M)mB^*@_%e@e?m^z> zCyq`maERUfZOhne?v%-H&5SQv!?(6R8c3#8Bwlot!t4(%va?VqBq$5AEF4HacH7r0 zbmc8q>v|QaicQc&)yIr1ZYFpOFpr3w)5YHmxe%NI58E#MiteeAGN^8krFY9(vm-Bn z9i*(P`W}KCv2cEJVRG)xeTo0D=061kK1%myEfQQ%1tSUI?FH+9vro+ zELK@mpHTU&y}jTPZ^2h0(Y567t|1B3HP7AO5T<-BrWl47Lp{e@TU&p``5nO*P0ej| zO8l7dNtW1dmdo<0-APe?Rx$RK3>pAN4TTl%Y`^#EW|uf_2YK~A{0fP;fZ+W_gOyrx zRcym<^vzwHe;kYxxoP_$`k+K`tJ;6;m|yP9O8M6I3vpx0h=L;i%8c^qyhHJg`T{XC z`|`i`+hO@PkGfAmQI$zM5_Ljf^3}xhsq|J8j`b>i zZs^zP9rc>j#XMkATY|zUywnL?OnKP&-+fLm_r^CS3stveAZ2CTt@kqyEbqpZqv?ME z^ho)b)I!1Qh4d;g-;7`$S|9t^4Pj$L7|MT)7X2*T*!$B=OD&sBPFT5uh5?VTZmTX6e3=H+KM z?z>XE6oB5jiWCZ$0c@4x$bMiRXwW19QSvBD7>zRnO#yZV+^@zt9`lmh|vO=$T3>YT2| z61q~OPmCr!it~Fj=GU@6!^<{m_zA6lmzDvlZ>CUINMb%_H7&8zavlBq5ju-OM>Cf_ z@OTA;N0?|iw6cyjAFD3~LAALKCM9`-9dD)H<>-cAL2)B?QN!lIB=F5$*_&Sq7ot#{ z3e0q{wXNKLEC&|x8&fXtF5e8JSbydpQov{4DK@(|v$CDKq!BA}I`vwOeLpn&g#m{h z)iHewJ)`wjZ^~<@r2kD^sx}tquRs(@pj0H!>z_h{Yl3)Gi0X}tYbNi>dLSaZ$&brU zlL|bu?+g}bp4Gk%;Wsk-T*Bwl+j@rWfXM#Z1grCPwh;O3^S{1?TkgT9r_NymGVzVn zoA2FRl0P;;>~S`1cZZzdWm$6!5Fn%vQtI2Wx%_8!NAsK|ms6N!^V0*RXR%Sqn1=m0 zze{jZv;Xg+|Lbvi6Ut>j>>XuH&PPjK4*CKZRS@s<-*>ij$5B+(!ZX&vyU8&p&%Q=u z{ZDirW&Ex}?V+99_|$uezj{jq@Ux9^^*=f<@~{nfiK3I;IV|G-wr#OA$-+B=_>Gri zeipjzsnYm>>`Bhnzm`X#aCV32oi7tq=yDD-^!sH_Py|nKjp)UBc+X1Co{UD8{XAZEaSDXN&fKc|jWhU!*I5V?-3X z!YYB%A&D?QqucH<>IXA52~SEfQ6CV_4WkYWa7Nck>SBhDK$G^JZBi6_o5z@&n-giI zYwU^%IwxV&Z9Ja>PQgV`Lg{svvW!noUP)~n>DOsU-ld6pf>orL4sHELrqh)Tadrn; zr?Git>85(NAUuX>N+Wo(Y^C{I#Fp`tKBJw*9EP4%hB@}Q)3f2+TMQdNryFHMOqG6g z_Km*heGmI8PNewSzb3_j-oh1DRe&NKvsuIm)BXK#Rw@P>=vm`oJ+U%jR1N4o22Lnz z=Q*yx;w6FFYz8hRt2DpN6{Jm8wsq?)k#=5bC4Lqjy%D|loa)PHUes^^l(&}%r`l|tc)*9 zqWBw%Ft!o{8Q;Hu7lSBeLPAm?w>|=gkfbX892CGQ|0=#;VTPhA`s~-;+pV>Y=Xd4c zi*1RS*{tIJLt%(hwA$`NHoF6>Av%SyTMI)B(?d&D8srm}b`C6RBn|Jr(igO`CUwzy zVB^kcYhm6+;^R?H%_|q%RUm&zVxmPPq_B;_C_0Jx$Mzn&L0s65r1>wh}4N% z0C)rSupRqOuvg{Wm$~TNp6#%q1uYs_+>YorE&IYr)ohH=l4FwPTio2X?WmuND}S#? zooLn$m8rM45|-}iMt-2brqzI%-|CoeuZK2TBnsAYd(@`hR&(2o{)m0GL(Y=uvx?Ie zX$xAJE*h9oJ{JqX#bOR)@)%J)uKS1O%|vy95SxsZ!hAkDGWAJ)Wy(t(x2D=4k3G9X zIn^?olKKtoFbBOpvJ6S0c;k71EMnm>+6oLMU-a)GhN)R=G-U1^kU{MyAwITD;OWd$ z1Idh_eX8Gn(N*ES9J8?pQd-8|NMt--|F*g5Hq{E=>0tR&S(_JzFq9g}WV__$3*lG1 z$}Ket3^SkQW*U|OB(fb&wMCi}l@i-evOPjv9|U+bh0k~JoqM8FuQ!Y2X~Mvy^64j~ z5D>sb@o?DqVbt(i^2^Pxki)A1+wva|9~>e-F2d$;B08?N`oEy8LcZ0haq`t6H&#ta zx!K8B(sc`DaD zNXF-BrRvRzNZcnVVBbN{Yh+~|H0NCS7O&*zgv^N=NUwh>YiFHem17B*DPQD;IQ`QD z8|ERDyD`ZXwS+vwOoar&A{KEz<9P*!;0v-^%gO;YkNOLZDR0LTX*p2k-G~PWij%8~ zP1>sBeSce2@c{aKfRim z*%P$-$LQ_&5mOQ(`N}X;RT|w60q-EEZ!yJOqrHcP2@ip#)Kx4AnHFfRQcKafzNGr>u^{$ zQn=^2$DUKy&SRG4)9Rgok;xHmfgbP_26Yx2>Te=MMP7WQ_wNZAyks%fxeNBV4wia7 z`RSv~i4#yyOhO}zPXUqteQN_n&t5H{(Q*W04pYW0@d3)X@(^nDc{>+!G1ZhO#HPVJ zDp|0nXXAp%M4SkI#dvoJFi)QL4O?)KHbVoj%o;Gs6+VNZh(yfZ9rYK(;qc3fBscoa zx09S@yjpEq#s8%0=oO+NgP{;cv@f&mz5|JwBlM>tDLLNBo71STCfsuHQ}=<`Wj9Lf z&l8`dL4E6j9%Y>D#sQ}lFuyh^e@#(%8N{E;1m>30;@W$4CU4GVpQ-$PR0L zCs}!(f_DqZ*aN|k?+cTm@SsMJ43yW#+4qf<@!W?gza6zD?wv{pz~GDphoi&4M$tS- zPY&S9qbP2ka4TEs&p2hy$nr--07B(%GwKC6yGK3yLl1A7mcl z9%Sjf?O&ea&k8S2+5z)sh%U3@Q)SSSe0)BY`6?4#NZ`Eytk@w$z6+F>0{VSP#G1qS zSizbO)Hh#d-@Av^Cu8{-w#_lJueRfi!F5As@57wq_RCYO4}#@5;q7ixLp}(Z4`SA& zYKyRB2GC~oK1z}tm(*~{O3ipZ@vHwNb#${$uJrWv-9m9|58lf0h~0F+Tu6xh4~yahlowRqAJe1$Q$Lf?KYRRvXXD!30o6 zPhu^*Vxop)KPp86=Bx!#GrE|2lS(LiRSc8v9G-C!^}h%6Bw{-;WQF!ZnF!+(}rn zCa5J)Qtr9lNV?$d;vVEO)3dJ?Q8IxXd}4mtH=%^#&5w|EOTk^f634NkAm9=>*y&o- z*P%4>&}ez4Y^LG_ebpBDKZxWw9^QiE+v8f4IVmnDpTJVj1LjFriB?tLq!5MM_5bbM zt2uY7hSON;cel)j({Jul^EfMnX!5Ilq>nfiEZ<_BwEo+Q*k1$$bGxxOg|Yy93Hjb& zJpTqZfDJ@(A%>~76MTXxEz`tIc-sbZ@(|>HNoE^KT0~`>Gg0K%F$ZIq%q-fGV|ik* zxe!f^0dIrg^Z4T~N#7+rY7;L*DI$TpMZjJ#AK?6qJTcGh}J=+w&k5;o_E zCXOm|BKG}1ujcThjngH|esCL+#6~wk1=Bq4tLoBEp6c7oc2+GAeLbdAmI;5iz^W z!**C}7yx`L2oqJAPU@+tp%EIYf<&YntjNcxT|qW22)Xd@Zd|e$+lP^yJDLk{OA??{ z4~1g`q8$d`6E`I;oW`9fg7yl`pFN)td7&CSxKw;{zwgPZMl|0Wd$Z!o;mENVgntVQ zk&hqqdDU8j88e4t$cA_cKU>Lh@@=y>f4w^JVwxA%j^b`n|F_a4r;iX97UVcXA%2YB z{)+VUib4X`bCN@JZr)tBND(JGsk{TxqhwC(rC0tc@3w4lldLk z+GLAT3qlKYpfr3%*%JAP$oJG=#Xq9Tb|`%(k3f>@fe(upKYcAw| zBczUjvwK5DJRN1@onK8vB$Rwt=F`jqygzK*4nQMyI}&M2*2-R70thk69>`Yxcw}Wy3BsXG~BkjlG2T$ zN!8Xptw_~FkZSG2$w;87zkRn^_ZkzlhMn*$m!Y3|Et#Wxd*J2MF8==hQIQ$rd}wYf z9C!Ee=r(NlDWus&rQEF3Te*-=FlF#s*dJ(a75tx5NT}@hz_{|3d_@K1K>|3Zc;Z(O zTsh1y5?}jbnF9`{mmGjijKIv{gb#N(o~8pxK{`)&d+E2in3b=v?7`l{9skp^V&48Uk@AOYx6Q6 zW1&RQ`Wxt0^<%S#nGNWYX4bcO5>iD47zgx5YV_4T%nCvkiF;1dkjQ8e^P>KI5O!bkD|oHwAa@)OnXye0AUmJZNODD@)%Lvk~0kRdWVa?~9RDZh#Z z{u{LPAL9SeXfbxX(1y4mftJ3$c;N1%vsb@)i<6boS;#L84?W^GZjTEawm?b2q}rbfD({b&|+H`rhPISI)=B9jgk z`)`oGgCm$XK5ua(9)9c`)7A6^<@!-CDV&UWhMI*#u(6sZreQtm+%&cFUy`sz{4jj5CqW}9 zkZIae_m%G@Uquu(dhg90`48V2Ee1le1?Ralu=hJRLX($}LMX7(TpvNNCORt0C%oR7 zGJX}ClV(t@4SyZa6HZuKfqG~KijKuHZnjp=Ryb!4@<+7Tj>c2F&S?!lrzz`WpS)#n zfb*1_?Pw~9h$-Vh!TaSUx-CsGodxN<4XWTiNMioXeVVE|N0_fck2ZSe90w#Z@ZEgy z#`x3db+9gHX5^b&w=pko1Z5(S==b47U5T@FmlO(JBIA~YgEJ0@C_*?>JE9_f_B=B` z!ayF`d7XE0Gr!F4J~ zl%{+h?=t^?@z?!ngX89a$k}Pq9K32BL3Fh)U^%C(gZ~c$PN{AH literal 0 HcmV?d00001 diff --git a/point.py b/point.py new file mode 100644 index 0000000..8318676 --- /dev/null +++ b/point.py @@ -0,0 +1,367 @@ +import random +import math +import numpy as np +import scipy.spatial as ss +import pysal as ps + + +class Point: + """ + For whatever reason, cannot get import to work, just moved functionality + into this file instead. + """ + def __init__(self,x = 0,y = 0,mark = ""): + self.x = x + self.y = y + self.mark = mark + + def __eq__(self, other): + return self.x == other.x and self.y == other.y + + def __gt__(self, other): + direction = "" + if self.y > other.y: + direction += "N" + elif self.y == other.y: + direction += "-" + else: + direction += "S" + if self.x > other.x: + direction += "E" + elif self.x == other.y: + direction += "-" + else: + direction += "W" + + return direction + + def __neg__(self): + return Point(-self.x,-self.y,self.mark) + + def shift_point(self,x_move,y_move): + this_point = (self.x,self.y) + self.x += x_move + self.y += y_move + + """ + Made redundant by __eq__ + def coincident(self, check_point): + if check_point.x == self.x and check_point.y == self.y: + return True + else: + return False + """ + + +class PointPattern: + def __init__(self): + self.set_of_points = [] + + def avg_nearest_neighbor_dist(self,mark): + average_nearest_neighbor_distance(self.set_of_points, mark) + + def num_coincident_points(self): + coincident_points = 0 + len_list = len(self.set_of_points) + for i in range(len_list): + if i == len_list-1: + break + for j in range(len_list+1): + if self.set_of_points[i] == self.set_of_points[j]: + coincident_points += 1 + + return coincident_points + + def list_marks(self): + mark_list = [] + len_list = len(self.set_of_points) + for i in range(len_list): + if not mark_list: + mark_list.append(self.set_of_points[i].mark) + elif self.set_of_points[i].mark not in mark_list: + mark_list.append(self.set_of_points[i].mark) + + return mark_list + + def list_mark_subsets(self): + mark_list = PointPattern.list_marks(self) + mark_count = [] + sub_set = [] + for i in range(len(mark_list)): + sub_set = [] + for j in range(len(self.set_of_points)): + if mark_list[i] == self.set_of_points[j].mark: + sub_set.append(self.set_of_points[j]) + mark_count.append(sub_set) + + return mark_count + + def create_random_points(self, n=100, marks = []): + if not marks: + self.set_of_points = create_random_unmarked_points(n) + else: + self.set_of_points = create_random_marked_points(n,marks) + + def k_realizations(self,k = 99): + return permutations(k,n = 100) + + def critical_points(self,realizations): + return find_crit_points(realizations) + + def compute_g(self, min_dist): + gs = 0 + len_list = len(self.set_of_points) + all_pts_min_dists = [] + for i in range(len_list): + local_nn = 0 + for j in range(len_list): + if i != j: + new_distance = euclidean_distance(self.set_of_points[i],self.set_of_points[j]) + if local_nn == 0: + local_nn = new_distance + elif new_distance < local_nn: + local_nn = new_distance + + all_pts_min_dists.append(local_nn) + + for k in range(len(all_pts_min_dists)): + if all_pts_min_dists[k]<=min_dist: + gs += 1 + + return gs + """ + Assignment 8 stuff + """ + + def nearest_neighbor_kdtree(self, mark=""): + buffer = build_np_array(self.set_of_points, mark) + kdtree = ss.KDTree(buffer) + calc_distances = [] + values = [] + for i in buffer: + nn_distance, nn = kdtree.query(i, k=2) + #do we remove the first one since it is the coincident? + calc_distances.append(nn_distance[1]) + values.append(nn) + distances = np.array(calc_distances) + return distances + + def nn_kdtree_avg(self, mark=""): + return np.mean(self.nearest_neighbor_kdtree(mark)) + + def np_compute_g(self, min_dist, mark=""): + buffer = build_np_array(self.set_of_points, mark) + g = 0 + n = len(self.set_of_points) + list_of_min_dists = [] + for i in range(len(self.set_of_points)): + local_nn = 0 + for j in range(len(self.set_of_points)): + if i != j: + new_dist = ss.distance.euclidean(buffer[i],buffer[j]) + if local_nn == 0: + local_nn = new_dist + elif new_dist < local_nn: + local_nn = new_dist + list_of_min_dists.append(local_nn) + + for k in range(len(list_of_min_dists)): + if list_of_min_dists[k] <= min_dist: + g += 1 + + return g/n + + def np_gen_random_points(self, n = 100, dom_spec = False): + lop = [] + if dom_spec: + lx,ly,mx,my = minimum_bounding_rectangle(self.set_of_points) + for i in range(n): + x = np.random.uniform(lx, mx) + y = np.random.uniform(ly, my) + n_p = Point(x,y) + lop.append(n_p) + else: + for i in range(n): + tuples = np.random.uniform(0,1,(1,2)) + n_p = Point(tuples[0][0],tuples[0][1]) + lop.append(n_p) + + return lop + +""" +Assignment_08 +""" + + +def build_np_array(points, mark=""): + if not points: + return "No Points in List" + point_buffer = [] + + if mark == "": + for i in range(len(points)): + new_tuple = [points[i].x,points[i].y] + point_buffer.append(new_tuple) + + else: + for i in range(len(points)): + if points[i].mark == mark: + new_tuple = [points[i].x,points[i].y] + point_buffer.append(new_tuple) + + return np.array(point_buffer) + + +def nn_kdtree(points): + tree = ss.KDTree(points) + distances = [] + values = [] + for i in points: + nn_distance, nn = tree.query(i, k=2) + distances.append(nn_distance) + values.append(nn) + + return distances,values + + +def np_create_rand_points(self, n, specified): + lop = [] + if not specified: + for i in range(n): + tup = np.random.uniform(0,1,(1,2)) + point_n = Point(tup[0],tup[1]) + lop.append(point_n) + else: + minimum_bounding_rectangle(self.set_of_points) + + return lop + + +""" +Old Assignment +""" + + +def create_random_marked_points(n, marks = []): + list_of_tuples = [(random.uniform(0,1), random.uniform(0,1)) for i in range(n)] + list_of_marks = [random.choice(marks) for i in range(n)] + list_of_points = [] + for j in range(n): + new_point = Point(list_of_tuples[j][0],list_of_tuples[j][1],list_of_marks[j]) + list_of_points.append(new_point) + + return list_of_points + + +def create_random_unmarked_points(n): + list_of_tuples = [(random.uniform(0,1), random.uniform(0,1)) for i in range(n)] + list_of_points = [] + for j in range(n): + new_point = Point(list_of_tuples[j][0],list_of_tuples[j][1], "") + list_of_points.append(new_point) + + return list_of_points + + +def euclidean_distance(a, b): + distance = math.sqrt((a.x - b.x)**2 + (a.y - b.y)**2) + return distance + + +def average_nearest_neighbor_distance(points, mark=""): + mean_d = 0 + total = 0 + local_nn = 0 + num_of_points = len(points) + + if not mark: + for i in range(num_of_points): + local_nn = 0 + for j in range(num_of_points): + if i != j: + new_distance = euclidean_distance(points[i],points[j]) + if local_nn == 0: + local_nn = new_distance + elif new_distance < local_nn: + local_nn = new_distance + + total += local_nn + + else: + for i in range(num_of_points): + local_nn = 0 + for j in range(num_of_points): + if i != j and points[i].mark == points[j].mark: + new_distance = euclidean_distance(points[i],points[j]) + if local_nn == 0: + local_nn = new_distance + elif new_distance < local_nn: + local_nn = new_distance + + total += local_nn + + mean_d = total/num_of_points + + return mean_d + + +def permutations(p = 99, n = 100): + list_means = [] + + for i in range(p): + marks = ["elf", "dwarf", "human", "orc"] + rand_points = create_random_marked_points(n, marks) + newMean = average_nearest_neighbor_distance(rand_points) + list_means.append(newMean) + + return list_means + + +def find_crit_points(list_means): + entries = list_means + maxEntry = 0 + minEntry = 2 + for i in range(len(list_means)): + if entries[i] > maxEntry: + maxEntry = entries[i] + if entries[i] < minEntry: + minEntry = entries[i] + + return minEntry,maxEntry + + +def crit_point_check(minEntry, maxEntry, observed): + if observed < minEntry or observed > maxEntry: + return True + else: + return False + +def minimum_bounding_rectangle(points): + """ + Given a set of points, compute the minimum bounding rectangle. + + Parameters + ---------- + points : list + A list of points in the form (x,y) + + Returns + ------- + : list + Corners of the MBR in the form [xmin, ymin, xmax, ymax] + """ + mbr = [0,0,0,0] + numOfPoints = len(points) + for i in range(numOfPoints): + #Check for min and max x + if points[i][0] < mbr[0]: + mbr[0] = points[i][0] + if points[i][0] > mbr[2]: + mbr[2] = points[i][0] + #Check for min and max y + if points[i][1] < mbr[1]: + mbr[1] = points[i][1] + if points[i][1] > mbr[3]: + mbr[3] = points[i][1] + + return mbr \ No newline at end of file diff --git a/view.py b/view.py new file mode 100644 index 0000000..a3b9574 --- /dev/null +++ b/view.py @@ -0,0 +1,36 @@ +import sys +from PyQt4 import QtGui + + +class Example(QtGui.QMainWindow): + + def __init__(self): + super(Example, self).__init__() + + self.initUI() + + + def initUI(self): + + exitAction = QtGui.QAction(QtGui.QIcon('exit.png'), 'Exit', self) + exitAction.setShortcut('Ctrl+Q') + exitAction.triggered.connect(QtGui.qApp.quit) + + self.toolbar = self.addToolBar('Exit') + self.toolbar.addAction(exitAction) + + self.setGeometry(300, 300, 300, 200) + self.setWindowTitle('Assignment_09') + self.setWindowIcon(QtGui.QIcon('globe.png')) + self.show() + + +def main(): + + app = QtGui.QApplication(sys.argv) + ex = Example() + sys.exit(app.exec_()) + + +if __name__ == '__main__': + main() \ No newline at end of file