From 535f99827263396ae72298f2db48c4689c0ccf4f Mon Sep 17 00:00:00 2001 From: khushal Date: Wed, 27 Nov 2024 13:54:29 +0530 Subject: [PATCH] (20241127) Mail sending (with replies) tested :) --- .../google_converse_test_oauth_20241122.json | 0 .../google_tcaoff_test_oauth_20241125.json | 0 .../goog/user/test_user_tokens_20241125.json | 0 data/images/cat_petting.png | Bin 0 -> 37472 bytes data/pdf/sample_label.pdf | 481 +++++++++ utils_v2/goog/base.py | 6 +- utils_v2/goog/gmail/gmail.py | 936 ----------------- utils_v2/goog/gmail/gmail_client.py | 959 ++++++++++++++++++ utils_v2/goog/gmail/gmail_message.py | 322 ++++++ utils_v2/goog/gmail/gmail_v2.py | 464 --------- utils_v2/goog/models/data/api_call.py | 1 + utils_v2/oauth/services/goog.py | 2 +- 12 files changed, 1768 insertions(+), 1403 deletions(-) rename creds/{ => goog/app}/google_converse_test_oauth_20241122.json (100%) rename creds/{ => goog/app}/google_tcaoff_test_oauth_20241125.json (100%) create mode 100644 creds/goog/user/test_user_tokens_20241125.json create mode 100644 data/images/cat_petting.png create mode 100644 data/pdf/sample_label.pdf delete mode 100644 utils_v2/goog/gmail/gmail.py create mode 100644 utils_v2/goog/gmail/gmail_client.py create mode 100644 utils_v2/goog/gmail/gmail_message.py delete mode 100644 utils_v2/goog/gmail/gmail_v2.py diff --git a/creds/google_converse_test_oauth_20241122.json b/creds/goog/app/google_converse_test_oauth_20241122.json similarity index 100% rename from creds/google_converse_test_oauth_20241122.json rename to creds/goog/app/google_converse_test_oauth_20241122.json diff --git a/creds/google_tcaoff_test_oauth_20241125.json b/creds/goog/app/google_tcaoff_test_oauth_20241125.json similarity index 100% rename from creds/google_tcaoff_test_oauth_20241125.json rename to creds/goog/app/google_tcaoff_test_oauth_20241125.json diff --git a/creds/goog/user/test_user_tokens_20241125.json b/creds/goog/user/test_user_tokens_20241125.json new file mode 100644 index 0000000..e69de29 diff --git a/data/images/cat_petting.png b/data/images/cat_petting.png new file mode 100644 index 0000000000000000000000000000000000000000..88a2074aff78ada8aea623a74e019e0826b5d58c GIT binary patch literal 37472 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 +endobj +2 0 obj +<< +/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font +>> +endobj +3 0 obj +<< +/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 148 /Length 6086 /Subtype /Image + /Type /XObject /Width 246 +>> +stream +Gb!$@6#Hik#XWn<9=NZJ.W:oU9k67.!qZBh?hjK5Y=E!OPu!"m=,n8s'Whi5c20GXl_LVJ6q4l+\PsoS*QKsGbN,:Yr5t.sPbPSE]m9WiELi?EP/sR\31%bj[GuLDCmk3"P$^4iPZ"kH]Jo<:/?Y2B=qV_G#3SmPTQV=$N%L6C9(FK&N`(bcLA0j/S&KMJ<_FX3hV_Wg'@`'&RB^>o:J$#saAGRWg@3t3J$ZX[b%aLYe/OoNAV/WU4>XE>r[Gsm*'$V?=rZ=fpMUi!8QdX%N-^+tWD$,MNb?@taZh*IPp8dJ7;KefoD["o3[q*UO\p%9/sQ`Xa77C+1ARgn^N/B`V.a^jDr/63>UO*j,VnWocD<9^m5U[T>:0B7jB%?]V%g$@n'1_gMsI1?Q:+3U_7InK8^7ugK)eqWq]rL:cK;H?F7UYap6.ML+3s;OO2$*7'QqPCH3q.n>UtMUmOVk5CdgF])75,,=#Q>UgE:NoQP4Ab&VgIc\XJ9$uA^hRn?E\5(1]8S$I_@Fr\he/X(ZVngd4j;Ms%[pZDFD`H>'Z9-U.fi*7`Fe;iRWZ"o:J$#saAGRWg@3t3J$ZX[b%aLYe/OoNAV/WU4>XE>r[Gsm*'$V?=rZ=fpMUi!8QdX%N-^+tWD$,MNb?@taZh*IPp8dJ7;KefoD["o3[q*UO\p%9/sQ`Xa77C+1ARgn^N/B`V.a^jDr/63>UO*j,VnWocD<9^m5U[T>:0B7jB%?]V%g$@n'1_gMsI1?Q:+3U_7InK8^7ugK)eqWq]rL:cK;H?F7UYap6.ML+3s;OO2$*7'QqPCH3q.n>UtMUmOVk5CdgF])75,,=#Q>UgE:NoQP4Ab&VgIc\XJ9$uA^hRn?E\5(1]8S$I_@Fr\he/X(ZVngd4j;Ms%[pZDFD`H>'Z9-U.fi*7`Fe;iRWZ"o:J$#saAGRWg@3t3J$ZX[b%aLYe/OoNAV/WU4>XE>r[Gsm*'$V?=rZ=fpMUi!8QdX%N-^+tWD$,MNb?@taZh*IPp8dJ7;KefoD["o3[q*UO\p%9/sQ`Xa77C+1ARgn^N/B`V.a^jDr/63>UO*j,VnWocD<9^m5U[T>:0B7jB%?]V%g$@n'1_gMsI1?Q:+3U_7InK8^7ugK)eqWq]rL:cK;H?F7UYap6.ML+3s;OO2$*7'QqPCH3q.n>UtMUmOVk5CdgF])75,,=#Q>UgE:NoQP4Ab&VgIc\XJ9$uA^hRn?E\5(1]8S$I_@Fr\he/X(ZVngd4j;Ms%[pZDFD`H>'Z9-U.fi*7`Fe;iRWZ"o:J$#saAGRWg@3t3J$ZX[b%aLYe/OoNAV/WU4>XE>r[Gsm*'$V?=rZ=fpMUi!8QdX%N-^+tWD$,MNb?@taZh*IPp8dJ7;KefoD["o3[q*UO\p%9/sQ`Xa77C+1ARgn^N/B`V.a^jDr/63>UO*j,VnWocD<9^m5U[T>:0B7jB%?]V%g$@n'1_gMsI1?Q:+3U_7InK8^7ugK)eqWq]rL:cK;H?F7UYap6.ML+3s;OO2$*7'QqPCH3q.n>UtMUmOVk5CdgF])75,,=#Q>UgE:NoQP4Ab&VgIc\XJ9$uA^hRn?E\5(1]8S$I_@Fr\he/X(ZVngd4j;Ms%[pZDFD`H>'Z9-U.fi*7`Fe;iRWZ"o:J$#saAGRWg@3t3J$ZX[b%aLYe/OoNAV/WU4>XE>r[Gsm*'$V?=rZ=fpMUi!8QdX%N-^+tWD$,MNb?@taZh*IPp8dJ7;KefoD["o3[q*UO\p%9/sQ`Xa77C+1ARgn^N/B`V.a^jDr/63>UO*j,VnWocD<9^m5U[T>:0B7jB%?]V%g$@n'1_gMsI1?Q:+3U_7InK8^7ugK)eqWq]rL:cK;H?F7UYap6.ML+3s;OO2$*7'QqPCH3q.n>UtMUmOVk5CdgF])75,,=#Q>UgE:rWGIR+mVr~>endstream +endobj +4 0 obj +<< +/BitsPerComponent 8 /ColorSpace /DeviceRGB /Filter [ /ASCII85Decode /FlateDecode ] /Height 148 /Length 7199 /Subtype /Image + /Type /XObject /Width 324 +>> +stream +Gb!$?5u%DG%)_l?Vr\r;gXlg6Ns+.34u%b:O"n!^g%\!fiRqBl=[''PMf%5/'-1X^.T^O-45oIe+Igk.VD.HnL:/H9*o#<$V-D0pZ)UJ+;Al>:#Y>Wi^1PPW33jup`2G%BVL$&3).eR\Kk7P;,dO&'k^8Z>t.DKnn8,4q/0ENc`O>1(M2j>?Q)hBRST+6mOA5!R;jd:r6ed`_?R-J[X]:SH!unf'[QQh%;'r,[osV+=Xr[nT8UY%To,_CT40nC7"N.RRC9i4p,8]+Ca!WpjUf=MR2Klsf,=+5e:J>3R@gm3E2L^crGd^XIQ4Ifm@b^VO6qeuHj_JW3oNgE*!N.$IQ>HJ@'Y=-!L;UcpMeH&j\e*SL3VK&PBd2-E,IOc+)2itEGE;CYad)a!$DOW^.C-`/Td0o!+])o"ot4Bnj5b6KqGZ#+i8U8(CSjm$\m-X8eIAh/CXltk^d]rbD3%J7PY%iZ]l!+hX%.bX;P0>n]Z1lCNbnV;_=29CROfQ5aMkUTnVN8].@$sCNLb%]8hDTPoeK[@*M(-YqN1oX[`\.r5cdo,T@jbME&nI4&`"_>s`mAm>iti#VB5?%.q7oHP[V_($FHf@r>eP"@KW@UpCf6mm_S!o+g5^"I,/NbbXdUd_fZ;%?mI?$n1+AKh[uHqtogk0=l4[*`pD?9POc<]n(nRj0PN;lc\_+>R51*4SV/l7;YnO8]$*m-N@LD]J@q[s0nV[OfZaFPRHse08gU>-M3m+6tY22'[_UTks2Q9JG@GYK&D+?L5O^NFB<_\kjCuf'[p@q$GR?YkEgW!!uH6gQYonb-AH]4ZcaMokG%+!M)amt"B>\r.9TBI\e;Rq,.fEkW?"PKS70njn60shtSpdKenfig795-U0-D;4(a*G&+u=)T$>iTcOJS(&g_0^g`N[Nca+82*/1X!Z!p2KH'>H[MQ_9M4F3D.=qu4VD:hqSX*14iYilAE+I4L1b;PAGO#10",VX:NVgmWEd,Rm"DE0Jo">WR)6MV(tt!dr$&uHCos-W+5"ZR[dEUAN\W&KX1+(ZE:lb`:$NBjR.hFbgQ@J&,T*,T\r;gXlg6Ns+.34u%b:O"n!^g%\!fiRqBl=[''PMf%5/'-1X^.T^O-45oIe+Igk.VD.HnL:/H9*o#<$V-D0pZ)UJ+;Al>:#Y>Wi^1PPW33jup`2G%BVL$&3).eR\Kk7P;,dO&'k^8Z>t.DKnn8,4q/0ENc`O>1(M2j>?Q)hBRST+6mOA5!R;jd:r6ed`_?R-J[X]:SH!unf'[QQh%;'r,[osV+=Xr[nT8UY%To,_CT40nC7"N.RRC9i4p,8]+Ca!WpjUf=MR2Klsf,=+5e:J>3R@gm3E2L^crGd^XIQ4Ifm@b^VO6qeuHj_JW3oNgE*!N.$IQ>HJ@'Y=-!L;UcpMeH&j\e*SL3VK&PBd2-E,IOc+)2itEGE;CYad)a!$DOW^.C-`/Td0o!+])o"ot4Bnj5b6KqGZ#+i8U8(CSjm$\m-X8eIAh/CXltk^d]rbD3%J7PY%iZ]l!+hX%.bX;P0>n]Z1lCNbnV;_=29CROfQ5aMkUTnVN8].@$sCNLb%]8hDTPoeK[@*M(-YqN1oX[`\.r5cdo,T@jbME&nI4&`"_>s`mAm>iti#VB5?%.q7oHP[V_($FHf@r>eP"@KW@UpCf6mm_S!o+g5^"I,/NbbXdUd_fZ;%?mI?$n1+AKh[uHqtogk0=l4[*`pD?9POc<]n(nRj0PN;lc\_+>R51*4SV/l7;YnO8]$*m-N@LD]J@q[s0nV[OfZaFPRHse08gU>-M3m+6tY22'[_UTks2Q9JG@GYK&D+?L5O^NFB<_\kjCuf'[p@q$GR?YkEgW!!uH6gQYonb-AH]4ZcaMokG%+!M)amt"B>\r.9TBI\e;Rq,.fEkW?"PKS70njn60shtSpdKenfig795-U0-D;4(a*G&+u=)T$>iTcOJS(&g_0^g`N[Nca+82*/1X!Z!p2KH'>H[MQ_9M4F3D.=qu4VD:hqSX*14iYilAE+I4L1b;PAGO#10",VX:NVgmWEd,Rm"DE0Jo">WR)6MV(tt!dr$&uHCos-W+5"ZR[dEUAN\W&KX1+(ZE:lb`:$NBjR.hFbgQ@J&,T*,T\r;gXlg6Ns+.34u%b:O"n!^g%\!fiRqBl=[''PMf%5/'-1X^.T^O-45oIe+Igk.VD.HnL:/H9*o#<$V-D0pZ)UJ+;Al>:#Y>Wi^1PPW33jup`2G%BVL$&3).eR\Kk7P;,dO&'k^8Z>t.DKnn8,4q/0ENc`O>1(M2j>?Q)hBRST+6mOA5!R;jd:r6ed`_?R-J[X]:SH!unf'[QQh%;'r,[osV+=Xr[nT8UY%To,_CT40nC7"N.RRC9i4p,8]+Ca!WpjUf=MR2Klsf,=+5e:J>3R@gm3E2L^crGd^XIQ4Ifm@b^VO6qeuHj_JW3oNgE*!N.$IQ>HJ@'Y=-!L;UcpMeH&j\e*SL3VK&PBd2-E,IOc+)2itEGE;CYad)a!$DOW^.C-`/Td0o!+])o"ot4Bnj5b6KqGZ#+i8U8(CSjm$\m-X8eIAh/CXltk^d]rbD3%J7PY%iZ]l!+hX%.bX;P0>n]Z1lCNbnV;_=29CROfQ5aMkUTnVN8].@$sCNLb%]8hDTPoeK[@*M(-YqN1oX[`\.r5cdo,T@jbME&nI4&`"_>s`mAm>iti#VB5?%.q7oHP[V_($FHf@r>eP"@KW@UpCf6mm_S!o+g5^"I,/NbbXdUd_fZ;%?mI?$n1+AKh[uHqtogk0=l4[*`pD?9POc<]n(nRj0PN;lc\_+>R51*4SV/l7;YnO8]$*m-N@LD]J@q[s0nV[OfZaFPRHse08gU>-M3m+6tY22'[_UTks2Q9JG@GYK&D+?L5O^NFB<_\kjCuf'[p@q$GR?YkEgW!!uH6gQYonb-AH]4ZcaMokG%+!M)amt"B>\r.9TBI\e;Rq,.fEkW?"PKS70njn60shtSpdKenfig795-U0-D;4(a*G&+u=)T$>iTcOJS(&g_0^g`N[Nca+82*/1X!Z!p2KH'>H[MQ_9M4F3D.=qu4VD:hqSX*14iYilAE+I4L1b;PAGO#10",VX:NVgmWEd,Rm"DE0Jo">WR)6MV(tt!dr$&uHCos-W+5"ZR[dEUAN\W&KX1+(ZE:lb`:$NBjR.hFbgQ@J&,T*,T\r;gXlg6Ns+.34u%b:O"n!^g%\!fiRqBl=[''PMf%5/'-1X^.T^O-45oIe+Igk.VD.HnL:/H9*o#<$V-D0pZ)UJ+;Al>:#Y>Wi^1PPW33jup`2G%BVL$&3).eR\Kk7P;,dO&'k^8Z>t.DKnn8,4q/0ENc`O>1(M2j>?Q)hBRST+6mOA5!R;jd:r6ed`_?R-J[X]:SH!unf'[QQh%;'r,[osV+=Xr[nT8UY%To,_CT40nC7"N.RRC9i4p,8]+Ca!WpjUf=MR2Klsf,=+5e:J>3R@gm3E2L^crGd^XIQ4Ifm@b^VO6qeuHj_JW3oNgE*!N.$IQ>HJ@'Y=-!L;UcpMeH&j\e*SL3VK&PBd2-E,IOc+)2itEGE;CYad)a!$DOW^.C-`/Td0o!+])o"ot4Bnj5b6KqGZ#+i8U8(CSjm$\m-X8eIAh/CXltk^d]rbD3%J7PY%iZ]l!+hX%.bX;P0>n]Z1lCNbnV;_=29CROfQ5aMkUTnVN8].@$sCNLb%]8hDTPoeK[@*M(-YqN1oX[`\.r5cdo,T@jbME&nI4&`"_>s`mAm>iti#VB5?%.q7oHP[V_($FHf@r>eP"@KW@UpCf6mm_S!o+g5^"I,/NbbXdUd_fZ;%?mI?$n1+AKh[uHqtogk0=l4[*`pD?9POc<]n(nRj0PN;lc\_+>R51*4SV/l7;YnO8]$*m-N@LD]J@q[s0nV[OfZaFPRHse08gU>-M3m+6tY22'[_UTks2Q9JG@GYK&D+?L5O^NFB<_\kjCuf'[p@q$GR?YkEgW!!uH6gQYonb-AH]4ZcaMokG%+!M)amt"B>\r.9TBI\e;Rq,.fEkW?"PKS70njn60shtSpdKenfig795-U0-D;4(a*G&+u=)T$>iTcOJS(&g_0^g`N[Nca+82*/1X!Z!p2KH'>H[MQ_9M4F3D.=qu4VD:hqSX*14iYilAE+I4L1b;PAGO#10",VX:NVgmWEd,Rm"DE0Jo">WR)6MV(tt!dr$&uHCos-W+5"ZR[dEUAN\W&KX1+(ZE:lb`:$NBjR.hFbgQ@J&,T*,T\r;gXlg6Ns+.34u%b:O"n!^g%\!fiRqBl=[''PMf%5/'-1X^.T^O-45oIe+Igk.VD.HnL:/H9*o#<$V-D0pZ)UJ+;Al>:#Y>Wi^1PPW33jup`2G%BVL$&3).eR\Kk7P;,dO&'k^8Z>t.DKnn8,4q/0ENc`O>1(M2j>?Q)hBRST+6mOA5!R;jd:r6ed`_?R-J[X]:SH!unf'[QQh%;'r,[osV+=Xr[nT8UY%To,_CT40nC7"N.RRC9i4p,8]+Ca!WpjUf=MR2Klsf,=+5e:J>3R@gm3E2L^crGd^XIQ4Ifm@b^VO6qeuHj_JW3oNgE*!N.$IQ>HJ@'Y=-!L;UcpMeH&j\e*SL3VK&PBd2-E,IOc+)2itEGE;CYad)a!$DOW^.C-`/Td0o!+])o"ot4Bnj5b6KqGZ#+i8U8(CSjm$\m-X8eIAh/CXltk^d]rbD3%J7PY%iZ]l!+hX%.bX;P0>n]Z1lCNbnV;_=29CROfQ5aMkUTnVN8].@$sCNLb%]8hDTPoeK[@*M(-YqN1oX[`\.r5cdo,T@jbME&nI4&`"_>s`mAm>iti#VB5?%.q7oHP[V^LL?_[20;u~>endstream +endobj +5 0 obj +<< +/Contents 25 0 R /MediaBox [ 0 0 300.4724 413.8583 ] /Parent 24 0 R /Resources << +/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ] /XObject << +/FormXob.3380198a8f991da010c93d0d1ea12014 4 0 R /FormXob.49022c30e1beb1617bd3612f012d5ce0 3 0 R +>> +>> /Rotate 0 /Trans << + +>> + /Type /Page +>> +endobj +6 0 obj +<< +/Filter [ /FlateDecode ] /Length 683 +>> +stream +xœuÕÛjQÆñ{Ÿb.[JÑ=딀944=Ðô̸“ +É(SÈÛw}~¡Ý”VÐõg6þÀ‹5¿¸¾¼·‡nþuÚ 7õÐÝmÇÍTŸvÏÓP»Ûz¿g¥ï6Ûáðzuü×ûÙ<ß¼<êãõx·›-—Ýü[Þ|:L/Ý›³ãëÝÇúð³¶Ãúýùîaóv6ÿ2mê´ïÿÿÄÍó~ÿPëxè³ÕªÛÔ»ü©Oëýçõcíæÿ<öç¡ï/ûÚõÇëBñ°ÛÔ§ýz¨Óz¼¯³åb±ê–qµšÕqó×½ÒŸðÌíÝðc=½>»È×*»d÷‹óStß|/MkÓÖ´7MŸ4}ÚôYÓçM_4}Ùô‡¦¯þtiü¥4ÝøKã/¿4þÒøKã/¿4þÒøKã/¿4þÒøKãïéïMŽlúsdÓŸ#›þÙôçȦ?G6ý9²éÏ‘Mÿ·§?G6ý9²éÏ‘MŽlúsdÓŸc¶ú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_á7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßàwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúþ ÿuC¼nì +ì¼ß{hxž¦\QÇÅx\> +stream +xœÄ½ |Eö8^U}÷™#s昙L’É=¹“„ !!á÷‘ "¹I#‡(Šrzà®È!»Þ‚¨kÅêºlPTE]ñˆ×fE Óù½ê™@ð«~ýü?ûùþÓT÷ëêêªWï½zõÞ«êa„-G 1|´?×x[Ú@È9iò”9 MÒ+ò*„p $ë”–…îkû§ÎDˆŒAˆY=­éÚ9;k&@ˆƒòš×Î^<í‘‹÷1"TÝ5½±aª|q +”ŸÐõN‡ i¥0î·Ã}âô9 =•ê²Áý!¨õìySÖ>¾øS„&Býè•9 ‹šÄ÷É Õǽ{nÜÆYo-Ú ÷€vhÓ¼ »YԈЌÕôyÓüƦçF¾î¡~æ]İ?ÂÛෙ˃âÃWæšFPï¿Oé]Õsß´xþ¸ˆÝÛx¤<‚J…¿áÜß?¨Å–sûikˆVV_Ð"Ë*´rˆšÿÿõ` 8óH@"’Œ4P»éQ2 #2!3ŠFdE6dGäD1(Å¡xäœ<(yQ"JBÉȇRP*JCé(e¢,äGÙ(å¢<” +P!*BÅ(€ú ¾¨•¢~¨ QTŽ  +T‰¢*T¡ÁhŠjÐ04@#Ñ(4AcÑ84Õ¢:4]…&¢zt5š„&£JîederQ[¸¡îã>¢Wet÷wÜ$w‡º;˜| `M'/âhô4ôøyt#ôþ´KМ‹>Äq8 }€ôúôvzΕè,þ ¨ó%N2…èôWtwj‚^”Á3(TŒ¾ì^Úýj÷yèÓZÔŽlÆqÝ{€«àØ‚¶b-¹¦û âPt=ðíô:Þ½³û+¨¿ÆFìgûv Üä '€Ö èyìÁ^œ†¯ê> ùvÀq"ÚÑ]ÓÝï}¥ü@§¥ÐÚgØ…“q:Þ‚?a:º—wß }‹…gcÑ8æ ›Ñ&´=¥–º†å,PPz +ºBgÑ ©¸/"ï1_1ß³}Ù-Ýí€ÇXho2º3@•D<OÅMø)ü,þ'þ‰‘&À¼Ç6±ncÑjô zDï¢Ñר]@!ÌNýðp¼ÿÞûÉ#õd¹'ß19Ì'¬À®ãnãöu³Ýïu_œãA~ú‚$Œ^7Â1 ÍEס›Ð­X@Ñ3蟀íItËØ€ý8Wá1ø*< /FwãGð^|ŸÂgð—€™¸ˆ—øI ´w YCž";ÉÒÁ™…Ì2æeææ'ÖÂÖ³/Ãq’Ëäò±üa¤rr²;³{}÷à‹ŽDéLÔ³@Å9èVàä ÙVôzý íD;»/âjGo^Ÿ¡ïÐ9àX,œ‹‹ñ<0œçà›ð&ÀpÞ XîÃûÐ1| _„CA"‘Lri ‹áØ‚6‘wUúh“Âd2C˜ÑÝ?0O1Ï0?²Iì¶™]Ê®e7±÷s±\)7ž›À5q¸ÝÜÜûÜw\'ǯâáŸåßD!_Ø$(8pqã$ô,z ¤î^¦ îÑ|+pu:ÒÛ ‹èc’*¦¶ŽY[YãñÔef´âS¼×´"oykTzäuúžŠŽª…¶33fPüÑ:íTïÔumAtÍd +5L¬meêZÉdÚ†1½Õæ­hµ-9m¿|ÛUÞÞëa+IØÐ¸v f]uøv2½k¸vCµä¶ºÚV|[] ÷p/½•4gòLw«ä-÷N_;s2ШÝé :+½“+êZѨڎ C½ÉÌØc¿±¯ˆ²'³fzíë±ß¾~±"œÿÎ˵\û§p2ê]0mÉ;ÐluOqÓz½€k1=5£µSŠ¡üÕaèå Àg@+Qb’Z¹¤A ­ËGGÐh˜^AnfÅNÉá¤}˜\^å'¯5ôf ¼Áë^ûœõv|seNC$‡O2üQòÿ’Áó¸E% mÎîNÙ×R¹÷Ú+{eÀ=dVd¶¡´Œ!mHQû ÆwÖµáîÛÚPEܘ`˜IWÃãt*p3* 9¸ÉÈ€Œ4@Ðê@¨g • ÷Z÷ÚAS׺º§ƒH±Iê4®­óÁF×YИZOk°.æØXW×êÉ¢õ°j=kë †™‘fª5@!(äϽJQ;²¶uyELk°¢ˆúòˆÚÖ—OuuP*û¦p]6ÃÁ9pÎN 7\Ëh¨ª¨[»6|çõ´¾¼vmÌZ:ÒÂ÷mý2#ÉhCj@À6¼|„úh¹×£’ØãõZu”¦y À=Ô†òŸÂ½)\ب.ú/Q¸øP8ð‡(Üç×)ÜpîC)\òGáÒ+(Üï÷)\Ö›ÂAÀ¶L¥pÿÿ…Ëÿ…ü! +Wü:…+ç +Jáÿw®º‚ÂÕ¿OáA½)<°¤RxȉÂCÿ…kþ…‡ý:…‡ÎÃ(…GüßQxäõûÝ›ÂcÛÑ*…Çþ—(<îPxü¢pí¯S¸p®¥žp‰ÂÁ˜VÔ›ÂËAPô_'ùUW|â¾7ɯôëU’Oú/‘|ò!yÃ"ù5¿Nò)€ó5”äSÿ$yc/’#ðζ€—\ +>2>V¿ ‡ããÀg…8ÉÇ0Ä)ñBFQÚá™]bOOÖYR*fø©¤Æ*Ae%¡šr²óŒ£Òöá¶®ÃÜþ ýÚØQÿ†Ôè„aÖÏ_88Ž`nõï¯ÎŠ&¥ïEF$õ Y m(ùH2Â5®2\³Ždç˜û¼Ü~¤ÈÓyò³ˆ×ÓËóXõlŽ7ž±y¯ž°ÅƒGÈ©™©rúˆê`ŒâÑúÌV;®r¤ø-ÊKb|b’Ë‚Ö[VÃ<"É"ÆüÒ[ŒC§/î‡7)g”X¦?&Ñ™éqUî¤$]‚Ë¢MÏ-HÁ ¹}søw,ÿ戙’äЛ#ÉmˆÒï389¹Á#–Ѐ`ábë„IÖØlN±IŠE ˰¸ 9dM“çæ0kNËü7øí†Îÿ «l¬8ƒjÊBß–9Ùf‘ñ2pö|†#7Œpšò>÷¢²64‚´vWNB›Û˜&/Â3[„šÈ߆XHçÏÎÁP =˜<ÿ³Y3³ŸÍäö‡î' 4©xÃÛÌm„:\øà7²NŒ’ ’M¶k’3 ´ƒ¥ÁÚZ4A7ÁP]g¯s̰Ïp,ŽÚ½9þIù)Íö¨m†‡ì9öÉû4{¢vÛw;^ÓGD}àüJ÷UÔÑ_Äž:›.aI#™íØf°›SõÉöÔøñŽ ÑEk×âµNb²X­FVp¹DÄZz,˜z"˜b5 k‰Õp¬%NæS8‡Æ8Y+c5:ÑèÐD£=Ê,˜ìQѬÅesYíQN—Õ¡qYc5ñ.kœlµ˜Då.‰çâÙ8FNÖ¡%L «‰mÃõ¦¸8Ù`޶±ö¨(»fYL‡>.ÖaÒkdÑèÒË,´Ù†{pÚcœZ¡‘Û±qŒ]ö‡w¹Ü×VÙÓ %†ÊÊTf+é,Qb_ÊJ°Ñd ¬ÊJ_f8 ØJVeÙ)d+1¨ÿÔ‡Q¿ø[e()¡)'Ïo®Çf/ãÉ3{‹òÌyŒš¯š¼f5‘)#¦Ìycø¡ÌCsÎylæÁ™¯e¾6îfœõä¼AŠq¢r'nÇVæÐ´]9±]iÂëiB ÅÝfÖÏç#P)º!8 Œ-ㆳùEš'ÈÓÌÓìÓœ´6ss&)ˆ3ˆ¬=;_JOáì‡Pl©É¬K+ÈgL‹5HœÉ°eûÙ@™¶ ç>ç±Ûʪú 3´´Û߯9|44ÌpâðÑÃFSÀo+ùØꣽý㣧ÊÚ?no7Ú@þqs}RaQaA¾/ÙÇè±%Úfµ™½ɾd³Ç +°Ñ—… ò¡yšå‡>£•^ Ó‡'–õõŽ™4~L™wPCÆ'¬×;|óGþý/¥EUã ¦Mz¸þq^9/Z“§~;jÕžæûöÉάæq¹q.r'©«“c»øÐAkp¶Ü˜> ?a/~õŽúMEU1Fñ¶Uº³¾¯K­”£Êfü½kþ@-¨Päï>ÎÎí@dC^äGy˜gžäŽh>Ò~d8j:j=é<âþ(ñ£”÷ÒÞË‚5_ÅÔ²µüUÂi¼|•½ÖQsUì˜øñ®ZϘC® L…½"¡Â;!c˜1ö1 c¼Ú“äîˆøóHÜIï‡éÂUè*ÉÉÍmÃ;‚µ¦¼¼ìÜ<"æd{ã2ÜηÜîäØÜ]__^ /üð¾-ÇoÙrœœ ç”׿Goi +ulêúà>f}ÏîxøIhfämzs߇Ƿ°£/dSùž×}‚Û +z:å ¾ø/ý}ƒ®‚4yеZ é?Œì W[P2ÌZ<ðSw~x« R*BëÃ÷B™×Õ²Fô +Àg!ÿ<$-ÔZ„’àI2”\‡òÐ&H<´ä„|'Ì€rNQ¢Ñód8×®9¯EiïDÑȬ–·£|xšŒ2!Ço:!% ÔV µÆÀ9®ô £¾[¬Þ1ðV”úÎGÈW7à‡à]òs!Gµ§±È£Þoæ¢4lP£ù¥PãÀûÀi.´å Ñyì*­GQx …:À¨ u:;;PYGYY‡¡Ã€‘¬j5S ´ DÅÃ0zd…« éíé%é èè9½Dý¨¹ÞTX†ÕQNe"šÌ0éçñ0¶±Ço)@0îU5’$ðBE©ƒ¾˜wë½®àÀžüËá¥×¿èÃ!¾»k•Ǧ ÎßðiÞk*)qæ–”&{rÿr}ýÀe>åÇY•D~©Þ\}ïÈŸÛ³þ–‡*%IÅÊ55õÊKË*=}±ø iψœWX–Umq è:º¤ +V5»?µm¦0 x¡:gmäq03 /¾‡xËö¬_&Wg¨3<Ý—Õt@gazÆ sŸÊ OÍa;©N™BîæŽ_êé̾² L£þ1À ¬%d@D…Bi¤H+!Ý é1H»!½IWߟCïp©;€} ûÀ\X”å-³ÕæJŒ†7‡o:VzcŽ».ÿÖw«*‡­c‡µmú"ôX»ò¦Ò½éÛ†Ú¿á"œ‰MO àY£â™´›Œ’Ù}6éD³ÄÌÕ]Ñ–÷<å{ð“TP:;CFÊýžù± 4‘Íd40|ö™Œ ìý0ö× ¿nݰʪwoͯsçÜXzŒãÛ”•o•w•×þVÛðí&Œqnûc¡/š }?“DNpo =ú0¸fšÅÍâgé— %Ü~‰þfé6ùfͽò£òù5ùCþC½±J#ƒe‹ü&½^‡ô²F–4~“V«Óhe0Ö$¿IQâXŽgý&Aày½À!?H ¢VÒè^§ÕÀ½^ŽåYÏÊòv2KÖ³°„Õã(USmÿ¸¾¹4¦Lh0heù1e% úfaPˆ0(ì⯬ªBa˜m0ÃÙ›à|E¾«ß~êmÿ{ë–¯»kùíïqñ?üP±¡üàU/¼pÕÁrUvMw+ÛFuŸ`œ€xŒe†—e°†¿•ù6äÐÎ<‡@Á8é‘Ç2˜©Y(Xð=Ç ¼ x‹2M9·bN….*SñÖ°¬¶(â8 éPß  }+‹¬®™Kaå(hO’™ |bú¨&ÏM—ü†ŽÀ%)èèZÀ0°ÁèöBc0ÐõØÛ2n$ÿÎOÌ)¸+¦ÃÞÔæ¯RqOaŸ¾”çøY2‡Ðqæ šPƒÜIȆ!öž‡?}Ø©zTíïPíhŸô í'û•¡Ðr@øiÀthÐŒS™ŽQj–³Ü%üjB½F'­`9ö+oS\ío7J¤ûê¨ fp€\Zð*¼‘lGÏ“ƒä>‡5˜zÃ@IÌ`ÄF,©Ø‹ç N}æ{hÊ1ì”á';ˆEYI Oœ‘y³^ßèýókî» F¤ÚêÁîl +÷¬j[\¬³aŸp,Š)ÖE™‹-CtQæá–M–çÍ{-¯˜_·èlh4ß‚Zx–çã_bÄ #A£Ž[¡×¬Ðo3DgG“¦èåÑ룈n>ý}´í¨²«VÚÑúæS5 Å©62 j~ÎG¦¼\SNÛF#—xÜ /LŒÕ©C€RYça@©Þ\6 ¨ÏyçªÂq…IfM‡r‚9»Ÿ×š¾þ>ó…qÌYh'cÂÃ=³Öê`ƒÙ!vž‰aãØjŸ†'³×ð×:7â d“ó1¬Aƒ#ßQËÆ:`LÇGÉA3ÿ GË2za—u ý”¨\Û ÜäYîYïyÀÓê9âùÞ#x¼U —)Ø ’nèì0ÒÑ*ëø˜N‰õ9Ùõͨ¹÷ðÜ%xöä²Ôx‚LðX<e¥ŸèS7mÒ-þNùZ(™½g°arÙúù³†ÇÅ]®­7ßýÐ¥“š'.i(^²gþ‡Ýï<¸lô´‘C+2/†Çf!È íw6jÙ-¹ñ¦œÝ†Å`I†->)IóÓ<íI-Ñj3ÌÁxŽ fè’’Ã<°"U{»uŠí4%u›!;;›<Ýš}$ûûl6;·*§—|t†Î:Žv€ÖPå®õ¡@)h½Ã*4õ¸ƒåNí;ÐíÞ‚žîò6ÚÛ¢~8/Üa!—ZíÄë† ‹Í_3fÙÂò;×Mj¨mœD”ŸXwHñ–¦#¨{hv¾oМî Ê¡Ee~q|`Æ‚ÙweÇ"޴壧/Ÿ5»alu^á±ç–×Eh|ºMùòµYOÁØ)þû¹ÁâÑ¡»‚•zmµ¶Zw—ö„–siq­°DX#l¶ §¨[¡{_Çu˜å£•t25:™9B÷s¥V`eÝ9ĵá¡A‰ÑêNËì’÷á>@o ?¾‹aUiTs´³äT¨ô*£Z<{QìàÛ]21U{žì1æyŒ˜õ?¢| úÊ‚ƒ(•Ê\¬¼Š‹Ï3M]-d~èN•§Ç§ÁŠ»:hÕGE=h2ó¥ßo–‚6[œéÁ(Ö݆ÇL0Ng,6›tˆ_áŒú'š§/vns'Ty Ã(OÕœ +©fZ p +¸f_(ÐÙŽ/©¡x¬²., IfIø¦2 yÀ¬eœc0•s“`¼NÖêæeÜÀÍ‹±œÒ΋ÙfHÈN M ËÖ'<Кp$áû!!«*3Bÿúæa§jB§ 0 ø½ì€ù×p˜êYT¬—ûhÁTLig©hš""iÌȪՆ¯¾±aÒœ& *ƒïŽÉª_××­-¸}Â?ÎýØ­|{K£ÞQÝïµÛ_ÿ> +»ç®ù7­Êè7™ïM«Ø:n{Yå¡7”×OïÂ1Mß³tÆò·ž^æƒ\/õ¨_0ÑJ,Ì9 ÷u¬f¿BxE·m7€$G´Xk¨Šê¥ZÂ}* Ô ƒ'O,“ÙTä1{Øâਗ਼Òk”tÿþËÌP&Ë"¶­LyñÉUÊ’ex%~s×bêQYJý Q½Õk‚Öé.ìÔëÅädwF0f ·Îi›’Ú†'íæVÄéSü­šqÛ Þl/yÀÛê=âýÞËzsª²/ã½g §µp8Õhâ^äæ-‰…E½íûxpó‘jÕ÷*ƒ¯žwÍ5óš'OnV>˜7kFÙ·~ømÙŒY³•þýï ¸¼aÜøI“ÆkÀ}ZZfÍ[°`Þµ¯ä|¸ê¯'Oþµêá’’W–<¯tcü<É›:uø¸††qt-í~ŸÍävƒ·“†& ã½G0-Mö §7e]¼Þrʽ‚×ÏÓÝà›Ço7ÄfÇ’å±ëcˆm=û},›Q•Þ[ vÔB§MTÃP;Ke,'Û„òÜf«Ñ :T5¸ùæ›ÃöÂY8¯Æóv‚±Ó†-A —"È=nbi8÷R4R çö>?ELzœUÍH¬My_)3êV%±jÝ&4üy!ÊE" x4)û­ÎÔ,ÉÑÔ¶â%½8AÓdB’Ã}¹1híŒÂöž; ‹êÕ«íÒùá²9¨¢Ð˜âT›0o},E¥+9npV-µ +ÿ\(Qç;[÷'ì3ìÕà%M æ3,CØÇñ`€±$Á„éf6Ž% fyL³}<Ëìã4Ø)"‡ îðÐX†3Tf¯ ¡°¥n´•˜=æ:Kw¢ª ÍØ(a#¶±[ºžg]œFþŠ_V¾TŽ™¾Â/S Bϰ·2ëTdíLx°ëW§D€þž™a›ÕðS}M‰¡ùCŸ„€ ÐwšØ[/`û^<À¬ã[P2éùŠ~Î +ªyük]åXè'áEj„B÷!ÂìÛÆ)’ßï,xå¶_ë-ª—ÂýeŸ¹8ܵ›Ý‚ÿª±§áTlSúA—ªñä·¡¿^4.˜æ°tú(Þ¥ÚÚÞ•®D›£Í`w2Œìí’I s½ŽÄ¤6³ËsSÄAV£ Fu(üÔ¶Í:£FÌ“™…¨­D#ž~¸ _².,|–šëÊýûZžüNïŸ<»ªY‹•ùüÙƒ­)u- ”“0Nrúë‡~pô–ºÂ1E™%É#¿yL Æ]T>tÙ–Ñê:Ø}L0q?€~ŽÎÇ'¥¤WKÒÇÏ”¥¯ÉÁáµÚú§™‹¤bÛ`Cµ­:P—6ºdFú¢àÊ’µÁMQ÷ÚîMØP²%¸×`I±áܼܼÊLËß·ò¦~¸_ߤfb5ö%mØü¬Øwxle̽)gö-Ô ©¶X5¶Ü˜¼rÌYmv[µÝæ‰áÜú}Ÿ&öô-¿)§öíã1² 'îòX!^óÇÍàLø;üpþ8kÕÇŒ)j ¨î7P³æŽÎ®Òv;˜¦Íª @½ÃkáÈK=Ë5.g*@Éù`õÛ¬¶¢<5«êfL“n7lVhµ2lãY¯›I6ÀˆuÛ¬FªÈi8OÕwìÃÁÂé÷(µFýàO»fôɈJ|qy”.%cÜSßܳGyòͽÇÿ­/=:a²}ÐÊs;•†S/~ó3^û¾u\ù晉S0Nö½žùGµZ™}nT†ä™ã >Û‹Í‹†yA9¯œxbãÀ¤ +cÓܘ¼“põ©ý›òéçʾéE‚Q®N¯AH‰!n;·¸L÷´žΚN°K‘‹ù"©šŸ./’W³«ù-Ìv¿ƒy”Ýηá6ùUüªüólÁÏ$Jœd,p$Z–“LpÍqI`(ALƒ9–È›<8ÂØ‘ 52 Æ6½Sb€ñÑ»e‡¶ñºùöôpÆ/C‡ªí~ºŒPSVRB +&$§ÚfCFÖ¶²/Ç´²íuáUšÁ@Ó^ްèª^9ŽbƒÈ0p`âÇ-mOà‰DVvN +}6My‰ì%™¤¼ÐªY5‚õ Ц E£Tðs3g· ÛLÌõÖUV+§aìCi)D“æc \¡}¸¡ÈåLGš$Ÿ#-ýŽÖ(p³#þt‰:ž;;Tá+ ©vf1£'âP(ðG‘>5UÿÃÇñ̆Å#*g)/Pxͤ‚Éx`sEEòàæåieUÿhM%‡ØýʾAõ×zl¡ƒÊõÎìÕ Òí˜)Ø|õŠU£²’SwÞ´bz¥¿0…n˜&hb÷1n)øñt§òÂ`êxùᑹŠÔÅÔÆMc¯Çk¸Ç£w²Ï˯°5ÇÉGÑÛOÆül7ØÚ°&èuŠ¢SÛßÅ0¦þNÉe-²‰E®xÁé‰*Šw¸=›=Oë¥ÊŒp’T©„Ú†ŽpçMáÁ¢®\ôŒ8º¬É#5;ñÄ·žåºðÉI‚r(Þ?æÑíûÿõ¡±~ÎIQÀ®QöïÞMÖ³ãßÞݹfíÌÂÉÊ?ÿ|nf`þÊ;‡ãFÆ }Ü +|\ªòцFs¯7aAô >m­i¦i){;³–]kÚÄlb7™žbt$Í"¥*òE§'YvGvïòŒ×¡|Djx÷2ÿÂj·:b5YÀÜIÅ*·bóßñ΋WÝ7¹¦¸åegè6²”ÝßÕïXËßý Äç­žÛ*Ç)êþuŒ\ ÀºˆY¾&7 IoC¼¡ á#h¯º}<Ð@yz¥;Ó‡¤gçà˱*ûIW'9Êg²/>ÌØ•ƒÝH¹M9GÁ”ì3ÜË4>´ i,+1iˆH"ß‚FL’²¦ ÇB—Ÿè-»§¨MÅö²Udôle-¡8²*´Xy“{Y )Ou£Ð½t§s÷‡ÜÓÜYuçûmÁ!¯Š‰œç=l*IñÌCìu–MžWûã~–$³lJ8êÒ§EE™Øþ^cåþ6Ék+^Ç$ TäIx2ÊàLŠbÔIò¦]ž§÷’¬Ã [4¸è¯[•°°ˆ…@«› +Â¥°€ j|ÜSà1zÕ:•2Uc#f—zW­ßyúç¿Þ÷ŠMy‚L;䪫Z²Sùhß?ÀØÇ:B‹˜Ÿ6–x”+?*ßÿk×Ý?u}Ù6#}ȇð5xÚ(Ÿ¿‡ ÇzöhPAÔÃp„hD‘“§Žh’C«{Ù3jqo"«»ÊJT*çõ +?nÁ9$ˆs•7C/sûCo’Ü ýÈŸBsÕùùVhl7wR•„ì ‘%‹,Z–EIØÁñ{ñäÁÏô4;¡Ê@3RAõáÝÊ›8w3·?ŽâÙ}‚ùð6£Ü`´Ù%¶”$iœ\hrD[Úð‚]žëz³@ ‘ÉÔ–°‘_@íV§Á±<‚0wŽ<Ëþs•Ï”ÏÚ‰?á‰uC3g±ÂEå…¹{q&fÂ4£:w·J³'ƒ×!¸–_̬…ùç<Ï9˜#±3El!WÍT±U\³ŽÁÚEA" Ia˜¡&fQ )¢$Àô09‰—Dް2Ø‚Dx‘òK*ù7{FÍï!¿c˜á D–Й&²jà 5Ô2jÑC»ÀÁ9~ñGnÿÅ*åœJ³ñT›ÐËÁõDQâŒVÑ!¥"Ÿ˜.%ÓLEBX"›f¢Fãbtq ZiÜ‚î5nG¢sâÏR,'Ê’U´K¬`r +NÙf‚¡kô›J…2¹Ì´Ä´GÚm:hÒG Q2‘£LFIDœ^ ŒI½½ÈˆÔ×!,ã#¦(Þå0SÙ¦áu ®áÄ {¨Äqu(‘Ã4¦v¶1 ÆøÁîR•X~aP2Új¡ÝÅì¼OùŒ€Kñžò5Q>Ã/c-ÝPÜN¿/íb:û^Ú}é]1@ŽÅt,-¸ +î€úÎø _$ã !¼€…4ð˜#2Ȁȋ²Œy‘ø8§æÉ¡ÑþHcB~u0R»ƒº†UËÚÕ««˜Á¿x‚]Ê¡Ðc€ã5€ÅE–»Ðµ]ü€ÙóëW0¿jÔ/‚ú}V­†Ã¹ÑÉqýcmŒ†V,)Š5Ç8ãÅ"³#.þ¤çë_Ì›‘Y“¶h*È'ê5'Z×ßÇD÷wIŽ'å¢tg¦¡ÈëÈÈüñ;v5|c´©îAX+ÐÔ³L…‹»áÅ\ºµÅpyWþÖ'‚9ã+ +/Ñu²YóØt6áÊ XÈLȉIÛpÿ¯ÞúÆ?Ÿ?¾µñr Û7tǃ;Gö²Vùô…S_ýÇâøýŸžÐ ¦;»³ºpälÊÕ.˜{ß^1×ÞvÓ˜û·oωö<ù¾ßóÖã»ÞRnÇB(›¿2JCµÁ47ÃÂùÌÉ`ÈÆ¡´Tâ‹ãÜ fÞ–ÀÙbƜȗ”âHÏhÃñ¿äö©öP»‘.\Ó½HÔ4¼iå’ ë-´Ú¨õJmØ8·Y¨‘çÇY8,ø®Ÿž?±.wêGÛúdÏ\2m¬¨ÍPžÒóZªSV+û•wÉ»`Í.´§Ý°2ËXQ¼züŒ7ÒR7Þ7¥11“”߯ÿš;®½¤z0c»szúUÝÃÁ™b”à’G”ÍcKž¦mÔÍH8©I5¤ZRœÉ¾>–bçËë––w2¾6m=o¾`=Ÿ¥GFM‚Ý•d“ôÖžu4Ý~4¶¿?šaû§K~û½~£m¸xoŠ3ÇUh +³Ù9*}.»aÉé¼KªyL-d¼JÙ‚+¥¸ X§tRY«œ%ß‘w> +„8ü¯¼@ÃrÕ‘жàÐ=h7øÕ$•LsÈnšxø8yœ{V< ~.^õq(i‘ØÕ V*gH0‹@ÈQ…ƒúêç$‘$  Ô®¦JMÖl¾¬Ôè¸îŒlΠ>%(7ü¾´r©öî€ë}¶`Á€UƒÖ0¶™Ó¸^1+‡‚gá\ÌôÐû$Ùº‘Ü¢ÎÇtÝëi5.!£æ`…OÅÉ|1.â‡àüU¸–›Žq«¹MX·¯ä æh×@¸8œ&3„Gi’(óX¿Rpj™ñ¬Ø6¼<³ˆëp +èQ˜x@Öü‡nLWñ_µì€â4S[ÛBOàPœ9Ùi]!†»xˆYfæÎu”.À£åJ iáŽÀ¼Ð?˜ìbð] fîG‡—s˜»_0ÑI‚p{YŸ“Ã^ÏM# +<²–B7¸4ϧ‰êp‹×˜gñ,Ç?=«ÈÜ‘#ªÞ¾b?IM0qzýŒÎ3¬-ÑM$˜ÆÁ’cþý=$¿ØBB{éÅKIiGèÝC PýýIRû3 èëék0`¼céÎÁ^ĨZ¶ºgq¼±_öÈ–gôÐ6gÏâŸy÷⡟SuÀ:2Œ¢Î37sΡó<ÈÛg˜\f03î‡g[piÍ¢€v•% = ˜¶ …GˆNC W²<³’styÀñ«ódØJpÄ,åz/Y$ìÕ)È <ïâçgºpÈãí¤0ô:³PÅu#vAw#ÐßÔáo€Úˆåþ^QdÀ¬7x,P56ªöd÷›ì$ü"q;IA¬Ž;`í%4òà¹vQOÐ!p)ìð‰ºãÏ‹=füÆ›ÊÛ¸ÔÆ¾‡Ó•I´¦¾ÝŸ°Åì$¤Wá®à𾤠p1^ƒÙâqò¿Ï¤}áÕë8‚8³3=Ñ›À&g%g¥Ñ 6F“cÍèãÒdMF®¦¹Õdõ)Hë—ì,qÖÄdŠ5޾%/`èæjü7t…µvÊ8|út$v:¸lÔ‡ç–ôˆÅ¦ÇêZKx È÷?¶®€±6J<S7 ‡7h‚U€™|S”œà+Ùgâ}ÌSÃJë'4¦ÅËJ‡TÏ®u뫼®“™¾5ÞóûÆ>ÚDLF‹¤5Ø|£õŸ}×wr”³h@^nRÙ]×WUP´ùƒ‹Stiž>IÁÌ‚Çï{mBŽ ÛúK»?g·r/#r£ò`’äÖèMZäH4 ÙÈi,·gBœKvé|‡'a“gİ£:O] +èÀ?cØ\Eê>€_²ÏY˜Ì3…üÈê-óø¿¿?¶jTN@ùÇö¯¹>iI|`ó}}âo¸‰ ¼þEÙY豆{9Ô94%·káλ]Çëoo ã[Õ}œÍ¾Óß̘¬ÜlÝn%«bñ K­iºi‘¼ØÔf9h~Õ"Ú ÏÆ½Ã&Æ;«^Öž×&Fkâ …Q.To‹sºÅB›Ãå^å©v…êTqu§µÈéU5zƒ‚jo«¡A^ [Pã˜1ˆžìÆõ±±ywLãH³R9¯€/múá0Ì7J ÙWšS~×Ð Z={Ü- ÷áâó؋۾Ĩ}+™n^ wÃgµ‹#Ù /Ç%Ê ã4»xãc.g¡ÎïÚä©®ìÕà‹1¼t抺¼NwnØÔ3zìM@嶨\!K¶€­©|]ºuáß•‹{þÆÆ~£–]wýbvâø"^nl¨Å?bvÍö®WÇå¿xûÆç`ú»O°}€¼úë%O WEoÄ›e–ÇÇ8çn a{%¾-j•Kf¬ŒÍl5۪š֡¶AΉ։¶ Îø#ö˸/Üç܆Áx a5·ÂÀ’6¼!˜7\?I?OÏèõ1|b‚G°™2b4V†$0…¶¥ ñ“µËµDëL$.ý†x‡7qÓ%n†¨pÖ?OuøÃä8ŽõÖ‡zBHÆ"x˜…ôs«à‰øX*WDFê‹ñ‘9z¼OXzÕêãUA³†„¬|CßѵEñ6Ð’nï:¢ìÇ®ÓÑÌÂf6_÷õ´¹ ˇÜñHyjnLvÃÔû±Øœ¶ó,ÀàuÜÛȆnîï‡;eÇ]h8èÄI@1AŽ Jj€ÿa ñÎËÒÙ#áå¼ò"¼ö·ú±•€2Ñþþ5¨HýU,ÎVHIf (4´Òb¸.븮…ëf¸n†ëãö@ú¸¥‡ò”J¿›ÁI„:íê9 äÖµÆ!êÉ MšŽG…HÂQð†Õ h€âÁ:‰º. ù±ê*{–ÌÛ  ×:C—× @Ý…ci=Û©Ž·0‘1'ð—†_ôXÔšáïcò¸»ndd¢œˆNžÖ’iS>‹Nœ±$ÍÃRà}벚~îâѵ³Ù Å£‹f†F’ÝýR†^“?(t=YÓ1|xf]¨‰ Þ?61X”7brf&ôŸêЙô—¿†39lÁI¸×j¦kxl2ðR"LBzV¶q…¶(âtéºÈš¤ýrd§£,Ñ&¿Ú³ö˜r–Örwa,èsQNíªìÄg‡ÈÆqYc–öo íÇ$•3êþŽr°«¶²ê~y;øV)6‹ÚÕÚÕƦ³GMÓ1\¢=ZÐ$ê5v»H +mN§Xht8œm¸eוF(ïK x>xö‰½?iSC”ùôlÁäë•+—-[µjÉR¾Q¾€ã &‘G‡Þ}mç#<óÌ#윦<Ç~ÿ ž <ö -—)£Ù- ›:ŠÁÁT›Y”c$Ñ-8y9ѬqèE]Whp&ð®—ÝçøU»Uµ +T+é’‘ÔÛº+0Q@µd/•Y¸àf°TKF]¿,KJèÐ-ãü™ÊlÌÊŸ´‚Ü¿ÿÏýT“Ù¶™”3ÊwʧÊ;ý+C¯rß=X•:(¬³K”0w^ c‚âžþAüW±äg-6™ÀßÌÛô‰NUϸÌ.«ÏâL ãTìiâQÔ*îa O,ºlÎ]ž*=ÆKæ9Ó/%¡tóìñÅ›‚crò°Y9ã¾oå‹ÊOXÓþΣoš:üÎÇo®^ÃÜ> yüC ¤¨üZœÕ… x`D÷’‹ìD˜ïA ®ÚE¢t|® +:Ì‚Ž×Ên’M‚„¡_4½Æ§U×~¦îòŒ˜Ö#¾GÃ>~=w!bì +É%kÌ1iº'ûz”ϰ¡8›™óÎV޼zy€ã÷8¡&g¹ŸŽÓî³ìXÐyôËÈ¡Á,Ùê´¦Y‹­ã„FwÂLÉ[õ:™¿Ì©“}N»Æ‹ 페ØËJŠ»)P:ªÒœzdeêþíÞñ}êÓÐmO µ$ü Õ7ÿO…±Ô›aÝÖËÆü8Æ¿aËCóêý£[‚3ÈÈ‹/márÍ%›¼ÜG÷–‚nϖüó×àp?†ŸÊ?Ê?Gƒ§Ø@ªàѲ¹žå«ðj´ŠÛÈmãžç^e¾Àç°Ä¸YÖG£2ıO] t]€gˆ,uU@^Ъ«”ÞŽ+– ¯ô^ˆ, €!pi5@R”®zÓÃÌ$á\åzå]e1~Ζ_|‰-ï:ýÐÜí~hQ  ¥Ñ_8àÀýá_:` É`Ñ_D¤Ÿ–ÒB=6Q-†¶¡î€3“UØóØœª´+=ñ”òÝü±ûŽ1^|‰qv8²‡…ÒpTãØE˜BˆÀšY§ÌøH"›Ì§É…l@®dÉcÙ:y»Y~€}Z~–}^Ø'·³¯Ëï°ɧÙs¬eì,ÇøL„`–³³ ç3}/KvY#ùL‚(Ê»,i€ÔaVYÄs á5’6ƒe™nä%ˆÆ¯ÅÇ‘CÛ¨Õ=–ô–+¢Øþÿ-нL%¿á€¹^&ö¾»ôŒ[e°_¾£æt3®Ï“T:J”N¼PÙŠëwïÄ£•-ÿå…I +±+í¸$ÔzW){€'¥ +è7Iý}ЃM>yœV0ê2·®TÈÑ êj9\/,ÖélQ…ºUÒjÍ&M›†ŽÖŠ:âÖj}&FæâEŸI’(¨“-Z /HÈE2Ì.CT´`éu4¬Ýd¸µæ?‰ŽF‹õÍ:kNÙ»€>4] +#–Õœ +* Ë-ÕŠ4 ÈÀŽZ´ä@^Dx)L­þva+ý:Ä–2öžILêt¤³J.ýö3ìWÖξñÅä¬,|ËÛ„È&ãl-;¿ë“xñˆòúÌðÑHµ'ó&ЋÆÄÿœ,2ÕÌk SÄK·²ë¤÷Ø$^`“ÙT äNª5´Bº‡½Oz„}Bz–Ý'ý“}_:%ïe7KDbèE‰‘И٠y™•0Ã9µXTãåó#ʨ¡Zbí‘}e¡ö²PI{8b®.ÑX‘¹€†Ì-žÌT1 CÇHI×hâÎL8ÛÚðÕ'äÌ…Ç R¦eÜqºothë]ˆÃ»‚iîØØ$³ßdLô'¹Óq:0)ÑÔÇîwãX÷ð@R³Ž´ôcž™=ßH—P]RÑátŽõ«_’”ú0ÍÑ}¢ê÷dê×9ô°À ŠÃá}£6õ#,ôG"Ž Í×ReŒ¯.¯+lŸŸ·aU=)ŒRu×±Ïnj_ìI©¼kóŠùF ¾ßŸµàlSù¼Ê¢?Ýš—g½Ÿ°G¾u §fîHØa ?š@Ôï»g—üD]iVÎsG.dÃkj™@Ÿ@ŸdÔ¸Å}â€>9nIïÒhÄ~㎗%‘áü>ì³ÙÜGë†éî‚=ap¼3Å—r̳^]gžu–„zˆtª¦>»½’VáÏ$éfì,\ŠónÔw »J$Ó¥ŸYd‰Ï#s­˜R5~jaÝ€ùýS®›1ü{”)÷[ãsç„î\“|xÅÙy#L÷c1?S@é¼k@JÂb{rÅråà¦ml¸,ÎaÛAðܨ2èy/Ç&p†•îãZ¬Mˆv;m‘uæ ®9n0Û°k—giÕƶ zpôt³!§œlSøë+º#@õ´‹òx5«î¦H௥,+gz‘ÝׯàËÔKù0ÓŽ˜mwƺJF½7&:Pk~ +o²¨Ÿ—£'t×Ú«üÄI Ã5¦ñuay¥éPÇ‚µ“¢JþÚEýÙäw‹µË{®çNtù47Jôw¨ÅK?Ñ ïð©J*BZ Ï?ÒÜùååË×pé>Hêá#+ Àß>cÞ@ÛØ· qÈeæá/Hªƒda } ‚ò-pï‡ërè^åƒîŒ\ {%zŸKá³4A6Zzý-£ƒÐV>¤!M„´•‡…g[ùKq…¶n…:2i5ÚðFxÞeV¯ÑÃ…çžH~áW$/äçCû*Îhí/ÙÑý&\ûR\àZ×2¸úiŸ.‡´ +Ú_I‚ü[àº賜æGž/ƒTô¹ž—GÞ[°ðÒÓ+$ È Ê RŠfÂ5Ú§b™ÇpG]„%0 Ù‡ØW¹Xn"w†çÇñ ù{ùw„¡IøFlß—J¤¤.¹EþJc×LÕ<©ù@›¨½]·D/ê—迉*Zõ˜!Å0Ñp«a¿±Ð8Ñø/Sši¹és“ùÓèåÑ­Ñ–Ödë«¶bÛí¶—löûöMöýŽiŽ—œΕ1Θå1b+bž7*n~¼3~füË®x×W»{°û÷YÏPÏÚ„´„ýÞdï=Þ݉ɉ7Fdõ´fˆÙô‡Ži gñ?¡—ôi3á’Ž@E`ú]ª ŒÏ˜Ì D<3³HÆOG`ð‰Ì#=ÑD`å’åØùô; ¦!‹b…&•ˆôÂQV#ÀÂ)¦{`Dá+¦1žŸ´ˆ¿F…Z†™¡Nf~†2Ìz¦½Ö +*LÃäµƀѿ#0Ôƒ˜AÕØYP·wE`¹ñÞÌ£XÜ4•8#° Å’]*,û ÜÑ, ÉÜÏ*¬Qñ F`¹…a*¬¥8O#0ô…|t5#ª°ŽÒAhÀ,r +m*LcK0ö(lØ-†a%³ñp`ª°‘¶%F«°‰Ö)†Ë˜)ÌnÀP?Û´=¤ÂÑ*Ñú(ΰE­3Y…i|LÏŸˆÀ€ÿ +Ûé—3b¶ +;(ĦßD‹ƒU8F­g² +ÇѶ¸ò øpƒ#°€fsÓT8^Ŧ +»ÔúÃ2àQáU8Amk­ +§ª4¿S…ÓÔw7©p@-ÿ€ +÷Sá'),ª2)ªtU9_Raµâ«Öb5ÿ–Õü¡Ça6ËA8²Q&Ê…s6*„¼þˆþÆûlÔð4Í»ëÐB¸Ÿ9ƒÐ\4eÔó>ý}7ŠfÀ“yPn1”oTë©êU*ÜJ@-;æR™ÑðÆlµöÍE zµ€wçÙ™¹ÙÙ…îþMM³ÝæÍiºnaã|÷ ¹S²ÜôyqŽ{茹ó.njt÷¯rG^ ä¸ÇМÑóf_·pƼ¹ Ôª†Fg£8ӧПүnœÝÒ¸pÆËUd¦0oöÔ_+ì¾T¤¯Ú«lÀ2îò¡LŽš—«þþô4r3.ìÕ„›VÜד•=5¿1§¯;7;§ 3;?3§ðWšsg"·;ƒû÷6 Ò^• 4NåÅ‚Íþ'&h\ãüÐíK-ýZg2/÷÷RÝ™¿Ýó*o(4ò¯UïÃ2ÑU¸žO§ÂݸÎG³ ohòß’Œ^š±ÀÝàžßxíŒÀÚÆ©î…ó¦6Îi˜?Ë=oZoîþ>K~Af˜7TŒèÿ1ñk¯ýþÓFµwn̹*Æá>5Ã=½›Š¾„žÌƒ2_Fh ZóÂßhé÷ŸÎˆàѨÖÝs½V-Cñ§Ð\[7¯âH妠éê]¿ù¿ƒa-Dp™÷Ø\ûËP®‡n*«WÊ­k¡š;r~»qjÝ¿ÞRËï< Klc„×Fdõrëj•ÝéP~®J¥ÙðlŽš?K­½A}÷÷9û{|ýõg§Tn„iøKš4Fèn}>ÐqŽZ~–Úî4ôÓïrò×Z¦Ö?îªÿwÈoÉ{˜g ½¸öËÑá Hâ§þfK=}ÿµž7öê9Õ$g.õœÖ08õsDƃÞ}þ-) ¶ÆökÞÿÂÑj8Ó¼i‘2´m*9-¿IÕÙÿ[ ÞËçñÕ¼ÿ7ž¦ð9|”Hã¡O=Á¯•¼ô¬§ßa^ß°q ͽ¤"™ÕÌ‹L;ów8?£ööKÈŸ2ÕÐ|„²OdweýB/t={âг½ßÊÎVGê\0¬­l1dKÙ!`•P«|žÊk ÄLuÌÌèý¦>]ïÐçBÎJAœCk€–§½\[1­ âŸÎ#)C"åJ5’çÊÒ7l>ú +¼~Ák>TÌþâIƒjU«Ý5¢_ù£¿JG×Íé—šm¨¤üt¡}F îÅëQt}gPÂ.i\8¾} g!:£ž[qVP«CÒ”%®)+VT§ö—ðT^„ W¢DõZ±3ñ Wþ­ÏkAÇwÖ 5 ”ø¢™d“l.VÌRÄfR²º˜Â6 ¨ÄÔ@­ž +¹YâEFìÅú½lv5.ˆwQ +úxrõ×A©3³Å£o>Ã|gÞw.{x{y‰3õ!;z”A¢[u?õ&üÐ=Œè(|'·á‹¯$_ÈAøÀν×Ãzé¼Ëx2Ã[âÝoȼÐÓð\?ŽÊöèúðH_‚‡±ó #pŸxhÕ5Ž>Ücù»ËBXñ/^óq¥#Œ.» ®'?ëÃ%’„&»ˆèv8C.Âi2Õ‚‡œT…ß”º¥‚È@}£œŸý0/óm³ä¤|‡ü4Ý12Q–?»ÖeòY(d<ô䥙ÊSíæ<ôYxp¬øXð1§¾FÙ7ŸF§¤ºëšiöftËe†U×Lé oË'W5Õ‹‹‹UiV¹£œWf”CЦ¤•¤²_Ù§Œ*aÂ#x'Þ·aŒƒ8€e,á°·ñ‘j¼ò G8‚ñkH¬GdI4¥­ŒX©sBò‚Òõ½‹ùH>4±{üXqÈÔØœµ?#ò÷EínizÖ~­Ûc|±­kÿg´&ÙT²Ú®ÕÔD¸ÑbѰo.ÎGì«ÍX¬7ho6@I6šsóœçZv;Þ*Úƒx1Ö³jCä—­x±'ÕŒêl¯F[EÇ¢ïRw+†YþÇëÆo/Ó’ÌàÉLîU)‘Ë\®p¯2÷*s¯ +­/M3.LOJ¿nPBendstream +endobj +8 0 obj +<< +/Ascent 750 /CapHeight 719.7266 /Descent -169.9219 /Flags 262148 /FontBBox [ -1017.578 -480.957 1436.523 1159.18 ] /FontFile2 7 0 R + /FontName /AAAAAA+Helvetica-Bold /ItalicAngle 0 /MissingWidth 722.168 /StemV 165 /Type /FontDescriptor +>> +endobj +9 0 obj +<< +/BaseFont /AAAAAA+Helvetica-Bold /FirstChar 0 /FontDescriptor 8 0 R /LastChar 127 /Name /F2+0 /Subtype /TrueType + /ToUnicode 6 0 R /Type /Font /Widths [ 0 553.2227 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 277.832 333.0078 474.1211 556.1523 556.1523 889.1602 722.168 237.793 + 333.0078 333.0078 389.1602 583.9844 277.832 333.0078 277.832 277.832 556.1523 556.1523 + 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 333.0078 333.0078 + 583.9844 583.9844 583.9844 610.8398 975.0977 722.168 722.168 722.168 722.168 666.9922 + 610.8398 777.832 722.168 277.832 556.1523 722.168 610.8398 833.0078 722.168 777.832 + 666.9922 777.832 722.168 666.9922 610.8398 722.168 666.9922 943.8477 666.9922 666.9922 + 610.8398 333.0078 277.832 333.0078 583.9844 556.1523 333.0078 556.1523 610.8398 556.1523 + 610.8398 556.1523 333.0078 610.8398 610.8398 277.832 277.832 556.1523 277.832 889.1602 + 610.8398 610.8398 610.8398 610.8398 389.1602 556.1523 333.0078 610.8398 556.1523 777.832 + 556.1523 556.1523 500 389.1602 279.7852 389.1602 583.9844 722.168 ] +>> +endobj +10 0 obj +<< +/Filter [ /FlateDecode ] /Length 669 +>> +stream +xœmÕÝjQ†ás¯b[z ÛõׂiÒÐô‡¦7`Æm*ÄQFSÈÝw}~!Ù„èz‡íÆçlM/o®n†í©›þ÷ým=u›í°ëqÿ8öµ»«÷ÛaRæÝzÛŸžßÎßýnu˜LóòíÓñTw7Ãf?Y,ºé¯<<žÆ§îÝÅùùðµ>ü­§m¿z?™þ×uÜ÷ÿ=¼}<ê®§n6Y.»uÝä|[¾¯vµ›¾½ñzþûéP»ùù½Øï×õxXõu\ ÷u²˜Í–Ý"®—“:¬ßœ•ùGÞ¹ÛôVãóogù,³KÓó¦¥imÚšö¦£éMjú¢éÏM_6}Õô—¦¯_»4þÒøKã/¿4þÒøKã/¿4þÒøKã/¿4þÒøKã/NÿüÜôçȦ?G6ý9²éÏ‘MŽlúsdÓŸ#›þÙôçȦ?G6ý9²éÏ‘MŽlúsdÓŸc²ú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_á7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßàwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúþ ÿyC> +stream +xœ­| `“EöøÌw$M›¦¹Sè•4mZzß %ô Ü´h-¥È](år•­*¨È!Ç"®"ŠÈaS(‡".‹ºˆ² +ºxTÄÛEwÑu×E…öëÿ½ù’4¥qÿ¿Bú½oæÍÌ›7oÞ5“J &„'¥£ËS3´ƒû\†’ 𩪙[=_µ9°‚Ú>æšÅ Ö¸ãÜ#„pc¡¾ïôùwÌýèpÊCðŸÀEwÌY6=õà£3 C!GgÔVO Ú\Fȸ—?gF+—Áûð3cnÃÒMëm‡  +ý¯œSWS½´võB*¶Cý«s«—ΧG„¾„TVÁ»u^õÜÚ ãïRÁ{#ŒW=¿naC‡@j ™ú%Öϯ¯ÿŸ¢èRã“u„NÐuD$Düƒ˜ #DÊOþ,™ÎÿŸO ×QJ–Nô¾Ï_V¿Ï*ˆô4 ÜFÿj%ô‰ÑÀ-!U<Ž£ì‚ʨ‰‚2¨‘•ýÿüã`- ZA”$€¨H ‚þƒ‰†„-Ñ=1#13±PÒ‹ô&a$œDHTÙH4±“K$ŽÄ“>$$’$’LRH*I#é$ƒd’,’MrH.éKú‘ÛHéO|28É R@ +I)&ƒI B†’ad8AF’Qd4)%ed )'cÉ82žTJâ"ÈD2‰ÜN&“)¤Šôôó"ÙŽä›xRH%D§Ü&eŠ_u|(¾# ïh•†â»›$¹­UÓ“Ý4É:Íê>QêÜBñÄJ›Ý¶¦Òê.-­´¹®0«»/B}].«;¨¸zš;_ƒŠ­î4ÒãDi¥uºuÍšj«;°´² +J¬XˆPB9UaU.—+ÌM].»›”VÖº\Én.É +ý±Õ@‚XXZéín…½ Ìfs¹iU²›O²=ÖiÍâÔ+Ö¢\‚ ÀBëëè®9MŒ]SVYUV=ÆUiwA³¼*ÂzÏPÉn!É­,L< ^XUìáÕ^`·º‰½ ÚÍMî¦50 [HHv+’¬HW\sT S­ØƒÛYåB”ª"F•RÆ ‰öæ!¶ÊZ¼Æ^\d“&aÈ·5 †÷ŽïæcíÕEr〤fQ,vÓê¢d·* ЬV·ªp"`/p¹ñm ¼Â[²;0ÉêÖ2 +­@P Œå*¬²®©‚õ€9$»ƒ’†­lVÒ"WŒ;¸Ö¾4Ù­N^V9¼\. ³A¹•'5uá¸Êfµº((p&ºÜ¤ÐÍÅ4«ðW ürS30†-­l¦À-Xž‚5ÀkV•`³C3/&×c.–•¸`&%@ ”våÜ øÙLˆÁ|)t“ü”R¶8 R,[IÜj{µ +F<Lag¬©jÝsâ3!€¨ILvk“š)>uIÍ>õIÍ<> IÍ>Àr|š’šø4'5+ñiIjÀghR³ +Ÿ½’܉·8vo»´ ƒ±ñcã3ÆÆg$ŒÏ(ŸVŸ6ŸÑ06>í06>c’¬ý™|Ä&Á°ÁUÖB`uU!ã,fL‚-ÙíHrÇ&ºcAFã@K¬7`ª½º¯Ýºf\åM1@*’Ýñ>NS³;.ÁMMilr}üѵ*!ÉšÍèLL"n¾‡Îa[ô8(–s SREùö¾Í Ô3I‚y¡=Ó ²YÝ7Ùœ”béŸìNù5T£@O…¥ æXkе÷7°pèš5%öؤ•SÃP³€I¡Ôd„ñÓ’€*qøÏPÜŠâÄÚ5)v«µÿè+½³Úš"÷áPI'ZÝU¸ee•9+o ;È9øÞ®Ô* ì Û>6Páõ»¡ +•‡¬/¹Âªiv7_X= ª¹Âê0€«Pa\ߦH%m kg‡üàÁFþzÄÎTÔT!ïE$±[¯Ð#Î(–¿Aƒ…Ùm®Î±`É3V(Øûk2Y±;ö‰Õ:Ø^‚ƒáje1–á<%c+S¬ýÁ¬ ÅžB+Òâcy,¼ •E½¸Æ.¯RObëY;Ên¶gøBïºT¡A»~~ÞuÌI²[SeƒA±öw¥4;¨v]®¯¸Ô¿¸oWìqú%¹Ó{ìô¶$wzâ%¨íŽk’âvjžO¼¼¬Eɲƒœ§À‘»ëŸ„V¦àÃ’ÿ+ÑCòQ©ô·ƒÞð[l›ËCãd†wþù8›ÝÃÏ<|SS6É;óÁMhHq'ÁFtÞ |è(j4¸“.Hr§Â£¹V |µSäåSQÊ¢»À⤄ô`0’¤”• €• Eœ C†##‘ˆÓ€QˆƒÀhÄA q(Cœ<Æ 刃ÀXÄA`âä0q¨@*âÜÀÄA`"â 0 q¸=Éácód|qç4…A¹U1y‚—¾ðRäÎôaOņ]Ã ÄžÆ D­MrgùP§ã C½ƒAˆ:ƒAˆ:3ÉíC…/ u6ƒuƒunR¢; ÖÍÇ”.Eû‘ŒªŸŸ—gÁ?åÑç>$ +à…Ç'fêlº8øk¶}.¿ZxTyí âCŒD¾þyÕa‘ãÀq/îv”V:M (à%CLPH8Ž/#<Ì… Gµ³RÓ¥Ò©G¯ŸãÇùªÁGrÒéõZÁhÈÔñv^—i²_~3}zÖ©Sâq)¢}%wWÛ•³Ðn ¿€›ì¡}€LCÐCh™È <¥jt)Ñ"—S'@$(¥B„¦¼N¡M¤0 þã&G.‹Ú±,J<ÞÞÂÀ‹vˆ°Æ #QT1j§C!pœF }st‚6$€'ÁAœ*¨\"åyu¡šâä€ß6¦\öÃ…øá;~Sïñ¿Š­ña;©gßþ»\Έððð¨ð¨Èˆ°Þ½B-fPzçG« …•1Øs3 ™<û(íìc7°O,<"¿™|)êÒ’MË>þÝÆeMù&êk€>’KÜâ)OâÒie=!9ñÓ ín +éqü4ÐJi7²œ'΃«È‚X0„äп;u™‘AJA%fP¢rPe_ /F*©ŠŠªP "3P$xå88±\¹@9DR¥ +('¦ä›ú·6 eÍ´ÿÛhÆÿm´Ðÿm4Çÿ6Zü­5ÓtiæLîÞ~)U»·¤L´Pºz’’œÐ'>."¼W¨,\ÁjX瀠Ęܜì¬8GœŽ˜-: 59rr³3M‘Ôbw`©„Q«T(Möì˜8Gv&¼[t)4›× Šž”}·´EÝŠº–ONO9u^lRF\s©üþýU‡¦HÏè×`ÏßýÁ[óõ}÷ Gtû¿ù©óÍô=qó˜‡~äV­Ð¼½gDn­(õÔoòQéÊü|ãÉ“†cµûV\ ál}Nì­WÐѪ8+n€$ôAɤ!òB¥«©’¢R˜DE¢A§¨hÀ$‚ܦ*)ǤS¡O3†aCÂ)¹Y7iÝSÃx_CTa³o©5jÃÜ[mCˆj´·©Š”à¢ÅÆÇ‡‡kµ„ÄgÆg¤$…Ç…;¢­Ú0mo³1DËDc4ÚDë©°G;²³r@5P»–ÓaV˜ŒæL½_ñ+Wgά[æÌúõumŸÔe,[6~ܲeã°`T‰ð2 +¹£gÖaÁº3\ëÕ!üŒeãÆ-[ +¨\â_åò¿^³a~`ޮދb¼x fJòèT§6/V,ð$-Ù¡(ÏyÔ‡ a9[#à¯PF!¸ÅV,'¢h½úâæx¡¢WAÜJÆ[ì/ôûsÜbñþxšá9Ã0&ÓŰÁÅ +_âÛÃ:&;35%¡OT„&Tc‰UÂÒçÊkªÄEµèsr©‚™[ñ X}ع4Ÿæf*¸ljƒj& ¹9¹ÜñCëÍ…£=™(µ<œX°·úÝ'vüaŸ+ëNª3íÕM§â¥5cŠ–<öÕÙÚüçø×ŠÊMæH0ßÕvuú@ºirÆð9‹–óÖ Ek=¿ìáYùeÒ‰ÒÑ%Kí½¤Wv»ú ùé±gçM',ƒ¹_@Ç0ÿ!Uæ ‹ËÀ.Ë®Cç+óTÌ(ñ:^öè[ƒMö ¯µÒd®Z7‹í<™÷A²/÷ÑÙ­Æ[„S't6‘—ÝÓ%=OßÙ*¥lÅ`ãgLJB¸¸¬d8©“ ôOvW!ºšÌ*™ˆ/B€Âñ”›Ø¥Òæ_;p´·šG³äÔ¡EÒ†kÃÌFLãožXÌ:­’³Y㺬\½MŸ£ËâìÑœÎh1gòλª*–KŸKÒò™Óì5»–îbcêçÅ­_5Kg¤ ’¾ûôÍû±‰¾úÕÏtÌ4O:/}üѪ7‘_¯Âä΃ý 3cÂTÒF_À¥žÑ]ê:×§—_1×u¡\NN¢É¢áî(, +yBù=Xß +ó!AtTLôGÑ­Vø‘7Óa]˜ÝÐG4&æèÒŸÚWÚ¶eèQχ òW‚Ð[õç÷dÙ|÷ %á_°ˆÆ_ùbÙàC«§öÖ›×´õyêç× Ï.Ÿ}÷Ƈ†¯:¶ø¬teç¾;KjGä¤WÌÚ#Ëz:ÈSoqI'Ç:Ê‹ N™€é¤ÐN`¯#§èµbX9f¤(' +[eyU*MJ/’ºµR€ÑS}­ýÛ€»õ«èJ%ímD•(!@|:I³b3Šìz•9Qà˜Ëš™áñ~”Ù‘43ÃYÈ@ÙP‚î6;5õ’:~ð‘µûíÐÇÂæÚAõ[k[Šâç÷áºj±Ì[í ‡ÞDndõœˆ2mæqÿó“" +€Ï€ÅЩ¨Î–M31Ò×qÏHÙô­ö‡¸u[ß}—^ãV·/‘D:Ùͯm›ò¸ôÈBAÇÐ-ÄJÃ` $¯D˜ƒ¬ì `?,™îõbÀo§œHñ”“‰ƒIáõ­n¹I¨Âë¯ÿÆQâë(δ_ÇV(ÈhO¢(aîX;šµÆÄètú;Hš¡‹˜Å¡ùàawff&#g‹Ž‰k×ßíûä¶#·¯JÝ>—»ÔþÄ€ŒäÒ™¯Qý5ér“ô-»-/òÌ]›ŸâTñüóR½Ã`“^ySzãµ3L†Fv|$ØÅ?bDU‡©Â·q¨7@µ¡œˆ[I(WRAPP…‚/eÊ{Wá–ÐM ÝöÛzGîÇzуy½íº Ã*Ý磽èàN1–Ãà ‘à àAï˜XØáŒ0R{ÓÉn{4Ñi™%êŒyø’ã´öA+·ÌŸ<~V UKÿ8-]t7qÏÃËw54=ñ°øÇ_VŽK› }#µMLŽÿúËW¤wi:Iƒ^¤Ó®~ü§{çÚöØ/0ý8œíçF0Ň0âÆ•ÀɇxŒËë¬X}6ÖHxpht80:Ìæ„c(ØjR€»Š +IoÈɵe ©Å_UV$G¤œ*º´zKÛ%±ññB©åım5è6ºù»ý‡äœMAÇû §·ƒ£e!dãáŒXÀ«Y¢^SŽ)µr‚ ¦kîÈÄ3&™èCï‚ä´÷T/Šüh//¢î5©ÁONŒŠP[Ôf½–ŧàøÇ£~0‰óR0Í€ëe¹ÜÓ÷5®¸·aóôžÙ³êž›¶K‡F_:ÿÖ·EŽRWæéÒ9é“»îä«&•Þwß„Úúö¼ûï{pÝÆ{çïäžL,m|òë×ßWžšÜ'{Ú“Ç¥_¾øà÷/¤ãþÚñ ›†y„݇”žýƒ-DâA(à©YE¯9>wn&á>t?‰õ4óCv&Ü ”óh6A¿N¼Ã1 V ‰TV+  ÏÎÒgZ ˜âÈög-ÕÌÎ-¾ç°£óô·øîí·¤`ô +éÔ;­\Fó¿[ùØ›è„Mý"ß§C§Œ¤Ü›¯ÐxéëǾ‘~ySzþÂ.êxØýÇÇš}è ô XíÁÆò¼·]—N¹y:9„¹aÎ’e“ÁºÀç‹sð#ØZÛ7¶Ê9ð/ÀÇ? +ý‡@ål éôòMÐ-WF0AÛÅß×3ŸŒóUó8ŠYgQºøü HlÄÁaJçžÊº÷üùsÁ¥ ¢RÝúÆì!‹-bY+Û¿á—…ýB<êóƒ"¥ñ‰jRQ Ö·ñ/]«ã&Ó7Z¤-Òæú&P8‰\êøÆ“TgúÈ„§s¸À‘è##iBݵ˂áÚe>g÷n©|ïÞéPÑløO…ý×êøcmÅÂzzXÊm¡³èÌ)GæßvÀ"ž…î­d‚̹Ÿ³¶‹&LzÍ…]\`ÛõhìbÑ8¶¥!!4Z§U˜c“DÏ6¨B©¡&{VNWß“^>uJjúñük—+VVõ;P´°4Æ¿èþg1â³g…ÓTùYÓ¬•·ß³ü‘¦££c žºî®â{Ù>ë8¯Ì¿%1Œ|éÉ$YÁ” æTàh†±W¥÷Õ%£¤A¤  ö“”‹ì0^EùI$ €ÍÁˆùÒÀò hò¥ì³ýÛ)¡Õ¥ßQn<Ñ󯆵±3ã×Ú©‚0Å_ák!šÓ V«‡©‡Ä8 1q±}blêÐD‚ +7j†>›ð0O96+Nàq²ü\.np0Ü’›Éò?AlV¥c)[FL®E!Ø…ÏʇÖ?;~Ðý[Ú·|~èÂô1:íÌŸ¤ïŸ«™,ðÙOÿݨ¸yú*!cãªM®½þô’ô´òô¾§OК]4rIÁiÛûü±é?«¦ÞAó~ßVIÅsTO)µì‘~øR:>¥0(4xᔢi‹Ë!<ÏÌMîó݉KTuñ¸ôùÕ=§gº&”>$Û HBÄÓrìY½óš`ƒ‚(uzNªDÜ- )& F19ÌùâPÿJ¯ãSØN³»ÔbFãlo†Z8´AÔ1oãí”_ûÉåUŸq¦ÖMíÇž8íã& GË×\-¤G¥!,òÞô +BÀOÖŠ‚8×{¨&SOvr<&Üj´†Nyw4MW4g¸ÊÁM+|˜lfu%ñŽP³QdR›TJHÑ9Ïóñv›ÎäQV: ¥Rчr¯.².#\ê×>aVá”'o‹j¿&¶M\ò +5.1§ê¹µ ÷'t´Š `?âí¾WFRÑ){–èÌžCÁª›N0m©€Ĉ†€ÍÇ$x3¢·€*ø»‰="›» ;£¯Çƒh‡*:ÑÙ1Ë6Ep»!&Z¯4&P‹=…2?Pñ^n&8W,CÏ.DÒ,ÝIÛk>”þûÃ÷ˆ<Ù{C“ô~yþ«}/Ò’xñ+©õØÚ]ÒÛÒk’$ýé9×úKì¯t->û9ð ÈP È溧y²hO^˜Ë PÐyzà«Õt­uØ+á+|L>4”„šµu ¦ÁbHb,Nµ¯–óʃΨä@ÎÖj–×;ää'^çÊiê³›*“îkoÚcŠ«s=X^Bu4åÚVÑðþIéÜ·Ç¥¨›À†\úñÆç’ƒjJ<[5 ºÀ±Tž÷pYIJ.Òß IÓÉÙÛW/àNëzØ|D>Ôƒ!’Îó¡MBjÛF>±í<×µ“\”x¼E*Ø#išØX–{ö¬"µ2¡¡=Ú™réV¯ñÖCÁÙÝꑸÌ6ÑØI›½‰¿Öv†;מzŠÑÔÔ> ùWÓñ¡¸ö Þ=è 4ƒ®¢vªô°cXWap€ç6ŠœÛ€­\Bï´Þ¨‰¹{?l‘ÇRÑÙŠ# +NQÑÙ˜IF«ÑÄÆ‚ÕhD«D΋Ë ‹Á– seÞMǽå£ô×b>ßwFúæk*œ¢"/eq«ÓjG­xCºöÒ__™¦ØÄ/JJŸîØ(½%“®JGþN¹gÚ¾;^—8칿Ñzº õ,D;`¿¤2y»Ýw{– +.¼/ '(»Ü^è¬Ôø*;ËYN²ŒÕò]e +ïR`îf³ã4×vút»pZ<Þ¾ƒ›rµkjÇ„ßià݆ߚƒõ9 #ÙOŸ>Ͱ”Ø;>äçBŸRí•OPV+ÚâÙ 2¶KúÕ¿^Ó¥gé©âPÔ*‰çšÀ!£Ý`——‚þ÷Íd.è]&?7wºôù3ß›½à‰ôÈ×èáïxéàW3g.]6·ðEþ]ùüÖ`[ƒQN•*@äÎg÷‚Ù C!ßÅ4³B¯ÐŒ)c¥dðÝ¡6µQ¥Î¾ý$w†Úç¤övé'÷YÜ™vwÛFî³Ï$/Âpv§eˆ<¸ÖËn ñ_ë]_9¨y ®¹ñÞ|x ,;¯gËn²m?Å]j+ƒù7¦êÑÎ+,lMJ‚3á›­Fž­¾»ßpyº¾R§†~>l6éô²z€é‚”eådS;zj&}  »èNÚû¸ Ýþš4A|Y<~Í!´^-äk’Ï.¹ÖGx?9ç㬶Ç=>¼˜ÀôY )u)qZèÓÃÿÛzèužõ ¸(üßþîë㟴‡¼ÌÝÔLv]-ž¹6‘IiÇyñè°v¯¿î`¸Ïaë<:0öttÐYmîZí4Êg¤¢ 󜰳ëžN 0WCôÙZ‚úȨ·ñÂcÇ6<ûª´IÚrÿ£/Óöé‡|)}ú5iᮾ"•Ž´vO? ÃhÂߨöêStÙÁOè/’ÞþQj'˱ÚŸ™¯gì´¡¦›<”³íÙÉånõo=ÊÍîV›ó°Í®‹±2Ñ`i;a¾› œø&nÓ«ÿzqŠo\Z°Pj Ý÷¬xüã×÷u´o^¸-Jâë×!½¥²51‘8²ÄiÀÛ@&¤ÅÙ°Ò½Î2˜à ÝÈWkîZ‹Î†ßúïò¨ÍfsœÙmuĈºÄXe#Þu‘ …RÈÁóÅï*i‰M¼0í‹1Z í9¹—­ÑªcìÙË¥Š9ñ;¦˜8ì;é[ðÍ9aÙþäœO[éy©`ñÖ®x}yo]¯å¿Û4ƒr‹ÙºOë'é/0ÑØKÙÞˆ#+œz*ÞlµgóöFÏ|ab§ÃÕÕ|tÇð³!½øÙÝQ˜¡ÔSX´X{x˜:0@ATT¥D—¼Ó ϰ°p8’FabÆbšJ¬ÒΗ<´³~Àt©÷)n÷î¹oÏ:¾BTòAú”Õ‚Z9­ßRÞ)>|þ†ÇûEJÜŽôÉí+wgÚë_Ûg°Ñfè?þ¿ëÒÃÚ× Tuœ®€à7i6LóíÌXÂñ â p} /b²š÷È7Çgòs±o€lî‚ .öõxPKÀÇö¢£€3;•¤&Ûõ)vð°åÄ”¡0dgÅ`öUNÆ*L°2™ŒÊR.¥‘ʬš«ó'>â©S¯”=Dõ×þN …¤Oluo›wö­MeIÿCúî±Çxn$m½{Ôkþ“K33b““²'ù‹ôÉ\øèÔ9Ö´Ôè¼;^ýñ‡üN`‡°Äƒ-&JR)3JÎ_&° |]L»_M§…׳SV¿4.Ì P%ø¢Ó8èWd §%Ý’N<Þtõߢ¦IÖ3{ÀDÿ¿-5á Ù·^z<Ƨ,‰È¤ÌäS3r¦K óÓ`¯WÈuÔKƒ‰˜bŒ1H;S•M¾¬=yG/0¼ ý]ï¶OLcè}ÒCÒC«†r…âñ¶†'g=¹òüCm§¤6HWhàÂ÷cüÊ‚=–ô*ÈhÌ_wú¨k®w†äÂNf3fÉ…ŒO˜ÉV…N/èUNS-ØÂŸ´_z·ý0<ÂW ™+M!òSâýN5qQáÅ ßè!"ÓO×Û=O±Ÿåcivn¶§œÑ€·GÔD &P¯¨¢™*<&W1íÔDG|@GPS«´üœ´_Ú{NjªÆ {ñ&ñäµ|¤Ž’àK–×G +B‰PoØM BNKzx#_>ñ¢Mö¿Å6Yö‘lv™"¤‡öþ§‘ ¿Ð%´á²dàÄŸ¤îð’Þâ2Ú³ÚC¸IL – ¿›7Ò©b«T>'A-; ]¬—Zö¼Kâ4Û{kÄÕÄ0w yÒlH¸ë´ë›ö󧦃§–ÏlÛØîæJù¹Ð.öT‹ÇG™áÔˆì[ƒ°êà¦ø2;ÞôbÏw=•7ºƒì­&òdø”K!1Q SùUmDž¶Åüšk¿ã¦=#ÌlÚ{íqŒ)i”ærD<%g¨z¾ð¬»Ñ…g_†ÚÆ2Ô¶FÚøÞ{ §6þrf#“ÑŽc°rŒPäáµ¼øÄíÕ¾‹GÁžûK”Ìfelçú]`2ÀªWpyÛÛ_ÃxÁÓ¦JsiÓõs` nÖ§ÿXGã|Õ]²ì:;„n¶Ôóçi£ÔØAYÞÅú_ÊMæßa{¼ß!žÊÎ^ß’cGRœš¹‘ïèFzw³^‡»YÞAÜZ½Sº"ýô4še·¹}?ÓòDXØQ äEà-SßuJq't°¨€HjkeàŽÓcâE¨Ž.`žœä ÖAóY€Yí½ñb=¶Zúñhh“óŽc:.%ÂPp(ñ{¥?8µ Jžp‰`ĸ‚þ”Õ`®o{€º˜³´‹…e`äì‘|MÏükh·þn¡7>7BÃ+ ì<€¶ùpEG³JÂBx¹¥|×’“•šï°F†‡…šmJmb ³€cìKr>Ÿf¢¯¢cIä\f—ãqž$sN®jêGMqm¶ÍȘ;5½œ¶ä›Ô+î|8ϸ[üiçñÅ‹,±êH]B’ãö³*÷­»6qËš·'$ ݵޮЇ§ÞAç$…&O*‘Pþ—dž ÙÚ¾%<šçW©vçY‡Øô´~‰zlqÇE!VI8|-wÑmS9^^§FX§ŸYÜZåÍíûâV7½r]\­óæ×;+œÞ·j…ÞÛj4äúl? c•:{ã~úÖ×ÒtÚüµt`Ë~ˆ öÒSR]ûT.|4éZ ¿üŸœµ¬niñœµÀú+b…â óB¬'àDÑ…7)@™’r¼. ˬ„xÙ/íÅÖ1h9Æh–Ng¯nŲ40³hˆ1ر1Ú Þiò¯Åë`ƒ {DØO˜8³\ G%ÅôªöƒQ Çfœõ‡#½ûÌŸþl‹ºutÌ€1ƒÇ—o»¶=—»4»tí®öõܱ¹Ãÿø6rNÞw Ûð¯îÜ)Ï.PÞ½™bó½PÔkX­géhŒôC®»aa–¥þÖö*[êÖ£]Þ¬&¿yÆÉ±…†Â]¹wÄž_–&‰H[îì3¬orX }&7yÌOážÚZ°¹ {ÁÌö·a"( +6ð9Õì¯ •ê…f°À{¤€gâh)OJ–¥ÄŒìû”«èÄ`ß*Ï(84ØbÐA‡A± +ˆ‡ôÙžÀ«†` 9ø +Ì3útUÚˆŸÙ¼yç{4²Múéc©êÿ®h !»6O~´íÀÞ/ùVéŸà*·KÏÓÄ6ˆ¨œ¢¬kKã„X _C¢iÞ„§Ä +ñ ZBµÇí ñÝ´°¯uÉžžÙêD¯ëβ|<3“=áho±¯Ð›á…vâ…Ýbñ·ÔŸ3=A¤`˺âÊÞo¨m‹3µ!À¯`ü†ZŒœ9gÖ +¬õl½N‹Ê ¿_jçþòlìàÇÂo)¥)Ç9ñw‡¥# Û–IËkYöî;“šMÛvWÅ.¾yíÐøþÒ7°HOmž’9´ýcyúKã`¯”À˜VZxØ¢çä”] ÇSáÊ"ç!Û;9±"¯a8¡8Ú[èÇx ý˜o¡¿õõó’»ãÅß Ï7¦3’x9®Ge¾#$$ÄŽ·#ïÎľ×÷ÎFS¨ñÞ§ù9®øÀK%q‰C.z–>21#eï¡ä'–ì•þÝ~š.Ÿü¬»z˃·?ñæß¸ü˜Á›®:8ÇqTMõ WÃ<6Ûë¥#Ke®©@‹ƒ }6xPVÂîý™™¡íäÑmÝRŒÌ’úÅÜòEÿ¢Ne~Èk÷ÜME½æs=Á¼ì5==[ ІiØJú…œÇ8þežkªoߊ·¡ã}þ°0œým³™‡R!|ój®²X~Û!‹}cŒöRHJ²ÝŒg,¾ïøŽX˜íQv?c‘]…ïb‹vOÛ: ná#«5|ô¿gr{DGþ¦Ï,޵ädÁÌ/~JIÐÒ i‹cÌn$ ½gëKk'ÌQ2Ê98¡—!"5©øÑGÎ~ø$÷ ®—¥ã{N%N­ F(V øÎX0f‰ÌS@ÍÁˆù5,èŪÙuS¡Ò‹c€!& Ü òwQØá†'[åÈÆP`÷á½{¦ôàHcTaÜò ë׋¤óÛ‹û‚(·VpÏÜka};¾à/‚žÆ¿T·ß¨aql(ËS£ÓoÑb[ŽÛéá¶µx« i¶±¾o3˜oTÝÞ°5~«“Ÿ•(‰e2''òð¤ÂB,1:cŒÂÐõHÇž«c¶.–öí¶â¥¢Ø–=œ=ëŽ_•'ã%©ö~c²ªvOxœÓ\;÷Ç cÿ0f5÷s-Á÷#ü·B*Ë÷zÏt:oBz:¾ !E]Oo ìЄ^ ‘4ñ5iÎ i‘Ú¶•Ÿqíþ9=Jô„ˆ;T“A~g7~‡4!78¤a#u=£ ã2Ãp´ ðý·Î½ñÎG-Òéc­ï“Þ„A[øm/ð%×ÎñÚ^åù}Péë9›é=XV=]@¶{Oa 0¢Å“ÓŽüæÊ/I[貯¥+’ô%]&¤J÷Óebûµöèi;›˜¤¡,ÆD¥Óª†^ƒ@‡sà½8yêU?cåxÎëÀah¦âNŽmJö…³œÜ|š såyÛ)ÇŠ©Û·;úD¦&h3Rµb¾Fj8C£¨z‡´^úçóÒôEÀÓÁ +[hÀ£1Â(`¿|g: æß´ày̰îç1]Ž\ntOß[MŠz:qÉâ~×ÞÂç·¯æÖ´5Ò·×òdÇÆvXï¡ìLä¼4™kß'v¢8hh|¢hd +tÅ¿‘ƒ¹è,ؽ ÂÔ{W•Þ¿ýößDç»›DïüyG¿¨ØÂ?Ÿ(Š·­Z¤ßÿ—·æ\h¨7ÍP¿ó¥ ¦zMãà»æo.]¯×m)åm‹õÞ×ùMàÎ#ß7pñ IŽl³Ñ¼½{¡žçÍçæ 9L4“8‡‡^Áb2ñ_&X¡ÌÎǹäæäÒ c£ú>E¹Iý£ó›Ý£¿iž½6¶èO\ʺÒ-óWÝ©©7=èjÙ9?¡^¿È9û­7viyp˺1[tlŸP§p”;O¢ñ¾›žPO4`ÇŒf€ù‰Ì+p—”à×l†À ³{BüÙBD›Á­S²TA”ç+"r*-…œ Ä3»L:ÝÚ/ûb¦-;~èt}C¯›’ócJÎ8ÊzM X¤‹ÏH¨ĵˆ¦ +c`ȱk¿Õ… +ÑrL,_4,#MŽ/ÙÏÝ}^6%¤ÿ¹¨öþn_õï½ÏŸkÛâ‚Ö€Á r¥§¢Ô6=…úËAë½=ù~ªE=þM$˜`?ö¹Ì½OÆ Á4.$Ne)ǽŸlçöµð)â#È(a™¸{à}<›°-âÃçUÏ3>Yð)€ÏHø ÷ÀC÷ ü@áØ{.$Û¢Èg0V$|¶ˆ§Èø<p“ðiRô#5ð¾Ú±Cùvl£ØÃp·C})â²ç)Òp´³¼à,åÃ$ž øòTè§‘ë×q ž©üŸÉRœ/ÌÅOœûb#ž}á3p¾ðYIOá§£ê^ ã¯Ärøä±v Ièg5Ô@; ¼7tèñ |²¸}ç9#YÇízö¡Ný†ÿ&“ t·•Ÿ',ž>ÅqøªxÌC’b«âSåXe[ÀU¤êËÀøÀ—ƒÆÝôjÐu€:Z½2xVðIÍÍ—!E!ÛC¾ÔÞ¥=©ý§._w¯î°^ÐÖ5h ŒFã>ã?ME¦{MgÍfóxóÓæ¿Y–Ë ËJË®Ð;{õÒûDØØ°]á•áO…‘±4â©HcäòÈ¢öXïµ^°M°í‹N‰®ŠþcôöHûdûVûQû1“˜dU“  g%Ó–ƒÈ<({‚û /l”ǽᓿRò”¦D…ßû$r,¡¤6Ì“(:Ó €ó¸‰–žöÀxCè;¬$Üd¬'*îüN7ûŠ‚Z¡b0~ÿV¡°0sïEƒˆ#Þã•d©øƒqj>ÊC9ŸÌà(P¤2ϘŸdÔ"Œöù?ú§:Ì“|ÚÇ  ›V{`"¦g=°Ê[=°’L£?{`=ÑsëåU¢LOô¯yGïh¸&¬$“¹?18˜Ñ9œÁƇq Öb[þY }ò/0X‡ß QÔ0XÏxUÇ`â aXI™FÖç›?W1ØÌÊ718”Á;Ü‹á43¯¨ëfp+?Ï`¼Ú®vz`%™#Èø‘l._18Šõù=ƒm¬m;ƒ£±Oe0ƒUÚÜñ•y ÎÇ9*‡"ÀäAÉxÀÖKy;ƒÍ ž‹°Oæ”w38•ßOž#V’NúÁ¿4’L2àwɲAd>ü›Cj.$ud.¼-" ð^%Ca7Ô@paõµï ¿­d™ 5u€· ðkY?%~Xò(ýîXN9´˜ÃzŸ Ð<²Ðoòœ5½_¿´äŒ´´ë ùóçÔZ ëæÎ_ÔP[o:¯&ÅŠõ}Ó­#fΫkX6¿Ö:¨ÄêiÒ/Ý:KÊëæ,j˜Y7o!k@ÈtY ¿qÀØèdHíœÅµ 3kåw1s ¼^kïX4§º¾§VylRi@d™*¢Þ°,ƒýÁêl˜h”&œã7Bž5=-%mZVmzž5#-=;9-+9=çרÏ¿Ðàîã’ñµõ a޾έÃîµVx"çªgLÀwyÅka +ÀõP; Þæ2æÌ†²:ˆ=o´îãYg.´V[ëk®v𵡾zZíÜêúÙÖºéþk÷kd£(.bd̃úž§QËȶÞ¦²™Òµ® Lª±º©½ÈÍÛç»-ÅV+Tkʆ»å*ÝYaîxWÕtüKæ¾? =ÕÍÙ‹QEµ~á—뀯*St@ LhVТæú@Y¥Ûù@e³‚/jvàÛQà«|«ä(íXånIÑÿ|5’ endstream +endobj +12 0 obj +<< +/Ascent 750 /CapHeight 717.2852 /Descent -169.9219 /Flags 4 /FontBBox [ -950.6836 -480.957 1445.801 1121.582 ] /FontFile2 11 0 R + /FontName /AAAAAA+Helvetica /ItalicAngle 0 /MissingWidth 633.7891 /StemV 87 /Type /FontDescriptor +>> +endobj +13 0 obj +<< +/BaseFont /AAAAAA+Helvetica /FirstChar 0 /FontDescriptor 12 0 R /LastChar 127 /Name /F3+0 /Subtype /TrueType + /ToUnicode 10 0 R /Type /Font /Widths [ 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 277.832 277.832 354.9805 556.1523 556.1523 889.1602 666.9922 190.918 + 333.0078 333.0078 389.1602 583.9844 277.832 333.0078 277.832 277.832 556.1523 556.1523 + 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 277.832 277.832 + 583.9844 583.9844 583.9844 556.1523 1015.137 666.9922 666.9922 722.168 722.168 666.9922 + 610.8398 777.832 722.168 277.832 500 666.9922 556.1523 833.0078 722.168 777.832 + 666.9922 777.832 722.168 666.9922 610.8398 722.168 666.9922 943.8477 666.9922 666.9922 + 610.8398 277.832 277.832 277.832 469.2383 556.1523 333.0078 556.1523 556.1523 500 + 556.1523 556.1523 277.832 556.1523 556.1523 222.168 222.168 500 222.168 833.0078 + 556.1523 556.1523 556.1523 556.1523 333.0078 500 277.832 556.1523 500 722.168 + 500 500 500 333.9844 259.7656 333.9844 583.9844 633.7891 ] +>> +endobj +14 0 obj +<< +/Filter [ /FlateDecode ] /Length 684 +>> +stream +xœ…ÕÝjQ†áó\Å*"éÎúSþXìV¬7Nvj Äi*ôî]_¾Òn<Ðd½ÃÌ&OŽÖôüêâjغé·q×ßÔC·Þ «±>ìǾv·õn3Lʬ[múÃóÝñ»¿_î'Ó<|óôp¨÷WÃz7™Ï»é÷|øpŸº7§ÇëÝçºý]›~ùþl·]]ßn7¿ëÛÉôz\Õq3Üý÷Å›Çý~[ïëpèN&‹E·ªëüá/Ëý×å}í¦ÿ:ýúî§}ífÇû¿ÑïVõa¿ìë¸îêd~r²èæq¹˜Ôaõ׳2ûÀ3·ëþçr|~÷$¯EvizÖ´4­M[ÓÞt4ý¡éMŸ6}ÖôyÓMjúòµKã/¿4þÒøKã/¿4þÒøKã/¿4þÒøKã/¿4þÒøgôÏŽMŽlúsdÓŸ#›þÙôçȦ?G6ý9²éÏ‘MŽlúsdÓŸ#›þÙôçȦ?G6ý9&s¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¡_àú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~¥_áWú~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~£ßà7ú ~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwú~§ßáwúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúþ ?àúŸ7Äó&À®À"|YGýã8æ¦:nËãâÁÊÙ õe¡îw{œÂçˆP«_endstream +endobj +15 0 obj +<< +/Filter [ /FlateDecode ] /Length 11675 /Length1 19784 +>> +stream +xœ­||TÅöðÌ-»ée7Ù Ù”Ý,ém³)›B*! H¡B ¡‰BU‚€)•"åEÔ(*y*b}¨X$;ùŸ™{7»â{ï÷}ÄÙ=wî”Óæœ3gfE!äŽ!•Œ(7{?5j.A™4eFU“ó.åá (š)s[ôüz×*„¸Ñð>hjÓ´ŠÊ-xn÷ÍÓL-2oBüU„2ÖÕÖTU»ULYPö|hŸR .(á}ö~xî_;£eþ®“I§àùCè¿´a攪WÉ›ÅåVÀûÓ3ªæ7q‹¸åÀ³¾±jFÍAáð ø8—6Íln!ÿF5¯£ï›f×4Õíùs*<ÓñŸ@¼pƒ{ ‰‰OЉ0CôÍ·£©rü÷%âºKÐüq¶ç¦³›FNÝW ²e*÷áÏô?3¸%ŒÛèlˆfÜ»0h«ûùã@`­@J䄜‘ r…ñÝ‘òD^È©ù _¤AZä‡ú!¤C(¡`ÀÊ€BõG¡( …£‰¢P4ŠA±(Å#J@f”ˆ’P2JA”ŠÒДŽ2P&ÊBQ6ÊA¹(å£4¢Á¨ ACQ1††£¨D£P)Æ 2TŽ*P%‹Æ¡ñhºMD“¢AqNDßaxŽ$Ñ›‹ŒÀ¹X„#3ô0r.©8€ñšÊøûáÃ(?ðÐÊO¼'ö0Â1z}A]þ~< ¸¨ˆ2ÄÇèíçCª0Vê[õ­EÕ­úAúÚªêýB(û†5­•ñúý¨´¢>GWögWêzÀšÊÊ0Ž@ÇØ8­•0Âty„élÀ +Ę¡úý|XIÅÈŠý‹òuû³ó+uƒ¾`ÿ©’Šý§òu†ÊJh¥èÁ¾ï¯ó“qVΊ(œ¤QJ+ögëö£ÊÖVéÉhØ¿¨µU× +tÈχѩ;*0º³"[®NÐùЂÃxQ {µÈhÐÑ +£Áh<+óan瘡¥€©¡˜Î!Xwb&H€½ªÔâPœ¼@íPè³×x-þO)ÄÃ{çKTh ‰xÝÐQ÷¬J¹Ñ +„”Y•G@k9耡«)!ÑÛàe“°íp×;bÛ­¬Ã¨Î}€ Ø~”xÚ9ƒÞJ“³áœèpNÒp +Äà ØàŠjÞÀ¸~8­äÊúÛqT&ùXÃUÑã‚=‡Š`Ü`ô<ŒëczØÆõ£ÃøQ|åŠZ@+ŽÁå`• +ÑÇ`õrÀ5!ú0òeì> +£ù!oUšT#´S¾ÒÀeÏw¨qj—¾½àwÏÚVo4ðí/A‹`¹ÐÕFK¢:‘gEidE"ÕÈ}¶vç*2ãÜêó#Ï¿~æõ§Îœz{äÛkÏ—œh{Û™¶s\*îO.áþ»ðãd-»È¥]¤ ¯£ðÛ­ƒI -/°¾À™HàŠwüQà³7ŠdX„¦Xà/<,\í• +­FË-aáaj…ÕáqØ’…i‹8Q©Ñj”Ú–§þ¸µ#£ŠüT¦Àá1åÓ¼TIAù««¢N•>ž…=ܽú5Ž-~ivÏ„¼²ñiµ·<–ÜtõÐNy©`Vdò‹ž:æâ7«ÌÌ­á*‡NÐi;Ÿ;£ÉnƾDçùàüRßZ=a£¥Pçíôð2÷¼úŸ+# •dɨu'»fr£¶LD7º;”Åân°ÂZ°¬ñ`=g­* ÕdÓ‚þTèý´ÀL+Ì’Däý˜8䯴@ņÕÒ  €r” ø ˜"Ìvâ'ÐF‡Q7!Ä™f žhÍ)|H˜%¥¢˜$ˆ¶JKJ˜c½:ùP¢ÜÜYìóËM{ ì´‰~‘›¼’ÖÉÍm‚·/mzA/¿Ò“?¹›7 ñ¹&äB!ïvlÚÔAËìŠõzǦ͟Ò*ñÌ-åžé¾$vÀzÿ’Cfƒ–²AëÀ—@Z(ñE ܈aÜô¢Ì’y`†fàxt[@G$¢@ƒÔ -‰T3Ô†pø2†p ?X£eZ ¢ZÃ/xªm.ɘ悺÷<µ#(à©G6ÅçxYå¦ño‘Å•…¬ÿòtHÀ^ü¤[L!ÓÝ%63,4ÍÃiÙ VÓ™{Ç{xNàCÕƒŸ¹õå#ë?W@HÒ½ù¬6œ¸¿À޶>| ˜20n°op^D×âœ<¼°!§è^àb¾ŠÛË쑟lî°D’ááöÚ["Ä"ŠÈþˆØ^žös³õãh?Nî—bI”VˆZ£5Â’áÔ*¼sÞǼ8-/*'Ägä³9²({€0üð‡MßYwž&ï’î?VUìËU0O÷ 2…³öÌ£´ÍãMçñ–çQñ¯ðÄÆ‹J ,ŽÇ‰®-}@ö;Íã>xyÌÚœ(^z±^N~!?’ äí}U?nÄ›Oï´~×ô!ð!”å?ÏAü2æq†y\{Ótl±3âÀh…€Ç¹Ë`¢Š-Z¥V® ·„ã–¶¤½I_z^©z|Ê«3^9#å߸‘¿>÷̸×^w&—ññYX¼j!Ö­æåms:Ó9%”Â7ª‚Ô ŠÔ ·²Ý” ÃµgêgSñ¦r¬,Ç›RÉÔrr³oÁ"ÞD¦’NR·Ð¹bÈ| GÂÔ›¹Ûæâé\¼äÍDæÍ´ ÁFÔóÆÕ숓,ù¹›u×ýšjp!ùKÎhX‰ñ¦ýº!væo‰?A¿PÔ—·´¢ ¦Åýz×C?ˆ?ÝòFÌ÷¶Âúw1™fÅ“vò´¹B þœrÚÓ‹-/ví,vÄ{¨YeQQ;Ç+T˜C=¨5|ª¸ .K±ô{ðÁå–îò0òùü°zX16c_ì»ê4v¾…]]äÖ-°_úÜể³Æß[•zï‘ÙŸv°õþÒ©#‹óc;™>Îí¾$tn&ˆÛeÜb(n1nàp`ÙSÜb¼$Í Á&ä"€\戂à•F +ÆÀo3gf´ØH‘(Kœ(£4SÿŒúð0 Þ£ò Z1ú mÐôŒ5Ñ«2juª¡5÷ú’?t)Écóv4µ¿¦›˜‘ž^NÞ¼E΋ ÂÇËÓêšÖštç¹~Q‹JkÕ7Tœ˜rñåEŸ¼š“ko×ï•tö–Âqq+˜ wس8X2»Òƒ—¶•Žäp˾]!dr£Mdk#A@&ÄNjƒøDPaÖö\r-×ږ̵ãìl'/œJÞ©7ù¦®¹Ül뾡»Côƒ8Qû¢»¸;/hâÍÂmföp?P÷yhÂ÷yàþQ”3ÒJhÙ<=SŸp +ÃÃ#c;2€÷ÇÛù¡ã§¯ñó+lLŠl"Ø›N²¾8ohD^å¡O¢ÈQÒý^G^:¡fý¬™Oºûå¸ñ†_ÈëÑÚ_¾{›œþü<°` СÁó€¶ôPD) ’(‰ì¡Ä¯gUõµª!*„Wî@äQ0 +ä'Å…v2Lµ‰‚TƒT²æ¨í*ÅM¸ÒO7qlQÎäà~q»“:xÂÊñfSî“cÿq2&šœï&?Ž˜Ñ¿öäÑ߬:{ZÓ¶vöƒËbró7~¡1*KٮȭóçÈÙo^ºµGÖ-zoµ 4À«™yH»J©‚Rª(õú\™ÁÅP£à”VY@5ÄÔaä⬱/û“O&âa.²Æ¦ H8<ß³ŒÜ{?~ïÀâ4Ìb£êî¡ Ö¢+‹ïÊQj+¢GûÿgŽR•U þLeýdÈÎQÊPÞ1f +”£,RrlÃUL^®õ«œ4i…Ÿ¶,w\€güôÓ“!ž“çÜ“ëNŽþúëëáþOâ]ås¼ÔCËËæ¨½†žž[?³¹yfý\.{ж§¿øâéÂmoÞû*鯸Õ{ß\[=¢¬ªªlD5[—«»?9ñØ EÙ©¶ïïŽ1§¨¦¥eT;yQƒLW…óÁBaÑê±æhsÂØ9{;Lf<äT£ÁtuQæ$}Àðéâ+ä³ä¹¹ŸøÇ‘ì’-e;üM?]¾† VSÖ“ ×Ef?ùÐCÒ^–û]в}gÄÝ´Ã+ŽQ§`6VÚÕJÁ~“9ãIìSÐ’I&sËÐái²CW+QÚqôâ¡}lÊ/ûØtùØ yšêSþ,àðÌËÈÞ@'ì + WAÃŽ‚ÇSÒ2¤X¢±ûsñiá  þŽ¿kOL Ò +‘¢Aw³"ÂL"jÌ;cïn¦wÍçÓ;ßàžÆ§È5rhûŸ’hkDÄ|~%ã™"p<0U)§Æ–Ø`ZÄüÔÎ7RùOØçJr+I,ý¤-=ϬÛñ”Ѳã)#.ã ó0<±þâS§2oíú=]€Ÿ&ÙXƒ£p$Ö’,Š' öáAñ}ègd¾ÅQ¶w‹Žlæ\aßÕ9à%‚íê$é¨Sm~ŸúKCˆ¼©Š e)ŽGÙó•56`tÂ¥yzù%jÄc¢“<¼ÎmyHE¾(Âò…øpñ'.®Lm‰Í+yþ¡Ñi:½%·øþM¥8ÒÒ}ÑÉ]¼ËjúÓFCE9Æ$Z‘$)U3ŒIÓe9©z°ì%ž®¿$”Áì/¼õd‰  Øˆ¸ßrDô<ìaBŽ/oò@¾¥B ¥J-”ùP–CÙũÃ?°zl¸· ðôª>¾ƒsêI^)Àé3ýÊL“¸“.°,~Tí0]@EZѨ·gY«qw{mäXÑ„i­õ ™çoZÞ퇹-÷,Y6*.,òàƒKj âS"Ä6j³vw_TL?‡¥]sÇžËN_?ZÑOâ,'ÓÂì‚+, WX®,LêçE·Ý²¿óå÷.y3§îò68…j£ÒF#&I¥xD4dRqyŸk™Ÿ«%ç•ýîØÕ•”¼ñéçÒ-8a™GºIÛÊÖâQbÄ+¿­hž2‰Üø÷¿ÿœž6ûùàü;¸/¦ú……ÉÍa/çK‰ðu JM+ÔU¾=²R{QSK·:6¹„C5ZJ N:cƒ†{û<èX:8Ä4ö Ì_¸\hëʺ8wÛå_&.oìF-¤ã<¹.¶ÑìéÀK x¹¢<V. ¬]#µõÓ%—ü¨“THøÉ\°Aü¢ë·\î¼ÅšT›R;·á4!M8NÎt#ò0ù“÷ÀXÀñšx +ø’Öç>Ùq~±'”£ÉtîÎY?|-ÖÀÁܲë‚%ä]ñ±’½ÝÈúk[÷§ŠõâUZïØ[Úç’5ök϶QÃ!zµí>%§lßá9à%BÞáiYð +Ÿ âÊçÒlÉ)e¦uˆç˜É4X ¼‘™C¦z°•Õ#¥8Š_X0á ùj@Ú™§7_O&/$sSwwj*i=H>[·ahñ¯¿â|ÜûùðlÈ0_É/äç¯^zô®k‡ë¢‡ž;'㩟|B®|Äx¾ d>—É|dŸ'²åºÛ‘„\¡¤J‰1‚¼ù2%$2Ol`ælNà ó¹ìùØLÎwWZO­Û¬ïræ[YÜcÖF†ËRX?±|^hŸkÝ>µ)ª;~…¼ C›m:TÓ}I¤:¬ß{»µaO›ô±!IØV>  ‰ ~S©mœ‘¬ý 'uDT®'—Éå¥%òÂÊâØzAÙI^k<Šc±Âp¡ö¹ývÞöÒç^nÂ×Þ¾YtÅÁ$©ŠÇg _ šÞãâŽâ5V#~´¼TKÞînå&Z·v=Å-Ý@Ôòú¾|DðäÿáÔ†ñƶ¢¨ñG8‰ts©¿ˆm…äOoÈ¡ +ÆS¡¹}ŽçE+¼îÊõZÑr…­ðVÒðHÎYÚ • I¨ÑŒ5fQ854jq'> +vù‚‹ÑÉz…|äéìr\9åKÏÇøo¢7GuF EmŽîÒ) $½Z÷3›<î¿—U/—n§…ÊJ”VÊC˜®0ݸçá¦Ïp0 {ž,ýœ\\:ñV– í¼&Å{Á÷ýSü ôGgÇJC§Ð8 ag=¥êIr8±´8ˆgÈË.YÙ©çqew–”=…«£T¨ÍH­](óƒ<'–&=õê«äzrò³¯¾Š½Î‘Óäô’—Æ”a×s8g,9T6†»òoìI~¹y“ü‚=È“{ö\À«ñús{öœ#õ¤Y¢eðW üu‚•ÙcÝÝ)êî´ØÓ…’w‘’8î²w‘¬»tÃÜ +M]üäòxŒNæ€=…@åÙ…1yŠ237¿Ý€ßnÀo·ž”žÚÆojâÕÀoµ”…M±„[¤#Ž™{šò UÐÔ{µ—ù¯à_ ŒÛ6ÏÜ/B›ôè믒Ÿ,9‹JW's«sïY~zí¸Ó[É——Áš+8m94"êšRµfçšÁ)#¨XºÀ뽿dÌ…G?³kW‚aÏ{øQü·÷žé=²ê »lŠA6.( +î3Šô§þÊîVÒðÁx[XIS¶ ª'„4†a)g3_-Zɰ€ † 4sŒÆjÓjt#b«ñGýu*íú%’ ¾¾aJ²WÀîðb9i»—\)_Ø´$Üâuß#qþÍ©ËËëÎEEnØ<¥¦š.4!(+gÅê{¬'Ä6~ä_º;Ä+âu‡êmTúP|¨Œ¦ÑŽ;Íè¾Ó¶>^4 (`S„P„P„iu±Œ®D~<õð–d0 ì$–eŠ´š`Ìd!ÆDü™2(õ•E+ý½R-KÖ6ôÁ¸(\µ×°OùÄwRvý¼m*ï¬ðU7ž.lŒŠ&‘oÉ—äÇ|¦Æ<Î/îþ¢ˆð cRæÔOßÄŠ?x85tRÙˆpcfD^ígÉïXù-Ë׃‡R s%lþþƒ½“$.ÇÒ!Ž¢ •Ù_…J +!ð=‹1)HÛHggžp‹’]ýª»ƒÅ¾öýI¯yäU·ÀK +&ëÀj°^aÛäÛøjsÑ4þNû‡Þ7èµc£õÿØ\sŒî'î1à/¬iVÿ!ñ<à¶ù ¾eÝ 7û"8Ê|j¬iò ¤„'XGÌ!çç7qýóÀœZëÇ\¿ÑúÓšø–Åi}òÃ1â{Ö™}'Eç1(©rÕó¯[ýS…©É]&^´t>ŒþÿìJ#]ìŒt.PlwÌ’Úéëk»¤4âD¥¿†ÿˆ¹JÞºC\Äöö[…ïCãÀ9þç–öÜŸt#ï¼~“[B?zöy pªº'»2Ké '¡'m"6Z@•WqêÕüi"®GÄãçÿ½dèÄ Þbë5L>ózŸûKiH›vRF,ø¾ÔYOžëâb@D«¸ëYž^©ì>Û„QÝ5=ç¿R6ΔÀ[ Ê0[Ójj`^á#î}’ÛñÒÞ7Z:ÈâÞ÷'œ)|„£%ZÞý¹pVK, =rÇîÒž5¢Qw½ÒB/ø˜Q0àß“ÌP²“_W°R2#˜ÊGG Öô¼ògÇAq0Š«Ä,eB¥l\x¯CRð?ÔŠj¨G¶gøá”aν'fˆ·WÞ€ñCŽ +Íuó5¶&9Ô\»«_ºï¾¨zWwgu?'rVÁ‰Eeµ-{ʽoânNåíëìæ¥ U”Ó°ö'OKÄ:׎_WXøqK’áeš›üüæ·Ç&Ð] »¯ˆƒÄS`'õhuŸ™ÙÀ¹Þuõºp×@GÙQ` 弘/—Jï}j¡Zù4È«ç|CÂÕÔÔ³ƒAUÏÙ㬨J!o_\6(*"\é8`æ !åó. ›ûyèžÜ\×/h̃Ïrñ„LÑ—¬OY+Ž0“³äzKñºÕCç­:|Ù‡º;„¯@‡ÑLäÌN°¼0‚ý{’þ}'!|ìáª-”p9\õa‡Aìp£‡ é$Ú í-*DSêüvQR³®4F×ÏM³ºº^‡¡3ö‘›äæËÉéxÌw>÷çŽe&ä®-~`~Ñò†²Å-ÇpêMܧ¾Fׯ‚îÏŧ@¶^@Ù£}fä=ëÝC‘;…M·6¾6Š}b_ Ø—‰Á(¾L¾Ôœêl´ë€vЮcD覓Öâéi£—·i”‚G#6·ÈúQ/¶œ|=1\œ²Ì5*qÔýOéK,ØÁæœneo¨ªÀÉ¿`-Î.'no•%_µáåC’m˜Ô}IxK˜öË`—l/Û`ÏhJ6ɵ'ÑÔ‡dinÓËFh+”p(¶W>ò±;þ¥Y\ƒ-z2°µŽÔŒ\ü%>æ=eÜ”eÜÆgAoÕ–šK+r!بŸ¹¢šÎì <ñ›åopkf͹ïñªECWoÏ4ëLUÕÏ`7‡u8n*Ó_ —?)¾˜”ôé;z¥<·N@¶´ýs†øÈ½]ºGëIOe3eô®¥Þ¿´HGôüI³¶ L—û±ècGÉ×GŸ‰ÞâZTz]-ž»ÊóÉz}ÆÛ]ò3ßôbîdz¨GrÅXcî(A}©žŒÚ+âhEœC…œt våìcKáÕ‡y? +¢ó`¡Ž”8ôg ›BÁ¶æÁÐ<š³æýi’[Î_;.^^£µHÑ1=¾ÕH"ˆå›}ô˜†?f˜ÔøDyœŸwÀÕ»½&F°ï¥˜{¶’ïãƒS8MØŒMCLÏT˔弖’ˆÓ>Å…m~nõÐÆ‰CZ7pmÑÍOuþq¡þðömfMø´Ü-ƒspxׯx(Õƒeÿ¸‰ÇÛ‰ˆÚìÛEïzg„{·,”þv±ñÐ…ÞÀz¥ä© +F‘“§…’üI –nNxv»Aø—^¼œüs•Z¥1k}Ðýäkf˜G½4¶æ ¾=ó¡Ç¬‹¸ )ÅVYŠÇ­N:HZ«+àãñ;C;#z±cÞ+Eé˜ÁãRj¶?àö’/RÁŒ¬Ä†ïÈÂi¬$ó:OÐùº÷’ÁÜ÷l>µ}¾^ÃË~Ï®mòAó]æ ÂÔ‚³CjðçáÜAr%výê§rŠJr'8°Û¸ý„»9”¢q³šÃ‘éÂÞÎá;žæ0•Ýb]>ÈÎ:Þ ÿ¯2”ôº¡ rꕵä©|Žb¿çᣊD¡n²ë¹G“«âñ®oñ&2ÑZ?XHž§÷ó€1—ÿלð.r§á@[Nx¼+Æ¢X´åŽ{Cv)i…Ñ¡BNÜí4¾×K®ÐÑ +TØ÷9”†]#d ö(,á@ÛÒ¥vÙ¦Á½@G©•Ó²»¸Ô‡0§ù¹ô¸»«fêÜܯäò +_WuݽézõJòÅwØ7¤Ð2iéý¹‰žÅª/â/¥•Z¦[Gr¯dEON*²ÎãVTÅŒ[im²ŸÓ?Û’X2)66U^·`5¨¡OË(Çw» W¸Ñ +7»!TÚ8B¯àÓ-²ÇÚ)m™¢»­¬[È¥Uj¿¹–Dù +þ«CŠÒ¦.{þ÷¹5„ÛP7zaNõ 1:4÷€´~wwˆ9B 3­=»QEI倴#Žª¾µÛ_åOí1ÖS»jÐÓ[VüׯªûïßcdŸdùî\¢ß±P¿³æD² Þ~àÀöí’‰xÌÏÿÂcÉÎýL^p7Rqè¬;ÄÀKMûÞž’´ã/ÿ@¢—Ãb9ÜqrÀJ„|kÌÛ‹P2A4äu‚œ˜<|¡»ÓN˜J^º!aJæ¤@˜šYIF*Þ²¹2Î?btâ¨yÛõº!¸"“?¿xpDÐò-ÎÃÞ!™™KN¾ÃW=>|þ‰a±‡Ÿ| ¼K¾$äô/°¾%þ´µ0²ˆ|Kio!%à—ï¥ÐÃÚí+F’µÏnƒ½z2GÔúÐ[\,s$ÅCî6ºÝnwšædt{à +F7=v—ªÅž¨K4«©GÛjùú:_ïà'vö÷óÐm|üP¤ÞˆÕä8ùv~ÜGŽŸM€KN/Ç%¥VX³óùYƒWðEaåÏÝòâ,¹Óp\öƒ$;ö–ÿÖœšùJLjÈõN[÷á‰=wÝ{² B;½~éÚsº‡ï\cüwYþQî{JãÉåï°WDeÚÄEN®ÂXr‰çš.±þ)䞘‘‡®µÝŸ '…*°õ}®,{dÛ›DôKU± ž6R±ˆG–?ÈÎñwÈ¥J—X&•ÝÁsȤjY"U0êéÅX¥_ÄÚÑ®.Fão/ffè±îâùϵ䊨2Κ0ÎÉ5,ô×­ùyþFòué>cÄã‹õif³©_¿Ì¸‚üE>Ýö–E?`@x‚F›1rÔÂçÞùt£ýõîïù b-(ÉÔË8ÞyGÌœð¿Ýyû]ú9ýá‘Wß;2ÏvzRiJP[ÁÓ`WÚ»Ã>(W¿½1ûçˆ>°ÐCWîè·üÜ€PßµüŒsØDÚÏYOå0þHTK˜Ê=Ãð>Ð}UÌrAµP_ê$ûò»o2{ÙKöK4}Ð}‘­%è$ÊÊæ©¥»+zs$„ÒÀ-_éãæ;û±Qšh8ôƒ^Œò/Y6ú—xÿˆ•B®uæ„øÒ¹ÙuÜÈΛD³:#fߤcÜ£,—,³€–ÞyÛ^1e¯Píîy[Á ›­ëÈ…gqvªÛyBÈíº$­Ëß!~p‚¹ÜТcìXÞÔésVy«ú,ý iBt  Ø`ÌÃvã‘8ÒúOòO^ Ÿ Åfðþ‰÷î<Áûw} °üÛàW¤í˜—•¹Ñ ¯^Ææîˆ +ÔOÉG³H>èIÿ­c‡œ<öÇ×~ÁšÇ¥$’§æÂEp~ä4ΰ^·^À…äÅk4)-À[µýŒ\žÄŽF/#ø!0ÅÆ‹9/SB0ÖÐÎá,S‹9šÒ +_Ú?rxP`.÷4ÎÌëp¼uç¾§Ž‡ÅžÏq.*ï7av×%¾g;9»óR>[xðsÈßöº§éãž›0 +ÙÖÑL³·Jƒ[ø³µ”ËHè*ç^áÇ^½n]ÿýçÜ}LFSÉþ˜Ø"Q"¢Çk·SkweCË«ä_‚Id);µíwö ì¼ Œ£’þ"uë²BGúךʂÒ\GŸVRÞ?ÕϬºý¾,ÿm´_aHášC†ËäEú-0D¬Án‰©UiIÞ®øUP\óզܙ–DzÎLÔ<à ۶Hz6Ta¯Øþ_çŒéØ&7q†Ø~Ë]YÞøcàEð"ŒñõþíÔí’g¼p†žÞŒ¼ô“Ç,úã6zºn¡ž!+yÆÊzc *dxhf¿” •KædëÌÚ”ÒêIJÔTµ[ZPbð$ÿ±Ir ¿¯'SžÑ™gX׬HÌÞ¶äêÌÕ3ØÕ;)icùmm^DÈ¿°üEäÌÆ¿ òq‚XÇ;Cô¢Ct«qŒú]½ïéÁ~=Ä2ÇtwJÏþ¤MZ¢‚£F1SϬP³0vËœmñ ËHø(lˆonuÈî¼/Ö zJWâ“V¶7z +·r@¼ÂÅg¬—û´¢£äÑ9d„«ª¼rÞ V>L-n˜è™ñ;L@„.¤º=hûþ“t…»½ê< ¬€ôR$‘¹axÿ‚Û«¨šÝBµÿ«ÏÐ{C é4(»ÑUþêšÑ(c•輇‹áÝÜîî| ö g¡} Ô­„ïE\Z÷:hß*4ãÉð e.”ùP ¬zßÕPVÓ9 < c4ÊÅS¸‚G*ßÁ!0W”­PvCÙ"–¡Â´E‘†¶Q°ûkB[pÞÂÅq‡¹y'>ƒŸÏïã;øŸ7!Nx@Ø%ü!6ˆû>ŠVÅkÊTåå'N§ANÓ69u9w¹¤ºìvõqäú¬ëÇncÝžukswr/qŸïþ¹G„Ç=Ç{¶{•yµzux{y/önW¹¨²UµªVÕAU‡êGµ Þîæó˜¯Ê÷ßO4­š«Z½¶V»[{Þoªß[ýÂúm÷×ûÏõÿMW¢{E÷¯€á›¾Ô.Ü$ f:Z…ÀÊ­c¿V¥ÿ\èc÷Èð}®\P zN†1rƶö(j´ ó(?&ÃÒàë2,"/.L†È—›"ÃJdæ¾aÒðÙt÷'ÐÜ`_Î`® ~ƒE€ýø‡LÃ/~3ƒé%% ¿—ÁN ~ƒÁÔ=˰¢0µ¿Ê0Œƒ½e˜G8U†Àÿ¤ ‹HÏ 2¬@QœE†•¨š[ Ã*ëì +cöçÿÉ`úƒ+?Q ô'WB ƒ=(]B:ƒ½Æ1Ø`áAÓËUÂz«Yýûì/°[9‚/ÿ"ƒ5lÌ ö£´‹]ýÖ‹‘ öx€8”Á:ÚW\Æà@Ö~+ƒƒ(?E¶û‚é¼,†k™Á!lÌNGÑö +‰®4ÚFÏà,Q؉ÉN1…ÁŒçŠ f8+n4»î£ø;ƒ]XýqôM(êr`­5Aì\pš‰fÀÓÔϳ¡¦5Â~  [ÿTøÔ£bÐíFhÝzÞÄúæ B‡VÒ,i¬íèž6¥Ð£^P#jv˜=¯OHK3ÅšM¦}NSSC>o挦9-5³õESâôô}j‚¾¸®qfË‚¦}N¡^î’– MkJg6Ìi©›ÙØÌ: 4&m@sá“N8%\Ó0·¦¥n +€¹ ™j@aš Pš¨ÕÀ‹™ Õú“êfÍ©¹Û ú>»¦3êM@ Þ&AM«3³ÿƒJ2pĵ±§8 ¢wœ0]Ÿ`Š3U'Õ$¤ëͦ„äXSRlBÊÿ†FC#TƤÚ,s¿7®¨¬fv30°‡»ÍÛ3o_³ÆÒYÿ’uLôš õÓØ³¤r5Œž€ªªu¬¸êf¢©}*žÅuÍú*ýìšiuÍ 95Õú–ÙUÕ53ªf×ëgNuTžÿO,ÎðŸÍ©bXÚ»’Ý·¡äþš-›>D¡oàî$ª›ÎÙ蹦þhÝT µ_Ã,ˆ_ÎçOó'áóÒóÇ:ÁÓ¸ˆr¥æ›Ëp¨‡Ï6ƒÄU:ÒhUȸÚ|–€ø¥ø‰ø‘ø)¢ïÄK}bþJ|_üas Z×£?`ükÌ,ÔC¿Ùè^tjìã6Ësͼc†™™.™ºL?˜Þ6ušv›>6}O/"ôZסKH¿Ïôæá3KÏÓ³Ä26‚ê9LÖ6nØùÓÌÖŸÅU›dêdŒ¤÷×mÞÐ~ul!ذV#¤ +ÙB¦0L°¾MÂ!]ÈHª£.{&ÓMÚg:PÞ=õL™jCª»’q«gõ6^Õ1^ýµP*%IG¥s h~flgdú£Î¡T¾8a^€ƒaŒz¨Í0¢’×£aP7›ÑZ# @Uº 4¤2ºRd*éìï‚öÂJÓ£ +èó=å¹sŒóPg³ó0gÒ;«ái> +endobj +17 0 obj +<< +/BaseFont /AAAAAA+Helvetica-BoldOblique /FirstChar 0 /FontDescriptor 16 0 R /LastChar 127 /Name /F4+0 /Subtype /TrueType + /ToUnicode 14 0 R /Type /Font /Widths [ 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 277.832 333.0078 474.1211 556.1523 556.1523 889.1602 722.168 237.793 + 333.0078 333.0078 389.1602 583.9844 277.832 333.0078 277.832 277.832 556.1523 556.1523 + 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 333.0078 333.0078 + 583.9844 583.9844 583.9844 610.8398 975.0977 722.168 722.168 722.168 722.168 666.9922 + 610.8398 777.832 722.168 277.832 556.1523 722.168 610.8398 833.0078 722.168 777.832 + 666.9922 777.832 722.168 666.9922 610.8398 722.168 666.9922 943.8477 666.9922 666.9922 + 610.8398 333.0078 277.832 333.0078 583.9844 556.1523 333.0078 556.1523 610.8398 556.1523 + 610.8398 556.1523 333.0078 610.8398 610.8398 277.832 277.832 556.1523 277.832 889.1602 + 610.8398 610.8398 610.8398 610.8398 389.1602 556.1523 333.0078 610.8398 556.1523 777.832 + 556.1523 556.1523 500 389.1602 279.7852 389.1602 583.9844 722.168 ] +>> +endobj +18 0 obj +<< +/Filter [ /FlateDecode ] /Length 679 +>> +stream +xœ}ÕÝjQ†áó\Å*"éÎú«µµØ­Xo ìÔ@3‰ÓTèÝ»¾|¥Ý:¬w˜ÙÌs¶¦çWWÃæÐM¿»þ¦ºõfXõa÷8öµ»­w›aRfÝjÓžïŽÿýv¹ŸLóðÍÓán¯†õn2ŸwÓïùðá0>uoΎ׻Ïõþw=lúåûëÛûͯÇúv2½WuÜ wÿ}éæq¿¿¯Û:º“ÉbÑ­ê:?øe¹ÿºÜÖnú¯“¯ïýxÚ×nv¼/¤÷»U}Ø/û:.‡»:™Ÿœ,ºy\.&uXýõ¬ÌNyævÝÿ\ŽÏïžäµÈ.MÏš–¦µikÚ›Ž¦O›þÐôYÓ›>oú¢éOM_¾viü¥ñ—Æ_iü¥ñ—Æ_iü¥ñ—Æ_iü¥ñ—Æ_ÿŒþÙ±éÏ‘MŽlúsdÓŸ#›þÙôçȦ?G6ý9²éÏ‘MŽlúsdÓŸ#›þÙôçȦ?Çd.ô üB¿À/ô üB¿À/ô üB¿À/ô üB¿À/ô üB¿À/ô üB¿À/ô üB¿À/ô üB¿À¯ô+üJ¿Â¯ô+üJ¿Â¯ô+üJ¿Â¯ô+üJ¿Â¯ô+üJ¿Â¯ô+üJ¿Â¯ô+üJ¿Â¯ô+üJ¿ÂoôüF¿ÁoôüF¿ÁoôüF¿ÁoôüF¿ÁoôüF¿ÁoôüF¿ÁoôüF¿ÁoôüF¿Áïô;üN¿Ãïô;üN¿Ãïô;üN¿Ãïô;üN¿Ãïô;üN¿Ãïô;üN¿Ãïô;üN¿Ãïô;üN¿ÃôüAÀôüAÀôüAÀôüAÀôüAÀôüAÀôüAÀôüAÿó†xÞØX~/«¨ÇÜRÇ y\> +stream +xœ­< `“EÖ3ß‘ôL›¤IJÓãK¿$-mz—¦¥PBK)w[Z ,-¥\å(åTÈú¢|T€ú¡BÔ¡h „£!h(†ŠQ *EÃQ*G#ÐH4 +U J4AcѨ +CÕèæ?›ÉCÖ?Á¥ $Pn”2ø/;>äßáw´IɻٜBõÄ$'¶ çK%NÎ:ÚÉŽ©0‰&ã² +ÁYRRar:*‚3›@Ù••‚3°°f‚3ž¼ +ÎT¤Œ—J*„‰Â²e5‚3 ¤¢JR@ ,eU«+++N”XY):QIE]ee’“± Ðg©ø‚’ +'/æ;b¾Ñdªtâê$'kaB?>_ 5û1“`°@X&,ƒîšRy˲ҊêcÍðÊ +±êePa$Ô»‡Jrr6§² q?0¼ :?ÉÉë˜/ +N$æ×8™ñ¸tr IN…M T1…µ‡94^ =8Õ•¥º¥J)c D±É³T …ËIJŠtÒÈHÆ)axÏøNÖ"Öô“ûÙšx¾Ð‰kú%9ýmP$Nÿ‚A1¿Ò@Þ†Ã[¼%9l‚3”R(Aµ0–3° ZXV ü€9$9mƒË+š”¸_¥Ù\'ÎOrÙ—V .“ &(×Òò`[ +*QÑTä;+¨ÀÉXò›üɯøåÄzXÖRRÑ„aµ€=ùË`­aXÿ“Í<°Q®'M -©„™ýEPÚuå~g=›Òа.N”·cL™£*ùÂò +ä ó…j±%8ÃÎÌÏ_VÝÌ':§'caeBQ•˜ä µ5aò©¶51äSckbɧÖÖÄ‘Ï0Xrò©³5)ȧÞÖ¤$Ÿ[“ù ·5ù“Ïn6§_âmŽcwƒ6F›|FÂØä3 +Æ&ŸÑ06ùŒ±É§c“OŒM>calò)ÂØäÓlzQù°Ø`Øàj¡–ºº€®,¦9Á”ä´Úœ–D§d4$°HøEk²EaÙˆŠ[b€T$9ã½+õθ'Ö¥ÒÉu÷]ˆ®U 6¡¥3цœìM:‡mqÓAI9Ò7SÕ/OÌnJÀ:˜‰ æ „ÞœNÍšì$g’-ÙÐ+É™üG¨ Gµ€ž¬@z‹,‘ý K8pÙ²"±6iÅx#Ñ, G’1Ö…Áø©6  +dþS§¢0±nY²(½–A_iÕB²Ü‡“#Jª0QpV“-ë(­8À¬`<ÀXÙˆÊ|¢Uü@;‰[ì¨àúÝPM”‡¬/™‚ê ¢“-¨™ÕLAàj¢0®oS$’ûïD¡?Ì >è(ÐßM©Š‚šj²ö<C¯Ð#™‘…¿AƒESeçXÀòt²”ðV÷ˆ½`i2h±Óö‰ ô‹È`„[™tÉÈÜ+ŠÊ+’…^`VÅîBÐâ]r ¼ ”E½°V”¹t3±u³E$²ÛÃ=|‡/ÕÄ ]??³l¢L–¬?(Ö^•ÉMV»Îî-.ñ-ÎîŠ}Sœ›35ñ¦ö´9Ó—ÁÀDR€Úq€'ÉN+ æzÅ˳´D²DódØ!rw½lÄÊäÿrXô¿=B>Q*½DÐ>Ì6UºiìMÃ3ÿ<2“è^÷<¼SîSÖÉ;s?"›P›ì´ÁFtüNy_ÐQ8LëL8ßæL²j…°®B0Ežuêg#²è,°Ð¶¡^ô È¶Ó’Ð’§7ƒ !8JprFpPLpPBpPJprNpPFpPNp0‚àä0’à`Á!@Á!@%Áé Àh‚C€1‡c î°9Ó½Ë\E^œY£ j*Oð’ /56g†{/â΂ÊŸ»…çÀ OÌP›ÔqðäsË·η^-8Ì ½v€à¿þ ø<øç5ƒÖ’ +G8uÝ13™„ˆaØRIJÁl?ã`âžv©Wu©wè¼Uàû3ì‚úUV¶¨5šPN›ˆ3±¨e3”"cysÒá‰eÛNÙNñ­R”k sOûÏgé°Å®sÏ¡·LSá .åYŽÅ8ÁP]JÈ 5Á§ä” +š²jEh"fE­»nÓ‚ª­Tñ­®ffy€Â*ðâÁ8Fƒƒ‰sí°*8†Q)¡o ñcQp ã€ü+y̲AA8 8€¬D`Ç߃4ÆL)é‡ ñÁ·þ©Þãÿ[åÅvXò¨¿5: l¨¬tDEFFÆDÆDG#º…ô 4j÷O¨:J‘>òŠøXûÍ_.g_~ퟴ­þ ßdõáê ?¿öÂe扟lcÒpÅü’ä ÏiÇ©·’g®vþ²h~‡–癆 ,ü/G°û1i‘þ +NÉ2ù2#Ò‹•˜U‚)J¤˜Œx_?Ì åÀ—õ+óÇ~~ žJ¥¢ ):Y¶ ÿ¢e8mú_ö_þ_iý¯ÇŒ¿í–ª.-©·hûTÁ+c|c*nDâBá'+4K«ŽÐ†é5†C¢%Ëžgc³X­ ++z­=C•"-ÔôJF©Á¢Ýgµg( zƒ6Û³Ìì½)êˆaIófîiœ°ä µ®þŸ‘ã"_ݳÏ_ŸðȤ¶¢ÙqÙ'§í>®»ô™C47éôÖmsÎn3 Xûe¯â…}­±®û1ïá÷ùuÃk˜KP½½kˆ½Ž—"úæT–~nÈ ;qB{¬nÏ#}f©S÷—vm¸òÊcÔÑ¦ÌæWAœº"e ¯dæ%ÁÄ9^É!I?^1†¤Z`úcA)ÂÂûû£2’”*ðªO#mÄ(™©¿ÛòÆFñ@­ÕÿaK¢Óo!ÿbw+TDxœžj†Q­1Ç„'bc­ö<œ‘®ÇXÄYV1VËHϲûÖù”+»Eÿ²båÖè˜_V®Ø*µÍ¼ö—™x¥¦zäˆUmõˆ‘«¶ÒŠ˜è_W¬Ü¬¥EZZÇ®8sf<ìö«¸¬ æ±`ÁZø·¿µ¿H^à9=Øq‘OâÁLÃQ..q„æˆ!A‹’Í*{UH 1&e2+X–+E«Š1_†x^Ç{ôÅ-ÑÂyr¸ÞÂn¯·ðÛëÍz{½Åû¢©~ÍARq`++û<æGy Ï>=d‹0§˜ºD Ûø©$ 5diY…ÒÍZL™MÞ”Ú< [“±kÅ8x%‚ìɘ}v &8àÌžÑÁ‰¹3¢~Þš5\ßmEÍ̃Җ˜¯·>ùP·è†¾¾n³w§<ÅŸ¸<©nÈC›¾Üd9Þ_`ìWÖ·j5©wCek,^[•>xÚÜEÙ˽°àñ©y¥ÒK%ÅEK®nÒ+;*»øeÓ_úM¬_Eì +ÆóÙYÌ2ê7¤ÈËDŠKÁË.Cç+õü©1bÕ¬ì'0Ëžž3Vö`‘.HUì&þ< +CámRèjÔ~‡¡°pÒÔËôZ1Ç‘ÐØaµ6]6·w^´¶bÁøDM7•_hŸåc~ãÏKo¯øHúLºøÏ5Ò·—M[³cT1Žÿz5¶ Üñ£TżciÉXÔ©"ª1K‹´d,–ô­‰³²ÑØ W ɪ?2;¯w´¦bÁÄxµ.0¼Ïc~‘ªpÖò Ø„Mÿ\ƒõ?Ï®[xe–ôÁåµÒEXŸbð«NÂú¨P†#48(0Àß|%Žep0êCWì Æ$ÜÏH²J‡¨ §bB±ÒnP”qÊ8{œÝ`g®¦~«þf\ãè½£šþÖçõT¾õïCf½XôÊ+ðkæ°Ï` €;ö#§½9C懜ϰbG=!DP9ëIÒxª/Š\눦ˆc¹z¨eY4”ø~ìp‚‡ØþDo•(º1ʰD­Ýî‹Ii¶qsÕî*Ü,JCîØ}>¸’îáƒ$ë=E:‹_@m0Ç´*L–Ô¡R2 %¹q<Ô]†QaåµQ'ˆÌçáà1)Á-îÏàéÉï'v{è®sA#’”ʶÓw6ë¨|¢£ø"sYBgp„EC©D’éªC¡G-Ðüþ9N +`Ö¡möÁ/B‹lÒä&8SÒ®ëH#Eâ'ç’ϵµÉy}öYº/re>Êž½ÜGg·*O™?Âõï]î’6`CûÏHAb‡':>ä~æ7€UŒDce㦂ˠª°¨=Ò!ÏZ°˜ã[%‡r)ÐYì®c‰Aj±ˆV ô,˜3“gÕÂ.3 l#Æ2,¸ •¸c¹ùy‹KŸKÒ°¾uÇp¬¿7£ÇÞgÞÉKÑF½ðØGÜ&éŒôñqé‡OáÜ+ûpWÊœ+—>ùh雿Rݱ d•ï‡FÈ: H"”áÉ7.–šÌ~* `°±î% éZVRIÎQüŸ:ŒƒÕ³ ÁÞujï åÒ¹—.°?/ÓVn¿:ƒýY–8zþ)‹ævÆÀ8QPÈ"ÌN¾‰ðn£‰N4ÆÅ!ÜXËqìP7ËVVTEm4vë~ Sº†hûLT>ˆf–†ñ¿°ÒQk0Þ¹ðH]–p(qÌVÿó®XËê§Ÿœ‘g*«2·wO;ÎäÎÜ£¬~áêÇ/=6ï¬ôós{î*ª’•6jê®#X4MÙù–߈ҳ¥;þƒÑŽ¢Ž($°T“I  ˜ Ô“Xr Lˆ:£”ÊrðMuJÏ$ÞÐHÖNÁñ6öižìb+•¸ØÝ+V&ŠZKz?1ÔÏ1’,xvÙë±GƒU¼~Ýd+ N­¤.QcL>´üLDÌæ­‹6ÖhÕ× XcX\×\•³?¶bÖ}t*.ªÂ>dêh£M:ö«´~´Ï¬ ó×ÌÃø–²WÔÏ™Ÿ×–†×_9²dxFTLÓâ¿I6©[²»‘ß P0º¿¡Í—ÈÀ*^9ðh*>JÌóÁ^¿ÁM˜©>8žj‡@kàóõ¤ž(ò‰ðp@E˜(]=K6l0ë¶$âÿ4‰w°Ð⇔Ä_6=‚Q5 ñ +†'{‹+ƒÝ S¡`Ë@³„³§Ù"ãÒ|Ð-‘ÃoYG‘M¦gÂ'ы̘q°ÒžF>¨ŽøßÇbYE±WÁÉq­¿Ùl1[ÄP%°„„®Ä"yù/Z ˜ª®±wi?Ó-iÉúú–N®šÚüqZwéÄ?Þ¸44gòxÈ?–^1”mŸsÖ5ÿñå-œiDêhé©}LRüW—^‘ÞÅix +<Š'üæ2Ì8µqÓÃGŽÃœAð£aÏ„ öÔ&œ÷â±öËqüâ§ +¤æ—Žm¬ýoÄë~ØÛB]è)¸ï@ÿ"JG‹¦™a +ŠòšwÐRn±¬Oœ#Û0ˆäÐÁ‹Êè†Zž§žÁay`È!›âÖX½t®7ëcðÐÍžð…$“Hüj·rêÚî_©Õ-œxçsƒ¢]z߉ÈðÙ›¾ìú2Ï‹»ëŘ(àFIü ØxéôåsÿJ6>·´3•<øàèºÆ¥®W]±úþ†çbú•,ÞòÕ‡+,KIêÞc–Vé·/>¸÷Hš çfw|À]›Gro·(Ý{Š„ª%æÈŒjØ÷˜S€èñ¼Çàà +—{EŸ˜H+E†õ˜üGØdiÍØ^qv·òÁut¿èùb72bМBV³ 31º‹~ZVÒ’¬cÏB‚–äqª|ÙP>.­ð¾KÓJ_žøöÑÄî8é2ÎÉ5¥eßõ¦têÝ"[{ïÝK^¢êÖÖ¿G¯Í‰¾€ŽŠ™7_ÁñÒW›¾‘~{SzáãíLíÓ›šÖ<¶íq ÷ XÜ5œ‰æ‹{ʳÖyø® j'1í©Æý*[Hî“&§å|'~ç%ðp¦6×ê6™wÏJg™ 0FDd}„x#ôÌ”"’ëí3hhÌ€Fx«Y2^m€ÜqƒÄ DÉÀÚ °A§'ŸO4$}›Î'Ÿ?\’Î+ƒÚNטgàKÛd;¹ ã{þ .žØˆ<Æñ‰Z¬ôÓ²™û)îÚ¯ì̸kç˜*|ºYZ/­kÆoRúEù(6‹®QŠÃFŒ8b1"¹aXŸ¡$ELèd™Â›dÑ•`Íáá£Äkß‹ìaóµïÍlÖŽRÙîÝ„ГäK?¶ÃÌ\ ŽãüÚWÆq)ø doÆSñ”f)‹ø] ·Dþ, ! :y)-^¿ ì" æ‘ã˜2è+}A—˜'özs?øk.%®}u›hn??•½ÇríßÚ,åï’Tûd:ùÏNb哸›ÑÙ™ú¹¡^婇*’.½¡žÐv’Fò=ÒDü5{-®ýLsÎêJyü%jŸkд»ãCÅ þ ‹¶·èÜyBZñÈ!J"ÁËpteR*AöaˆP_,ÿn ý-|yœQEg#)Å(o[*CVÇjü $WèÝ`P´&;ÌRxöE:¿çDÐIæÄž3ÒŽ¾Ù[1w +gåH™ffé_û-µú´tmÖâa¿|‹“ßæWÏ–>ݺZzK:']•}™mí?´ÎL´ó=܈gµ%:d+È×$*_w¸M‰YÌ&yê â\un.•*o%1 ,ÇÖw©E]E)ƒ5iI‘pìÃ7îcÚï{CzýU.nÕ|«k+3îj³ÏEsÔo€‘:ý?Éù2˜ "ç|1rt|Èmƒ~µ>·EX”ÂbémTÞ%éë[¯êROVÂ]Å“ZÜ×ZÂD­Hr¢Íb­}À?&®èm{:~èréóm¯¦éé#†Ïzf€-þìI|ðè¤|9eÊüÓ Ž²ïÊ~òfàË\Ê—!‡üx°¯^ËLÏ9 +Ø.¶™ª¼…Ž`I3õž“Ê­ç ‹MþØ„y`Ã{'6°°ÖƒJ.i£ôå4ØÒ®LæŒËÙ¾šùì3 yiáè=›2 ¡~0Ñ/¡¦xËÁ4žgFzxÓ âÀjsˆNyï”ô=sÙÒ^ +,ú79. 6_YLyTr(8ÀwÞ*yÞøü>Cªä‰{K*úNý ^§ÖÈ*C ÉñYâHü£žfvãéõÖÃþiÝ\#O>˜xø¯|ë5+×vµ€­M:{çµîÜ…¤¬O2ÛŸòðf<Õuƒ*aÜÿ'k4j7k0Ù ˜0æøW«ôúߥÀvBÈhnûÕnÛµ1²ÿö|ÇyÅi°ûäD¿Â³kÝga79»ðVê»TBœG’ h”·š!ä˜o8·ÐÐs °i ˜"EÍ”¾ýÏ_“ÖJ{WÝÛ¿ÏË¿â9xiŒýÍ\’žê›éÄ:èr¹¼"•µu O?ÀƒpÂ{8Ô +þA/é”ôö© / s!ö S/¬Órp3$‡å&–nÍν¡^å©'F3õ7Ô“yЫ6 T H"…‰"".›‰øñøkfí«/'š¥Ÿ.Jéœât½fKs¦áÇ<Ë·~òúž×jm\ñ¬›RèPšéÐÒûH<•ˆCKÌ¡ˆpŒ¶{;D×|nL§×Õ՞܈ácT"d£r# +µ›Œâ¬1Òà§@þØ_I|r·L6Ðp9‡ôŽA)Z3!h¦NºÈþó±c1¦‰ö‰RÄÔlfÇŽñÇzD®œ^œ§CX6AyEo¨Ì¼KÊ]zŠlXõTN´ÀlM«r-Ù‘!6.>YÞ½˜IÛkäV¤]˨Ž\Õqžÿˆÿ¥ òä-ˆaA øÉ ÞˆåIÆœõ‚;›¨ó:C¿‹¬ï‚숽j¸Øt"éôD9¥$‰šdQæNoÉ!J +¶ÆÉÉDN)'~At úLÃŽ•߯û]m¨=Ñ·ïÆ¿é??.¸ö5Öf  ÚœGt†âÌ×^]Þï΄L©áÒ öÀm ‡­ò¶ÌÏH·$ÙzŒ=ôšô÷ÿÌë3{ÍøiéBjJlî¤W¯¼óØ£?óÊL÷žWz´—†ž‰—rô"a3ïSÓií5ÔÚûÔ5J=%R‚¿ÁkHÚT©É®ÀI-}k%µ…oÝwõß¼ŠÚ™ßÀ7$~Žœ™RÈ]L³L9H™Î«oäU—z´›½B®ÃtHg3XϪƒÝ§Š”µ1³çåX‹ý]×âÂØ—O;s&—“’ãä[Ûçl™ºeoÕ3ìcí§¤­’~Æ«p›“žë5hU bˆÖq§¹!úæzÇH.ì\¬`ºXr!]'’8W …ZCçZz2Î ØÌìþ{»óÝ¿ƒ±‰â¾¸Z£a|B~; +B•‡üÉå$ïÈ!<¼ÞhêÜÅ>ÆŽdôTê.'jŒÞd BA`õ4 +-¥@&‚ÐÑÃÀ ú`£msõ?WêÚynÐ3‚ÛM0€'®åº8Ø÷ßh˜Ã?¼#®3ƒLoÌr.Ó½&ò%O!1ÁäX–bj‚eïÈ$úã ú_Ä8âŸÌ ÒîßPþî{×ݸîé +ó/ðÞbÒ]™®f,={´Ü ´ø¡¢ƒ~¾¾@ì t±\A²+à±VA¨‹#Ð DP×( —zðøË8”éõ+bá©…à˜å1'ÚW»œL ‘߈·¾£º×ë¸óŒ7»öì­TýNJÙSí¾ð¬VÃjØaÿ˜”ÄOÎÍmoµp–k³Ë,×îÞÆMÙ·ûÚS$îK¦³=ùSrö:Á7{Ý9”úfÙk•oöÚ¤ÁQ6á£xqÌûÒ ïÇH‹ùS«;³šêÖŸ`«­¢ñ@?÷ÚÊLF¾<ò^t +vß—òå°ï…)ÊÝ'0»Yr‘È€|!w´IÓ™o®ŸÍ~Ó>}çA;á­ö™ rl7ÁlÞÃÃÏÇàÅRƒt_Rd®þu;!çW¦ŠN÷qN ë>éö¸ =åb‚¨‡ØùN¶ŒgÇjÔtÇ’‚Ù;Ÿ[(M}ž1€æØÊ¬sMeÇ‘µê8ݸáu@bDùl¢7 +;Öfé¹F}ª«´®•Mç/Bµe°Ó"X°€r.ÏËG¯1!T㉮D6ƒMäÊß¹Vlj:>æ6rÁ'ÍE?JOàYy~*èJÜߘ ½ÑœŠ¡€S‚>âËÀ ¸¯êÿ¯ófáíô'§­nÀ#w +eäγíN4òu_ˆ×åzD#u¹|#؆QVfJR¼UˆŽ4†ëQñ“³>}`™ä«& +}×Ô<˜Z0­¬œ/V’D2˜XÏýS;þj\í6s´eFFCý½z>àˆQû‡5ÞõøàãŽþ\ëĉŠKPŒ&Ê–d½#2„/ºtÏÚõQÂ'›æÚn_©‹T¨‚#S& Í„ùÙ“Ɩ I({mÓ€\ë#cYvi"_t ˜ÚòðÚçµÄjÍë¸È½ÇŸ@jã æ€vžó½{J“1Ô¥0Ð˼dá|ÌbС…3¾wOÿ ·°Ûë-üöz‹¿Þƒåp¥Óž©èÚ€sß,=dÃÌ¢;Anjè™@œ5Né½PLÏñ¾}³·T¿~<'K:ÑvWQb|Ôv¶Þ<þñ»?µ Ó‰U'ø® -•¾—®H’3Wú#î¼xðÜúª¦Ëd§ÍíøŒ[È CxÌQN¦V_—r5\—ÊõÜj¸YzÖp]*Wu[¸r¿·J'_߯æOôõ'úùýÞ*MmøSijƒ÷úå!s¬ÆâÎU{¯“}œ®r,c×!nÒ>~ä¢=3ŠbÅÑ«¶¤ï,}uì#i½ðˆ÷ZZ™Sµ옾eëÇÜyþ$Îø +GàžNqfGo…=ˆ¢Ð:G –¨À\õ•×^-Oç ˆÓP¨ëœo._£#Ê€å&Ób-ti≦¢ŒF"Š)‰^ó\Ô¦7ä„Ý{DžÎä/|+1ñž»>Ÿh©aT I³÷J§ž)?>óÀkYi8ûâÝw^xãÍWΞÞs™]=˜‰ºš·¶¶']ýhaG·+B‘ÈŒÖÈS¶"÷¥E%V€šR J NÃPàÑÄwn›^oDæcv”Ÿ§¹ü¨¨(s”Ùb¶jcÃü€ãz¥^irçî2ȉ¹+Îh)ÏYwèÄÝgá±Øþcô¤õOê%6…MÏ­½·pøëdÛñØÏ_š¯ê–¼÷ž·Dö¡Òiƒž}îäYE¹+“K"CÁ„+0ÈziåÜþ÷cÈ&r1˜ÐÈÞíç“©F3N’úù¬›œ{/ C5M—ß ‡%WÅI +V“‘Fîú>%I1+”îoGÙ3ìY Þ¬6ëEc·Àáé–ýÑͯîumôZs$?o,Ã<Ïà/,oŸÀn^¾£Ø›”˽Á壔„œu £TR‰èŽŽdí'ûa…•‘3Áò]ºÐô{!TÁvó†+Ižô¾iåä›6"×ÖÜøJصä«!×·ëÄ&G&¬u’)Él5f­?á«ÁžÁÊÙY{†'H£™òVéÙåÔˆ³Í6kÔö·G<#½±÷MÝ!&&õ·ÇeÛŠv.|á\ï\ttѽ­ï)ÄÕßsbNßÈÄ{8N,x¨=ý̼¶MÛÄõZ5ò“á%¿à(ˆÅ’ŸÙ?ncKë¾Ú%§^’óªK`;n GE-Œû|B>†¢ÆÈ=CçI«^>iíZ <>¨… “¦83äk\Äãµn!eEÜÚõ¼Cº†ÞJU—Jzb€ë»VÊA†çâ +K\O<ôù!œ}ÈvˆK¸ö>ßz1‹¥¦Ò †ÈW9¯Çáì°lˆW¿«9z¸Õì\WYy0Së>?ÁÇÄËÀò—@â˜~ͶfWÚ‚lðòš¥önéåû‚£¢¹ïÏþ–ɉc¹ƒ×ìs{ŽgX˜ÏbàÛ«4þ¬sóÞèSíIŒ‡\«=™ñÎ +w™çRa®ËÓ“0”%Ü;¼÷ “ò•¤ÆâW7Ø ÿn|JšéÏD.“fȲôðkîÿäÌ¿Ü,½Þì939P´ž¶¢†ƒÏqdªÄY×)0Ç¡2r Ø­„eð‰7»Q ¸ŒÄ`†NG7’âëP8šœÐšµb˜ÅLî*ƒX¸…Ù@\/·L»EÚG¸'íJs'ÎZÜ׬+>P÷ARxôúcOëGzH\rh!¤[ÃÄ7ló›¹” ÅæÞ}ÌýG–m._î²3—ëK–ow­dŽMOüôÛTðå=¹æÛ ÷îI2] MÐbªÏº^‹ÐËò~«ÝÒe·V4˜ÃDy»*}f'{ò¹Ä¤ÝBõ±É—’#bWzBj\ä°÷ÏÎÐßIæQ5ü™QÏ’-;¾×„`}~YS\oÞmìø; >d +ï¼Kæ>ƦF‘¦OiúJ#ËŒòVƒ ´oÏÙóäé…™ÜžŽ†m"“Žn{Ój®{îÀñOíÒ‹Ò/Ÿ¼Ú£'ùõÛ_0Ý×U­iß¿ûÙ-¹¤pb;ÄDé;YŸ¥Ü;ªP,69Ô°’ÄL¾'˜ Í—X®œ8:ÄkWóïÕHú*c±ûÊÚõ(¡·×Sø-ÐÂ;ÑŒ·×[üíôF¯’r<æÆ^IëÝî&¾Æ*Ò‹ napGî a¢«ÈWMEöS£F8zlzOS„6öè¢÷\ÛöEœ|÷ÁöAÞ¸ (!qN3½xlÓ± ïµý]æâòñ½¤o€9Ï®×#z ëàËtàËYw°£ÇA½š‘Sit±‰ÄðØM°ìx¸ó 2Ûn†Þ‰úǽ„ýq/ú?îŇ£žðhñ·@ó¬ò8\‡I뽡¨6XM„WÞä:Ý4Ô¿À¢|™”zx¬iÿ‹Ós…hCüá¹ï$E1³b„ÝÒ‰–¹½›îÜ}¾§¼± qÖ¬ôŽgÞ|ïQæAsÿµW­ŒuÀ„5 yt<»x¥FóäU ñ Î÷ÃÈatø‘,¹Inæé©Ñaκ!Hí¢Ox,ÿ –q+fo¥l•,¢û–)ý¥Ç…=5mwœp²žŒ}øP·ûA?ÉÚİe™}® „î¸!Ü`”ŒŽÉb#ÊÇÕäñUº“¬|¹7¾‘ãÕNT߃‘ëqoyŠÒù÷NQ*º(iù%%'‰Ú¤Îc”ëNQ@ußì…^4¦í˜°[’;ý¡û³ë"Ìù÷ÐÔð]~‘)ON\  +é%šu8g´-]»øã“F\2:uÔ¨1…f}”96aà}^\>zrïô¢aŽþ Ý´Q)¶Â5Oœýp‹lïwüÈ|ÇM?¦%˜J7óÑTrߌìdž: +ìó}EGt (âƒÅЀAkÎ/‰ ò÷`Ü3WÊi+3à7:vÇì^«M ŽÖE› +ãõѯ_³’-_í*ÌÖbf¹¿ß}“˜“«é]œ/¸—¹ˆmv·¨Ü7IÀ åÁ«Ã!òáJ§ÏDÔ‚ÁS…ÞËáá^•pÓêÎøðw[Óo±H9XÄVȈî90 ƒYf&§¾§8¢]!k_»–1®W‡xqr¶©¡ù‹]bjï«¿LŒÚÄ¥¸r†gVïý£ºvîéÞ åO„ù@æÙ fƒ5 ù_ìßÉG6!¾G6•Ê…¸ßMOlðñ:|é¤ë‘—vp)íØÉ×Α¿ècüP—„úúœÙø΄üÎá eý-ÎfðQ#^rZÀ7»¾:– -<6Fnf‡´a‹®c{·¿£’¿‡†¸¢l÷ÙL'Á²*êrƧ¥0ºç† jð§£Â*}³l“ºcþ«iç%ü=—"=„ð®k®ð*ic‘×Ö( äÞ„qÑÅý‚Å`òYìÑfårP¨·XåAäXŽzþô[pôV;›¡å¸S½Îmžteûfk|¤hëšž¥SÞ¡öÌD.e’´Rúîib³Âïù`…)Üo™ÖNu\&Ì›¬»¿¯ç%ûõ·>r!ÑÐMN\ØhWs,›Óþ5³,¶}ñrm]íâ·Ò¹æJUl+‰Hq@ÇáøD^AU2=ߎ#¶¨ m:¿þH´^*,Ómß« 6C˜uOøÁò”p1þöðçË“#Â…¬ñ'[ÍÚh~ãs5{_{kzŸÙÚFÝŒÞϽø±®Qµ¸ÿ= ëJVjÔëËž×{ì×;ùw`Åu~í¸óøÅ÷ôÀ[˜ Îù»q¯ÝÐŒžU¼ó(ƒy˜a~0luOvÛËsà”vÏw+þ$LTG?.åu·Š0›½áÍ)[¢t¥¹Û´½Q¦hû„/2-Yß°¤ß]ªFÝ£•ÍÏ5äÍÒ6jæ:êß:½C;WõÄ£ëW _¯ÖйŒÄ~8sÅ’³`¢”¢æÉiìžb&‚áÙ1ÔóäÈÕ"bA(Çpõ7Á"ÇzE•‡,Zk¬ÆJ=jhâP>HÁÄ€’ó?ݨ°€Ùå˿Շ…„öµŽ)›;(=Uþž4Bo-Ü0z\H¯ÿ01~ôýÝì ÅžÏ_—µÇ­ò7qr¥ÌG¤è.u‡M¡¾GÐ*4éïO ¯!— ¦•CŸï™ ØÆÍFUðÌWFaÄDâ‡ð|fºÀìêø‘ÂÅÜtp§@ÙQøÜGÚþÜl¼ >ðL€gEÚ ï[¡ÝB(ß }mV좸›¡þy‚K?O¡f€Wq_àL€ãGâiÊÇñP–ðxè/úI€ç'&§£}ýÊÍî8ÍìÂ-Ðg<ó`Œ¹ð9ž…€×ŸdM–àSäéX õ‹~Æ_BÊái„ÇÏtX“G ~´;ï»þèø|Âc„'“Ùƒr™0´‚ÙÓñÌŸ\ž §ÿÆ£ux8³‹mäqÏsm¼ŠïÏoàßâ/+YŠÍŠ‹ÊråU¿*³ÿ¯=Þ +¼+pO࿃‚‚z•½ܬòSm‰Yr14>ô¨šS§ªTŸÑ0šrÍÍUíHíaUaWtYºÇt¯ëÃô£õëôm† Cž¡Áð¬á¯†‹áÍÝEÌ‹øÙ¸Øø^äüÈ×¢ü¢Ê£žŽ:½%ú‡˜£Â +á;Ó:Ó± ±ÏÆ~.F‹Uâñ}ñWs/óÓTFkÐ:ò§[hD˜‰ú"’¼xžÝæ–µLfžG’Q zÖ cäO¾sênÚÑ ƒæÁ Ü0‡Ôø¤æQ(þÍ +šIvÃJ”ÎlwÃ(w‘ï–Óo&¨Ø +“/+Ø +ó´<ŽÂ +²gX;…•±})ìGË‹)Lfµ…RE` #ü䆡¬vÃ,†»»a"á­n˜‡èë‚V X&À +ÑÆá†5Pþ!…¡O=[Iá Jç, +¬aŠÒ¹–¡ç9 +«É·>ØÖPúSXKñß píG¦GGÛþƒÂz +_£0¹¾”¸Áç &7ËÍ\"…‰®Qq¥Ž¢p …£i[™æB·Âä9ˆ{ˆÂ±´O™þг“Â9G¦?Â/ØòŽ{›ÂtÍ9J¿¥™ûšÀA˜Žû …H9Ï¢H@i(þ¥¢$”¿SQ”õE ðoª¸ÍDÓám.šïP2$·‚ÁÛ>~ hš53oà×Ñ~Š|°äQr(n¹§ ZL£½Ohší3Ú)¤åä¤&¥§¦f }¦Õ 3§7ÌS×( œQ›,úì4aÈ”3ç,h¨ú î&9iB9))›9mîœ)3g̦ ƒNCóà7°6%P7m^Ýœ)µƒ’™å³€ :x?mʬ¹u7k%\‡›K'™ +D§‚É„’4Z–Nÿàu˜x*”&œå3¢à!WHKMNY—–+¤§¦õHJÍLJ˺qoì Ê$Œší^ÐéB#ëgÚx½Ù@I¿;PÒ-—e +å ¡|}—%§n„Ú ð6>ÁO€Ì‰¿+?>œ2[¨ë&M™ P7A˜ÓX3¡nzMc½0s¢¯ ü·ëæ‹ÂP²°nóÆ÷Ð R"[„I¡Z4àK0QÄnbCäO¾ž4ÚO£mäÉÏsoì‰ÿ”ÿ€?ψþkþc€¾¥mçBw¡ïþ®-f"”º+õýÔoSÛS÷!ôBêk‡O-9Óì¥c.]ÀNúfÓÙOƒß7ÎA~ÿÞÓ¯·¾ìI—Êõär¹<®7ü j¡Bªê)ûämZØü–©rµd”!tc×>a8R9TþªªXùÊe!ŽL’p +Ÿ”öIîÑ ¹l¿ŒžMG¯€ÚoÉÜüµþ6ÿ¡þéþÝõ-‹ê6—ýñ\…ŠþŠ$EŠ"­Ë¼)ÏeÛŠ:®Àƒiã~F¯¯hÂxyå?p'k'û9Y±Ái(¨V•v*ÊFW83ÎøÊê‰ä¯N{ÿŒïx'#öÛˆ ûƒð+ ~Uîçâý ‡÷Ûä§LhRà~Mfüpi…ÓñpE“‚í×d%o‡9D^åPý0îXêäoâQ¿ÿíu†endstream +endobj +20 0 obj +<< +/Ascent 750 /CapHeight 717.2852 /Descent -169.9219 /Flags 68 /FontBBox [ -932.6172 -480.957 1571.289 1138.184 ] /FontFile2 19 0 R + /FontName /AAAAAA+Helvetica-Oblique /ItalicAngle -12 /MissingWidth 633.7891 /StemV 87 /Type /FontDescriptor +>> +endobj +21 0 obj +<< +/BaseFont /AAAAAA+Helvetica-Oblique /FirstChar 0 /FontDescriptor 20 0 R /LastChar 127 /Name /F5+0 /Subtype /TrueType + /ToUnicode 18 0 R /Type /Font /Widths [ 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 0 0 0 0 0 0 0 0 + 0 0 277.832 277.832 354.9805 556.1523 556.1523 889.1602 666.9922 190.918 + 333.0078 333.0078 389.1602 583.9844 277.832 333.0078 277.832 277.832 556.1523 556.1523 + 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 556.1523 277.832 277.832 + 583.9844 583.9844 583.9844 556.1523 1015.137 666.9922 666.9922 722.168 722.168 666.9922 + 610.8398 777.832 722.168 277.832 500 666.9922 556.1523 833.0078 722.168 777.832 + 666.9922 777.832 722.168 666.9922 610.8398 722.168 666.9922 943.8477 666.9922 666.9922 + 610.8398 277.832 277.832 277.832 469.2383 556.1523 333.0078 556.1523 556.1523 500 + 556.1523 556.1523 277.832 556.1523 556.1523 222.168 222.168 500 222.168 833.0078 + 556.1523 556.1523 556.1523 556.1523 333.0078 500 277.832 556.1523 500 722.168 + 500 500 500 333.9844 259.7656 333.9844 583.9844 633.7891 ] +>> +endobj +22 0 obj +<< +/PageMode /UseNone /Pages 24 0 R /Type /Catalog +>> +endobj +23 0 obj +<< +/Author (anonymous) /CreationDate (D:20240628153010-05'00') /Creator (ReportLab PDF Library - www.reportlab.com) /Keywords () /ModDate (D:20240628153010-05'00') /Producer (ReportLab PDF Library - www.reportlab.com) + /Subject (unspecified) /Title (untitled) /Trapped /False +>> +endobj +24 0 obj +<< +/Count 1 /Kids [ 5 0 R ] /Type /Pages +>> +endobj +25 0 obj +<< +/Filter [ /ASCII85Decode /FlateDecode ] /Length 1565 +>> +stream +Gatm:?$G!n%"7lRcssYV9Ln^9R69"&duY38`n>6VqVkm1ck@OEP24Ucod^t8L4kVp4bP)HB;@'&*U+beqI',G3!!^2n@"%$!ob.a`>$62#\-Xa/!Ws9rq3-0qM]LQqOj62:,mo`-`gk?K$&7,2TL1ooZAMN@[9Xo_!-h_ZRhXW]uh[m@9.GLpfcAcQOM7kW4XWu)-R7[KV`+e6Fo#0Gu`q%W<-.HXt3TNTi]nsQZk=AdV&7!oAu6Kk`*6+LJ/kbQUO2AMko9)U5$c>RAK-X2E*Y>PgElnE`06oG('+(EQY=AehCN[.e\O%oC@$Qld=s,70j4iKZG;8jPWWgLk6")KCa7.inc*eh4XX*./u-_I1Z>\([&URLqc7R7mWQ(oQ_mmd=g)n?(k+L_k#4s"Hj>kba')*'3t?S,bMq>%)!EE+!;Dj8&=:A1r;ufa)H=s-"s]"eub1^3Xd3$W1fdSo@,WCHNGsH>JR8=6?4a8qX`cn>"S)jTs)^Qohh%g2QS5$Gd&=fo2OVXa2(i'(0S4*:c+.aMbcmZm_i_Ng:IMDL.G4U5$FKWpAhiQ>jYL$A@$bAQgJI)n4]5[.>'G*=5X@:_#&o)CFQ;Q\AFm`7DQaLT=TQlh_9^TZafWIkuEgk2Z?ZnSJ'-+!Cg:eDPP_l0%)8[`&7fW`+epWaYMH:EEiX9B6^BXS+1Y8hat4G\L;Xk6q-8>8/o?:CkEt,N;AY;rq:>&=8?VCrL4[Q9/i"q3m^iY-+n]j\d&+&2pRXQ#46+($`Ur>C*:j2T)5Zce1)/nmQC_a%`]sB$1c="BF%)Af'bJ.sXpdUHM`L?IsMCr1L[PA3O.'r/Bs]10uAa=+i4T+OTQ^IhoH<5(kXIJkcR1o;MC4XCh"EqY'*#9N#km^T&E2("_!im>16KSZ?nAPP$M3)I4f!UoQ?U3\IQmXu/6h/LMj1fGg!*BgOCnk[_h7b\.-"<*L:^)Ud>J%Sr2*+fI1PfN8H?AtZosXXEI05p"JPI*4Wlf\EeKXIKeL@5'P-eG!SlW9O9%/oL1g9jrn7b>)bL8f6[Ca\a5od;M_1(e2CF6U;6SH'+?Bn!+Ya2[1?eF&C0&sNk^Cgk3:7$B@*fBknF7ua69$=1]dVZsQF&>#>OF]EKB,:ERa1J_KVm0C1m'V6P)au:d*In4HPl.*U/aduSHngK`CZMN9.lak+'bd6DuEt!oASs5I[344bEMgCRcG,?So13GRGu(9``%lVQ#205e44pU,b^'sp\(FDC:u?Oj3dW&kU1q:*tOFcjQ&4gApNs7V3&uW:QoVkaL51=eH!s:9$-=/gNY%MMS:&gU%'!=mB\2L=$pJ7k5l!8rr]:sFXR~>endstream +endobj +xref +0 26 +0000000000 65535 f +0000000073 00000 n +0000000155 00000 n +0000000262 00000 n +0000006539 00000 n +0000013929 00000 n +0000014245 00000 n +0000015003 00000 n +0000033943 00000 n +0000034202 00000 n +0000035321 00000 n +0000036066 00000 n +0000050109 00000 n +0000050361 00000 n +0000051434 00000 n +0000052194 00000 n +0000063962 00000 n +0000064233 00000 n +0000065355 00000 n +0000066110 00000 n +0000080203 00000 n +0000080466 00000 n +0000081547 00000 n +0000081617 00000 n +0000081914 00000 n +0000081974 00000 n +trailer +<< +/ID +[] +% ReportLab generated PDF document -- digest (http://www.reportlab.com) + +/Info 23 0 R +/Root 22 0 R +/Size 26 +>> +startxref +83631 +%%EOF diff --git a/utils_v2/goog/base.py b/utils_v2/goog/base.py index e392163..1aef5d3 100644 --- a/utils_v2/goog/base.py +++ b/utils_v2/goog/base.py @@ -232,7 +232,8 @@ class AsyncGoogleBase: url: str, headers: dict = None, json: dict = None, - data: dict = None + data: dict = None, + content: str | bytes = None ) -> GoogleApiResponse: """ @@ -259,7 +260,8 @@ class AsyncGoogleBase: url = url, headers = headers, json = json, - data = data + data = data, + content = content ) # Note down the results: diff --git a/utils_v2/goog/gmail/gmail.py b/utils_v2/goog/gmail/gmail.py deleted file mode 100644 index 19989ad..0000000 --- a/utils_v2/goog/gmail/gmail.py +++ /dev/null @@ -1,936 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Monday, 25th Nov., 2024 - - OBJECTIVE: - - To manage e-mails in a GMail account. - - REFERENCES: - - 1. Quickstart: https://developers.google.com/gmail/api/quickstart/python - 2. Labels: https://developers.google.com/gmail/api/guides/labels - 3. Messages: https://developers.google.com/gmail/api/reference/rest/v1/users.messages - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# My utils: -from utils_v2.string import json -from utils_v2.string import regex -from utils_v2.date_time import date_time -from utils_v2.oauth.services.goog import GoogleOAuth -from utils_v2.mail import mail_parser - -# Related to Google: -from google.auth.transport.requests import Request -from google.oauth2.credentials import Credentials -from googleapiclient.discovery import build - -# To make API calls: -import httpx - -# For asynchronous activities: -import asyncio - -# To work with date and time: -import datetime - -# For working with datatypes: -from typing import Dict, Literal, List, Any - -# For debugging: -from icecream import IceCreamDebugger - -# For computational help: -import math - -# For base64 encoding: -import base64 - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AsyncGMailClient: - - def __init__( - self, - credentials: Credentials, - http_client: httpx.AsyncClient, - debug = True, - debug_prefix = "GMail | ", - debug_only_errors = True - ): - - # Prepare the debugging utility: - self._debug_prefix = debug_prefix - self._printer = IceCreamDebugger(prefix = debug_prefix, includeContext = True) - if not debug: self._printer.disable() - self._debug_only_errors = debug_only_errors - - # Accept the input configuration: - self.__http_client = http_client - self.__service = None - self.__user_email = None - self.__credentials = credentials - - def enable_debug(self): - self._printer.enable() - - def disable_debug(self): - self._printer.disable() - - def debug_only_errors(self): - self._debug_only_errors = True - - def debug_everything(self): - self._debug_only_errors = False - - # â”┓ â”┓ â”┓ ┕ - # ┗┓â”┓╋┓â”â”┓ ┣╋ ┃ â”┓â”┓╋┓â”┓ - # ┗┛┗ ┗┗┻┣┛ â”—â”» ┗┛┗┛┛┗┛┗┗┫ - # â”› â”› - - async def initialize(self): - - """ - Call this once when the instance is created. - :return: True if successful, else False. - """ - - return await self.__build_service() - - async def __build_service(self) -> bool: - - """ - Build a service object that can be used to perform various activities. - :return: True if successful, else False. - """ - - try: - - # Build the service object: - self.__service = build( - serviceName = "gmail", - version = "v1", - credentials = self.__credentials, - cache_discovery = False - ) - - # Note down the e-mail address of the user: - profile = self.__service.users().getProfile(userId = "me").execute() - self.__user_email = profile.get("emailAddress") - - # Done here: - return True - - # In case something goes wrong: - except Exception as exception: - self._printer(exception) - return False - - async def set_credentials( - self, - credentials: Credentials - ) -> bool: - - """ - To update the credentials. Needed for the times when the access token gets refreshed. - :param credentials: Google's custom 'Credentials' object that describes the OAuth-based access details. - :return: True if successful, else False. - """ - - self.__credentials = credentials - return await self.__build_service() - - async def __ensure_token(self) -> None: - - """ - Checks if the access token has expired and refreshes if needed. - :return: None. - """ - - if await GoogleOAuth.credentials_have_expired(self.__credentials): - if not self._debug_only_errors: self._printer("Refreshing Token.", self.__user_email) - self.__credentials.refresh(Request()) - - # â”┓ • - # ┃┃â”┓â”┓â”┓â”┓â”┓╋┓â”┓┠- # ┣┛┛ ┗┛┣┛┗ â”› â”—â”—â”— â”› - # â”› - - @property - async def user_email(self): - return self.__user_email - - @property - async def user_profile(self): - return self.__service.users().getProfile(userId = "me").execute() - - # ┓ ┓ ┓ - # ┃ â”┓┣┓â”┓┃┠- # ┗┛┗┻┗┛┗ â”—â”› - - async def list_labels( - self, - raise_exception: bool = False - ) -> Dict[str, dict] | None: - - """ - To get the list of labels of this user. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/list - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param raise_exception: If set to True, any exceptions that occur will be propagated, else they wil be - suppressed. - :return: The list of labels. - """ - - # Start by assuming failure: - labels = None - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # Make the API call: - if not self._debug_only_errors: self._printer("Listing All Labels.", self.__user_email) - api_response = await self.__http_client.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{self.__user_email}/labels", - headers = {"Authorization": f"Bearer {self.__credentials.token}"} - ) - - # If the API call failed: - if api_response.status_code not in [200]: return labels - - # Else we format the response: - labels = {label.pop("name"): label for label in api_response.json().get("labels", [])} - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - labels = None - - # Done here: - return labels - - async def get_label( - self, - label_id: str, - raise_exception: bool = False - ) -> dict | None: - - """ - To get one label of this user. the label will be identified by its id. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/get - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param label_id: The id that Google assigned to the label. - :param raise_exception: If set to True, any exceptions that occur will be propagated, else they wil be - suppressed. - :return: The list of labels. - """ - - # Start by assuming failure: - label = None - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # Make the API call: - if not self._debug_only_errors: self._printer("Getting One Label.", self.__user_email) - api_response = await self.__http_client.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{self.__user_email}/labels/{label_id}", - headers = {"Authorization": f"Bearer {self.__credentials.token}"} - ) - - # If the API call failed: - if api_response.status_code not in [200]: return label - - # Else we extract the response: - label = api_response.json() - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - label = None - - # Done here: - return label - - async def create_label( - self, - label_name: str, - label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = "labelShow", - message_visibility: Literal["show", "hide"] = "show", - label_text_color: str = "#434343", - label_background_color: str = "#000000", - raise_exception: bool = False - ) -> bool: - - """ - Create one label for the user. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/create - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param label_name: The display name of the label. - :param label_visibility: Whether, or not, you would like to show the label in the web UI. - :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. - :param label_text_color: The colour of the text of the label. - :param label_background_color: The colour of the background/tag of the label. - :param raise_exception: If set to True, any exceptions that occur will be propagated, else they wil be - suppressed. - :return: True if the label was created, else False. - """ - - # Start by assuming failure: - success = False - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # Make the API call: - if not self._debug_only_errors: self._printer("Creating One Label.", self.__user_email) - api_response = await self.__http_client.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{self.__user_email}/labels", - headers = { - "Authorization": f"Bearer {self.__credentials.token}" - }, - json = { - "name": label_name, - "messageListVisibility": "show" if message_visibility else "hide", - "labelListVisibility": "labelShow" if label_visibility else "labelHide", - "color": { - "textColor": label_text_color.lower(), - "backgroundColor": label_background_color.lower() - } - } - ) - - # If the API call failed: - if api_response.status_code not in [200]: return success - - # Else we note down the success: - if api_response.json().get("id") is not None: success = True - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - success = False - - # Done here: - return success - - async def update_label( - self, - label_id: str, - label_name: str = None, - label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = None, - message_visibility: Literal["show", "hide"] = None, - label_text_color: str = None, - label_background_color: str = None, - raise_exception: bool = False - ) -> bool: - - """ - Updates one label for the user. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/create - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - NOTE: Both or none of the colours must be updated. For this reason, a simple default will be chosen for the - other if only one is provided. - :param label_id: The id that Google assigned to the label. - :param label_name: The display name of the label. - :param label_visibility: Whether, or not, you would like to show the label in the web UI. - :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. - :param label_text_color: The colour of the text of the label. - :param label_background_color: The colour of the background/tag of the label. - :param raise_exception: If set to True, any exceptions that occur will be propagated, else they wil be - suppressed. - :return: True if the label was created, else False. - """ - - # Start by assuming failure: - success = False - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # Format the JSON body: - json_body = {} - if label_name: json_body["name"] = label_name - if label_visibility: json_body["labelListVisibility"] = label_visibility - if message_visibility: json_body["messageListVisibility"] = message_visibility - if label_text_color or label_background_color: - json_body["color"] = { - "textColor": (label_text_color or "#434343").lower(), - "backgroundColor": (label_background_color or "#000000").lower() - } - - # If no value was given to update: - if not json_body: return success - - # Make the API call: - if not self._debug_only_errors: self._printer("Updating One Label.", self.__user_email) - api_response = await self.__http_client.put( - url = f"https://gmail.googleapis.com/gmail/v1/users/{self.__user_email}/labels/{label_id}", - headers = {"Authorization": f"Bearer {self.__credentials.token}"}, - json = json_body - ) - - # If the API call failed: - if api_response.status_code not in [200]: return success - - # Else we note down the success: - if api_response.json().get("id") is not None: success = True - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - success = False - - # Done here: - return success - - async def delete_label( - self, - label_id: str, - raise_exception: bool = False - ) -> bool: - - """ - To delete one label of this user. the label will be identified by its id. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/get - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param label_id: The id that Google assigned to the label. - :param raise_exception: If set to True, any exceptions that occur will be propagated, else they wil be - suppressed. - :return: The list of labels. - """ - - # Start by assuming failure: - success = False - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # Make the API call: - if not self._debug_only_errors: self._printer("Deleting One Label.", self.__user_email) - api_response = await self.__http_client.delete( - url = f"https://gmail.googleapis.com/gmail/v1/users/{self.__user_email}/labels/{label_id}", - headers = {"Authorization": f"Bearer {self.__credentials.token}"} - ) - - # If the API call failed: - if api_response.status_code not in [200, 204]: return success - - # Else we extract the response: - else: success = True - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - success = False - - # Done here: - return success - - # ┳┳┓ - # ┃┃┃â”┓â”â”â”┓â”┓â”┓┠- # â”› â”—â”— ┛┛┗┻┗┫┗ â”› - # â”› - - async def __list_messages_on_page( - self, - count: int = 100, - query: str = None, - label_ids: List[str] | str = None, - include_spam_and_trash: bool = False, - next_page_token: str = None, - raise_exception: bool = False - ) -> Dict[str, Any] | None: - - """ - To enlist messages on one page. Google allows at most 500 results on one page. This method respects that - pagination limit and returns only what Google gives. This method should be used internally by the class and the - class should expose another method that calls this one in loop to get any arbitrary no. of messages as the user - desires. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/list - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message - :param count: The no. of messages to fetch. - :param query: Any query filter that is supported by GMail. - :param label_ids: The list of labels' ids that the mails must have on them. - :param include_spam_and_trash: Whether, or not, you would like to include mails categorized as spam and trash. - :param next_page_token: The token to fetch the next set of results. - :param raise_exception: If set to True, any exceptions that occur will be propagated, else they wil be - suppressed. - :return: The messages that matched the given conditions if the call was successful, else None. - """ - - # Start by assuming failure: - page_messages = None - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # Build the needed params: - params_json = { - "maxResults": count, - "includeSpamTrash": include_spam_and_trash - } - if query: params_json["q"] = query - if next_page_token: params_json["pageToken"] = next_page_token - if label_ids: params_json["labelIds"] = label_ids if isinstance(label_ids, list) else [label_ids] - - # Make the API call: - if not self._debug_only_errors: self._printer( - "Listing Messages for Page.", - self.__user_email, - count, - next_page_token - ) - api_response = await self.__http_client.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{self.__user_email}/messages", - headers = {"Authorization": f"Bearer {self.__credentials.token}"}, - params = params_json - ) - - # If the API call failed: - if api_response.status_code not in [200]: return page_messages - - # Else we format the response: - api_json = api_response.json() - page_messages = { - "messages": {m.pop("id"): m for m in api_json.get("messages", [])}, - "nextPageToken": api_json.get("nextPageToken"), - "resultSizeEstimate": api_json["resultSizeEstimate"], - } - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - page_messages = None - - # Done here: - return page_messages - - async def list_messages( - self, - count: int = 100, - query: str = None, - label_ids: List[str] | str = None, - include_spam_and_trash: bool = False, - raise_exception: bool = False - ) -> Dict[str, Any]: - - """ - To enlist mail messages from a user's account. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/list - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message - :param count: The no. of messages to fetch. - :param query: Any query filter that is supported by GMail. - :param label_ids: The list of labels' ids that the mails must have on them. - :param include_spam_and_trash: Whether, or not, you would like to include mails categorized as spam and trash. - :param raise_exception: If set to True, any exceptions that occur will be propagated, else they wil be - suppressed. - :return: The messages that matched the given conditions if the call was successful, else None. - """ - - # Start by assuming failure: - messages = None - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # We convert the messages to a dict: - messages = { - "messages": {}, - "nextPageToken": None, - "resultSizeEstimate": 0 - } - - # Let's figure out how many times we'll have to loop through the process to retrieve the target no. of - # messages. Google allows you to fetch info about at most 500 messages in one go. - max_per_call = 500 # ... because Google allows at most 500 entries in one call. - iterations_needed = int(math.ceil(count / max_per_call)) - last_iteration_count = count - int((max_per_call * (iterations_needed - 1))) - - # Run the loop those many times: - next_page_token = None - results_size_estimate = 0 - for iteration_no in range(iterations_needed): - - # Figure out the count for this page: - if iterations_needed > 1: - if iteration_no < (iterations_needed - 1): iteration_count = max_per_call - else: iteration_count = last_iteration_count - else: iteration_count = count - - # Retrieve the messages for this page: - iteration_messages = await self.__list_messages_on_page( - count = iteration_count, - query = query, - label_ids = label_ids, - include_spam_and_trash = include_spam_and_trash, - next_page_token = next_page_token, - raise_exception = True - ) - - # Check if no data was received: - if iteration_messages is None: break - if not iteration_messages.get("messages"): break - - # Now that we know that messages were received: - for k, v in iteration_messages["messages"].items(): messages["messages"][k] = v - results_size_estimate += iteration_messages["resultSizeEstimate"] - - # If there is no next page after this, we break out of the loop: - next_page_token = iteration_messages["nextPageToken"] - if next_page_token is None: break - - # Format the final response: - messages["nextPageToken"] = next_page_token - messages["resultSizeEstimate"] = results_size_estimate - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - messages = None - - # Done here: - return messages - - async def get_message( - self, - message_id: str, - return_raw = False, - raise_exception: bool = False - ) -> Dict[str, Any] | str | None: - - """ - To get one message of this user. The message will be identified by its id. Note that, if you choose to return - the raw message, the message body will be compliant with RFC 5322 and RFC 2045 (among others). - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/get - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message - 2. https://developers.google.com/gmail/api/reference/rest/v1/Format - :param message_id: The id that Google assigned to the message. - :param return_raw: Whether you want the raw message or the formatted message. - :param raise_exception: If set to True, any exceptions that occur will be propagated, else they wil be - suppressed. - :return: The message either parsed as a JSON, or as a raw text body. If the API call fails, the response will be - a null value. - """ - - # Start by assuming failure: - message = None - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # Make the API call: - if not self._debug_only_errors: self._printer("Getting One Message.", self.__user_email) - api_response = await self.__http_client.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{self.__user_email}/messages/{message_id}", - headers = {"Authorization": f"Bearer {self.__credentials.token}"}, - params = {"format": "raw"} - ) - - # If the API call failed: - if api_response.status_code not in [200]: return message - - # Extract the raw message and respond based on the request: - api_json = api_response.json() - message = base64.urlsafe_b64decode(api_json["raw"]) - if return_raw: message = message.decode() - else: - message = mail_parser.parse(message) - message["labels"] = api_json["labelIds"] - message["messageId"] = api_json["id"] - message["threadId"] = api_json["threadId"] - message["historyId"] = api_json["historyId"] - message["snippet"] = api_json["snippet"] - message["sizeEstimate"] = api_json["sizeEstimate"] - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - message = None - - # Done here: - return message - - async def modify_messages( - self, - message_ids: List[str] | str, - add_label_ids: List[str] | str = None, - remove_label_ids: List[str] | str = None, - raise_exception: bool = False - ) -> bool: - - """ - To add or remove labels from messages. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/batchModify - :param message_ids: One or more message ids (assigned by Google). - :param add_label_ids: One or more label ids (not the display name of the label). - :param remove_label_ids: One or more label ids (not the display name of the label). - :param raise_exception: If set to True, any exceptions that occur will be propagated, else they wil be - suppressed. - :return: True if the operation succeeded, else False. - """ - - # Start by assuming failure: - success = False - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # Build the needed JSON: - body_json = {"ids": message_ids if isinstance(message_ids, list) else [message_ids]} - if add_label_ids: body_json["addLabelIds"] = add_label_ids if isinstance(add_label_ids, list) else [add_label_ids] - if remove_label_ids: body_json["removeLabelIds"] = remove_label_ids if isinstance(remove_label_ids, list) else [remove_label_ids] - - # Make the API call: - if not self._debug_only_errors: self._printer("Modifying Message(s).", self.__user_email) - api_response = await self.__http_client.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{self.__user_email}/messages/batchModify", - headers = {"Authorization": f"Bearer {self.__credentials.token}"}, - json = body_json - ) - - # Check if our request was successful: - if api_response.status_code in [200, 204]: success = True - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - success = False - - # Done here: - return success - - async def delete_messages( - self, - message_ids: List[str] | str, - raise_exception: bool = False - ) -> bool: - - # Start by assuming failure: - success = False - - try: - - # Standard token-refresh check: - await self.__ensure_token() - - # Make the API call: - if not self._debug_only_errors: self._printer("Deleting Message(s).", self.__user_email) - api_response = await self.__http_client.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{self.__user_email}/messages/batchDelete", - headers = {"Authorization": f"Bearer {self.__credentials.token}"}, - json = {"ids": message_ids if isinstance(message_ids, list) else [message_ids]} - ) - - print("HTTP CODE:", api_response.status_code) - try: print("HTTP JSON:", json.to_string(api_response.json())) - except Exception as e: print("HTTP JSON:", e) - - # Check if our request was successful: - if api_response.status_code in [200, 204]: success = True - - # In case something goes wrong along the way: - except Exception as exception: - if raise_exception: raise - self._printer(exception) - success = False - - # Done here: - return success - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import dateparser - - # Create an HTTP client: - test_client = httpx.AsyncClient( - limits = httpx.Limits( - max_connections = 100, # ............ Maximum number of connections allowed in the pool. - max_keepalive_connections = 50, # ... Maximum number of connections that can be kept alive. - ), - timeout = httpx.Timeout( - connect = 2.5, # ... Shorter connection timeout. - read = 2.5, # ...... Like what EasyEcom gives. - write = 10.0, # .... Time to wait for sending data. - pool = 120.0 # ..... Time to wait for a free connection from the pool. - ) - ) - - secrets_file = r"../../../creds/google_tcaoff_test_oauth_20241125.json" - secrets_dict = json.from_file(secrets_file) - - my_oauth = GoogleOAuth( - config = secrets_dict, - redirect_url = r"https://api.thecaoffice.com/converse/mail/callback/gmail", - debug = True, - debug_prefix = "OAuth (Goog) | ", - ) - - tokens = { - "access_token": "ya29.a0AeDClZAYoo85BXRId_n-hwo_amKshzi46c33GaJcsZZvGB7A7OGU2RFYcWBM_BleNBfAFUSJP2NHAvmd7Nsp_U5Kg68hXSy0iO99PNTm3pvKrJSzbkA-rXsVLsCnBIfPUMyNt2nOOVJmGwm17DNN0jAELkm1fPNTju7SZzmuaCgYKAZwSARMSFQHGX2Mis8TZui2rZT1gKySVds-N0w0175", - "refresh_token": "1//0gnqzjMf9YT19CgYIARAAGBASNgF-L9Ir3rcY37nGrV45XyOUBRllEH7Txui7T1JbwevlmDoNw7PuMu149cCWQSwsScuKaZusUQ", - "expires_in": 3539, - "expires_at": dateparser.parse("2024-11-25 10:40:40.833699+00:00"), - "scopes": [ - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - } - - async def main(): - - my_gmail = AsyncGMailClient( - http_client = test_client, - credentials = await my_oauth.credentials_from_tokens(tokens = tokens), - debug_only_errors = False - ) - await my_gmail.initialize() - print(await my_gmail.user_email) - print(await my_gmail.user_profile) - - # print(json.to_string(await my_gmail.list_labels())) - - # print(json.to_string(await my_gmail.get_label(label_id = "Label_3"))) - - # print(json.to_string(await my_gmail.update_label( - # label_id = "Label_3", - # label_name = "Updated Label 123", - # label_background_color = "#cc3a21" - # ))) - # - # print(json.to_string(await my_gmail.get_label(label_id = "Label_3"))) - - # print(json.to_string(await my_gmail.create_label( - # label_name = "Bye - Bye !", - # label_text_color = "#fbc8d9", - # label_background_color = "#7a2e0b" - # ))) - - # print(json.to_string(await my_gmail.delete_label(label_id = "Label_6"))) - - # print(json.to_string(await my_gmail.list_messages(count = 10))) - # print(json.to_string( - # await my_gmail.get_message( - # message_id = "19367930033154ca", - # return_raw = False - # ), - # default = str) - # ) - - # print(json.to_string(await my_gmail.modify_messages( - # message_ids = ["19367930033154ca"], - # add_label_ids = ["Label_5"], - # remove_label_ids = ["Label_3"] - # ))) - - print(json.to_string(await my_gmail.delete_messages(message_ids = "19367930033154ca"))) - - - asyncio.run(main()) diff --git a/utils_v2/goog/gmail/gmail_client.py b/utils_v2/goog/gmail/gmail_client.py new file mode 100644 index 0000000..a837c11 --- /dev/null +++ b/utils_v2/goog/gmail/gmail_client.py @@ -0,0 +1,959 @@ +""" + + AUTHOR: + + Khushal P Soonderji + + DATE: + + Monday, 25th Nov., 2024 + + OBJECTIVE: + + To manage e-mails in a GMail account. + + REFERENCES: + + 1. Quickstart: https://developers.google.com/gmail/api/quickstart/python + 2. Labels: https://developers.google.com/gmail/api/guides/labels + 3. Messages: https://developers.google.com/gmail/api/reference/rest/v1/users.messages + + DOWNLOADS: + + N/A + +""" + + +# ***************************************************************************************************************** +# ***** **** +# *** IMPORT *** +# ***** **** +# ***************************************************************************************************************** + + +# To make sibling directories accessible for imports: +import sys +sys.path.append(".") +sys.path.append("..") + +# System-level activities: +import io + +# My utils: +from utils_v2.string import json +from utils_v2.string import regex +from utils_v2.date_time import date_time +from utils_v2.mail import mail_parser + +# My Google utils: +from utils_v2.oauth.services.goog import GoogleOAuth +from utils_v2.goog.base import AsyncGoogleBase +from utils_v2.goog.models.data.auth_tokens import GoogleAuthTokens +from utils_v2.goog.models.data.api_call import GoogleApiResponse +from utils_v2.goog.gmail.gmail_message import GMailMessage + +# Related to Google: +from google.auth.transport.requests import Request +from google.oauth2.credentials import Credentials +from googleapiclient.discovery import build + +# To make API calls: +import httpx + +# For asynchronous activities: +import asyncio + +# To work with date and time: +import datetime + +# For working with datatypes: +from typing import Dict, Literal, List, Any + +# For debugging: +from icecream import IceCreamDebugger +import inspect + +# For computational help: +import math + +# For base64 encoding: +import base64 + + +# ***************************************************************************************************************** +# ***** **** +# *** MACROS / ONE-TIME INIT *** +# ***** **** +# ***************************************************************************************************************** + + +# --- Nothing Yet + + +# ***************************************************************************************************************** +# ***** **** +# *** VARIABLES *** +# ***** **** +# ***************************************************************************************************************** + + +# --- Nothing Yet + + +# ***************************************************************************************************************** +# ***** **** +# *** FUNCTIONS *** +# ***** **** +# ***************************************************************************************************************** + + +# --- Nothing Yet + + +# ***************************************************************************************************************** +# ***** **** +# *** CLASSES *** +# ***** **** +# ***************************************************************************************************************** + + +class AsyncGMailClient(AsyncGoogleBase): + + async def get_user_profile( + self, + tokens: GoogleAuthTokens, + user_id: str = "me", + ) -> GoogleApiResponse: + + """ + To get the list of labels of this user. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users/getProfile + :param tokens: The object that holds the access token to the service. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Getting User Profile.") + api_response = await self.get( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/profile", + headers = {"Authorization": f"Bearer {tokens.accessToken}"} + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + # ┓ ┓ ┓ + # ┃ â”┓┣┓â”┓┃┠+ # ┗┛┗┻┗┛┗ â”—â”› + + async def list_labels( + self, + tokens: GoogleAuthTokens, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To get the list of labels of this user. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/list + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label + :param tokens: The object that holds the access token to the service. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Listing All Labels.", user_id) + api_response = await self.get( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels", + headers = {"Authorization": f"Bearer {tokens.accessToken}"} + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_json = await api_response.get_json() + api_response.data = {label.pop("name"): label for label in api_json.get("labels", [])} + + # Done here: + return api_response + + async def get_label( + self, + tokens: GoogleAuthTokens, + label_id: str, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To get one label of this user. the label will be identified by its id. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/get + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label + :param tokens: The object that holds the access token to the service. + :param label_id: The id that Google assigned to the label. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Getting One Label.", user_id) + api_response = await self.get( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", + headers = {"Authorization": f"Bearer {tokens.accessToken}"} + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + async def create_label( + self, + tokens: GoogleAuthTokens, + label_name: str, + label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = "labelShow", + message_visibility: Literal["show", "hide"] = "show", + label_text_color: str = "#434343", + label_background_color: str = "#000000", + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + Create one label for the user. Doesn't apply it to any mail, just creates it. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/create + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label + :param tokens: The object that holds the access token to the service. + :param label_name: The display name of the label. + :param label_visibility: Whether, or not, you would like to show the label in the web UI. + :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. + :param label_text_color: The colour of the text of the label. + :param label_background_color: The colour of the background/tag of the label. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Creating One Label.", user_id) + api_response = await self.post( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + json = { + "name": label_name, + "messageListVisibility": "show" if message_visibility else "hide", + "labelListVisibility": "labelShow" if label_visibility else "labelHide", + "color": { + "textColor": label_text_color.lower(), + "backgroundColor": label_background_color.lower() + } + } + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + async def update_label( + self, + tokens: GoogleAuthTokens, + label_id: str, + label_name: str = None, + label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = None, + message_visibility: Literal["show", "hide"] = None, + label_text_color: str = None, + label_background_color: str = None, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + Updates one label for the user. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/update + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label + NOTE: Both or none of the colours must be updated. For this reason, a simple default will be chosen for the + other if only one is provided. + :param tokens: The object that holds the access token to the service. + :param label_id: The id that Google assigned to the label. + :param label_name: The display name of the label. + :param label_visibility: Whether, or not, you would like to show the label in the web UI. + :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. + :param label_text_color: The colour of the text of the label. + :param label_background_color: The colour of the background/tag of the label. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Format the JSON body: + json_body = {} + if label_name: json_body["name"] = label_name + if label_visibility: json_body["labelListVisibility"] = label_visibility + if message_visibility: json_body["messageListVisibility"] = message_visibility + if label_text_color or label_background_color: + json_body["color"] = { + "textColor": (label_text_color or "#434343").lower(), + "backgroundColor": (label_background_color or "#000000").lower() + } + + # Make the API call: + if not self._debug_only_errors: self._printer("Updating One Label.", user_id) + api_response = await self.put( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + json = json_body + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + async def delete_label( + self, + tokens: GoogleAuthTokens, + label_id: str, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To delete one label of this user. the label will be identified by its id. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/delete + :param tokens: The object that holds the access token to the service. + :param label_id: The id that Google assigned to the label. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Deleting One Label.", user_id) + api_response = await self.delete( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", + headers = {"Authorization": f"Bearer {tokens.accessToken}"} + ) + + # If the call was successful: + if api_response.httpCode in [200, 204]: + api_response.success = True + + # Done here: + return api_response + + # ┳┳┓ + # ┃┃┃â”┓â”â”â”┓â”┓â”┓┠+ # â”› â”—â”— ┛┛┗┻┗┫┗ â”› + # â”› + + async def __list_messages_on_page( + self, + tokens: GoogleAuthTokens, + count: int = 100, + query: str = None, + label_ids: List[str] | str = None, + include_spam_and_trash: bool = False, + next_page_token: str = None, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To enlist messages on one page. Google allows at most 500 results on one page. This method respects that + pagination limit and returns only what Google gives. This method should be used internally by the class and the + class should expose another method that calls this one in loop to get any arbitrary no. of messages as the user + desires. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/list + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message + :param tokens: The object that holds the access token to the service. + :param count: The no. of messages to fetch. + :param query: Any query filter that is supported by GMail. + :param label_ids: The list of labels' ids that the mails must have on them. + :param include_spam_and_trash: Whether, or not, you would like to include mails categorized as spam and trash. + :param next_page_token: The token to fetch the next set of results. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Build the needed params: + params_json = { + "maxResults": count, + "includeSpamTrash": include_spam_and_trash + } + if query: params_json["q"] = query + if next_page_token: params_json["pageToken"] = next_page_token + if label_ids: params_json["labelIds"] = label_ids if isinstance(label_ids, list) else [label_ids] + + # Make the API call: + if not self._debug_only_errors: self._printer("Listing Messages for Page.", user_id, count, next_page_token) + api_response = await self.get( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + params = params_json + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_json = await api_response.get_json() + api_response.data = { + "messages": {m.pop("id"): m for m in api_json.get("messages", [])}, + "nextPageToken": api_json.get("nextPageToken"), + "resultSizeEstimate": api_json["resultSizeEstimate"], + } + + # Done here: + return api_response + + async def list_messages( + self, + tokens: GoogleAuthTokens, + count: int = 100, + query: str = None, + label_ids: List[str] | str = None, + include_spam_and_trash: bool = False, + next_page_token: str = None, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To enlist mail messages from a user's account. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/list + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message + :param tokens: The object that holds the access token to the service. + :param count: The no. of messages to fetch. + :param query: Any query filter that is supported by GMail. + :param label_ids: The list of labels' ids that the mails must have on them. + :param include_spam_and_trash: Whether, or not, you would like to include mails categorized as spam and trash. + :param next_page_token: The token to fetch the next set of results. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # We create a variable that will hold the results. + # We must supply the URL, Method and a few other params here due to the custom looping functionality: + all_messages = GoogleApiResponse( + serviceName = self._service_name, + action = inspect.stack()[0].function, + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages", + method = "GET", + data = { + "messages": {}, + "nextPageToken": None, + "resultSizeEstimate": 0 + } + ) + + # Let's figure out how many times we'll have to loop through the process to retrieve the target no. of + # messages. Google allows you to fetch info about at most 500 messages in one go. + max_per_call = 500 # ... because Google allows at most 500 entries in one call. + iterations_needed = int(math.ceil(count / max_per_call)) + last_iteration_count = count - int((max_per_call * (iterations_needed - 1))) + + # Run the loop those many times: + results_size_estimate = 0 + for iteration_no in range(iterations_needed): + + # Figure out the count for this page: + if iterations_needed > 1: + if iteration_no < (iterations_needed - 1): iteration_count = max_per_call + else: iteration_count = last_iteration_count + else: iteration_count = count + + # Retrieve the messages for this page: + iteration_response = await self.__list_messages_on_page( + tokens = tokens, + count = iteration_count, + query = query, + label_ids = label_ids, + include_spam_and_trash = include_spam_and_trash, + next_page_token = next_page_token + ) + + # Check if no data was received: + if ( + iteration_response.data is None or + not iteration_response.data.get("messages") + ): break + + # Now that we know that messages were received: + for k, v in iteration_response.data["messages"].items(): all_messages.data["messages"][k] = v + results_size_estimate += iteration_response.data["resultSizeEstimate"] + + # Also copy the API call params: + all_messages.httpCode = iteration_response.httpCode + all_messages.message = iteration_response.message + all_messages.success = iteration_response.success + + # If there is no next page after this, we break out of the loop: + next_page_token = iteration_response.data["nextPageToken"] + if next_page_token is None: break + + # Format the final response: + all_messages.data["nextPageToken"] = next_page_token + all_messages.data["resultSizeEstimate"] = results_size_estimate + + # Done here: + return all_messages + + async def get_message( + self, + tokens: GoogleAuthTokens, + message_id: str, + return_raw: bool = False, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To get one message of this user. The message will be identified by its id. Note that, if you choose to return + the raw message, the message body will be compliant with RFC 5322 and RFC 2045 (among others). + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/get + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message + 2. https://developers.google.com/gmail/api/reference/rest/v1/Format + :param tokens: The object that holds the access token to the service. + :param message_id: The id that Google assigned to the message. + :param return_raw: Whether you want the raw message or the formatted message. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Getting One Message.", user_id) + api_response = await self.get( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/{message_id}", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + params = {"format": "raw"} + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_json = await api_response.get_json() + raw_message = base64.urlsafe_b64decode(api_json["raw"]) + if return_raw: api_response.data = raw_message + else: + parsed_message = mail_parser.parse(raw_message) + parsed_message["labels"] = api_json["labelIds"] + parsed_message["messageId"] = api_json["id"] + parsed_message["threadId"] = api_json["threadId"] + parsed_message["historyId"] = api_json["historyId"] + parsed_message["snippet"] = api_json["snippet"] + parsed_message["sizeEstimate"] = api_json["sizeEstimate"] + api_response.data = parsed_message + + # Done here: + return api_response + + async def modify_messages( + self, + tokens: GoogleAuthTokens, + message_ids: List[str] | str, + add_label_ids: List[str] | str = None, + remove_label_ids: List[str] | str = None, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To add or remove labels from one or more messages. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/batchModify + :param tokens: The object that holds the access token to the service. + :param message_ids: One or more message ids (assigned by Google). + :param add_label_ids: One or more label ids (not the display name of the label). + :param remove_label_ids: One or more label ids (not the display name of the label). + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Build the needed JSON: + body_json = {"ids": message_ids if isinstance(message_ids, list) else [message_ids]} + if add_label_ids: body_json["addLabelIds"] = add_label_ids if isinstance(add_label_ids, list) else [add_label_ids] + if remove_label_ids: body_json["removeLabelIds"] = remove_label_ids if isinstance(remove_label_ids, list) else [remove_label_ids] + + # Make the API call: + if not self._debug_only_errors: self._printer("Modifying Message(s).", user_id) + api_response = await self.post( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/batchModify", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + json = body_json + ) + + # If the call was successful: + if api_response.httpCode in [200, 204]: + api_response.success = True + + # Done here: + return api_response + + async def delete_messages( + self, + tokens: GoogleAuthTokens, + message_ids: List[str] | str, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To PERMANENTLY delete one or more messages. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/batchDelete + :param tokens: The object that holds the access token to the service. + :param message_ids: One or more message ids (assigned by Google). + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Deleting Message(s).", user_id) + api_response = await self.post( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/batchDelete", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + json = {"ids": message_ids if isinstance(message_ids, list) else [message_ids]} + ) + + # If the call was successful: + if api_response.httpCode in [200, 204]: + api_response.success = True + + # Done here: + return api_response + + async def trash_message( + self, + tokens: GoogleAuthTokens, + message_id: str, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To move one message to trash. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/trash + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message + :param tokens: The object that holds the access token to the service. + :param message_id: The id of the message (assigned by Google). + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Trashing One Message.", user_id) + api_response = await self.post( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/{message_id}/trash", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + ) + + # If the call was successful: + if api_response.httpCode in [200, 204]: + api_response.success = True + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + async def untrash_message( + self, + tokens: GoogleAuthTokens, + message_id: str, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To move one message to trash. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/trash + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message + :param tokens: The object that holds the access token to the service. + :param message_id: The id of the message (assigned by Google). + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Make the API call: + if not self._debug_only_errors: self._printer("Un-Trashing One Message.", user_id) + api_response = await self.post( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/{message_id}/untrash", + headers = {"Authorization": f"Bearer {tokens.accessToken}"}, + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + async def send_message( + self, + tokens: GoogleAuthTokens, + message: GMailMessage, + thread_id: str = None, + user_id: str = "me" + ) -> GoogleApiResponse: + + """ + To send one message. + NOTE: If you want to apply a custom label to your outgoing mails, this API endpoint doesn't allow you to do that + in one go. Instead, you should note down the 'id' field from a successful response and use the 'modify_messages' + method of this class to immediately apply that label to the mail in a separate call. + DOCUMENTATION: + 1. https://developers.google.com/gmail/api/reference/rest/v1/users.messages/send + 2. https://developers.google.com/gmail/api/reference/rest/v1/users.messages#Message + :param tokens: The object that holds the access token to the service. + :param message: The object that has the content of the message to be sent. + :param thread_id: Replies to an existing mail if the correct thread-id is specified. If not specified, a new + mail with a new thread-id is created. + :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". + :return: A structured response where the list of labels will be in the 'data' variable. + """ + + # Ensure that the tokens are valid: + await tokens.arefresh( + http_client = self._http_client, + client_id = self._client_id, + client_secret = self._client_secret, + force_refresh = False + ) + + # Construct the JSON body: + json_body = {"raw": message.get_raw_message(as_base64 = True)} + if thread_id: json_body["threadId"] = thread_id + + # Make the API call: + if not self._debug_only_errors: self._printer("Sending One Message.", user_id) + api_response = await self.post( + url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/messages/send", + headers = { + "Authorization": f"Bearer {tokens.accessToken}", + "Content-Type": "message/rfc822" + }, + json = json_body + ) + + # If the call was successful: + if api_response.httpCode in [200]: + api_response.success = True + api_response.data = await api_response.get_json() + + # Done here: + return api_response + + +# ***************************************************************************************************************** +# ***** **** +# *** MAIN PROGRAM *** +# ***** **** +# ***************************************************************************************************************** + + +if __name__ == "__main__": + + # Create an HTTP client: + test_client = httpx.AsyncClient( + limits = httpx.Limits( + max_connections = 100, # ............ Maximum number of connections allowed in the pool. + max_keepalive_connections = 50, # ... Maximum number of connections that can be kept alive. + ), + timeout = httpx.Timeout( + connect = 2.5, # ... Shorter connection timeout. + read = 2.5, # ...... Like what EasyEcom gives. + write = 10.0, # .... Time to wait for sending data. + pool = 120.0 # ..... Time to wait for a free connection from the pool. + ) + ) + + # Read the secrets that give you access to the app: + secrets_file = r"../../../creds/goog/app/google_tcaoff_test_oauth_20241125.json" + secrets_dict = json.from_file(secrets_file) + + # Read the user's tokens that will give you app access to that user's account: + tokens_file = r"../../../creds/goog/user/test_user_tokens_20241125.json" + tokens_dict = json.from_file(tokens_file) + test_tokens = GoogleAuthTokens(**tokens_dict) + + async def main(): + + # Create an instance of the client: + my_gmail = AsyncGMailClient( + service_name = "gmail", + client_id = secrets_dict["web"]["client_id"], + client_secret = secrets_dict["web"]["client_secret"], + http_client = test_client, + debug = True, + debug_prefix = "GMail (M) | ", + debug_only_errors = False + ) + + # Create a sample mail: + my_mail = GMailMessage( + from_email = "pskhushal@gmail.com", + to_email = "orangebhopli@gmail.com", + subject = "Re: Bhopli is the best! (Thread Test)", + cc_emails = None, + bcc_emails = None + ) + my_mail.add_html( + """ + + + + + Sample HTML String + + + +

