fix: add les 11

This commit is contained in:
2026-05-19 18:50:11 +02:00
parent b053fc7206
commit 634789e615
37 changed files with 7587 additions and 209 deletions

View File

@@ -0,0 +1,2 @@
NEXT_PUBLIC_SUPABASE_URL=https://ooozbbewsglfvysikbsf.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=sb_publishable_QNSXIe0FBRAP-Wgd_Rb_uA_GB1WcEHJ

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,296 @@
%PDF-1.4
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 6 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /ZapfDingbats /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
5 0 obj
<<
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
>>
endobj
7 0 obj
<<
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
8 0 obj
<<
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
9 0 obj
<<
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
10 0 obj
<<
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
11 0 obj
<<
/Contents 26 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
12 0 obj
<<
/Contents 27 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
13 0 obj
<<
/Contents 28 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
14 0 obj
<<
/Contents 29 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
15 0 obj
<<
/Contents 30 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
16 0 obj
<<
/Contents 31 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
17 0 obj
<<
/Contents 32 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
18 0 obj
<<
/PageMode /UseNone /Pages 20 0 R /Type /Catalog
>>
endobj
19 0 obj
<<
/Author (\(anonymous\)) /CreationDate (D:20260422152406+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260422152406+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
>>
endobj
20 0 obj
<<
/Count 12 /Kids [ 5 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R
16 0 R 17 0 R ] /Type /Pages
>>
endobj
21 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 941
>>
stream
GauI5;/_pp&BE],.K3,.dqcBC].D<q._T0=8le`Sd.YF3CREa"2Tm[3;60T`2\;.i\N$kDW(&O#bjPC@k!&q\!?\WIc8WPN%'Mlda:R#bU_Xm%%"DfO^F(36@i\-sd-rE;0N"!d)La]GGd.RO8<PeqPXZjU,D.ZYi!JR"-R'#J,g[*Bd&l8J-mOrTDlM5a`%"___a4RdK?\_D&1ZnJPSp.hWZ:fo5U=??NS"Z/AK+<Ue3F5*1HI_RWb@DuKl?$*(QL,/OBiuUfkhuIk",tLU83[sa=$kGqG\`$q,AT2BA;,mCdU28[O]#+l0JgQCMR08kPJUra(@m-ONcHQNSO7OGP0VW4u!#Is(X4Ei8iAW8^inu9*O2$'s1cTTrJ:q!C$PZob0O#,rPM@\M_+.T(:FV^%X-lZT#tJbns@%e-$)2em-!)+q"+^3(HQ\R#8rL&gfqZUJ290O.e5V*r$>o?S'5Z#A.od,uR-7.@0KF"!-8:4=]M+IK81)GM87X$^*Bl0i#L:(/'Pn_SU/nWHu0DpTSuZ5J\/90qXDaNg]@mH'aSY%=iXpkr\V3#IX/Q>4mF?c)0,nX/g_HgJWb$1gcT>oN,_I?]fhl9j&0G]!e3m7gB/9Un_$5!5?Fbjk1aDiN^V^ZE1Rr4=s]!hR4`([X?=0<I1*<oC2V<gh4QG-Z!U1Qdkco$S8m?+MT?2hJHJ3%U^A9^b=0_WOp0OCJp0:htjYWcJ%6>2a9Xren&1Y"Qi7&H#[t'rll*N_Y9Y(M;M1lMK2k$W&TTMe=R6j4JV,<EuE"XCTVNsU\=,-EZWFl'uFC3.Hbr(D!Ur-\Zli5b51?ne;h\$:+6;/m2-^3=Ti),BD;qEi[=.?IE/d4Z(`"fD,q$WI<!=F;9pZT)pmKO^>[,:4(kjNpam_7ggX6IXn)eeR/!(p1@B-';!WJB1&2VYa@&u~>endstream
endobj
22 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1770
>>
stream
Gb!SlD/\/u%0#[%_0m0c(@t[Q]$j<&%Wg(*9p_\oisZk<+HY\XX@/@28TqNXrU8e2c*Ao]C)Rf=*$i[t8;]q.Gt=?TL-INllRi/I-STpBJMNTt"6G3Rj:mV%]t\k]f5++?5]gF:L(;/M"g^5-2n]3V/SYqgR/t/?KUK[W`e\&le:^r@onslr$[kqeQGr@9W%dSG4t!e4)*k/rFA#`O#ntfh'"L3HKk:AE*%ff.KSCFFknd*!b%I1\L!-u!Mpn(4Ymc8*?l%/#_,4_DrNl75T>94N7OIOc%"5WVA*M9;\7Eg:dE,d\,[QYV)8)+_l%dYQ#3g2rgqr-kQ@3k7E'nHp5EuOO%Gj.^//a+,DKkI&G_#suB'9=d\+8#s4>d9iG\*6W'ms!BJc]?bIS:l=MBOV_:TGa]p#+eEL;?s-?s,&WPm<(nGR*j@7a#l`n"WZ69kCQf8[C)*W-i:k=?HCFSl$$)Tp_2QXN54a8c>>q;QU_-h'gY:lm`cr0t5afoZpG`_RO-=BFcum!<qL_`Xp,JX`RJI,8kT[TOG2*cLTanWX;3U921&.FQ]Zo(cupqPE7pa4'nf3O$__G3)MM'EZ`CN0.LL)X*n)r.EEWQ)nZ02Q>mPW#9E`OXL;pN?#Uem60mW)1Oij1>1A(?!p>Lr%CZOf8J#';Et.<fB9g,]J]`c-%8/kIa)NZ6_g(-J(!jlpm.<!0<&_/=DHsYZ6M2<G4Qd-S,`r,HS\]IdbLlH>BRq>E?/OPUmQ:?[m8Xn-FoD*4L\C2[UG(2Ra-@1u"YOQeg;^S0QE*UDReb=!4g+7oP!R?j`=hKeV;ktF`F5EA'in)r3E,0d_32%i-c=AN%Y@7r(q.g[A?[8,kW8\QL8GTA+II`?A/IW]`aPg+&AYD!R@s_[<286,.3Yem!N+/&s-R&N0+LcRNipY\`hUH!q=3"Sa4$CH1l[ZNiUAa1h@GLJO^o=i;^[^G%4gKs=r<gD5J-dbps5;tT6Knk)qQ<fr7>m:"Db(=b9WCq2$SZs[0j^t[4SPV,-a(Q.^QGf6nm)?!OEl;q^jMd.Y3L/Y;u;n[BUfL'/)DF!)pu5iLPXe(X,dqasRMiNYBb0r\KliS/3&u=&(NCL3O6G@"pi<*2aH'\4PUk(l_<^"/(PDi`KktC>^e6i&DRZS7F=e[)al>A?cUVXu<RimVcaIP,h1@RVC)#D8g]O^o[itlt]a*n%cMEa1ZP5j=P_HN;%C2:.8F?a>Y-=LnRk/N3_PhV^%L/mk,^4qDeCNd`jI;iqf\MB5j>f"/fZ7YL,YEm_gV5a_#.a"Bqi:$_YXEZN(ZHPWhD+nIF)n(l.hl@b^Q=eb68%/tBO+9qQ4`IW*!0kpu$J48F'k:L\P3Hdeu'L:OoA9t#h.%W.eQH<VS6D!<g.#I-]TXTgAbqX2E[NFlRDM^XN_p^D$kSQ$B(50>\["g6m)!REY8pT0<[f&l)ORJuk7E)R9S<c^(-ral-#3IItV!l.a4b;a0]e7HBA#&53#AWgTq>h^[t_bXX;;U-=JeC6+C=,S`h^_nVs24U^Y-cT6r2A8Q*^QgI>D)R\o22a.ck6kbbl@Y9+\+(dslP&`j7hO%<BG@/[,A*(%i&YZk7UAZRDR.WKSAn4j:/13BSN,Lh$F-,kh*+R(mqo];?NqOP9Y$>EQ8`fB=ifl$U&Hg08;4%ehQ[0ijPK9l>?V<?2Rd&oCBFgE3mB7A>k?`Kghs:uhHUA&!Ci]iF,2I+]Z>?jR)Zs#f_'SMN[45mEK,V)FtF6Oq\OM!$6K~>endstream
endobj
23 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1290
>>
stream
Gat=*D/\E'&H9tYR!u!Z3@0T-]jBGa=-]TB6H]u/+B9p872o@E$!q[Z6`uF>h`Jh9fKcHPD8BuMI:o.>2$Fq+])A6h!1+pD?;mL*7Pg^-E#A8@1MV;S&B>9.RfdY8i<omHn$jq,ON\X^Q$jP^7[X68E!c,@!K7WLH.7I7_<cT&"GOR&]=uU1A^hI2?D!EHfE*IDLuZ*2E5GiuA.lF:a,THgi>aEP5[5671t++0p9U+g,)VJE8rM/D2XuKo*10MA/i\_V@.eGfn%qd]=(\aoj!EKWM4,tn(c1;?]6hp`-8_]j_CoZ!QLQG&3^&,C,E1J$fZ2>E([ckQSh`QJ\<2)P/n1C+*QWN),rcW,T/!si8-NuRQTO+\LJZ,2<[CC&V4QTd*3Ma$R-P>#3+mot8A3+=H/@nijaEFKU9(_<=4kqY1AoANO+TjFiZs[9Sp_^pft^Kaa4lom[cU'D%RSBZcn-<PH-Pqq:cfoo^^?i:S>>WUP=3Ml%99]2aji/bPenrpOuS&;5F_=<5"MH;`[(#q"BAF]paO.OQL\4-9:H;8V^aD_nZ@]F[T/IP00Om>>#3QXo:NY?SW9iB)8,<`!#jH9/R/_5(j#EPjKf7fR`RC$:&krtXqQ6C87S]0).8`J'4hSLH:.P"5=YC"]?=OTl@*t:BOA3'Sbp#P]cYQ"RnC;BgV<cjoB1\]95OoFn?!o>^g*`'jmjf3j\m4<T+SB\30JbS59cL^\d2^Y%orI\YGqjoluhB"JSqP*cn\M^Y`[*d0(CEl,6@kiI/)rZ*N4[M!K=-Z##<)In3)Of+M:`u(%p1RhYn7>Nt&r/51mLQl^*YAm#pO(-V+&?c3[,\DV92uA_5"H9sc*ddb*aM>FR_MKQO3&RlaUNh]okUD$Jd:X+Mj?Z3Nq9"(]i#+sB/iMD"K'>i=aocD%N8!CK:>?`90&1p7dWHT*`H[c<GjXiVQaY+EV7D+QLLKn>"G*>+aJ/55Uh1fk403dcNL"eg[`S`)'<l(aAX5\XmB\rakr<#G`r.Ku'P]-CRh@&j3,n0IZ:"Qcjk,""_q%k*fuNuOoe%3@BW]Q(n75\P]Z9P(TW/FI8o.-ZN.fZ@,=Nm54n#qet_@P>N2"V\;,nSPs-=g.b@ipCXjY_K,^J]J3gnAaNAh04h!4rnZ(p_6K$9D'hJ>#OWV4t1n(Z\O[oY142JniY>5S,W\o:JsBm!b(Sk9T#0!'Hgn>Y%<bf1YP8h;R8`!+TQ#Qf,;ElTTqf\MMOY0Ludh@qH[VS0r)h?W]<7YIE1TVUAI8CiuaNjDOL~>endstream
endobj
24 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1652
>>
stream
GauHKD/\/e&H;*)EVZim#om-EW4)c_k-jNC/PX^6faHpc?tJ%mUDI!pP86mlqi5uhC^4YYbXP:iFSG:`4\,'06,PA#Ibb"^`<8Z6.8U543D`I19MXPkdehfE]&qW`#GN07D<aB&h-^_JGgQmRfVT-ePaPo=#%<g+!b90U/8@I%@=HQJ:(_DYL2A^d))Y*cNp">82%qCgM/F7jE5E%K.$$K^j+CqGi>`FL+GPUTWo=E7[c6WbZ_37X>--#tLi&TF"1*j09o^h,%*m`.IKFG^KhU95'_u^9`mS.i0P/I[n]B`L8\?=61O(3aU`Z]?)5d9bq#ln6%R*c8gb_(eV_S:Q_&F!3P/A]lER2V@$O-#(d!NuS`RH/fDK$V`AeRcs6WI+V.CDie6$FlCB3:*0^c<W56gJ1[SEEViOR"G@,:+qBKIs+A(Ufe"L\"WnUGrf6Y5MVDU5)WFh9%!]NB&Dh9$#pK:5_ae^#ljD<)\NM(jNkHMGs9SDCe4+04]GTj-RK8.><,9a&)j8T9Jq?Hk_DW,tZlF'3'aYaY2l`RB3,:O[D[SY%1u;]Tu+u';B?.A.qob)3FcZ!K#lQke_]f\uCIb"Q!tWb?GS%koe9FNgdK,IJ?i_!UsY---q__4E#3aMSXD]MukE#LCN;BFMGd*^r>d]*aq"62''&3=)m<D,U"qU+_SiF:9Mkq?_!_#]XkU8+28Y"*+*!#38GO&?c`$/h:^=sa+&6kg?VUHUMEXP7iO)](,?p-rcHN/?29=g\rOZ`-):MbFjrn)rG]Z=']):N,eB(CXiaGgKj\U:$[7HV%),"U!\C/eiNK)@".oP&,oeh1inW!K,BaH)J??hhPYR"QAh$u\oY'Q36F9W0+aGI:?.q@r;5$-2,ob!M%/5aZ*W)\(XdM]`eg.?e#\\kHA$X(UnEM#``&_2(]":AnB&OI:hAeTRD(gNip8i*^lU.Xq)>dqjd\TPC8Q$.uaWFiHH1-gl#g`K6B).;RMJ^+n_i98o1U<$h>\b/+oqP?$Cp.tk4q&oDFq1]l_mV$PQ89'?99^M1>+#&T//HXh)QG"8rl$=W0*Hdfh?%CK=,Al"]9Mgtr7rRM+0!unC%!Od!)er*mTohM"_&YDk2OBJ5_;4Efcola6Ds_A@(P66(<SkZ9lAKEr@@kql4IXf#;>)^pu.P\hKZMh></YNjkSe37J9o#^=$1sXl\8Ug'[O;qmLg,U>+'teO)/6Cl?p]f,.=WD`/IC2HU`<=:TQEAMFlN#'7(&a'b2>LWk$YF7Hfs1$Ent5]meqHHi[B1DBo4g)IUX`XC<tV0L'$A\tB+Mi[tJBoU:UhS)(CJ;7\P];+(RdKHd26o]k+PM/=(<c+bJQL6?d*K(fj;15D.JuTEJVhOW-StO@E5.)Xhm9Rga^P9cUbYGFBBl"NrG0le7fI[tc-A#BXOE^`:)h&W/UgaL.XoZAIQ5d3f$E!+WF$CN%%Kff-r^YpR6QE4,$(1ZV>g%(ZMS#)jI@)e9.@5b_:t`JriYlE2,04#DYf&$fLo2IUk>7BU.o6F]7B#6T<0A>7jKUPA_CN9[*jH2imF!?Mp)T-c+9&J9Qu8OaX_'eEr82jL[]@jfY45hK_\I"4idWp_ZZS/9_!LkoLM=YIqcR)_m+bmT=UXl9#JGTfSfm$0~>endstream
endobj
25 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1596
>>
stream
Gb!#ZD/\/e&H;*)E@A'1/K.fgW4)aGQG00>OEG9sp-[dlN(hu`-./RQ,YaF$^7ussZL#*S0OV4!1Eu9^GL&E7$4_N!q&<rHYD+_jTg0J(-U9]N0Kaus_qrudELeM"3"X^56f/%[\fQbhk\2\?jcDrb;<EKIH%Z?m%u_)b#\X3A_W4.H7(%L%G[\[4A^p=H[6>t#n+]/I9AIl%JJ71na@]G.*$:[^#j5kE!oc5M6*5SVFD,0ELgPpr]<m%!^`fE?;[t?(0)%A`AC1AGkN>cgYGSU]B1f#ia_2R<%#c#2i:us6\1!NWa>(>i2_nBk9]kIt%'O+7U1594,M`#Sp<R7Me:I?<*uB\^YO%j=Bp&kn>)#4MG+2$Nijg+S_5@=ML`'74-D/`%k5f\V3dDG*_)Waa_7`55<9;=QXfaI5dFbb1VPl#SGS"%S5FlRM;*#?phtpYldDI_<2^lk_YuX>."!?etp8&!A]W)'VLhGQ9PAHr"JaX.c.?&YF-C@8IJ;I;E*;h]cPH.!S>_jn-a?_!BNRS36jK+V2a?+GdMhT:]fdQ$nfi9KOjB\`3MJmbKP@Yf)"S;Z]m;US,o'90hjp3T>In%cCHfGSY7L.LO+bbqh2?R+P&sQ.qC?YC.aQ5"$\i=I6OekfCcaPIDC+N5nD2(`\)>+O,ah_/Uek.8ClJ&(/4=bcZ%&$C8.h]1Nbu&s8!iSOg3^bODN6&VU-M"-`ND<65^6FFkQ*6^de/p`FBk`kohl$P&Eh$ODT][d^/HZMfaSm4[Y'Yitpd++eer+`87*9A!j(s]cqj>63H/u=CS;hB`-.ij`@H_4sh<;;)(OSiEDJKW5!=8kr0L2LM[q"LQ&!2T;GXtnaM!('24;R^2L_'Ni$bpjgbI=U<@>e9J_$NJlo;i6rOoX<Aob@8#q*Z6gV6DRfKg&Df]`bI'7KRbXXjhCo),a?@Bp-e8fG4UMdfQ>h@4JJQ17:cEC/JlU7-A8>2_SUB1'=lD\uG]\6#e,B.O?$9fKd>![gAd[emQ;kAa=HtdfpLeqctU,E\3,b1QMURo61:F/`:q,+DfPaQUUIH7B5e&a0/5$?Q-2"Yc8>PbCP"^h&a;D,qD!#Ru&DEKiU.S(pb_\IP6hWo,[)_L?l@1KhK<=?=(U_K&o0i]b?J8Tj]8W>cn@sN@8C?9'A#-$8p[BD6&/F`.RuP`53.+K?!b0LVe?8MT$6>bG97A#^fJdl<"m*T3GD)bC);T>QY9Vr!U6UND^\7laqSg_m@rET-QH"Bh^aC:T)+4\41nAVUH5.F;NRke_j</T4YUb7MfZ$$Fu(P,ha*$r^T(,9GT^'jtsP\*A?sBQ&l?S`jMnR#ZmD__UqLkC4T(:ZRnPY"J!?I>c,Rt\$C\>'(<&O26N1Eqkbh*I#7OEEf'sf7]sl-0F^d:6"oH,J9`-t7TMCtJ'Bf0`pRIXcKJT3@1C\iMJ;c<82Gn49%=p6&Y(:3d/8i$:mjZ::\b.g;YLD>\$"+#bkn>o;`Rl*J/*NWRrj,;dg^nYQ]Rsi&9=&M75`75MDIZg'A1t1UA_@r%5RoMM"qfr'fmCl`F=q_p]_S-,c8*;P1J#Z,5#,RLYcB@Is00~>endstream
endobj
26 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1174
>>
stream
Gb!;bgN)%,&:N/3C`YX#1GqSicH`rK1pI^<PfBtnoV(OP9L0:3?;pp3e+*4j])X:;,3as<kt@k88-"#1EmCgU$5U@Tq2R7]TB@oATKm@]YCO4&L%u/&kG(73`3H&`Ee-3A+8QJ/d.-JD"gK-1#S(Q:Chik*738]9cNi2OILsj+"GbON&W(7M@!Q0oj41#u+78SNM1!JO8fcoE?3i0g4W8$m$Lcuk$A#]>HAI)r(2cs.YEKH=c4TU4P]<&@eHH]pI@n)YLW"1\(JQZPr;,CD-+kbZ>fN8-8E#aF4PhJgfQI7u/l,hGR7P;`n:oil[+JtQ=!o]:KDE]NInYj3^=Vm>itA9omo[;gVaXqf]jg:QBAg6=I7/7J9RYn\T'JX,#ptVt`L/'Fd_L&/k[&&q!\4?([>AbZhPjg]S6<ktSfu<IbA&u1m_[sLW$?_7-2=JO),jZ3'bbD:1/fPSEZ\O:VmL.[5P0'FdgNY5JQg"@@4(#4Eer0IaW']+et5NsD%!&q&RrSEiie=J4MaW()2s'6VTJ4)Q<SOU,bK6"m(qoa\gS:0%5R*ReMLq5adT3)aG2K/$:?]_9H`b6a1iPQ-"!o4<NmtE=F5['Jbl'rHneco^glCE+>.]6i-1ct,lJc0=6KGJ%le@a/LKNJihR+<1+=:PYr&D[H>s?I/_Di#f*417mLN_VQ:a>obd`m>KL*>UmZ.[AaI?_2J(bgrA\C&UUo76RgFK-=m$[5T8&KLWZu$??2`P(l2cL`1&BEj=GmoT;rrK:1YiGjIqYXZH3J"LY%n$NXA1P/RHrEVmaU25,/ga2T]RO0"GXu"JOK:.&*H@XAdBBR18)Q]J\r3hD#F=_E+KSN]+tNGaMoGfl_tCI-VWs[6Fn2^L1slQ64"S`\Oh,gaNh1crp>9gDI_F_1(V&L*ic&74eXYfAM^h8_TS@6M-M`uEj*lN2oeYQekOUJ//Q&"n_#7'>XlbLW9=[?/VgZu3'DuP\>[)W7f3Sio8"`*(?2O>'^;n"#G_TtAk&P,B%8SVch#g%coZu\U`I8C9U?S?sn!>W9.RcO+fRG[.s0U*9W.FIZBX"DtIRB]BULTeWR2.hu3&@Z]%$'GaDO9M5k84'ONJQu^$_M8sfB]mjI$Akh*d"^dUQ/ZXE+=p0p47@jD7'dV-3K8lRQ$3)#%CI:"T~>endstream
endobj
27 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1300
>>
stream
Gb!;bgN)%,&:N/3m!,D8SJa`o#i7=V>.7'AGML]IQ1dX"O9e^*^l(e2ZH(FDn+%Z+2nJNPB*s\'!SC\J4aT^O",_T0q4&f45>>P`JH=db=TB+'^uQ-b:I_f<@ai,j!f66R^2!i@D2/>tMJ/6KZd/]i)0`n'*5XkZ"jVtjH-Cn-_;a"$"J*:t*T-$>F6:!KPJ85k93krL-FWC<+:*0n:g:=+!Z0>k+p:@@J2e6%=RG!sp1qkQEBD7ObI[%&8po6%!k;$Bi<hD5i8iAUIpTq2/5kSWR:R;NQpT&a#,[o;E.25dQXsD?'uE%TVf\4P.Q++X\Uhl'SbNJM#hRadJ#Q%J'L'Yr/?LI?j'KhU:*k-(JNb<j4]8aVlJX[l3EB_,^_OQ!mD#mCqC:5WZC7kf.57s93glSpWT#PZ&a0YN6/H'en.s/G71,lR7b%W8:LA$++2C@$^cStLCp9nP$(`lq`e3*XPD4$=&:tQjER1XdXWhElor7r3Fe;SWg%Dati7Bo9G?(S1<[?+$<NfpV7jqhYH]=E%k$?\oh%;#<Pqbn$L,rEM1d,!jJpRK9_Y=W'>*e7tRAdHe,YkJ<<R(uK;HRUT%l*WX>'$K='jIic\>`(60-7]GQpk%Ta9Tn^7rNU1pMQ/gf#gTO=BUPSCFF6a=4W#c6Z2_s(I9'g[6uiJA5sPJd(2`FV$s\qV5(`ig'dY!EIZ(hE>Wh:f'o0t2TB$5WNg''%M&TVd24d0#'<)[G!*e+FW@5bEqfZqcf]@;D*Z6#O^D+7%'SXb,"3MB\G5q4bjgi<KV*1fBIjX?.?qq_geY016.f6V(?7O'%mnDLcog1GH2FNU0kBNk2+qD"p:/%"N)oB\)=,KB!Bu`k4gstRHYKtp+n#bRD(Pr)*7@8sVWCKc=IMX-aGR;K<F\010\ujle(OZbRf-8OM$i9XTFs?JnEP$N`4QsH&-`0TBjM[5__j>+&%UsAKt=DG64M$Pi(iQ0SNSmn6hCJHlt<D"KSIqh2*HZ"[nnR'i56"5A.^7XRTS%fi@s#/AC,AH4n&3[AOHH)nRi,rAOT_9<LTmub,2Oq!@6WCBl]1_=Q1!qY`(MD[JI/MRA@pPGX*,+6"R\s1H?eq6H&nhD#TUM%'24sn_:J#A*i:J[/O)0XZ]u?U8uT.J#T4#i\XE+eDOdJn1@t\>YEfVI96(lrniY?GB%##YquFMb6WU<=+-Et4S9Tb;T!Wu6oPY?ei)><gb:`"kjqWW`.R"D:65;/7^KJZcF"Zghp`+EK$SXeZc\Xd/`D%1q!4p02g'H%[l;+?kTB^!'?:~>endstream
endobj
28 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2056
>>
stream
Gau`T>>s99'RnB331H<fTeg[>=hZUUVql5pG1gb;B_R2s`E!rl?a@*KV+gpd*ncS6"<17]b_D%<FX2Cu4$#;+kkIThhd-`\l5V-h#S7@+1E]A$E.///T+CoABSPq93WmV\/]TV3Et"8D%'j9&i*qJO)C<l7dks!tRhei#=gh%@a99_Y%lCb%DsO:\:jc/M>4-]"dp,PTJ.P((*7Fqc;3SL^U0>l^TKAf$L-)o<R6&&)C4-QF;4(Y6WZgD,;JTq2RU]KR!Hg5O=U[`.(qotHb6bgS"-Is%1l^G"b_.pAE'^H402KS@o/t6nnDUdb&lH6!73_Kbr"@;IDs`V41hN.[qk&`cL^rluiof>YWV6;+K.u9BZo7c:lo%Bdbqr++J74lb+cN-q'`!F7(:.HH=d-n)WL:O=eYnLHa47]Z9eU]sZ\4.!Bk_)0e^6A8W7-4oOGR,/`E]/*+*bd1BPM#/V9(ZfeY].Q6;/bO/?1mZ_^]F5?+i4O&N$-7=QDIQ"?_#8(S_]S/HLAh5J.%Nid(Npa5Ub\`E,(F@jmrj>!Z\ilcN!PPR2hUl2'moFkZT-$#Y(EZ0Ys"qs*S"bVkE-aZVAm)&pJrI8GAr8;VMU2bPH&9]JqZ_%1TNNJ)e')l;=#PMgcup=;gej&ls_0T3kN\1DY<c>IC1@<jZ+Yl$Oo]aRT`bX]M70pW\Q&9rr1+\Ra37qQ3PC.`h3RAG`[a2/@FReH&m-j<:snMD_KijO'q4M;B\_+N/,onJ'N'H%>@c.LNm.)bFKZNMphn!*\nd55^DpT+H&o<U,A4ti3!-P<#hAce7R_l:>5,YE[h#MkUd:+Cl:pXjuMU=EWWC%>IBHAeQQ3I5ior^)\>:;^ViBA!7["p>ga4,[_G)=s2a-sNEObH(-:q9()HO'2KV(.AERUS'$kc#.Bjm<8*=M2H!&L@1!Y("]!9=-oYl"rF%mI5j9B>f`-*2I;>k=^B6PI+cl@0>9U-?PU7i8Q5(fo6,h\B.%egG@CoG!dFi7,euPRDhrcANSjB07+ZaW"qYT%C-,dh`r/s(ZrtGm40L:1RmD+)P>D4oT?DdT/c9"ngj4Eq42B'^h9)>Z3e(0`+uh*Np%FWanQOf]D$b?&p9FPLaRrP5@^(!XmhW_8@U0CYk$40i8QkXYhU&iQl`\iHF=-eroC>1=R"cmn1Wc(,9@[X>+Iih@Id458AR0Q3>`]EC]9-Spcn8g-eUkhY4ms't<>!Um.qKGVqN=;Kpu7cn*-G@-P#V5cIOgon%tgRYI6Z'-0tMYM\Vb(O&7$LG<sV8`.hSo6(h%[LR8b6jM^o2PR;ul;V,gf\P%>&)OXQV<<3ggf`a]S/]85?b83"q'0'2Y315Sni8+SR(#FJ?[l=utQf9g8_-&<aIi*pND<@ITccsWWqrCIHW],LSbKaUG<0YB>T%<hfpaO:0$GCb2lW\>u5*o^N5>]]7$Y#FBsOO8t`*%#+<0j%Y)jVK,_fCA;NeC8q.e7K6)_`!_'Xn\1tO;*L6_!WZ@+\m`K-f;ea*<HHl:[!\e?/33>KssmkSeXm^jgfon4J,DJNbffTb<jLZ!XLqA6VR0nn/8nsLNKEc.e%@Af>Y01<KTB,U-B4HM=%[FA:LN5'd\tBUPt@Z)(!V6benHOa-KaMp%P/\3_bC0ZZ1,53"kC8bWo!n]@!:`[+/RDi!6ke#Aj*D8\eI$OqaC3ZeX+[2&r25=$-h<W'ZK!c(;3UO7I`Q-4Y4_"FJ]iUEEbhr`ORqk+G/#J\?0Q?+eVebdgM;L:WdT_.A5q2eWoeLZjKl%TGP/__r6J`AB)!%$\Rc;6<>+_ml=qr#Q?Ho0aRG_F>gbT#;#!/g&[AdH>E5?,[@^5g6&`8%$#eR>$3L.WOZ^CNthe[jLS(^jI=5(rcqWE`Mhh_=UOA^ai+MBQ7%6EN&p\)&O5-6=B*cb=F0FYgerKC[&:&rZ>fPPIXeI<i%0Ek+jWR1!6j1BcQM>OuIF;olrX%3>c684P$Y7*EbnEG%6'?ej:@Y%V"!YKl8g^e7_Y9W1"h=WH_K8RR)q/[k4i;3\Z%'^u.E_9KEg~>endstream
endobj
29 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1546
>>
stream
GasaoD,]1K&H88.Z.#*kTn?q"Ol%!`9!@@1RpJ_q]e<)E.#sH-r0"Bs#fH2iDe2"jPLshdL_=Frfk6p_aeE2%+"]^p"Q8)nQkpI8%G*D/N%hd@$m2VWrsZui$@Ia4)*+kgNe$mL`srsIo0J8Z4q3<BD&8_X+h$RD@,&Wm4R,3b@.n1tK%f+g*8e5F[&N'i)h1<Yf5cGj&K1D)%uf-N%CARccgZ_O"(;TM![*MW'3+k\Uj^KJ+DsmkB5*p-B+a$D.0J<P,N^a<8RV>Tlee>m@l>,Y>\$tG5?'8PKn?RHHZ8u+30uC`8ke3W\.`kj9LPljiVEb]hsB8G28WU2#QM,l5V;cPe#>10[)0N;o-i]3[",la\d_TIB'LNRN]'oAQWp^G(g.d60(UnQC_U&#:(WsV'Lrr]%u@8tf(FT&6fD=@h88@mXp!l6i&/0rabr9LMD_*dpT.1XDXm%$BJg41%Ho-m(TNOF=<l#\4g=6upHZG(e+Hk9CeUm!)qCr(n*b!.?7EV,G!%CRGYVT?_XAg6LG2Ae=c-JdS>Q\.($Wmk,1uL?=[e_C<mlZ#k;&+dNLImpSDQXNZ:qL0+3H]&)e.6sW"LCX[G`$KGl3'4g3rNR,DV7$YR%'6pO&A<Ib3XgGH?_jGW'Pl0q6f2c5P7%WqobQ]\2$S7pWIt3*M*W"^adsm4oKa/5Ndm*IGnL5/:(EO]RijCTKc[1-<_#YUHo)_5]9oS'992L'NDH&B5;3GHb,Gg`mErR4EN80GduNhb+W-Jm"ZkE:DG;UPUFX-(f-*bT24n1SU5*/T3aMYu52Vn"MgD;3lD&I$i/HW/gLOCf)JsDr_Q!a&*@?JW;s*/'cn(h"lqK,I^ScX3u>EB"Wp7b_e7,Pj2Qs&''IpfRs=mrDY9AM4F,]O@&2N^YlIBGuDZ^(XaLfcc/=8N">[\o1G%lNAN]CT%TPh)R^%#[]Sp9\St8A5!@Y0]`t!.KFs9gLGX[%gU6]!9Y'0'<Ah.^:YP?17iQ&n(MZ6NfUX#S,M+Fa@;#7IlW6$bdh2NU[?k`!Dh4g7/?Y^mqR'-QUt!@e<h=Z>X5]4P+W'1tJJi+q-9LG"_7c3DD73/bLMe_DOlLe.\-6l(rK!G.9DO8hiq1c3DVQlhCid/Fe*PqQ#u%XP.WT%il>/uAPA.DcS+)\_Dg8<"P*LU?A[#DW$tOC;UV#Pk54Ml2q0U3[fX"\]i22ScRQVK$U$dV*@:@MX=9-PfO[b.D.e4)ADL=f(ngM1/XA0;u=jXU8_W/PLA7o&FN(Fd\];a^e>0_3g?j%6s?Y49dkKDtD\Y,MK9I/5tn6#+/f<9CVpoJ.G.:CGf#4"hkrT03?HRWD3C_C]h5'7cq6mOmPTDE#a3_1oV8YHiiHWc5]9R(p\\@'$H0VOhS/uG(XY91P(]+b![A*dE#<R=--UEXt1f,p-l9f_*948';hEp;hb^)E%CpTs3Cm[-,aDmT.:lTf,[Rlg,3pjY)5Y#mdGpHJlW?G:@6*Kn\7TpgerWkM9;QE73&CWj(re-YiNmjdD-DE?YZ0_c.j-Y%u~>endstream
endobj
30 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2265
>>
stream
Gb!#\D/\/e&H88.E@W`e/J)'\W4/iVQ=b%#c#?S8m4bX=5hh7"7M]9d:6lCemlOFQU;W4iAneLaNPbFFG7PePOarGkM"s2<!PFpfpD!]q@<)j2=UZVZkY2ON*E\=B"uZS,EP9//^^;'JL()ML6%X^k&mCMr&)>O>W:,$tWTEq>nKAWdrp7E-Mt+OK"p)[r-*A'@N+Z2TfcC^a=AIcY^b"c6;"r&O1G%/Z=H)2I+]tn,'h"*95R/3KBR'blX<kjRI+nujO"d5XjY2a(QPFUsVsjNP7P7(e>=odN4-b]V;S`T1I5pX:*bSW?.5?UM`MJCPH6j3s'IFo1o'F["N4>0Jr&aK\6jCSa2a!L@LGI!74l_GKiE0HTkq/@5K^':KI?.P+V<A\2Xt4/ee'eu:cgE;e331^scl"@J`bn:Y9abA`Qf-K5+!3%0q]kP86[h&W.4?VtV-&NV3):[Zf5dX(!Nq4%]`!pp%[h":BZL<8l'%[A7WQ)[`QaQXMl(tO94qPE??^HUQHK1VH>I6\!05LKoa[#9+JpIE3uqSHAIeLRZUhVQr)4hn]AJ4X'Lr2A.B/;lLSgH&f/E6W:c1bD*ESc6mD@KekdA,h9?"G8='QmLcZmSCd%A8HNF-UPo1<jO9lX%;FnZWo%g9.[`;hsHC+WAlp$d5V=7F+'h3l4H"IYg'o9LJAM"qGXs*.Agjj&)Bq>_>A\hV"c`WW.Y_q6g"eJA$_[9`0&ku0OkgI>N_>.U`BK,4a$I+^p%)Wk(JAiST1,nM@V(GM-GlP;n[6Il8l-^s4G!R\88Q8HLr2^b$2l8eQCS)_K=*$'Rm"l6c!.T\`)?Mlrj7e&SUaZn+`VP<GI]R+F_#7qJa;W/+O>*6&U=&6Z,\WME6A(UQ:n?'K=2?hDR<?I!VrW+N[+Z>K]77+X_6Hc4>LDgdhe@Bc+fZ@]U387X^e.qj<\=];7UJbNY!?Jhi1>m.'KK0$dXC,Hc8p)R_7I./]"3qX/`5<cSKbk)Vb1(PR,muh'MU.MeF+=U12r&03CpFeH:ciB,0eD/OosT<>E45]p4a*`;oX,X$rF4f5DT14gEIBo#Y3uZ8==!XaOj!YmPJS!$W)Or];GDp>).V<LJ#kR86>7U&W.+K.Op:TVe8<3kDJi)OiI-si"9.'^)+NUJ("lK[?g#h)M:@WjT-Ich.o;kt6LYZ+n.sb&c<!I5CE-W1>f2bLOc&6%NW,`l^!PpoiECH1.;D-S(4KO.T;?S.).Gi_Q!,8P&_`2a9:;b(a0oh]#'Ws_i_$(h"UgHMH%^bEQYn5H]&k*U"^4-I`9'Z*_gp=4R),%Y0,4C$/P*a+G<bg>$`aN?na+jK</N]'7SA`lFNR#4ALoKb*Pk9Q_*I0A0G^uh)QE$<LtOr.a.+*epZ-]]%Pooq%ktXHY.999mp"7iCp@P'`-*sSU['X[j;0"XUUj4Ymt^]Bq9`uLT82rKc)3Z;n2&CV;p!KK]\(>q`c!S&Qq'cG4$7rm6ZE:%2BluO`]?D\<p*nmj1(?gn=D<L0;3-pA;]8.?ZMSJVSg<`0%P>1'bT:(MGHZGEI-em0^4R)Er9t)K=-Zu%!k9>(nLX1KAQL^!62^9GGG/upE+/UagI":dUq,6iaH?N8gnJtX^^9^chaTMm*HS"3Adg3ZHKbFia3GKKV=0iY`4R!c^$>n&f`_(8AR%N*Y9>&0K,$YReV-K9dmZ2e>:+<.tL?r,DXSHoJughI8&RD?p$&>Xs1M6(1N/aI">A=r&a[B!+2qg1QMRE3<?d&b.!^t^0Im;8J@F5dA!&#TQmZn(J'<FF]kZ8ch'4G^Qh&&buomRZ.(7b0)O0(dRA4%3N2C*]tb=&>k5u)?u??h5MKB8;G%VSk%EBfqtjrf@S"-*=c#u/?7#t)'p[:FD_@3Hh^FV80h7BO-Wb[m==H_B@n>+3(hRIT*b(uo0Q*A0GZkaUACN]4o\f(Xcp.=HSt)4"*&i$YM(:cL0j20?r(jLNO*jh83uo)P]K.(,1(JUXPHsT3\3GA#bGoY/5!1FYd^11Ej#go/@M,id7%1qal=\Ci;@GckW:WXpb2\Ib@T"/i\:,4=a3X6ocVf<Oq'6DOqnmDlFG"^V$G8E&g$i3qnchkGoM0kkh8obP?aHRQf"0L+p2<"CX8]Q@nQZaem2(3.4Dtm_s's.M8FIL(6crMH>>skA>=58S$"TGbg-2:)rhl7L_U&m5Nk?j57gf?caKe?=0W^ij;:;9rE[dm7r(1K*&l3&D$NlUds7GgOp$W8Jp_T(X3<K~>endstream
endobj
31 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1602
>>
stream
Gau0CD/\Dn&H9tYQsJr%\e8oI3,^t9LE9)mG.WG[oM2=MI5&Udcm34e:t5L@)^cfACd[He"VitV4aH1XRE#sJ#(C:c4,s=?*5_4`"j144!Qk_(i?`T#N?8U=)P1_`+Jr_^[L'l0/`q%DVMuEO]@8'a1)hdj,0[<.@#W`u6QJ]C9Kk=i=718@bB4\_N*<[!hTq$k)`CN-'%=6ni.P7_djp=S*%q^:#j5m;"(E--61t3i[&Yp.`%E4n/1nPV%-#u!jhP,1Egu*P#b"i.^UeBXVD91L.2B]oQH8T%#.KOOE8#0"VJ2-(dYH0>6&'+qaZ)A6i=(I5G3j9b&VE,+p+Ktae:7o=qe8^BL#'J1#-gEH2_9AIH7Pq;$.V>g3&1n8blZ1k"[=om(r5h9BhlV:)(VIb+$aKL1,6fY-TNT,34VIt[.3/VZ$!j>L!Wn00FlI9#Gi(&-)c))W&TK)N+BH[eFTV5]?W"O[($F.`AZKqPWC]m$p.se2:Ua'3?ub`\X'rZP/YMEY#>G?T_"ROft;V^hJi.OId8A%U68&X)">716j)\IVN]K92&8[5>Z9D(C`f;>+p"Z//H(rJWs)enb='Ji+u-3U$K[J1=%"q#f:CB!#Pu-WDYkONfIIaEo]%*V9/-c"N#i!U0R6X&r)dh&>u_ZdHIjk7>^"i=lL)oiHZ]h-bq*#=gS<Y-oD(NY/=p<?:GI6T<$j%^=9W\^%jNSm*/XQ=N2MU#%SIr^$XFa+J[(#>S4K/QTrLQ8]c)!qf1:Z[&=Wm))h3'e(XTn[[(j?+%kQE?M\W]Qk!%M34aO4\%k=WXqPO91D7o4#9an%Rs+5a,7TF"]j7R["'5:UGH*g=gI2TmE^L_6<0Xdj<NJ/<ESh]lNY$*F&p5>#$m5Ge(k5Z)48do\gW$4nYfLgd_7>Q<YQH!T0_+3mO]9U["3j7$Y59$)/'k`@1V9IKZ6%t\Wps4=",K,d5YjhT*F2rX!@SM?tYuPbe_94:1FU+B8_LFS?[22QIQBO_6G;,4'k4=2S\I+I"e/URhK3=.<0BGL<g,3Nk)e&[l`'%d"N<?^narI>1Wrhrl-MQ2K"&SR_ATWJ!K8Pcnbr,0Zn4`;)N5-4nD2Z\fA^NXibjbh?k(<A>LJ2LjpYt9<hA(\?q!QB=K-n$;SZQ!)ij"rl6)H>Q@mld`'GfI\'bCb8PdsO!JPPs[_K9Mqn;VJQMhIp!r!]IT8b`=0W*/)rEDA\=02^[)+a+4F0oU3)/!DC1;O"+K-I_Y@\&V(0^8hdBW$TME@bSVd"Z'M?_<`3Y61uS1P>ZLo:iGh.)tB&6o<qeD2XgrDl3Ma_K,in>)jG7Zfh-V^?3qrFK_XiZ/@lcg]@@RFMSmJeOIP\XMF#o6'l]GL8'"+`oBVLko-NBW`-&T+J9b?>]uP7+&&e)/"V<Q2.n$B'ka@4sjq3O1Or!Y<[@c?=)3YcqR4D_<oYc4TcK.IZGF].<56"!hA@XM"bW@i-E\YF@5K)iWjr0<Ds!F"^Ch`.M)3k?(^.obITC@Z(b)ojYrTB2oZ8\SVrntDo_^pi:]I$Oqo%oIoXW^RVXVo$WXi><;^Y9T+lS_fACo4WmAF='U!fd3\#rVDo~>endstream
endobj
32 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1671
>>
stream
Gau0D>?BiC&:Vs/R&;!K]-rgng%$Ash5,n4]+Fg:qOfel0l_$]G(B;<GN:hB2teM9^t*Apc)8tQZPZO:A``r"!H:)OiF`@R_rq,g+9G#6E%r:/4Wk7-'brtRkpk9cU)_:'!SMQ+j']iR_ARP`qN>en]"g=G4calM)0kp9+FZK1UJ`P$:X5d%GN/ks?0VK$%WR_4+:+=X[lpb]!Xhs.&HXQZ5U=;UB#iMrQ,W)'[t]jLXS0r77(Fo`^_LjB/$R1uNip.qE=$!9WQBcqP!j7jA1!ZYE6l'"-^Vk$Gol+%RD?@Y1/X2e9O)sqd3FT6^9K>Y,a<RmlsH/#(ko.ST&dp`>hT(YVdZZhi1?be88emdXeC&=&:AM'(2WD57R:/J]_$:?R3U,1EIubqAGC9:`rk=)RdKsedAb4qM^!F%ftX6RnJ=0SR:%)0K<Kg,L*GCgb*ie\eh-3Hj)?lSV``o1b-!YeLb3[GYK+tDkkmYfQ8I`g&aid7O%sdZ2%-PLKn46_Q&3!AiqiXhN(pfRL\3C)?(mE!k$lP-LIgA`E,=i5G&T5=C\nCblXNRl410g!D]-CUrL+qf`LZ(uUH%'j^$krR@?5?7.opu1`@bN^AS\bK$68taR<b:ARPe!Y,d#Xo5GX2OVhpY0Kk;R3%1UO3K_e%7Pk"@`6uOX*E^Z8R0V,:f#EqdqB$<W6OL@*o[hq)e'aaua^7nn6ilJH6(kq!Y^.e3%k@PQ!+f7G$j?*-rC$AnOC*qSKR^;'82]5R._u7tcol??LdNliAr;OT;/4]qe%RgPq_Ap-+'pS0<MVE0gNet?[,86Z`7j8`-A.k;CSXH&HpXEO)a$\M;hL<O>5(d2c99rS@%V@%lK^j/:pJUG,H_%$$]e!d55Y'4(#P2@1ALAt'fE2l'UN-V_$KF,TiS+Z*JHj7$%NMoi%\a(0bV7RGlh\eJh]99p_3>F1I^O'r7u1'c:5Ybl1K.7(R4^0?dS`YR$N<27*jkf]GcdUX3nqpTI3_1M0:\=L02)C>Rhs!;+i1jB97\7r!l]*QpGa9&-'<gPfrp[.?R`7L0*Ck8\J6-CmMrXR#]=FSen^q^WbJYHYKIhO<fcmBYh1l(f;!RL%r.)1$^R4ce.]M"/2[mrPq/R2^gG@4S*;pJeLF]1D4s8pA"DnK./#SL;k_^tPj(UR:P.Df]("2bCp(,@X26nuDG"&K9!NeCrX"(>LcSsb"=I&W0^;jS%D%hU4.mDTT\tW_T1G2Seh";YD1/A#h9?[:W%iasc-8I7!-Jdpi_>^#9STL;9st^Zm',8N`gCV?n%_:$9@7$I]FU+!%SP/_/P.:ddO9AI%.W-qAS)Qe-7C"f3eQ]#h&tH5aPMKcm-5@IP4JT>cV66I,_\(3U>50k,V?kY?8$1WPk)&s8rG,,6=dGr-HIZdJ_Q*`MmLeY^t6cqgP["uAM8#srVU2JYnOt5^tCD9X7-7OUfsd<m3eN6*$t3e0j.KuLR=$h`Z7<cB60*r^?hIV)t2%_o7s;7I+07+jjftGMRtM+=0.nL-Ycc!,RKe1.L_O=PI;N?`lDnfVAM-c3X4@>Zf]C\8LKq7pJ&)i\dp%T`Jh-73/<p$r3m)o'@Ws`7MT?:el*@C,G$-j2&hr=1/#o7*pKXE$01N[1c8Kl\ZI!6SR[C0ba3R;QBl8T@IP@$&_`E~>endstream
endobj
xref
0 33
0000000000 65535 f
0000000061 00000 n
0000000122 00000 n
0000000229 00000 n
0000000341 00000 n
0000000424 00000 n
0000000629 00000 n
0000000734 00000 n
0000000939 00000 n
0000001144 00000 n
0000001349 00000 n
0000001555 00000 n
0000001761 00000 n
0000001967 00000 n
0000002173 00000 n
0000002379 00000 n
0000002585 00000 n
0000002791 00000 n
0000002997 00000 n
0000003067 00000 n
0000003348 00000 n
0000003486 00000 n
0000004518 00000 n
0000006380 00000 n
0000007762 00000 n
0000009506 00000 n
0000011194 00000 n
0000012460 00000 n
0000013852 00000 n
0000016000 00000 n
0000017638 00000 n
0000019995 00000 n
0000021689 00000 n
trailer
<<
/ID
[<dbf6b6212623f71a2823abf47256514b><dbf6b6212623f71a2823abf47256514b>]
% ReportLab generated PDF document -- digest (opensource)
/Info 19 0 R
/Root 18 0 R
/Size 33
>>
startxref
23452
%%EOF

View File

@@ -0,0 +1,475 @@
# Les 10 Huiswerk: Supabase Auth Uitbreiden & Eindopdracht Brainstorm
**Vak:** AI-Assisted Development
**Opleiding:** NOVI Hogeschool Utrecht
**Deadline:** Voor de volgende les
---
## Overzicht
In les 10 hebben we Supabase Auth toegevoegd aan onze Poll App: email/password login, magic links en basis Row Level Security (RLS). In dit huiswerk ga je de authenticatie uitbreiden met Google OAuth, polls koppelen aan gebruikers, en nadenken over je eindexamenopdracht.
**Wat je al hebt na de les:**
- Supabase project met Auth ingeschakeld
- Email/password registratie en login
- Magic link login
- Basis RLS policies op de `polls` tabel
- Login- en registratiepagina in je app
---
## Opdrachten
### Opdracht 1: Google OAuth toevoegen
Voeg Google OAuth toe als derde inlogmethode naast email/password en magic link.
**Stappen:**
1. Maak een Google Cloud project aan (zie Appendix A)
2. Configureer OAuth credentials in Google Cloud Console
3. Voeg de credentials toe in je Supabase dashboard
4. Bouw een "Inloggen met Google" knop in je app
**Checklist:**
- [ ] Google Cloud project aangemaakt
- [ ] OAuth 2.0 Client ID en Client Secret gegenereerd
- [ ] Redirect URL correct ingesteld in Google Cloud Console
- [ ] Google provider ingeschakeld in Supabase Auth settings
- [ ] Google login knop toegevoegd aan je login pagina
- [ ] Google OAuth werkend in je app (je kunt inloggen met je Google account)
**Code voorbeeld - Google login knop:**
```javascript
async function signInWithGoogle() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: window.location.origin
}
})
if (error) {
console.error('Google login error:', error.message)
}
}
```
```html
<button onclick="signInWithGoogle()" class="google-login-btn">
Inloggen met Google
</button>
```
**Styling tip:** Gebruik de officiële Google kleuren en logo voor je knop. Google heeft richtlijnen voor hoe hun login knop eruit moet zien: wit of blauw met het Google "G" logo.
---
### Opdracht 2: User-gekoppelde polls
Koppel elke poll aan de gebruiker die hem heeft aangemaakt. Zo kun je laten zien wie een poll heeft gemaakt en ervoor zorgen dat alleen de eigenaar zijn eigen polls kan bewerken of verwijderen.
**Stappen:**
1. Voeg een `user_id` kolom toe aan de `polls` tabel
2. Werk de RLS policies bij zodat gebruikers alleen hun eigen polls kunnen bewerken/verwijderen
3. Update je app zodat bij het aanmaken van een poll automatisch de `user_id` wordt meegegeven
4. Toon in de app wie elke poll heeft aangemaakt
**Checklist:**
- [ ] `user_id` kolom toegevoegd aan `polls` tabel (uuid, references auth.users)
- [ ] Bestaande polls een `user_id` gegeven (mag je eigen user id zijn)
- [ ] RLS policy: iedereen kan polls lezen (SELECT)
- [ ] RLS policy: ingelogde gebruikers kunnen polls aanmaken (INSERT)
- [ ] RLS policy: alleen de eigenaar kan zijn poll bewerken (UPDATE)
- [ ] RLS policy: alleen de eigenaar kan zijn poll verwijderen (DELETE)
- [ ] App stuurt `user_id` mee bij het aanmaken van een poll
- [ ] App toont wie elke poll heeft aangemaakt
**SQL voor de kolom en policies:** zie Appendix B.
**Code voorbeeld - Poll aanmaken met user_id:**
```javascript
async function createPoll(question, options) {
const { data: { user } } = await supabase.auth.getUser()
const { data, error } = await supabase
.from('polls')
.insert({
question: question,
options: options,
user_id: user.id
})
.select()
if (error) {
console.error('Error creating poll:', error.message)
return null
}
return data
}
```
**Code voorbeeld - Polls ophalen met user info:**
```javascript
async function getPolls() {
const { data, error } = await supabase
.from('polls')
.select('*')
.order('created_at', { ascending: false })
if (error) {
console.error('Error fetching polls:', error.message)
return []
}
return data
}
```
**UI tip:** Toon de email van de maker onder elke poll. Je kunt `user_id` gebruiken om de gebruikersinfo op te halen, of je slaat de email direct op bij de poll.
---
### Opdracht 3: Eindexamenopdracht brainstorm
De eindexamenopdracht is een zelfgekozen app die je bouwt met Supabase en AI-assisted development. Begin nu met nadenken over wat je wilt bouwen.
**Schrijf het volgende op (geen code nodig):**
1. **App naam** - Hoe heet je app?
2. **Beschrijving** - Wat doet je app? (2-3 zinnen)
3. **3 hoofdfuncties** - Wat zijn de drie belangrijkste features?
4. **Supabase features** - Welke Supabase onderdelen ga je gebruiken?
- Database (welke tabellen?)
- Auth (welke methoden?)
- Storage (voor wat?)
- RLS (welke regels?)
- Realtime (waarvoor?)
**Checklist:**
- [ ] App naam gekozen
- [ ] Beschrijving geschreven (2-3 zinnen)
- [ ] 3 hoofdfuncties beschreven
- [ ] Supabase features opgelijst
- [ ] Eindexamenopdracht idee uitgeschreven
**Voorbeeld format:**
```
App naam: StudyBuddy
Beschrijving: Een app waar studenten samen kunnen leren door
flashcards te maken en te delen. Gebruikers kunnen elkaars
kaarten beoordelen en favorieten opslaan.
Hoofdfuncties:
1. Flashcards aanmaken met vraag/antwoord
2. Kaarten delen met andere gebruikers
3. Quiz-modus om jezelf te testen
Supabase features:
- Database: tabellen voor users, flashcards, favorites, scores
- Auth: email/password + Google OAuth
- Storage: afbeeldingen bij flashcards
- RLS: eigen kaarten bewerken, gedeelde kaarten alleen lezen
- Realtime: live quiz-sessies met meerdere spelers
```
---
## Wat lever je in?
1. **GitHub repository link** (public, of nodig Tim uit als collaborator)
2. **Korte reflectie** (150 woorden): wat ging goed, wat was lastig, wat wil je bouwen voor de eindopdracht?
3. **Screenshots van:**
- Google login werkend in je app
- Polls met user info zichtbaar
- RLS test (bijv. probeer een poll van iemand anders te verwijderen)
4. **Eindexamenopdracht brainstorm** (mag in een apart bestand of in je README)
---
## Tips
- **Google OAuth testen:** Je kunt je eigen Gmail account gebruiken om te testen. Je hoeft geen "productie" goedkeuring van Google te hebben voor development.
- **RLS testen:** Open twee browsers (bijv. Chrome en Firefox) met verschillende accounts om te testen of je echt alleen je eigen polls kunt bewerken.
- **Supabase Dashboard:** Gebruik de SQL Editor in het Supabase dashboard om je policies te testen voordat je ze in je app gebruikt.
- **AI gebruiken:** Gebruik Claude of ChatGPT om je te helpen met SQL queries en RLS policies. Geef de AI je huidige tabelstructuur en vraag om hulp.
- **Eindopdracht:** Kies iets dat je zelf leuk vindt om te bouwen. Motivatie is de belangrijkste factor voor een goed eindproject.
- **Foutmeldingen:** Als je RLS errors krijgt zoals "new row violates row-level security policy", controleer dan of je policies correct zijn ingesteld (zie Appendix C).
---
## Appendix A: Google OAuth Setup stap-voor-stap
### Stap 1: Google Cloud Project aanmaken
1. Ga naar [Google Cloud Console](https://console.cloud.google.com/)
2. Klik op het project dropdown menu bovenaan
3. Klik op **"New Project"**
4. Geef je project een naam (bijv. "Poll App NOVI")
5. Klik op **"Create"**
### Stap 2: OAuth Consent Screen configureren
1. Ga naar **APIs & Services > OAuth consent screen**
2. Kies **"External"** als user type
3. Vul in:
- **App name:** Poll App
- **User support email:** jouw email
- **Developer contact:** jouw email
4. Klik op **"Save and Continue"**
5. Bij Scopes: klik op **"Save and Continue"** (standaard scopes zijn voldoende)
6. Bij Test users: voeg je eigen Gmail adres toe
7. Klik op **"Save and Continue"**
### Stap 3: OAuth Credentials aanmaken
1. Ga naar **APIs & Services > Credentials**
2. Klik op **"+ Create Credentials" > "OAuth client ID"**
3. Application type: **"Web application"**
4. Naam: "Poll App Supabase"
5. Bij **Authorized redirect URIs**, voeg toe:
```
https://<jouw-project-id>.supabase.co/auth/v1/callback
```
(Vervang `<jouw-project-id>` met je Supabase project ID)
6. Klik op **"Create"**
7. Kopieer de **Client ID** en **Client Secret**
### Stap 4: Supabase configureren
1. Ga naar je Supabase dashboard
2. Ga naar **Authentication > Providers**
3. Zoek **Google** in de lijst en klik erop
4. Zet de toggle op **Enabled**
5. Plak je **Client ID** en **Client Secret**
6. Klik op **"Save"**
### Stap 5: Code toevoegen
```javascript
// Google login functie
async function signInWithGoogle() {
const { data, error } = await supabase.auth.signInWithOAuth({
provider: 'google',
options: {
redirectTo: window.location.origin
}
})
if (error) {
console.error('Google login error:', error.message)
alert('Er ging iets mis met Google login. Probeer het opnieuw.')
}
}
```
```html
<!-- Voeg toe aan je login pagina -->
<div class="divider">of</div>
<button onclick="signInWithGoogle()" class="btn-google">
<img src="https://www.gstatic.com/firebasejs/ui/2.0.0/images/auth/google.svg"
alt="Google logo" width="20" height="20">
Inloggen met Google
</button>
```
```css
.btn-google {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 20px;
background: white;
border: 1px solid #dadce0;
border-radius: 4px;
font-size: 14px;
cursor: pointer;
width: 100%;
justify-content: center;
}
.btn-google:hover {
background: #f7f8f8;
}
.divider {
text-align: center;
margin: 20px 0;
color: #666;
}
```
---
## Appendix B: SQL voor user_id kolom en updated policies
### Stap 1: user_id kolom toevoegen
```sql
-- Voeg user_id kolom toe aan polls tabel
ALTER TABLE polls
ADD COLUMN user_id UUID REFERENCES auth.users(id);
-- Optioneel: geef bestaande polls jouw user_id
-- Vervang 'jouw-user-id-hier' met je echte user ID uit Supabase Auth
UPDATE polls
SET user_id = 'jouw-user-id-hier'
WHERE user_id IS NULL;
-- Maak user_id verplicht voor nieuwe polls
ALTER TABLE polls
ALTER COLUMN user_id SET NOT NULL;
```
**Je user ID vinden:** Ga naar Supabase Dashboard > Authentication > Users en kopieer je ID.
### Stap 2: Bestaande policies verwijderen
```sql
-- Verwijder oude policies (pas de namen aan naar jouw policy namen)
DROP POLICY IF EXISTS "Allow all select" ON polls;
DROP POLICY IF EXISTS "Allow all insert" ON polls;
DROP POLICY IF EXISTS "Allow all update" ON polls;
DROP POLICY IF EXISTS "Allow all delete" ON polls;
```
### Stap 3: Nieuwe RLS policies aanmaken
```sql
-- Iedereen (ook niet-ingelogd) kan polls lezen
CREATE POLICY "Polls zijn zichtbaar voor iedereen"
ON polls FOR SELECT
USING (true);
-- Alleen ingelogde gebruikers kunnen polls aanmaken
-- user_id moet overeenkomen met de ingelogde gebruiker
CREATE POLICY "Ingelogde gebruikers kunnen polls aanmaken"
ON polls FOR INSERT
WITH CHECK (auth.uid() = user_id);
-- Alleen de eigenaar kan zijn poll updaten
CREATE POLICY "Eigenaar kan eigen poll updaten"
ON polls FOR UPDATE
USING (auth.uid() = user_id)
WITH CHECK (auth.uid() = user_id);
-- Alleen de eigenaar kan zijn poll verwijderen
CREATE POLICY "Eigenaar kan eigen poll verwijderen"
ON polls FOR DELETE
USING (auth.uid() = user_id);
```
### Stap 4: Verifieer je policies
```sql
-- Bekijk alle policies op de polls tabel
SELECT policyname, cmd, qual, with_check
FROM pg_policies
WHERE tablename = 'polls';
```
---
## Appendix C: Troubleshooting
### Veelvoorkomende fouten en oplossingen
#### 1. "new row violates row-level security policy"
**Oorzaak:** De `user_id` die je meestuurt komt niet overeen met de ingelogde gebruiker, of je bent niet ingelogd.
**Oplossing:**
```javascript
// Controleer of de gebruiker is ingelogd
const { data: { user } } = await supabase.auth.getUser()
console.log('Ingelogde user:', user)
// Zorg dat user_id overeenkomt
const { data, error } = await supabase
.from('polls')
.insert({
question: 'Test vraag?',
user_id: user.id // Moet het ID van de ingelogde user zijn
})
if (error) console.error('Insert error:', error)
```
#### 2. "Invalid redirect URL" bij Google OAuth
**Oorzaak:** De redirect URL in Google Cloud Console komt niet overeen met die van Supabase.
**Oplossing:**
- De redirect URL moet exact zijn: `https://<project-id>.supabase.co/auth/v1/callback`
- Controleer op typefouten en extra spaties
- Wacht een paar minuten na het toevoegen (Google kan traag zijn)
#### 3. "Access blocked: This app's request is invalid" bij Google login
**Oorzaak:** OAuth consent screen is niet correct geconfigureerd.
**Oplossing:**
- Controleer of je je eigen email als test user hebt toegevoegd
- Controleer of de OAuth consent screen status "Testing" is
- Zorg dat de juiste scopes zijn ingesteld (email en profile)
#### 4. Polls worden niet zichtbaar na toevoegen van RLS
**Oorzaak:** RLS is ingeschakeld maar er is geen SELECT policy.
**Oplossing:**
```sql
-- Controleer of RLS is ingeschakeld
SELECT tablename, rowsecurity
FROM pg_tables
WHERE tablename = 'polls';
-- Controleer of er een SELECT policy is
SELECT * FROM pg_policies
WHERE tablename = 'polls' AND cmd = 'SELECT';
```
#### 5. Gebruiker kan andermans poll toch bewerken
**Oorzaak:** De UPDATE/DELETE policy is niet correct, of RLS staat niet aan.
**Oplossing:**
```sql
-- Zorg dat RLS is ingeschakeld
ALTER TABLE polls ENABLE ROW LEVEL SECURITY;
-- Test de policy met een specifieke user
-- In de SQL Editor kun je een andere user simuleren:
SET request.jwt.claims = '{"sub": "andere-user-id"}';
SELECT * FROM polls; -- zou alleen polls van die user moeten tonen voor UPDATE
```
#### 6. Google login knop doet niets
**Oorzaak:** JavaScript error of Supabase client niet correct geinitialiseerd.
**Oplossing:**
- Open de browser console (F12) en check op errors
- Controleer of `supabase` correct is geinitialiseerd
- Controleer of de functie correct is gekoppeld aan de knop
```javascript
// Debug: test of Supabase client werkt
console.log('Supabase client:', supabase)
console.log('Auth beschikbaar:', supabase.auth)
```
---
**Veel succes! Denk goed na over je eindexamenopdracht - het wordt het leukste deel van de cursus.**

View File

@@ -0,0 +1,200 @@
%PDF-1.4
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 5 0 R /F4 6 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/Contents 16 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
5 0 obj
<<
/BaseFont /Courier-Bold /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
6 0 obj
<<
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
>>
endobj
7 0 obj
<<
/Contents 17 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
8 0 obj
<<
/Contents 18 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
9 0 obj
<<
/Contents 19 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
10 0 obj
<<
/Contents 20 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
11 0 obj
<<
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
12 0 obj
<<
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 15 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
13 0 obj
<<
/PageMode /UseNone /Pages 15 0 R /Type /Catalog
>>
endobj
14 0 obj
<<
/Author (\(anonymous\)) /CreationDate (D:20260422141611+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260422141611+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
>>
endobj
15 0 obj
<<
/Count 7 /Kids [ 4 0 R 7 0 R 8 0 R 9 0 R 10 0 R 11 0 R 12 0 R ] /Type /Pages
>>
endobj
16 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1725
>>
stream
Gatm;?$"IS'Re<2\AJ_:Br=r_=gI/'[8<MiG7.+n07?]6OdJ+oZ(6X:YMUilEP@mm=TUr1`KKZ"pRHRU-oh!g<hJ=Ri3El++"0qir?"9biR#>jX+'55LU^)%*=g"&T(H81dM4=kO:OE%/s\=:N%to3+:.Rm#E08@pSe\6L*+GV'$Su)Nf]F_P>U9BbOqA.T&TjJ/od_L^^1Z2YVYS;&sp32i'-i1TO*-BYsSZ<E"h+Pddnjl6&EKaO21r%_]51SjgPA=SU$OL-5dA5Sg322cB1@O7uS9V3;<T`#]Tm9=/q,:H:/*uW'>k$5I^C=nAu)]&WVfAi*2W8E)a[V@m4.&T3`4#>a.:$p\I`7-Ca5+4G*Q.kTAR+/,OBW0l_\Qru55DFl:_*/nR-dfDC"o_`1X]=#To49JoAS3Dpt!Kp21RM_%!,m(6Vq[f_W%6)b'F`fc*'KLq\6gc/D,/mKU1lf'$i%Kp,X8\uA*^j1H8$6QM-S;[4iILi^C'a$GQpHAE0Bbi^PZ`o=Q^^.Xr6eZgddqB-:.mgTt(P#8#:ohX92QiIL"R]4jB8sP?KjcCK\f`s=2Ta#,/KJIG(pHUqDUfl!oW/X6bPlY`gb(g6?7EXjbJ,H8<W5F8SRnhmOu?fD@QEATkg&02X3^Tnq892kKJ+,_29,k(_E@bV"7^1P2ML=pL$/K6n?kr>XV[M^Jl?CH=6mD&:OLpq#XNbP':JqGE<X@5DJtuCJLWK]9Zn#qMp"Dhj%-*;(L4pnA?mUb[P]^Z'rOK7o#^3>/NQHoT=Bj%X`eG+poKmfR0_N29h!R20J%qV"d>Xoa*kPl[)q+(nTb;AY$J`6gVQg2-%OE(,ei"a_;`K!n2Z^p9X+anjrG/tH`a"f:A&ZNmu>F4ddUq5+f\j9U5Kcm*VZd\`5jrB8+mq@2+=.Q7q7;+R()bPm\Y36-LB@#F'fOrna-rDpGnB/H[K%gXqX(g4MgOjDGCL5QT!CK);e`QrrkK6hKWaG]W=$JgIIf!`N?Fh-!cA=PDf+4m[VO%6>C,Ef;Y$m27/Je%+&?nHCZK5N?7@Tr.mV;'MSA!iJU8?\B(ssck@-AB:16,RE6[E%/U"G,)oNV30`/sB@*4-3?J;0G[(6g_#SHUG@h%<[e6>l_eC0Ys2%,>`UIh7!22i$$)>IV@Ar+^[N\cY$[j3/<>fS>2VtqLldYHH\KS6e;&:oE=f)j#@'^a95sC:K3\O5ZW)V_6A,Ket&K=H>,kZ)0[^6SmBu(D<#572XTnmP`oNd^tMFoEg-";P=^X$+,EJ&\%:^Obanj%VQ.??#=5OH!r.pY^M*RqZr)XAY`!KQP!jk%=SXm7^^qaaTHPu*Rn8tIVrTe@H,g#%eggVR>r*$3+2h01e@gCA3?A+Q26.]VnH]IrHE"Z4Oi4L?&3Q;buU$>irEhZLMkg)e>@(>/-U`Y$&4PC_-CKKlp5`C5`WYITY#9l$3/"j]#E<q5Nl(gFtla1,>]cp%l53Cft,'Es:e4#/cdPq'pN)b17$G2:%*.*CKZ1>&nF?AVAA["ZCp0)(D(U(Sok:/tfN=G(l.h^)kQ2/[&fNJHp8)TmcQ(ra8Kio-g>;KmVV?UW$B]JJf5GW<r*SlR_t@BLi%2HmQLN=9cL@1qAt.V4Bhl4U$`M0`A0BOt=*G&sNKWYc2(b$1AX!Oj1WGqbJQ^nmIE.dGnrgEmfl7VM3%Dd\OUJ:4Li1(sA@c`II6rrKDpHjB~>endstream
endobj
17 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2332
>>
stream
Gb"/)lYkN;'*"Q<@^*YBDR!WgVl0UiU"?tAp580RPAYq=J:f%%[UND38ofO>UAt*#8NlE"Z'.(*"A$nj&h2-'2kqNr$5*92r\p;Kr::a8?;mL*NmE4_,2i5Zr9JUrO$1@T6q7:aQV&b<7!$H_!S(_a6t/k(_C/>*'1l:W'ei*V*7G`S"(s:\8CGr,OjoiYPu4NDJR4F+71(I)KPRPQ&12,N<Wm`.j?*J('BkWFs7+>TO`6.NieV9EVuTC\`4081#Kb>I-s;rgi+T=%;EH*:U08Lm5]Mnj+p@1eP%94Ze7j^A[.RBOKe&moe*)#dU]5`:r>iPY'2rOBCCBpe<$n(mE5G]c0Al03XR!N:bSYde(T+Ep\LF$2E-r/90:_5@rdn!(4MJ]4]r?QPn915OQ_p2T^;$P/]M*mY0_u5'eSD0g9k+bIFCgCCG(HHo&i#*@f6&ko&5M`2CY"'Q]4pnPC9gun[_R[;\4W<OoPdNU2&/**4,O]-C#mXVJdRWi*!CSt7:$&]_)>u#!l^4u#&T&@4Y7'D,&8;Onc]5'i0lZ&8[MlgiLg1N8L/TJ"pi@*:J%Xq*l\8eQ%pB&Yqjoc)/_?upG3]XlNbC`Y\6`Wfb6@f(N-6Y+"i\b.>''sIKAQeO/<n8fY&LI#?AC*rVeE[e#ajfJ@eKbD&dL@CdNi":e:jDe>3hA+lb;9BEs[u[J:jt^KgjMVhAgMo]j)3-g5#.n/?QVdOQV,I,A$f5u53EluEMmb+:\]VJ/%Fo/*!q)aM-;<tAu@"Zfqf-U9mk5dL[skRT>5bnM"O&CWYR<8cTY@*3A+A?s?70JO5>R`_"4Hj><t9bR*J'>bh=_YF:"pd[-c]c01aHk2XIr-aS?)uHUDN-DL,e6gn7[Y;6oc8d7O,Ys^'OlBV.&=g3X`hqf@+.F`F4I`4S(?J'07=(ER#(4Cn:"/$Xq@5KG@Z4%Z<6lX8cK2s\H!q_^Au/cuA$J8/^n7lI`SnIV\FBCMgETs<ZqNXUjGt&7l<thu[-$ed`d'N;^eP[R3#U]"Cg">%#(_f:3R"a"a2sW$bqb3<:S.$0IWr^T@ht*Nd"L^$#h:U'mP>tI2K3)AF_]^Dae)"=AG)6U+[mZCJccg:7Ah*2:\j>j>S.a.fOpi7$'>YPN@G8Njr%$bZXKq?`cM<OE(;ep(#`-VJItV>6%g1faM;)>Nj0Nk"(gP=B"iT$r+]<@QcNsU,JU2O3aBAlq3;?qn%6sfZO3I&A).@%4j1Ka]ckLB3#filE:H+OJ7$`_oI-d2`T@cSW]2;V\94Ad;1aN-Y6F-O/QcB6P@4=M&r9/M;Q(7fde_9Fo:iJS:`f4fX'5a9`>1XMb;*jR>OH*'kEGIBq)NAj!QldbPNVFHX0j^o-YkNnZS]9oquYoc8Uge?<ORL_n;lE!VjD+H$dNnL>ET[n()^B99A%@"],Pur<,Rq>XbTr)':^rF>2M\l2XrMHp=!'YN89\*]5SUd%sPrRde>#jC:CRjp(/kJEbmC#@C+H46#;fr);M)Z,48$^YM5l:ke<ito,_+uU[ALQYY@aaErYQ,c-LQGe&f[DkcXcumgDln3:\1XlKHpT]@]n#5&72'R@Cc_-Y@^!f`)+`o\L.&q`]jX9isaX7\A1YeRNo-Ye)7p0u6>6LRpmp*g(B1,S0KP:XY5N:XT]*n5S3lDEF#ANJn)@mS/>P1)ejYknNTBgsYZV7Be"-@O=NqhKP@M>o+\dXP(Y12tS6E]d7Zr&9:R$ggbaCI<002USHtt+tk=jjDB7Sg3et>NB+,,q$aJh[:a,tQCFW;WFpof<nM-H?d&oDgK3!I]2k2=Ml+LaoaT3Fb-Pe\jQ@i;puPG49:"])f%$G/#3H]upV1`I\oQZ#E&]GtjeZn]VtdH,s21<J]Pqn<]J@,m,h"^Goo'Ch[XP#ZF2.#;HJdm?&\]Q5?ZasEI&]oK5;=t+=C@2.?t"t&o<;pr*NJq83k*mVn=0/Ms7QeM.:tjNImS\^9L>gT"lnAADB=D=nh#p<J$%I;q=B9H_'$;p@=Sb']K0YQVupm0kV-Hq+7[*^jgJgSG!T:GNXS@G*9Y`aT-?21.(BLoW8"9X4$H%uci1d\Qh`Xb2Q#8grMC**oF4"N?-'1[n>O0/-XuZ_Op/P*A?*-*KIMK0XdOEh0+h(]bJu<CKq5h3T.ZAEG?Bu$E=3L+r@KLBp#[/5)1g-%^JpjQ+5\/#D-Z2$iA<d>pq+oI=K=Lt\14]upgo:^U5sMRJV06'mkub`cEd4?>P.<[E<;aJBS#E.*eHQ#109dgs7=`+o`>6CjTOKW^s92$Xg>"u8Jeg.>E+El3&ej*<4pkf$hjQ(n$Q6m~>endstream
endobj
18 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2220
>>
stream
Gb"/)=`<%S&:XAWR$XObdBL80"k\SOkr(uW/+2h`JV>;sNac.3,rn7qoY9jVOt7upiiQF,OgKXM.\)./mi)a.1SFN8\^+pjn@T!%?SPq.H:))'8EcV[;6TT%6NdjG.Y.l%I4^!E6Ld<-53eplm'D4]`\j\[&ah(WS.k:8b_+]dn8X3d[Cf"pmrNksVKC2-9+kp<JMBHDYC)Fb.i-bYQ+W1;+op+kaTn+/a$2XR_%eHi..O]W&elRT$dE)]MW5OeYja8rdnW%uh[VCa\fN)YBTDpSUdQ<PP+q`'=V"A[eWH;)&XrL;HISELp[,T-No>+=1.?;VAI3`6Etb+2d-'2:B?(8'MBXZF1OthSdNmLf@aafZoIcg2fU?-n00-q$HT1ShQi\+Yf<_us1ASH.q`Z"=BaA06d0H2@\Ym%4e<>i!-p=)/4-@b9dUR7fH$u((:4TXY*?M0XNegLi<aA:iQXqVa.1?W<dj\P@##$d10[5a`cA`^-&;KGj9YtaR??:(nMh2SaP]Lhe#:emWDEA%0Z5N^]!:?Ypqr6C!irnNIhG"6#B]k3oY4kd9A>pAqp*A?(]Q/S75?A&i&31,G:70T?>tI.<1H8`<L1c?/:e)g"8N]H"9'e@MfFhP3`NbP5p^'s;ZOJ0\opucAp\hNP+^4YN,FpBuCQu25QFbE"7&Y%\8=#4^CG)TsOH"6h?e,+U#BaO6i#M`F$u+mU8I%oKhNC]==.:iJo5@Vu\Fg8D&2mb^H6/H-pC^Fn"-oP0_JDh00iU8c/o)SME:*TD0HY047khf-k/^Ikb?DZ@c\c0HXe*7iQ1=P2L@2,sq*4Db\['<#/r[+^Rm<C0Oh&DkJ`S!'rG';WbKaRN/C'5HT\l<bikZ9:n'L,BNA0OKZgsVgRmmA)&jpOH\7LQiM%J1KB?K%@$NK?aBu.E</C.$f+q"V*Z;c?/98m!!Vi`8<$M:roE!-ue^;V=5=ojEan27pNGN&bV6dc`&pRJaWS.L&+`2sE>[C+c0P>fYZ3;RY$Yo-rD7o57dWMh5.R'."kVai+)07(51>QpR0WU>uL*<itN*<D0^O<be(!\cBBq(*Rs+Tpb-R[OHL\3*I%Z%MuEgXDpY]0Y:k#,u#)OM@9H=2,p>_^)K)I8JNG@@4[nDTe;[F+.`f$%bPBVtVj:oo=2^]W@0.mLapr&[24qLqbeB<IA4J*=M_1=P<$HH42jP@GHM7DM$aB9t%CSVGencfdndp^PeX"")%--S=?gdFY8dtVCmF;:BMJjl=Bpd#'Z47rbmts/IfiR9?UUZ*L;fC>V8QS&pI?`me/prJ)9.>D]^`>W@kM.5;OW(e2KD=s#E4iaOQa,)m1JD;*mhTb[V$pXX0BY,a1P.:8R,E-:L06a/G`5P#q*4dD"OU>?bR\s6+`/Cu4e5&PW)(,4:B?KPa,U^cmrOZ#.igOuf.r9+mO[9s<hJS_%(Z`*Drnk-LqIo;H[(^p\D3&'dAj%<h%V_4/b.>S>Qr,>u>&qpVJ4-G0a_UHG-N^Cdg7Uq^BX&G:psS#ZV*?8+cgT8K7-!RZI@at4H=nKj0b.82?fG[foOHW?!G-9]7L)O5<.DH@S7-7k.1F2.TtAdU']"L>"T(B$bmD<&Ecgsa%`ZrV)=p)=FW1-ELQ44X:is8U^mNUSEVDkXh29uF<A0Z;e@N(j$RD=kFj$I?[&E*>VGXm22!=bo]cW-VLrR;$h`^GaM9^uTd,s-,3U)D3XCH\s9jk1QQfIHV0%*c@QBk5"n[)Q/C^ZJXJ/+/\.klo!!MKK4fH)HQ_:D4N'bRuFW*XO);LgFTcc%?S/]?>#Pl$VTBd^k_=e5(uRI^"ep#JpkIJA*WUKSha)(gn#M^?'fN=/Ne>d5dK&s9+7f$Frqd9FQXFY3$#Obp$cC\"j+[s76!&l-Y;E-n\9`-2ruU*`<r3^<pU,/*"r-8jnI"Wcn?HK?(Ns\nYZhCmC%[^9c1!!ENMV"'/[__%bjX+kn2](LoU)K<X3cZ'IBdR:$LQB?0U6'Ui]L/bGu$N7ZF.EI_-MkYbH!bYH6cDOR;mS-%@'(59PLc.'N?M[anLfK/p`emZft?Q(2gJII47nhs.H.dkR*WoPhd3N;Mk04ft6-ET58QY[Ma)3Fq@S5Nc6S!cO%2Y1hjIVn(t_+e,.]#&N,hr[Ua!)6U/>)E86@A'=J;rHUbmKONR122GPRZ(jHGWdd?$FoX274ghGu`J4qFrWQ:jIk:~>endstream
endobj
19 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2086
>>
stream
Gb"/(=`<%S&:XAW(gp4Vm5BoJl,ZM[DN>K9Cq!-IIE;k6dB[4ank*r8c*-"JF]e06Vs>l8,`!%hPfWZ4jr8&iUu:/Q[Ju"\JCbTVr/LhiE%qDDLk(DEnFiUNGE6\jn/VO_9@nAJ&>)T2#frcIMM$<q&4W&q16@07dKRXHlZq!4>f5boNs,-#c]PrfnB.\OKB7>D!nVFC;GO_TI1V'')ONI`nNIHG!T6)jpn/Q*jaE1\=PtHr6[[L^![K'%j">s58;9/b6)QAeo3SPqDj1Zd>O+f_MK=.f66Ja^,TZ6E"sFJL[A@%Uga0ZkLb>ROs5VS[%rdh'\epI6/:kRY>S"k$>VbHXl%c%_U54_*L[[c?lQhroF]ptaM^u;^@75>%(Q>*JhTGa<FTL!CZ[#e,F?Z\drDQ.)W^(YQqM_"\Oh*DJO#)Bbo[(Lf*SH#&J8590^LKO2SX?6?s3iOCQ-kP_^tUgXofie+adV'PY2Zf:Z[@',e4*PX+M+eUk6d9el?*gWnk<**OJ\&K8"rV6m>V=`%Oj"qlP+5Y15b]L]>8hORm@m,\C*(Pk)0kL\qK\N9FXsPF/6fcWqKPi7mC7)NkfFiVMB828#@ccklccQf/e\@.a>ni3%=7]3[K.*_P9>($dk>nXd\6s36pQb&W@=YFd>E6blZQ,0)Lbc`\>;BRY>a'q>=b6FL"Q4%Ku&U(b3(%VefE9qNQMqg-sj_7B`LZ:$X1MRJIZScSCLVBPUoGi2]"[F)b=;C_Q6g-Krk2f5V^G_u:*:&S=]&kQl@Mi?h;uSR+M;6P\l-<Y`>?'b7a"NPa(**L<r_G%l"2?_r9($?HWOJPK/_Ta`=c1,..VSEIK9_a?3K&$)#KUfJGg%C3*nl"$NT.m\nePD;38Ll%@9?).`$4N:4T7l<Lb$b.mjD19;7m0c,jo4uP,-J7"Y>*SM4JW?^qWBC;h8pP&_993r*G"Fh-hPd^]GhHG+6Xs%B#kQS1&KnW.&"$,Tjg`9^Mtn2k`]`k=i#_BXj0qrU`^JE]Aj7X>JT9m:JGJd+]X:J:,FoNqJIt)\%kq05AN[Be;(=Nefaj(_#T'Z!)M^Yhm0e,o_tM8XjiTK>m/Jup_b#H:"*>0Pm2.iq_i>O`0WVh-odg6d5->#hf!#chRu;KS1cs^M^ucjY:PnVkY_6EtcS-^^pl8KDM(b6,fLXB;`5,Pb<A%;E;r[Ve^MK\23Y._-8Z/b[A9kNTHJ:6oq:\<D-Hs"(8[a81N>'c@^L(7dX4%X"nEgCT]k<_cXQf\9>%J#J\N+EnWa]IV&%KDL+i7tY:rD?OWpk`m_/^<+WXTr&'8Mqc2&&'^e__#%o*TIs-.JhN:24PbjqH1=?r1LYCWp&fdP@0p%^FFR`8F/-@.li&geGf)QK(!VD<[,PmHqQ00hJ/>e&qSZH-IE:Y?*20XLK0`hgru+-NOR'ipu-jZ?RKs?7X&>Rpg:K?PVZCa@nUfr$c3+XCRV-KZkAn_;e@-R)`c[LGcXl7_'b"bCX,;[E:VHIGqqAX'`,d*b_*t0Zrsc.X1:h8M10*`udc3q`tcR2Md#oKK6oU6.@f+i-1[7TnH>\l[Kreaj@-AN=E@BCa.'1f)uq1IElZH=cRUjS3neafhHO&%0W``Rc[Xk"74+9mRV5;&G:>9S,3%rot#kC]K2*?MAk+E!j-OP3lMAG)^>'e+F5q`DdCtJ2+/5<f0!ZS9"u$!0B_<gfCL]o^/M>%#Emk:fh^OCI6M07Gb@;M3\@V;0G+MQ\]N_PdJ8Nal@K]A5i=u8$TC[W0cm>W/Bfa3<11'6r7N+@7&L1EfDEF1;+'+FNd1j2ViqEj$"`+GA#+ZF[+3/Lr^Q06b@>B1A@!IWC<&W)JOTBc@)4HM_4_-]f$/uZY?WL(587$FJTja:TKt(XQnuPD>cHphV<,S(?l'aM:t0"YI]jc!q:sn)B((4p:luR+TZBJ4OV@LPO)L&U=ZA(YTu3-RkH-'t8mR[nj$ESr]OQ`Vh-0N`PC)pugcK83:JTVb'<l*Po)dbGZEm*8X@"((rt:2tef8pOK6T)'jtPm"oMifOnOs\:!^d!;L%e^ciE,f<H+YF:K&46n6g;#~>endstream
endobj
20 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 3051
>>
stream
Gatm==``=W&q9SYkjm;@.4H2_5k&f2c'C;.*7#lLa4>'5ncD[m"IgSM*`=?"IN&8?aZ=go<(qoe\f6'Hh59,gs4$t*B)qrL_T<#iPeli)-mp!hTAY*AnDf&/:)#`/M!Ol1mfEf$O$t&Za[(f>6Q-P+R1EWb&JfUT0Lks_TE4*dDVlLsW'2:_?5PGF1@"[4GFk#>GC6(5-#Vq#^^9UGUqa.s6Tjd+J9:/RaI^/\3$97nO\"Dld.\soNtR5Y5(a_t%.E+B]lse<*7VG+od(jBf68J[ff:2ec;@'lj>m!eC'jD1XYnXLEIAIG>,'sa#64Ym^J"?h9k4i3ZRg[Bb$;s8'#$.;^tIi>=]),lP[eqk(Ga+p1RXPI@!Dpo\!hH#5%bQ_*j!ch,R^7TI&p;PPki"hHR1!g(#\`jI76f:P5<+<4mo&c*^Nd1BOT]qD'\WgP[]kJe88GWS>\I5cc8s?i5h6F4MXC;MhlVVB3]E$m!CR)kd#*n6ej7UMPm!,iL?J4Jbn=B4u#aigKR2ZIZs$kJLlK&^di/*ce;H^HHYdp(Y1klF)>\Dj26oI@FfaDUDIdZd-:\'R(@igk*>,0aW5?J`R##@+#nrMf7r_O(iIJI(DD'$icZSY103X-VD(nlE1;Ym)N/uJX;L0eW[Nh@ROHd[DGEJIc2V++][Usmm4L.WJr(I_nRT6XP!n:SOhYG<90hdTSq']aV4+*`'"*hjUJeje$]1R.hE@&Krfd.[U,e.B9P"-!DdV,76Pm5JkXV/iOA[[qjq#,mK:U,#jY"9\#m4p_"Z,C^n4f.G[Y;ra:4c+<]iBDrY2BoZESh[cgdWF,T]<1j,7kMii,KE]Snm6DRkP8_2:iGmDOT5D/R?TDBRuH\ot6<=?Jo8`9H(coiH-Ff6Sm:+R!<M_Z4FuH]dKCqf+'$&,OdF'1-X7ff7&@KV>#u$<YaKu6DPT@SKljgd%#,imhA7i#0J@?dg<YF::_bUYoP8!J%0XZpCHqkW:`8G__n%[O0,SI#.FFnMsQdPX926Fg[d\gg8b-'qX7uE<3dRjO&+E^OEL4?V@l^-Im-U=\mKrj_rsFP+0-!b`B5Xb<f"LFj/)L2;"$3ndoH*CeL4;b&S/A4An*]LTpe9D8kf'b`*&7Z&QUKJCV)t?ak1BBK'cPu7b*^t:k'^b5;Oj+W:AUFo8]"'I6]rn@6Re*)1$Q(rQTd14BJ+3)sAc&Bmp,I9TG0AM9D_D!'roM-M:Og\qH$JC5J4#JKhs5[N\A0NjJO@(C2:qf,1N]fkVGIh.rt@iH#[qLc^K.<pmalN@gaDEm5:7=Z4*JP[qAl>!R`VR:@4=geeegb>ikX*GGocV(BbpqPI&1ONi+0qZGkYio1s68H'=UEAYtjHIsV^.P3=`bT;n7Sp0EV97.Kg<&A:H.HZFR&YKo95feJD$K#>I>b@Y%s*VOHSj2`%h':W=M\The#fM,>oeh8m^ZEgc$ZSFM#?T.SQM95?Y3Z@nXe[+Eo=K]RHC+K9hXl!'B_J'E-Ua#H',jCWZ:Hp_'G#2CgGn^c(1MJfYItk!`N(+W6UHS'4H+$b7@Q_?J:!6b!V8?!n\Iq\[=,E@Fd(#fXpkS?6`r:2VrMAbFf[.Ac&D"u[,KAA("\PsJ5N+2*E6nS3=9\jlPd)lei?sH3kEM<)7=X"C[9e!],%-9f#Y+!X]r@R*^h:7q!iYHe+=4XRbJAHGOdju[79@A[,4A1SUBbp.p!.RPq.T6&*eoj+W>YI$b_@YJ:8gS@D-WkPE)=S_[GT.OfSN2TKI6sY;lmc%>8%NI3d1H\Z7/Z7u'iMeC/&HDRE4+p,iV5Tpj`iAsq?T-KBQQ5lgRY8#n(8?d>ZlC<DT2:EL,b^`V4B=)"Y_Ui#]VAr*KR`,VY]:ZNq-'G`X%^RSp,<kmt3qn_5Rcc25>7u%;6grh2!#\>0@PSF3Be5VGt*?8e6<Q(!PFc3,?DAN5p*/TtSM0LDoQ<8,7KP2TQ[ik0XRV+Fh;[OT\!k@U[pG\s%@uFX2;jAWl%'mEUM])fQ9T*[Hl2m^1U5*XZA>@\</bDMRbrfP:AT"NY(l:SrHVmI,RE3F</p1T&Nd?;HYNSqq%JBf+6fuHj`Hno=$)r&.(<1m>Ub-iYD8^hY=RZp65.g1*]h>SRM5X61eBY\*-nh`X[;a.2M)L2k[$LY\-$(Xi^-Y2q@PtV;85e=0M]up^0Wc$I(/i2O9StSq\#QH5T3gR[X$!\U<loah:!S)>GLK:ce3YTe(=6eK\V3FPpTVH.-!3+1+I^+/XAfS$)ZWlOBi-pR:3(K$NtuDIFXpp<.-'@A=*-9L#2C%=GF3<ij$ulr`5JFopU8H_$YfKhhHlYf^SC"jL4W1YZqK=]M[&3inh6JKS^#P,`p+qAS\duo\rgP]#D?j`A$*(IrS.=V<tH4jpmuM+hmQ,7c<=pf?1J6\/AI6fr-FmppW$EcS]]],(,KMm1O@I$C1SZuAS`)t)AMS,/g4-H2mr5QK<9;$rj2]jp[h&&bq?V,f-_0ejE[QIFBs4/La_h#V-TgknbdT&<fPjmEFfg$rl[N-NqJuD5Uo/3EL%AC,"\l4+VQ(=M6kkIb_3JbaX^As>!edj5_uT$2[/pE$;2LLFG'Q[e`!Y[#eJS#7o3D(a[hsahVeoiJ*s<A!;dMaaK^;aA^TaY(Do6G\h)d3R)/?IMQrED?AfP&Z(Nf1&6icWc[V69:IT;K"H*V\e\$&!5q4ETOTop,'Yh`M6rtWA_obZAq3nJZAu)Y(amQ2<fA'EI\K'X@P^"lnh4Rl"K3juA46*S5S1rCDHFS?rP'[hpQ,"U"l98'Kop>+R%0)pB;tq\0NSKQVXjI^>%]n\.Rc[e6PtB/K?!j0]hjH\_)2KsubB\)REaj1rs0@\H*0-9niPG!V6&HT4@18\4PiZFA:LZ_N,8"j_cTYq*&?JVIJp)`rq7O0M7dYr>16(dl@0C/LV9JG%=kKJBK&H`[0KejUL'N0546+kS\hZD;qniO)_=3!Lqe]QjS[s\??!H*+l[5g=kH!EbM[3oV&:s_OpZ<!4mgW0si!l_e3;>_!R)K=~>endstream
endobj
21 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2719
>>
stream
Gb!SnHZ.Xu')t1g@SgGE\%>L/ML+C2!bpXPhX`%-ltl+j!s_8,*$qoOQ/q^`(]Eb\Un2a=a_fSdXsap:12#`._g-6,$3^B+p"Pr<]GncSpCo$.nI8<tE>T4[5Ml9c:Xb/1'+UIKR'ruHB'TYB35i/:&;b8hBT+\[%*-_^AXL9#Am,tX+;SqfC/8nkHA`WKc1&iR@6,,df,U!A5cLpN[UB9iQpDb',GV`1>^$2DAFrVdJ,*MK1LPo1/>Cgp8N@Ve,>:$6be[\c"*&)E!Z:=d>1ukG7l,3,23-[P%3"Dc&LA:t?VlRj$#"4U;Mo@,[NQ6BkKl:Ps(qb6d7bhBD%m.mQ,^\Q9jto+"\42tUEoAn<(u7=4GY+`bXIo5K^g(A?V/X&rgZhbgtL[N'F@S;Vb96WM>09pHf<9JcipbqkTc\K,GZY9O/B;RK^n)pXp'tSl<X\sD<n%V"o\Sja,t*HS3*1UFWD8!E29iLDW$*cHM/E;fX>(f3I%qB#utNt;FdoUD^lW%@T4Q4!f>G`-lC,2W@3V_kt)#fLQoEV#>qE_\:m_^+PcicK[WG[[<Si@;uf*iV8&]W=>j&;S5RN]r@Oqa2\hHmk<p.I5`75*h7,m6+d8fR6]I@^<ZE31JE#+AeS/\7Z+BRd)@KiVk`&JaZ/uU?Q_<PA%P%$LS<(>4(E9H4U+*ICNS<l,VM=6o(5:#r-44KO$%m"I=t\TG2^uT8]I:G_B?ODq,&C>p!:kfM9Lbl#G-#A<AU98Cm!EX87j5O!M`?%PV]nn*mgi8P6SEfprD:)c<.g+E]nbX`7hQZ/5R"N]^DmP5(?p#;priIg$U0!!L'G]G<'V@YLIfX4Z'b?0-V)bls+\r%"Xj:#*/'s^oJX&(Uc3Q*2p5%o(YT#qrWJ?W;YOV,O>t(!6b(%SU@dj0V"Z6SpS9.F^5/Nq/O+OVKJ(%!ceT*(6O!.qMHO3+@M,=rk@RP_Q`DZQNJ^iA;;u>CP10eZ`a=UaU:H,_18E)6=ktJ=ELB#$Af/_r<ih9CWI!m@<b>s<RG;uVX@J1;c@?j-dk,026G1!/AK$`pGPPbfZ7o:`A88_[DIUi2MmqAL?4^[]8HG<Z;PHP_MQD7>o7e0I6]l;C/D)8;D<b*h$Ub_HL8EtV2V)ZoY!fk#@*U(IZ_eeCT*VEg#H:HCUY<X7Ofq9QAJXs0,C!t%qS'5NcqtJoKTmDo)?;R/!&3USiDt\/8$M35&g(c>HgL'7SQ0H(.?uQbDFq-Sabclne#jNb`)DPT$P+,rB2C:J$W9h7`D\gPWE_+6Ps:'kh9l:"Q)A$]=Yp*k;$$GWY-L[5HYpZ.@k:E<H.0;!gle-!X9k_&--4]AiE,ci*I4p)BIF!=[d@=iXeU#<:UBbB,S"mO'$.nTIhm?$Oa3qK12`\<RtNk!Q-W]#`jI,tS$0K\a5=H/Rd!@qVul62ItXDVZs=.)6+3P>:PLk:gK?[BH2_PVeg;CdM_.Pa[Nk\XVJb\u![<Z"(d>j,G4j[VlgMVLadXX%`P+dA/9*<>Qq=L/$DuL=].NRhkn*Q$l3-g1Bp*89NoWY;koe(kg,BdG?fm)_F9jB]S45"\LpA'sMdg#t_<3.=H<6g7q8mNNPf('>1]O?.3@6oNE#9&4:SU0gft+Z-Q6"Ju_u8@R[CJg@G:&dOTVO)b4d,AU>=IV]/Val'M2GDO0Zsprj-AoI)LAVaEKJd^>#k$n'q+YSqh>LBRc`.K7hl3IZYS0%JORi`&%juWdDmCm7$ngWM2;3!:Z4JEU:KWY(K'+;^.>](7"pV_3jp&5H<t((7RLd5f`ZW2!N3S4^sAZsYX:BW@\6tWKEi*mr4?\'Ffk":QqhFI^MijU3G[H/br30MgSf6J[ZP\c[Sc?sCc/pT.#HsZ4hDMeW9R].obH;@aZJ]m%M#:a2PpPNX'C1\e8=c=j/JLlqH8nN6].NKNc'$)@ZQ9(rac>*bkUDXYi!_Re$#%kdE+rbR#]LJ=8t6qB2fj>/&SEg5o7$`qsXEKrNkP`VupY3-^#AnPFb"`$X+4e^GS&QE?!QTYo:QRT77F3#-LCXU1\+!'[Qb2>-:JU:O3Q(a2n(thuk_m(?7,o$aR7Za-G)SV+fVa"iJm0ajIU[0-9f,]0"mhfU&HqOR!!uH6=S&qs?.&SY@WWki.4II.HW=3;b[!m-LVC5FUIj6Ig@9gW=$]ci:Wk0&Q"aG#q*OT&khY>D&Z`KW*aNmW-eSk"n(K4MU+<fIkI)KB%Hh1E*o]r]e$98)k2o3!t7N"`=l:+p)RG?aSiUh]Zl:3&eF9hGrt=0s'i!Qt`/<qOL>!ILPNq(K37-cXqUZeV*J5Yl5=mchFmIf!uB&VFHC'Cn2M"q+XJqTp+GlIL'T#=KVd3%S,'",TiQG6WqV1)deE2I8FB%n93R<4N/G$eHR>]`.RXRV6r;`@AGd]@3ceB0N&j?0EnMM,`8LtU^#^5k[:2MkeP`8%lt]n=lp]E0%<H`+(+_c\k7)\e1WFRli!`2(ZI+:2SF:i3#amS6I+mbpnC?$FT-/7h`8:&Fannt`?esB+81c-BZRAHK<l*#9]XZI.4-\eCIdo[me:SCjd3@SVsZYQB-N.DGR9aolZh[ObQ",S^C3J,9F4u`S@eMIDU"[neZB'hU]+g@DZ+9'5)&%Grpelina.>%ErK$e6efoU9lW+1M&0nh8%`r/".qe_qYj0A1?79(+UGVThO(dj:W,fT8\s85!>;Er'E~>endstream
endobj
22 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2641
>>
stream
Gb!SmD/\/g')q<+0jA%jDNQUu,uIQXG6)XI2!MPnlSp=/#Z)p)j!^4iX<]1Lr;%@1YAnA=c5CiAU93)\adIo?_r2$GJDqZJJ,MCC+(I8iB#$BbYCW+[K^f'=j3D!P@Sk[M-4n'-N\GuCL;dF3P%c;\aUW@uB3]uK>(kXr!7$G*D.Z-ZiVHi8\A`ib>)pM*jie?T4l7NfTE5rdLuDGGR"S\f<?q)1%Serf5X,!k2kN>2clj/e+;:4W7gN^Y`<bR[i%PCoiu4lNp_L_LVc]dj(?lH/XHAkuN]KF!'/?4,MrFu=&E3gnBW@5)#i\qnd<H/WcbkZ>3/OOgol&hLK_$aWr_3T`SD2CPh=%1SOCiM7n)_4kj1Dj\ZF;O%L%.5N]#!:b$l<e7nK5gd(kn/BO?U`rQLk(79nULh]><\]>,jn=Lh0\c!<QDu.W)OHG5lq9E>iBE<@C_RIKk6<gnF]McC0BBE]H!o,XNb]@\KBU0MS-g8$b5\YA"#d9eaK%Bs_W/r[ju]%FpVh\:JSe+R8kUUWG;KKJ?[R^ZDon(<+"N\Z_se8Z5sADD:Iu<;SDR]XZH#g5g6F/#8kd$3iO).Qj>DE,:-$5$Xl;QYq_r.$"X8GmDKDmdRQk!:C,)fZ(6u%=u,N$rb6f[BM\5N]-L_aQ<?Cqqeit$V"d,T0I/SF4oBja]i:7A._Kf]9dFp1].[tWD(%dn@)2`qs0COEOYAUK\oPF-ZF1U5Pk-SGI@Hc>:tXb^"W/'<[si;Jm9[WiR^V?k`0b22!XPL$bm)TVal5SB(VrB9P*:1$-^$fUa#HFK6s"K"Lf&4aQQ@QdY7Io7YLO763!Pi&R+pb`W$a$`7QR-[&e%m+"h*0;-1U,7L]N!-AQOdB>NsD]F[k;FKiOkAD4I'DXPU+cd9Lg`\6oZ_#HLek&LtY:\N_MKbs0n6]g,OpMZilCQJ3O6@1g5IX2%Gl1\)2RlA?rPQ'bL)b_V?CAI)@^ZZ6ubB&14]!QS'jRSg>0M7_MQr:ie!S"(QW9sogpTZ;oN\gu7qb53G9uG=lhq:'dR//bo\!."k/0sd,`e!B5S*QfCgUk)8bV/_l7u&cniW\Tn`S<H]U?Pi'W02)edKYf@.BQaSc)oT0@O5DdVG:hW,QH&R6(OH&<D$I.>R3Kp+rr4Vd+^$>gnqIb7Gq_4L*^=ud!@%h4FMo+:R:TL77/rt%I%kZ0r>PJJG4=l68>m+W\Gi9N5:$FQ>(s)%WZ_eQ#]s/;U2#VW``+W1L[tK1W+gASn50,S8m-RN")["Z*"dc9;S:\jd,eCT%"$2Q$_[V%.2olnKM0ZbG\'MgU1A.H5J#jT!pm]Ea]O2_8>Y`h!`)sX4:jpnE%'CEg&gDd:F8Lj`VLK'.^>H#%to3;1e&h#BAs=5odR'\Z\H<StO`6K\D0uYS)G9DNT[h/=pJc"Yt]Idn>Osk$1pkVg9cV&8V7/7-`Rh"m4MJhX6Le7j20nGun<%M,(FT1-7u;.bOmAqA:TFICg.G/$l9#cQ^3$7D6KQ[M/8(7e^5F65)?c<,elLSW<uEc225i9BmE1dK-0G*[;cdGT+^3b>B7U0h1'2Q`1oEAb+*CXK\f,OGg5LXG7>B:GFntr8Ag1a5Aj:KUXO)9+MOC1kb;#GuIhGqg71]b4NFITU-64-pK]$B*UV4LK@edVM.73fM8oV@nG#@AX^J9)#H,Bk#/$I0h1WKUr+7V'n!BYN&!qP]g&!PlV:qM!OY5B9SVkqeHXhAZAVg[iDtQ#HU.p?/2:4%+[[)mj6].$H.eq7ft2=e!,om0O'pjY-YTiU_m`"Th3E0\U(Yo^6QA5nkk\A\ZAuT_1C!$e(<+&#:tl4d^q@Zh4qKh0HB=3(qP:C)@<l.cV,K$Uq1NB64Mu4G\hqFL2bOplmG:HHM`V6;]kAUR\JM+=/tl1aPuLi'nc]9ZCN1mS,en4ZaR9rQFhg+1leN=`K0%-k_$`TmN^37Aj8K>(]fu`"ii8jT=VIRh[gL`[J'f@2*KSK9VrL"r9X\Ll>[t&:BRs;#hpnX.g>OM>[1qo&_-Vt-8MqU95UK'm!1N#N3%@m5d<Ll=?FQc7Q*#4^B8D87%bBp4^$HdrIee-toPK,1=Is+>[NL:'%&+jP0RH?e9NK.$O8/2;"g:C@,rBNSGY"hI\1Dim>tC8eWlf$t.C/6U;Pr-$AD)[u8Ya<A<<j9dN=McT%Q?>Z.UD3pOVa@aT3I!q<.@?$rS-UhU#@[pW^>7pY'N<B3!hMh(KfNt*4lP]'prR7gFRbQThL:s*OdF`=[A8\9T'S%k#O(Pn!qq&Ml%,ghVrc/[B,=RlM3bQ6Wu[S&lgVk/LV^a8dPr(W^+mgJ(<8+;+m.(e3/U3QSk)P=I,I]QE&!D6;[&I96C']6NNq@<oI/_ehsorgbo_1_:RNfU$7@]#%4q6%XjDFjpcP#HR*L>KIU>67Sqq0d!ELi-VMp;l48oJ$trS]q3,A]Ml)Y3Z`.GFAME)mCb/c]\!6UneV#5E9*$[njX3.f(XJ]?<uG'1=pKmc4F5F-,IUh5O/nJG\0/9'Wn>*ek>h&+PT^6GQ1"YTmq"<XSR=sZY)[YA)dp,F_ja:]q^./$4c\FXl1Y`:P>)!0P`$Dkj=ilK:Q+Ia0>apN09UF>Ou6=<d.n3WY\8^~>endstream
endobj
xref
0 23
0000000000 65535 f
0000000061 00000 n
0000000122 00000 n
0000000229 00000 n
0000000341 00000 n
0000000546 00000 n
0000000656 00000 n
0000000761 00000 n
0000000966 00000 n
0000001171 00000 n
0000001376 00000 n
0000001582 00000 n
0000001788 00000 n
0000001994 00000 n
0000002064 00000 n
0000002345 00000 n
0000002444 00000 n
0000004261 00000 n
0000006685 00000 n
0000008997 00000 n
0000011175 00000 n
0000014318 00000 n
0000017129 00000 n
trailer
<<
/ID
[<4c88adf75e990bd3ea85826d6e0ee994><4c88adf75e990bd3ea85826d6e0ee994>]
% ReportLab generated PDF document -- digest (opensource)
/Info 14 0 R
/Root 13 0 R
/Size 23
>>
startxref
19862
%%EOF

View File

@@ -0,0 +1,296 @@
%PDF-1.4
%<25><><EFBFBD><EFBFBD> ReportLab Generated PDF document (opensource)
1 0 obj
<<
/F1 2 0 R /F2 3 0 R /F3 4 0 R /F4 8 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/BaseFont /Courier /Encoding /WinAnsiEncoding /Name /F3 /Subtype /Type1 /Type /Font
>>
endobj
5 0 obj
<<
/Contents 21 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/Contents 22 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
7 0 obj
<<
/Contents 23 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
8 0 obj
<<
/BaseFont /Courier-Bold /Encoding /WinAnsiEncoding /Name /F4 /Subtype /Type1 /Type /Font
>>
endobj
9 0 obj
<<
/Contents 24 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
10 0 obj
<<
/Contents 25 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
11 0 obj
<<
/Contents 26 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
12 0 obj
<<
/Contents 27 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
13 0 obj
<<
/Contents 28 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
14 0 obj
<<
/Contents 29 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
15 0 obj
<<
/Contents 30 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
16 0 obj
<<
/Contents 31 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
17 0 obj
<<
/Contents 32 0 R /MediaBox [ 0 0 595.2756 841.8898 ] /Parent 20 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
18 0 obj
<<
/PageMode /UseNone /Pages 20 0 R /Type /Catalog
>>
endobj
19 0 obj
<<
/Author (\(anonymous\)) /CreationDate (D:20260422143453+02'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20260422143453+02'00') /Producer (ReportLab PDF Library - \(opensource\))
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
>>
endobj
20 0 obj
<<
/Count 12 /Kids [ 5 0 R 6 0 R 7 0 R 9 0 R 10 0 R 11 0 R 12 0 R 13 0 R 14 0 R 15 0 R
16 0 R 17 0 R ] /Type /Pages
>>
endobj
21 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1754
>>
stream
Gatm:968fX&AI`dqN@),ZH)RfBMY,<B&f+7fbflWI$)AbA;!>r@5drSgG=-u0\@WS<&&,Bh>L&4^)dIm^Wc_tF+Dje3.Ju!E>[L5P=3:O')idY^(6$mTqN*T:tfR``!F=L$,pG:TsA)MiJ_PKTcuTq)E9**#Zq(\L"hpr&iTRe<Q8u_3E%tDlUqk*WduljKM_q!iJN>,8$-]+?%d`OCAkBf^\W:B'WfYP5`*mW8Pk@B/i8>D.#qr5@IIJ/_a/?9islq>h40TuF@QcO.1meN;A<IlLCb2&'<098d)7>fBJbL.O.X-m_#&LgbBTK=.=A*%)c%uojue/q(MBqo1+=_8L:?m5VYO\=Zg%^QmU5\8\aJ.;ggGrWQMjH\!i(9==lm-#fmfbgP"!04G!9E13hX%b)IOo)Tm4;^Tfn7p]%c_&nEe/h?)XKee7.e)$K<mFp`r^qW)S?s.0L"B=tlg,Kq(]Z,tJn_;H3^j`b3j"W?K:.j,sK3%g)-iBr=@iZ.OCr@1(mu68j(#Zge,c:K4.]f`F3%Te7ST%G*'%Ptlb(o<-Bnk]"I;#Gd\+$BhuJ#i?H]ml58n7*L.=8XCitT]'o'h*e)n=3G=cceCRQ>[7guEorPU\QL""8*PYhA*W-^62&E7UJKKmBEGon)b.CP[*tc:@f1/>cn*]DM'#M$*aL6"KPUJg5d]k//hOYijpZrN:C@BGa+=GS!mlMGc6G(Gq@RJC?RZVM9:<7=]iF*oSo"%^b7M*m&k>r2:LT(Z-+5piJ!0=][AsR1g'k.T't,5CE0n_@NL*(3rHLAqD)WrgMKH52h2U4p+hJ3<`J7-B7q&F"5"=@t>9GKD111Vn=-6jbfcM8A*S4KRj8`*3G6#XCMXT"<[E1DM-G*+BiROi'8n3m=nnfFXFETqi-1_5sBQ[96,E)\g<>=oGm77%\7IH7noI5`J/F5&CP!t)N;3J'pm+F>8iFteX#G@EP@&L!;2(PN=2Qo'thgQ\(ponu+j3[5VM.CDE)X^$:QuDH,1Q7+T%?Jl3DL;Ze)<Pa3eu)*P\er81bh/gbL?tQ+`IJ5kc.W`H+jmi>6Au-(R^RsA5hDISgN55IHdZbS2%0)UT-2rd\.<VQ$n:qWa@FlMl0-\i^W<l$>"3^8/Yh:neEs*?`Ak?+boW+OkL5J(9Pjs4rJ>WC+([-$.N%@=dW#rEQ5SK2]&N\^CDI'B*Yn*[JII[:YY;(H:*uoF/^"cnW6ag,^W;>/FQ/U[c$>j5IbLegKfRkrF)7E=<J9/6b4B*/%*e>A'gnF#ZZ=79QO^qj\+&A2#c`8aZdNR,Gs9-n!bI$T>1mBI%Z2U,XCohEWOEX\ML8FX_Bmn>!V`@2^O?b`ffY]\5b#";29Sq7T4N)@o<KojLYTN+brL_mOkebs(OOo2EWOGu]3KX]7D>kmh2PoU>Kj-"bh\Y>G!*XL]C]@CJ0[Js"H*HA$n_$,M1%3aVhYd\DCEo\h'VlX'$%S%2rJO]DcL]&EID!*EYcA8!e4@_aJScRr%q>mdJ)<Mbk1?94X7RNpI7m7QgVg^9g=Z#WT.IK].e+\PJ:Xf$UgKHaNS:!Wmc@N<;WG(=Vr+pXk8K=.<DR^f<-@UXp9Ib_W-63]>/8?0t'n?h[dN#fl?P]?2/a,;<JfW$cNu]Pb[_0$diF'!*FO-hU24H#Mqj_H@qP3Uafo\"/,0/[nO"6g?XJh0n*1]_`ii7H%mOtag27+^D@+tV+5D>ZO?#HL4:*b4pWW?F.%]ts%S8^h#~>endstream
endobj
22 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2925
>>
stream
Gb"/(>E@Ms(4Ml_EF&]+fo/O$e1JIF0gX5ug9fUHgs/Q!A;ar5/5&o5*i&>mpDd(4>JA+m53sK78/00e--t[/#DW8gr]=Be]H>$%5B>Z``Xfk]-"6]T5)uiG]!?,fpe69N40J&+@/75U!X\\h.`KXr%kPPN$VoV^_K/rn_K%f#H]Tb&G]RF"eUEQ>^+\t)\Dme\IVAs<F+JDeZ@0auBaKP"[)22(EP!4kdP:V$ZiB?h/'EK$'(M@N].TH.E/P%W'sIg2TFNO:HqWDcWm]<C,m2>mFL3=!@m4!mU5[18@JGD;KXcS7Q>3q^Y2q_jd<Gtm?iU)f/UYiUWgM)</:g%.>YXB-HkXALS(m7uU54_*7IWT+X!E$qWjI-_j$ss$+k@\1;YXp7H\;;6<<-Z^O.si>%,'OT=e(3h3cog@7l>nPBPQZ5i,PQ'9,AV-dnEOVS[>GcG-u!'c$Mq^5J3F5A-?I'8JF3q>/E+QT?uLKY#p9m>:p74EKG_<=c@?m#'Ngka)g1nU)g!Om@`.'FM?9ng6\r'c'Km-CBhlr1Y*5]DDj6)QJgY8IJ$uOV^]jKrXGZ)Y>cEWl$_J6[%c,)f?KdFa[^]n"a$7KN\GptQ*>NP)+Ze15Q$<ekW:<eC%h%>\IRj[NaTfk'6;q+Y0RKHR,=rW:"8^5]Adtd>MO:ra'nSM.?IaA`:a'A3eWH0<ok=IHoqk]=M]%Zp`[i@Jqgr@4=$$O<d,&BV'YA$U-sVA>d%FP]Z:r%*$[=dKAOutc@F\"Ks6g]?K+Jf(Mfk?<&n9!Le,!/>X4Nb3N-I#L,l?A4MnXsRYP;a]nIb\Htfr/9iS)-.`E^=.LVUoPsC^+.PE>tYMuM?K3+ZJU"O'Q*B-*]3/M8T_Pa<MLhLWCF";4OJ9Ph:o6*cT];7pM8DD_)>@J<>*9khTF):Fg^\GP#Np1SlPFg.URNVlXN[ML`KFV^!ci?#jB2TD?!Gcm79lm<F52G+BQ$G&8olo5!/Q"+h[;`-=gKZqU`o0:#."QX\BWOI>,#bD<HC$UC1@%iHrSo<$(5E1MrXdn'8D+r>a:E+Yf(g07C_*E`DdS1'Rt+nFgY3N[kFoje_K#]-$dRh<,K;Pp\>Q'L@]17.qI^k(Z^i!l7QZeOmk_Sjr<O'q"HVhT7i:b_4E&4V`+I((j.&_c1I`saG6sI^aAd34U1a&Nd-eSNa,^Bl@7^g#D+du@=NC.P2(O_Antj9L_K5fo9Hk>2Vg*k&P(Du6MTb0VjXT(rGlKNh)&(6t1JW&=ph00P;#3(EZIoYIo2:jHQ=6<!5@>L@-+uc>G"^4"+(O;ERGT$Lj!I?^^/Ub7''C]:OogqOh`!G84f]P58p%iZ;I73NpL0L?Q1)7tPoJ"Z[s@],7k@#"Lb!Zh[ejY2rYkL_^4ck#dU%GeAp2LAqhCNZfX%EZ>-pK53p`eQIc@UO<r[(1'McM3;/JE[,1'SJl.9a2D'_*:E2TS64>-YgDkjLCm_6@UOPhMas*-p^DG$^9Vt._KFl%6]e=@4i42q'.=M"rVSB_P'l3T"R3YOJ.'0\@XTd$po2h`R&$J.('V!2Jfc_%3i8!>`9(TG+S#^>4:8Q$jm^2emfrFIj0X87"n070ZhAsOtGTIN3P4fAWW7p*2IS<h:hlE8%Y4;u4m@>L@f>nq;-neFC?E\k=2<effl,I<]f*'10u<KXH-F3h9SF52(%$Eo5S(,J'23?,^gl;]<'NM"20G^nIF$.2YOjVToANp]jB_@"Zc>MWr@=`LWJE"FroKClk9]8UqqWsY&(c[8e_-g5=/U))PW>;EA1d`6P58at-C,;-BCod3/H^'>7dO;%E;k&RLUEB6gLl^Wi^+@0=B;#NX+9tP:HF;)Vfe%RmX@P+AGR7cJZ7@`WU8uJ++1uAX20F"ECFNj'f!$_a_?$N3q[8TrlTSbLR`mSZ=L?2X8J:5%9EVn^@;Upe%Wp0pM$Fa314su?Tl'dg71hA&"TGII$!-^%D4V@jqp@l]'\t&l]V"-niQ6g&P[9>-p&Z5b!:lU;B;gQa=,Z^$VL13<T%5I4fCEs9=l'pCGE.RDa$iV%KASNmiUV(uDU2aKR]!HoY[T[H0d"dIHW;%D*>bJ.AD*)X5i=/G?a>$]Dp$MDV.+B)TR.tj9*Thn.LM=#T_]DLLZ(o5KLZ)mhcnu)F1Y\(Qlhqn.rZ;;pS"C#dM]hNg!dA8k_6e#umdEVn"fAkW_$Te=gkkkcK$KX-.!=1_XJ%&87/[s#r*>OZ/TlH4B=)nQX%h?)D+pI+=%f4Q5e\R#l'U8qaqa'5;TGfs?)R#-L%DO9;a46[U*(RdU?9sL^4e=HW3eg].?<pk'.QHnEs!@OGtaB4%hT#AGnqRj_[nQcU1;Q@GFt9iVG?Z_=*+b\5BJfW?duckJT7?V?[T</0+M*rPA-Iabr,;LLmL(C"CaHXf/7_)7ffkX>e&I/$Hc!6p8Kb/0?17Yh&?'U"OOF:;?*.89VM8K(JMFQ#b,6oc>7qNP7$6@C*R*)Meu:1&?ti[7G@a%#&%bScM_1eWA1An,1n8p_(PXaV0>\L%\]l>kqlV@AHrJ++AZifYhJ;,+[WeS?l>4X7=sX$/ca.W7Z]e#Xt(E'Snm9oofacP8r][?0FP:7;&7s9R;.j"qFN2FYM_F:$BBS_.X'"u_e#M;?c#r.KeIGW3:,lC+f9mPIU6$jT$i=90ud=C?f^b;9]qqc3!fot:\o%KM$6*knH.N:B$rL8eB&#\:"4pt:IMX4!n&WW#:fI"LL3NoqDphjSIPmb,Y8e"AY$qH_*@6-3;!k('))M3MMXN_,T=b&O%hLY<59tb;c[Z<-7*BQ.$2G>)DnH!p&)@n&Z3#Hcq(Zpd"p+MSKYTOZO7]9PZEE+21ZP!W0nKm`T1l:j_/t_*_M'cHRMU<G:29$pZ-\3M7M,8pIj&;-B(s`l9@P1GgQ~>endstream
endobj
23 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2894
>>
stream
Gau`V>Beg[&q9SYR!n1tP-nFt#a!hsmR`nFEDDsu)l8#*$VeGMD2M:aaP)hb^B8uhWLG2Zj5e-5#nf$2$td6L5aVVhJ(4JCjoE/TiMT`k."h%!cnG`6r"a`#TDa0RE0A-bKRaFJ9+F83"\V1\Ve7:_a#")>AJ.BT!Yu(KN!1toBEY_pS*+EMd`P'J`%f.[UI$<@Hl+,l8>)1P4;KZ)!>@:E4e-nYi]I7kj5^k$s.A2p!WafN&s4<&P(k)m5T#grjrbMdJL#k\"aiFJB,R11-@p!r(kajgM'3-lZk5e@"<UHM+UZTI;goE5K3/tK`cE!1HiM\D]WS-3a_"OQ^aEEgCo6/I@hHA`]Qhg\H)&mm?E/?P</\::oeRHB_YCYZHD!K50tN`jk^TWOTEOc4kj$0erK'eG1'Kkgo-Z0?QD$&\!I?N<"if.Y>UpKjSR**>?(5QLML:!C$W1XK@@.0Aj;]*BK]og7KE<*di9iThM;u*aLQM1gLfp^[KhFrkPe<GUpA4;#"jNn-FQ,IR6Gt:qbfJFfFC!T.Z.<M@K<+03T)G>)ajuC\"K\l)1\?9U2Td`GJTb<%*H]-;7[G`/Ls6[s1Sn<+(e!]]Ta:</a3Dd+oSRc0\C!#,6g7`2;/;(N>h11?%)R^HPk*FkJsEA)1sD3`pYIVa@0%\oIFK*8Biuoc_c0pnbPY,#S)Y'\!0n"!`L.YoTTKX-$CfZ-`r<ZOVAKI)?S(m:YQs9(6aFXi8N4Y*k?5].OeZQi"oS/(1-%6o)Os5\Sp/bE<`M<10WD&j_*TfAo`WDoXkSm!TLu_pjrPL3>1LeFTXNTi\Unq.#S&L,9hq/qPriX0XlQU9VTSJ:JATTIPnuK39;NSGAQI%lL&*HGY3*_+>/;#O[46B'qZd)X*WbI_"6Y(B@`tEg#moj:^qBCnM^@LKVKj,qk.P^/pKiF[`P$RN5_d_SlVf/sdHOb4&Ct<VR$'j7-:Hc*JIj@:ei'?,_e]c*%@E;DL2l5BMRN8]Ca`E$,6Y2FHZo+fpD\*kN#*O3JecrQ2J2g>eqRU.[!gS5k,h0i1?j`D(A7&KKbYOZd<ojmB[&4ALafEr-$uNJ++%e9A8@9.br49k7EJcE3Or1KS)[mkA@MtW\-Sm;""1KjUTo20.3mN2iJ7Yj3^hf[+V_Z.n[TTb+QPG',Fc7dQ](JsD%mg4KUZP@l!-)mOi)6o0T$&m4=O@)8?iBH5pb>p$P\N-+2TiC?SGPW(efSSP/QX56I&sj3^=T3+&)G2)]emB,`5H?&lMt+%htQK+U9kp@TSluMT'#;Co?,'BF`"o3LM5,E\Y*`,T.8ObN+f>Y>S;/eP;^BPCLqXCM'&[*0S.B9q-;lMJ3k`q6^(,pcSENm"ef-'A:HuRf+j?L*gG6[4F22BfStOJlsRtk%S/;5C4`?iXTOR6tEUT]GUBS:Z@\`ng`7t%r'K05'3<Q:,RaoFO4TU,\FXU&ie#KikuQmaVF:;Ob%PQ't_0K#OWTg..Zp=mT#6/Zpp*Y*bnuD:?i(a"g[g!M2M%#I@LsG*IkO3539A8"oN(RCRm!9NE(Eh;<X&Gk5Y*!@B/st7b,ORs/UgglX`9%V[BmK;h]+V.)07Z'#0g1`D-p`ceV;=*,n3mFS+9e]AY8,r$s==6NS_7$aD$&H3q#,_)_ll,NgUNik'r?&!(>mL2*g=GUhAbO1,gs@k0q;1166)7aS<S2TWNQA2bfa,1_&ipNQ8Se0-U&>o;UWgP_'5HnA+.739RjhSS$PgT>f^H77f=:`=7lFO-!SpDk=5a0OgIdJ@UrP0b@:Aq>n$le?GsgTi_)N"SlsgoHR3f8oYD$;2'0X\NSdGUGnPji,Y#=kfdd&8U[N]GRn"M*k%U9mS7Dgei7Md5.jkg^t9!idA:s=<ZfIJef(j`3DDqjCSecHH_#h3+)U,6C&S>$&md`lT.`9n#gW=/Bp*_>NmcCnO93o>fS9EF5:@_,YX#Bk*$198+8U>8_VCkX0ec1U\d0]q^^0aB;s1W&q5QGF`j<drFk^"2bPfQL0q"P-ElSah=s+\=EW!*38E\0!F1qpW2n%gcs\>#A?KV$,k!qu+cCtBj6qJ6!V2l[,+1qFTMgGIOj"7G7L=#dJe1f*H2m(CEsDl(A"Rh$/jVfCq]%P[KZ9n*PP08@ID0Q-h`&2i0mM7ul#4#Aq^3^2I&#=4N3&Gc^!PdqjM9'G2mp9.n968B%-DgHLJ4q-G")D2!4+%5barf^%:iA(q2?[To&g2nCX;a0QAF6.P\<&SYoH1.D43V1@A3Ql@7aO1pt)"90oRX<X).CQrB\`GJ;/1G-P[CC^;Bu-TgqDmMkVrZR@?p(L?ncgj23n4ebSU^!Xhc$`M"?_7QA4)i8d)jg@H:/p?(E4GAsC]SLXbdM.hu0p/R5!;=g1%kSb'!gqIJ6i&!"5jqb(dTZ"6)%bkZDIu?4.'G"Q8)O2MlBVQ[)a677m<DASo,+RZj[S>)JlE8sC&$<<qj;(CllY;.Goc1\F'*hoVY+1,DEMq/CHWF,u9"R<Y<U*$mK[gDL"lK>[]3e75jS`QeJ)A<CK+R+WNr!,<'\-suR>;)C7Y`^@!cW=aI6UWr1#-?!<B6fNG6`-'6Q&KPdHtn&<'dq4(d!?#L22;,@<3SVH:PZ6cCJT^6GK:.fsgV?Y;;I"mIREW**H;,\girED4FAO'ZnKP!9lWrq02HZs-=_6J9fM:p;BZeW5XAK:s`\@#u3qOo_k9uIa^",%K*>0?TqR]>gY780_+hp"=KDs4$$Ml9.0b9l7\FVM[$r+)N*::@VV:n^$FO/Epm7SgH'bc[Qgk^F`kli:>ZA*'j&Rsl"\6t+,FQOj1VF*8i=3Sk;d&WYO)uBnb/?!V6JgYd+a<TXT(H0!T"`W5k:lPaoH)S"0la-+o~>endstream
endobj
24 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2717
>>
stream
Gau`UBli&f')et?dIEMQA$6$oioMg4a`\k>?*YH0mG06l\MtRB`"A%:acR46o&$oBO<E`9?!EU`!X-(Vd#EecL]PJEXSs6:!/Eqos-WoJ0Y@B4M1jgmGX(!ZI>8(Hpf%;,NpF:YLbB_h815fH)0Y^V5WIdV3.XH,kIA;fEBTA.:aihu]gICK^IK=%kP4,^EJ(F/,_8To?q_-j4$H3P*>[iSVSA2J70%#AoFFXqhgX6%%c!]hNtU>mR089Wb(\"^"c)+TB[EeQi,#;/V6:+A&@WN%Om%i%5bpf,kfKN#_)+LF^m^[s?A(t!7jAqL0KAn'jVX$KM(5:D4AXmV<N,,eJof4#3&obV.*K-%e/7&ACR*te<+XT1(f"N7>.a4UQe]V1(/+?cW"KpNI$@W[@Eb<tP;iq9p?[1D5Zsat"4Rtb_3spL^cIM"F/?obq7/IW$<$cWs-Ws&FY7obQ3L^6$GOOqVukrePfhq9YJYiA+BZG+:);,j&&ZSQ6Kh7"UI8O8UC*_@Sm_mNp.@VC">#8B637cEk;gu<O;q]oZ,ZP:Xt1a]IH8'/ArE$I$kq>5dTL<jkQ5q1T1Ng#(MMEaei':L;A*8M>+#Vt;+GR3?XH1/o29/[Q''n.G\TVui'$Kb.?Ed+Qu,4D\i+l^GWo:@,f<1,A^U/@qM'^=cEQfI2JF%[elfd?+1*32H([l6qgH%D&iPl2#uN(ua)%i7Yu8]`h!oAq$L`Q.Fe4WC2?(<he`Qej4sbOG+6;HTSeiUk_0F'aXo"fOrZiXsh.uhgGBouNS@2Y"m"*I7U9igN1Bgd-Ko6q#_ISfGEL!P.-hD&b+12%(^sO$Dgs(HUkFU23IVqs!5Ee37%d*';8pNX>b[!<E?du$Aa&f8ha'f^sJU**BHMhXs<#Wcu/eiT:gL;%*X!5[W=VX^kj(kRmJ[;TaYFL[1^l*.Gm4g5"1oRXUMUS3'r&Q0-nmY6_=R["J3K#7f=NucK3S+JSI?Ks;L"Wt6R.,)RJNSWY+c5!me*i\((aU#'+9Sr&Z<1*<QOno)7*WTS\huNE"7utu9qpbbP)k4<Ye5YT0LMkhli@'m+D2WlqH*SZ]n<1;qbGl":9g`D<3s.-^3HgZJ@eA@".%.9T:'*O4hc>'ql]q@4\j5@S(dW1l[<1tS58G%41NT=/Hcr7P'WUALuWFrG[#?\bs,C]"Bn)fi^uFKG%]AA)?\FH7!RMOS4#GO4kJh)*G\No>Hb/>=;!ZS5MCB=]fK67k^#ar/SdNA>XaX(WO3*MKMdus9lgGE(RJdYpfR6+U.VgCDB.=Xo;2#$:"FjYXL1%=:[=qOb1<DR:hBuOD$.fl[__"#Dce,07!X4rX)a-\[E_Y@G0Ume@,/.'k%N4UH0^oW'l4m[(q_`/i?h(VPX1;EE2Mk]#j53ZL/j1f&4i)'dmu?g(ZVB$k@=RfGR>q2!o-nlkNWC0*$!BGi$O+W"Q%]*WTM&i;kKm#gBIh4hN$M`+U-`@$Ds7CZYC;jk??WjKSaj3<^U+9\S?'s\BNJlV#b=_/N(:U`&]m%Y>IU+f\pS:B`lV56_ZCHj0@Q2rDA\k$#)LC-gE$H_29>[%'$d^3m0=t;49k87M2!<3hDu5>E#QkY#2njA(`BmZ'O\o2c;lN4gl1?ijs\CaZP.;>NuA7"XAROKaGJYKX[ppEt7)N6o"lo"EEsR-u7rV*heho\q!:6;ic]P?gt5"$-j<&n"a%:)X1R/RbO8:mFah3if#KT'"/GW[jIfGIIj-)Ql^C#lCbR=HhP^SBC6`?gnKWY\\kls#V8@4qP&Yp<sTl;\EiAK%*('+a7?otHCIg)Q;YorRL9J+n,BJSj]]g,0/\!&D_q0fSBo&L=K;>*/:'s%-,5e_FEu1)VR2%cL$.(m9-bnG6V+@ch;][fisNoh#1mTRdlap.G\6cSiO:Kiom#)3)AW'B\ZQa"O0aiL+jF$;-QiPc<+`*Te81g$%8d6D%6NMZEc2OcYA;+E2&I6m"HLjg/<$aKM$54KW1>T[C<_PAV"8,ZMe`Nd.K[Xn=bTGA&-j8#O]e_DgF18X\-mr9(N_QU\+#@k0&]cU7]GSZ-'VY\+\6M9S$d(U7SkrGe7qQV_P^eEhjKU%B-6"g\_tBRMRiUu3pF'O3$r'VZGH+<@1nQr"hH(Pqm$I0#i;-`S*RuRkD#am1tRkKeLUA90N:IZBAr"M&Tl"Wc/Ri!Te>m;pXVrr:W"AEJLm2XC6i+LY.-@t<%"AXo#qMVONgZsh)_NCO[OMlk%/If:U[Ka@&WWAgWV#"pM>K&lEs!ckhp:j04)))!/I*!o=]AUH]VKZB,A;-4>!A9E3!AU:B$M*LK/LQE-jWX%2[O:->HauW^6Tk5W,*=dklsYWhph"WG6l1j)h/]Z9I)RN3i$pfKrrgGI-nBCk5*X5$]jj+hk`.9X)fr/ni8O:J2S:5eEVp[eYl`;'WBRThG.C%E@Uq&4]kkqaioUlZ:r/+/r;MrLWc!I3pG[>g&$4rdq(F@ATDmfjsp9E1tTW5;$p!NuS(kTi&tQU"o5u^g)$D58Uf/5O&QcQtK82k?0SoAjXcJkHEgIc/X#?.nY<uM[-M'?'NV>RfOCtqCI-sAjmd"JW6VpR[h%jcg]]RkJIhNDnhik5!:kf3.(\mo5>_"f\Hs2q#=-/#:CTh^A[s-It-)ZO?YLk[fAO?[FsrRabIS!.KgTRk5'"[&F_gZrNSDV]bjj!"(:;A"-,ln~>endstream
endobj
25 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2259
>>
stream
Gau`UqbQ!:&H;Y-MQ*U(QRFEALL3Sd9*d@g.3[Y@=pYKQHT;KuqeH!N-/sFCm.ti8T-6KqN[2>EG%SIZq.@9$TjZdhec5IZJ6*uJgnR+PN6Zt],%.bg];*3W"2YN!0a&&*>)pRQ38A&IJ93o0;:qQp@?ao&\gCjoB`V_^Z>F>D.cL=$J@MGgD4$@$nB%VC\W+6EY%:^#.4<n**>!mle5\"+GmD=!$`KtbG743W^CQ,,2lOYQLgsReJ4YU6\A_hW-Gqt`mbD%M7tYiKNnU:%XE'@iTK0mj+p;@C9;[7R<$=X1>'d3W_Cac7$INMg_h3.Thnkjn/2R;M8Kp.>;s@ZME5ItOgM]$ZZRj=@)8L$5/Yci;O`C@/7[GfTY"[1+(X,/]o-OA41';7k5-d:20@V%hj"U2BSC@'N"'#H28t\)K#^Xq=!9:9G9]9=pI>@ZuWI1?`DlB(F+OmiQ9imqN(l#4?A2:ia.JQbr)hFJ(%<<</ZZHshjUfG)0l??`>2ShJOP!,Odj.DVXBa2@*.mMgh"L=nM-Hb]]TJ3Dar-[q**iGh5=r"ER@Oa^T!arup1g(^5V,._RhsK\AD.5CR6[_aEX@l@7F_);".t=7fD$qc6;Vr@CEYZ1iA%kl3,lp/$dY"mM,Au^4,Y@>hp7RKVoW``V'[=H(!I4I%O)mc,\@&eKODb]-Cr%W1Ub);#+TZZedO.IWT>so3--#PC>bigoo(B>C1&l]L=YVLe&!t3[AnTk)RU(lnEDsOK-rDa<d$s2Aelp^bIX>Y<Id$XW$hn*G%6Z'7=93r@WfAar2_XgP?L&Wb37sM@YUXTPnTX6U8SWf.](%T+\VdY-p68.AlJ0BbN*7I@o@?X/]qa4'hPe3j=lk^8NQB^/-CZ6l=!-APhWd4/j*4^'KN0!l4bKp[Q+aNQ-pYdJ=fFeQURY8'Ie;4k:&1Zl#.$`/:G+,<%*ukd6#K+CFX#hH.I\nFrlET_c[)D`Ko%UXQ4$]"Y]a+p>LB7lY9H)XpCFF;"1=!%q]/\!Xqenj^it&ncVnX-$V@T=Nr_RZQ5M0NZmD1Ka=oijKg[\8Z.b\a6$NSE<2H(M2s<<,3*HZYl"1Yo^MY+rnF!mUZ98Z=5-6WVoKnQIsTLn%ZaRR&Dd&r]7\QsGQ6oZ86sdk`/]eNO0't(L7ub\X\K;<<?*DOA!q7*d='Q!p/kV#:R,6\R3<$L%VWLN$EMKY(HYcllr9UYoKc'8;0!rRH\,i$9ADPuC,?'qm!AX7`bG2O@W*Gti5%FBi?OcU@l`<fig7E]LYUW-#[eNk_(>6Dafl4h(Y*gn">q%.bZd;pk[qRlmkW/bV"7mD\YV6sSHZ,KQ7[%JrT]r[ls2T8(t@&Zc@lFEF+ZCZm_=tnS)@#,K>*S=8r')s$Bl:teYTVklUtqL&40#i,J1UO<bb='dBDD(-u9gHIFM63.j;=m;3t.m'"X+]k^]\H<*hr:\_V)[i9N%i7F:Mf^T[t9?hS&k`GDTO2\@TbAr<(4KJ6WuEp/u`CO7;qo&[jH4VY$`,#.PnK6E>)#C*R"QPgi^8B&[/8"#A`!fo^ZU;"9T/7"!6/EO0PoZ6g*PtUjt\f8]kbN16rkJT7egVnL]dt'/=o\cqh?.8ZaKQEr^BaC7Pga7bA*Aubm3F=XFWj,0XH;I7)F*!V0k0(p<H:Bi5gfhh*0k14sYD"%Fe*6982c-P.)tg\D9IpQ*`e"ro/iBb[QKt@qW[2OK\$_WAptEYuQDsR6$=Hsp;)]9Qf2Bf!bBC0SDgm,_/cr=.5ZB\0R-q6jrsFB$OuH\s+3n\7;IYKK6=)<!XEq]\n_rJ3R_K;(Q0`sO,q$J0';V5BiRRYhFcrOCUFX-[FIU@PQE8ZnCg81C8n.&UU(!iVlV(+IBWA]#FZE$j=="6cQLP]7?E>X6Ud8%\=G:fCY@SQ)A(5f??7N3FcI,]h>6UZUWA*AlWl=@48AFCEleSOdGq8Delm\KFN-6Sj=N4ktN%<;L[Q>:rLXN*_1Z^YLCe^Nt#U;mE\1Y;Nf*?g;U7ELXqSrOX32*e:g<%YrU^@_8?NRPQ)7R;r<9S9+Is`/#Sm[sf@>[2o'WIHEl!DjXQM-32gH'P5hCMIlE#!!a`<1KQl1a_aLLc^o%!dQ2A3*l^"6A7IaFYg*]&J'B4&9]XPsM@,mGdOk!HBS]0N2^F/EY3'&%Gk)^hWPX2\h3-%bN5B^_kWAR9m9_+D=l/?OInh)44+<15e7g0C>Tf8EIhZr_5G4:dOL>+97&o!E=LNS,~>endstream
endobj
26 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1767
>>
stream
Gau`UD/\/e&H;*)EP[aj#ngF;W4)h2QaZ,d(8Q4qed_3^0J[LGP9j;)P86ahqi6gZ43k]$aOnUbBaQ'QiUbhFO"pkD5IC9I-NGfHd!\941?]0uEl+NZ%su"@k8&'..!.E[fCMAe"VSBfM`;EG<ec5o)A,H,%pn</(3i"s7f4C%!>H0$Rk571ird=06\[1fSf]Q(Et\;/&!XZD%D<<4@31F#'D;,3LV"/V4SAKJ*e4*r76J)u8HO[#^/$b6PW6n[),.hU\-=<a\sL9*X''#4(E!h"=X2m=c3]&@NYp0,kMQfL&`NfE0Qh0Moh"@]7(inK%R0ga*o?!'=iTJa:Z57f1*.t01D[doqsE4F9M-T9n60/>1nRNRVDb+A$$r)po[<Z-Kh/J\1B5'>JNA<UWUaI\m@b@CR/h_NSg+s7(9$*j%GZa^P5u#lFejT7!t)*rh,QMO[GC6i#1Tc&+j_c_?;$Y2K0^t?"j.J@"*qr`MLEhD\-l_V*i5n'YFeI@%8*.g&uCR&`+^tqq0X/>!KP?8%M,e-@L%[_bSgt(omQJ4ct/-L&+NO&kt7;RpqrqW\<tA#hSOs6`&N<ce+pqnj"*Y\eXWm^nJQ!=<7<fAl57P1E>,Y/]$(BQ<^pcA0W_^Bj&_'!J@B[)p33F/Yu[\.8Z.`&h$2r1B2mMr]FhVmg!t7G>dkK8f-*CnV<q&T(3+OA02^h`ibG5fVi94'@3LDO0bFcKqbRt.,LrW.:h>GEm6)!t[hT<n&cHdb\kY#Kk(SC;L^PYr4H[U:/7,.Z`XLY<YfJ3=rhZ,Z`ORC.[k*I2"!O=Y60-ciGp'l#@p)RuXHZq^^.r6\lgmf9$cEq>l^$()N-P0In8=!l!<*d=Te-H0Q\l_ZIa)==cE^OuH+&qtqOO?mkP6l5r=-7l0]Unc&g3GHjpj88&pE[k9=00Hc4q%7?2GQfYWkrRc^'N?)*TPee0$(36aGT(d,<X,$t*9"0lDe8Af'N9n+Y\liT\PapTMk;:(MPUm[id9SK@7'D&L\Tp4&gk4nru8p?UQW7Yk0-fRmjn2ZD2gA2LA./,q\nj`;XNC\\:*CF%GJReAi*bel#ET(uAW2(PtXEZklTA-($Wca2lUqRSD+.!KNSW4pE/K8,RrINlP3<H)R%H']M\6:9,BSqtFc'5eALQs^qR+jue.Rfr*UCd;a;L]U\%Y.J"oN:o>+0MUEc=t?6]pl+o6gYND>mFLb&[KGMNSSno,WNNkUDgEQJdscf`Y-Rtu45L#td`h)KNmU%s*>bTSlVb>l@C"-%RgsmW0HAef;j5_tW@@$C`B:Jo4h=pD-U\:D#r=]"@[$m79X.Z.SXN)G'!SC^&imRgR=Pj+fqLZK>erZRJ[JpGo*.E@+>-*g3/S8%;e')SS`1=FqM7;B5'i08(98UCn#_gW`Q8KIQ@kuZacm*/5am`HP@PF:U1=P,,9X<riN-#ho'G&Ip8QU=ASkaWkn;s^8BFi0Z/3VoWC3H&O,:`5\_XC[C#_*fKPIpEq-L!\YhGt!U)$[l\ZVi2l]aI)b_d*ubple7RV1'=AuO73A@<a#igY:Z!KP_,UcGU7WKN/d,P=,(f#X)pil+_Xd&1KM8*g<nP>4LDC,PtZ\ufNY"4p=sF7T[;XhC6=?=MN#!PaE3#U@[fL>&5'j)"6f(=1r8dn/5%^pgrPI/.7=XSs/+$'iH\FXNT5Oh;`mMZcTqpiTm(VJEl-oJaj'J"pjA:"W,'Ii6I6X%HEFiopC!U@mEL+XIWk!`.i9C-h/-C^7!<~>endstream
endobj
27 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2586
>>
stream
Gb"/(>E@OI&q8_F0u-)d:6;;@h%cUHg#g^8OJ_9^Bn9`#BUQ<>Q6hl\f4g-?pWel3pmu:[IQ@]?<[,d+I[iJi*$"msc/3UQnDaNFY;gJ;#%QRTo3q,,?4P9[3b+bF`/YAP$c4mqJAkjQ-9gY8=cUET:RK>]&:u08DA7c^\h&da*eBV2IWEGkRQbbD3-OiVnfUUeHClLW'*@><oAUksT=FtuBSE:DOk`S0q,mL3dU3#r`WB6cPK70P(ig]"c5bFD?'n";iYe7sD(^HbBD!]`3b6+EqM`Y=m@5#\mit<W.<'6X'1*u&[A;M^]TC)5+WARupZC)bYMeSQ,0P(3'H+QeZqRA4gph5)QWFuiAZ<gENo5W(P?G/XbIi-0K3K0TTrlrAqeh?:p9sb2Q6gJTn536*fWooU-7TfCXmu2r't"-#9K5C27]9_mq9`"_),t(48JH#F6(4bVMD%At3T/Rni-QLT1@PD*i=JLDnE`8P2>5gC*(&?g:hn\;:G26`(jBf5T];+%.2(YcCO"jNdh4[Z/>WYXi&"*lLL\].0SM`_5^rDtk+eI\EAWg1pJ:jLWRRe7-lRmX33`,<(pR4L)]*IP$b3;@1ic$>gp+.i;k!l\O*6>jiW526?b*\*B#_W2'`&F!H0P_.I[$8A-X,?OSf']FXY!fhVQtfa)N?M_&dWP,b=^\inZSkk[9/W;OI5^;:A`jf<gC9JT>I(uQ\,CI@^5.cOtcYK@ApK:Z_!CAPREm/+Yn9e5?.!XCp5Y$n86`t;5I3jpRElgo!+W+m/gEjE*!_l<\g.9G^o\'KTTM$ICoGK$__=e>"L-KV5aeu,q=W:f89mtn3?Kb$FKTB=B8@&(nWfA!GU2@j,iU)<^0e)$6'cg4]E=<*iaWuJVW4.M%[1!O80KUN*Uh9/_RB*H*?j&[/0iu-[DO)0ur6-%D8L.YPk19P?52FQ9&6>CRB2s43Q@rEn#8om;1p$5k8*QYP6l!,b#9Yo5`6mh:%iJ!jUC%K3E>d*.09rA+1_X-BE=E??Ao]LbOI8!M*jWJmR(He&B?)6.6183ZgfVgE2FiRt/?[&2uVn2/0XG8J_;1AD'eT1Uo''Q+Vm/F-gl2$$T(U=V-6`]APK=O+1$j_a%XX12RS<6B$I"nm[8L_*io:BQV')UWGp#OK!W9-bPS^mumT`,bsHlObrHK@rRj$5]LWbLO,q3;F@_A#^G160[%tIHAV`9\^VA,>;!ijPS-/PaG&!qdE_reIWNRPdUFK:(W2KLhEDo4,dO\,=GU,1"[+/_8>!akQ)2E,8\(O^>:GtrN4"5Rhsn*7.0[KS5R&4R9T(pNgPO^FIqq(U4NrjgK>_Ods'4f='oVDQOY%U#+TkEMj?:4mkF9nn)4T'J)=X"CJ[Jok(Cps"T($V*)GjD-B,cqGi,k3DiVB-#`/V=Ep9P5r##PKtJjs*E8jme+BWB>EkI0]'f(FGq]lJ!Qs$+l+mgWdm)aeB*J:3k5"G'G=UUOEe$]V\8bLF!f$`pj$mR8JtDEN+S=m%/jO0'GWU\<2b;4rR>"0%T\P0Yq<<A/`OYsu>gs)1,#_gYa8:VW.j:?qEQ`@U!?h,E@0>39"SM]tZ8DK+_tq'G6pLS;>9&&?r+Q[:3AaU^iRUAR)K@D'h58ejAaoQ"p"e+0[gelC&Sg:l?)L4>5>K:bb=5Xf0Sg+&rGl'/^'bGS0M7D\4%Hk3bm;>o-VAkS]N4?a03M,0(q!]T+B#L"O#]'5d70BYj14]']'0WXtj.T:S'mEo't>>9?'75V#XiXMnTXQUS-*h.%na&EZG-U_U`2!>d1E@*oG;nO*mk:!iAKmlMu^;q6Z*X;Jf:ilj(Vo-,m%ohCK/CcnS-FBk?3oA!]X=:&bH8`haP<D-qm'e9jY`SS\]F+I#FKgl$4L\Vcj]@K9%`CM_.Pdt%^mYn",hD<,1ga1js)>'@Zj>H3*Pj\E9)R,n$)mj2p&78oGA8CG#qMuf<5N.a/GEH^9Rq$9D9o=n+Y$b3\S5r'"nesaG6N:=olAJu;5r<4bgc%(<peCT)4@?+ZD]:!Ql!8W<G6,H'_;VHrfsV5M#h`0AR3coHe^'TIChHQ,AJ1R\m>5:j<tRmdU"[IdHhNSY2l0$a\I?5Fo=17T!Z8rqs42LA@:)t%%N?-i0Xm=i,n^GJ:KRH[.IdnK-YQ5R(A2>>mn*QN5=59/o^<>\r8cIRP*V.71D@h=I3s0XQoPI\S8%j]s9t7YL(^;^$V2\JY6FHWN2=f$cd;_@j,J-`jS*62r.YA2:d2cc$8<@ZAFEaSbYEPFa.V0DNYuWeY/..=C3EShl?PqCt5p89HM]`g[3&7/mR"n45T\/::6[')DHTN'#'"](n;=H\3pPiYO5ihIf77Q:r;CUdk:DBl1Us.O6RL/?mROe$-X(:j=n*/JBeT=p#,;7b1)+,(R4gd17_K[5gT/"?Yr4cXG%kiIBfd'-Jid<.n3[a_GQ[*ZXP\AfeUlnA,BD;,eL4o=Z]$Ya9KhtrS>>4<tF%^9Ld']58It"SM<kk6s84W@hk%*pJ.*gYB#:bh^=`Oc/YR92leWk<N%SIrq5afm<W!FVFK8;XAYgEZ[W!ekA1V~>endstream
endobj
28 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2150
>>
stream
GauHM>>s99'RnB33&<WJTgKO;G;I&,hIWV6dPgGU1jr2:-#mqcX=]3N=oS:>a`_P)"3\2.+Nr=rqT_O%jWb*:r_i\ZS,p8B5lWD>C;O?ee0['^hSYgKkO/ncN5.Ag+I;'aXp)bQ*&FfBRrec?q_TEB2-k/&LR=[nJnYkLo;Dm3L[h\\#qC5HE.$Q]ete<FXQ442\:tBU>/]tP+)GCI1f,DhGot#-!)QH?+-c>ghfX_WQ`.hYM!qq)#)<i/Zs48Vi0\21&Zje]i(KuRdT8mB`3!i$2GRo[5\qAoi_5A`2lK'!!jqOJEYchE^7u5KB$gMGn]t//4e;()S>L!%k;))V<5R!=4a:u#H]dK2/pRT'q1:!YI)^lqLV\0O4B#1^l*jA/?#4BBJ'W2/#%3Y<FBkh/A!:"KnCR;[_E]](\eS&&;M(M40YmI.D(5W=)h!M<WM=j6,B'MB@j'9BD3*OeZO(_\F-spDPjh>#Z&)p"QQ0H83=dEZ*16<EL^VSdaO";q;9C2FPe`GLr6'Y(pfNSKU3OOP(-R=Snq5YdmU_hU.)^,L-nF9b/X#WP7b:6DN+J[&p>9$b.*ULrP+kULRk%^S"PpdTG/e&Pjk7np&>inV:LM-(N$T*R9.i27Bd#28,@qM6B$h7Q5Oiq`2F=W(#d/*L"lXXnDT9^t_<J]lJQd@cH7DVE=/eGd`i3@5BW#DsTUS-L`JA+"J78c`!t)2LVaRl^<LGc$5<)m^6AGp,0IGp5cS;lm*(CA.*YqGJLU"YijH@V/-h&nj^.?^h`%_9&0k2Ku)2f.DAa!`o$C'^_l"-,074_<MG9Kd9:,7]PKQgEOD<(uJ(CNp;F:oTP3Q&*AgHlRt2.o#hED.L:Cm8>K<LSV54@a:/;/-:nY"@*H4mXHH6'!,nWA*";GonK]\'.k0KlGSII7oF!\h:7dl`V#UI^#8-F[B'#g170"42sn@coOO1>o[A(UT2>\W'crh?dCuZSo>:tY`)C!DV/hW<n<(A^cg3uak4sX/5r?<#b;Ifnnh8$):Qi"TOk!#I(J-OB:;htR9fA>V)lYGK00P=@60mYe<"sjb]Y3%+#*%6O;GE/U]kd11u,i'ljAb_.l^>M1-SGhA-$6&1R9bC_-#4XoS[R]]`G<C#8[*b1=12gpPPIkY9LWm><#d3Da&(<Spq,u*HPA49=DhWLJ5Q"KGeEc^X?0#22nk`#(+\n8Nc;$`LPo`kP`#@@^[#8,u0EDB1:e4&u=GMA7)Q04CO+?S)@0((VkAR*ojOg:mYON,P_s#H8oa3Se\d&_NR4I*&4&JCYjEPN,F'kqjo`uHt8$TOS5!t<kS2<m?!-b=b0e0E?RZ644UBUfH'Ct<J(h;[K6VIdumB!MTM&&i+>T]@"![fAMtRnkktm`8<T0F=#F2E\I%r6/9N>iXB^b*X-K[>f79eW/uoT7M2[hQ=m[hDO,W<jo%In5-qaV.F&a,#T/:/cd9\NlE(nD"`b;USV[26&Yft.N9I$VWfG-eJZGVj5'dI$8N0c)%V%@'hS<D$HjodGD,HDGu?@u'^)hGB;:&rlT'=Z%?!;?jfMr\o,!+3Ju:]BZ.`,(Q&b1/4X,"hWsGTo<enj/2C<DM5T54]CtF)''&3Mh*2P'N0cLY]YLI^.K1VcC=,i1Ouc$D626QkoLlJM!htlSapUC!YHMQUN6?@5OAJ=CPs&oauZMS2<pr,#bG4/,f$dqR"oXX`B$e652A(U#c`;7Zbra377.:\cd2)eCV0I8(I0r6),>5;W=$;.W?1D?6!<hnG;h"\Ltlr\2`c?,9,RL]!9UiqoquSFb9]Kgi),O(3^P:nE*0p>$XQ7h6_!&RWdH3T5L]L;qiW'F`^c1@mGHgis#:iF2,;im1ICI/C8NH8*M^LH/>gKqfR1mmd%H&h/NKJ<Bi7>Wc,#ZF]SA/>1J#*=dFG@<FDt`%&N;fp"mJb'j`#63^3/>/Pku<HEY1`"79O[iRQd?oQM92RJ/aS3b'p<;fT>-Lo.3GDkH8F5@ShmUbd-eTO0bE*$iRaC9fla=;I2G@4[QE"uu5Fo\o_T`tPW$lqen-:L?(W2NKiGnI@gr:7,#R7@dAMJ;?52p27?&[qs+9Q"bVtJ_J<@E-PqAcF`";09=YkXsQc+#5Bp/-JU_d.b>8SrWBaYA*!~>endstream
endobj
29 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2772
>>
stream
Gau`U=``=e&q9#Ik[_k:Zn$gm":!^1fqr8U(eH&gVipTY7#i[O+@$U%<77u-Sf(eGFB[?i`F&d(h-V8Qa+sf5s/>m?Z2f,6L:<d':^5r9TY_?r*^G51q9e^l#o+'1ETo!GK;Z4iTn([pPN$1C6]Y+,K++Ts!pKesSf\(lJ<bkq2]XP&pBO)9`UM!JoYY:Un3WcB5UlH;OpZl_,Rr!*[pS*;*WknPqa7iBpj:&FE/dNmi[Nc_![RFEj$&)!8;90eYk9W";5_oA)'qYr06QmiMB`Hj+V5kjOp#,gK+KugdSdIemX%PE7,nGmO,gsq_WPa4o>u9D-1J<El,e2Oh\cg[i37EekAahl.=BWH3m!ZqSJJD;Hi`7d7WaR'?j]WP2u!o*%[6rWnfg/:Cepd.S44'upj>@teNj'GBRh(:^_o1XI/uiFO<=[5.8LeMidr6m@QurND(H5;$`o?k\e[*simk"t,Z$n,M+2DX$CE+/&j>77M?Rteq5B-8+ora0KMZ4c*gZ7L:_^dIBceZ2;=@7`mj][/O0.O:RgJYdM.B6r=bFZY9a%pOpi!^WHk<@-"O>u02ir2hl#aM5pH9n#JQi$9e\>@f5M-'%TT98?V<;eDCkaG@@05Z[-WIo'C1b@H^uOTNUX+/l>ucSTDsb4I-ke=Bb%J[m#3B8#g>Xj.HkB3-Hu9#V.mVT*5\>(2GF2ZGGiRb5Oe,g\io10VGDCgupXa3N]aIRUl'QBO.RJV8dd%(,eI-i-UZ)@(#QgdL^i<sFDpGf`C%MH/&E4\::>nl:`?dS7.S@ND[ORS*\gLWebZ9&^APdhkpikP6SnaW^(e[`/iDq==*dlNBSE`Ge0j0l^E+-V"VNW"^QVIJC`[RdN,XDjlEfJ=#f#V5:R8;H0qcY@gA.`/k]ng9^kZaVW##UU;U:L)B\\u19cWSNj9!>DXMlC%Ie:Wg%@FR^`gDWPJ7CJ*FW/1,TMS4:g3Z->9UJf2)4GjbibHoq5,I6F8LIPAdns%mm'A*Tf-VI;G\B6s:+:*)FIed!,(Hu]Xhj`h_9lr^TSeR^L6mo4u"B%bm7rn>Fh^G<>g>n[a,F<RX9a4]rn^,mH.+WuRKHY<@I3o\=6]bn-YrjDb+=<@RX5&>0eB^`u(/Y7Fa(1UQl9&V/(b=0Q\>n9aT*1O&]hhPt@U7:&?2/$PVDZ@uh7;U\ghEk/2\Un^7*Gc2`5l45Q.PQf\FXlkh%a#D(jRkn?-Z@Or4+UulY=hu/X2;X0tRV'a*\jS0uj--Y=b)%e0D!o/^"-"(O;rRW\O;UQ,PlWFZ9AsU,5MOY&EU4K_Y`pb^#S717d9?n=KieD\D8p9>.oflYJF1@"rNiT$.Qj0JV0=]#uX]-aCtkRgk;>cZ%8ccJqK>YBPZp8`!T<QmS?n9fXu*VCEfm->qkP&[5,L<KI$*oL+UR?p)6'^kaEpF@]_+WJ5)<2(==8p]A>?Hh8StR,?j>)ZC/cN)9.'MH82QIIfjP44MPMENU":*anM.f$uo\;2_%1dj1F/[9cS4H,E)Q9l>;&HQ8KlCO,u6Bg<FqqE#%6i;XT()#7E^=gY1U'm@GECImbai7B'T=L:77jZY*Xr*`3Cp"Pa5o9K-&Z^LVo'@lit!lqGf+Ng!b`BlA[;VWNk4]e5>9]<cadU?;?-gSb/ZjObCKaQ!Y9IliJ+=-Q'^gn[#dM]G\]14I*9YINj>4i(=*DIuD1t(0^7[.Do>EE&^.g[e)PHn2n9a]1ZPXrPmNo2M"Be^uF;mQ!F0k5PZW:i%%T^Qd48e;H@$HI%jmV-%Q@UHXX[X/%=on)B#[rrNYo>s#do#VpJ(55DAC'(;!9DCYK]KhZ7+p&Pf33c)7BnJi.pV*/ZCYH8f;\EMHG#]5&`8f?K%3J2e,Jaq'C,aIb?oJ4&FqV^`=]7Ah`eDZMe[?A](#GOU*]]^bF6fEm]L^b(mRcc^>te+1^%rhdR1];E(oJm+08qNMDRfQ\jl`Pp>m86l:WbqIFgBG.fkM*6Kq=l(WsCKqa8!%OrRu<#OrK;9Ic@$U.-FRsp3M6(D@,qUg_G$K@&/#j0F*5MIgG(epOg1/2)l]PO"<"JrX/r/DuB]qqB*E]&''2"G<\2UrWRQ"ZA>jZB`RrbS_6qg&8mD80BF[BS"g6.qcaN?M')(&%L.RbW80Q5ZJPfWV0ms+rm9:<@V8U3m\WF`1<ic*fqN4*nK#(7@/DHm"6\Nf.@d+q.d2$nW3.#*C_kfuM++XTPa,$\<G3kQbJY._[k"!\m6ZT0>U$?'8CI!o`26s7ROg!!n7iWAA&U6E0W)]`#u8J%pb,k*oT4<Fm\OI7*?PaBn+bOfmeGZ),YD]"*#d]$\@[YQgYa3]Q37T*Fa!jd./dc;gl8A:3;6+fh8X'R`IVd$>GICQWtr4dUjQ\p/XO5f2[i1:;W'eDe(C+o*NP8kp3*R'MmmWWp;SL:h488*pU)K0nTr#m>EtBZ2BkT-?JXG>3;HOQ-ciJrhKG?/J%&bq-Iij6]j.[X:!qDWehel#D5m2o_g@+Jf!ZEF)0kX27Q9#ZEiS*@&:'SDMB0/,miJ-u0;"nKS^u05FA9kSJ'e3LFuRWg:;=Oq>dO$[G(mYFGD-(RBF4jhn.4:rEe;l7DuqgX<1A\\F^D3m1g'$d0R34sC/"B>?ESD#[q=c7`cXQ$cMjfV`*P8BLAcaE+&7h$LEHMM?V`5?BOsuZ[C,hp%Ho=U]#dkKl[F@;eq"e_Pns4<49TjjrX\tIf?rR)n)fdDFfE-jhJE&^Anf5scr\XAC$>I*)7<gI~>endstream
endobj
30 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2137
>>
stream
Gb"/(CJWtM'`HlqEJ65I)1fhOm)5=BC;g0/F;OHu1Kk*!'iIt.o&qDLB]n"9F^@d8$Y>W]*R+j)pEoV,n\+WVG0PQs+"R?f&\s/c]_fd#ETga3'1>+c&GH!l^H9B.Y+buR-#I3t5a3S*.j,jU@Vi-59/tri866Gl8/jN9[c9%H;@V5r42e8T4&d]KZ/eU4m^0YMY"`b@bT`@9$3]=N\Y_jL?=@ou"nYa%GK]\mT/oBW4Z[R2;7=^P84G#:C^q%JNan`"lWFMVSSFD3%+6GF2+Ado40!f:JJbX>8aug;#dFE2,1Z<pfgJDaW#n>"kkK30%[*O2r0nr<i?D(*J!7brk76kN[Wf#.aDsFo4aj6GA/shnhh:t7qJT*[/cUE,Ar(O-%s8)8!Z"q1>aK>(]O;@uppfGL'Jn8^[4A&5?j&j]@"qB"R:?V[_0e7)9F;Pi't\qhO^h/1GFT5mKW<cg3o<0fQQSCDNkAR:cX<,-+Y>,oYU+.[G]T\n4lkI"W%l2=%Xo7R0oIruMEp+`3>E#B+W;tqQu+[5i8o$M>fu&)gBN.B.$Nem-&KTW20G\De3AEVYq[#&m1[7`V@b]2Hn9*85jKn"5mt%`gq]8c&9m!pGjo*/KGF$2q6HUdC'o&%NH2>R,'[ZgMY0MunFL6Lf$VJ'g9uk%S!-fY-Y_Z'36P(0eADH"1!;!]l:e`FcPEH/bsakQm;:J^6`ji(iZV(NiBY:W?_rtE<i6hj:?!,JNKZ'?(/KQ#R$+WZk3gq%:4F?\NXpKKJ&94N,eq17(&4A'DNi:0ot;4?<9'/Tm`':7Q<FsGj.e)'+-4a@>X?P1E3U`(rF>?N!Eotad5=5bdd&!jm_Snj+)ooXdttfor+-AXksGq0REQG`OCAfm`>(@J._Go7?(C8La]20nI5(L9$s0,`C!d]RT2bPJ:gNN%N^MogUAm$[h'KU\,uRCUH'#rjXd,sKa/$,$oA7lmk;/RfOtal-;FZk72\fYNdJ!8EpM371dj^I65c6T^0>!@lM^X`[0Y$IUDI.3Ec#a$#:XT,O]'k475#(i)_@oQN?Fe7kRDbbX^u7a/bHpp/G^\_dBXhrQ6]E%qjM&M,C7@3s,K"ihMYaS\YK\$UCS=FOTsZol$<m@4^mFVbjiF=9l9$I5(:4Fu:<A'5L?RQA')QsI+/?FT"E/p[%?W&K<77k)P\YSM%MWN,<qK\'65e]6"<!S<R>nTrGXt%H39,am5!M3cXoQ?>5Ne68GNEBSnjM@]HC,@*5UIRfI@\7bI]H`FWU#J#hVNkpc,dN-:+&E=/!ek_@irN3@0U_E,7eK#&_;*5*d1XSTR1d#Gdq.+79>:&ctT;`fkT(-mu@h.U>HA7s!A1EG6LQLmpX*:U]CR[2lt-eCG;dACZ+:q>j6U+idl3(XH:u`gj9?arL>.tQ.FpPr@B-4N#Cpg#70HQ/OXB><S)-3Wp@sP.\hCFJME+fR^,dkA'h(r2%J4dXTb:c>E/<'EE2=6_j/.Tk;3+0N,_`X-EM";!A"u:,S'hT4UCVDZup6&5GP>VSLE'dn>g?jg>r2]D11g/DZ7!)1Z]gk=q<L*reXp[ik>!f%FUCD-,LF`<RP8l\B^%E/h(`j68IOk@H`[oS[dcc@j!QCAI)C*iSNB-ZtW'j6bhh>I%81t^Fgu3X\iqV=g8f"q5`g@G,pLsRX5a<3XQn>_D#J@%oP:%H4(WKI\1(><Lf#BilSQ!CM#Dd=*h*.Bn9J$*4:PX@&^Lf+UH%HI#Ik4\DKe*&$i%gc+Zk"qMjoq&_u^A(=*\)SU.fLb'oiGWDT"*UuX<b<(+EsgfEV2+t&%+Eo*so-_C.O-F:lZg$FO0'ViVV8abOq:03ThG#P._KAE_^No/C%H-QY*60MY]gGtk&G5GJYo5?L*(7_[*B@=WO(J)RT_6'":qZToM)sbWEP'g6`qr]9e\O!J9Jh+#T[MGi^g$A,%)6IjH>EE$HWZA^]O0+5=otjVW$\j"('4o)Np%OWAc!-)djZ(NN`i.cZ(ELDl:h@.CES&te1Me:p*oN_\EeW9#b%?o2pp8sgP_KfT.(:CF<Z@;++ZZeIV#._6^N86;(bN]6$^<e(mG]=YS#V0"LTYIH'"qtXkZ.&p")9HqCQFONR?>rRQI,FDJk;-;~>endstream
endobj
31 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2380
>>
stream
Gb"/(>Ar7S'Roe[3%l6!@V&,gUo4=3d*(";bITQN=('+-/2N;q=ir!M7ec4m-rRG=`,X3?BFCUP;j;MZ4I>LV8dm-IA_h:5!-g\^VnXup*6)X,";*=OJmZNmImt]XM5C>F,aDCB&04?6#cMC2&rAJ=#\RCn9I/T%<5:LkEQhmj%@fR&Oi5_h<,0Ztj@lRa9eT&3Vujs_&o"=2&2%*p=#bMcjA?!"a3c8prqP$"86@%!QkHM8'-J0d4Am.7+?Ak@-A-XKS;d@u[G>@[Pi!\t.#r$b6D0>e8Q*4;XG09]]VU4E8.dGU7cOXl]`$lo6[2n]9Tu#K<<;RCg19@uS8o[gZbn0:RO2rV1PM1XaqWCf_NaF4(gk)RYn]F[06h$:\AeKh1r(Ntd'V>kA,Bn"bKCS/2IQ.e4`sItV)1J:`opiYr8#:6*OP(,0PK4BKri?Kd=).r(*H"3Ukg4b'Hkb=YnRfu6:UB,hU,N1k5qs^7#R)*T.,^*N2=>0de3P.)@>e-oK;Xc%7J]$bH,5Z5l2jVTUiM/SAU-&:l`7Gjn.8ep-n=U%o9_-@>;#tXC$QI2_;4R)P_0q&WF[Y7%u&dL4"!H`OF/Ig1;*3q:0gd"1%232'cTR:Epeh:OhIhLWFKq3-f_$Rnf<0fa*=@3%uK]`>s@6qrah6F&V5G:@8^\6stUq)Z0F6<i26'W%Lf8[^g+$hNC8g(<CB,.3Y34Jo2,SKC*Y_\o?(B8-ZrOImCS]cS6U7/B&=ZCV]g>om:;?H[]!0`ftFB<Aik!$pe;[2)$hMHC<)RI0WDp5!@J/h^K9r0DQ$r[[&8`I!U*XqIm(+mjmqj%DI=Ap_'aX'%"9M)#=^SI6T<N\l"I)'&K6#^3p1KoFH`;f=fsl(U&=6n_4LV]YXUaG:7eY9J+h_K/6`l8ee@3_V<-0Uk;nK1h*`ISp_SjiHYZ="1F?K@S6r2K?V,d%[m16pY?]S'4X2FJtRBuX#WNcN-ZKX.CfZNVqRDuCnnGk1.6s33cR^:r3`F;P*7:`9^fN)UQ`)?W@ML=8AZc51U\[hG&91m;Tt:"RsnIa'!F(XQ)3DrRPdZ,2Y>a5B-Hq_fGi?6,eYNd[LmB^D$$P8.'Vi<o8Rc3[+sN.kMl1pfGYcVJI\59f04.QgH&N_2`!-gI01]BY)0Y_`1%Q>*Z!PbWbu@I$H8t0"M&KJ1r\VD.W&AmM]Y7%Drr:'e%&%Ol,VWT(fZV(-!f96X_[,qV%*lNl,K[f`d1G-@5qYa4e*fD@S1jAer!Yl66F-0D:']?dE"5[fT9m]Lhq"['2cq(l_G9qVjjtIf3Jp]>u.EQqmmiUMnZ<3&A_B7A>3>r_J0-R%H(@=H"/AW2$^hLG#[r5]osP&mu$/MR-kAWLM>8kG+CY21m53J'0iG`f+[q1G&hKhB/a!m3KX1B-hk)/U\Cj*R+:NFB!7?'%"@^E;f:M@=Q/]OleI2Fdt<kGANEC%A%cu5qM5QnA_3e2/CKqjH[KpE=1g8,DC-t+aJZkL#A#d;B<G\.3[^+-q92*MGtC31I,;Wjb)Ndp>j;;%cb-n4()@Pe7O]C0WBJBnG1&Ht1RJ_*3Q5J`mG]V(Q_)?kRWQc"VL=lc']dhkEHETYo-*9I_BuTXLVMR&YGYZ-!68Pm..7@T8a0"*'2!aiOOq7QO=gqI:[B$OcOP6POj;q?!:P=#_nhfQA,%*O<7UoDDLEnb$+A1T%lh$?kME(l9.c_Zn-h$=#b'B@7>G+`O0!!J$;\bt7:8cH#-uNIYc?u&Mask:Bo3VH#eW!uaJ[M(XO;ESDc`egF0f,ZGZ+@hfL'A\5`fffF-tkd):-?ZH1eq;R6TWc=+YXJ-:HLhH5Gd6E?#aA9?9U<O+jqoBr1%MKQcnU-%!>qar#A#jOe,#"8=!g-i6,YhgY'A?<=2Ie5f<9!B+^rD:7#1gWhUQO'I1sAltoGQW7`_7c;57=+ND??I-SRh.5LoL.m%,W/3cUcIrbQ9l@5g0n)C-Y65^fVFcA/gPLkoX0CMd6H7bE@snr&r;BePYoag.F=6ZE!98N9h!!lCDsWDE#u9Ug?M;)(Kfc'HCMY#hFdhHp5K']D\fY>4r'=h]-9"-lPXKbcfIr/[?F3O1bLRdO4uZ3*U7q'8[65rqFnTpZ#XQ+N!5kuB$oup-=Ng(56TeA'"lBq0En_mLdVsniXFk>:I+`^qa41NWlpl6c+0oIK[ib&KMG2gI%1f,A*u'cs:'R)>&3*D='G&%9BO;!..J#'R/d_G]PuC)nbGrXigb]d3e"XX9R@+c>Hu;V@-1K'*Y7$FOr/_37_Dd%:OOaQVGh@J\^omhB=VR&fMeM94*6&^j6H2)',`-rPi_TCZc+EGK(nP^`T'qtj2MYd`Ank7VgO0`orW@JS;p,~>endstream
endobj
32 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 2151
>>
stream
Gau0Eh/D%-%"HT1_3Y2U%TP&_o#JH![9^66O=a\#DA^_:a3bO/Nh*MI#'YRq;=\q"-?5/8Z,s@@r^_pBA;5\eIoQI:Y5k`&0_dna178%BapEjf#_pgbh`YEeY%)DnVQ_&`"QGf#\K$c$01'9+\qEpmJT(d$[]k9:@bEZI+d)9[?&uK!^MO7s@5p"l/@Xd)`3g!]-oHkG#R<=tK">\ccL2mfklT#Lq;%S@p1'-hfV/r3+HC#1%Y>=GR21Di#_k5SDW>".P?q[oUPs;O<S0i%_ANgpc;@)"&dH(C8jd-^Kr6C7disfK)GO;[s"aS&"/"S,9`8NBLN&S+dU-U*c^50.2]%fp)Pidk_gD2)_g&kX;>(d&%krF0TH!G^1R3eYnjbG=C&e`X(B;OrIe=IBjPaE&"F\1YHEJ]0"C5a%%cd2NR7'6[]NHZ1[seO1(p),7*4]+c\P!&a9dE'`kVcXaJHQd$rZ9rVN`4CHr!#H.[YeT4'c9Z1+HH:t&;i_b4bf50WYDEl%5$%1,H`cD<Q/?ZXaO<gO*;0.hT0C0bd&IUX#2@A^0m[k2bX:GjVlTf)f&-FMJ:8<*L,o28o:Vdac]<Dj,u-.p8g8$fqA67Bh;oMC3ReDFH5Y1k\DGBkI>(!.\5f13n%0pI"KMEd^Z.CoBe'/YbA*OX(lUAfaaCPaKrG!;bj*8<AXn%==M*d,5P@rbre[]!F3[G'gBU=b0d:29\<GOSQ>m+O(GgGg<_ClhQfH^22Rue\4pCUgkEYp7,s]n2W1>&$A&P#$Ua\Fh5n;XQc_U_-D_4N`nTM3iZUJ$Gh_GZ?f;LKG/m=[S!45(RqrCHc[YTVW-D/?6oJ1,AA6AEC#TZ??re..^j:eA&'7SO]rMA7D8/^&D2O)2aDg%Oc6"_Af5ZI>l2B@(IP<fPaD$)gNLj[$RNK+UYhos)NEEfdTMKY3F3YL1X'e+%jjm)c8_,]!=ktj_g2$]N$MJ[7nIcL+5kCa9DRM<Ph]Rb7=e--&RCYo1"E-keSAP)iSDp[&"-o8V+4G=dff@FUSE?NJ>3q<292ug$G^,,+"BKc^o-"O:`tV2?=KORD%GGg"p3WRU&>IrGdU3[CXmc,l@^Gbq=8Wm4i;<$K1W8mZQ1oNBs/C@2rI8GL:%T[OQ=%<^h8[S72![6ho$U)A`et"4`(FXGp$`>uMif\XjFjZBg;sZ]m)7`KXN#_d5?B#3b!VV7P/@lNSdOu2q!f[mdHpHMs':`JqgQW;ruo,n1:tH!n3gL,PMi&k_)tgjfVi"?]O#pC6*nn#j-QP*n.qmf=/-oM6=BRW5MhEM^hELk3.f9AqX4&hqX_35cBIG#UPZReqF`AZBKu=oUt";_cS!L;B:L:"YA]2_dij)ZO)D+MC3PWOki'GS(*,+J?;HWoiB6?gOts^Qa'mp+F%X859=@X:q@\fiY/'ceq/U>SCd$5JY<Dr\r+$>4KuAY:93B8<Z3_SWef?m:c="+VGg*kMP2/1BXmb]GjukhP&YPu.brYIbq`t@KDklU?Vo'X=qsV@NiP1-]>(CmrAlX=c.oLNfb'$I"$H[%?=fj+uX!sggA^jtb_pXoMA2T&_p!"p2X!ucbU,A9POYipL=\Z</BEO1$Z"O5t[]sKJWt!TEC'->4g+X6Kj),noWd@h[GtW)(Gm>dQR,R9&T>Opa_PP>l<K@]B"iH718b8ZtkdMLgWr6TBMlW/7DXGi7-j4M*LhSYBKD<,O%:'AWY\FEL'".'bmW;#.4JPBh\LOOEk^K1P/M.PQ:qH%n>H2F+#")LhBN/<%],o-MG*2Be1K6TNFD)D?47qKdDP9HEXjU^o>MJhi[`XmmFc"#(mOc,V^a<Zu!2js]W$luVB*=0d8BXgMCg-;Pb8M4L=E`Q^f\88rU0_f3CMjlSFup`bbL!)qG-^4sXH?R9-hEXbd;it^[2<?%nqDrb9+>;Y;^fUX-:8kV.ZJSt'MF>"d+TQ*Q65O"MM=hA8E?>bWk3JVF,>@B*IDN<.AH5cWb7PInigQF_*%EMlIQ`;aX8`?-OlZEOoCV6SNQ]Y-NlWq#;%Ls_o`?cLqGS:(0d1h_CTrYY?TV>^1(,]Q^],JbOG"%.j$%X+I^@:H(r%!#^fE1]Xe%CP>$`#YCrghdu5I,D'$C3o0W$77/Nk]T_BOHSN]7~>endstream
endobj
xref
0 33
0000000000 65535 f
0000000061 00000 n
0000000122 00000 n
0000000229 00000 n
0000000341 00000 n
0000000446 00000 n
0000000651 00000 n
0000000856 00000 n
0000001061 00000 n
0000001171 00000 n
0000001376 00000 n
0000001582 00000 n
0000001788 00000 n
0000001994 00000 n
0000002200 00000 n
0000002406 00000 n
0000002612 00000 n
0000002818 00000 n
0000003024 00000 n
0000003094 00000 n
0000003375 00000 n
0000003513 00000 n
0000005359 00000 n
0000008376 00000 n
0000011362 00000 n
0000014171 00000 n
0000016522 00000 n
0000018381 00000 n
0000021059 00000 n
0000023301 00000 n
0000026165 00000 n
0000028394 00000 n
0000030866 00000 n
trailer
<<
/ID
[<35a2564fd62d2f3a937cd464104f15c9><35a2564fd62d2f3a937cd464104f15c9>]
% ReportLab generated PDF document -- digest (opensource)
/Info 19 0 R
/Root 18 0 R
/Size 33
>>
startxref
33109
%%EOF

View File

@@ -0,0 +1,933 @@
# Les 10 -- Slide-overzicht
## Supabase Authenticatie & Row Level Security (15 slides)
**Cursus:** AI Developer -- NOVI Hogeschool Utrecht
**Duur:** 3 uur (180 minuten) | 09:00 - 12:00
**Project:** Poll App -- authenticatie toevoegen met Supabase Auth
> **Voorkennis studenten:** Supabase basics uit Les 8 (project setup, database, tabellen). Poll App met Next.js 16, TypeScript, Tailwind CSS. Database met `polls` en `options` tabellen. Nog geen authenticatie.
---
## Timing-overzicht
| Tijd | Duur | Onderwerp | Slide(s) | Vorm |
|---------------|--------|----------------------------------------|----------|---------------------|
| 09:00 - 09:05 | 5 min | Titelslide | 1 | Presentatie |
| 09:05 - 09:10 | 5 min | Planning vandaag | 2 | Presentatie |
| 09:10 - 09:15 | 5 min | Terugblik Les 8-9 | 3 | Presentatie |
| 09:15 - 09:25 | 10 min | Eindexamenopdracht | 4 | Presentatie |
| 09:25 - 09:30 | 5 min | Wat is authenticatie? | 5 | Presentatie |
| 09:30 - 09:40 | 10 min | Supabase Auth -- 3 methodes | 6 | Presentatie + Demo |
| 09:40 - 09:45 | 5 min | Hoe werkt een sessie? | 7 | Presentatie |
| 09:45 - 09:55 | 10 min | Auth in Next.js | 8 | Presentatie |
| 09:55 - 10:00 | 5 min | Row Level Security (RLS) | 9 | Presentatie |
| 10:00 - 10:15 | 15 min | Pauze | 10 | Pauze |
| 10:15 - 10:30 | 15 min | Hands-on: Auth opzetten in Supabase | 11 | Hands-on (ref) |
| 10:30 - 10:55 | 25 min | Hands-on: Login & registratie | 12 | Hands-on (ref) |
| 10:55 - 11:10 | 15 min | Hands-on: Sessie & beschermde routes | 13 | Hands-on (ref) |
| 11:10 - 11:25 | 15 min | Hands-on: Basis RLS | 14 | Hands-on (ref) |
| 11:45 - 12:00 | 15 min | Samenvatting & huiswerk | 15 | Presentatie |
---
## Slide-indeling
---
### Slide 1: Titelslide
**Timing:** 09:00 - 09:05 (5 min)
**Titel:** Les 10 -- Supabase Auth & RLS
**Ondertitel:** Authenticatie toevoegen aan de Poll App
```
+========================================================+
| |
| LES 10: SUPABASE AUTH & RLS |
| |
| Authenticatie toevoegen aan de Poll App |
| |
| Tim -- NOVI Hogeschool Utrecht |
| AI Developer Cursus |
| |
+========================================================+
```
**Kernpunten:**
- Les 10 van de AI Developer cursus
- Vandaag draaien we alles om beveiliging: wie mag wat?
- Supabase Auth + Row Level Security
- We bouwen verder op de Poll App uit Les 8-9
**Spreektekst:**
- "Goedemorgen allemaal, welkom bij Les 10!"
- "Vandaag gaan we onze Poll App beveiligen met echte authenticatie."
- "Na vandaag kan niet zomaar iedereen meer polls aanmaken -- je moet ingelogd zijn."
- "We gebruiken Supabase Auth, wat het hele inlogproces voor ons afhandelt."
- "En we leren over Row Level Security: beveiliging op database-niveau."
---
### Slide 2: Planning Vandaag
**Timing:** 09:05 - 09:10 (5 min)
**Titel:** Planning Vandaag
**Ondertitel:** Wat gaan we doen en leren?
```
+========================================================+
| PLANNING VANDAAG |
| |
| 09:00 Theorie: Auth & RLS concepten |
| 09:15 Eindexamenopdracht introductie |
| 09:25 Supabase Auth deep dive |
| 10:00 -- PAUZE -- |
| 10:15 Hands-on: Auth opzetten |
| 10:30 Hands-on: Login & registratie |
| 10:55 Hands-on: Sessie & beschermde routes |
| 11:10 Hands-on: Basis RLS |
| 11:45 Samenvatting & huiswerk |
| |
| LEERDOELEN: |
| [x] Supabase Auth instellen (email/password) |
| [x] Login/registratie pagina bouwen |
| [x] Sessie beheren (wie is ingelogd?) |
| [x] Row Level Security policies schrijven |
+========================================================+
```
**Kernpunten:**
- Eerste helft: theorie over authenticatie, autorisatie, sessies
- Introductie van de eindexamenopdracht
- Tweede helft: volledig hands-on, stap voor stap
- Vier concrete leerdoelen die je vandaag behaalt
**Spreektekst:**
- "Dit is de planning voor vandaag. We beginnen met een stuk theorie."
- "Daarna introduceer ik de eindexamenopdracht -- heel belangrijk."
- "Na de pauze gaan we volledig hands-on. Ik laat reference slides zien die op het scherm blijven staan terwijl jullie werken."
- "Aan het einde van vandaag heb je een werkende login, registratie, en beveiligde database."
- "Vier leerdoelen: Auth instellen, login bouwen, sessie beheren, en RLS schrijven."
---
### Slide 3: Terugblik Les 8-9
**Timing:** 09:10 - 09:15 (5 min)
**Titel:** Terugblik Les 8-9
**Ondertitel:** Waar staan we nu?
```
+========================================================+
| TERUGBLIK LES 8-9 |
| |
| +------------------+ +-------------------------+ |
| | SUPABASE | | NEXT.JS APP | |
| | | | | |
| | polls | | / (homepage) | |
| | +----------+ | | /polls (lijst) | |
| | | id | |<-->| /polls/new (aanmaken) | |
| | | question | | | /polls/[id] (stemmen) | |
| | +----------+ | | | |
| | | | | |
| | options | | TypeScript + Tailwind | |
| | +----------+ | | | |
| | | id | | +-------------------------+ |
| | | poll_id | | |
| | | text | | PROBLEEM: |
| | | votes | | Iedereen kan alles! |
| | +----------+ | Geen login nodig |
| +------------------+ Geen beveiliging |
+========================================================+
```
**Kernpunten:**
- Supabase project met `polls` en `options` tabellen
- Next.js app met pagina's voor lijst, aanmaken en stemmen
- Alles werkt, maar er is geen beveiliging
- Het probleem: iedereen kan polls aanmaken en data manipuleren
**Spreektekst:**
- "Laten we even terugkijken naar waar we staan."
- "We hebben een werkende Poll App: je kunt polls bekijken, nieuwe polls aanmaken, en stemmen."
- "De database draait op Supabase met twee tabellen: polls en options."
- "Maar... er is een groot probleem. Iedereen kan alles doen. Er is geen login."
- "Als je de Supabase URL en API key kent, kun je direct de database benaderen."
- "Vandaag gaan we dat oplossen!"
---
### Slide 4: Eindexamenopdracht
**Timing:** 09:15 - 09:25 (10 min)
**Titel:** Eindexamenopdracht
**Ondertitel:** Vrije keuze app -- jouw project!
```
+========================================================+
| EINDEXAMENOPDRACHT |
| |
| Bouw je eigen full-stack applicatie! |
| |
| VEREISTEN: |
| +----------------------------------------------------+|
| | [x] Next.js 16 + TypeScript ||
| | [x] Supabase (database + auth) ||
| | [x] Authenticatie (login/registratie) ||
| | [x] Row Level Security (RLS policies) ||
| | [x] CRUD operaties (Create, Read, Update, Delete) ||
| | [x] Deployed (Vercel + Supabase) ||
| | [x] Nette code (componenten, types, error handling)||
| +----------------------------------------------------+|
| |
| TIJDLIJN: |
| Les 10 (vandaag) Introductie + Auth leren |
| Les 11-12 Bouwen aan je project |
| Les 13 Inleveren + presentatie |
| |
| IDEEN: Todo app, Blog, Recepten, Budget tracker, |
| Quiz app, Bookmark manager, Habit tracker... |
+========================================================+
```
**Kernpunten:**
- Vrije keuze: kies zelf welke app je bouwt
- Zeven technische vereisten waar je aan moet voldoen
- Alles wat we in de cursus geleerd hebben komt samen
- Tijdlijn: 3-4 lessen om te bouwen, daarna inleveren + presentatie
- Voorbeelden ter inspiratie, maar eigen ideeen zijn welkom
**Spreektekst:**
- "Nu iets heel belangrijks: de eindexamenopdracht."
- "Jullie gaan je eigen full-stack applicatie bouwen. Vrije keuze -- dus kies iets dat je leuk vindt."
- "Er zijn zeven vereisten. Laten we ze doorlopen."
- "Next.js 16 met TypeScript -- dat kennen jullie al."
- "Supabase voor de database EN authenticatie -- dat leren we vandaag."
- "Je app moet login en registratie hebben, en de database moet beveiligd zijn met RLS."
- "CRUD: je moet data kunnen aanmaken, lezen, updaten en verwijderen."
- "De app moet gedeployed zijn op Vercel, zodat ik hem kan bekijken."
- "En nette code: goede componenten, TypeScript types, error handling."
- "Qua tijdlijn: vandaag leer je Auth. De komende lessen heb je tijd om te bouwen. En dan presenteren."
- "Begin alvast na te denken over wat je wilt bouwen. Een todo app, blog, recepten-app, budget tracker... het mag allemaal."
---
### Slide 5: Wat is Authenticatie?
**Timing:** 09:25 - 09:30 (5 min)
**Titel:** Wat is Authenticatie?
**Ondertitel:** Auth vs Autorisatie
```
+========================================================+
| WAT IS AUTHENTICATIE? |
| |
| +------------------------+ +------------------------+|
| | | | ||
| | AUTHENTICATIE | | AUTORISATIE ||
| | | | ||
| | "Wie ben je?" | | "Wat mag je?" ||
| | | | ||
| | +--------+ | | +--------+ ||
| | | SLOT | | | | SCHILD | ||
| | | [====] | | | | {X} | ||
| | +--------+ | | +--------+ ||
| | | | ||
| | - Inloggen | | - Rechten ||
| | - Email + wachtwoord | | - Rollen (admin/user) ||
| | - Identiteit bewijzen | | - Wat mag je zien? ||
| | | | ||
| +------------------------+ +------------------------+|
| |
| VOORBEELD: |
| Bioscoop: ticket tonen = auth | stoel kiezen = autor. |
| School: pasje scannen = auth | lokaal betreden = a. |
+========================================================+
```
**Kernpunten:**
- Authenticatie = wie ben je? Identiteit bewijzen.
- Autorisatie = wat mag je? Rechten en rollen.
- Twee aparte concepten die samenwerken
- Vandaag leren we beide: Auth met Supabase, Autorisatie met RLS
**Spreektekst:**
- "Voordat we gaan bouwen, moeten we twee begrippen begrijpen."
- "Authenticatie: wie ben je? Je bewijst je identiteit. Bijvoorbeeld door in te loggen met email en wachtwoord."
- "Autorisatie: wat mag je? Welke rechten heb je? Mag je alleen lezen, of ook schrijven?"
- "Denk aan een bioscoop. Je laat je ticket zien bij de ingang -- dat is authenticatie. Maar je mag alleen in zaal 3 zitten -- dat is autorisatie."
- "Of school: je scant je pasje -- authenticatie. Maar je mag niet zomaar in elk lokaal -- autorisatie."
- "Vandaag leren we beide. Supabase Auth regelt de authenticatie. Row Level Security regelt de autorisatie."
---
### Slide 6: Supabase Auth -- 3 Methodes
**Timing:** 09:30 - 09:40 (10 min)
**Titel:** Supabase Auth -- 3 Methodes
**Ondertitel:** Hoe kunnen gebruikers inloggen?
```
+========================================================+
| SUPABASE AUTH -- 3 METHODES |
| |
| +----------------+ +----------------+ +--------------+|
| | EMAIL/PASSWORD | | MAGIC LINK | | GOOGLE OAUTH ||
| | | | | | ||
| | +------------+ | | +------------+ | | +----------+||
| | | email: | | | | email: | | | | Google |||
| | | [........] | | | | [........] | | | | [G] |||
| | | password: | | | | | | | | Login |||
| | | [........] | | | | Klik link | | | +----------+||
| | | [INLOGGEN] | | | | in je mail | | | ||
| | +------------+ | | +------------+ | | ||
| | | | | | ||
| | Klassiek | | Geen wachtw. | | Social login ||
| | Makkelijk te | | Veilig | | Makkelijkst ||
| | begrijpen | | Simpel | | voor users ||
| | | | | | ||
| | WIJ GEBRUIKEN | | OPTIONEEL | | NIET VANDAAG ||
| | DIT VANDAAG | | (bonus) | | (complex) ||
| +----------------+ +----------------+ +--------------+|
+========================================================+
```
**Kernpunten:**
- Email/Password: klassieke methode, makkelijk te begrijpen, we gebruiken dit vandaag
- Magic Link: email zonder wachtwoord, gebruiker klikt link in mailbox
- Google OAuth: social login via Google account, meest gebruiksvriendelijk maar complexer
- Supabase ondersteunt alle drie out-of-the-box
- In het Supabase Dashboard kun je providers aan/uitzetten
**Spreektekst:**
- "Supabase biedt drie manieren om in te loggen. Laten we ze bekijken."
- "Nummer 1: email en wachtwoord. De klassieke manier. Je maakt een account aan met je email en een wachtwoord, en daarna log je in. Dit gaan we vandaag gebruiken."
- "Nummer 2: Magic Link. Je vult alleen je email in, en Supabase stuurt een linkje. Klik erop en je bent ingelogd. Geen wachtwoord nodig. Dit voegen we toe als bonus."
- "Nummer 3: Google OAuth. De 'Log in met Google' knop die je overal ziet. Heel handig voor gebruikers, maar de setup is complexer. Dat doen we niet vandaag."
- "Laat me even het Supabase Dashboard laten zien waar je deze providers configureert..."
- *Tim opent Supabase Dashboard > Authentication > Providers en laat de opties zien*
- "Zie je? Email staat standaard aan. Je kunt hier ook Magic Link, Google, GitHub en meer aanzetten."
---
### Slide 7: Hoe Werkt een Sessie?
**Timing:** 09:40 - 09:45 (5 min)
**Titel:** Hoe Werkt een Sessie?
**Ondertitel:** Van login tot beveiligde requests
```
+========================================================+
| HOE WERKT EEN SESSIE? |
| |
| +--------+ +----------+ +-----------+ |
| | USER |----->| SUPABASE |----->| JWT TOKEN | |
| | login | | Auth | | (sessie) | |
| +--------+ +----------+ +-----------+ |
| | | |
| | email + wachtwoord | |
| | v |
| | +---------------+ |
| | | COOKIE | |
| | | (browser) | |
| | +---------------+ |
| | | |
| v v |
| +---------------------------------------------+ |
| | ELKE REQUEST | |
| | Browser stuurt cookie automatisch mee | |
| | Middleware checkt: is de sessie geldig? | |
| | Zo ja: door naar de pagina | |
| | Zo nee: redirect naar /login | |
| +---------------------------------------------+ |
+========================================================+
```
**Kernpunten:**
- User logt in met email + wachtwoord
- Supabase Auth verifieert en stuurt een JWT token terug
- JWT wordt opgeslagen als cookie in de browser
- Bij elke request stuurt de browser de cookie automatisch mee
- Middleware controleert of de sessie geldig is
**Spreektekst:**
- "Hoe werkt een sessie eigenlijk? Laten we het stap voor stap bekijken."
- "Stap 1: de gebruiker logt in met email en wachtwoord."
- "Stap 2: Supabase Auth controleert de gegevens. Kloppen ze? Dan krijg je een JWT token terug."
- "JWT staat voor JSON Web Token. Het is een gecodeerde string die zegt: 'deze gebruiker is ingelogd en dit is hun user ID'."
- "Stap 3: dat token wordt opgeslagen als cookie in de browser."
- "Stap 4: bij elke pagina die je bezoekt, stuurt de browser die cookie automatisch mee."
- "In onze Next.js app hebben we middleware die bij elke request checkt: is er een geldige sessie? Zo nee, dan redirect hij naar /login."
- "Dit is belangrijk om te begrijpen. Je hoeft het niet zelf te bouwen -- Supabase en de @supabase/ssr package regelen het voor je."
---
### Slide 8: Auth in Next.js
**Timing:** 09:45 - 09:55 (10 min)
**Titel:** Auth in Next.js
**Ondertitel:** Architectuur en bestandsstructuur
```
+========================================================+
| AUTH IN NEXT.JS -- ARCHITECTUUR |
| |
| Package: @supabase/ssr |
| |
| +----------------------------------------------------+|
| | BESTANDEN DIE WE GAAN MAKEN: ||
| | ||
| | src/ ||
| | +-- lib/supabase/ ||
| | | +-- client.ts <-- Browser client ||
| | | +-- server.ts <-- Server client ||
| | | ||
| | +-- middleware.ts <-- Sessie refreshen ||
| | | ||
| | +-- app/ ||
| | +-- auth/ ||
| | | +-- callback/ ||
| | | +-- route.ts <-- Auth callback ||
| | +-- login/ ||
| | +-- page.tsx <-- Login pagina ||
| +----------------------------------------------------+|
| |
| BROWSER CLIENT SERVER CLIENT |
| - Gebruikt in - Gebruikt in Server |
| Client Components Components & API routes |
| - createBrowser... - createServer... |
| - Leest cookies - Leest EN schrijft cookies |
+========================================================+
```
**Kernpunten:**
- `@supabase/ssr` is de package die cookies en sessies afhandelt
- Browser client: voor Client Components (interactieve UI)
- Server client: voor Server Components en API routes (data ophalen)
- Middleware: draait bij elke request, refresht de sessie
- Auth callback route: verwerkt magic links en OAuth redirects
**Spreektekst:**
- "Laten we kijken naar de architectuur. We installeren het package @supabase/ssr."
- "We maken twee Supabase clients. Waarom twee? Omdat Next.js twee omgevingen heeft."
- "De browser client gebruik je in Client Components -- dat zijn de interactieve componenten met useState en onClick."
- "De server client gebruik je in Server Components en API routes -- dat is code die op de server draait."
- "Het verschil: de browser client kan alleen cookies lezen. De server client kan ze ook schrijven."
- "Dan hebben we middleware.ts. Die draait bij ELKE request. Zijn taak: de sessie refreshen zodat de gebruiker ingelogd blijft."
- "En de auth callback route. Die is nodig voor magic links. Als een gebruiker op een magic link klikt, komt hij terug op /auth/callback, en die route wisselt de code om voor een sessie."
- "Na de pauze gaan we al deze bestanden stap voor stap aanmaken."
---
### Slide 9: Row Level Security (RLS)
**Timing:** 09:55 - 10:00 (5 min)
**Titel:** Row Level Security (RLS)
**Ondertitel:** Beveiliging op database-niveau
```
+========================================================+
| ROW LEVEL SECURITY (RLS) |
| |
| ZONDER RLS: |
| +--------------------------------------------+ |
| | polls tabel GEEN SLOT | |
| | id | question | created_by | |
| | 1 | Beste taal? | user_abc <- leesbaar| |
| | 2 | Beste editor? | user_xyz <- leesbaar| |
| | ** Iedereen kan ALLES lezen, schrijven, | |
| | updaten en verwijderen ** | |
| +--------------------------------------------+ |
| |
| MET RLS: |
| +--------------------------------------------+ |
| | polls tabel [SLOT] | |
| | id | question | created_by | |
| | 1 | Beste taal? | user_abc <- policy! | |
| | 2 | Beste editor? | user_xyz <- policy! | |
| | | |
| | POLICIES: | |
| | SELECT: iedereen mag lezen | |
| | INSERT: alleen ingelogde users | |
| | UPDATE: alleen eigen polls | |
| | DELETE: alleen eigen polls | |
| +--------------------------------------------+ |
+========================================================+
```
**Kernpunten:**
- Zonder RLS: de API key geeft volledige toegang tot alle data
- Met RLS: elke query wordt gecheckt tegen policies
- Policies definieer je per tabel, per operatie (SELECT, INSERT, UPDATE, DELETE)
- RLS draait op database-niveau -- je kunt het niet omzeilen vanuit de frontend
- Dit is de autorisatie-laag die we eerder bespraken
**Spreektekst:**
- "Nu het laatste theoretische concept: Row Level Security, oftewel RLS."
- "Onthoud: onze Supabase API key staat in de frontend code. Iedereen kan die zien."
- "Zonder RLS kan iemand met die key ALLES doen: lezen, schrijven, verwijderen. Dat is een groot beveiligingsprobleem."
- "Met RLS zet je een slot op je tabellen. Je definieert policies: regels die zeggen wie wat mag."
- "Bijvoorbeeld: iedereen mag polls LEZEN, maar alleen ingelogde users mogen polls AANMAKEN."
- "Of: je mag alleen je EIGEN polls updaten of verwijderen."
- "Het mooie van RLS is dat het op database-niveau draait. Zelfs als iemand direct de API aanroept, worden de policies gecontroleerd."
- "Na de pauze gaan we dit ook daadwerkelijk instellen."
---
### Slide 10: Pauze
**Timing:** 10:00 - 10:15 (15 min)
**Titel:** Pauze
**Ondertitel:** 15 minuten
```
+========================================================+
| |
| |
| PAUZE |
| |
| 15 minuten |
| |
| 10:00 -- 10:15 |
| |
| |
| Tip: Denk alvast na over je eindexamenopdracht! |
| Welke app wil je bouwen? |
| |
| |
+========================================================+
```
**Kernpunten:**
- 15 minuten pauze
- Studenten kunnen alvast nadenken over hun eindexamenopdracht
- Na de pauze: hands-on, dus zorg dat je laptop klaar staat
**Spreektekst:**
- "Oké, tijd voor pauze! 15 minuten."
- "Denk alvast na over wat je wilt bouwen voor je eindexamenopdracht."
- "Na de pauze gaan we direct aan de slag. Zorg dat je Cursor open hebt en je Supabase project klaarstaat."
- "Tot zo!"
---
### Slide 11: Hands-on -- Auth Opzetten in Supabase (REFERENCE SLIDE)
**Timing:** 10:15 - 10:30 (15 min)
**Titel:** Hands-on -- Auth Opzetten
**Ondertitel:** REFERENCE SLIDE -- blijft op het scherm
```
+========================================================+
| HANDS-ON: AUTH OPZETTEN [REF] |
| |
| STAP 1: Starter project |
| $ Pak de starter zip uit en open in Cursor |
| $ npm install |
| |
| STAP 2: Environment variabelen |
| Maak .env.local: |
| NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co |
| NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci... |
| |
| STAP 3: Packages installeren |
| $ npm install @supabase/ssr @supabase/supabase-js |
| |
| STAP 4: Browser client (src/lib/supabase/client.ts) |
| import { createBrowserClient } from '@supabase/ssr' |
| export function createClient() { |
| return createBrowserClient( |
| process.env.NEXT_PUBLIC_SUPABASE_URL!, |
| process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY! |
| ) |
| } |
| |
| STAP 5: Server client (src/lib/supabase/server.ts) |
| import { createServerClient } from '@supabase/ssr' |
| import { cookies } from 'next/headers' |
| export async function createClient() { |
| const cookieStore = await cookies() |
| return createServerClient( |
| process.env.NEXT_PUBLIC_SUPABASE_URL!, |
| process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!, |
| { cookies: { |
| getAll() { return cookieStore.getAll() }, |
| setAll(cookiesToSet) { |
| cookiesToSet.forEach(({ name, value, opts })|
| => cookieStore.set(name, value, opts)) |
| }, |
| }} |
| ) |
| } |
| |
| STAP 6: Middleware (src/middleware.ts) |
| import { createServerClient } from '@supabase/ssr' |
| import { NextResponse, type NextRequest } from 'next' |
| export async function middleware(request: NextRequest) |
| // Refresh sessie bij elke request |
| // Redirect naar /login als niet ingelogd |
| |
| STAP 7: Auth callback (src/app/auth/callback/route.ts)|
| // Verwerkt magic link codes |
| // Wisselt code om voor sessie |
| |
| STAP 8: Supabase Dashboard |
| Authentication > Providers > Email aanvinken |
+========================================================+
```
**Kernpunten:**
- Stap 1-2: Project openen en environment variabelen instellen
- Stap 3: Twee packages installeren: `@supabase/ssr` en `@supabase/supabase-js`
- Stap 4: Browser client voor Client Components
- Stap 5: Server client met cookie-handling voor Server Components
- Stap 6: Middleware die sessie refresht en ongeautoriseerde users redirect
- Stap 7: Auth callback route voor magic links
- Stap 8: Email provider aanzetten in Supabase Dashboard
**Spreektekst:**
- "Oké, we gaan aan de slag! Deze slide blijft op het scherm. Volg de stappen."
- "Stap 1: pak de starter zip uit die ik gestuurd heb, en open het project in Cursor. Doe npm install."
- "Stap 2: maak een .env.local bestand. Kopieer je Supabase URL en anon key uit het dashboard."
- "Stap 3: installeer de twee packages: @supabase/ssr en @supabase/supabase-js."
- "Stap 4: maak de browser client aan. Dit is heel simpel -- je roept createBrowserClient aan met je URL en key."
- "Stap 5: de server client is iets complexer. Die heeft cookie-handling nodig. Kopieer de code van de slide."
- "Stap 6: de middleware. Die zorgt dat de sessie bij elke request ververst wordt. En hij redirect naar /login als je niet ingelogd bent."
- "Stap 7: de auth callback route. Die heb je nodig voor magic links."
- "Stap 8: ga naar je Supabase Dashboard, Authentication, Providers, en zet Email aan."
- "Neem de tijd, volg het stap voor stap. Ik loop rond om te helpen."
---
### Slide 12: Hands-on -- Login & Registratie (REFERENCE SLIDE)
**Timing:** 10:30 - 10:55 (25 min)
**Titel:** Hands-on -- Login & Registratie
**Ondertitel:** REFERENCE SLIDE -- blijft op het scherm
```
+========================================================+
| HANDS-ON: LOGIN & REGISTRATIE [REF] |
| |
| STAP 1: Maak src/app/login/page.tsx |
| 'use client' |
| import { useState } from 'react' |
| import { createClient } from '@/lib/supabase/client' |
| import { useRouter } from 'next/navigation' |
| |
| STAP 2: State |
| const [email, setEmail] = useState('') |
| const [password, setPassword] = useState('') |
| const [loading, setLoading] = useState(false) |
| const [message, setMessage] = useState('') |
| const router = useRouter() |
| const supabase = createClient() |
| |
| STAP 3: handleSignUp functie |
| async function handleSignUp() { |
| setLoading(true) |
| const { error } = await supabase.auth.signUp({ |
| email, password |
| }) |
| if (error) setMessage(error.message) |
| else setMessage('Check je email voor confirmatie!') |
| setLoading(false) |
| } |
| |
| STAP 4: handleSignIn functie |
| async function handleSignIn() { |
| setLoading(true) |
| const { error } = await |
| supabase.auth.signInWithPassword({ |
| email, password |
| }) |
| if (error) setMessage(error.message) |
| else router.push('/') |
| setLoading(false) |
| } |
| |
| STAP 5: handleMagicLink functie (bonus) |
| async function handleMagicLink() { |
| setLoading(true) |
| const { error } = await |
| supabase.auth.signInWithOtp({ email }) |
| if (error) setMessage(error.message) |
| else setMessage('Check je email voor de link!') |
| setLoading(false) |
| } |
| |
| STAP 6: Formulier JSX |
| <form> |
| <input type="email" value={email} |
| onChange={e => setEmail(e.target.value)} /> |
| <input type="password" value={password} |
| onChange={e => setPassword(e.target.value)} />|
| <button onClick={handleSignIn}>Inloggen</button> |
| <button onClick={handleSignUp}>Registreren</button> |
| <button onClick={handleMagicLink}>Magic Link</but.> |
| {message && <p>{message}</p>} |
| </form> |
| |
| STAP 7: Error handling & loading states |
| - disabled={loading} op alle buttons |
| - Loading tekst: "Even geduld..." |
| - Error message tonen in rode tekst |
| |
| STAP 8: Testen |
| - Registreer een account (check Supabase Dashboard) |
| - Log in met dat account |
| - Probeer magic link (check je email) |
+========================================================+
```
**Kernpunten:**
- Login pagina als Client Component (`'use client'`)
- State voor email, password, loading en foutmeldingen
- `signUp()`: registratie, stuurt een bevestigingsmail
- `signInWithPassword()`: inloggen met email + wachtwoord
- `signInWithOtp()`: magic link versturen (bonus)
- Formulier met drie buttons: inloggen, registreren, magic link
- Na succesvolle login: redirect naar homepage
- Testen: registreer, log in, check Supabase Dashboard
**Spreektekst:**
- "Nu gaan we de login pagina bouwen. Dit wordt een Client Component omdat we interactie nodig hebben."
- "Stap 1: maak het bestand src/app/login/page.tsx aan."
- "Stap 2: we hebben vier stukken state nodig: email, password, loading, en een message voor foutmeldingen."
- "Stap 3: de handleSignUp functie. Die roept supabase.auth.signUp aan met de email en het wachtwoord. Als het lukt, krijgt de gebruiker een bevestigingsmail."
- "Stap 4: handleSignIn. Dit is het echte inloggen. signInWithPassword. Als het lukt, redirect je naar de homepage."
- "Stap 5: de magic link als bonus. signInWithOtp -- je geeft alleen de email mee, geen wachtwoord."
- "Stap 6: het formulier. Twee input velden en drie buttons. Simpel."
- "Stap 7: vergeet de error handling niet! Disable de buttons als het laden is, en toon foutmeldingen."
- "Stap 8: testen! Registreer een account en check in het Supabase Dashboard of de user verschijnt onder Authentication > Users."
- "Dit is de meest uitgebreide stap, dus neem je tijd. Ik loop rond."
---
### Slide 13: Hands-on -- Sessie & Beschermde Routes (REFERENCE SLIDE)
**Timing:** 10:55 - 11:10 (15 min)
**Titel:** Hands-on -- Sessie & Beschermde Routes
**Ondertitel:** REFERENCE SLIDE -- blijft op het scherm
```
+========================================================+
| HANDS-ON: SESSIE & BESCHERMDE ROUTES [REF] |
| |
| STAP 1: User ophalen in layout/navbar |
| // In een Server Component: |
| import { createClient } from '@/lib/supabase/server' |
| |
| const supabase = await createClient() |
| const { data: { user } } = await |
| supabase.auth.getUser() |
| |
| STAP 2: Conditional rendering |
| {user ? ( |
| <div> |
| <span>{user.email}</span> |
| <LogoutButton /> |
| </div> |
| ) : ( |
| <a href="/login">Inloggen</a> |
| )} |
| |
| STAP 3: LogoutButton component (Client Component) |
| 'use client' |
| import { createClient } from '@/lib/supabase/client' |
| import { useRouter } from 'next/navigation' |
| |
| export function LogoutButton() { |
| const router = useRouter() |
| const supabase = createClient() |
| |
| async function handleSignOut() { |
| await supabase.auth.signOut() |
| router.push('/login') |
| } |
| |
| return ( |
| <button onClick={handleSignOut}>Uitloggen</button>|
| ) |
| } |
| |
| STAP 4: Redirect na logout naar /login |
| router.push('/login') in handleSignOut |
| |
| STAP 5: Testen |
| [x] Ga naar / zonder login -> redirect naar /login |
| [x] Log in -> je ziet je email in de navbar |
| [x] Klik uitloggen -> redirect naar /login |
| [x] Na uitloggen kun je niet bij / komen |
+========================================================+
```
**Kernpunten:**
- `getUser()` op de server om de huidige gebruiker op te halen
- Conditional rendering: toon email + logout als ingelogd, anders login-link
- LogoutButton is een Client Component (interactief)
- `signOut()` verwijdert de sessie, daarna redirect naar /login
- Middleware handelt de bescherming af: geen sessie = redirect naar /login
**Spreektekst:**
- "Nu gaan we de sessie zichtbaar maken in de UI."
- "Stap 1: in je layout of navbar haal je de user op. Let op: dit is een Server Component, dus gebruik de server client."
- "supabase.auth.getUser() geeft de huidige ingelogde user terug, of null als niemand ingelogd is."
- "Stap 2: conditional rendering. Als er een user is, toon de email en een logout button. Anders toon een link naar /login."
- "Stap 3: de LogoutButton moet een Client Component zijn, want hij heeft een onClick nodig."
- "De handleSignOut functie roept supabase.auth.signOut() aan. Dat verwijdert de sessie cookie."
- "Stap 4: na het uitloggen stuur je de gebruiker terug naar /login met router.push."
- "Stap 5: testen! Open een incognito venster en ga naar de homepage. Je zou geredirect moeten worden naar /login."
- "Log in, en je ziet je email in de navbar. Klik uitloggen, en je gaat terug naar /login."
- "Als dit allemaal werkt, heb je een werkend auth-systeem!"
---
### Slide 14: Hands-on -- Basis RLS (REFERENCE SLIDE)
**Timing:** 11:10 - 11:25 (15 min)
**Titel:** Hands-on -- Basis RLS
**Ondertitel:** REFERENCE SLIDE -- blijft op het scherm
```
+========================================================+
| HANDS-ON: BASIS RLS [REF] |
| |
| Ga naar Supabase Dashboard > SQL Editor |
| |
| STAP 1: Enable RLS op polls |
| ALTER TABLE polls ENABLE ROW LEVEL SECURITY; |
| |
| STAP 2: Enable RLS op options |
| ALTER TABLE options ENABLE ROW LEVEL SECURITY; |
| |
| STAP 3: Iedereen mag polls LEZEN |
| CREATE POLICY "Iedereen mag polls lezen" |
| ON polls FOR SELECT |
| TO public |
| USING (true); |
| |
| STAP 4: Alleen ingelogde users mogen polls AANMAKEN |
| CREATE POLICY "Ingelogde users mogen polls aanmaken" |
| ON polls FOR INSERT |
| TO authenticated |
| WITH CHECK (true); |
| |
| STAP 5: Iedereen mag options LEZEN |
| CREATE POLICY "Iedereen mag options lezen" |
| ON options FOR SELECT |
| TO public |
| USING (true); |
| |
| STAP 6: Ingelogde users mogen options AANMAKEN |
| CREATE POLICY "Ingelogde users mogen options maken" |
| ON options FOR INSERT |
| TO authenticated |
| WITH CHECK (true); |
| |
| STAP 7: Ingelogde users mogen stemmen (UPDATE) |
| CREATE POLICY "Ingelogde users mogen stemmen" |
| ON options FOR UPDATE |
| TO authenticated |
| USING (true) |
| WITH CHECK (true); |
| |
| STAP 8: Testen -- app werkt als ingelogd |
| [x] Polls laden nog steeds |
| [x] Je kunt nog steeds een poll aanmaken |
| [x] Je kunt nog steeds stemmen |
| |
| STAP 9: Testen -- zonder login geen schrijfrechten |
| [x] Polls zijn zichtbaar (SELECT = public) |
| [x] Poll aanmaken FAALT (INSERT = authenticated) |
| [x] Stemmen FAALT (UPDATE = authenticated) |
+========================================================+
```
**Kernpunten:**
- RLS moet per tabel ingeschakeld worden met `ALTER TABLE ... ENABLE ROW LEVEL SECURITY`
- Na het inschakelen van RLS is ALLES geblokkeerd totdat je policies aanmaakt
- `TO public` = iedereen (ook niet ingelogd)
- `TO authenticated` = alleen ingelogde users
- `USING (true)` = geen extra voorwaarden (alle rijen)
- `WITH CHECK (true)` = geen extra voorwaarden bij schrijven
- Altijd testen: werkt het als ingelogd? Faalt het zonder login?
**Spreektekst:**
- "De laatste stap: Row Level Security! Open de SQL Editor in je Supabase Dashboard."
- "Stap 1 en 2: enable RLS op beide tabellen. LET OP: zodra je dit doet, is alles geblokkeerd. Je app zal even niet werken totdat je policies toevoegt."
- "Stap 3: de eerste policy. Iedereen mag polls lezen. FOR SELECT, TO public, USING true. Public betekent iedereen, ook niet-ingelogde gebruikers."
- "Stap 4: alleen ingelogde users mogen polls aanmaken. FOR INSERT, TO authenticated. Authenticated betekent: je moet een geldige sessie hebben."
- "Stap 5 en 6: hetzelfde voor de options tabel. Iedereen mag lezen, alleen ingelogde users mogen aanmaken."
- "Stap 7: ingelogde users mogen stemmen. Stemmen is een UPDATE operatie -- je update het votes veld."
- "Stap 8: test als ingelogde user. Alles zou moeten werken zoals voorheen."
- "Stap 9: test zonder login. Open een incognito venster. Polls zijn zichtbaar -- want SELECT is public. Maar een poll aanmaken of stemmen? Dat faalt nu. Precies wat we willen!"
- "Gefeliciteerd! Je database is nu beveiligd."
---
### Slide 15: Samenvatting & Huiswerk
**Timing:** 11:45 - 12:00 (15 min)
**Titel:** Samenvatting & Huiswerk
**Ondertitel:** Wat hebben we geleerd?
```
+========================================================+
| SAMENVATTING |
| |
| 5 KEY TAKEAWAYS: |
| |
| 1. Authenticatie = wie ben je? |
| Autorisatie = wat mag je? |
| |
| 2. Supabase Auth regelt login/registratie |
| Email/password, magic link, of OAuth |
| |
| 3. Sessies werken via JWT tokens in cookies |
| Middleware refresht de sessie automatisch |
| |
| 4. Twee clients: browser (client) + server |
| @supabase/ssr handelt cookies af |
| |
| 5. RLS beveiligt je database met policies |
| public = iedereen | authenticated = ingelogd |
| |
| ---------------------------------------------------- |
| |
| HUISWERK: |
| [1] Bedenk je eindexamenopdracht (welke app?) |
| [2] Maak een lijstje van je tabellen + kolommen |
| [3] Bedenk welke RLS policies je nodig hebt |
| [4] Optioneel: voeg user_id kolom toe aan polls |
| en maak een policy: alleen eigen polls deleten |
| |
| VOLGENDE LES: |
| Bouwen aan je eindexamenopdracht! |
+========================================================+
```
**Kernpunten:**
- Vijf key takeaways die alles van vandaag samenvatten
- Authenticatie vs autorisatie: twee aparte concepten
- Supabase Auth: drie methodes, wij gebruikten email/password
- Sessies: JWT tokens, cookies, middleware
- Twee Supabase clients: browser en server
- RLS: policies per tabel, per operatie, public vs authenticated
- Huiswerk: eindexamenopdracht bedenken en tabellen plannen
**Spreektekst:**
- "Laten we samenvatten wat we vandaag geleerd hebben."
- "Takeaway 1: authenticatie is wie ben je, autorisatie is wat mag je. Twee aparte dingen."
- "Takeaway 2: Supabase Auth regelt de authenticatie voor ons. We gebruikten email en wachtwoord, en als bonus magic links."
- "Takeaway 3: sessies werken via JWT tokens die in cookies worden opgeslagen. De middleware refresht ze automatisch."
- "Takeaway 4: in Next.js heb je twee Supabase clients nodig. Een voor de browser en een voor de server. Het @supabase/ssr package maakt dit mogelijk."
- "Takeaway 5: RLS beveiligt je database met policies. Public is voor iedereen, authenticated is alleen voor ingelogde users."
- "Nu het huiswerk. Dit is belangrijk voor de eindexamenopdracht."
- "Nummer 1: bedenk welke app je wilt bouwen. Kies iets dat je leuk vindt en dat haalbaar is."
- "Nummer 2: maak een lijstje van de tabellen die je nodig hebt en welke kolommen ze hebben."
- "Nummer 3: bedenk welke RLS policies je nodig hebt. Wie mag wat lezen en schrijven?"
- "Nummer 4 is optioneel: voeg een user_id kolom toe aan de polls tabel, zodat je kunt bijhouden wie een poll heeft aangemaakt. Dan kun je een policy maken dat je alleen je eigen polls mag verwijderen."
- "Volgende les gaan we bouwen aan jullie eindexamenopdracht. Zorg dat je een plan hebt!"
- "Goed gedaan vandaag. Vragen? Anders zie ik jullie volgende week!"

Binary file not shown.

Binary file not shown.

Binary file not shown.