From 923dd2e2a5e8a72d3567d9a78dc759ec2db7dd41 Mon Sep 17 00:00:00 2001 From: Citlali del Rey Date: Tue, 19 Mar 2024 10:58:08 -0700 Subject: [PATCH] New work --- .gitignore | 303 ++++++++++++++++++++++++++ Assignment2/SolutionPA2.hs | 100 ++++++--- Assignment2/report2.pdf | Bin 0 -> 72233 bytes Assignment2/report2.tex | 421 +++++++++++++++++++++++++++++++++++++ Week8/lecture1.hs | 9 + 5 files changed, 801 insertions(+), 32 deletions(-) create mode 100644 Assignment2/report2.pdf create mode 100644 Assignment2/report2.tex create mode 100644 Week8/lecture1.hs diff --git a/.gitignore b/.gitignore index 5cb2b23..aa4ecbe 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,306 @@ a.out .DS_Store **/.DS_Store +# TeX +## Core latex/pdflatex auxiliary files: +*.aux +*.lof +*.log +*.lot +*.fls +*.out +*.toc +*.fmt +*.fot +*.cb +*.cb2 +.*.lb + +## Intermediate documents: +*.dvi +*.xdv +*-converted-to.* +# these rules might exclude image files for figures etc. +# *.ps +# *.eps +# *.pdf + +## Generated if empty string is given at "Please type another file name for output:" +.pdf + +## Bibliography auxiliary files (bibtex/biblatex/biber): +*.bbl +*.bcf +*.blg +*-blx.aux +*-blx.bib +*.run.xml + +## Build tool auxiliary files: +*.fdb_latexmk +*.synctex +*.synctex(busy) +*.synctex.gz +*.synctex.gz(busy) +*.pdfsync + +## Build tool directories for auxiliary files +# latexrun +latex.out/ + +## Auxiliary and intermediate files from other packages: +# algorithms +*.alg +*.loa + +# achemso +acs-*.bib + +# amsthm +*.thm + +# beamer +*.nav +*.pre +*.snm +*.vrb + +# changes +*.soc + +# comment +*.cut + +# cprotect +*.cpt + +# elsarticle (documentclass of Elsevier journals) +*.spl + +# endnotes +*.ent + +# fixme +*.lox + +# feynmf/feynmp +*.mf +*.mp +*.t[1-9] +*.t[1-9][0-9] +*.tfm + +#(r)(e)ledmac/(r)(e)ledpar +*.end +*.?end +*.[1-9] +*.[1-9][0-9] +*.[1-9][0-9][0-9] +*.[1-9]R +*.[1-9][0-9]R +*.[1-9][0-9][0-9]R +*.eledsec[1-9] +*.eledsec[1-9]R +*.eledsec[1-9][0-9] +*.eledsec[1-9][0-9]R +*.eledsec[1-9][0-9][0-9] +*.eledsec[1-9][0-9][0-9]R + +# glossaries +*.acn +*.acr +*.glg +*.glo +*.gls +*.glsdefs +*.lzo +*.lzs +*.slg +*.slo +*.sls + +# uncomment this for glossaries-extra (will ignore makeindex's style files!) +# *.ist + +# gnuplot +*.gnuplot +*.table + +# gnuplottex +*-gnuplottex-* + +# gregoriotex +*.gaux +*.glog +*.gtex + +# htlatex +*.4ct +*.4tc +*.idv +*.lg +*.trc +*.xref + +# hyperref +*.brf + +# knitr +*-concordance.tex +# TODO Uncomment the next line if you use knitr and want to ignore its generated tikz files +# *.tikz +*-tikzDictionary + +# listings +*.lol + +# luatexja-ruby +*.ltjruby + +# makeidx +*.idx +*.ilg +*.ind + +# minitoc +*.maf +*.mlf +*.mlt +*.mtc[0-9]* +*.slf[0-9]* +*.slt[0-9]* +*.stc[0-9]* + +# minted +_minted* +*.pyg + +# morewrites +*.mw + +# newpax +*.newpax + +# nomencl +*.nlg +*.nlo +*.nls + +# pax +*.pax + +# pdfpcnotes +*.pdfpc + +# sagetex +*.sagetex.sage +*.sagetex.py +*.sagetex.scmd + +# scrwfile +*.wrt + +# svg +svg-inkscape/ + +# sympy +*.sout +*.sympy +sympy-plots-for-*.tex/ + +# pdfcomment +*.upa +*.upb + +# pythontex +*.pytxcode +pythontex-files-*/ + +# tcolorbox +*.listing + +# thmtools +*.loe + +# TikZ & PGF +*.dpth +*.md5 +*.auxlock + +# titletoc +*.ptc + +# todonotes +*.tdo + +# vhistory +*.hst +*.ver + +# easy-todo +*.lod + +# xcolor +*.xcp + +# xmpincl +*.xmpi + +# xindy +*.xdy + +# xypic precompiled matrices and outlines +*.xyc +*.xyd + +# endfloat +*.ttt +*.fff + +# Latexian +TSWLatexianTemp* + +## Editors: +# WinEdt +*.bak +*.sav + +# Texpad +.texpadtmp + +# LyX +*.lyx~ + +# Kile +*.backup + +# gummi +.*.swp + +# KBibTeX +*~[0-9]* + +# TeXnicCenter +*.tps + +# auto folder when using emacs and auctex +./auto/* +*.el + +# expex forward references with \gathertags +*-tags.tex + +# standalone packages +*.sta + +# Makeindex log files +*.lpz + +# xwatermark package +*.xwm + +# REVTeX puts footnotes in the bibliography by default, unless the nofootinbib +# option is specified. Footnotes are the stored in a file with suffix Notes.bib. +# Uncomment the next line to have this generated file ignored. +#*Notes.bib + diff --git a/Assignment2/SolutionPA2.hs b/Assignment2/SolutionPA2.hs index c9f427b..eb92de1 100644 --- a/Assignment2/SolutionPA2.hs +++ b/Assignment2/SolutionPA2.hs @@ -136,11 +136,12 @@ myDouble n = foldr (+) 0 [n,n] -- >>> [1,4,3] doubleEveryOther :: [Int] -> [Int] --- I don't like this code. It doesn't feel very Haskell. --- Use list comprehension to get all the indices of xs. --- Then if the index is odd, double the value. --- This will double every other starting with the 2nd digit. -doubleEveryOther xs = [if myMod i 2 == 0 then xs !! i else myDouble (xs!!i) | i <- [0..(length xs) - 1]] +-- Base cases. +doubleEveryOther [] = [] +doubleEveryOther [x] = [x] +-- In the recursive case, just multiply the 2nd element from the start. +-- Then doubleEveryOther on the rest of the list. +doubleEveryOther (x:y:xs) = x : myDouble y : doubleEveryOther xs --mySquare --Write your own my square function using foldr @@ -171,9 +172,8 @@ mySquare n = foldr (*) 1 [n,n] -- 30 sqSum :: [Int] -> Int --- We can use foldr and list comprehension to add evertything in a new --- list where mySquare was applied (map). -sqSum ns = foldr (+) 0 [mySquare x | x <- ns] +-- The lambda function should square and then add to accumulator. +sqSum = foldr (\x acc -> mySquare x + acc) 0 --sumDigits is to add the sum of all the number inside the list that is already turn into single digit (10 pts) @@ -185,11 +185,9 @@ sqSum ns = foldr (+) 0 [mySquare x | x <- ns] -- >>> 10 sumDigits :: [Int] -> Int --- We can use a double list comprehension combined with foldr. --- Take every n from ns. --- Find the digits, and then get every digit x. --- Combine it all into a list and apply foldr. -sumDigits ns = foldr (+) 0 [x | n <- ns, x <- toDigit n] +-- The lambda will take the sum of the list of digits of each element +-- and add it to the accumulator. +sumDigits = foldr (\x acc -> acc + (sumList $ toDigit x)) 0 -- sepConcat will concatenate the defined seperator to a list of string. If the list is empty despite the defined seperator return empty string. -- @@ -203,14 +201,10 @@ sumDigits ns = foldr (+) 0 [x | n <- ns, x <- toDigit n] -- >>> "a#b#c#d#e" sepConcat :: String -> [String] -> String --- Base case 1, when the list is empty. -sepConcat _ [] = [] --- Pattern match a list with only one element. --- When we reach this case, we don't add separator to the end. -sepConcat _ (t:[]) = t --- On the recursive case, we patten match the first element and the rest --- of the list. We then concat it with the separator and recurse. -sepConcat sep (t:ts) = t ++ sep ++ sepConcat sep ts +-- The lambda in foldR will prepend the strings+separator to the accumulator but +-- skip the separator in the beginning so that the string doesn't end in +-- a separator. +sepConcat sep = foldr (\x acc -> x ++ if acc == [] then acc else sep ++ acc) "" -- Part C: Credit Card problem @@ -290,7 +284,7 @@ mergeList axs@( px@(_,x) : xs) ays@( py@(_,y) : ys) -- If x <= y, the first pair ps should go first. -- Then we can merge the rest of xs with all of ays. | x <= y = px : mergeList xs ays --- Otherwise, we can just call mergeList again. +-- Otherwise, we can just call mergeList again and prepend py. | otherwise = py : mergeList axs ys @@ -341,8 +335,6 @@ type BigInt = [Int] clone :: a -> Int -> [a] -- Base case clone _ 0 = [] --- List with just x -clone x 1 = x : [] -- Create a list with [x], then recursive call function. clone x n = x : clone x (n-1) @@ -383,8 +375,6 @@ padZero xs ys | xl > yl = (xs, clonez (xl-yl) ++ ys) -- >>> [] removeZero :: BigInt -> BigInt --- Base case -removeZero [] = [] -- If we can pattern match a zero, recurse with rest of list. removeZero (0:xs) = removeZero xs -- Otherwise just return it. @@ -399,8 +389,22 @@ removeZero xs = xs -- bigAdd [9, 9, 9, 9] [9, 9, 9] -- >>> [1, 0, 9, 9, 8] ---bigAdd :: BigInt -> BigInt -> BigInt -bigAdd _ _ = "not implemented" +-- Takes reverse. +-- Base case, we use n as the carry bit, and so we just leave it at the +-- end. +bigAdd' [] [] n = [n] +-- For recursion, we use mod with the sum to get the digit, +-- and then we recurse with the carry bit being the integer division of +-- 10. +bigAdd' (x:xs) (y:ys) n = (myMod sum 10) : bigAdd' xs ys (div sum 10) + where sum = x+y+n + +bigAdd :: BigInt -> BigInt -> BigInt +-- We use bigAdd' after we zero-pad the incoming bigInts. +-- Since bigAdd' wants reversed, we reverse the lists. We finally have +-- to reverse the list at the end again. +bigAdd xs ys = removeZero $ reverseList $ bigAdd' (reverseList zxs) (reverseList zys) 0 + where (zxs,zys) = padZero xs ys -- `mulByDigit i n` returns the result of multiplying @@ -409,8 +413,20 @@ bigAdd _ _ = "not implemented" -- mulByDigit 9 [9,9,9,9] -- >>> [8,9,9,9,1] ---mulByDigit :: Int -> BigInt -> BigInt -mulByDigit _ _ = "not implemented" +-- Takes reverse. + +-- Base case will just return the carry digits. +digMul' [] _ n = reverseList $ toDigit n +-- For recursion, we use mod with the sum to get the digit, +-- and then we recurse with the carry-over being the integer division of +-- 10, where the sum is the digit in the list * q, then added the +-- carry-over. +digMul' (x:xs) q n = (myMod sum 10) : digMul' xs q (div sum 10) + where sum = (x*q)+n + +-- Just delegate to digMul' after reversing the list. +mulByDigit :: Int -> BigInt -> BigInt +mulByDigit q xs = removeZero $ reverseList $ digMul' (reverseList xs) q 0 -- `bigMul n1 n2` returns the `BigInt` representing the @@ -422,7 +438,27 @@ mulByDigit _ _ = "not implemented" -- bigMul [9,9,9,9,9] [9,9,9,9,9] -- >>> [9,9,9,9,8,0,0,0,0,1] ---bigMul :: BigInt -> BigInt -> BigInt -bigMul _ _ = "not implemented" +-- Long multiply algorithm: +-- For each digit in ys, multiply xs by it. +-- Based on the index, shift the whole thing by the number of powers of +-- 10. +-- Then, just bigSum them all. + +-- Helper function. +-- Like sumList but for bigInts. +-- So megaSum. +megaSum :: [BigInt] -> BigInt +megaSum [] = [0] +megaSum (x:xs) = bigAdd x $ megaSum xs + +bigMul :: BigInt -> BigInt -> BigInt +-- Implementation: use megaSum on a list of bigInts. +-- We use zip with [0..] and ys to get tuples of the index and the +-- value. +-- Then, we can use mulByDigit to multiply xs by the digit of y, then +-- use the index to add the correct number of zeros to the end. +-- Finally the megaSum adds all of the resulting bigInts. +bigMul xs ys = megaSum [mulByDigit q xs ++ clone 0 i | (i,q) <- zip [0..] rys] + where rys = reverseList ys diff --git a/Assignment2/report2.pdf b/Assignment2/report2.pdf new file mode 100644 index 0000000000000000000000000000000000000000..b6cf9a55143064beedc029a78c2f3a4ec88bb789 GIT binary patch literal 72233 zcma(1Ly#~`u(biUZQHhO+qP}ncK6%1ZQHhO+va>XW@h!@#jQnEM%1n%D&sjP52=EP z7%d|mD-`MU%E0o-`uy-H6ej@#fxVFx6b}ypy_ltqi>cFpr;VYDsfekuy@@FSy^N`y zxr+q>6DtcN0Usa1|93$-yEvH|+Cq73j%aDxlXSrPz15ZTBh~0oBewHwJgy&Z5HQ+W6Sm>#CAp@@1<2Thqzv^if8i8J(O-*sH{tK5bFw()5%u zbt{Fnts8!hRuMsFzDaIb7PshSyg{ClQ`M8zD$S!|@Qt-0(W0)J3B!>5@_o8T@l~ef zBAdw?sDK!-mo;s~5w?LbFVWd_wz7)oE~F~pGi7PTL|4;7WxrDg4W3@AxWfp)1jXl| z7;9Oaf$1!BqFLQGqTG^g-(r81VDwjoye`ijvf1LIhD+#p0taPtN6Kk=vd(c0^bVcuAbAoDmSV-|$aJ6UxoZ z$mvAhUIz-H1&f*3H20`gp@dTbO;>-txjYRM~m_);z|u`$pm5ajtK| zGC9g4$x)G2njD`ZHz{Ol1>a4Q!di-uzHWNFiIC)BTXw-vClhUCzLC`|O(x_SWYAL^ z#NxMm+B`~0!&&8hov>BQ@kUYVM>$X+P=ZK-Fs_36`3PdUi&7KcsS}7ivIuvYM$*NLNtW3V%;p1Z|H5Z6o?^Gwk^Gci}nN~oB;13M}c$c)umj!-C%v?wG& zC9sZ<;8;u>X=KSQT)2L=C9rT4#{~ik_@yYnnmc3N=t6Poc>(uA)dW_~!(i4I%DaX{ za>jUrb!0+I*7uj3_~?5o>oiG3x4k#hV~GzNEwb{mNQic0XOgvS7*D=|fboq2XVP7# z)fFy%MYHwB(`3mOrvt`-gKMMjAb-qcohF2_<NwV6- zuUfe6Cm3oxcrCAwUMyByVRs>(#i}fah)_~naAduur78*iC}q=4g$=y0Q<)>nG?7p4 zF(QP>=uOu4BJ60g!I7>7$^2;(6CUSlrT7a@q2D6{_ z3-%NB-$p7IXFe1T3n6P4fYvJ~Ez~_6Qyq*4cMIZ{M-R*a@M;)n&JN@boWKQuH))Bq zUmS6+N_|n#E@t1k2KzZuNQ;Aq=9F*Xlj)60PV;>K`i<4V)y@Ve0SaMtV85>`^lX(y z@bUZ4CbJqf!P+*WxA-CUK1#O~gtro_SL`eZ1c#!oO~u&{p6b(`pUFH+!Hk)80E`uSxCtUTaYDdou+-)Rjc#-t^S40zM;GQ~@Z4poA$$c4+ zaV_gXyBN<+RKoI^nl6q?fB__K44h?Mcxo#)@cd(kOO@TTuh&^bAibQzuH?Np*XD~@ z-xM^)9`sGcmdkdJvFeJIXtOEYr>9+No2s3edTStAvZbBWHJPN*9@)DC5SU&;Nclbe-G-Hz#`2VCrjEs{Zgpu85bjyFjGOE+o%v)j&geO+*L zvJVvoyE!DS5DuDJ!E}8yP_$6b8pY1K8rI%Okt3I%EsE*r%R6^IPh=H5_1^4$GX@?u zA$kXHIUcU#OgCv4jIlRsqNeyb=Rxj85P(iCgxwJ(+Ge4$M5Lv-5lQ)G&p~GNf*bfOSS72A3)ycIthw{gWZdBxX@3MQ6Qw-CS`<-`-Sro zNR3OLFSt*BH&r`KS1xxUH-po^#j9}oyAeBMaExC!056;TPav}57GWjy#E`ES2y(%6 zhHIlYWzhxW^^=o>J81mf%6-SLlc}M2{)K-0i;qAlYw_2YJEj-t0^vHJN$9`EpM!%p zW<-e%?tg;_dZdNyRZ23@kjv#lA@Bn}+GTK6Y*2 z>_Xa&lj4UtXe8{n_7fetJv?(2lRBr|o~YYwekr_V?0F;pSQPl@C5}OT7qBz9qUaP6 zW^=H7^z(-~I3#LOBcp*n#GC+LO$_2M<y1~E{yM_vDY38q`GhqD+5mr4&SmV%FppHVU0z>~o{y+fF3_gmlgwV> zG82?-w=oApOq#MUf^M%FkF|X7RFh~anw0+i{MA!|km`T=%=grjmyXvzj25xRZ2o>Q zCceCoqtR^sneGRos|P~U2=B!f_gFR8l6(SXD}{7+6okr!mdS5LV`kRaWjtkGl3G?7DtX`TcvI-bABD+G z29O_|pJ`LeXR9!8H@;WfnWxI!ky3Zg{zh7|jk>Rw`jVW|UV<@cPoXnXY9GBsHfA1Gh zb${PuVf6m|^9NG`;r3Z`Wo_Z`bz-nFh}5J@LtFIlFm>~Ru%r9wm@I9>N*KGnaCvaa zOk$M02ju?WVoFiONy=1u6eqXJNAWOuN&LU>uexTTKGXdai-Z2T@C7Qe9pQUvqVv($ZB48$3?V6dXLUnK8@%(Bh;Pjf#mp z9%dXlL@`bC>EkngrIT0{uwBCywcEnmRe5fbNw*&bH6@#mE$irNt8>p$NhH2b%^G>M z>LxkTWKB{WZ98h*NgW=#9>-q{j|pXtL0_te)fd&GI3BBy%j5S#1qe5D%6w(iua{p7 zeIbt4?uV$0j2J|qimsRE0Me3~l<6tOg~1)ng8hpGu2CkM?UG-`7$ixWSV`?Y1TFAH zlWu^}qIYSm**fbXb}6W$8M5ygkZ(JYUChS3+LK8G#SQJo8Ndp+a(_ z|IM#*kK6p^)QmDowy;KWf78Yxukw1F9s+u4>+pLvoC~&59 z)*lR$gz%DoT-+SYiTPAOipzg~zZ@*ZdmNa5f7s=NRAc_WDEAevQ5IHrJ+vK!hu=vP z0nz9GhEO>sLf~>VjIxoCh^n(0A;*%0P%>600vsWnnDx2NcEO6rO?0-Uo^e>BHmxBOwNN+plPULi@ zY%b{v(VL^C^_tb%#KA;b@C(tr-LeVon@(e-ibiZ@4wP6V@y1#b!E}XJr6lX7KOR8M zh!cXp!T*8Vo6u9r5hVtrSvivc*2s0rbH>SlB>6=vCdIl)@CwwE*$kT zCTUCOpFmYcDtE+;<}}~nO6{o1?WeOC5Ndu+P5juj5(0#(U|-VdUe98~ zh#{DzUDu(CY>_ePPM@caZOV0vO?2$4b=&4ALMf6AbZDwX&;fXs3?vl?dJqbC)9IBc z;SRdPPYMP}8f)?ae;nqSnb;`kRu3(}Fj?ajK+YKe$$~PB>jV<4$K+>fHggnmC52y) zjSCNAKBLg3?;~YoO*TRGk31`^q`8FRH=$WcjZIBIv7$ZTa|%i_k6v+Rk75dmT-X36 z$QDCmy)-QQl<t@p8|{p;*`vrKv%-N+vjqpb+P#Gp55pw_2oFpwY*AIV&h9XrU6g zZcnGh{IK+QoCAutLgTau&1ef%WS$e{qK0rO-Yn{xqmkTMztvj1!3We|z1|WDk#Qn0 zE3?iKnIPpArt8>4HELUsFqV_4T>VtJM;2s6B7XYAb<}%zmt}Jt4|3e|oQ`@EiZVLa z6>mqRuW+b{?woL3TUJlqmS~HlS>3h?4j@6fYPQ+kHV&d;d!vz;8qEz_O;Z@^ zd+P=CfqB;!U*`k74eM!A56BTn1o@x7+-aRcRawz08#k2RaBGmI;$pP8HBXOTN3Sa4I#|kS&yQ%ydhCZKF_OBXm_BbPSVj{`_5Zb(^6Z6CdwqnK3MZMzw=EwQx>{3?W73@_RcBPbH7VISouoF?mw z#*~uE_C`{iN(Hsz){qcgs*#&=^_FzZ7N(5XG4DLog-X$NSnHRD;llm=jtUV==e-@J zmgEPn+xHO~9#_y=78}1-h#4t_y?{--7SO<>Eq)JJ`P(Tc3X8#&awsahW7`w_TbNr_ z4+uOaqsy&r5S*wXdoLU43jJTtF-zwf{I$flxG?-gf!rDTV+}aJQ&bpZewM1#MqO^` zDK6|SeF0KdTUE-m?2!QVo%x#$uH=gLx{Tp=ryA7Z!H1SEJJrFheX6x@2We5G1VQ}5#VQcM zAil8-j`l-^Sx_PLWy>bWXYNP3rC& zVQDh>AXm(TyDG(mq~7Q*VzuQ)9B~K=21(w2YZ=Ko41l3 zz?lWw=Ai!1CqOaa@CX-10w;9x6rHQ}-k<}_>@uTE3Gr?nr`}c{wSs)LON^JjPC;Sk z#&ID(n^(}+D=RS`y;8IO#3{!8MJL!r?OpuLsuvmH#`(#Q6Itr{u6Zbl>guphMQi$t zx}sfdPXAl^ymmMSnuRc(*)ZLHv#5+6qnYVFf$6#k}MYIQ9^Li zRwIRg0FU@xL~xf}fk=tFOF9bkL_yaRCeNFb*C{N*v6{|t#C>9a(C8kaQ386!K|C}{ z6))LAMN?+Oz4Lj!n0LL%@Rr`;MG0w{(Y~y_1<$(T&F)TL-=>~=tD6&Ji~E|nH&lQ; zL7QY>ty%~A<$0Q z-DN-wFq<~+{$A6gwh=xWws8UhFwQ`NKfYy6uFB4<^GiIM>(_Es6468?{-hTDzu)*h zzrQR0-?1?JKfl7Ewm>-lbG|*kyx!bcEDU0_fQy4CdU=?>0$}Wz{~;o0X&Tg_v$umZ zb1BTSWWRlK?+>8l!w8=u6qXX4zC`kG?R|2&q`G%vJ-?rC$|hkwGXs>11OHs~0-gru zVYo~!A`0ng5T^t*|K%xk!eeKWOEJ{ndlsnEQ0zC_C;+DTL!SH({Yl?5OU}gJT+EbU zLW0=FlSa&1Y=@p$3cC#)(F2LFgU=6d66QXlS(=6HmgN2r(*S)PJq^8>rGh`bPEJjq zGDTgw8a0^ub{|B(6LAG35z|17Jl})P1mQ`B;M{E(kGSln!{WGYdBGQAQpzEAxt4=1 zM^?wI{IvCnQ`a?&%tis0`)aZX8`%bgEVN+#Y~IB9xiWvZDFWDODt3;xt~2AbZu+C78K$z}qF<`Q$j+ zf-$C#=g;c+>=1`Y>WBb2w0Z?%b|#L}aU-lHX~5fkx;nX^4Ae0KDVewgBp<>!2W0sI zxF*?uTO3{sdBB4@R4C2c^lc#+HRKIx`n=$A{u=A*rt=MU8;=*D$d!z{*J?kOW}4vffBEyQZB)s+?~2lyf#Wrp^&s1ja@*W>km94{GbEh?c*X4o+Rg2!ynY zBDnJ{MS!x zH<+ZPydfFB_n}+81vF@+XhZ<6nl6!^P0|6oK>&fj07(s?36InxnhjJB(Xx4zjpMP_ z;24f!R+{5d7hx-5&M0uj7G@UdDY!~D^rmtl(cs^B2^LE{hQNN^u(J@-? zsXJr*aYWWy4t73j{b9Mi+o?^xl%dT|eK7Y>t~m>O#6+<^K6jVyO)vO|+ z6)g!I1%_rS?^ts2w4&}HBuZ(qeS%a4?n#8@$5E8l!+wnu&_=MsLF9}#Q?ZmgNvtml zExsDWcA!qVUE`?0&+SoR?k-u}RY{;!OS2&T89>pq|5+Isj{$rg@cwqm3g2kV8#SK3 ziCSh|m^hM<#jCi7p9(M%T`#fxD_w|q`7Vo@@{Qd;ethKT2T{qx@S9I!)nU2Qf^;wP zd}0QHxKi3y4Jxs(J5+9A zDZk7`woD3n!a%I-AB0IT|0`c?LkC0ry`^0Q$cIOsUM{v2pRV*RgK^_`k$g(T1~#Od z3EgTAsz(WDQ&;D&rM0fTWlsxH0wcUcbOASUKoB^#wRuE~iXAZs|1U;dMSj>9?4mj4 zjBH*PsbFCH?xC*GgFM6qusW9yDF>d-?n^!AB)*+UC zarFD?znX(7;Z95CRA*hCqa=h+FrIPi2 z*?d(EkT&O4kC@l_^Lqpqa0__|v2@Pk?hS(2<7xc1e|+rz^Y$Di$028@oe*fg{BoQ^InLnQ~~J2$*+?ZY;)@}WJW*^u^4 zjD$@W&Q$n}s$tF_GI)`39XU+CsO1%m!pF+SrA0W(wwxJrhkg1_)9*HuS0O5HlLfCC z1r6vXQT99NPK?qdpa@OOk|dyF$X;ctcln9K2B{3QclctGbo0Be-jwY;%>L11TiP6x zx7(`=60ZTRabiK>Ev_s|Joz=o8F;1ixi4-zUto(sKLM%akp(eGrv`iH*S!Z`d986_ zSFl_EIhEVJHAM&YMKwhQAfHCs;!|&Ywz#nB1$L{e3$^B=+GAk&Irq-D=#3Z0LVrL7eF%l7T#T(m4dEAz#L#=oDn&f;uup8pB+^5RjnrY zScxCbifYNC?6=~o`=^8s%N0ab%0puk$437oDxoAbQVLS9lbRKV<}iaZ57vUuA7j~8z|w@WZm&(v-% zc4*Z9sbJ*JB-gq;#I*b<=-`vib>8M0%$X`?@UoL$YOL1|095tM6($5IuH&=y#Gg5p zRhFG$vuu_oEh7_W$__Ot#ouPZ4vCb=zG%d}debQ;=3R;HP2HR>$FT3#S6X(g<5R4-~Nu<(V%HU${Tc8qfqE_zE8;f~EAZ=NpNHQAiO0w%X*|3M7gIyq%7jV!1}b#Z*tl#>nnmJ~h(5<}~ijJ*S% zD0eqH?#=RqkEH-(r;C0G5JGFC+hTJg%L4+q7wA8EdiDh%OcNmzuqf_Obq5)Q-$mS0 z7&k`}9*CPy;pzp3PI|eHr=4V+fy~+W5|4-_vqdzbUs^Re?-`)>nj6elk@g5Mx8yi23bW6TC+4CkwjW>;`J2vwRr{#_OgQP z+=k-r$P1=^Du~%QzZd&aMATwOt0(x^9ExdIDEQprt*=%>3Ujy-SMjr6#}%Czz0f4) z=rKsTf`aWj7)0#(dgpJfl@DS>R z+YlVL9#G?*80w6J$nZuKo!|u7{;*C-Sh@Vp$Cu|Qmag9WMbp*RGL#K667BXFq&LV+ z+_T)oD}JX#kVZ%NPkZR;IoT?MnEmB3sKL2|)UvEX<}99Q@if*{;bty{iQ5S?byKvy z+0T^>a9(boVK7S1omUBJPG8W+K-aNRGc4X=_5dvZ?m(B8|JCuOg%~`aMa!-VL$3#s zi8_8iTVewm@=>BL*P-15W+cuW@*iIzr9c1Qx`~*%D=w@28NNZ`BC(#MY}`W2%L}L@o2Zh zE(0&3v*WOygdb7z8n&ntM3B0awZY8<0$I$Ca+g9B(KA|uXa5G5a$a$#wFUKE%TlPb z;?xHkuohOI+gR143mF_Q{45Z2A&2$l7ffe(vWINz`{Cr$6Nzkv3S2VVqQiB3pA114 ztgwX}ChbIoU7HeF6^YnY2h$QP5>=HLlxm|aRy-Rsz5Gr?H3=%Kf|UAqXD+kK##Q6yPYHt^W@8Dm0w)wtc<9^1O)90h@r{`D)!0ZR)AM2NVrnAjLkTdB+ za1BB){=-uo{x{v+JI-sL&qqVOh@Tx2j^&|$Aikd~uJmojagauk5Yf0QA!FzsYE*uM zV8*tZ-yOeXfUX7P-Z34tbN^XjSm{|}W(nT~rk}|rwq@tMp4UG8$51Xd`G0-g?n=F}9CyHFz3J?%Y7*sgeD^Hy4G@z}hs0yKzh zS?(lyP0e{^UQrNY_89rG9WAX5jP2aor+K`P%#)g%b=dY+2JLUCB zFDDd=A~UdPL*;^AvwPhX21Ujla3NzHX3e;S^zA-f2QXBv$~j@y1lqRr+Gd!{S-pD! zZ)c)Phj=!3n3j}&7LcS%Hn42afT$Am*_~L)3$SaBXUX2kgBctOt0^v%3vMrI1{qg* z`Jql`{Ev<{;uYFlO6<;Y&`zi8lEn;2p6x0KUEVu<2;wJymoASSB2eT8Fzepw)T7K0IOlCCf(CTAbt$O+i zvShIX5&9gzcx0PkklbVtE@_3fWh9J&WDF7nL2^Pu5lI2Eoq%_Y91oVl06n7MrStoC z5E0yv!H3Df&bfv!x0%5E>9}OOd7XlM&^Q&?Mw~{Px&?X+1EF*Bt2eqC&G76O;7sd5 zV@T<@v1CFz%e#!FQ!R_87-Qi$Y13o*Nclk~Q+@&-*aGv=2WejgjG^q{xQ{@4{1nk3 zx!0mY&CvFU=yOB&_}X{6TU$a7-J$+-nfp%a6t^$kxf$^igyNa*a8b}0kx=0SW?!T@NScBF_2LxxM;r)2(Vf9bC{f}tlqX%Ic$Z{ zwVvdu6lPRW%uCBHo_|^bez;U5CTyu%SV7Com7q7Nja$N?YY$!`NPdi-(fqqIQbfxk`=D~D*4l+`Zysz(%G%H?K@zxJOwhM?JOlC#*B44= zm#g5tXu#k}jttF53fflHWBbe85Hbw@w+r*H_gOn@^W;Lf)*X>|OqZ^9-VEET7KhIVIV&>UB9e0!2_Bq;oZ2yB+ zeGowJ#GH%7XWrQt%)}aGiP*FsMsTzVVIq9^!mys%quizO3<0W{a46XM5UrIAkrDZ0 zFQ6U=KU{-(vZJ5XXr9jz?G7`I?k79a6X)13PW;MtXu~)Hjd%p8J2?~-3V`R@6P_0D&Do=7)^Z`Y16iLecQa@? zVV}5oO1>w(z5Zey$E`BxQFZoFrsrzD>}k>Ij(4B#<89Ah{D;3>ekQg(1e_pq& z_WFh7RR%JseC(mH-v!ULFBNcIHn`Z86?=i`k(0I#OCC7djORXb&a(6@3L1qZTv;tw z^0_$DECF|eS3ZO zELo>-*V;HDt4)R{Gj_UhRBDmNLVy!(e}vBas(5g9QvVsh&9p)=dB%>mU&LA8m(BT>qlJ2)0?uKDbG>AYFSOf7I|h?>1DI( zRd|gW{O4=~>>EfSsqi^$n~Yh-NyEJ>|CH-$~{^oNA6VdmhIchC8%qbd!%)o$8V zxjh}w%#2C0%g5@djzH{bAx#gStflGNlMNObsaKH>T{vOZM#@eb!q5;=!83&lsdEhA*$ysZ{Ug8Dz-&?C z!gh!Du6NPML1GBr(OziB*v~etn~DVRGzonJ<0R*}({Dq#C&r3~XtU>{r>+6$N)IY&6t^b-ICuX=hPrC+bSm!YbZ%R77F$POVs1j? zZMmueh0aG8POs#>73%j!qqJ7we4XKc5wX>;hGyjj$G)pNeHH(BU3-&^jF||kFEk64 z_%Qb&U#Iq%JQzw>K)scxHMag;UP@VY$e_N}mF8A9LXnc1CYyYxXzgMQcP687GwdIz z6q_0Ceuo{G(HNxQhkda!!5%hZp_)&^tKjdIqj>sqOdEPl26q~XEzK2{+qllfK{rQx zEChMoPQX?H2E56@gVdddNnUcBwZUlCqy`_~R)#QTE2g<2I9BvmW~OH+@7nV%Bec1O<5Lx+{mWWJjYJZT%F|vNU20TDz>= zIrK^7i(}uj&&H|~_W<>zaxX}?0AAeI!9E}PKKKIKV(gPO9(^WXDtAWK^W=)sd;{WR z|11l313f+XUBY;cLhraZ45Su#cSnimt|7o|bcgt;KtI}hzM0Z>vM(a7IX$q6G34TM zf%6VJ3Nv2CL8E*iNm2JBn*r}Icg#uSb(REjIs;UK8>7K@oV|h$SCu@_?{2gn#%$H5NeiuzAyg z?0yBGVt6nTtBmr96+twHLO>RxJ`MVXqXIO2d|i>@yCQe~vpe#v{Y`Zi=k;*GIE%L5 z2J2%50=u2-xEFgX@xJWD+bhMyrh}F$SZ#4P-Q?T9i2lnfG7TXNk;b=~8e&aXTDw-- z`EVHe15|7qt^0q46f5KZRY#vIik%ne2-tOf4zN7TNA^rWh6bEZKf5zm0ZcCksLV15)p2y1g zc@+Q0s2|$q|NC~c67&0gxOll*g3pVI`ZoX_+gMiTKbuX9V4BcCn)n-DYGu`nOm+a|vS4#|vIrf1AXnK|1$1*p zVh*0wP$$G$^aVbD8y4j%D2Z_VdApNt%@m6^qP2=SV2iGG$wDcwC?=)R_V7FqCT}$k zC95Dm1F#gD|E#es40&On(4d=bbwBI!(fg#^=ergO;eQCaTcKuN!1s@lz~H)5rggNg zd&5-5MR`@4SiKQX_zn=gLI#mev=vVHDnE3c+^@G|?uT;#LkE1mz^ChElXx(|uTlcP`oS;t#km2PSq!A^HG9SWV z0NEgUCJDg;({v}4(W?-&XU&+*Fh+wigRTcpcR|WoX|wR?IJqAL&0U8Mj9$OqZ$F}+ ziM~E$UteYXzKdE12s*<=Su2VrF^`im$`b6)`TJh|xhL{WQc}9y%o7t=RwfL{QtII` z)cI@smsIvY&L{2osy>zcmgdkbaqvH&2=Tmq3yS)RKBbl|CVz^E(DDPB8TQV<8~yJI zYaP_`2{Co1DGeB*Xzf#6SNKnm(J^n`Khd}Y-nK!fu@a#Pg4~O-zXX40YX1HEWVWI> z(kZ(zx5TzLEWe&88YS}Uyn2TA=&WqLfyU@lI@mHWXHTk5Uj?gkq$>2xcXJ7q%?BAj znVl%ZMSZ|o112KP<(Nu5_VarT*r#Or0L%F%sy6vlyGNh5TiuAgPqHiB*J86Dxu8OQ zQ68}VJ~J;SVJ@kTygrX}DZ0DG#%;0S@Iz5Fm{dhTwPk14ccv?mvL;S4$t$6u>-_Qg zr&gg&7B^ucg^@M`6+ALl|3MT&Go)wAoIya;Y3ESjTnMyN=n+Si*)O)1)gGijPrraX zv~0xN88dW5HJ*It(NSv&mef*rH}Q+g8u7H3)Y1c5#KGsCgS^+^?}~KZ+*%UZMAC9> zC@btaQmH_X&MYE8m&rNi3)ZQprFlNAL7j!|>6{gb;J%RLw@dmrH#J~!@wdb}t4B2b zg!b?>Iy*>h4w>`?VaU}Xmj8vd){%POGyZ726NJkbrRsBctvCu9tikJpGox7+vnx5hEKFLaCWb zN-9=UlQfxpyRO1hLX)&+ewZqA*Eb`#0G4#VSWs!oq*$8#-i4yi3jUb1MAr5+tJ;FI ztJWmSAC^75Ip>I+u2s2KseWVStq7TM^%Bs60@Y*wVI26lwVw#!lL3%~G;}Nxpd)LV z)-xE9q2wHq|17%)2tq7PHrl|ur->P6+hZx}LQ5H51r;=ML&G+RO&cQ#-loK0GF!(q z<|Hs$<-O8g^jemiwTaJvY0T+EpBeRmXDpOTI_Awe6lIxPmZGtERybv>?46{AT(e?e z&31PS^tXSr61{`F?Wf>2jo#VWubM!->&a-dRu_t>w``UnuDsb~- z_}9C+e$`_U!Ew^%)do2+(NgZY?trPjRV$hg5FK2o|6Ij}j>AmSrj4%Cp4HNRbb9hGlvyC&&THz^nLaX|BY<`YjkxP!XOI*6z)ES)`b4H{#q3WL3*=3PL zE!48>if{X$!3hSCcpm_6g#?|_T>nTmpNid7Wd}VLZWrtFI8&C2i$vqca){Rpxhg5J z1p5{bY}bAS#9+Z$--f;CaJGKtsx#Mq`*{?Qb=yvhg6sMxAQ@)oKUYLV2Wi*o9o;b| zvP4{ktvSm(u3Xz<;W8BBYW782M#w_f){s4-r!fw$38!rbB(yW`)V@V#Bk+SU5~|fX0DL8j$q7WKwKKOedSjM>c@@ak zec}hQ4eZQ!N6GFL>+8|;=gLPzQ)*lP_GW0918@k(xBY28_0bK^&|GM)IGq2-w(Tx9 zhK6rP!Z9CyM$7$t0QwrcJnUlLoS~wE- zTqpV9{Kc?+*HqN}n;N;-_z%zC*J^UrqhC=kf68&@6QU_ykcD;*TC0Cn{|y{wm6!Zp zv-f3`mTU`UUxLFJJij86Ltr6QL1${;PFO`xZ2_=I1FXLS&Tu;{X{A z5=O4zKR`|dvBjd7_n!_ydcA(4fbfdsx$&bHTn?_en%vm44@o;^0YE5*xS}&fRJ@_Y zmvaD)#7qi+Tm@pb!dB4#MpT<}6iDzCC(-Z%Yr6kc>&N3OM`-$)-og7>cecI@&e^tOx7Cv>LWp zd3z0S>ohbPKZ0%w9HYxgBjC7-zZY$|(Q_>1Xr`7MS5;2T!H^klL1!T-B2{pRBK{Hj zGl#uWvd9eeE8gw3eAbI#e<3-pkle}09y}oavRmG3=GoR}9Ut3Z*aGdfWA5T)*jKSw zX#VpXqYd#Rza;a4E6c_WAkj4OUB^TE$VSuZ1xVPZHTF^C&7^i#F)Ue6yV7G0qv<_b zNtf#iJV1uj*FHjxp0&tfey0G5H~`ff+FSxExDcP!aN;$~^e)+;MvS=dR{M$DCB|l( z9*5oB-UEgZQN}5Q^SUFo_*_&m8l_ty+~`1D2_(|yc?5wl%&dxWWW<8tpI!NTCCK=w zll5z!%>dmCTmhs{kf~3}LeLk6Ad$}oi0BK9x^5cFpX-@l(G5;MLby!h;YnyF!v_x~ z2S&4nNDWz}Vh_IMB66&D`X{wJgLqhqFm3uq`L}=Vh}DGCjVU?%JqnSrF5HTdw1@Qt zcnmTZD{xh}&WnI8c+M+_h}v6yHD|UgYI+(&*yfXfcW*WEQmI9s7;Xg|e!8o+@sNxf z=@@mE9ylloCT%N)9TO0R!@N$)Y3^3D z^*{q_M z@z^Cl4eh!LrMeH7F}zSCXCFWiRf-v6~z41^~L3^oQBpRU*3*PYww znBbuVx;-a|hLYhK}GetLBc;5GU`yTRSaPv9O2YUx`u z#60DvK4WQv?Ah=>ls>|q7e6<+Tjiiv?ikH1`~BE)6~OC_v3pJtVx8771jUgMp^;^6wL=*v@(&MuATUdV9qXNRz z5vB(h zFa8~7_YO=ULwydfkvlv~s&@pH$(P6WML%D6d>48z&ii{oe4nM=U(@UR(_|)Ky^?TD z6#7ehIgBJvTLlm!$P!@ie=tW1J-g3-WHrhgTqq~GkWQ(l)OoNjB5zi$@)f*CAZ3Oh z5T`3krGv&>7GXjuW(Y&jKT|RV7fU$h5fhX24nT+z z1jCf1Ke!{)nutK#dds$gF17D;ZIh&dYX{D@M$KiAmmpaJCCyTB>HEr>NFGnxdtHHo z{EbRK!Y2KT=8)l`t*%x$z|{P}!Kl>m` zn@g+qIDqMZ1DlgH5HcSth>?SSO;k9?28yn(mnv?(a$?t(8D%qR1mjM>w)tz8)d<9? z7|}eDNRQFvPP#e_l)i<1@9e?9)~=P%q+H*>AIKGS9S8cp1Da1N5-?MrIJ>5EKzlx-#+^17#qQBM(H@#o+K#kczj||U;4wB&n{>x`wJ8A%PXFj;r=_^lk@j_H-;y=2rCuL4%PrYAUBxpgcMphx2om| zNnF{_mISsJfGA$zF?JZe==>x8&hz)>hE?~IVn!V}nOKZgb5{ldm(fO|$rwaZ0?EL4 z$)*D6(0eXIHwTk{kx$sr{iw*GWwbpn>=*01h2qU}MI^{*Hd+>&Iod*lh3Y(pA#-@( z1lp^VjAEuHtH}Hu(!^n`obm%pVX>%d#z(Dh>ckoRcq zT9gtWd8ff$@%5lZ%q0DU{_Wt1uG0emCZ zdrLxKi^o7#_ZF#d!wqH<_pSiv;Ci^L4{eRJa7(SMWe~lOK--(D(IrNm(ehpE!YUKs zXdDeGR~@Q)6IT}KG+GG(3$|?|_%vW9EWAaST1r~)BGA{z8*mrN52X;BLtah%_(P0o zPJKWK(&{s%WiBD6H&3x(9f@I5R)dsMyBIkmIdX!v)v*{Q{qu60i09KxHoYwl*ep=N zjlQ~U&_vEm=Jb@UI;6}a$Rc&u?VcheT_Feh(ON9oHlD@-S)qp`BcO4m;jX-1s^u$# zFv_H=Yr(VVtaD)MFA1&hZugjVH>M)zA-57EGUGN$i%j<2bZJ?zu-IR_m5NQxma(8~ z^OPzS)g4M{zGq+1tij$Y4xg@|8JGNrvX1l8mV21(1x`;LkbWl>)_}@pqMqEI4%qN%VQAIXH#O6;YjMjJ@cEp|~0~d*CJBcREwpr4Rs)j1P+blxAbizM#bT4=HgoQY5QeeZ)O#0jD zPS()!mY(g$^F*)p>N2-oDZd)w1b88oR_O=Dt#cO8IH`Dn0-Mg^1?3CkrFVMFkS}>; zA*f{rDO{^eHnMoDyn)=$)`Yp#agt^m)S#oTKi@rM!AKRz7m?J$a?jx?wI|f{?A0VN zA2n2g=#+ubK1{L2SSd-)uP--3^)FZjDv+L$sIB7_!?&v-D~X83|qXIV^m^ zaxhCzR}w_p7SsJwgGj?lvNK&6d4L#06P6T%%KJ~XMI}lyz&!@NO&)A1!TA5f-Fv`O z`Sy?FBH4R{ltcDD_LiM3d*|Tb*c_WwHpxmMWJR{hsEo>%Y?6#b_Q*~|{qJ)mqdq;K z@AG_r&+~o$ywc-}n2zPGfF2ziv^FdSBy^!^oqEk(ehu7vNVY$|+WL zZ?N4vyO2m35@PV2B#YVgBt4rnFPX+Cv|Ri>$Ej~M)|G^H#Lg`@_Kr!ospn-# z6$JXy48?`J6qt9JK`%L%s0K=9i8|h!xEVYet$HmWfn>E+fMrHW%lA#ty?`F_*D!1+ z-X2kQJwhA9nV@?<4Gy<%%sh#)$~&_zzg{kC^>|DP+fD&Dgp}aM*y-=zxg}%nlzq4((|hK8>r}THl|~mO<9ZX(WTmd@ znJY@`69Fe?jAT2{ZQbiGP4Ekum+Q<>^^CkHlUz(8?rTZoT}=J)rJ-%0L0q4Kv&?Wh zEXVXhHQ`6sNE7pkMGNDohcfC_nvu6ctlS+RIW#xDpcX&P{9S&1m}q-y85RpW@nUm1 zysW9eX&B^(-;%*b3`LpCM3FPp5noby;y@r1sH=wyyvdae_hnkDfLl$aW}v4u4Xu1y ztb3{RK0A(`tg%RwXb^L&)q{Tc;=>&~Th949UN+k=e~ah}xWh&L(S*6^YIxKtx&tjNAXY@8&# z^_03(CVRx9cF5=YG8@hCEOzNQ+<`&Lo7diKS~KkFlM(7iJ%KTTtk1%T`x@no-jc-4 zzcH58a8PLQ;=}o9mC9j#=7rcBs&fVlC!7{y;2_Np^yZft$hUWez!~mF-@5O$WAQaA z6OpezJJGp;lBJDz!oJopUyaZ_PmGz4^Rzz)jr+-MzQ+|4{BL`gZ%lKS1}>OS(k{)( zHki97F!M{9Z{TJRxQ6iX81prgC;P)V64wlSH(Ki_wQwl-#MOtMh2|B z`v`DDzoJr{vNXcyc1l_wGCOyQs)+uQFu(HuZ|n`}Y}j>$J}zZd@A+bi{R!QkDnFeCrPds{#$tuQ6)Seq&BsZof!Ti zx4jL<$z{$G#Y5FlXB08g(6X_gVrASr&y+p(6;0x$VV+xX!ua{i+4f?rqq`4=UuVT@ zZk->z{J``n-rE<>(=T8#Tg?RWljh-Zx>fy*DF$>~AXfA`vzqTa8GyV|z~VR_jyBp=Iorq*LHtH&>K8`yGFjMv+!Wr8|j;`80f41{|s6X>BV& zr9AoZX68tAh|+L1Q z1Xg}kQ<$k?^KxL2!hma?UB#=ZJ3PcOoHtTym_#LRo;#W4u!gCH$w}c<#L=x}6*o*@ zMSsRynvleLBw7l8qR&jzXt#t+P1O7Ym#j;Rk@1tjZ+8km;Jtn$c6E~X6+`ta2e7xt zgAXXvys5FWLsBnqCUF+9ErrHd1)!~ z(V{TcS95pp1OtiSCBiTHq|ntc6Hd`bnhnYPc9hunUl`%9U#m~nEfSoXHy3LX(_DS% zfYEcA#nqfFywio#^Ww{;a_k^6(?TaT!^^5gT+{0hveHFvY}_u&J3~{%{yue{`68c$ zqgZLvJz)r`gWAn|ma;7TQSW0&0yoY$wS4TJ8t^)8hf18EmENhd=wsm0N4zD@(v20< z<0Ix%jKW6=!gZz~@5j||6|i1A(dTTVLs8KYMaqn;Z7MqGyIk>XWcod0Wg=GySyB6t zbZB^*GnQk9dzZstzD&oNY0bQ+Efp@UbPc#yS`;WSJN3^w@O!4HEmrjDO;4RpiBBse zSiC@pf>$2q5bk7sXgT>5G&!suA85Qv|PNb|3z#Y70%<|0N8OYSq$F|0Y zm}@*)my)s8Rw=U8*kYR#zY^-!!xl`zc8QQ*h-^+bH=0~jCBW?yorS1&cEkze4%5Ul ziA`l6`@(hgL`JDEGEetFAk(itxN+TcpT0wcQ>r1$ITMp(uXNp~ahMZvn1M3^0Z`jYC@SXQI zBrNQjyAsyxG+0EJ>nLqJa>>)ZrhM7UB;gg@q4+ab!8soj!O>zDzxZ$Gpfc#69BZ-* zWa6KVK6(Z0UqF5ja+Qq%y#TU5kHyApk2ZQYBE@T)*zB zgdF?#?aK7?k`K_IlF&{HwY?*_lr?%2Lp1p`rUkMGR7EI-T4Z^*M`CrEEX;h^x!9XOF7S8zl)lxCo(Q@bAE;|yrF$okExgg9!ZIC3w_+#pT5FN%`WI=8{K}LA(Q3;c8VOx1z+m_|lBk z-{|wuvVJCVkE0M&t$L67o;$!))x`DGS@y5=2?=pB8xv=YO|;17X9hY&F=tWpsproq3dh-Uug>us zr&0xZQ#(Xo2S?>zcX5B)%^a{m8+S4mU#+V7$$U@JYXaR(6|T4HjZe|+c-UioaFo9g zBz>qOy?}?BVh~$hrI_yfHqs)T@1mPmSAHN`Cndud*<|O$4H%R3^2tXY1v z(5U$e3kMyj_0e>MmbN7SMyd99LD9Z@kyT&SSbG~N6{p^R_EaHW5Y_Auu{H^eT3Qio z_un>^*--PD{xtC{FC*h2yb5u6Gj^Os=#Z<7znyh z^mXB=9s=F=x8C@wT;u1otNa%owDdI-=`V296Eg?VTlH~92wCiC)#hMR&qu9)^Ov!88O@pJ87Qaa}MV<@>eO&Oas0x+$QCn2} zQdT-Cyb&VEOpl>yOyH!EyLzh8?h0-vOg45az0FDIN-cQONg>!d+%!bwIWo_DXeiWoH}s}Y_Dh|JZ{`qbD}4wiR4l1ZWAckOHuHX zj}4w;4KuuOHFud+wh7XLr9H<@C#@nMBwJrL5S2c@^_F&=LDV!fhVXISK&?n~lZf~1 zr4m$&ZR{3#Ujnc7d?$iCYRlaR=sIgfJh5K6*st<*8y} zz%3ANenU8=eoLO&<-U+~I8F=KN^&F(KG5baA|3oPqjByiQtck*_|>je_MWnvbMkxrLuDN zTK6rq3hC98cNR_9@cU96aniHV{BN0_AIrG5q+vqTN@S~olVC43MYg_s9pzQyyN^Q` z;q>z&7loT@`cHpqFl1+0C+abSR^&Xc9OlBrkRK30vs$k1xl(?ZseHl7M6=i@V<@VVh$P^KnGxoH%D(Yr=yUygAdgP&=5nrY&)^~*pk z<-j7>%gbg>?^2@g&aYa@_Sm;Ey)8VC{XObQYV&H;199q|(Gl(_-WHefO~DKJ5gI}g zuSOWMGU_iceWIKZ^4#<`7%?Soemn>7)J^aHcs(${P;=L#s2Ng(0aMzN27B|&7quOgDfZzAKWPKG&`*)&2@z88u!C3zb*&*+E{`k z8FfpWJzoz?)4bBDYE~|``4+A;166C2`-FE-`7CGLa;%qhQ8)xwdD)pTgEk7!!;9Vw zf4nWgasWRKlP(^Fbt?@+_zO8BTcm$8%VK5BJoEHyW zqaQ#g7EPBu_oQ$HlcA@yUEljUS!yW$&8K)_VCj*E&~bYw(%4vTwVR@_RQdBh4Y$n_ zFJUaPfc;&E&YI?0uKK^AmCqO8*(^=)&tS^abn*`p)5zm%0lUMg)cFW2nA+3R$8iZb&(GridmBC#?Lw zuUtM>s341I(4x#5zgK9z*LuKBx|>>6R^`5Wr|zFAa(-@JRK1qbU6j45EB%;Goadp6 zTVhR~Bz9=UMSkcFZBJ}1%|!#xNHMVHozS9)(Dp2`-D(0Wsjx2c1;U54G&famUD=iJ z!+T#~JV?vXX4`hh+p(7C^GQ%MQ%l5arK{>=0%u?5?&#dE(E8G$1nvD|=ZW1zcIkTN z=*5z|_iNGBnv`S=W5hiQ7VeUJylT6aUhSae(jjxU8gqsR3O5&CNGi%nzCgw}GSyYH zNcw(-=l!J^ez@3>Uv#0p(%p*YsZNe~*a*2-QQIw(CIaE7yZpoafvdViH-yi=F?pUp zGS}bk&Q!r7KD;TuCBm=TvTS@8*zBV^fA)c1uL3 zjliB3EB2WuP{&i$1PUEgv;)3m-cRVM{tm32ZSh5ibX42LK|-%fa3eF5)Fl z2LZO{f{Fm=h}&Fr64)RyS4%4qOgr7$Yu{VY+6mH=Pb9RF{If4*lLd>1q-NfnWfajnegF7D@ z+!4-+M26GC$$<-azy;>y*r zBMGpy;DXvi9iWbGaG)FbNPA}+CpRa!jg#}wZbu;fe2j#548`Af*+=eJV^!5ZH+OJ2 zf*0IP&I91!kJ&ha(>?$=Laewnp>QX6R|}||2SDHX!$1MXLJ)FtXhtD0m;;g}h-X}m za4wkT5vagz_doS<|BFt5bo~xfU^uT|<`!}D7+Q|bQ20JtUcW=j6$W?s3Bnn11$Tou zT0&eck=-024p2CtB~Un*IRp-~;Nk^@<1j1WZt{+Qi<|OJ$C#+->}J6Sh@*^?EA%G@ zfTUX>0mI!axem8LN(oZoj(|sSTh7Z3>IerE~!89>Xz2I>I$b8k4Z z%`Z}*;p*fJb#?Rpb7$utt$yi_kh4E`MOd?6y2-Gk0@5xayCH_$U1@n>sWI|Q-NS7ZEe$(ZreClW_O8iby_Ej1%0!M~C z((yL~?@!qezWiX67S!eEjlaz+1eXz1?#qe@0=9%YU}9m85PMlC3wMM8Rg~Ss?`W$Z znEf(@2gKeTIX4mj;m0~2Jo~HO7Qlw%)=sY85->+#2XX+3VE z@HP&BgMwKCgunpNa|KyBxq=|}_8dqwvQv5+Gz$$>Ae@e~~ zG6AzZhBQ(Ge$aeaH;%~bKkz$8hCI^oHv=Ez)BnDpdqW|v$L1HQ06!=8n06e9uOc9w z*3jdf51#+k2tUR5e?zky6+Z`k@A0DRCT04I*u@e8ba(rQWk(Ghr`Ta_Aoc^ ze^zJ_>zE@V_CGVv$DQ-fmCune|Knl{ct5vebN$~Wwi*EX2(eYvQU`(gc!Y%iH39w? zot-PxoVZu z^>z1FF8`d|Y6H>6v7Y~CzXeP(p#F%(ivGW*`u{0W)l}3{1xX`He`t@J}Gk=Be&h{{fqXiTQB&=Ze&|^~gH+|TDUVb%@ z^AC51S^xpXk5%>oaUfvXil7eU<^=Mzfmzsq+-zX*p8*93Vrc_)g~E>!|MwPa|DvyR zb~m^Gfv_47=p94h-@<=Hs^eb`>og9?03nb*M#sN}l@M!dSEw~I!b0RBj-l{h$x1{% z=NKLT7FL=&IoZkW1>eWO|JShb2l@!N<_6>(5EOx6jz85OdZ7KD5I6{_hHx9`j|B^0 z4UvgDk$(%fJ)G=;q|SdUqYtb89wi`0cL(!dBJqCbc=0CGi8fJ`?cjKY3Kai714d%!x*(QQ8wiLf3p zw;$$VZ&`6nP5&*t2V}wV7~KCFnO4-&Qv1npBy*vbd*=4XGVTAUQHCo1|ApzmJ68)g zS0_gxG(x($|J!_r!Oj1RWnKD^tRGqu{~wicODEWWt67l+-iNsXIcjxtTR^&hzF_(B zF6ppwKStrd#b5&!568g%O?$1QsdB92{~!_czY)j*2!J4Nzgs3-KpcV67r>OeJN`#j z$>!c}P#FOD@l4s@aF`Di5tcYvxIx|iGYJS_S@hq| zRyAb2fmo~|R;h3VLw~!J`%jw%I8bi}bNkO^+5R_-!+!Mv6CCsxr2IYW`Y$Aj_qy(v zpzPU7x&2z5BgHC+9Iprv$XmKwKwTy5-61ySZcs1aC)UA&oZQHc2Tu|2hWFab%KymZ zO8~#c{-f2wJ!Cse3lT(KW-phFEDhL4=f~@Cpz2^RBYL<5;W*-lM-c-q?19L{9gyBX z4hwbU(9zl(X}`4LH{%`|3NbcN?Ra?HgCd9@g$)us+`v}b+`JrMUTv_D2se)iA1?>D zpa?g>r(bE(IoV67K(wLy$Vd%j1F+u}DE|@TI^O7LPpB+{@IMgu zv-@7lpS@L`EMZpOf2a4MmIu9myny&y{SUX@A3;@BWM9=3WhLC*VU{A6JUl{H=H^x$ zP(Fwt2cJ2Fk3)!C2+ASM4dLd42=MV*3GcDvXx~F4Dmo&H5-gzmBMMn?^YHUo2yyUP zf(1DEgu%QVLPC6C4ltBo*pklzY9U}Qgk&%<;-S9C5s@!DL=F<{fSMuPnS`5-D-@9+ zKvV|)=JBDv2t$o@I}!kpz4iyUfOdO=Cwr)J2q=?93L{V_3)Ize{Vc5Af2V^eG&}f* z0QJki|C*Zz#l}DllsKIyqLdgoJNg5^f`9u5ez}Ey`(f^)k#h8q0O9i`;0Jy&W$=al zP;Q`C+c{kuzWa%zCF5du`h`G=>zUu5^O7oF%49dXQ?p2GQ(nPhYb6xzWF}x zUzF~X2Wjcz(7n4jeUa|Yl(1rJ&*F^MXN%RXv76usD_g(ise4Oe)!l~YOejYuw^sC8 z&bxe*=#KJh6`Pu9O_|1U-c-z~NAo(@OW?H4Rbd^*sBX84JWRMLUuc=iuWoEe2(HW59|5&9lzvq5zsK~|>+I+JV0OD@Es zR1lfHwG+W*)hDmJhRLY%>Sga%K>F!(4^C!!W<1n)l;moy^%wiPFL^3W`?ya*)0qqwJFq*8&cETGYxu;*9 zIxY4NsvcDu;%*@KI&zay3sKk7>)G9Tj_B_0u$gZ0qg zLBcwYnut z3sFm4$qgOu4jV5BsG(BLDss{8%t(1NwQNb*9k`@ov%&4v$D{E0QqarTF%Av%X{E@U ztqS6GT|An$=2tG;xqg$-E$`LHpChHH2`Qc8e#FDDX2n>weOfKp@3DSzd0Q`o=n_cuxor@CMDn`JytqnYJR z{~Rr*t6>0#qVg#TOD^Bzx>?6BB;L{T64eD$#4nW%O&F$af~LsZx|!*-ruA9xJ~vlml9fczbkxJmhKya`NRW5rLY zgXUwU{1_2D5{eb3@bj3=8BZh}2M5qtVx-qLEC?bWdVL%a9en^_xS9PJvfOH_pbyE3A=qPw1_e`ve74)KBc%5LN(`|WhHpF^ON%BxZ3yRb*0KTpIttGQ7i^y zj%6}J!~oW`MLx$!7ip1dBNDAMPOv5eFBsTO0|1-Qj`5f)-pn3gKTpgyRiQOW+KP?mpH zk`iVG`y`hGo(7Rlj(~6Uj#ip3=<@zmc0m3{%p%EbFf0_h9f!-4+$PI%_s#yi;st-hAUs z(|NUFqarU}KO*b*ruQ=;l}*if&@iU&u6nB_{BkLG7@u1wJL6+K7w`>?x~X?2`|Epw zm@XypQIDG^HSZ3-$n$Xdx^4gclm zt{)?>CA~2&rjfgSQs#sq(S0X%F4FOo71%w@jtm;89}}MnrcIS(R*%8u?6TWYQ)lCD zb6x9~y;yjKo9u!Nf4qX4whY4(6$c;rhHZyOjO$YGwKAi-@I0)ww)ox&iq`gg=L?3` z^}E=&ao%ord>pRS_cfNbX}r~zFXlFKtSb;e{VpI>qXGhm*=gk2eCO^dUZ$0 zsbE8~ip+C1{q~|!1pbEkIl%(tbLlO844bMl8xU^=v3qv6cFE!I!*321cA1%1&6_TP z&NN%2w6C1Cyyj-uJjJp6%?xvH&QD!}jc)-YnK1oKv(9vIhQzoV->Ba2BrTjdG`)4C zekS3JKtQO&xDeCQyyV7EBaTtSeTy+da))d&?4Vj*ZofY&NYE~mr$gMw;7U3XP!kpibrOI95Isdt2jhL+m3B-rV#_gfdj=Py-?^7v!E z4%#J&kQs(>yAPZbJ*OtV+$Ey5R!ATo24-Hh-to6gVXauFcc7>l^MHKFn93r%cUnf&pq zju&=?<74je?Z{xPb5RJ%b^K<{arpOV5pUT+TpGYi4#Xt`e6WG|um^-(m1u%~eh&lO zLHt4%a0glLFYV+7G6Jr-LHxq}oIHX8AYjeO2^1WfAVva8zTH4zVPty=Khn>goHSGgn2-Mg2J3&9vEjL8w2JuN503Gp-3J8IcypRwG`~xLPC)?7K9jUSTnbLwP6%!>!-4!LP>#q6W;xs%!DB>gW@BDK0pL&2 zn46nh195;L4z7rU8{%Nh%?JE(b4wu(B8TrtBQB7w;fOOB;$U&O!NsEu>=2hw#KHdO zVSjWaWF*jo2JVPfmdH*l*!$Bdgb#lhUKK3hmG05n3G(1A8M5s)&OV;$V3Q z&S616!p_5RcnbEKhN9_K|Cy|e+iNI2*mwOF^@nzV50{D z4w9kBd&p@*UaI^=0D12)7W;yM5bVFig6}XE!uyhX1PkQA$SFi}`mZ4Z%KJBFl>Z3C z{mADC#DBnP1j(8|8RBukc;Wqd`-S8mnsa29h4=OB2<$&;4pL8!XpTGr4WvvUH32E( zNWpMKJU~jvzG5JoBH4(1hSV=4p~&{gF^~`7hv?atieKnC5M7?5Dgx%-SF0mb9q0&B zc9GDKxR@jGMB)xTfD7i{7lc0oKEh2f_r9JT0gU9xZ^0n|%OMWOWE-i;>WBwO?${vC z_9Xu>g8OpwM+A?k7?^usEsr30z!@zBBp1X1$(aM|d4x0jLi0z!N3;sey|0N!03+23 z2@VN(Pr(k62;QH_KSDa9O<<%~`o$R>Q{dlPF9g|#BoFv>`XB2u52wIkT?T{q)$dn2 zkrU{Q03w4p97sD-4UnupWV*oM{i*te_8*FTbY{W(dU6EtpEMbX#Su+L-Z?P12bzqO z!hI!1wmOguWUKvW2c8c}-XYCGknC`HYWD@=ugE(pKRo-|__xVJPVo`)kTQnE3rXXF z;rZ22Ng>chngpc%I_QKnR0m3l)SSaI11#G9q5bDOX0CYl75NBlNQp&?3lfh5zy}Kv zDreQiDh9ZA@p$w9CJ$pz%43gQxp3=+Y^63eqMf`5d5 zRBU^EKR$(rXy@IRkYAwx(3hiT0{GRX|KXZZ4ng@5fkOI1BrlNsQA9LA%Fm?DOuc;Soqku|ujjQo9Wi zgdGTj(;=?&?a$vIVIH0HpFc8u1m=O=LCPMI!~?hZClvN)@{cGSH7Ce0<`*Y{G*<`n zi8KO81{_*SgZcL7=8xcx3LD?PW*ngyNhi|hAtx0nO-Rp=G+hUHAkPkq6yN@&{Sk$u zj_KzQk{vZvsrA_;xS;rvl3;YpC2a8pt-8di{X-p5BQ2u=*28707 zAfn_27A+T9{o!kw-znMnU~GB>?8%pDHA8_qSA$QItgl$cP*Pw+sO74^a7m5e~o}f@*07 zftXoZlH%aOZ$_-Y`K-+0`FTT?{Z*HHYiH-FS5Lode90JSKffsxG8W4Ikw7?yX0=UH z*1-SCGPlzdWb29a6izhmcLK`yrwbqB;zrKyfF565=7}bbsikkpLLIkW$>n*7#t}Q{ zF*aMEu3yCShL^9;xnG-`hr6tgA9!u3?cB!ps`E9wE+$Jy=c~?k_E+rvS|6}qp+v+_ zpN6ub%x3nb^fiq4kp}lv$M?|%$3<$RZ+3kkM1QhVO^lw_Hqlo-u8nSD5duGf5e_n_{UqC$93o%YOgmN^DJ4X4doUn(Ue~wxZ-L(MeHXn)&{F4kkk)LIPx^ z*6s-#6)HAKUEmsD&gRXvQ3HW*R^L0?{QcfE%DCRDVsclVD}*@~FBX4jNz$pYeY5bc zz_Wop`qoD@xo0m4VCVSFs=))-#x-ZC%ET7Juypns&%nO#6@*6WQIQQj+)&`zSIXB0$v~IuGPZR>Q1rg*oD;cwJY_^wviU##9M{8#6Gd* z4=LBRzj3Ov*YeIqh);jYMUP_PisI%RtaHKDM#G-zRrS#yu1J30RtaSIrqavD`@k%- z&+~#wr&?m^#y4xUf?658oiOn^C1&9esWeU7(^GNkI%A)8W0zYoAj&B?uQtet@$r*z zLtdiuzHOB>fXKME59RRa)AQ)jM}UU)AMsSKG>8)y^C@sl5LFUj6~I0_I2)iK7nWZZp=fsE2Ae_xi>M)YqiV`E3+)D(7Nl1yHDD${y;eXsk+# z)VQ5pRfgd$&Zp}Pu=F~1ye>$UnYAIkZ0|p!>Q+0vY*17V-JJE7#bBa;kIJbtTe-9N zUBy?zxZE)2GCk%{;jd!)({>}Q=Yf+1o`1Dc=W)QLw=NGS>(sBq#_lKp4p39CnWahnGWt(j6eYJy4w^ z?lJwm*$EUBR}}PLCm1ZS@7@1t{|ID`58(dJKe~EgyJGbn_m5sX|1zg(qcPqc{5;3 zB)!V>Zp_23ti*22%fqH*U_jU1-e$<2_1Th}-G*IYXxtVi)-x3f z&hr@q7dw(o_(Vy`Ku=kLh5TAWrDN3G)D-L1y^c?u{lbhxCM7}eovpU1vyV2*#Auiq zFn406E}=Cs2I4VWIRyE4kZi3embr})Obd^$RX*Ub{+ilX&pAyNm(^J>92;7Y9O}#a zwvL5l`|AVs#FqNfB;U1$q+Jrm&ztHgE%i7k=M86n=Q{-sFJKRJ|M$LAQ$|`-_R@dS zcY^u<;5?D~cgT4n)%~cY+h0E;H1tmffERGHztcp7^9K3&_4C5uGU#Q4l--O$w}SY-}c?WJB$3 z^j5Hpk1&QAH6)wT{_(rhWC2cs_js~gM{Y7LF9^Bw*VVm&5GXU$=WsITOB=@&s-Q@n zEGT+L7Z9-99r%3S_;WTGw`456%PylWWzx=kioI?_WX{2HM6Ik=Y#CM%5AmE8mc?mC zmq0CsI#dlWert0EDmMq>E@!{)|cgRp0p+68t;gx#zQv`c8p8?{(Pc{C@3u z$gBUA@B9l?j{8oeg6{cFq<{N=aW5|_$qhFG$eLw zabq(CH#r>lHIc5tsZ$}oJD}C<4`SySK!M;;1@wliEm^HE@yn!#2ShoA&)ks9@d@eJ zLccASG)u{VEq_Wr1Ut$Ho3?RFcWMF$cJi3+#!To~4YtR=^w0I3zQ0i_^v&&|=UaDv z&$1^1Q{};)@cZ-+IhMo+*PecL*?d$ynMysRIZ$7@##p90o7lzw%=c7t^vJ^Np|5L` zUoMQXEX&+gz$0bONk_3I+ybTYisJMrmEfXaIDFO2uc_0l#^h|N!^7q@ONGmU*_xv#+$pUgj{RFN zunJMpu)nMm^p$I@;$^aA_c<0asB6zw<|}$J1wORq2%6ZA!Z?kgoJr|i+a|v1q&v9s zbfT~b?@k^&sR27k%;1qgMIE@BI&oT ztwpRVqJ3X`uR5{?B}Hf9$FoGa-{$RmR!wIxFa^WCar26KK-~9kSb{rCWf#?UXRh9W zUa?84jn%w{Nc4Ee)TW7?U_6GHU0KD1zw5c~TCDKsG2MJu1OF|pS*PF|_-9seY+~O0 zHsJ+K;~(RqzZtRpR(5~mbAA-i9Q8R!(K#wizhATc4WIK{M1Ju&2(|p-aS&eN|B=T* z*7hK{3wRvB;Rpa)di>7>gm6XscTEsk%OjWkM=y^y<`FpbbbpM$`riZuydgLk`>&e) zGxtqEKzzM7G;q340dTqx5TNon1AtqHo(dnr%mf5jC}1?;Jw9-Hlw!nt`2!jNc5xqL z&~g3&Z`bw_1OH?f&<{w6|GW<@xDU?vS&C@04;wiDN#H(z5cl?BBhHb;AW=TZRUaw# z`lCraoX0w}q9_oqs{Qu$`}YSYDX@9li1D3);szgabQIr*ST4WuHb4d1fj0l#5d84! z>>p&Wc?Ay#1qadjO?{X?sb2qcyuJXlXW5t@5HeO)=7@o7>8PlvCx{+O#aP`|1&urM z5ufIc3a4#aIV0Q1fX#WyK=y(z8Q)V#W_NCFVs04YrS3#Z^)Xn=GugBy->Ianm5u1< z57bBDbHkg@t-Y0G+S{Gd}f_^fg3#?t6H)Nl9I|>q$u7YtN8qkGo%%{8O7} zo1(9>4bAmVaV85|uMDM0`|1Ku zm`%8>eG4HSN$@~ih9w21ntV*GCFvt3d`mt`8R}R1JW)ciD-B61AdzutueMQJ8~V=#%cp@WrX|D3TjoB#(`5vDLg-aVynQa4T+s;cJV(Ygc@T ztYj_yK#-CEeKc?(C^h))FML9!;8p~ZvyqWy5UZh=Zcp(tYf7!uwwE1yoyaark`Voj+m%Nx< zkvy3_f+L^ZmfetjkloZMsyxLu?@5Z&v%%Gv$)e}sS4y`%*7>o~f>xvxHMsZ&1t2N8 zgEiO!gEjb8$#)w*g*sPG)83m3ve4~(=TJ1%;b=DnVXAWI7uckfwC0PCIWs>1r(5(U&cQRGmYdK|qfJoD%iDxBR%ihk?85tk}H*`@mEJS#+bF%{PNoJ07k zYWHPpT;8lZUlna8H&Ay#%X6c(nKj_{C(>IhLTHR&38qIcf|l^)(BGQjKNLDiM>aN| zEMzVeh6bln=JX4}-|SNDPP+c36i4ksvKRFYiHI7XM6$j)e4?s%ek~RsbTQs%YOHgg7E9%bj2f5wD2;zfPGSb=ZPmoUNpOHMYe!I_FDS5J}Rf@D!> zuokUDx&qds_;Nt*mCm;MA@VW)yXv#qo>Njr9mehP%mjaKNE4K8H5E&Yc=`!o)a!g2)=PPQ>}fT`}5?> z+;dhUkxTO*801`dtJ$O}F=SjWWGwM*P9~jj-PO*yU+%7OdwsKx)Co!!N}lY}O@-TS zo@QP8NkYgycPF=+DcgLjNOdRLxM$k#bG+S3qaGb0#iPkd5z6+b!pgU_#O}AeQ!pew zq1hkqU~CTC-O>~*CW(^f(}Z(Ci#xc+Qnf+i^!3&YrB;6a51%^DKU2lV z-IV=cq$cZOI9bTMc6+@#H~5sp z`j&poB>CsY+TgrP;fe#zT+W-fNzwhrGH1lA#$BKH#9j8Cs&K1fq~p1a)vB(NMvvuN zwbmdgIQK1CB&OiSK-qkdo6mPKE_53AJSzOMUUik$guvC&6a6cpY`tbSuTt4XrtJS>l!!Or}THo9<=ahGS5HtXy@YSS+L3^^_Q0}DrR8hWwyI*!2->}Vb4kGu-RSPcEm<_%BQp1T zrk_*V#x3<`+L^i&@TKRu%E9^6J)~~ZE$A3AufNck5x*L&;<)uK%g&ab;-VnI$r5Sw z9h_9DK;53mL^;^3(kIGO)Hz|%(LU+k_W}Z4>luX=!S6!z^;nlr7elYgK$GcnJCx7=2) zE6K(o0N$+RS4(~+(FTdENLlXH0e@ZyTvx-2r{UZ=rS+)v!;P;>lhfAtWlHTjG?x9W z)0|+Y`gM#E28FUn>bwu6PoI#qm$SUW5v!NMzoYP~&eK-Bz0Accaz6W1Z0!S*V8Om? z7BR!uUx7r@TdGbeb1MdUW|@Jx zv@Zp6Jk6kxVSPkHaK~PB!LfM+_cm+BWpI%Fb-W!4544aX`DSQKbRdr%fd};+4m5v$ zA;)VEYwMzQx%4SeUU6gIN;=KQF9zXSv>8f56~#yAOJ|^G3lc9RwRja$|IBk4@6wJ$GxdcdDH9&&TW_5Au+Q*DC4 zJ!WCkRvb^?67C2OSNx8GD>kA@`GMqjTO8u6L&&?jcV35`JbT4Ug<_5yjkhBM-<-5B zuNsrHDuZjF|Ex)kWm@E!$WLtwcxfqLb(J?0Zmbv#edfsC(PH8Wc1f-aESuRT5)Uq7 z&($gW=LPTV%Z- zegAIsZGx^bu9=&yG{*Z6FG)}naS}@I1ztD&U`%8F9ek^IgSKxM5=QRSSP@Je&!ru2 zx~+!O7PQn|*T~Dpr{b7g+t*hX&!;$A*0!;!8g?#A_NhRrdT0A8K}4_Uw!&FvRSk1L zih9q}{YFB;Mu4^ew z5HxoQSl?v4HH2DNdnQEeghFB-dNf#l_NA3%HxWk5GObdkwdLC4=Q~q0gGTG`@5K^n zk+$Nx=j!Vi8tU9OxSNual$2t8SJCc%(VMF?krhqfr_~If>xQ|Lk-59ilC7-F&aSMG z&AO9f6>ILy_p1(7z@n{hXVXKi?iUU`cAdBNCg!y4=!LD1U%k;F)VJ{B%Y#OhYLaiL zJ69FHix%17eWV?i{aiw^P>wU6cxiz%vi^h7I}2L6SmM+NHJF|oV%Dx{@P`Fog|#jy z-c`7L9wxCqmv;JLU9($L(CJKYgAQIssqL-XF4+Z@aZ1I^H~2Rxsa@*H=$-olKAKcU zRnszEf?gweJQGn`E|iSlSWNhV9w+7^2j~M)*L#A}a_%#E*G@!F(4RgfuU2z|Sj4uw z`*!j99L-iJG>oF>EIzI0%EeALA?XZ?RNBhg*iU+14S3Q%b+D)PEF7#4gM{T+wCjc+ zZA%(l>-@GTNvoC0K~-w}hFzDVYEzfz4()durLnnY^AiP?^=dgcct3MK%QEl^URx%! z;%y$wu<@IH@Z9oj+xtRP6(a`!E8_)oCGpQhTYH}0d6{z(m)k866{r6N2Cb0#T_FLs z7G>CHCvlgWox!GB?$ur&w{NJaUbrJW{$>GXmamFSm59U$+AfPmZ@F$|)~R4|)XngT zgY+_Xr$P83Cp5=Qx|yDQ+_uWTvi6ASZFbN2ZDkMU`DK!+T{+n6UiuRceQ(Sx`_ySs zb>I5bZk~>zyyy3v2GILbai!2%xsA4Djv zToUf2wnlYfqgcycMBfz`dHz7ef_2VBDmu@NFYnvsFR_BYIDCori*i2H_6xwF(Ass; zz$-HL3x%~-h~qm}50@_#R`nKPmX)rv=ZrfC;B!L57r6!$&N6uL8~d!%SG2#E5b#=` z37IvCV677d$MBz851O9l8GUSf!Bfbhtd1JY`k?qxUhe1hyv!g988yE$RE#dwvglMb zyuhkTs=?eW<#2#VoJn>Va;v_{KWN^^&Rq&iL)C7E0@JAmx+HD7$1IZ{g2YHT6(%Nni_1} zUchHfz$UwYQ8&X2e7(cL2NbXh06AWuSo}x=7O0~;oPZSsD%lUpW_S<}e_J-g!!3A_ zf#v5vmVy0IVX$8}gG??QO`7e$;P^+c{se%&zk8S95Z|u$k()Gl(;K@J6^lGOd}M%B z=eG3K`<$m(BNE@;X@Jso-&fLtZGZmw1#Wf$guXGbIqfIdUGwG9d)&vF{*Tby&)!h* zEmT)^#3)T0l5ukZm#p=^*IleB59Zh&`dFkd=>Ggs(bJTose*j_6659k)={4`6bVO)VS-(X5HC{&d@q0@u4aG{x?Mz zi$4l^VBE-0eDf9mBL!X{8F-<6u{GZ&fM%uV*$rZr2p*@v)$eOH$qEV8!Zb!zmvyQ{ z?y58_cbl9WnpzMym8%cUd8leo6Y;vUfB4Omn^5(;j*zgdS#45}X;zVMUl-p;K$@Sj z4m-TN_u{30kVGnh?!^+4g-Lfvbf|-4vcraLR=7;m1M|mjS9@D@8xy`J7ABnSL0^}= zIajhOIn;Do$v8vk9D`N~y;3HrQigmk5vyEw?wLM3+eoS`t6WOksJmHra9y1PL@N@?lt_MR8;`|ykZ|JPmjuJxYvo-=1=pFR7`%$eD< z_kLoe_h=F} zoQbxKZ+cJy`+enmYxlw;Q>GO=G{apB{nuXqPrB<{t?^%U*SGrPd;6uF|GejOkEQz>x%;+8f92t?YU^MA zsDP2tFSk+9Xz>5q$cXdTMkvU+71$@eRm1{ktblJT=m7McAeAW#P*YaGk{`LAq^tW36us-L3&zFV94VH+)OzEKMGF3)PV!g8gl^JSv_Jlkh&Ihn-$n0 zW(RyyL8Ul=Z7yzR&f8+3YaqKGa2J#nu%TxMY_e`B0mXo1kYbma33xhiexq&%ws8R! zH7NOpaUcU5U<(N<1^Nfs9sf$dsVL|gC=EL20xAv4_v=0=ofS}8vjPT@Ao<+f1JXcG z2i*f5Aew;OxLH8Y1`z=y!3Nk#0-9&QBnl7!Gq5!RumV_E-V_JO-`|`Ds`jU9_dlwV zS?&$(_f*Nol0SWW8m?y`0d=w1cLPWFV=Rna&bHU-7rdhHI<*lp=2Mnl#ZC$K4NedhpBFiQp82jL8*THi z)b$=T3?9so`z3O{fqVF{%5C`D8T<~Srd#1 zVV}04KZ1SrfvVIOVQC8?i7TNZQa-g$P|(8&<|k?xTu5E`#o37$B}@mTfV94VCH(UU zuNCRJ#ka5V9e)lirat%hf%T-G?W#KOAO*qadUEBOZR^ZD)tAFvKAMG_nt|V4&a;%1 zn^_(wP5?Nk^B`m8rYDKNl#iiZQd)D=`a~l|sQ|Cu(G!4Ogs6pH$HXm#Q%7eP&PT0B z$Y-nV;83GWh+m+Z-IvHLnirOkl7z)dmiR43K$O{4*`XBVOmX!~3&ql$mNGd|KW$8b}D%&gd=KdIkv!bX7)0V53 z3sSVstr+F8;>VP>P2*60A4pM&2-O4r!I|Q_FnEIOCB+eo+ins z@+C4XdXCJeS#!KN)Um=R(#v-6>`alU!+KrL~to9A^caYRhOp^iqs6C*@xx{ zxx)M;Po#ZQ(%Ra#5rpU* zT8kKv45E=EK{68Tphbq_dPYAOs_~`j7)6JcxVA+BEcItwtM&2l)>^-m)Y_VqRR7x6 zR)7E2LK;M^N8gu?4NIAX1gH9%p*M)Qk4M*>P%hekdc3nAigj=`2W zHvWdU$qg3UV8O5~tV2cK5KLX>fr8Ab&!nPFL7_5SNOGwkX6fW+DgWldDFtjw*WvK7 zX0Hwtff)wl7ux|ZcF$foMgLN|49YBOFGaVGIhO69@P`eb@GCrfC9HU-^KmQ3CavZm zor|1`MTF;!alLm;py%3JD$ zonzVI^af9D^2sQGJTnSXmMp{2hA%p|RSb_eG;|83SHp))U9jJ4`{*4L%!K?>S8g}# zk**NZ!=SFBVdi1x^~VpzpB0xQRTi{w$=OSz;H5!IN4R*o9@Rq-wKhF>hsEmb*I~me zDVWgo(U0nelnOxwH#jur)yGG^Y*Exxexv?Tflf=*|A0ofzE9BO^5A6pgalP(R%-?} z`Qfab=@q>s zjhP`r7(XUH=zpU^iL|=@R?py`Z8TuhtvoRrUtTZ*1fH25K4#NMqGMH|366{`)q^wW z5t?Db59F`#<~?_1Ludhm^i6PD7=vaIJ+&i>kyS3gfFQhHJ5RNs$5;<94Ohih~?n;~CrKTpAcc3;-&qICmR!b8LAffOqJ z{u#M4U-K~$v=5EfAuBa|$p#)QRESqq*?6=J;hJdWG3A&xS?aa5jXBR4okgt8ibfNR zVp?!D)vLIv*yV8JP+={Y3#aQ{KDJwMyaPwO8riaPlo7LeqAi-Pc{n(M?{bJv)PGs9 z^mx;D^ZQtBfgurokf@gEGwCgB5l^9O(iR7cxmGm$zr&z=R;(Rh60WF@(0Tt~OyUU)iicie91RI-I(s zO;?g=i?^_M=|5(*_I4uw*n~FOF;0qYS_j4mPHW}qMV6-9qWZRdg=tpTS?NuT$qAJ!6 zlgC~0&AOMPF*r;M>@J&)9mdfKjl;(*GEh?Z1=w_uT6x8NPnjoVdR~JsOlUIh_9AnA z<0xqVVkm&{@MR0eG4(Z_dR0(8-o(o{h1y$3>f>i^t!;>$mYaBl0croIO8#KC`Bt9D19APWe5Tkn~u}MI* zi+MCjKlCChY2w-CRR$h*n3iXGAeP?wNJ}e`^jtl`#o*EFeD9b>ond@bQX4{;kWBpwePjRM^kTd^L!xrPKHX+OT zKUzi3Dn?k$NHZ+Dr zBH3g|!=9idh-FBRP^NOWOzQs(qDPuqmn;_6i{49?Orp&y!EH5lLevIfHvqcp?BaXX z7$nEjI7_`nDJ{IgufnL~-&(Nt(RtBujcHYqyT6LL!|8|W@!9Xy zohC40W_y}9@cyi?PHoeLaK??QK1SLia3pv!l3UtUOg)5c-TstZ%;>QZgh67@48$;s z9z#JYbNLzET%KRR$I4%to?GUp8aR z**`x-Hx_=%C*s@IfSwf48d|IF*=n`itlBo9(*j+>7#6TDN$Pgt0Kt7Z-|PM^?q%7) zaMc2}tvlQS~&Oy{B3(XL7~+4Ff(7{Y~; zNrB~hzI)6JALr>_wZ$X1I1QC!NSqVO%TZ%)_KG_;WCrh@!xv^q>vm z?tHgc%}7(l7Y_4JS{e+J6vzj>9E|-Rw1i_A51_9n1VtJTTx>XWy~N{QES^i&aPQ;A zI>$%A(dp{wZqe*IeFu#bojawR^WCbFLz4%r;tVp60x!a8UT)&4G%J}_!7gX0DeGi1 z*FmMVwzof9sTtB*1fFc3iQM~LUvSZIk1l7dYgwCxQI#Hh+ZLp{7?(>|Ik=pvVA&O} zpgLdtcx3(M`F5;xaD)ptDYOp1_1F}4?T1~{+_a*RW%Gy+kG#GzZ2EWTXy?&{g1v1^ z=Ca`#Oy*MiF%z)!)W}=x^=wr8?5;z6K$PF9RhC;$bpxR*3iSvYc7|+Z!clXgLfh4l z%JA6K*wlpSv}vgbMHR|HEQ%GK{L6MjOSYK!7q9APn+&WFn1i%l_fdU=v8$Ie{`$WB z^-GCycpyrnclbuz`j7;4L1cL{eRbtdzaG zEY&T5c780Q_n54{aeHj+Z2z|9!`$ck@xck%#%D#U_R>WQr57`soh)F7nX+vZLk*OlIYi$wQ zJoqxzBZ9e~0un{b{MjlFaL1<``@VEUuAhm64!^g^wsk~q8yUwFHhi8@OcY7%-1Oau z)+RB*T)|qlEJcIoL{sc?NP~iLG)#V9zLl1$)Y&rDExWNa&-qC96}Xm4;zpN~SvCBL zgY|?EycbNR8FCfD0PYiUONvqAY>|gZ8Dkb-;_~}UOhQlQIib|V_@>}d8u+Xr&2WjV z!f4@X+1NvowjGEXT7?E+aD2(gv8+nr4#J#B;3JRW-bv_TbxNu0ag)ZY+BOP|ZLAcH zxr4v*5E3_df$WAa=(VZZnd5+2Oe3K4%yTW(V9N(LC0OH!eSNi2gApZP&|F@WM$~{H z^GWM!Z=j>T`L&2!Q9&}q-~%s>b*BwcQVv^bWD0O6W2d&1A&9)V2eVM8QC|m7kTYJ) zGzWioKtm!wWEA&twU~^0$!&EG?dC)&xeJ?^vFKW>)$h@KmgN$RDhyjKLO^n=n@_1tULrGH0*waX*B?aN}rYHFZ8&ykfI8 z8yrt5xyzEi;N6^DQrB=;IM*8$KeVq0oF{hA`k^=;=zD@`!kOV~IrAXSU!a|)!|#}G z!BLg?I9=^?zNjaf;mYYGRh6J5mV2X4Z^j8Xrfyq30nJfRgzs^@e?c0RD?rS;^t3f9 zg@E71YYqir`8exT`T1}^s(hRL`dm0e(KHtK!<{r0GP0aD;U|)j{oPF@4So#B4Al`b ze05$_2B|H9LxhUx=N)NgWqeJQjXIuH{nHCGw%l-Aitrr9w#=dC!GhKv9U=h@k}-;6 zVl8F~O|}AdHE`o|Rl{;aV0b{Ggx&ucDIn{kOtkbyk-X;xG#uidG;gyA@ zjKaYDfC;WMNeQJ&PO-z!ys#wtIYFXy58@B#+OLTLxY#AgkpjH}z2paxSslucf5hUS zUZD}O;SjV(8P#^wV9v{B2<{efyXtXIq>Y*|PZMC(c8BeT%M$unvd#MTOHmTiR-56~ zVqw75_qjFro$&YBAnzPp#5?3RGl-B-JPXDUHRI@oe}mp1F@e+ctzGwr4uKi(1d4{p z!mz{8DVUOHxlvkPMwV06G5DIfis51Lu=R8A55k?ySw&S^_?eapI~{Lq-6bx_2Xjbf z=gkL*PC{4``aZ6;!WIOw$eBr)H5BMaa6bG{Rwb_S-pAc=99+o0FDeP!AVz$7%<3cL zl#>-ktVCR8I`UA-c4eIOLeR$zjUO^&l5guZQL$m|MXjpy8Q?=*J)&KI5c;(aZCK$* zq|4UU(WlT&t*jBe32`mcb6RsaI|hS&?&Y$=PU|UAz&{hh`kr*2Q3Do$oqbb}J@BE?)!?Fs2-AhrX~kXjvu_anig;1q7OwW& zz#Q%m?}QgcKUy(lbtBZaz&?m>5|_S()Dmmd!Xgq z#RvY~6T?U6>vduRdkLY=M9%qojB)G35iS^pkhApGXmhzcii#+$X8dR_ROceD1 zX=3llfLl+xB{0kO^xd(PZQQ4In>vj{vIB62tP+R4&P}mB>4~(r!QGq%8E3$9o7UcHN0-v6oi)C=r-w}D7@0;`kE&#m1=jB6bv zM3wkR{3JDnhRe)&7Tj&io>E&|D}`pHQ+x*emkP~sD^f1iiQ36qev)tDKRn1wO6-8nDUBY$tumsK8#V&g#(e{Pk1DLtH){@|yCG3e&HV93{JCr_YV=K%a*!ziA`hx}3L&0*D;O&OH2X0n4pQ zn}_^EM%-GXlTN#6c6BaBsArh8OwzZ&mfh3zvQ47>Q0|#$Jb1LVHSg;p<_VY3olBMM zmi1Cu(P5&|D|NTp>paZG*tt9}WyQ4iZ(1AqD|L86;rj>SU%J~?6tE8hh?GZhhLJAggF5)^=y9sA zCfOY(p@M&e&zPs4W+6_6Z!YegV-n&lo;8(yz+2od+Jekn*~^A^A35`)3O}BU>2o^t zBg$LH<5oRKj5RiC7J*o+AO4o)3!xkyM6}KCX85`g^`JcL{#ONea$2(tf^I>zUO&8g3}Vu5zsF z?nhh^zskf)#rxQ9z<+7_u_S%1p&F~Rh<(P!Hr=SN1^#DpP~)a2*>I!gDxm?)Pea3H?<;}LDl1brR6po)O;f8Bi@Q=HVaXYnCu;rd}NP!qOqac=qh0* zh_kJ~Onbp`LI?DYU8>8d;eqduJ>MGK~kdJ*~M z_#u4Dwa;=7XSz?Yk-vpOxeO%|l$Oyt9HfDhkcUm-W4uct>UyxZv#mSW0^7$2B|kI- ze6$~WBN@EI4n5zvn8NeU_6PSCSVChNSVO7&%3l7OV?52$JjEh;i9oB2z`8CBl?5Vd z;lhHe(dWeY$j}tdoa3yZAeiUTrVWqy{_d941W9FsAx$|}T+G^#M0V>=M~a^{vAMOd zp>||C9dydeGo7cDZEBPiw7fBO;yV_vS2siX?9sZXr%R*`3`uMV6@6`Uho&q1*u_c_=m*33?jx}#t73q3~iQwn!W|E5Rwl3!5khhi$kuqu1}q6G}`flUejvLnv)Qao zfCMsuVz{_aTQJ%a>sa(vf$gJan}){-f=77uTHR}Mm*|!KtUpsmJX*%nvHB=--E;W@ z5~c{6`22jcg$>ea8H5zd#G9*P4RqCwpwRR4%iO|0yic~6%fVZeQ^FFVf=TPs#R=HW z*gSb|T^tZ0cRjdFi<-TMV>kH~F)(ZaF;AibmVZ#rd#hvWxum%8lMeZM z`T4AJy(zZgmiYgmXvg*i8Gdpk2oNH;Qi^KskX9<8sLw3DVxzk z{$rD*;Z2e@LKIyNc)t;AN~?Mle$i72wWI6W(6ejr6QQ7PoL9U2o3od%j(U90)SEHC zIlQyQKk2Y@oFKr|rM|GH^h>b(@LpEmm=Ubbfxs{%f}?HbC1CiyWxbPMY<+NQ70its zEfXEtje@wBO)j_*`_`HSuiP_|gQzHlbA`pgo)ZN-&FFo7cVLJbAB5mo{L|=X^3K9B zA9M|hKMq*Qio{LUp5et&^ssxtmOf7J?LH!ilQN{oS&cK9R+9^9x@pt}_m;&9l*F)ZTYQ*dNJsePSv3u$&kM>1*gRx~V*5Iu#Bl|!D-smnsr zk`R;k$?KRgaZwj$bzD)UMssq+z`HO$aahE4eWVc~L%7>ZYSpgXdleL9&KjT2EENCske#4(x-^vMA4}>FMZg&=Y|lx;@2{pl*=2 zehkjvQ;LVj-Q1{Swr0055v}9R5bFuFX{@HK zrtk?@MV>5bz>*YcYUO^-G+UttlVbgx`u24cQ#%#L5331kT^T<)ZAaq?ZJuedoC4H_o5V~EgZ;J7K# zr=3|5gWU^Bl^JoS#N*oR%aqsgQO1)JVB;@qMlI@4q3T_YF~}gUvddDhgF2mG8`41= z9T=&+EgHuB@CmDBKa<)pRGK=Flw;224CWeatCBRuSF~+bOzjk7#yQ-}9*+#!DCcJ_ zRwKbOxF*Rd>}R> z|CEf0qR!psr})peqWI*C0h9gwW${if*IJ~cGmY0QTTmK?w(8Q)>^N}LVm4T(rf_km zX7q;Zh47JK#o_wb`^G*ntq6MbHBK70R&^@CiwE$#7OA#;oy|10ug`XuML3x7st^;; zev5(oqRE&v8bE z>Xjk}d-w&CX)k$)!_HBTg&G;_M`$W;+eq-eFYIABFDfU&?O!(W^4Qt4CCHhTb=z^k zKsWflEa)_1ou{9QHfiZZf2(c=+ey$cyrUU z0hWTyY(NxeW>9b~z|!b04j16k4VVW0TOckL?til={7-?nZVWu`xpd!{nEYl?2-u?h zZ$>8^fMwDjmLB(vPF&u~*-r^!h@V_zj)-TP2!HB4KqU>tkj>R(3l&jyk=Z1vz_sb+ z$Ui+HxOkLH69&1^=ha$!0@ql;$ha{qs@_nm^c*itWBly}k4whVbT(XZF_vk~Y<0S~ zBZJdq$<(*-xEk5lnXlK!i zO8K_4q=ON)Y~!L-6(Y$R;7q~b+l7#w_jR?J#70Z_iiknNUPh>QX*in03LCrBL<{Hs0tN;<1?wX&+G3CT%t)PdewGQu5YKRBja5Z@kwfUX;SGNtyr|(tlO@P`G%Hvhf5f(j5xkG& z=|?#PE}izoqN*~G&?`*D0#=;AorL_u!!Qz9>c_!snZyv5T_Vsm0d#>cA0aD&_mil0 z=EhnmS-knDLsmmJjyzXVao_{YLsK}@XlKkdY3F=lz-j(Vq?E=RJK359A#x$CRxS%N2ZCS6!RdH!kYvVR&lf7J`C-?w4gqO z1ZoymlkBd(*9oMoqGpLef+b6tN%o%kUe13%ynK&~H{O0Xm>4k;IA!fj2vy2KkCu%P zNR{PcUWqa37?~B^`kub(`rVQ$>!RiuKF=WJYI)67UcYK&ps**ucC7Kj)Jyl6fS)ly zkWKjQKSj8@-{k-7-S;e@{zrSlf9(1HU{uHjGGP2`0JEEp_j_0TuXc|AW>ol(jQrKI z@CJ(D)*=4J`tSdfL;N4G0)QzV$n=dBaGSmj@Cn4b28`bTOTB+P0CPD|mfPGw1|oS?hY`?18ngC+dvSDAR9e)VDM!Fj0SK10a396+=9+Q2MZ7bR}bLhCM);NB^M9| z{N^@boA@gmD-gAnm74=F4+N?RA_oN2xO0KOJ^j;b9Po?(-$q>kT;$I|_ui;${PZH{ zbb3>0@#lH!0|G2)k&LLEZyDf5j-GU|k5vtfXPBxlczw|1ys9fPlrF6%@ zHb0r??a!kVXK`7%&CO~C*Jh74u1>ancN#7VOxnIgcbSyF0;iP2#l+a+VDJ%EbYCh| z4R}@gX(Ae(C+6|&_}~32gf)|!-KV{uLOw4 z;$ss{hMwSji5^joj*x;@@Kz;#ulYKbSz)jv;&ka$EBKVl+ssP$dGJj9qmM-V)GX41 zH1uP+MDH>1QmsP9z1&xif=}JO(}&{)CVG40xjR|ujiWTc%b49M8aY|q6UIFva0MB9 zjBO+pcdNRdDlCd*2$0Z=5@FjXy?bl3%hn2Pj}NkSmP!w-3%4N@9GqLa@dyOOvNv$upr_Y)6f>_j-s$2_qJ=&KHui;(|$;EFfLO@H4tQE4u9^7#QI3VxWu8b!e$BDQ4!A(S}yhn{b1@`(>HBY zBAx11*yK}RN94DBWfmk9HXF-{c7?xLa@9A`y)r+RY(p$!xx_r$UpIi%V8(#G3Kivj zOZ(aO%Iu(F;jk-Y5VKDM zeD>J}xZ%?Fs}3kl^c1K>1hW%A8WiQDdg{rPDUqz*CaZfPoAr1tlVcVRj+$>+Z0TF$0Ze)}{uP zsa&#%0Gtw>#jgugFSpYv@Lwd;BGE0&QMzYK_6$zEe()Tl2&35Ur$18qc0%eaSoRdr zi)H@G;*CcHvnr^m@V>80j8lHVXfG(n3ROxxGv(m!~m7dnmFqrLp><7UCT|qwL~%3zBme zJ2kkg{COu+2c0ftq>*q&A*|QD^(M8wLaUiDX#qE$lxJbYJIR1kmO*wXcotflgOp!-#SV!)ybWucJZA(3-j92o& z_AQzRlO_df!*V2fR+qWVm;5O3vDlC_W7lt!wPRZxhB8AhG}f{cA{2yo{k8%gBR{QDb=6S z!`iDO=)q-lT|>nLN_XF7GRPQ{C(PQ9Q)tbm9igpxmgsNqns>@fB2Tkl1Y zmql5;@%cFSEpvA85wz47yb+4ElQ^g=a%%gpi1Y%@aA1OyQs46kTr`CsRuy?{NTAaK z#7G%CKEbIY(=N>9Mdwv2@(bI$W}nHNTxrI$fKeSIwa zl8h7CkkT|EZ25 zJiFI%(gM4Th++Ucel%*%;~d1GwO*>s{i;A8N`z%LbF+b@3rnM^lveHBE1xH=p85p# zQPi$QWwn0CTyRiwIKgCa;?pNfTQJw#$6BMo`3S5qYsw^K_DUpz?T$Nj_Smtk;%l0^5}E4PT#WvJHIQN(-RIlt`E0EOJmN&-0hqF zkoR@z8-n>!`dp$dQ9XNKe{YxZ4_3X^{B&E~gYo$NA<0RYaF@H{aRznY)ko4UkcUKl z!R1hlA@f7mL<#a1^BOF2c;SDD!@Sx}3{p|Da5IDX!o#rFbm-rWV5>1T5Nl$Z$&dj5 zT<9z8W&{UCC(){_aQD7{d)*XcEm8pO%-3#LV{>jSGkA@;FJGO!aPXPd90{4lM$BIg zBEZa;D)ovIsI!_TUWbG#>xjBhns~k=4?4bnF?EQq5I|1to>?IFg>yS5vt|SlO)D0y zD2p!ztD)g}ZXGm($X*T}nFqU`PCP~a`p{PPCKxZ|dEye+w6H3F(Sc|4yX_vqY<>ia z$#xt*p<=0C2R;pQUsK)AIhC`agzqk7RFMMX9~MUUoMj1kzRoA`OcLe2SyWhfB640* zrN`Vi!QAqapL|ju;VEo>@Z!tx0+0M9k;st_>noC)rwf)oatx=`#RGZT+Jk5mmkwaI z&PE7h4%QYmOyvA@EL@Aatz`?f$Q3Y#=4RKrGq#A~+7=AKn|u)4y)@4ozH2=-9e*mI z;da<^*3*ALmT=0-#s2LhELAcNa)x=1!d!`e=qmr`Llj4wqN2;XMPN0Re9=n_lG*yPB3nf0aq zx?qHWmdJ@fxKQbsR(lafL?}3M>U~g))e`JE8H7v++c_?x)LbjksD?i}%S-0KWbM?N z9VE`DUH$NM?*i$Sm(-6Mhxpf+ye|dCZF%)S9jR1%@0iX7sIVS&q!DDy(2~&7yF4TH zs^gfkvzqcgNZBT^UEUkT-GV%S_Lgc)sdL0zX-G{(Yxsq73je}%xa5|ElVzuQoUEa| zB?~XOMRZvzOhF0g2gdS4~S>K~dtTc}aE*s=sKjB<( z^zMYU2C24|a>c`DSf|_hHjmS3Y+jVQgPAm$clVmLxQEb%(ylnkRab}W%2tOtqm zNiiN2#1&}|_$Fj^$tTo0Gh~XacbuJFO1QqjV z?K)-`aF7)m0HIB0}O3p8n%DU!cZG^D-r{(AUNM(PjSwQ*`M@t9i-|-BD z)zl`cRrhf6Ze0B_VP=9`Ix>a-={ZCq0woW_Klx?zepFDz7cxv-oXl> zY9B7T;0-v}XD~IaY)00ce~ZOf9u!B9kO;5gOYJ(uBbD>i+)A0S)``FWouiU?uCXyn4MkHM&4 zgZB%u4)w%{LA_W>=~<^Y}lI+pX4Q7$nq$$_IVJBRz>XSmO3z~Ks+vfC(A zMO!6PmE#b{ByIS%>2Z(}cm{?9Y=rV7ieCx-#Uq^v=3}XHZiU|wuWH19RNHQ0?vGE* zqPvOGh#GL#=i$Zun7u}2<}1dpFZ34-FV$N5hyM3p!)yMJTF!s%n*X5b1U4!DLDTuS zII=g{{$ohef75jSD>Hx7cHV_j0Q{(LG?M?Hw4L|+{OuSA!WVWT2F4$I7ZA7#F{6y7 zi4&kXyp6fd0@6Jz6SIO|jxxyQ8T1FJL~s6X-OTTzbKiM?-^T`K{sX!cG{oFKPQk_5 z#?lUWA`l4P(aD(@P=A7GG0GYO7oa%vH&?gJfLwJ!4Fx3m+gpFU150NB+l86^R#D9e zp!MEBLIHIC06D&86~F;Dbp;f=xBTBH_uH1)9l5(Q0J$4Lt9#_`2;7ll`+CcV!6SoyCZ%l)xV16me)JZ@00s&0J@d(4JO|mxjQ-jB6riaLA>8IFd&TX zJzjq`S-2JMeEZ;lBOkGv1NDt;CpKw( zgW^H|6VrFJZkfJE3sl?RX#q3*8v+2SJMsPMG{3d5U!Tfb!oQmQZ6p6xf!iVG?w$T> z7(!GlOy~F-uSC|-xIC5VmzfrndirfnOhM)UQ z`?sye+fn`3S_UBddk_4b>|Hf(#Pc_9Z}zl*7yGYy7C`p*&i6anyJmAk_HV1G-(sNL zaeF63fb8$R@E6%zN`LKkH+O$$@YlAtFc4biH*wxhtbk^HTh}|G+_r=}lbPGm?oPVD z8Uko{^pC;r=4JnSAPA)oH0ygTW^YWd;%w;XObyuk+&uKLq?x_Fvz@)ODF_qxZa94G z08ATiu5asjdkrAD-hESUuK|?R8?aer;@fKg^7L-9a(fM6lHSeRZm$8@PGCzL)NpRE zIjKSM+W)-fq6Px%++I7~A$@{ax~>1?Ur7KLci+rEk^n~TreJ?0fq1#2{i`6r&K-8! zAGrXIZX%ci969}oj>~*g^IxU!r-LN$i=F%F00Va)-rwl}T-<%se@_Qkx%*JvPrrec zzne|`o(`(>-=E9E0D1#|=aYp2c<$W{=yy86bMNM7zo!FoxS56iE{7Z3=(}m|{roqG z&Ucfb-_rqp?k4T`({Ip*?{Id0PY3FC2gL*EOJpr=EpH(9?zhsv<^O#Ja(}q{qmkcx zmFyr9-9c9UP6`mw4OGhSRc2=ZwUWC=`WqckQ@QO7zp?sT9^hHOKLjZBJHMb|;a8`; zTZsVynr_-W^IdQLjr_g-`d=u6I?gZ3z)~0xB*>l*)Vb~t3ZO>xE7$FcP1F#8)3gV0 z5pP$Dzb0aTEad(ijBdsd=3n11Swj$pps5|bnhNzzSvh+U6t0?+>93-U3J#`r!p6>) z_IAWNcV9jUOJ}{C+_Hv7rZ!FhMj@lTi>;Fm6L6x!C?+7FCm_HmXXD@L3ufWjGzN_&cPvYOB$$?7ytka z45&PSwvUa8m6?^93pin=XX2z{VxppE1jO;5a{x{T}_DrE?B9l@4f4r zDe5mt-7U_ItW=zBfzJvkV%gmS9TYt5KZ3S#0bl(;ZGQf=y6IP!v&Z8^so&7(W3G4T zJ|oqF1WT%s2QL?Tnj@qw3ZphzE}?5nT%>a{yHd3DTvL5r4I_=)T|-oGpe}*4HA{(H z{%v%$O0;A`RZCRnyAoMSO}A1sYEwsb>7Z}$m_4CXbgG|HBWYMmR9xJ<99}=gs|iYu80)_`L1yY@viYh>fJ?Hj)ygv%5`Pbd46wk zs4qt!u1^?@QHEVrv@o=x4q#Sy=ynGu$&f&ZGkglt6ap{S-1RML3zLOehmMAx7N?Bz zM$(T8WOe60Hs5vJWSldVEb@!PQx0Z*D?;jyIEwD>(XJEe*jC#SN-Isw;c@yp5&LI@ zZJvj~1;ijxjrc6XIi^~!lXSmj?Rs(Sfoo9uM{FNE1HC>%w{d4AUjI}mln?3D#K~)O z=CCkbJ^_N-bUal7iUDV?$<*K0<5!HJ#U_tk1M4@k5F zf98zxK`77#;;V>kK5{;lNmNew(&RA{kRpZ@_IAv8x8;+yq>^M=U|5apd$M$ra~yVs z8f*gg&cnI2jp7aA48%3wPXrH%L|(IZI*Kv{6!1KF5^_GXSl76UWewMuBrwfKcsY4u zuQAKnpP$-4>+DZRHB?-!z$=g(g5;Pyh3Rh^<+~4`49W&bJ$QW}xD3M zJlltR*kY(v{)5$-5JaaWHa}ls3YR2AayiW!gd{93%xAiBJP>}Ea0W3@NIIX)6e8ND zo7u{%4xXh5{R1WF5nVuFwMl(t6?pU~NE$-&+?PSwXP1@L2dC4S}C0AA{L{mzaQjZx~+feZih&?Y*$> z{j4NN8xcm#^ChKf5BUg{SoVt^PL`Kx@7EXL|e|wkgmj?$6yyXBCigy+JpJx$|c7yx)A1AHcFFqjXNZ2 zA+y}}8!%yD-# THG|`1W@BN7qo5F1kbwI?Y{mh= literal 0 HcmV?d00001 diff --git a/Assignment2/report2.tex b/Assignment2/report2.tex new file mode 100644 index 0000000..4d1faeb --- /dev/null +++ b/Assignment2/report2.tex @@ -0,0 +1,421 @@ +%! TeX program = lualatex +\RequirePackage[l2tabu,orthodox]{nag} +\DocumentMetadata{lang=en-US} +\documentclass[a4paper]{scrartcl} +\usepackage{geometry} +%\usepackage{tikz} +%\usepackage{tikz-uml} +\usepackage{hyperref} +%\usepackage{caption} +\usepackage{bookmark} +\usepackage{fontspec} +\usepackage{microtype} +\usepackage{minted} +\hypersetup{ + colorlinks=true, + urlcolor=blue +} + +% Math packages +%\usepackage{amsmath} +%\usepackage{mathtools} +%\usepackage{amsthm} +%\usepackage{thmtools} +%\usepackage{lualatex-math} + +% Unicode Math +\usepackage[warnings-off={mathtools-colon,mathtools-overbracket},math-style=upright]{unicode-math} +\usepackage{newcomputermodern} + +% Use Euler Math fonts and Concrete Roman +%\usepackage{euler-math} +%\setmainfont{cmunorm.otf}[ +% BoldFont=cmunobx.otf, +% ItalicFont=cmunoti.otf, +% BoldItalicFont=cmunobi.otf +%] +\setmonofont{0xProto}[Scale=MatchLowercase] + +\newcommand*{\figref}[2][]{% + \hyperref[{fig:#2}]{% + Figure~\ref*{fig:#2}% + \ifx\\#1\\% + \else + \,#1% + \fi + }% +} + +%\DeclarePairedDelimiter\ceil{\lceil}{\rceil} +%\DeclarePairedDelimiter\floor{\lfloor}{\rfloor} + +%\declaretheorem[within=chapter]{definition} +%\declaretheorem[sibling=definition]{theorem} +%\declaretheorem[sibling=definition]{corollary} +%\declaretheorem[sibling=definition]{principle} + +\usepackage{polyglossia} +%\usepackage[backend=biber]{biblatex} + +\setdefaultlanguage[variant=american,ordinalmonthday=true]{english} + +\day=15 +\month=3 +\year=2024 + +\title{Programming Assignment 2} +\subtitle{CS-420 Spring 2024} +\author{Juan Pablo Zendejas} +\date{\today} + +\begin{document} + +\maketitle +%\listoftheorems[ignoreall,onlynamed={theorem,corollary,principle}] +%\listoftheorems[ignoreall,onlynamed={definition},title={List of Definitions}] +%\tableofcontents +For this programming assignment, I was tasked with creating a variety of +functions for different purposes to practice functional programming +concepts like fold/reduce, recursion, and function composition. In all, +I managed to get a full score on the autograder and I felt that I had +created acceptable solutions that are clean and easy to understand. + +While I didn't work with anyone specifically on this project, I did end +up searching for help online when I felt I had hit a wall. For example, +I wanted to use only one \texttt{foldr} call on my \texttt{sepConcat} +function and I was having trouble creating a lambda function that would +work. I looked at some +StackOverflow\footnote{\url{https://stackoverflow.com/a/44101237}} answers +for some guidance and I +found I was close, but I just had to re-arrange my use of the \texttt{++} +operator to follow the ordering of the \texttt{foldr}. I also found out +about the trick of using \texttt{zip [0..] xs} to get the index of each +element of a list, which was useful for the final problem. + +Now, we will look at each function and my solution. +\section{Part A: Basic Haskell Prelude} +These functions are simple implementations using basic Haskell prelude +functions. + +\subsection{myMod} +The idea is fairly simple. Use \texttt{div} to perform integer division +of x and y. Then, we can multiply it by y and subtract that from x to +get the remainder of the division, which is the modulus operator. +\begin{minted}[frame=single]{haskell} +myMod :: Int -> Int -> Int +myMod x y = x - (y * div x y) +\end{minted} + +\subsection{toDigit} +This function uses recursion. If the input is \le 0, then we just return +an empty list. The recursive step then splits the integer into the first +digit using \texttt{myMod}, and then the rest of the number using +\texttt{div}. Finally, the digit is appended to the end and toDigit is +called recursively to prepend its result. +\begin{minted}[frame=single]{haskell} +toDigit :: Int -> [Int] +toDigit n | n <= 0 = [] + | otherwise = toDigit (div n 10) ++ [myMod n 10] +\end{minted} + +\subsection{reverseList} +Another recursive function. To reverse the list, I use a pattern +matching to split the first element of the list out. Then, just prepend +the reverse of the rest of the list to the first element. +\begin{minted}[frame=single]{haskell} +reverseList :: [a] -> [a] +reverseList [] = [] +reverseList (x:xs) = reverseList xs ++ [x] +\end{minted} + +\subsection{sumList} +Follows a similar strategy. Pattern-matching to split the first element +off, then add it to the sum of the rest of the list. This recursive call +is ended by a base case of 0 for an empty list. +\begin{minted}[frame=single]{haskell} +sumList :: [Int] -> Int +sumList [] = 0 +sumList (x:xs) = sumList xs + x +\end{minted} + +\subsection{toDigitRev} +Just a function composition. +\begin{minted}[frame=single]{haskell} +toDigitRev :: Int -> [Int] +toDigitRev n = reverseList (toDigit n) +\end{minted} + +\section{Part B: Folding Functions} +These functions use the \texttt{foldr} prelude function to perform +operations on a list. + +\subsection{myDouble} +The idea was to use \texttt{foldr} with a list of the parameter twice, +so foldr could add them together. +\begin{minted}[frame=single]{haskell} +myDouble :: Int -> Int +myDouble n = foldr (+) 0 [n,n] +\end{minted} + +\subsection{doubleEveryOther} +This function did not have to use \texttt{foldr}. Here, the idea was to +use recursion. The recursive case would grab the first two elements and +the rest of the list. Then, the 2nd element would be doubled, and the +elements would be appended in order but with the doubleEveryOther +recursive call for the rest of the list. +\begin{minted}[frame=single]{haskell} +doubleEveryOther :: [Int] -> [Int] +doubleEveryOther [] = [] +doubleEveryOther [x] = [x] +doubleEveryOther (x:y:xs) = x : myDouble y : doubleEveryOther xs +\end{minted} + +\subsection{mySquare} +Similar to myDouble, but using multiply instead of adding them. +\begin{minted}[frame=single]{haskell} +mySquare :: Int -> Int +mySquare n = foldr (*) 1 [n,n] +\end{minted} + +\subsection{sqSum} +Here, we use a custom lambda function. In addition, because the last +parameter is the list, we can also use partial function application or +currying to omit the name of the first argument and make the declaration +cleaner. The lambda function just adds the square of x to the +accumulator of \texttt{foldr}. +\begin{minted}[frame=single]{haskell} +sqSum :: [Int] -> Int +sqSum = foldr (\x acc -> mySquare x + acc) 0 +\end{minted} + +\subsection{sumDigits} +This function needs to add the digits of all the numbers in the list. +Here, the custom lambda function uses the previous \texttt{sumList} +and \texttt{toDigit} functions. It adds the sum of the digits of each +element to the accumulator. +\begin{minted}[frame=single]{haskell} +sumDigits :: [Int] -> Int +sumDigits = foldr (\x acc -> acc + (sumList $ toDigit x)) 0 +\end{minted} + +\subsection{sepConcat} +Concatenate a list of strings while interspersing a separator string in +between each string. For this, the custom lambda function will prepend +the string to the accumulator, but only put the separator in between if +there has already been an element added to the accumulator. This way, we +avoid the off-by-one error of appending the separator to the end of the +final string. +\begin{minted}[frame=single,breaklines=true]{haskell} +sepConcat :: String -> [String] -> String +sepConcat sep = foldr (\x acc -> x ++ if acc == [] then acc else sep ++ acc) "" +\end{minted} + +\section{Part C: Credit Card Problem} +This is an application of some of the functions I've written to create a +function that validates a credit card number using the Luhn algorithm. +Double every other digit of the card number starting from the end +(reversed). Take the sum of those digits. If the sum is equal to 0 +mod 10, it is a valid credit card number. +\begin{minted}[frame=single]{haskell} +validate :: Int -> Bool +validate n = myMod (sumDigits (doubleEveryOther (toDigitRev n))) 10 == 0 +\end{minted} + +\section{Part D: Sorting Algorithms} +The task for this section was to implement some sorting algorithms in a +functional manner. + +\subsection{splitHalf} +For the \texttt{splitHalf} function, it needs to split a list into a tuple where +the left and right tuple each have half of the list. To accomplish this, +I first created a generic \texttt{mySplit} function that splits onto an +index. This is accomplished by taking in an index and a pair of lists. +The index is the number of elements from the right pair that should be +moved into the left pair. So, every recursive call will move the first +element from the right list into the end of the left list. Then, mySplit +will be called again with \texttt{n} decremented. The base case, when +\texttt{n = 0}, is to just return the pair. + +Finally, \texttt{splitHalf} just calls the \texttt{mySplit} function +with \texttt{n} equal to half the length of the list. +\begin{minted}[frame=single]{haskell} +mySplit 0 p = p +mySplit n (xs,(y:ys)) = mySplit (n-1) (xs++[y], ys) + +splitHalf :: [a] -> ([a], [a]) +splitHalf xs = mySplit (div l 2) ([], xs) + where l = length xs +\end{minted} + +\subsection{mergeList} +This is where it starts to get complicated. \texttt{mergeList} is a +function that receives two lists of pairs that are sorted by the 2nd +element of the pair, and merges them into one big sorted list. The way I +thought about this problem after talking with the professor is to +consider the first element of each list. Then, I just let the smaller +one go first and recurse. To accomplish this, I used a bunch of pattern +matching and a guarded statement. Here, \texttt{axs} and \texttt{ays} +are the whole lists. Then, \texttt{px} and \texttt{py} are the pairs +that I should prepend. \texttt{xs} and \texttt{ys} are the rest of the +list without the first element. Finally, \texttt{x} and \texttt{y} are +the element the list is sorted by. The guard statement just compares x +and y, and uses that information to prepend the pair with the smaller +sorting value. +\begin{minted}[frame=single]{haskell} +mergeList :: Ord b => [(a, b)] -> [(a, b)] -> [(a, b)] +mergeList [] pys = pys +mergeList pxs [] = pxs + +mergeList axs@( px@(_,x) : xs) ays@( py@(_,y) : ys) + | x <= y = px : mergeList xs ays + | otherwise = py : mergeList axs ys +\end{minted} + +\subsection{mergeSort} +Finally, I got to implement the merge sort algorithm. I first created +some helper functions. \texttt{applyPair} applies a function $f$ with +the parameters given by a tuple. \texttt{applyEachPair} applies a +function $f$ to both elements of a tuple, and returns a new +tuple. Then, \texttt{mergeSort} puts it all together and applies merge +sort to each half of the list; then applies mergeList to the pair of the +sorted halves. The base cases end the recursion of mergeSort, since a +list of 0 or 1 elements is sorted. +\begin{minted}[frame=single]{haskell} +applyPair :: (a->b->c) -> (a,b) -> c +applyPair f (x,y) = f x y + +applyEachPair :: (a->b) -> (a,a) -> (b,b) +applyEachPair f (x, y) = (f x, f y) + +mergeSort :: Ord b => [(a,b)] -> [(a,b)] +mergeSort [] = [] +mergeSort [x] = [x] +mergeSort xs = applyPair mergeList (applyEachPair mergeSort (splitHalf xs)) +\end{minted} + +\section{Part E: BigInt} +Here, I was tasked to work with a new type BigInt which is a list of +integers. + +\subsection{clone} +Clone takes a value and a number, and creates a list with that value +repeated n times. So, a simple recursive solution is to use the cons +operator and call clone again with n decremented. The base case is when +n = 0, which returns and empty list. +\begin{minted}[frame=single]{haskell} +clone :: a -> Int -> [a] +clone _ 0 = [] +clone x n = x : clone x (n-1) +\end{minted} + +\subsection{padZero} +This function will take two \texttt{BigInt}s and return a pair of new +\texttt{BigInt}s that have the same length. Here, I just made a quick +helper function \texttt{clonez} that clones zero n times. Then, I use a +guarded expression to prepend zeros based on the difference of the +lengths. If \texttt{ys} is shorter, it gets \texttt{xl - yl} zeros +prepended, and vice-versa for \texttt{xs}. +\begin{minted}[frame=single]{haskell} +clonez = clone 0 + +padZero :: BigInt -> BigInt -> (BigInt, BigInt) +padZero xs ys | xl > yl = (xs, clonez (xl-yl) ++ ys) + | xl < yl = (clonez (yl-xl) ++ xs, ys) + | otherwise = (xs,ys) + where xl = length xs + yl = length ys +\end{minted} + +\subsection{removeZero} +Kind of like the opposite of \texttt{padZero}. Takes a \texttt{BigInt} +and removes leading zeros that have no value. This is just a simple +recursive pattern matching. If the first element is zero, remove it and +call \texttt{removeZero} again. If we can't pattern match a zero, just +return the list. +\begin{minted}[frame=single]{haskell} +removeZero :: BigInt -> BigInt +removeZero (0:xs) = removeZero xs +removeZero xs = xs +\end{minted} + +\subsection{bigAdd} +This function will add two \texttt{BigInt}s. To implement this, I +delegated to a helper function \texttt{bigAdd'}. The reasoning was so I +could use tail recursion and bring the carry value over each time. + +First, \texttt{bigAdd'} will take two reversed \texttt{BigInt}s, along +with a carry bit. We take the sum of the first integers from the lists, +along with the carry sum. Then, we take the first digit of the sum and +prepend it, and then recursively call \texttt{bigAdd'} with the carry +bit being the sum divided by 10, and the rest of the two lists. +The base case, then, simply takes empty lists and returns the carry bit. + +The actual implementation of \texttt{bigAdd} pads the incoming +\texttt{BigInt}s with zeros, reverses them, and calls \texttt{bigAdd'} +with a carry of 0. Finally, at the end, the result is reversed and +trimmed of zeros. +\begin{minted}[frame=single,breaklines=true]{haskell} +bigAdd' [] [] n = [n] +bigAdd' (x:xs) (y:ys) n = (myMod sum 10) : bigAdd' xs ys (div sum 10) + where sum = x+y+n + +bigAdd :: BigInt -> BigInt -> BigInt +bigAdd xs ys = removeZero $ reverseList $ bigAdd' (reverseList zxs) (reverseList zys) 0 + where (zxs,zys) = padZero xs ys +\end{minted} + +\subsection{mulByDigit} +I followed a similar strategy to \texttt{bigAdd}. Essentially, the +helper function \texttt{digMul'} will take a reversed list, and then +multiply the first digit by some factor q. Then, the carry bit is added, +and the sum is split into the first digit and the other digits. The +first digit is prepended to the recursive call of \texttt{digMul'} with +the rest of the list and the same factor. +\begin{minted}[frame=single]{haskell} +digMul' [] _ n = reverseList $ toDigit n +digMul' (x:xs) q n = (myMod sum 10) : digMul' xs q (div sum 10) + where sum = (x*q)+n + +mulByDigit :: Int -> BigInt -> BigInt +mulByDigit q xs = removeZero $ reverseList $ digMul' (reverseList xs) q 0 +\end{minted} + +\subsection{bigMul} +Finally, the \texttt{bigMul} function will take two \texttt{BigInt}s and +multiply them together. This function follows a basic long +multiplication algorithm. That is, I take each digit from the second +number and multiply it digit-by-digit to the first number. Then, based +on its position, I add zeros to the end of the result. To implement this +in Haskell, I used a helper function \texttt{megaSum} that recursively +adds a list of \texttt{BigInt}s using the previously created +\texttt{bigAdd} function. To create the list of numbers to add, I had to +reverse the 2nd list \texttt{ys} into \texttt{rys}. Then, by using the +\texttt{zip} method, I combined each element of \texttt{rys} with its +index. Since the list was reversed, this index is the number of zeros to +add onto the sum. Each element of the list passed to \texttt{megaSum} is +that digit of \texttt{ys}, \texttt{q}, passed to \texttt{mulByDigit} +with the whole \texttt{BigInt} \texttt{xs}. Finally, zeros are appended +to the end based on the index. The sum of all of these products is the +final result. +\begin{minted}[frame=single,breaklines=true]{haskell} +megaSum :: [BigInt] -> BigInt +megaSum [] = [0] +megaSum (x:xs) = bigAdd x $ megaSum xs + +bigMul :: BigInt -> BigInt -> BigInt +bigMul xs ys = megaSum [mulByDigit q xs ++ clone 0 i | (i,q) <- zip [0..] rys] + where rys = reverseList ys +\end{minted} + +\section{Results} +The Autograder on EDORAS gave me full marks. + +\begin{Verbatim}[label={Results},frame=single] +--------------------------------------------------------------------------- + Results: [90.00/90.00] | [100.00%] +--------------------------------------------------------------------------- +\end{Verbatim} + +% \inputminted[label={SolutionPA2.hs},breaklines=true]{haskell}{SolutionPA2.hs} + +\end{document} diff --git a/Week8/lecture1.hs b/Week8/lecture1.hs new file mode 100644 index 0000000..2690d13 --- /dev/null +++ b/Week8/lecture1.hs @@ -0,0 +1,9 @@ +fact :: [Int] +fact = scanl (*) 1 [2..] + +fibs :: [Int] +-- to understand recursion one must first understand recursion... +-- F_n+2 = 1 + sum(F_1 .. F_n) +fibs = 1 : scanl (+) 1 fibs + +