Hello, Bhopli!

+

Bhopli is the best, most well-behaved cat in the known universe.

+ + + """ + ) + my_mail.add_text("This is how you should pet her 👇") + my_mail.add_inline_image(r"../../../data/images/cat_petting.png") + my_mail.add_attachment(r"../../../data/pdf/sample_label.pdf") + # print(my_mail.get_raw_message(as_base64 = False)) + + # Test some feature: + response = await my_gmail.send_message( + tokens = test_tokens, + message = my_mail, + thread_id = "1936caffb67996d3" + ) + print("SUCCESS:", response.success) + print("SUMMARY:", response.to_markdown()) + print("\n\n---\n\n") + print("DATA:", json.to_string(response.data, default = str)) + if not response.success: + print("\n\n---\n\n") + print("FULL RESPONSE JSON:", json.to_string(await response.get_json())) + + + asyncio.run(main()) diff --git a/utils_v2/goog/gmail/gmail_message.py b/utils_v2/goog/gmail/gmail_message.py new file mode 100644 index 0000000..bb29eb5 --- /dev/null +++ b/utils_v2/goog/gmail/gmail_message.py @@ -0,0 +1,322 @@ +""" + + AUTHOR: + + Khushal P Soonderji + + DATE: + + Tuesday, 16th Jul, 2024 + + OBJECTIVE: + + To be able to send out mails from code. + + REFERENCES: + + N/A + + DOWNLOADS: + + N/A + +""" + + +# ***************************************************************************************************************** +# ***** **** +# *** IMPORT *** +# ***** **** +# ***************************************************************************************************************** + + +# To make sibling directories accessible for imports: +import sys +sys.path.append(".") +sys.path.append("..") + +# For working with mails: +from email.mime.multipart import MIMEMultipart +from email.mime.image import MIMEImage +from email.mime.text import MIMEText +from email.mime.base import MIMEBase +from email import encoders + +# For random strings: +import string +import random + +# For system-level activities: +import os + +# For working with files in RAM: +import io + +# To work with Base64 encoding: +import base64 + +# To work with datatypes: +from typing import List + + +# ***************************************************************************************************************** +# ***** **** +# *** MACROS / ONE-TIME INIT *** +# ***** **** +# ***************************************************************************************************************** + + +# --- Nothing Yet + + +# ***************************************************************************************************************** +# ***** **** +# *** VARIABLES *** +# ***** **** +# ***************************************************************************************************************** + + +# --- Nothing Yet + + +# ***************************************************************************************************************** +# ***** **** +# *** FUNCTIONS *** +# ***** **** +# ***************************************************************************************************************** + + +# --- Nothing Yet + + +# ***************************************************************************************************************** +# ***** **** +# *** CLASSES *** +# ***** **** +# ***************************************************************************************************************** + + +class GMailMessage: + + def __init__( + self, + from_email: str, + to_email: str, + subject: str, + cc_emails: List[str] = None, + bcc_emails: List[str] = None + ): + + """ + Create an instance of the message that you would like to send. + :param from_email: The EMail ID of the sender. + :param to_email: The EMail ID of the recipient. + :param subject: The subject of the mail. + :param cc_emails: A list of recipients to add to the CC section. + :param bcc_emails: A list of recipients to add to the BCC section. + """ + + # Create the instance of the message: + self.message = MIMEMultipart() + self.message["From"] = from_email + self.message["To"] = to_email + self.message["Subject"] = subject + if cc_emails: self.message["CC"] = ",".join(cc_emails) + if bcc_emails: self.message["BCC"] = ",".join(bcc_emails) + + # Note down the values for accessing later: + self.__from = from_email + self.__to = to_email + self.__cc = cc_emails, + self.__bcc = bcc_emails + self.__subject = subject + + # â”┓ • + # ┃┃â”┓â”┓â”┓â”┓â”┓╋┓â”┓┠+ # ┣┛┛ ┗┛┣┛┗ â”› â”—â”—â”— â”› + # â”› + + @property + def from_mail(self): + return self.__from + + @property + def to_mail(self): + return self.__to + + @property + def cc_mails(self): + return self.__cc + + @property + def bcc_mails(self): + return self.__bcc + + @property + def subject(self): + return self.__subject + + # â”┓ ┓ ┓ â”┓ + # ┣┫â”┫â”┫ ┃ â”┓â”┓╋â”┓â”┓╋ + # ┛┗┗┻┗┻ ┗┛┗┛┛┗┗┗ ┛┗┗ + + def add_text(self, text): + + """ + Add plain-text to the mail body. + :param text: The text to add to the mail body. + :return: None. + """ + + self.message.attach(MIMEText(text, "plain")) + + def add_html(self, html_text): + + """ + Add HTML text to the mail body. + :param html_text: The HTML text to add to the mail body. + :return: None. + """ + + self.message.attach(MIMEText(html_text, "html")) + + def add_inline_image(self, image_file, content_id = None): + + """ + Add an inline image to the body of the mail. + NOTE: This is NOT the same as sending an image as an attachment. + :param image_file: The image data to attach to the mail body. + :param content_id: Inline images are inserted via HTML bocks. This field identifies the image resource. If not + specified, I will generate a random string. You may write a custom value here if you know what you are + doing. For most use cases, please ignore this field. + :return: None. + """ + + # Read the image as bytes: + image_bytes = None + if type(image_file) is str: + with open(image_file, "rb") as opened_image_file: + image_bytes = opened_image_file.read() + if type(image_file) is io.BytesIO: + image_file.seek(0) + image_bytes = image_file.getvalue() + + # Declare the part to be attached to the multipart message: + if image_bytes is not None: + + # Create the HTML block if the image pointer is blank: + if content_id is None: + content_id = ''.join(random.choice(string.ascii_letters + string.digits) for _ in range(8)) + self.add_html(f""" + + +

