From be818315f63545af24da0bf9ec534843a3499d46 Mon Sep 17 00:00:00 2001 From: KoroLion Date: Sun, 26 Apr 2020 16:08:03 +0300 Subject: [PATCH] Initial commit --- BMPImage.pas | 258 ++++++++++++++++++++++++++++++++++++ build.sh | 1 + generate.sh | 1 + gui/constants.pas | 8 ++ gui/gui.pas | 214 ++++++++++++++++++++++++++++++ gui/utils.pas | 34 +++++ images/generated/.gitignore | 2 + images/k.bmp | Bin 0 -> 252934 bytes main.pas | 240 +++++++++++++++++++++++++++++++++ ucomplex.pas | 71 ++++++++++ 10 files changed, 829 insertions(+) create mode 100644 BMPImage.pas create mode 100644 build.sh create mode 100644 generate.sh create mode 100644 gui/constants.pas create mode 100644 gui/gui.pas create mode 100644 gui/utils.pas create mode 100644 images/generated/.gitignore create mode 100644 images/k.bmp create mode 100644 main.pas create mode 100644 ucomplex.pas diff --git a/BMPImage.pas b/BMPImage.pas new file mode 100644 index 0000000..850dc62 --- /dev/null +++ b/BMPImage.pas @@ -0,0 +1,258 @@ +unit BMPImage; + +interface + +uses classes; + +type + TColor = object + r: byte; + g: byte; + b: byte; + + procedure set_color(tr: byte; tg: byte; tb: byte); + procedure reset(); + end; + + TPxData = array of array of TColor; + + TBMPImage = object + private + width, height: integer; + + function get_padding(): integer; + public + pixel_data: array of array of TColor; + + constructor init(); + constructor init(w: integer; h: integer; c: TColor); + constructor init(px_data: TPxData); + destructor done(); + + procedure set_pixel_data(px_data: TPxData); + procedure set_width(w: integer); + procedure set_height(h: integer); + + function get_width(): integer; + function get_height(): integer; + + procedure open(path: string); + procedure save(path: string; monochrome: boolean); + end; + +implementation + +procedure TColor.reset(); +begin + r := 0; + g := 0; + b := 0; +end; + +procedure TColor.set_color(tr: byte; tg: byte; tb: byte); +begin + r := tr; + g := tg; + b := tb; +end; + +procedure TBMPImage.set_pixel_data(px_data: TPxData); +var + i, j: longint; +begin + width := length(px_data); + height := length(px_data[0]); + setLength(pixel_data, width, height); + + for i := 0 to width - 1 do begin + for j := 0 to height - 1 do begin + pixel_data[i][j] := px_data[i][j]; + end; + end; +end; + +constructor TBMPImage.init(); +begin + setLength(pixel_data, 0, 0); + width := 0; + height := 0; +end; + +constructor TBMPImage.init(w: integer; h: integer; c: TColor); +var + i, j: integer; +begin + setLength(pixel_data, w, h); + width := w; + height := h; + + for i := 0 to width - 1 do begin + for j := 0 to height - 1 do begin + pixel_data[i][j] := c; + end; + end; +end; + +constructor TBMPImage.init(px_data: TPxData); +begin + set_pixel_data(px_data); +end; + + +destructor TBMPImage.done(); +begin + setLength(pixel_data, 0, 0); // not neccesary + width := 0; + height := 0; +end; + +function TBMPImage.get_padding(): integer; +var + bytes_per_row, padding: integer; +begin + bytes_per_row := width * 3; + padding := 4 - bytes_per_row mod 4; + if padding = 4 then padding := 0; + get_padding := padding; +end; + +procedure TBMPImage.set_width(w: integer); +var + color: TColor; + i, j: integer; +begin + setLength(pixel_data, w, height); + if (w > width) then begin + for i := width to w - 1 do begin + for j := 0 to height - 1 do begin + color.set_color(255, 255, 255); + pixel_data[i][j] := color; + end; + end; + end; + width := w; +end; + +procedure TBMPImage.set_height(h: integer); +var + color: TColor; + i, j: integer; +begin + setLength(pixel_data, width, h); + if (h > height) then begin + for i := 0 to width - 1 do begin + for j := height to h - 1 do begin + color.set_color(255, 255, 255); + pixel_data[i][j] := color; + end; + end; + end; + height := h; +end; + +function TBMPImage.get_width(): integer; +begin + get_width := width; +end; + +function TBMPImage.get_height(): integer; +begin + get_height := height; +end; + +procedure TBMPImage.open(path: string); +var + instream: TFileStream; + px_data_offset, i, j, k, padding: integer; + color: TColor; +begin + instream := TFileStream.Create(path, fmOpenRead); + + instream.position := 10; + px_data_offset := instream.readword(); + + instream.position := 18; + width := instream.readword(); + instream.position := 22; + height := instream.readword(); + + setLength(pixel_data, width, height); // indexes begins with zero + + padding := get_padding(); + + instream.position := px_data_offset; + k := 1; + for i := height - 1 downto 0 do begin + for j := 0 to width - 1 do begin + color.b := instream.readbyte(); + color.g := instream.readbyte(); + color.r := instream.readbyte(); + + pixel_data[j][i] := color; + + inc(k); + end; + instream.position := instream.position + padding; + end; +end; + +procedure TBMPImage.save(path: string; monochrome: boolean); +var + ostream: TFileStream; + padding, i, j, cs: integer; + color: TColor; + buf: array[1..1000000] of byte; + k, size: longint; +begin + ostream := TFileStream.Create(path, fmCreate + fmOpenWrite); + + ostream.writeword(19778); // "BM" - format specifier + + ostream.position := 10; + ostream.WriteDWord(54); // pixel data offset is bytes (54) + ostream.WriteDWord(40); // second header size in bytes (40, 14 - first header) + ostream.WriteDWord(width); + ostream.WriteDWord(height); + ostream.position := 26; + ostream.writeword(1); // must be one + // bits per pixel + if (monochrome) then ostream.writeword(1) else ostream.writeword(24); + + padding := get_padding(); + ostream.position := 54; + + size := width * 3 + padding; + for k := 1 to size do begin // we need zero bytes to fill padding + buf[k] := 0; + end; + + if (monochrome) then begin + {color := pixel_data[j][i]; + cs := color.r + color.g + color.b; + if (cs > 425) then begin + cs := 255; + end else begin + cs := 0; + end; + ostream.writebyte(cs); + ostream.writebyte(cs); + ostream.writebyte(cs);} + end else begin + for i := height - 1 downto 0 do begin + k := 1; + for j := 0 to width - 1 do begin + color := pixel_data[j][i]; + + buf[k + 0] := color.b; + buf[k + 1] := color.g; + buf[k + 2] := color.r; + + k := k + 3; + end; + ostream.writebuffer(buf, size); + end; + end; +end; + +begin +end. diff --git a/build.sh b/build.sh new file mode 100644 index 0000000..a9b2d4c --- /dev/null +++ b/build.sh @@ -0,0 +1 @@ +fpc gui.pas -Fu/usr/local/Cellar/fpc/3.0.4_1/lib/fpc/3.0.4/units/x86_64-darwin/fv diff --git a/generate.sh b/generate.sh new file mode 100644 index 0000000..c4116aa --- /dev/null +++ b/generate.sh @@ -0,0 +1 @@ +./main 13 -100 1800 diff --git a/gui/constants.pas b/gui/constants.pas new file mode 100644 index 0000000..54aa779 --- /dev/null +++ b/gui/constants.pas @@ -0,0 +1,8 @@ +unit constants; + +interface + const cmAbout = 1001; + const cmGenerate = 1002; + +implementation +end. diff --git a/gui/gui.pas b/gui/gui.pas new file mode 100644 index 0000000..bab439a --- /dev/null +++ b/gui/gui.pas @@ -0,0 +1,214 @@ +uses + Process, SysUtils, + App, Dialogs, Objects, Menus, Drivers, Views, MsgBox, + utils, constants; + +type + PGenerateData = ^TGenerateData; + TGenerateData = record + path: string[128]; + width: string[16]; + height: string[16]; + power: string[64]; + zoom: string[64]; + centerX: string[64]; + centerY: string[64]; + end; + + PGeneratorWindow = ^TGeneratorWindow; + TGeneratorWindow = object(TDialog) + winRect: TRect; + curY: integer; + + constructor Init; + procedure addField(caption: string; maxLength: integer); + procedure addButton(caption: string; command: integer); + end; + + TMSApp = object(TApplication) + GeneratorWindow: PGeneratorWindow; + + procedure InitStatusLine; virtual; + procedure InitMenuBar; virtual; + procedure HandleEvent(var Event: TEvent); virtual; + + procedure NewWindow(); + procedure GenerateMandelbrotSetImage(); + procedure ShowAbout(); + procedure ShowSuccess(fname: string; t: extended); + end; + +var + MSApp: TMSApp; + GenerateData: TGenerateData; + +procedure TMSApp.GenerateMandelbrotSetImage(); +var + s: AnsiString; + startTime: int64; + success: boolean; +begin + GeneratorWindow^.GetData(GenerateData); + startTime := getTimestamp(); + + with GenerateData do begin + success := RunCommand('../main', [ + width, + height, + power, + zoom, + centerX, + centerY, + path + ], s); + end; + + if (success) then begin + ShowSuccess(s, (getTimestamp() - startTime) / 1000); + end; +end; + +procedure TGeneratorWindow.addField(caption: string; maxLength: integer); +var + il: PInputLine; + r: TRect; +begin + caption := wrapFirstLetter(caption, '~'); + + r.assign(14, curY, winRect.b.x - 2, curY + 1); + il := New(PInputLine, Init(r, maxLength)); + Insert(il); + r.assign(2, curY, 13, curY + 1); + Insert(New(PLabel, Init(r, caption, il))); + + curY := curY + 2; +end; + +procedure TGeneratorWindow.addButton(caption: string; command: integer); +var + r: TRect; +begin + r.assign(3, curY, winRect.b.x - 1, curY + 1); + Insert(New(PButton, Init(r, caption, command, bfNormal))); + + curY := curY + 2; +end; + +constructor TGeneratorWindow.Init(); +var + wr: TRect; +begin + wr.assign(0, 0, 60, 19); + inherited Init(wr, 'Generator'); + Options := Options or ofCentered; + HelpCtx := $F000; + + winRect := wr; + curY := 2; + + with GenerateData do begin + path := './images'; + width := '512'; + height := '512'; + power := '2'; + zoom := '1'; + centerX := '0'; + centerY := '0'; + end; + + addField('Path:', 128); + addField('Width:', 16); + addField('Height:', 16); + addField('Power:', 64); + addField('Zoom:', 64); + addField('Center X:', 64); + addField('Center Y:', 64); + + addButton('Generate', cmGenerate); +end; + +procedure TMSApp.NewWindow(); +begin + GeneratorWindow := New(PGeneratorWindow, Init); + GeneratorWindow^.SetData(GenerateData); + InsertWindow(GeneratorWindow); +end; + +procedure TMSApp.ShowAbout(); +begin + MessageBox( + #3'Multibrot Set Generator GUI'#13 + + #3'Developed by Artem K.'#13 + + #3'MF BMSTU 2019', + nil, + mfInformation or mfOkButton + ); +end; + +procedure TMSApp.ShowSuccess(fname: string; t: extended); +begin + MessageBox( + #3'Set image was generated!'#13 + + 'File name: ' + fname + #13 + + 'Time spent: ' + FloatToStr(t) + ' s', + nil, + mfInformation or mfOkButton + ); +end; + +procedure TMSApp.HandleEvent(var Event: TEvent); +begin + inherited HandleEvent(Event); + + if Event.What = evCommand then begin + case Event.Command of + cmNew: begin + NewWindow(); + ClearEvent(Event); + end; + cmAbout: begin + ShowAbout(); + ClearEvent(Event); + end; + cmGenerate: begin + GenerateMandelbrotSetImage(); + ClearEvent(Event); + end; + end; + end; +end; + +procedure TMSApp.InitStatusLine(); +var + r: TRect; +begin + GetExtent(r); + r.a.y := r.b.y - 1; + New(StatusLine, Init(r, + NewStatusDef(0, $EFFF, + NewStatusKey('~Alt+X~ Exit', kbAltX, cmQuit, + NewStatusKey('~F3~ New', kbF3, cmNew, + nil + )), nil) + )); +end; + +procedure TMSApp.InitMenuBar(); +var + r: TRect; +begin + GetExtent(r); + r.b.y := r.a.y + 1; + MenuBar := New(PMenuBar, Init(r, NewMenu( + NewItem('~N~ew', '', kbNoKey, cmNew, hcNew, + NewItem('~A~bout', '', kbNoKey, cmAbout, hcNoContext, + NewItem('~E~xit', 'Alt+X', kbAltX, cmQuit, hcExit, + nil))))) + ); +end; + +begin + MSApp.Init(); + MSApp.Run(); + MSApp.Done(); +end. diff --git a/gui/utils.pas b/gui/utils.pas new file mode 100644 index 0000000..f5a269f --- /dev/null +++ b/gui/utils.pas @@ -0,0 +1,34 @@ +unit utils; + +interface + +uses SysUtils; + +function wrapFirstLetter(s: string; wrapper: string): string; +function getTimestamp(): int64; + + +implementation + +function wrapFirstLetter(s: string; wrapper: string): string; +var + i: integer; + ts: string; +begin + ts := ''; + for i := 2 to length(s) do begin + ts := ts + s[i]; + end; + s := wrapper + s[1] + wrapper + ts; + wrapFirstLetter := s; +end; + +function GetTimestamp(): int64; +var + ts: TTimeStamp; +begin + ts := DateTimeToTimestamp(Now()); + GetTimestamp := ts.time + ts.date * 24 * 60 * 60 * 1000; +end; + +end. diff --git a/images/generated/.gitignore b/images/generated/.gitignore new file mode 100644 index 0000000..c96a04f --- /dev/null +++ b/images/generated/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore \ No newline at end of file diff --git a/images/k.bmp b/images/k.bmp new file mode 100644 index 0000000000000000000000000000000000000000..67d7aa569649dba0ef46c6108dd6d227421e70b4 GIT binary patch literal 252934 zcmeF)cf4Iixi|2gPC_UNBtT3dg%k)almLbr2!!4QR1lGl2uKwW6c7*)0X3*7wyUC8 zQ1sd>h>D0E^BiUn`HxTk?XQ3R```cm)1Ury#`Cs()rtwX9#$LvH=rqS zXzkXOz4@=#7@!550l}Nz^rkWte*4?sMrL3u*gw(*gt;ZBTth24-jcs4y$j58kgWmO z(_j=w;Oxs^{_=nQ*MI%tFx+p@$wy5=*AXzw(u@03TuY=%bJR_{TqXH-Sw0 z*=L`aVJWPzKX{p@ES z{pd%Pfiu#}0c}6|$xp~I2%|K*r9gsLB%Db&wSDJ1-#PY}V-8+CvA4$GVF5Wzfy2uF z#*cmMW6g2Ui{eV85U=Wf+XWkHKB$7N+$|Y6d-|y- zk6b#v_Xs>(^DqTapoFteed<$t?zv~Kymg9+LVxyliL(!X=z~Wt>MgB&n8k)E5ELlkjN@+6 zqD3G1$VUq3X>u8O>NcthHLpQe{V#+y0vWlbso(g=2t;LzD)Du;~+16Wbd`oXmoD2`>!xTV) zDx7iFoqqc1iT(R5k<`UXF&4-OkP&7qtw$btq&dh``1#L&zJRmvgT$H3amJ=2h8ba) z0=-RvDx3k<$tR!OJ(<+Krvl1>vrrU6l7UD7q5~^`Oduo7fQ&Q>NmdqP9fsMz7;0*Z zXPqH6fh-bV`^uMg*lHMOy{j_yHVY4m`WxWvnrp6k;DHDFOpAyzepg<6~#bUXpcONImiNM5Eh5aPd)g_J?0L3^oMcQ>lA2!GYtOLx4yN{ zaF#U2WRQV^U@sc1d1Mn{Kp%5s;kKvm1;_$V30rw0Vj8(mp|eAnt%g^adU0XyZRx@- z2E~9l+{i&qfd)7ev2?{1SM&|ea&t5H{(@TdF zL!JVSamLr+=nb4DpJc*WfDHQs8B90&Sx}W1RH{!ty#3 z$U_Q&G09iQi!?g%K#28_g!>H4=9fWLdQr8+gy!(N(be16P zt~qjxshf=Z)qgz!j%Kr8dcdspq34Icu`emmS2!!%WDzD@5N0Hnwa+2Ua*$QdM0W}@ z1z!B(7r*OW?+UZeIhkn5>-eU-?p*S`5$BzHtb1_wwXc5lsw1}S%N`hh*ZM$#zQS3u z%tDe;7vU_qKawyb&+Je|m;sriOMb;N>^#2PZo5$(17~2A^u~mX!TQki1K}Hacdt3HcENt*&)9pDQ}&v4+%6l@7!(9vV^JeT%cCE`~4*3kk^J00@9gG?mL(d zyz7qJNjeG5+hxvLAOAq$#G%@Ts}CIY!rdk;o-yHh)3!S0lv7SP;e?mH>}6M9ef8%* z`)NL_?|%2O+itz}q!Uk=J8Rn3n~#3Ut|QH5Lgcjv)-GIDd(qCdedp9(xKr)4-A0_Z z*N7MITsw33+G`K01!@N-E=xG;y*aZ2$dWL_;A9D$Q5t#lLzwj(WYBiqb=RGG>Zxk> ziZ}vcNvcUeA!j>@#=tP-X1_@?DqiH{z&e^Upo!oVUL9Zt*zgN|UZ5fk|`< zelX}VA9$Frz4qD}GiIE0;tMW#`MH-}^2*m;|JwJx=idMP zy6`0@zv%d5j$C=bo_j9c&2F5_7EW3^d+Z?#N1n1v?UH?K*R5!qd%oK=EaB|ZOD}!@ z``@2`db`rtIgaFG3^q?7Lt6YE>f&n8eG*OGN*sFVq4(ZIu5^|yq5{`4v zJ?Dk{&bjT#VW{;MW4>gU+J5^y|F^&W4NhpnS0e4eYtEcGqehJyIdbHA=bfi_49v}+ zN);Nd`K90d<~I|Nr<`)~{Q28V+jI<<^5y&0Ubb89)LrZ6^Y^NW`nh0PT}-~d_ZJ|R zaAt0rkB%fro{QA{ZX}`-gOnqIEKQgp9x)Rdqp)B3$tLR-uGV>o(nuQ-fNaDhq`d{C z3OMV?dD6Kf@zfJP{=v&$eB9g4+qK)n*6@Rs6u9w_x|+9m%MoXvaaxCEUJWwb^19c( z&gi&e#fs~%zy8iU@3eeS%y@84a8Wmy&?8Sg@#FhG@V;waebq}&KIzQUPJZ9J-oEP1 zcV764myh3I+?dfLCyuLawNY*2*xI&JYsYP0yLg{E5U)C*rrGV%LQ6P{@A!}Z_z#}C zcEy7Pg%Zw^ECI665X_kgVhpov9kBG^;_YvLyVX4(`p}02YzadqEWIx9v@Y7}JMhT7;4REGKcFex$qKjwdChBHBZ|a(b+VTR$f6l3?J^yQAGY%N{TIFNgjsjKKs?s)D$p+LkYvEc zd)HPjtSz3g;h85N`=&c?kL82tkH|R}aRuw9bIv(u;>3wdmMjsun)odrn*(R<0vS#_ z^UO1$3cTi39gsJD`gEAvXrqlLOc+0A^r&&8Yx6g+9k!@;(cayZaJ5>XA^-Z6wq@G| z7hKS!Kq}cJkq=DBjI{$~s2&<4`k{Awg&CZ&@F3XRU-`;c63;N5aHbhijHZ-s~P~M^6b3XB-4aCWq zF=JR@oQ+l)=69t7YK3zuBR@~)mnpxTU_nqypZC1y&1bc3vrQGuig{qi5wq1+TWz}O zrlUuV+Imv$<$HA*ZM7Qx>W(|^Xrv<2j_F6X)M@)cBhY>GH7Nh!cl! z{$=~s7EK#}$;Gb}I2t64ku3BEB*kVQ_`nB@WDsU=nyFK#O2_7aopMz0Qu$nvb_z7A ziVxtJV~!!o7A#l*XO1GKI=h}dd-mkXlegG-^n$4)IaY2sxK*y`&>JoGI_jvS2=^X} zuJZT!=paJ^SwWat{{jJg`6;-n2PRqZQI6rIOPAU|)!J}x(UOF-99SV@^PJ!gg@5&{ zUtW9ls}|3hy6FbBqqZCVp^JuW#dolD=7`;v>}ZL44u#bFGQ-6NUU7^aJN7Mac}tmR z@|;vv0#m9GN9E~sDbrJVB`LjX)vC=l+iYRS0cwG^&Y)FspTaq1$`tM2aBSUa(#pWO z#y%4wZ@TdK+TeN_y*~SSvj+*vptZ-g8!M%A}1hyx;<=N#cQE_5>7K0_`gh zHe$qxefQm0AZsdInTThDg%Ts_%{XE#48GDweEAjtJNVROD&rAnJsAC~w&y?p`LJbs z(tw(?%NDiAGTgXMn3bDNsL!5v+KFp$=0mv*ZoBQal`B_XeDTHR2P;3l)685V`m#ix zpa*tF5+K9%&YbS@lP|w5b7nczgi7*a5teXfN=CW~o?;kqj&4k6ImQM|ap|R(9D3-= znbW6jH+QQQ3&)(dXP1@qPJ3f;6)^22G-LlgcDU)r8@~7W zY80m;Uti8Al@As`raOX#5+m`LQ18LZXlm-l*}L#CsKwHI#t0t6fsjXxFw1C++itrp zoH>9j65Y@qbIfs)EI_8l^3hcipvBA_WQc@Y@puR`Ame4H!ZS)! zh*jG`25>Ahsw0h*4f?jXy$x0p&Jv8G-vVT*CnZvW)WfOqx|h-Zf@6=GHK{(!(kVE& z2HG_Z)9JhVtbpm=d3=?`O9AiW5vBe6bm_w*0Fdh6r%z=nb_H2gAD)+&H`$IvqM4{ibFcvhTN0a7z2WW@+gQ0Z3KiX#x_+{pUylM%Gm4veing)nom-FDkacLQGeBjy1%89%DY zpj(Br^yxe!HcX{ir<@iOiBzO^uq|rg(9jrR*KbRp5W;{_FM-T%2YgxT_ZF&)F+&3a zXE~};I&fAvC$!~X5g+1P99&q77R)XG^6u?NZ}5_(<7ZADHD=U+h_7oANsWqKw5+!G zoDn;0Gi|#?3qErHhxBg~P5`E(k3KpVVk|N7S(+>;oSU;tSH2qp0d-bl|TY~>6SoP+U18Asd|1t>=4GNb}n&XEYT z70%{%;4C35B|@^f45;*Z$YMxS?BhYs9O*bu{zdHK(wj)N( zo4MsDKk>j5PyB>eZTggn)U5%Ir*iXNf9Qx)_nxw7&b0H-J^Oe6^Vg0vUwuv(G-f z4~4=BWHAiKIl)VU)o#91uW?}IOafQk;DLBVVDikFGs_^$b9UHahaGp^(V39zwx^#+ zGq1Muw2H3m8O{n+bXmq(;z!b-K?7&KEy;qq-eqSHuKnYVJ1&&Qgfk8+Zq-h479h*H zAfe5(NpFnAWtU#Ma^GDqKWt0k;6AxNz&!cn)mL9-ztys|h#X!Lae#}a)|St!|7%pN zZ}K(f+JkC`ESQ|>Y!*UlFa!_*r{r67@lMtfx$Rm%WVpt+EMq-bIuta3H zD2is_@Ch;2ZB!K=O@3EGrk%ykcKMB3QVBg+nv9^kAz(j_Y5 zM}(~NTISA|4t23WiQc>9H8qwo&NM6p52)#L%8Ya1%sINc(YcH>ISK<)AWWSO@={FA z^1YXS|C?V(by|EOItNh9udveaastiO%SRlvz8c6{3@b>FwsvvdyQg&)BXZfc)AZ3t9J+$g{pL3xdH(Eruv}Z9(@G`u!|PYn&e@}O z$o3OI@}c+B&{`eh=z1d@&C0gbn%gGr$h@82)T^@IO zBgbL`tsYP_&Vn}tQ5ZKbvFbAy#kERIQ{hN zj-Sa0o43`(1D5S}_~NmkaOM8BO~#LY^PBF{B<{)$HyCxy;$qLVf|#zBxp`&Bddsaw z?XYn6d8fbl3lDziFCF34J}QBul?2<@VwN0a#F&Ltxl^&s7>JfA6Z99pp)cecgL{Jk z)X51VWFv6a3dq2VNXrikc4W4WHY*S;YAtk4`*5bO(vjFOu`{ao5+NH^tK0o(E>73^ ze2-?vK|xdqi#@ff5?<~W^5b)y3m+&)$u$_O|0Uj@erk0jr+Va=`&qbP{`Susx97YK zUw+;>S6qJCp?l0ZddVgS?Y9?>hBNaI7oKzK;d{-`waP*-_3)B@NP4Z@cFfEzHhuZI zXR(12zx#w%fR&dKCMwD!fy_J^%t1^llMq%QS9&SRC_`7|_27JNqcv7$2Hm~omRrJE z4zgT~Nr&i4=K{zKA&y;l-4)=})2UBV;K@mC##vA_$Qf+t>*H zR9im!@WT&lhPRsqbjk0;oh2uZXlJxJH9IoXt&~W`3W+t9)lucBL+$Ccnxnf$|3eNr zWb5ZmJ^IMQQS1lb|K98wTYc%Xp9uM?JWKc0S6+Ta@BAG775mke%$@X_Yp#0akw<)s zw#64Y>$n7t787Pj#HlBcN!WuUo=xzQNC=ZigbhOZUY=*MBrbauVZmKu@Azf92eJSh zc)^+27PA(dsOD;xFJCUP`|i5~pPGem@w2c~ogJHOvWc+I!qC_=c~-z#Fd*SUgy_bg zD=y=b>QzWJsa#J28AcG*BJPJgi&n*1BMYF(FB3mTW)5h1P8r+i{g*DD3CYZbWlT9dC8)JqO&)*BlKRw3>)XFT70b^C9B1!Q_h+8G>ljmCXTS8s zuY9&{fTkv;wAc9--`FLDDQxWIvP%e)5c}}n_r5pPlaIIwUMS;r-X2E;wQ5x$tnDt3 zN?xMSa7;A9S<)3HfC*4YDF*?TgUqeCYh_KyGa#d*I3Lt;NC2NR31^3qa!hd#{iqc7R`%3K;(Sk8Ldna~sPDxVbyu8BmXqgXtf&Z~K8 z%^xp{cjb&0H|0YcY&ims0ls&?>)uHd$L+uU)E(w*w&#LP&s_ezOIB`q@$!u>*{>dA zU?LlmxFwIV&t&H4$DEd;f5QcYN{azS)y3};o74f>Tw@*df^psc*7eE31OcVgjo(U zY2u1lavX5L0cHflAPa=$=fGcRl6&m2$Fh!tN(q0Y9qn=K=n?IkKTD(yMhgx?OP4HL z#(!`SWvTGpeRgTMgfmJb2ct#4(VpOat;Ge7XnYx7<(y!jz*+uOq@C54S6i+jo{eHk zYEK-}T1C=;ojAaQ4m^#MXTnN3p|FrOYqoNPNm~YzX2^mK(ukYBF@0vV z4P$7SuJ0Qemh+gsZ`o(mxdO<_8Y9IoDS@5hEYOyankt_6z>pYuX@$1a5P4CBsRnd1-Miqqnw$56+D$LRhSN$ z?j{~AB%)4*wFliKqN-?HN6znm{cI!!{H8aFD6#C;mR;ZY#y84PP_uWbA-W)a zT_K_V^0Uozbl;0!^r8a7L`eucG5y&H#}%J1FoD z)Djd@BB3M_phIIMqU?1+fy`xCo(_Z+aHa;;+C603Eozlp$@C0osgqHZ*&&{Z{Gh7g zag&cmvGRBKWez3Qf>lfrIMds~fWZr~_Ledkut>~OnNTK*<>%n6jyv^JR2!FW72s81 z$#_A)S{@^{C&3csUXz9FN_?Sz?(ONqL+& zk#r8Ki<=3e@+mQ%`w~_8yL2f>laW^o6UgM4wS4VsUu)BSJ`vIUmce1woXwl3gQ1j3 ziIkR;j;JK4l+H2}W2VfUZQGSz{g#e*bg52WVoOLw(Ad%`M;QBtkp zJ~?(!G%1Rh4uhu;?c;=gwh4s>#G#SApoUlZI3n5~pP-!*j>I)75&4C4luu9PcV((P z-BM3}#4F?!xOE_0ns^bTCO$KVSERYq?5vx<1oKcoYgSJ+b##V3!pu!%^+HWwrwtQ~w zbxrqj>=w?DJmHK@X1wG37ziMX@k_*@UmG!DMqAJ}P3>?l;D9GV(5#PJ4x5G;B-~9< zNQsmwQ9csXB9Sf&CDoSm=736DU4R0-YUY~DAhQJj$}6vIvWVWN#mD+~R1I~JBy)+K z>59P*{cDybVU`jUFRqHYbLaL@o#VaVf&6KP^)j|n4icphkGztU_JQg16UY#mjSiYX7R)ekBw50lgp~=_P(w)p zYOU*yj65?Ne&u56%ykwz6#}gam+Q(iNl&G5$p-2R=k(uH_S{S*|HF!M#tiDNi zplhA=wi*Lult$;f?z)Qy#QF$~kmIHjSmn(8kw)owDv_vP65smPw=5gCq?dCnViqWb zmfwjGsuWrYSdkEAE}Vh#Uy0QGi=yk1A{SwCs7=x+4QKbOa*ME%acwz$sp8Xvx5SG zGxS7TUJpT=10P{IBI%F}&=70|kO3c|6(J-Ne2F3lM%3!R)O7ItnqTm3;_oPkv2>Z? zj3=JQ$+<;(qqHH6LW00SW8B?mA}zfLu;PejIQs;K7t2iCD+SVE&~1<*MHy0+u7MVb z*7joXaqO|jCd70pL4XOCG4vJw16lwEncITo2n8%ngWBTTs zP2OY^a~K;>ojPUq*0cPU%CFgzh4rK=HN zAT#DQ)$a(qx6e$pgfM*zVF531M>Yb?*a~F!n0UbpUf?SX2B1cy(QhdXF4wR~v%ihL zy3g_{7I~CzqxV|rLzC$ewo>6ve?y|tOCuj8ndb461yGebrGF9DrDiA`<$ViYa^R)9 z>ig_7|9Iwa&;IQ%fBn<%fB5i&mOb2Xa3`B7B|J4stdVDU(26)~Sb~av2{Zf%mBhxP znnq5TyTs9K%RX~41!0gRA&hHFC<=r@m1by+OWH3!vY!kIZ66+o=~s(ljJ#wpf!7FS z`S*5pl+T~-N!kb}F5E1C^Gf_epSjV5n@$r3ZhjD?c;`Fc*}9fkZUgG+cN>?YtFu3a{oOp>1^-(M%c>pJ8)(%Wh1^gz#uCA zVknjgoN_Q}DCW4ELl0lad`WMMv;xQ=%%RVP-vU`6j8x;7(L9aBupjuq2khx?+~)`3 z#>T(K55q|rXX)$uJ#obqSJ<(L;738Eq3S3R3 zEhKO#G6&A^c;GCFH0>j7ntWEbZ$-x@;SOQK4X}^NXecLE!9BeAEOYF@`G#Aq>98l0 zUl%u*#$TZEmA?GKH}>x(!Snw2zrT4Kh!d+YSm{=C@GDx);q2gG6eA_7(~pr*K8>JB zM`>PRD|dCeu1Duy>f&zmMo%6Lc&VX7M|zeVi+}HX@4J`I8j)`^-6Etai`8mGmvKKQ zvq@gDe|b(yhZqQ@5j%rs0cSMa=!AepPY94d8?}Y5NNPeD6%lUCw+6z9u>>-fxdmq= zbZRz%XZ?Cy#yAlllFq4Qzb6a>=C_(CjoRF$Ms~G)qsrlxqDWU5N+82yYjO6^XX%R1 zb)5h9e}CFzrv+`?v87fkI6G+H6s=XORu$+SI)+XIGDpZWY>vC}IA+KA*uOVa#{gMK zvJhhg80%1z${-UvY^K#Y_)EOFFS61BkEAbhD?d{HKuCzE5VO!oqsyC}r?uQ=W&2Zp zN>mnWo@ri9lnt62>hke#2&7lz410AT4Ah=|=C7~4_Ugm7pHL~8x|g}e50c32H*{@p zNC2c9iTm%rpA%0)U*$Lx2?A#h{2nG69E3;xBL*)NYvr;qfVJ|7GK8_fAY(&bK5uZ)KhG(r)3Z%(r83PE zzJg1cd_`M5+pZ2BIQ0b1LRYLCX8(BhlOOxg-rJ17<*=Um7;{9Ha7L0bWf*Nietc?1 zj~b@OLX5@P(1!4=1e^|M&e%VB9otLA1TwE+2s#KS=RlaZ3;LnYXpdF}8v>cRS3K)0 z{2~)h$+;=#zC6E&X&B|UjY_D0f^em~3S4%T@HuXs)R@%T__Wju=`tl!$#O!OJTq0^ zBmwIN-S8P1M~9fY7%aM4n7Qbf`gKX3E!$~!8#Ts2TM1_ZNbUSgPtXI*FYB~ygp-kzS))C8l{1@W1wFY*E@9S`PT z>Q*^ZPPrL!j7&bq=!ND(Qj8UGwq^?O+|y4!b(i+|7@Nv7K49~YL3{o>(Q(cO+0=oN z(8+M7AIww+`$H$;7kXp6{}MrL3E2&)8{=23NoIm9Pmd}?rkm2&QD#At;_ znp~QT@)nwvMUqiW!W;r&Z?oMd4_4k{P+C1t<8?P+fz)vzxFbfCJRuzgQrD!!nn&w@ zBQxEKM35qH3Aa5jt~w2G?dr#YSx*SF{QRDK-#%w@kK#UZY~|^aJd3#&gvYICoN)%| z*q@?|Grgqi^oEg_l}68zqj2(rbeptlP_wGkNnSd;bk-gReT=18Ko~IqdBHeXp1(8+ zGn&sWx7?EWCX_%2?Hgu>uJ1V&`RIY@x?>_dOZMUA{m#K1mv@2c0 z*?H%kXE?(eHmAS-`s;DDI1#RdymO+LCJ|C&eN4gux3$mb$BS9)pq+PYqP_~D21zLM5m zx-VrUjri%%0r6D>qt zx{O20 z_Ac@g?BJM%icoPFhZ6W;F3}2!;>c+j{iPV`g;wEIYSJD3b*o(#jI# zVXtV64RB_9mlK4q%t$Soz?7Ko)s1X>3%PU}cm*q%vd4w>l?3Vbl^u>y$ z12j|Gv(n+?0B$c@%_r;r35Z7nF1+wUExfhkXU6Zl?>@3EXJIU#dbqRTUL)47WIIaAp|DS#9=Tq@|m{OHNtk>b?7hMB;OIm zoYx@mPbtT83QJJia2&4Zm&sYX5;UphDUm-?PFGeE#mtFI(7W({)K-4H zdpSNw%r8%hUZ6>+9CUyNRvZx(U~J=sA>QDICF+14ImSqS8Tro2r~y5tQ|K;ztAS$eXh)n2 z1)N36#Hw&c>|uN(W(wo>DQbW%LubO4eohB#EDkW@N5C3}a*7Q=%Sn~ziIh*jrDD+x zwZu!!li8UdwZBm!uPRSBDlfkg&S-Sp@OdTWbh+A8rhF^UG2~buCf3nna0H?KhQ5c$ z(1xBdN_C7`YZU^dMq76su$T^)^4)F3n*%vNL8O&N<}hlWR@*&y-+Ac5UU7UBu-E`+ zctOX~G_>WCOD01Cq31E`zMXrf8BMW;&TWh&EARpq&|d?m=@aZtGE zqKhIOtb{#zeQDqkv7Nn|&8&>OYEK~^b`I1W+@84)(|V9ryC9|0?llr!iO zzN_^%=R~MXM^$m_uYY>#=w;h<2#o!ISdu1YRZ8oBQM8_eB7ZVWKfD+(hpryW>^@+81oLAu@BMcMR-ch@w$|V zOJ{Z%U!0KJ6u8KD;4P^@Wunac<($d~3z_LD3Y&I1qQQ}lOF5zXMnbxLK#WWUqW++# zbkyLM96vB-ISGC=1kuUM~H@^1F zJx8~KlAf1ofHN8q5P*p0FhT56FA)ZLu)O|{15?N`7c5$cE6k<*un){3iIc<>I0CQ$ z2w%{7oRxX#p@%T3xA1qc9wHwu89KpwcrD%)JXkn0#ptnqcp&BDM8Yy%RwfcY8YL>9 z$}{r^165Gs2xP?BWk4!m6zS$?kHp7D{ZT_Yv(k(!R=ZF#Y%YYn0W~^gQW}DThQPT1 zjuyWtJ(bF*oIq8|myq-9-~YO7hv}7j;rAR>8I%vckL4OC|g`f!__Z$Sh@s zG)IFlVB{o^FDVCZARbrc{+Mbm91dgw+t4Z@u%D3zzkUWfqvL!WoVL z3pP`s1F3&}A~+$jo{}zkpzYE{pP^nRoJARz5{d;^;+-M-LGO_*`u-%7|RWK#pishafq&WqAtos$jc3pBu znYfjw^TMf~dM0`Q+&@?U``5p8!a++H_#M>VLshxv63#G@ZX}#4M@b#a`w&pTeb_|L z+a}t;%9y+U`s>AU$Pd0wJR4}sxiwg|(K*;TJst^_2(=LIVIwPnO|~`{oCNo+sEbiU zyiVnXnp?b#Rz)Q_$O1P|0$!mHYbwnUwz$%{1oQq!RRb7Wft~W6ibI8uJo1Pj0RVEa zbjd$C$g6+~;k67?jZwywA<+oa;kU|PH@MOX91>M6@4#7ylAPdGS#sTaR->~HH;c>u z_UFsbJk~E0m!Z(BIqTv~Z|i(^7zU~O(E3c6nBw3ve5aqWxu1Q)3(7Om1ntVi7X{{( z6G!9+&!)3SQaTd(;~o^xL|MA&rkl7WUAikQ3}+DrKh1vjE`KVeqr6wdk@CBd(6%+z z)c*oO0c5CQh=K|3i2xajRq_IIfgsE&2_G@D5fjiFOtCSfnF(QsnJ4kpz(?k>>ZF0# zx9cX7k5bCZ%0FVL^T?ofizM_^@?HQ1Sdvt0P;9lpE0O&mTSRAu zGgvXs;uHgMqc4#EiBEij+dgreXc50l6XnH2+D*zp42Z$qIWNn}kGRzYUQqzg3Td)$ ztl6@7Jms4c$m?&Cj@CLWqmm{iD{rMo63Bd@BXEXpA;~D)K|Rb4Kq1LWz1@Vg6}N)* zq7oJAAXwBvpjnWV6%P-ptoYIX&<{^2+6M$k7CW(E9p z;0((cg*#a1_c&!u)2ja(rZK)5;b1zxFYBd3$z&+lD2w)p5gIXU4zuLjRk4%cCS68?AVD8B1g#Rzh#v*WHaG}`1wq#B>S}rp z=Ozj?As2O<(pR^!m}nj6%EB_!k*bv-1^@EL-@p6?%i6VnRRKnwUe;=O5I*pT@ey<+ z@&=aEIEZZlUbxI*|4~0=9Bkz*4vE)MsJ$V+5l06C8r=51~SyDL}7N#?Ug1urjx_B?n4Yd*vZax{kAT zydm+Hgs@0tuYS&K*;y|<^s@c>+AK@>tJN?RoP`o1K`qG|Se>L7F$ma9RHhfc@P(Fy z1kRLRwQAMF4?oQPh$|h90yGj75*mV?u`SKhP6MJAfi)EiDUw)TBHcU(s(;*fEE(tK6k@S?RSnQ^c zttQ5dX(@ls!jVp}ND28M3ul3VR7^q?vmF$yjT3YpC^f0b9FASGtz+`D3^$Ho>0bRoTH?4YDUx$XN}>(6H*o{ zgGeu!Q;A31@o^=Cc@g4M~>#n;_+?^oC-1ij~a$fK>!x>J;n~t1?BPY%&|Lb4>x<}Gw z+!aZI*&|bq=w>)$5#s$+QX-%e32$t41h5L{RJr=KL7T;Ma-S1d76fs@_)I!5zYH}p zB$-(&hFU8+_L@Gg_-lltem9yzsd!-h%32MwXP^1oCqD7OYLInkjL49qs*qkwr04$m z>tFnQ|6S)@wR~jG^8J#o)z-GF>nZD(i5VXE9A{Atg^I6)iQ_J=$HEB~0iZai%tndu zNBA8*@*~QaI`UFz1ImC`!c7@oU{TIYIq_irYONABNnZNJ97_&_l!1b;pt5=j+MG=y zm%q0a;^jjck*_v0B;=*35|kM+|&ZkELz4!;sYsjt?)b{N7G8(TcA!iV=rQSc21GrGa0O zqL=1C?6kHaU7+r~f9lEqef+zRopQ>_evk}k8flC{hmdNCCWPVZZ@%$`du-Y-(yRQ^ zp5ZJ$i$|`J@{1SOT0QJM&J+p$ouB;VCta#xJt>S~Zn)w4uYTn#t3CQ1pPfvxb%{{NS$=Rb z?zeRN+mC7I4^fmwRF`sk8E5hJ$OB}2{N@2f0f%oMUvmVQ>2{7p$GrF2r7?zk5&2m1 z=%bIOc>;k)-~(35C@JJ5JgHMUYR=E8Ks@M@Qs<2cZA?!glw=!8rVaExYgnj`ZBgxr ze+Z)}qK`MGd6k@5*5@>H!vVD`02Ud>LgMlWZL?E^CFrC?0#?FtO2n;HQsrV#IBuwmum#ha zci3TvF`lG(7iq2Bo=v*98@CAiZag*QAJIpYYC};+tW{WMt$wso@JpY2aK8l;ZeH1M zp&ylUu1|1=O5}k(cIbQJlZ0)t*oX%#3}oB>BlM&g<5?J20^q88~1ZU}hHgFU( zX#>d)bgez*U@D|@Y^8KURR@OGqB$zK%JvNvIWIgdAF&9Wy_Y?dI8Qn z2wr4!909eK`hU1k%M`#82E0(t;fxa4%A@*1vA;a^>-XPr#mknC${Bosr27hIK`qf* zxRoTs-MHBLDw`9^fjm%iHjq&iQF<-DI#LNeig`AdTRCD+h}StMsF|3CT`%Ru_ZD-|~pZ?%GyUf{WpqXU}mwk>iLl4>@D)%G6 zffUnCg5yJ!F7BqGh5w$CiMvTS1suY7!3FFBkpzrL4d~&+R9h~h0zJ+$^?;|yQTnR# zrU>L0WSbm;n&1U$T5|Bg2XlOwM21Vw5jvzyKwJZ@b^gNHFw`<+bTi3K=J!_(y{$iw zk;J{>AAItShrYJs{OOnOJFt8o31kxefiqDgrja;A*gc2@B@SDDh$Q6JGo$SiUx!Z; zp0Ih6J%OHtApl}R*^!38Qzp>n45=<1AVr2LrV@v0%{9A}nb4*@Gz)x&Gwyt*;r82a z57}0k^2OLMp^?%Eal<%k9T|;ELJZB^5ZI_dIUfsAVz|{n^Lvj!w*PJmuRNfiBZYHR zmD7ETGXz7_z!`CGFv9pyMGqvIVu7ejqZ?^Q!YM${R1zoy770lbav(+lBqxpRy6V}$ z7VxQ=A_|e7RfDtwge57(C{)t3YH+AZG2tpg#7I!H(xw!ws{>Z><=XeuIzlYF7{*x{ z1YOOcOfbqZMyC%d6N;j)G5G17n{RlH9|yd2|A94IHjr?J{rSrw3ClYK>eALC%_JgP z%%C7D+UJUyoPa5b7zGlitIB+vO2{h8Bwq%H3*p4Z@`!_gq&j*~0e&r`VF)(R1T`i3 z8wF1S=&7fkYO8GI<(SR|Q%3%)$f&t4lRjy7zR4st&F2zKqgj7?K25T*yFfTqDk24k*FJ8?3W!!|b zwaCg+3F3v83}3cL0oL~3d+%)^Y*Jpg>NpyS(UIb!LxGH*Z&2K0;gnkr9nk7xLR;_S z3<>FM#0(;d;K%;#FloH(!2YJJ0&u9#4?+lmLV%{*(!v|5ozZ*V#mq7vCe!Pjqw5Tg zAWrSnfpDgn1*?8^hKa^Z)HYDtVTT>)v~FeSTAdsQSrc%yc#B`xL`svwdMXA*U7+s_ zz(8h5rfN>wWaC$_?9)Ak6KJ}T=mE|G1c}|6V*=ZT{2o)#0H$qFfDFUNY0%tzuccQV`Mg^X@BamyEn==)I7_^S zFp*9Pmj!C&mlzh!cpPji?BL2XM@4g3v0{bzVu$T_>EdWQP z@rD=%Y}=0uXq$W@#IR{=e4!2LtDApgZ?txZ)oDznpCfqF@3KkN-~RLmF$w>RZD=QE zX7m(|QB2;MD`pQOkilXXah7;3D1=oDi73#Ne*ePM4jMQ5(aQJ+F*~ZuA%vPg+s3<^ z3RPYT+?_$ zpskEE*g`O!3~=VRT$*Z>rhWIzupTXBU{g-4c`}j10-!7Iyz|ah#~1@hIL+gl@ln0U zo3O=HwMs#l7nj<4g|p}a=R{tle&(6KGnjw(?sK^MjyK3A@bnVAPG>^a076Lq46h#3*CIJ|ZydjRW&pw;d zk_^Y39opM$q%$WT?`m(&1GcsxemX}x(E+su4*dGpzcTtF2nC2wYTA}lj@f>o2Yocb zV$W~}VaED&1mKV=L|O;fitYo}j|sB@()ocKP8m`}Jcvme62)$;G)WrEO*h@-ClpCF zkt06M=d_43vYF9IN`Vd))GWD3FYr}KlMi@+S-aUfWs^y)dFfF1MOo|5MY*hF+{r2 zGi`rF!$3;Jhqw>%;(W&XnG=MG#_Faq0*b{Nq+OSA#))ckEQb+=7RtQfy5uWk|26sq zgSg2JOH5I(QJEo@U%;8Z;0vSinBxR8W*MS=`O9Cr^uqI|OdNUhp#wJ-zY=GgYX9}1~fs3RCpAj%235+F8YHF z6l|iBe&?6?93st3s749{641y{V|a_8tfK?v%0TcN?%Uw=Jil1O8# ziG9ZPxS+Rj=B3=5xD4I$kMgrMNe{^L`yidVIC?X0STI1)L`#s)L?Bh*`@Q z+)mG;C;iZO;T(tZ^cxzx0gohm^wDqM^7@;1+-9pc96PbVu!Honi#S8GG@u8i6R^kw z1dB`LcSN@!Ar_u9XO1&FpA-FwC!SEUO#Xh!@j2S5+2k%Zw@U%TNK^U!U{23te6|7! z=L7T4?}OG7Z{lSrkiGY==tMdjThMO^h|{qG&t#rJ0`qx(QdI-|rU8NKE{#OgjQC%n z*78j*3OV2>TC`}9!Xz;dVTh>a4F)o*xWe>vRP}ZyJIrAWIfmgo?|9?n=mC7)yes}<_PM7nsJ}DVExuzcim+`B)vA+V1ubsr*66BmRoGG z#gZjU+#(_To-WR9u}}K4m`}iW(C^G4VwkoY51!&8kxBdIA2CwrU)|fyBS%5Jm)=52 z6I?oG%$Rxe=2<3TbPU{>f-s_ZwR0?5FfZXS3rM1K3`sa7EUO^W2t34Ty^#pWwM0>{ z?1+!o@4mvB90M>GBIL+3;Q>o_-tqOvPOfCwL7LeuoF%#@zC$W;!FJXVN=4~niW%e3 z(%5G-bT&}(ESUM#r32HX52(SJ0oTB46CT=;A>QN}tp;ZqaMRF|C@@G9=FN#BSmEe# zh=GGGnlnzPK!%aTqy_~gong);EP4ds)S6jGJV?itRIHlXHgXk$-+8bwG|8toiuUG z%|~yN_;j!*+J`e_=5*3CiQc+`t)qWZP9G#l9X!lB$F`QwojW4&~KYkf#lN5~tW zFOkNc_;5LXSC}i!>b=%Spd4qy-QWz$!JT{sXd;$;eZ?!zpS1CWbM_xPCR$r@hC=)9 zyKizTMsK8nuWz`LQOHZyLvIT_@d$94&YCsLkBG7u*d^Rzee($e|1Dt05a-?kG6%8L zdYg$u7NN)Kjc^tSrh*!eS%)I7Sc?Do=}*m>vBlB543uBJ?YT5kkXk9@{GnS5d;a4?1!0L~1-ber;v21pLh z?Y6d@KEVXNjZwyp8<%6K)Aa1wvvqo^q5Zn}#Bg%t9&*Sbyk;_uVO*C2;Miw; zE@l<3y!?`xTWoUiK7%_#fa6-j=(-&1XfatE`Rn zu6dQWI?Xh!^EBG^-$!*?n5%NlzZS~&LJ>g%ci(+?w=33VHec=(Qk4a)L+{di2{6;s zTW`HJ*U2{9Y-7&a<5UN2FmM_g;f&J$r7wPN+SJLn9XBbl>Yz^a3}?tg;v1nNIE~!r z|28Taq`3KeuDP|+f!YApH2q4!)=CYH$^bE`CV-xJ=8A4=Xa>$2)zs_xXwHb_5$8PY z>dVZ1dbScntz?>6?CKkhi_@o17d~p1+%U!(Mq6COL^Fp6XQ*v5;oyUoUvlK^K@G3e z_#WU4ZOAa<9;);+3)V1%JkHX*;EbfEyxG<6DVEnKDT_?Cr>Q}?C%R&)t&rdfBQ3-p z8H)?I)?D^8&NKtaD7u(;O_N&s>(d19w1TI~G6YgryBMnY%Pc_>DrxVduzIN-;Ld4j zoQ_F5mhrL29KFLfTMms`wC>`JO3sDPcGb5)hP%yRGGdrAJnMW1phm`s9cZb$yH&`j zN3Y90$`lWtX1oUa-Kw(sq56Wui!T-d!71RAs|)pOEgbV=YSyaa{JV&5VdXX=#AE?zMdRL8F4OqY`N=s}!VGvZ*o z>SSS|5XP-8I)_C~`YRyl5zV^P6Cjjl-ZG*2% z-_=TCBAj>E+1SS75#(#M>r(UR+apGdXc1E7VixYU($2h0;LKpK`|i8*XZrCg?T-Qy z@=+K&8MEQc*tW~gJ8r%CxB>esok=b1G|_dOk?+JtU<TaYLhB!M9gJ!2@5#ye+{k#bGw zQ`^wbdI|;;ucNpeV^iNu^6E4LV!IshK9gmx!$q}_noKmGM!fkP2Q$?8QJ9oZBK57<hZ`RN!peZMQX4$$nvqQAUU3OV=({Y1ab?h$A z$SMf4-hJ7!Wvp>=KUgv!o^lcnmbCV>!wuHV9gC?WRAGQLKBukqULjE!h&U1E+|3I# zX|qkd5^hF}9e2Wqzkbp;o|=F6m+N>MJtl6A7`wsbQ?DAc^}^b^-pEOlCfPrw#TQk! zAwcGAHMbDQav7Q=qvJQUysUnA%xb`;k`lc5Jts@T8Gj?~w?H~~!xdtL<0XMJDuv_jyH`!0vhnK&vx(M4 zoEghVFIyDYDvrj|8&g&V+V|O|Poq=y+3ULcB4A>#m?R<0%r;OOmoHy#!0S>yyrao7 z8?nKL2Y=+TTc3FPrk^}Lb?N?)G-}f+BgRdrjUJoBYvjn0wo0LwcIicp3J1;%X?Be% zkI?S=OsbL@A=4(l7sw*=VZkji3CNNbykm|jY^25*9{ zV#f+%qg^utZ6^hZ!Vb0_7h%Q)F1C=IYyB<8$b_MB^LJ*1&HwaM3m*L4xP`mc^~RB- z(%nc{VP?v>_4+$488|cl1H0wI?i%fUBOAm7kr@?z0cX&5@{3M7amPXI3h6G+(1T>R z85yIR4uC3UvJJYN2tyEEVjDx&r;qB=%x@ojFCH|i*%RW-Gtcajx~OgDI44h@oRBnX z(v*!?o-%R2V@FNiB3Wi}chsm+wzOjc>gD!+RN&0;VC7l4W_M+BsPdiiSM!So&Oq(< z+iuxw>-A8c1(BEwXuv^hcruyW`ut6q#se)U)JPi60BIO6pSWz(lZ;4f2?k-*U3qSB6Y{d7PXUN+b? zL1pa^r$cWHDjMlX9TYg@qqfgr%Irwgab^vl0(1zb8|h2ENI3h{rye}{phac7XRzdS z7iWlv7{XV1^eI}r#oToC0Rj3g_WZhJ9=__F0^qf3)hZG8$?@3vGaV&NY6=w0LB>PR zSFFDvwZ%%hT8vnN82ca4c+#_AWO{7#%{OOUrp%5+9c2G{uD(m1r=EWLDPeqY=1av& zJMO>#!~1PJhy(Y#i?bk-4nz#5xL`lwcKl!f*Coq*U1ASkbwUBdn@MV}5J7;Q6kT)M zoNvAr!GsAD`0;WXv!-C1|1#g1S?0;|mGy9jNo>hq^|IAsk0u;A!&C`pdn{eLWcqq* zpE1j6^t@O?tMz{s@diO2rW1W2TudYr_o)Sw=BY^z{;mNvW{_u;Mjj9g)x#_!6`CMM z@7PsYY*t7zzi)u$$%#Jb67JA__SuK|C?L<0rTmSwA1h|_oI;vBGym{|AAFyE#?wfc z>5H*r$2@=QLA+N;&*WK9h-#0V07pqE&}>j#(s0D9a^mS;yxfFy`|)#Ni-!VGM68(M zW#728BEn!$sr&Jr3q(x1qIvDU)aSXzn1jp;Ls!hL2k8tCix)4(Fij|_3k+}8Rf&}i zoLMG6ZtUobmaXSFLo>ZavC>-ifHfiZ@U5HzycmA9z{qX~H?eNceBOo!j4Y_V zJTL%d+Ks@P<;pU7{cTKZ3DOPA3=!k60kym)N@`erKF!}X48y75?zw=;L z8hbELT_8_fLYuus{WMJF-Qmn`Pyo-`7s_lFzrJ{3LA6AMLu8{+Lr$o2og`e$lkp`I z(&YlZm!q}bNN{Rl?jF zLastwrNLESQ}$F2WUSjpZ!vG+2R}O%W`wsonfq{Nu6)~V7oD}|=)vN@Z`982+Ghq? zilW2vLNQo|p#pVT>o(tF%AN256EM#IlNO~>heeRZw_tBp4%db zx$?9Gh4c0h7-m=UoVKU&KK~&aib-HEnm6Z^5eno*1eHLQMm_HCe*5j$M3_M;%Zy3K zxD@dQk*XaxZtM};4PtkG5^p`j8S2s^?0&xe*5&pnyXCUU`PHuZr znZ*Nn{CGxWlDHAS^t=t-t3eC3&9nnWA+=5Wh2ezG*1c-G`jlTfHJQNGY1bnjW~wQv z7L$1(*ko>peF>UPUT2UX%X;$0*%h?)7-vB_rmy8_##t;JDnt{C z_Tw$%=^%{^!+Mnq)niAwR!G|Oet~bVb2e5jSg@e=xpFk8>o!@%qixC%W(Gepo6`8j zFMNLbv@KtC@DTY`&o<#qKO?{WLFUh&Pe~u(+E?OA?Hu?rIJLGiVdP*dbINgX zd)tdLp{R50W;`n%gr-MGw@d7)$DF=ckIME`W{MiNV6O63WU7<7X&?z<24|<8ddl|G z$0ogNuqWDwvmlr;D^?}9t5=(JPET%`lGgdg<=iO;c2@Fo*_CUi()0}?lTKJ}L!%rB zqf81`qxr@-^ng;q>k+}UP zH+%K+VVsqF25aQpVgAPY&%TWHDL1K64gruHq-~!*CwVoGJUM>V4T63aH~hZ z{jEKB*?#}ILkDE-@PqKt;Y6fzW}opr8e6UYH&q=An+EcPHPOrQXfQ2vLF7;uMYv#r zMg_W*4*?JcMgc5CJpSTHj6+&Z01kAN>=I&>H)e>v%{AdJHLqQT6M$5RwwBFRen=E^ z%O_(VeF0~}hd=$PPfVM8h6^JruMd>k;@#vd5`_T`7aM1Dtj@@bKct8ShJ+{x#$!wFrkVT6Y`5`9Ocp*p# zQJJ^{pEb%Y6p3f|`f|P;SRppx#u;>cpfsJwV8hOnkjV#;W{r*7a05Lg7Pf*d<_PAB z0|5<7Fl{3-(TU0=oK?PkAZG@8qJ<(;Y_A19qG`2&Y1qltov3rI2GZ7XdYzBVNRk`!?9No@+m*+&*sKaoj(a)p1y)Ga;P z&K-O!G4U-}!!Iu1?PP>vmT!U-pc!QwKam1Cbut$YBoMrD(J z{_~#)X!5(%V0g05SEeCY+%(Us7<86sj4K2cP3e?VPRT`hsEYwIbrM}Ti<;yW4%o6^ zhFN~|2~+{aP!9u!-k86AP^1&ie9n|9Q@Co&&5kn2;$sat;r_rjH@)t~`C2CzRDtj*9uML7g^WnDFI61uVkGx6m75O9(9m&#FadnbaiVy-=8cdw|SS z25vlM_<=2Bl8HL}B}5RytS2MVV3bM;WNITdJvbN#s=$yz!eYdocix%suIzeWhbBfH zTcVm~p#gm1bDx>H<)mv59L8BC!3vp1e2X#;I_Mw{k;1LPdugUkghe1Mz5>n)%kkxx zVNn1XF$Q6DBr?pwG3)1vXr4fZ;|MdaP;-E6@RCc*d7-W5=Blmy3S=>y7*_~&Amb)8 zLSJ_Ah0C`YnjmYd-k2y#nEAz1(LYwz69XxKeM^8H#DET)j3fgx0t~!xmY^t$_E@xx z68a|<3)8X80%RU^3|?|kdTmr~Q!D5xe}zvYu+fBQ=lH-OMjFTdd++(0gNAWdCRoZr zIiy8AY=W&~Hpp<#l(A@D7?ANR6<&W5bSDI%3X)X;GVxEW5Ha^=LeK~1h&Qf~5N3vW zxU55LFoR70T5TlI%GOMkeT^BIWsFpsGf8Fzh0y#De&GGP&mLEH9}JnC9{cq%1(4w; zj)3sa8m|r04uh2FE5CTL@4oxm#BZ>(PbJq>X8Kax1Z0LB1_~sRWX5i+CphA)v(6Hb zLh8dA>jcLUW>_ykR#{=EnFcu<{Bb(u%5A4l^+o~Ev0s8EFg~ZUe%#`FeK-mLnTd7B zjyvpd?%o>=8B~=&q{lczOBAIB02xPs-ZldyI^2PqOjYZA9y!|^5N`@p(te0#0vT=s z9Sp_x!c%4d_&aR-OHIOw=zz-@YKUfhGD-num!y6gv^*{bXWqPdoSY;?|5B3J_Pg{J ze>VCS`9=ami%|z-K$wtcdtz<1*~G#Ai=Aa`R*oNy|)L*a1#e3!;5#3Q@}!FYe{exlf?mN4Pl0c zDCwuMj9#`KrHH=Z1uuvt;l1~1oz|>9=5~BeqmqUnWI+=YFb3lghd9`imJGE3kQ`*v z4RA)`X+)~Zd{9GO3KI6gO*BSlwg_^XsT3+=C^z!PC``$5RMs=tGZV5qxox{(UJ_a`-a_{2NXM0w!i0@0Ww4YGJ^^w zie6-WfB3EIKDCD)LKE`L2*fx;C4NZme4~zMyU_qo=_v-WH^vy&jY`_}2qjrWOq1FQ z!VGb&&faXZ$;-DH#6N77gQ-cn0nT(9d>~8{vQ^&F^K?kV7Hrv(*2Z&Kpt9r;%S18c z^5Jk}OgGFBSK(j`*EO5pL7uq`;|vgaNvIAUY#k*=ED9%grI{1cZ+;k)6roA~7}Gf+St^8m_l&bb8wUO*EeB)ph#F>41I~;YJ8iSo zkhjb_!~&%K!$GI9E`A}G2$$Taa<0s zEc$fYqd)K=Rc;}rk(&&03@|ijq~M75gBGXmKIk_ZPMTr!L}Pgt)WR31o_Z=jeT$L_ zwk*IhbLQs?SjCJyizCcavm}^nObS1chRa&4t=wY+D#uq)hm6!A$?y?%F+c`PG)6oX z!VFtUz?n>nlQJx-WSn8cf%9F42d&kfu8yxwK0#G9WW+%hTC}-UUg#}18FSOhp>LVB zAkTtwh(v+3%E}PjgqChmf&AivosFCeTS6Gls8WK9#Y70>Hf3T-BqnWM;Q+sz)WziZ zFof{_;U?M<6%nvO-1Va8_V zVl`|NX7+aVbBCwyKBl=07)p0LlV^!+s4lF-(Zr`jj0w1*cQ@x9gg0pFPX-)go@cVF z({-s;{gp`SB7O`PJ|7^Zh^+Ey;m8m7N9af-goK=!ISb<~SbHGMc=#N9eT9-i?MGF= zh7_<%6i(PGBvOIOggRLbBsco_cB2kbaDPk~J90g-%vzRbIsMG{STRj*<(WN6)3|IR zZ3k(={p4kIbx$hnn`e_G12WA{UJv6nF-Bbksa%+a-Y6dm!I2F|1cpa{ASjK#BCTW6 z#c0TlnNzZWt@34FI8XaJT^s=n2qIj_&KBdxZ?JU6`l2y*3uieA+nc6A=?5CuK$voE z@@Ynb09i;fAfpaxHiQMR4B7bsVR6U=K_%&y_|AlWD2;tHv@nkx@m=2dv5$Q$y%!XC zKAVWuGOEfsl@#*|LJ^3KL%tozXgp%?CX5?(*}lU#tEAa*CJJDjf+Pbn>JaHgE##}l zO3r}g60nleD90r%nmOYHF~69?trEZY28GEIF&CD8TPMIMj8`zA<)qg^K$A9f{9JRh(7Q zEq4WzcE*6pVkxr>tU^vIDPbj?vyVcn@G+8?C}8Z-zcw=%J!;gY%O~UvxSpiDf-^S1 z-*~qw&ySLzUm7BFN_Q{KL^qvn*3EA^d4;(*oY=jp+WS<1EF>9OOA?shfE6GMb&&uA zFHGd%vI~(0XNGV56-UT3IP(;MM)+_zLE78eF4d;l_K)rq=mk_2F7r2j^rIh*-*^v4 zKCw+tMu(t@Rpd6YSi1H4D9nr{UBOu*Dkl=+8Kl|>HA*8+6iWhUTn3%?e`-wcCA2}S za*#1=63B26kinMuKSw~V3C^fb)T)RCF|NRw%6qTzoz~pqQ^xSDU&63&kKOuBVN)Yn4?3z} z_z}pAA{YlCLXrU)>na={0WxiaFw!>;P-}#x}aKVW|;2(ovO1-|~k?To? z1s3Sur3L^Q$z67Q;GiVQEFFpi9gqdiVq+9#>i&<8Bb*?~*~kSq5ad~x$dcd{iK=Jo z8{vi9MTh!)gHTZB{`)_C=9y4vC9(3#8`N z_In!02vH#8sRRA6$&As&Qh+QZ89ox96x?LgF5@iCP=~WIoceIqy*)wtoh%I+0AY2I zA)4M4U*%&1WHyEQTfl8zcKco>87t73_YOK%Xr5dKW$ihEn z>Wi93hIto|37Ymg(ZMkZlt4yH43G($7Q-Z6&>Ja?>VYumLx}6LeZb=1J5TOShnZx6DN#2W9fPq{ZUXF`xR$-FQqh<1HWTfeilEt%+AQ&+yS7@4gw6PurPp6TvXU(Bw2vW zBu1!<0Wy3P2dIg#;7qeIPBPI5ML09E2grCpD2)Z2d0pVF{4H5iJ4yBu&a^+pjHDJI z6k+UAgP;57>KTc^w+!E6@L+(#8D|h$oqx_5n{2eC@0`HGgTK~=iNW1pa=DsK@PVTVaF zjL2a>VJNyQWB?h&*exD0t0xSd9V@|)02**D(`HeHl9rXMPGS&yW!sX0;2~+uMDu#Y7CLfbXpX6} z1T5-e2h3JO4bJ#MBIM}83ojH}boSY2`?W!e6OIdcmT*Q`0x^Chm9Z^p0p*>H2h|N< zotxvVX~8bs)Fh=*M$Eu_-}_!5^D}0Ju!Pj+KsHaKVn}CD@zwN_9k$Rgh}68j5zI7y73toOS-=me|=r&(zPWR;}{;wVgJW*fXmDpne;X6$n_MK=u?s zMwqR!$5w+Z#2e!*KxU1w1KKd=Nhh7e#Iym53i(AqZA=h8lf`M4y0rYIP(d14>jdxy6eLq{;*x`n`~v`+mxp<+IG~AK-ix=1F}#T zxe6(MVU{HaV@NUxi-SNT%wVenW2;YK2Yd`Q3Z$)4_(#+)iXD-|O7jZiKJCV>xkiq0pY{l9v`12nu1g*;Px*H= zsY?T1AK?tdo_!`fM+sh$&{|fe5AjiCxo`B)!3Ro?PIy_4%^H52BNGbrY6s z?=77ZMnIElaa_sp&Q+I+M|C*nB|jKIcor0}d_}o6Szh5020S4|*pPw@J2*4yP#^Cni4UCq1Lc_ z#b3%54?T{nxYsyKJeFSq+ibJVOuT`z1OGNI{x3X&yKPZUEP*DRg**$K0SD)FEEr&E zb)c&b9em_)2}}if25oQ|sv}TFN$`R;2jF5rV?94)m}_K!mx`ew}&`TW> zTG&W$44k=3<^|L|8;^%-cP_PP*xPFb~w@a*xYj%bz*-rVaC%+X3XC!4QH5_zzCd?XK8xcuaE+b$uOc0 z6ab=dfSM+S>WH}rFz|{)S`PdL&Oj}pEkP}ztpl{Hcg8{o;7rF+;}IdcM;vj4Vuc5JXyMq8c72Zf#A*GGa-fjSG~%Z44m%Xx%JD9utDiaFTyc11j}KHp)K-XBsnk^5kjL zrlAH&oXfMfyyeYscKlAmksy7qH@3OQ@z`^#8O?5>wgM#@i8Rqa^XAPXlgh8FKhbf- zEqqFz!5Qm^eHO99L$&!u3|@z?=i)JG%>NZsB^!pgIB*=@sw_gh8I817@o? z=gC#aI=(uN1hVjCI?Hi~kR#sIAI?dy^Ii@b=3^+g@{J8)v6Xem@`txK$5h%s|M8Fi z-`;(|Sy|orAAdlKARt}Jh$3~UL+?nFB47m!Mv-Pguz<0zu2I37C^2X(*{BSb6pfl> zjhnvyljtVd6x1Zfm{_nxMNIjptl53vdu9&L+HLX$(6e=G*S2WBZ{H5vOIgm#y&lf)COz9p4?m-7#Ku&-zM{vI zVqB$yJFlRu(gT^c8(+wBMmAtnsauaT4i$F(2pwKvrv{ldDKiLSjy(wog$qNF3T%aG zAk5UNkb<5Cu>6W{nJTJbN#rbK!a{2UZBB!NIxE8F^wis!(}3nsji?p8-d(fs&#%1l zvO$tswQ9vmbPri1Tu2^)(~T{ipY zHLF*vG>5QaHi7yg&b$Vkt#c!3)P3d3(+BtNI-~dYQdSQIEa#H)Wlj5B(s@M1_kL!kx%Rx*&?fB!w3Hl4I+k+8jkx^+_# z4=P%*fs#*26eoKKdAI~+vb~)X!kEIbESHqikZhbzRyiMLDtAMut7+up79k-- z&dIYLKLkm`w-J!Ep*xnlm(Q8=#2M3(v~!WPX`ZZ|xxJL-yxi;I>>kfqe067pN<#!da}SF^ox?%M=67S|iNq zi;Y*kQ!)<3<)PyN=S$pS4rlBD7f8vR49#1*bjj#$MaZh$fxU~fci!11h(le#)P72_YzG zn%clyD%g!~03{=7-cqYhKXrD$hV@XiYPjURhciTFBu%+fKij(X%_dEnc=DO0Rg>}< z7RdbanWqN~7{HepYf;F^n2Yx?7`G?;6qd>Lux!~90r!Xu)i`(sG5{xUdEiW0ljJQ4 zkogW;mZHoAQZbQ6$==w61l3d?PZruH4WcDBP!kF*YB@>YBO^;fkvFk+npJ;RwhxpdJ-E;_t*4TY{A zuBzm$mX9dj=3Sb3zpv&DXWU=k`o?3=KliL585DtlRC*dYduQ9*A31K`rI%i!bg*_5 z6IjS>=c_U&)DU@m{Hs>2!U6x{#=GxcvUt&|m8bhHAa1?&)(smrq#+BO1u>&!Ie7UA zZtxWFQceNH`U=S`Z;Mp{xUiWe)`Cp^jGK`;r|pU@r;4c|kls|SrKzoYon-#>+L)H?xAh`syn$lU1kc*0~iD&W@iy_xhuY!65l|qkA@J z&>&AT-o@RUQFc5rzKI<^jf@BKowwh3^?ToXtYO23Ubtz(GG!*4LI#fG$Br&9-w3B5 zV9{JO8&X^)V~}`KhqD`R_+&|!E`EFZ=_>@Gj2kzO)bVq2ODbgu18WdS#w4i=@A{}= zArt6<6neN|e)5wa^ECiSdh&;v@RN`{6iMDTR|nJwKz$9-kXOU}o&xL)?Qr^beuIC}8fSw*`spEI{j?+hUo zZnKzB21(At;n(69V4`@3YH-R~yDMfrMx}nmiWLgij_e;w?`(VP^)G+Eyj81~So05>IY|K@NP(X6B3;y?XV$YTeqgW5+C7 zbfReAU^hn2(B>6yRsiRXH{QqsjGRR!1JILCJ^?Qh#Svrrt#5sE?b<6=pSkLqtJnE0 z1nHa+ZB|3cXCzKm9;?#j01YUK|i=Im%Qm_Vs7=i7hYv?u+-{)uKfU z##C0qD!M1TipUusV@XMg!Lh0WR_&Z%Ue~V6Fgk^tG;P{c1H$>|eQeX+|Mt*>Uz$H} z9^;U11>YO~-TIYy&q>!`f8C~x#BLOn>*Lms zJp7Ql9n@$T3(Z^5t4{Q$Howq8jnNn^#_%`_-=d7n|IuGo-ZD=OC}C=J2Pa9xoFvsO z`15?uZ02wd?KCjz+DSOh*xnakbYV${mRHUwa#rOIBni9RK^?c z6)!$lErb$y`D!EaWX?P9yqj;nS!q>>;+8ul<0y*NU;p}7F|)dYiCW~{;22ah_h2!n zYGRc_XI4!jTgo!8?=-#PSk+VEK zBTnkEte5rc*DqeY*cYN<TL;7T1ik5w&+nf9 z?bp8gm91~QddFvO>f5&u&H_~tFBuEjlN7?mRqhWoj)(wKcjl7HQRu zx6i#NXWny8#vWK3l+0_x^!SAz8QHUSeg4#04q;(7Njx#*Unn(D^TzbtsEG9UzyJLo z|M-XLGtWHZJKrcU|JHy_<_AP+q>YvzneeT&Y< zDn=vJl7wZg+_`zmEU*;tkp7vMct8{r&&Qix5K?%9!ze%*NKr@_jOtp0BmZw`dL*(GWgW+{cHie8S!bqK$if9q9A9Cdy zT{t3Jwrn|g(7>rvCeJ(er~%nXWG@f5ngDA?cTaK-ggG}BwWfvnE8lqMXK$kx0kUu* z@zRv~%;ja(TE=XZdu!!8Z~y4YA71`(Lluo4Hf(5qRV?xpe;AkKWWol4GcGgNMZaCX zw=6xIGWpP9CB4Qn z?l4m|{s0XD0<3_T+BphGnJNyuMa4+o+utjmDyXKA2W7-&@rRL~u%B?WkblqVV~>4( z>Xb=Y&J@N>c?`uc$QjdX&FZs5<*WuhQ{+LQ$m4^nV#0(8+(YVHF=37w>59071dM3n z;tCO@Mf`YW`7FRk`(ei$qPmtZV*xTR7$&HVCBn~!wdGM> zrxrquhk`Y$K5f_(VK3bFzy8%P^G6o;T%-t7n2k%qY+M`23k$ujaOUm8?-MyYV&>$- z`xZINy#q-SOs^W5`9Lc%5q|GLFp@kgzC=|w;dAT_o-PZmm4a5qpTx|2o9<`-&^dUQ`AuJb7m@ z6e3|E!#IGKYP9orXw_@}$-mGsuGc?q%QzlWDWFr3q)1i4wK(&#B;hIum7INf&h&}( z{8Q8gbvj965&qv)iVJso#z7)aS+sI%T|v*{acv*-HD@A}GQa%!lLJe8z43?4xBNn> z%$Ck9W}=0*yma=Nrw1oUesPX8kQM{4s-lrJjZB;u+y`t(0+vqe*RMBjB+-JJCPtg# z433gjpahV8vIgUx(-}x1l`fhZ`U@FUEnm;TSJJto_=_}BIO8H##$DZSp8eGWU$}4G zy0xI!6;s)_Hic8jlDUkJA9Hb4nxT+SuL}9}HgTQ?8YxYIBml4m1A?? z<^_vhy;_(gDY~j;YcAC9Z*4dL4!{&3%bDgt<|yGO`G-rNYyR4;f7sHwZS&v!`WY^d zEN2PT zz4PX1m}VZES_=`#Y6VQ=B_9q=%s?g?AokpI&qW)~^6O_BF3w%ODtj#zq``=S(k-0z z>Ul_m28mB04IbE!?V3|Ri)4gM2DNM}TAH3nSj^a1KK?dt9G8Up89ie+W-1p6&&OxPv|j<`)a6Ze+hSUxV#-&I_@{c!KTJ7@BU ztJhr_y>ltfw!QY+tEZi^EI2`G=1k{CRU8rpf^OZqfyn^ZI#xqX0vWRqPr!njs0!`r z^6FtRsh^QRZ5=s~g;^qpFy&(tYdBlB_=L4r zT-LFDyZss`U0Wqb^h@SU8xuJQ8LfJLQgva7!P<^dny0E;Zl5d2S&p8mK6Yx`;>uzV z&)K_|Gl=BS^FC%Ha5=w?%R}bUi$1n=$)Xfzm2$Ri+aLb$+8L`>)rK>MANN1bd@q|T zLHLG1P_!{736&{~fJLiJMPrgZniQ}L!13Z6&NzpgFpD1Qm952n#&2mJ$SmP|%-P<7 z4xctI*ua4^kco3_)ohayL7kJI|0MH8)0k9+?JdrxGXb6Sl5{=? zzM46ssggI)*gkEFjnw%j@vhOctUguv8`H%n8Zlyo5fM1%*@uB48fKPXA7>$1E@K*!t~3H812lv)M?3j5 z17xPmKU16)G#XX%F1>I~tZN1_d-B_l%q`7*Z+>)0vT(t?G%oTyjn!F_IWVPv7*@p% z0%z$BoR1(d?G?cff-{Zpr%q{~U&@M0-ixyw6k;hZn5nw)yZ`&o|EapmA2&Rwe+HUQ#e$183@I{QBaqgiBv{-L;cOloq9{;2qdIIs2#P zxxfD9omHnURYR)ES%$VB|LDoFqeo^r6W&x)pA>KiA{OO=6^=(e7C7>uh8sE*IE#J| z8NPX2>X>Rvfsve(KCi^cOdF8)spT42EJk}HmO;$a-{po)$I_6{iJ@D@~iwiN3vi1(^^qUv=fjhYaY|qifq)1NS>|RI@V< z>u~+?-9CAAv-HJXIxT76uFYF-y%`A$8B0bD?vrT_-gp<(a=^-&#hFlhRVYTF7-7~R z#S-oj*osq9M=C5AcO^p0#_~4K@$1`L@PH6A_`)=ZnHpRAxLV!RcmiQMn9DF4-`=`) z&X}GxTa4+;KW|d9czoMNjT+s1?>%W^$d5PjXckgplF^!DzgJ?KHNt9zESM^>J; ze8tRz(iM#PFQlxp%aGmm^5n8d8=1mb=d`%u3mc1@}o~Xe)iI%#vL)T%eaG+nSC1^**_Bm zv0_Yebv14`muOX+W(`s<#|qvk+@g;hqjOk!EjUyB$r%5kKr0Q_2*4aEiiF7oSBOfR z`k78KEKHv}l&5@YdgP-A1ZP^kK?Xb3wR8*!3Dk_h-h)?wEJ*V0H(Y*9HNO1#JkuFO zo-=jd;|?FEMM5nqQbLOC_7}hSMO?B2nLk$qATvP?TJY1K{#4@}eRUlAJp! z388UU&q_W%J>j3e`~wf0-?X8_UXxe zn(k;wlVGg#7L*;(v3;LDeLSNyPsV&nSKXqL#Y}qRm=6KSX5B->0qNpa!P!^7(!O20 z%jcEEl2y#4??8>5dDJ(pzv09qCY(99_o8ua5AWC5qn^}z-vy)Fe{@`jV@I?-W<MR?Xte%i?Hm8sL;pCT%NKQC@ zVO7pDuKlylI&Ss*H zh)&25Ez*T8z7>ik!BVQkP zMlHpeGekd+sBtNAcH6C=8B%)iwR4KYeHR8NNmReoW}n&o^NY`4Q&!Sw$?(1H3vnk7 zYjD`@|k`r#Y?&^YeW8gzf2M>ZqEaC(&ZCykNpgi{=VI6bMAa` zHr|1xS_0!HdqHMy{|2|*{OM>q$|%ALIN`~}gH)quffAk1)Xc~aqmFTC+yZ5viHI#j z8iZs35q-!kG`4~GMl90508p?PK_&%fO324)G#U|k{`uz-Fq}!wP*hXP=1nfCMU+)- zp3&mrP-|M&_rMV&hU*^*$06$dWN$xBZuy2n?r5Rd9T@~esFfq#N@;i zj#s7N(a$EK6K0hBI-*Qznl7;Kprju3`_}rhah7=Qgse--|E45GXTMkR?IBi%&YKX3n6- zZNa;tU`j$f5Ej%cEolNqn2YLg8maNeg$STfGYep;oN@fi$GVzKY@SA;v4)L#jx#4l z%v602Zr?<^#Lg{Q#uGWDT|;p<3`jj?b_lPqv8o%p5oaPwa3)|9YBMGd-?`_xm+h^7 zaOR;cm|SYe-%y0JW@Cmk;k2VikBW){se%a&T!qxsW-nty|T8#*ZI6x%bYm@tk{T(yD3F zZoh^-x^?E(5$00^Y6ZO^7J5-}BnfUb$T`TMHfvnJy^M^VdpY%nvstD4oU!tBYC$SO zQk)G~e8k+j91{iciVK0LL0R)LA0y5}`&sbo2hP;kI1>3m%xXCkXbehLq5%(J7uX_l z0zKH1AqBw;hrlt(RC1%3;qsVi!?m&O+@~G(X1w6eEt8VAOu}oN?_73)&T@y4UQp-f*UH&73yz_19mEkSQ!`Y%Dzk5k#b_%cw|++UFAqF8lx) z?1))N1c~WL!`Px+lme&J(ts5OjMEaM_9LYsb3~X@$|z<|?2MJC8GB$Cc@|WphIUDY zmn6gbbrZniaMhufW-FcdKF|*5;~W~P`5TR(KBUVoc_kD%%Nq%@j^7dywLLpFed?z_ zOvzcMYnR%EUdGkorT7P{(v%?a>xcSTXgmvIhBH1!zC<#nQw+%XM1<@^El5{H4PK;6 zN?WRChYlS=1)Yo{FR7&s>f2qfmR)yCwRMQ*?%%0Fx2~PeIAc`}zQ>4H$e7yLE5QeV z^zdXca)LN{?Q^^CZ1;ja*Bd?atY-E}K6S;}%(Jwl3DV<$sE#wiAo@wdMHq;0a;l}7 z60=GbtN3rZ>Y9dWonj!!sZYsJMY<}?#O%L7SQ;|N&4@v^7fgT*ZC71+`GO%kzh;(G zTF;-HbZedTIrxBP`|hhhUknh=(YAb~j&fuuE8e7`3X`ARPbv~R0 z)Uu}HoxC17goT5iynH!!S+F>BN}D#`d1%kZ*L*1E!YQMYz8xF%>D5EC-!Fdt)7a-F zjatMjW;j7q&cx~&-5+EU@9U_dp4Irs>Jw+`C8Z@T@BG|njk1v~)Nd-?j5KCm&8~f4 zr@)Q2U3h8Q=3SK0HZ4WqjM}D04B6AuixY%?!3$dw+9+8;l(`~}r=>j_VUl40I<{_R ztkWFr*>$s%4oOPdH12j_N&o)+UfII;SP_w518Uw9cgh+jyshIZd@Zp{FuDct% zZqN0JGk0}Z-Z6*XO5sG1G< zN}|7`prM#P5D7f()KgSa#k|EO)Bf zL-dFVk@~(ASyIw`?~D#IUhdk@f>SY#RDNFNt+cf73ora$$pt-C>));QE_%+@?Uu%` znV1~Zu2IK!t-Bx8&G#9R#6&cWDO!wS2@Alf>Jbwn^*3zzbfZT56#XF8-Qlpj{&6;` zcasGR=Br@@3Bj2!EE{dH2F}P5Z~fG%Q$ZFugPK;f$eGF+f4?RII0_#QoKQJ*G^x{4O`kV8QL}J)2T_nK0TH$SrYL|XCi7L;!0$r za23u*Mx%zq=FOT;>G5Ho`A)wTyL5;3k27U?{=8%9N92sWowVqL8cavTFdD~?AJ4+f z#9n0+FMe!4!l@fAOBrwQrv6^eC&^l$|rjXT}LX zq;0Zf!QsB&mL760q82za%LyVb^k+Z&S&Y;-MsuTv4f4NSQ=3EApKa&(lth8RV8MbFAUPKAZhHz(AyJvLCkCxb*o_J zrcd3tWbsJ|L;TZEKQ*ZLfg+-ISGhZ~Uk0_2{ky3wsv`Cc>Qe|JdHZ8rT37N2kz`yGdLo#u7k<&VZ)~O+@0lAoVBma^lG2X zoi&xe)R%N}@Cvh9sGYD#5TTfcxx$%r=_QvmZIl_GY>z1KyXz$DA7}3LgdUB~T6Ox1 zFZ@1m1~~8W4L9AGLqnWp1ZqN4Mbl7JR#t|v$XPHQ`5Ofa@_-2aurdE+rmdj*bjR(t z8GuR*uM|q#=O3vO85Rn;Xu9^e|(TT=XG?1e*C>$}(86`s-cfR&( zkVytDDA*)jvHSA!#V0NDbrnZvH z6EVTfp^?mZRD{hEiOUgW@G|IzSSvxq@Y1?Q+o~ZpvzWtW%%~CKP#m2LW^}JswR~2) zdNZGqZ`mX{pheQHTM3hxYca=qw1k!GoH-jg^@*7p>hObh|4U+5-$HLzs(LAdbQhg!}Em`-UtjY7C=Nz$s@ zkG8tmhtHZhV>-xagWBHesda_3i>D+5J0)$KC2d+YfAnjQi2KOljDJLQC}$%l2*|$r z)vwN&K7Cf{P8h!AgBRpFzK8nCnfed|>B=iE50a+H|NB=To;l;N3?JpW!xLL3d`g#U z0~o+7BV}36#C>@0OYBB@T{?Z4lcZ?`;0?*_Dlc7p@kPUimXSus-{-)L zyP{;BJt3oKzB2QvYc6}`l`T1(A-#SeJCclETsa;A`8I-|+( zAp$hO+ z)nm(wc4LvVnqT_EN|N%sKNlp;^yZs43?1Bmf8#sk93+Is(%^9H?lDcdamw!!*MmXfgb>#kX+ z78UVIX9Qh|3enq)tw_cKYHUb)#v7>>`{Ii)rfTd)zp~c$>7TDzvwEL~4Zrg6mw6Mk z031K8E?Qifal%I>U0Wqb&6-4>)y5)fuoH15Oy3a6KB&d}+O$yvV~N$N5?wb>rhaqg znfM3`Uq;}}`})BLADn&o%<4=>!*-xbM`@kRSd8jqA?ZDB91!NBZ$)T4V>AlA(qAnN z8DZ1adh*0EAk(kp;LiIq(&}cRFk+;rnLgdx;VeB)I2+s8J1S?y%#C75cin$)9$|MU zKAn2cnR_{Z%D~_K?s<@9(;IW=%(>x{*XMgf#DnnSYdNE2T>C!o9w1{rsi`QEI;a^@ zRir+@J_EAK@IK|`r>|Jis#VMHe*2p^+qm)WI{u{)A2b|R(qQPIeqJYT3rW+Q#@r2@ z(KDzScj)MW`|QNRxEJrL$l2`VoJkEwjuc?K6|>d@m9M^*G7S`#0>` zseOwUEwDw;)X(@qG*XKeS$D-{WxYD>#R{}@FRjQ~mNO%`P3+h9vB$n1P$N0VAHQ(p z-327gAOs@X^@B#3#D>J2j233;)?vf~pZp#&c)+C6y3)d4o6Fg~+Y~vg96n{;tOg@W zOV~(R)ZTpHfiEpvwlu$%MyU8W)XBtJMWa#PQ2joZCN`vsl4WNO>E2!44!gcw+q7{* z!vXEyXI{&rlQg4#@Dugw(qj7Lanq+wed7DyC2ZWYdV(j3k?HDC3wtduYIki`VN*X71470$n1KvlAoDHWW9QDe`*XKbGR@h|n>RCV zWGx>^UEXZn%;NY2@AG9@M`da~cyjoK!ZQE+2a zxS(XGEje!eC$0vWL3@1>?YOZW_e6`aE)&1Uom-K!>N)c;efna;=pol#d(GpIKaQu1 z&i~jaufMi@Bif|whpjW2%KmCuwOhCD%F|CfMSn;Zqn7Kl79LusdYJ8TC3NpN;UZ@> zaz=-I)A@wy1N4CwX>{|3PwR1Y-PLPZhByn;XiQpSoDtFd&pr2?)-rXwV~#rFyvfBz QruS)U?Hz=Lt4Nan15>(T8vp 7) then begin + error := true; + end else begin + if (ParamCount >= 1) then begin + if (not TryStrToInt(ParamStr(1), args.width)) then error := true; + end; + if (ParamCount >= 2) then begin + if (not TryStrToInt(ParamStr(2), args.height)) then error := true; + end; + if (ParamCount >= 3) then begin + if (not TryStrToInt(ParamStr(3), args.power)) then error := true; + end; + if (ParamCount >= 4) then begin + if (not TryStrToFloat(ParamStr(4), args.zoom)) then error := true; + end; + if (ParamCount >= 5) then begin + if (not TryStrToFloat(ParamStr(5), args.center_x)) then error := true; + end; + if (ParamCount >= 6) then begin + if (not TryStrToFloat(ParamStr(6), args.center_y)) then error := true; + end; + if (ParamCount = 7) then begin + args.out_path := ParamStr(7); + end; + end; + + getArgs := not error; +end; + +function generateMultibrot( + width: integer; height: integer; + power: longint; zoom: extended; center_x: extended; center_y: extended +): TPxData; +var + color: TColor; + i, j, mb_out: integer; + p: Point2D; + palette: array[0..255] of TColor; + px_data: TPxData; +begin + setLength(px_data, width, height); + + color.reset(); + + for i := 0 to 254 do begin + palette[i].set_color(i, abs(64 - i), abs(128 - i)); + end; + palette[255].set_color(0, 0, 0); + + for i := 0 to width - 1 do begin + for j := 0 to height - 1 do begin + p.update(i, j); + p := translate_point(p, width, height); + + p.x := (p.x / zoom) + center_x; + p.y := (p.y / zoom) + center_y; + + color.reset(); + if ((abs(p.x) < 0.000001) or (abs(p.y) < 0.000001)) then begin + color.g := 255; + end else begin + mb_out := multibrot_check(p.x, p.y, power); + color := palette[mb_out]; + end; + + px_data[i][j] := color; + end; + end; + + generateMultibrot := px_data; +end; + +var + args: TArgs; + img: TBMPImage; + out_path, fname: string; + px_data: TPxData; +begin + {img.init(); + img.open('./images/k.bmp'); + + // draw sin + for i := 0 to img.get_width() - 1 do begin + color.set_color(255, 0, 0); + img.pixel_data[i][f(i)] := color; + end; + // convert color + for i := 0 to img.get_width() - 1 do begin + for j := 0 to img.get_height() - 1 do begin + color := img.pixel_data[i][j]; + new_color.r := color.b; + new_color.g := color.g; + new_color.b := color.r; + img.pixel_data[i][j] := new_color; + end; + end; + + img.set_width(400); + img.set_height(400); + img.save('./images/generated/k_generic.bmp', false); + img.done();} + + setDefaultArgs(args); + + if (getArgs(args)) then begin + px_data := generateMultibrot(args.width, args.height, args.power, args.zoom, args.center_x, args.center_y); + + img.init(px_data); + + fname := get_filename('mb' + IntToStr(args.power) + '_set', args.zoom, args.center_x, args.center_y); + out_path := args.out_path + '/' + fname; + + img.save(out_path, false); + img.done(); + + writeln(fname); + + {color.set_color(255, 255, 255); + img.init(100, 100, color); + color.set_color(0, 255, 0); + for i := 0 to img.get_width() - 1 do begin + for j := 0 to img.get_height() - 1 do begin + if (check_a(i, j)) then begin + img.pixel_data[i][j] := color; + end; + end; + end; + img.save('./images/generated/circle.bmp', false); + img.done();} + end else begin + writeln(help_text); + end; +end. + diff --git a/ucomplex.pas b/ucomplex.pas new file mode 100644 index 0000000..d0603b6 --- /dev/null +++ b/ucomplex.pas @@ -0,0 +1,71 @@ +unit ucomplex; + +interface + +type complex = object + r: extended; + i: extended; + function length(): extended; + function squared(): complex; + function mult(a: complex): complex; + function power(n: integer): complex; + procedure update(re: extended; im: extended); +end; + +function complex_sum(a: complex; b: complex): complex; + +implementation + +procedure complex.update(re: extended; im: extended); +begin + r := re; + i := im; +end; + +function complex.length(): extended; +begin + length := sqrt(r * r + i * i); +end; + +function complex.squared(): complex; +var + res: complex; +begin + res.r := sqr(r) - sqr(i); + res.i := 2 * r * i; + squared := res; +end; + +function complex.mult(a: complex): complex; +var + res: complex; +begin + res.r := r * a.r - i * a.i; + res.i := r * a.i + i * a.r; + mult := res; +end; + +function complex.power(n: integer): complex; +var + j: integer; + c, res: complex; +begin + c.update(r, i); + res.update(r, i); + for j := 1 to n - 1 do begin + res := res.mult(c); + end; + power := res; +end; + +function complex_sum(a: complex; b: complex): complex; +var + res: complex; +begin + res.r := a.r + b.r; + res.i := a.i + b.i; + complex_sum := res; +end; + +begin +end.