+ + + """) + + # Then add the image: + image_part = MIMEImage(image_bytes) + image_part.add_header("Content-ID", f"<{content_id}>") + self.message.attach(image_part) + + def add_attachment( + self, + attachment_file: str | io.BytesIO, + file_name: str = None + ): + + """ + Add a file as an attachment to the mail. This file, even if possible, will not be rendered on the screen in-line + with the body. It will be made available as a download. + :param attachment_file: The file that you would like to attach. + :param file_name: The name of the file. This is the same name by which it will be downloaded. You need not + specify this if the input file is specified as a path. Needed when you give the input file as a buffer. + :return: + """ + + # Declare the part to be attached to the multipart message: + part = MIMEBase("application", "octet-stream") + + # If the attachment is a file stored in the local disk: + if isinstance(attachment_file, str): + file_name = file_name or os.path.split(attachment_file)[-1] + with open(attachment_file, "rb") as attachment: + part.set_payload(attachment.read()) + + # If the file is held in RAM: + elif isinstance(attachment_file, io.BytesIO): + attachment_file.seek(0) + part.set_payload(attachment_file.read()) + + # Encode and attach the file: + encoders.encode_base64(part) + part.add_header( + "Content-Disposition", + f"attachment; filename= {file_name}", + ) + self.message.attach(part) + + # â”┓ + # ┣ â”┓â”┓â”┳┓â”┓╋ + # â”» ┗┛┛ ┛┗┗┗┻┗ + + def get_raw_message( + self, + as_base64: bool = True + ): + + """ + Get the raw string dump from the current contents of the message. This text will be compliant with RFC 5322 and + RFC 2045 (among others). + :param as_base64: If set to True, the response will be a URL-safe B64 output, else it'll be a raw string. + :return: The standardized raw text dump. either as a raw string or as a Base64 (url-safe) string. + """ + + if not as_base64: return self.message + else: return base64.urlsafe_b64encode(self.message.as_bytes()).decode() + + +# ***************************************************************************************************************** +# ***** **** +# *** MAIN PROGRAM *** +# ***** **** +# ***************************************************************************************************************** + + +if __name__ == "__main__": + + my_mail = GMailMessage( + from_email = "sender@gmail.com", + to_email = "recipient@gmail.com", + subject = "Bhopli is the best!", + cc_emails = None, + bcc_emails = None + ) + my_mail.add_html( + """ + + + + + Sample HTML String + + + +

Hello, Bhopli!

+

Bhopli is the best, most well-behaved cat in the known universe.

+ + + """ + ) + my_mail.add_text("This is how you should pet her 👇") + my_mail.add_inline_image(r"../../../data/images/cat_petting.png") + my_mail.add_attachment(r"../../../data/pdf/sample_label.pdf") + print(my_mail.get_raw_message(as_base64 = True)) diff --git a/utils_v2/goog/gmail/gmail_v2.py b/utils_v2/goog/gmail/gmail_v2.py deleted file mode 100644 index 64150d0..0000000 --- a/utils_v2/goog/gmail/gmail_v2.py +++ /dev/null @@ -1,464 +0,0 @@ -""" - - AUTHOR: - - Khushal P Soonderji - - DATE: - - Monday, 25th Nov., 2024 - - OBJECTIVE: - - To manage e-mails in a GMail account. - - REFERENCES: - - 1. Quickstart: https://developers.google.com/gmail/api/quickstart/python - 2. Labels: https://developers.google.com/gmail/api/guides/labels - 3. Messages: https://developers.google.com/gmail/api/reference/rest/v1/users.messages - - DOWNLOADS: - - N/A - -""" - - -# ***************************************************************************************************************** -# ***** **** -# *** IMPORT *** -# ***** **** -# ***************************************************************************************************************** - - -# To make sibling directories accessible for imports: -import sys -sys.path.append(".") -sys.path.append("..") - -# System-level activities: -import io - -# My utils: -from utils_v2.string import json -from utils_v2.string import regex -from utils_v2.date_time import date_time -from utils_v2.mail import mail_parser - -# My Google utils: -from utils_v2.oauth.services.goog import GoogleOAuth -from utils_v2.goog.base import AsyncGoogleBase -from utils_v2.goog.models.data.auth_tokens import GoogleAuthTokens -from utils_v2.goog.models.data.api_call import GoogleApiResponse - -# Related to Google: -from google.auth.transport.requests import Request -from google.oauth2.credentials import Credentials -from googleapiclient.discovery import build - -# To make API calls: -import httpx - -# For asynchronous activities: -import asyncio - -# To work with date and time: -import datetime - -# For working with datatypes: -from typing import Dict, Literal, List, Any - -# For debugging: -from icecream import IceCreamDebugger - -# For computational help: -import math - -# For base64 encoding: -import base64 - - -# ***************************************************************************************************************** -# ***** **** -# *** MACROS / ONE-TIME INIT *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** VARIABLES *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** FUNCTIONS *** -# ***** **** -# ***************************************************************************************************************** - - -# --- Nothing Yet - - -# ***************************************************************************************************************** -# ***** **** -# *** CLASSES *** -# ***** **** -# ***************************************************************************************************************** - - -class AsyncGMailClient(AsyncGoogleBase): - - async def get_user_profile( - self, - tokens: GoogleAuthTokens, - user_id: str = "me", - ) -> GoogleApiResponse: - - """ - To get the list of labels of this user. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users/getProfile - :param tokens: The object that holds the access token to the service. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Getting User Profile.") - api_response = await self.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/profile", - headers = {"Authorization": f"Bearer {tokens.accessToken}"} - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - # ┓ ┓ ┓ - # ┃ â”┓┣┓â”┓┃┠- # ┗┛┗┻┗┛┗ â”—â”› - - async def list_labels( - self, - tokens: GoogleAuthTokens, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To get the list of labels of this user. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/list - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param tokens: The object that holds the access token to the service. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Listing All Labels.", user_id) - api_response = await self.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels", - headers = {"Authorization": f"Bearer {tokens.accessToken}"} - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_json = await api_response.get_json() - api_response.data = {label.pop("name"): label for label in api_json.get("labels", [])} - - # Done here: - return api_response - - async def get_label( - self, - tokens: GoogleAuthTokens, - label_id: str, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To get one label of this user. the label will be identified by its id. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/get - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param tokens: The object that holds the access token to the service. - :param label_id: The id that Google assigned to the label. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Getting One Label.", user_id) - api_response = await self.get( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", - headers = {"Authorization": f"Bearer {tokens.accessToken}"} - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - async def create_label( - self, - tokens: GoogleAuthTokens, - label_name: str, - label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = "labelShow", - message_visibility: Literal["show", "hide"] = "show", - label_text_color: str = "#434343", - label_background_color: str = "#000000", - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - Create one label for the user. Doesn't apply it to any mail, just creates it. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/create - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - :param tokens: The object that holds the access token to the service. - :param label_name: The display name of the label. - :param label_visibility: Whether, or not, you would like to show the label in the web UI. - :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. - :param label_text_color: The colour of the text of the label. - :param label_background_color: The colour of the background/tag of the label. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Getting One Label.", user_id) - api_response = await self.post( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - json = { - "name": label_name, - "messageListVisibility": "show" if message_visibility else "hide", - "labelListVisibility": "labelShow" if label_visibility else "labelHide", - "color": { - "textColor": label_text_color.lower(), - "backgroundColor": label_background_color.lower() - } - } - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - async def update_label( - self, - tokens: GoogleAuthTokens, - label_id: str, - label_name: str = None, - label_visibility: Literal["labelShow", "labelShowIfUnread", "labelHide"] = None, - message_visibility: Literal["show", "hide"] = None, - label_text_color: str = None, - label_background_color: str = None, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - Updates one label for the user. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/update - 2. https://developers.google.com/gmail/api/reference/rest/v1/users.labels#Label - NOTE: Both or none of the colours must be updated. For this reason, a simple default will be chosen for the - other if only one is provided. - :param tokens: The object that holds the access token to the service. - :param label_id: The id that Google assigned to the label. - :param label_name: The display name of the label. - :param label_visibility: Whether, or not, you would like to show the label in the web UI. - :param message_visibility: Whether, or not, you would like to show messages with this label in the web UI. - :param label_text_color: The colour of the text of the label. - :param label_background_color: The colour of the background/tag of the label. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Format the JSON body: - json_body = {} - if label_name: json_body["name"] = label_name - if label_visibility: json_body["labelListVisibility"] = label_visibility - if message_visibility: json_body["messageListVisibility"] = message_visibility - if label_text_color or label_background_color: - json_body["color"] = { - "textColor": (label_text_color or "#434343").lower(), - "backgroundColor": (label_background_color or "#000000").lower() - } - - # Make the API call: - if not self._debug_only_errors: self._printer("Updating One Label.", user_id) - api_response = await self.put( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", - headers = {"Authorization": f"Bearer {tokens.accessToken}"}, - json = json_body - ) - - # If the call was successful: - if api_response.httpCode in [200]: - api_response.success = True - api_response.data = await api_response.get_json() - - # Done here: - return api_response - - async def delete_label( - self, - tokens: GoogleAuthTokens, - label_id: str, - user_id: str = "me" - ) -> GoogleApiResponse: - - """ - To delete one label of this user. the label will be identified by its id. - DOCUMENTATION: - 1. https://developers.google.com/gmail/api/reference/rest/v1/users.labels/delete - :param tokens: The object that holds the access token to the service. - :param label_id: The id that Google assigned to the label. - :param user_id: The id of the user for which this service must be run. Typically, the e-mail id itself or "me". - :return: A structured response where the list of labels will be in the 'data' variable. - """ - - # Ensure that the tokens are valid: - await tokens.arefresh( - http_client = self._http_client, - client_id = self._client_id, - client_secret = self._client_secret, - force_refresh = False - ) - - # Make the API call: - if not self._debug_only_errors: self._printer("Getting One Label.", user_id) - api_response = await self.delete( - url = f"https://gmail.googleapis.com/gmail/v1/users/{user_id}/labels/{label_id}", - headers = {"Authorization": f"Bearer {tokens.accessToken}"} - ) - - # If the call was successful: - if api_response.httpCode in [200, 204]: - api_response.success = True - - # Done here: - return api_response - - -# ***************************************************************************************************************** -# ***** **** -# *** MAIN PROGRAM *** -# ***** **** -# ***************************************************************************************************************** - - -if __name__ == "__main__": - - import dateparser - from utils_v2.goog.models.data.auth_tokens import GoogleAuthTokens - - # Create an HTTP client: - test_client = httpx.AsyncClient( - limits = httpx.Limits( - max_connections = 100, # ............ Maximum number of connections allowed in the pool. - max_keepalive_connections = 50, # ... Maximum number of connections that can be kept alive. - ), - timeout = httpx.Timeout( - connect = 2.5, # ... Shorter connection timeout. - read = 2.5, # ...... Like what EasyEcom gives. - write = 10.0, # .... Time to wait for sending data. - pool = 120.0 # ..... Time to wait for a free connection from the pool. - ) - ) - - secrets_file = r"../../../creds/google_tcaoff_test_oauth_20241125.json" - secrets_dict = json.from_file(secrets_file) - - tokens = { - "accessToken": "ya29.a0AeDClZAYoo85BXRId_n-hwo_amKshzi46c33GaJcsZZvGB7A7OGU2RFYcWBM_BleNBfAFUSJP2NHAvmd7Nsp_U5Kg68hXSy0iO99PNTm3pvKrJSzbkA-rXsVLsCnBIfPUMyNt2nOOVJmGwm17DNN0jAELkm1fPNTju7SZzmuaCgYKAZwSARMSFQHGX2Mis8TZui2rZT1gKySVds-N0w0175", - "refreshToken": "1//0gnqzjMf9YT19CgYIARAAGBASNgF-L9Ir3rcY37nGrV45XyOUBRllEH7Txui7T1JbwevlmDoNw7PuMu149cCWQSwsScuKaZusUQ", - "expiresIn": 3539, - "expiresAt": dateparser.parse("2024-11-25 10:40:40.833699+00:00"), - "scopes": [ - "https://www.googleapis.com/auth/gmail.labels", - "https://www.googleapis.com/auth/gmail.modify" - ] - } - - async def main(): - - my_gmail = AsyncGMailClient( - service_name = "gmail", - client_id = secrets_dict["web"]["client_id"], - client_secret = secrets_dict["web"]["client_secret"], - http_client = test_client, - debug = True, - debug_prefix = "GMail (M) | ", - debug_only_errors = False - ) - - test_tokens = GoogleAuthTokens(**tokens) - - response = await my_gmail.get_user_profile(tokens = test_tokens) - print("RESPONSE:", response) - - - asyncio.run(main()) diff --git a/utils_v2/goog/models/data/api_call.py b/utils_v2/goog/models/data/api_call.py index 766a70f..6301dff 100644 --- a/utils_v2/goog/models/data/api_call.py +++ b/utils_v2/goog/models/data/api_call.py @@ -107,6 +107,7 @@ class GoogleApiResponse(BaseModel): message += f"*URL:*\n`{self.url}`\n\n" message += f"*METHOD:*\n`{self.method}`\n\n" message += f"*RESPONSE:*\n`{self.response}`\n\n" + message += f"*MESSAGE:*\n`{self.message}`\n\n" message += f"*EXCEPTION:*\n`{self.exception.__class__.__name__}: {str(self.exception)}`\n\n" return message diff --git a/utils_v2/oauth/services/goog.py b/utils_v2/oauth/services/goog.py index 88249a3..3376e1c 100644 --- a/utils_v2/oauth/services/goog.py +++ b/utils_v2/oauth/services/goog.py @@ -363,7 +363,7 @@ if __name__ == "__main__": import dateparser - secrets_file = r"../../../creds/google_tcaoff_test_oauth_20241125.json" + secrets_file = r"../../../creds/goog/app/google_tcaoff_test_oauth_20241125.json" secrets_dict = json.from_file(secrets_file) my_goog = GoogleOAuth(